1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <alloca.h>
  29 #include <errno.h>
  30 #include <stdio.h>
  31 #include <string.h>
  32 #include <sys/lx_syscall.h>
  33 #include <sys/lx_misc.h>
  34 #include <sys/lx_debug.h>
  35 
  36 /*
  37  * sysctl() implementation.  The full set of possible values is incredibly
  38  * large; we only implement the bare minimum here, namely basic kernel
  39  * information.
  40  *
  41  * For the moment, we also print out debugging messages if the application
  42  * attempts to write or access any other values, so we can tell if we are not
  43  * supporting something we should be.
  44  */
  45 
  46 struct lx_sysctl_args {
  47         int *name;
  48         int nlen;
  49         void *oldval;
  50         size_t *oldlenp;
  51         void *newval;
  52         size_t newlen;
  53 };
  54 
  55 #define LX_CTL_KERN             1
  56 
  57 #define LX_KERN_OSTYPE          1
  58 #define LX_KERN_OSRELEASE       2
  59 #define LX_KERN_OSREV           3
  60 #define LX_KERN_VERSION         4
  61 
  62 int
  63 lx_sysctl(uintptr_t raw)
  64 {
  65         struct lx_sysctl_args args;
  66         int name[2];
  67         size_t oldlen;
  68         char *namebuf;
  69 
  70         if (uucopy((void *)raw, &args, sizeof (args)) < 0)
  71                 return (-EFAULT);
  72 
  73         /*
  74          * We only allow [ CTL_KERN, KERN_* ] pairs, so reject anything that
  75          * doesn't have exactly two values starting with LX_CTL_KERN.
  76          */
  77         if (args.nlen != 2)
  78                 return (-ENOTDIR);
  79 
  80         if (uucopy(args.name, name, sizeof (name)) < 0)
  81                 return (-EFAULT);
  82 
  83         if (name[0] != LX_CTL_KERN) {
  84                 lx_debug("sysctl: read of [%d, %d] unsupported",
  85                     name[0], name[1]);
  86                 return (-ENOTDIR);
  87         }
  88 
  89         /* We don't support writing new sysctl values. */
  90         if ((args.newval != NULL) || (args.newlen != 0)) {
  91                 lx_debug("sysctl: write of [%d, %d] unsupported",
  92                     name[0], name[1]);
  93                 return (-EPERM);
  94         }
  95 
  96         /*
  97          * It may seem silly, but passing in a NULL oldval pointer and not
  98          * writing any new values is a perfectly legal thing to do and should
  99          * succeed.
 100          */
 101         if (args.oldval == NULL)
 102                 return (0);
 103 
 104         /*
 105          * Likewise, Linux specifies that setting a non-NULL oldval but a
 106          * zero *oldlenp should result in an errno of EFAULT.
 107          */
 108         if ((uucopy(args.oldlenp, &oldlen, sizeof (oldlen)) < 0) ||
 109             (oldlen == 0))
 110                 return (-EFAULT);
 111 
 112         namebuf = SAFE_ALLOCA(oldlen);
 113         if (namebuf == NULL)
 114                 return (-ENOMEM);
 115 
 116         switch (name[1]) {
 117         case LX_KERN_OSTYPE:
 118                 (void) strlcpy(namebuf, LX_UNAME_SYSNAME, oldlen);
 119                 break;
 120         case LX_KERN_OSRELEASE:
 121                 (void) strlcpy(namebuf, lx_release, oldlen);
 122                 break;
 123         case LX_KERN_VERSION:
 124                 (void) strlcpy(namebuf, LX_UNAME_VERSION, oldlen);
 125                 break;
 126         default:
 127                 lx_debug("sysctl: read of [CTL_KERN, %d] unsupported", name[1]);
 128                 return (-ENOTDIR);
 129         }
 130 
 131         oldlen = strlen(namebuf);
 132 
 133         if ((uucopy(namebuf, args.oldval, oldlen) < 0) ||
 134             (uucopy(&oldlen, args.oldlenp, sizeof (oldlen)) < 0))
 135                 return (-EFAULT);
 136 
 137         return (0);
 138 }