The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_environment.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1998 Michael Smith
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * The unified bootloader passes us a pointer to a preserved copy of
   31  * bootstrap/kernel environment variables.  We convert them to a
   32  * dynamic array of strings later when the VM subsystem is up.
   33  *
   34  * We make these available through the kenv(2) syscall for userland
   35  * and through kern_getenv()/freeenv() kern_setenv() kern_unsetenv() testenv() for
   36  * the kernel.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD: releng/12.0/sys/kern/kern_environment.c 336217 2018-07-12 02:51:50Z kevans $");
   41 
   42 #include <sys/param.h>
   43 #include <sys/proc.h>
   44 #include <sys/queue.h>
   45 #include <sys/lock.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mutex.h>
   48 #include <sys/priv.h>
   49 #include <sys/kernel.h>
   50 #include <sys/systm.h>
   51 #include <sys/sysent.h>
   52 #include <sys/sysproto.h>
   53 #include <sys/libkern.h>
   54 #include <sys/kenv.h>
   55 #include <sys/limits.h>
   56 
   57 #include <security/mac/mac_framework.h>
   58 
   59 static char *_getenv_dynamic_locked(const char *name, int *idx);
   60 static char *_getenv_dynamic(const char *name, int *idx);
   61 
   62 static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
   63 
   64 #define KENV_SIZE       512     /* Maximum number of environment strings */
   65 
   66 /* pointer to the config-generated static environment */
   67 char            *kern_envp;
   68 
   69 /* pointer to the md-static environment */
   70 char            *md_envp;
   71 static int      md_env_len;
   72 static int      md_env_pos;
   73 
   74 static char     *kernenv_next(char *);
   75 
   76 /* dynamic environment variables */
   77 char            **kenvp;
   78 struct mtx      kenv_lock;
   79 
   80 /*
   81  * No need to protect this with a mutex since SYSINITS are single threaded.
   82  */
   83 bool    dynamic_kenv;
   84 
   85 #define KENV_CHECK      if (!dynamic_kenv) \
   86                             panic("%s: called before SI_SUB_KMEM", __func__)
   87 
   88 int
   89 sys_kenv(td, uap)
   90         struct thread *td;
   91         struct kenv_args /* {
   92                 int what;
   93                 const char *name;
   94                 char *value;
   95                 int len;
   96         } */ *uap;
   97 {
   98         char *name, *value, *buffer = NULL;
   99         size_t len, done, needed, buflen;
  100         int error, i;
  101 
  102         KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = false"));
  103 
  104         error = 0;
  105         if (uap->what == KENV_DUMP) {
  106 #ifdef MAC
  107                 error = mac_kenv_check_dump(td->td_ucred);
  108                 if (error)
  109                         return (error);
  110 #endif
  111                 done = needed = 0;
  112                 buflen = uap->len;
  113                 if (buflen > KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2))
  114                         buflen = KENV_SIZE * (KENV_MNAMELEN +
  115                             KENV_MVALLEN + 2);
  116                 if (uap->len > 0 && uap->value != NULL)
  117                         buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO);
  118                 mtx_lock(&kenv_lock);
  119                 for (i = 0; kenvp[i] != NULL; i++) {
  120                         len = strlen(kenvp[i]) + 1;
  121                         needed += len;
  122                         len = min(len, buflen - done);
  123                         /*
  124                          * If called with a NULL or insufficiently large
  125                          * buffer, just keep computing the required size.
  126                          */
  127                         if (uap->value != NULL && buffer != NULL && len > 0) {
  128                                 bcopy(kenvp[i], buffer + done, len);
  129                                 done += len;
  130                         }
  131                 }
  132                 mtx_unlock(&kenv_lock);
  133                 if (buffer != NULL) {
  134                         error = copyout(buffer, uap->value, done);
  135                         free(buffer, M_TEMP);
  136                 }
  137                 td->td_retval[0] = ((done == needed) ? 0 : needed);
  138                 return (error);
  139         }
  140 
  141         switch (uap->what) {
  142         case KENV_SET:
  143                 error = priv_check(td, PRIV_KENV_SET);
  144                 if (error)
  145                         return (error);
  146                 break;
  147 
  148         case KENV_UNSET:
  149                 error = priv_check(td, PRIV_KENV_UNSET);
  150                 if (error)
  151                         return (error);
  152                 break;
  153         }
  154 
  155         name = malloc(KENV_MNAMELEN + 1, M_TEMP, M_WAITOK);
  156 
  157         error = copyinstr(uap->name, name, KENV_MNAMELEN + 1, NULL);
  158         if (error)
  159                 goto done;
  160 
  161         switch (uap->what) {
  162         case KENV_GET:
  163 #ifdef MAC
  164                 error = mac_kenv_check_get(td->td_ucred, name);
  165                 if (error)
  166                         goto done;
  167 #endif
  168                 value = kern_getenv(name);
  169                 if (value == NULL) {
  170                         error = ENOENT;
  171                         goto done;
  172                 }
  173                 len = strlen(value) + 1;
  174                 if (len > uap->len)
  175                         len = uap->len;
  176                 error = copyout(value, uap->value, len);
  177                 freeenv(value);
  178                 if (error)
  179                         goto done;
  180                 td->td_retval[0] = len;
  181                 break;
  182         case KENV_SET:
  183                 len = uap->len;
  184                 if (len < 1) {
  185                         error = EINVAL;
  186                         goto done;
  187                 }
  188                 if (len > KENV_MVALLEN + 1)
  189                         len = KENV_MVALLEN + 1;
  190                 value = malloc(len, M_TEMP, M_WAITOK);
  191                 error = copyinstr(uap->value, value, len, NULL);
  192                 if (error) {
  193                         free(value, M_TEMP);
  194                         goto done;
  195                 }
  196 #ifdef MAC
  197                 error = mac_kenv_check_set(td->td_ucred, name, value);
  198                 if (error == 0)
  199 #endif
  200                         kern_setenv(name, value);
  201                 free(value, M_TEMP);
  202                 break;
  203         case KENV_UNSET:
  204 #ifdef MAC
  205                 error = mac_kenv_check_unset(td->td_ucred, name);
  206                 if (error)
  207                         goto done;
  208 #endif
  209                 error = kern_unsetenv(name);
  210                 if (error)
  211                         error = ENOENT;
  212                 break;
  213         default:
  214                 error = EINVAL;
  215                 break;
  216         }
  217 done:
  218         free(name, M_TEMP);
  219         return (error);
  220 }
  221 
  222 /*
  223  * Populate the initial kernel environment.
  224  *
  225  * This is called very early in MD startup, either to provide a copy of the
  226  * environment obtained from a boot loader, or to provide an empty buffer into
  227  * which MD code can store an initial environment using kern_setenv() calls.
  228  *
  229  * kern_envp is set to the static_env generated by config(8).  This implements
  230  * the env keyword described in config(5).
  231  *
  232  * If len is non-zero, the caller is providing an empty buffer.  The caller will
  233  * subsequently use kern_setenv() to add up to len bytes of initial environment
  234  * before the dynamic environment is available.
  235  *
  236  * If len is zero, the caller is providing a pre-loaded buffer containing
  237  * environment strings.  Additional strings cannot be added until the dynamic
  238  * environment is available.  The memory pointed to must remain stable at least
  239  * until sysinit runs init_dynamic_kenv() and preferably until after SI_SUB_KMEM
  240  * is finished so that subr_hints routines may continue to use it until the
  241  * environments have been fully merged at the end of the pass.  If no initial
  242  * environment is available from the boot loader, passing a NULL pointer allows
  243  * the static_env to be installed if it is configured.  In this case, any call
  244  * to kern_setenv() prior to the setup of the dynamic environment will result in
  245  * a panic.
  246  */
  247 void
  248 init_static_kenv(char *buf, size_t len)
  249 {
  250         char *eval;
  251 
  252         /*
  253          * Give the static environment a chance to disable the loader(8)
  254          * environment first.  This is done with loader_env.disabled=1.
  255          *
  256          * static_env and static_hints may both be disabled, but in slightly
  257          * different ways.  For static_env, we just don't setup kern_envp and
  258          * it's as if a static env wasn't even provided.  For static_hints,
  259          * we effectively zero out the buffer to stop the rest of the kernel
  260          * from being able to use it.
  261          *
  262          * We're intentionally setting this up so that static_hints.disabled may
  263          * be specified in either the MD env or the static env. This keeps us
  264          * consistent in our new world view.
  265          *
  266          * As a warning, the static environment may not be disabled in any way
  267          * if the static environment has disabled the loader environment.
  268          */
  269         kern_envp = static_env;
  270         eval = kern_getenv("loader_env.disabled");
  271         if (eval == NULL || strcmp(eval, "1") != 0) {
  272                 md_envp = buf;
  273                 md_env_len = len;
  274                 md_env_pos = 0;
  275 
  276                 eval = kern_getenv("static_env.disabled");
  277                 if (eval != NULL && strcmp(eval, "1") == 0)
  278                         *kern_envp = '\0';
  279         }
  280         eval = kern_getenv("static_hints.disabled");
  281         if (eval != NULL && strcmp(eval, "1") == 0)
  282                 *static_hints = '\0';
  283 }
  284 
  285 static void
  286 init_dynamic_kenv_from(char *init_env, int *curpos)
  287 {
  288         char *cp, *cpnext, *eqpos, *found;
  289         size_t len;
  290         int i;
  291 
  292         if (init_env && *init_env != '\0') {
  293                 found = NULL;
  294                 i = *curpos;
  295                 for (cp = init_env; cp != NULL; cp = cpnext) {
  296                         cpnext = kernenv_next(cp);
  297                         len = strlen(cp) + 1;
  298                         if (len > KENV_MNAMELEN + 1 + KENV_MVALLEN + 1) {
  299                                 printf(
  300                                 "WARNING: too long kenv string, ignoring %s\n",
  301                                     cp);
  302                                 goto sanitize;
  303                         }
  304                         eqpos = strchr(cp, '=');
  305                         if (eqpos == NULL) {
  306                                 printf(
  307                                 "WARNING: malformed static env value, ignoring %s\n",
  308                                     cp);
  309                                 goto sanitize;
  310                         }
  311                         *eqpos = 0;
  312                         /*
  313                          * De-dupe the environment as we go.  We don't add the
  314                          * duplicated assignments because config(8) will flip
  315                          * the order of the static environment around to make
  316                          * kernel processing match the order of specification
  317                          * in the kernel config.
  318                          */
  319                         found = _getenv_dynamic_locked(cp, NULL);
  320                         *eqpos = '=';
  321                         if (found != NULL)
  322                                 goto sanitize;
  323                         if (i > KENV_SIZE) {
  324                                 printf(
  325                                 "WARNING: too many kenv strings, ignoring %s\n",
  326                                     cp);
  327                                 goto sanitize;
  328                         }
  329 
  330                         kenvp[i] = malloc(len, M_KENV, M_WAITOK);
  331                         strcpy(kenvp[i++], cp);
  332 sanitize:
  333                         explicit_bzero(cp, len - 1);
  334                 }
  335                 *curpos = i;
  336         }
  337 }
  338 
  339 /*
  340  * Setup the dynamic kernel environment.
  341  */
  342 static void
  343 init_dynamic_kenv(void *data __unused)
  344 {
  345         int dynamic_envpos;
  346 
  347         kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
  348                 M_WAITOK | M_ZERO);
  349 
  350         dynamic_envpos = 0;
  351         init_dynamic_kenv_from(md_envp, &dynamic_envpos);
  352         init_dynamic_kenv_from(kern_envp, &dynamic_envpos);
  353         kenvp[dynamic_envpos] = NULL;
  354 
  355         mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
  356         dynamic_kenv = true;
  357 }
  358 SYSINIT(kenv, SI_SUB_KMEM + 1, SI_ORDER_FIRST, init_dynamic_kenv, NULL);
  359 
  360 void
  361 freeenv(char *env)
  362 {
  363 
  364         if (dynamic_kenv && env != NULL) {
  365                 explicit_bzero(env, strlen(env));
  366                 free(env, M_KENV);
  367         }
  368 }
  369 
  370 /*
  371  * Internal functions for string lookup.
  372  */
  373 static char *
  374 _getenv_dynamic_locked(const char *name, int *idx)
  375 {
  376         char *cp;
  377         int len, i;
  378 
  379         len = strlen(name);
  380         for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
  381                 if ((strncmp(cp, name, len) == 0) &&
  382                     (cp[len] == '=')) {
  383                         if (idx != NULL)
  384                                 *idx = i;
  385                         return (cp + len + 1);
  386                 }
  387         }
  388         return (NULL);
  389 }
  390 
  391 static char *
  392 _getenv_dynamic(const char *name, int *idx)
  393 {
  394 
  395         mtx_assert(&kenv_lock, MA_OWNED);
  396         return (_getenv_dynamic_locked(name, idx));
  397 }
  398 
  399 static char *
  400 _getenv_static_from(char *chkenv, const char *name)
  401 {
  402         char *cp, *ep;
  403         int len;
  404 
  405         for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) {
  406                 for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
  407                         ;
  408                 if (*ep != '=')
  409                         continue;
  410                 len = ep - cp;
  411                 ep++;
  412                 if (!strncmp(name, cp, len) && name[len] == 0)
  413                         return (ep);
  414         }
  415         return (NULL);
  416 }
  417 
  418 static char *
  419 _getenv_static(const char *name)
  420 {
  421         char *val;
  422 
  423         val = _getenv_static_from(md_envp, name);
  424         if (val != NULL)
  425                 return (val);
  426         val = _getenv_static_from(kern_envp, name);
  427         if (val != NULL)
  428                 return (val);
  429         return (NULL);
  430 }
  431 
  432 /*
  433  * Look up an environment variable by name.
  434  * Return a pointer to the string if found.
  435  * The pointer has to be freed with freeenv()
  436  * after use.
  437  */
  438 char *
  439 kern_getenv(const char *name)
  440 {
  441         char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1];
  442         char *ret;
  443 
  444         if (dynamic_kenv) {
  445                 if (getenv_string(name, buf, sizeof(buf))) {
  446                         ret = strdup(buf, M_KENV);
  447                 } else {
  448                         ret = NULL;
  449                         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
  450                             "getenv");
  451                 }
  452         } else
  453                 ret = _getenv_static(name);
  454         return (ret);
  455 }
  456 
  457 /*
  458  * Test if an environment variable is defined.
  459  */
  460 int
  461 testenv(const char *name)
  462 {
  463         char *cp;
  464 
  465         if (dynamic_kenv) {
  466                 mtx_lock(&kenv_lock);
  467                 cp = _getenv_dynamic(name, NULL);
  468                 mtx_unlock(&kenv_lock);
  469         } else
  470                 cp = _getenv_static(name);
  471         if (cp != NULL)
  472                 return (1);
  473         return (0);
  474 }
  475 
  476 /*
  477  * Set an environment variable in the MD-static environment.  This cannot
  478  * feasibly be done on config(8)-generated static environments as they don't
  479  * generally include space for extra variables.
  480  */
  481 static int
  482 setenv_static(const char *name, const char *value)
  483 {
  484         int len;
  485 
  486         if (md_env_pos >= md_env_len)
  487                 return (-1);
  488 
  489         /* Check space for x=y and two nuls */
  490         len = strlen(name) + strlen(value);
  491         if (len + 3 < md_env_len - md_env_pos) {
  492                 len = sprintf(&md_envp[md_env_pos], "%s=%s", name, value);
  493                 md_env_pos += len+1;
  494                 md_envp[md_env_pos] = '\0';
  495                 return (0);
  496         } else
  497                 return (-1);
  498 
  499 }
  500 
  501 /*
  502  * Set an environment variable by name.
  503  */
  504 int
  505 kern_setenv(const char *name, const char *value)
  506 {
  507         char *buf, *cp, *oldenv;
  508         int namelen, vallen, i;
  509 
  510         if (!dynamic_kenv && md_env_len > 0)
  511                 return (setenv_static(name, value));
  512 
  513         KENV_CHECK;
  514 
  515         namelen = strlen(name) + 1;
  516         if (namelen > KENV_MNAMELEN + 1)
  517                 return (-1);
  518         vallen = strlen(value) + 1;
  519         if (vallen > KENV_MVALLEN + 1)
  520                 return (-1);
  521         buf = malloc(namelen + vallen, M_KENV, M_WAITOK);
  522         sprintf(buf, "%s=%s", name, value);
  523 
  524         mtx_lock(&kenv_lock);
  525         cp = _getenv_dynamic(name, &i);
  526         if (cp != NULL) {
  527                 oldenv = kenvp[i];
  528                 kenvp[i] = buf;
  529                 mtx_unlock(&kenv_lock);
  530                 free(oldenv, M_KENV);
  531         } else {
  532                 /* We add the option if it wasn't found */
  533                 for (i = 0; (cp = kenvp[i]) != NULL; i++)
  534                         ;
  535 
  536                 /* Bounds checking */
  537                 if (i < 0 || i >= KENV_SIZE) {
  538                         free(buf, M_KENV);
  539                         mtx_unlock(&kenv_lock);
  540                         return (-1);
  541                 }
  542 
  543                 kenvp[i] = buf;
  544                 kenvp[i + 1] = NULL;
  545                 mtx_unlock(&kenv_lock);
  546         }
  547         return (0);
  548 }
  549 
  550 /*
  551  * Unset an environment variable string.
  552  */
  553 int
  554 kern_unsetenv(const char *name)
  555 {
  556         char *cp, *oldenv;
  557         int i, j;
  558 
  559         KENV_CHECK;
  560 
  561         mtx_lock(&kenv_lock);
  562         cp = _getenv_dynamic(name, &i);
  563         if (cp != NULL) {
  564                 oldenv = kenvp[i];
  565                 for (j = i + 1; kenvp[j] != NULL; j++)
  566                         kenvp[i++] = kenvp[j];
  567                 kenvp[i] = NULL;
  568                 mtx_unlock(&kenv_lock);
  569                 explicit_bzero(oldenv, strlen(oldenv));
  570                 free(oldenv, M_KENV);
  571                 return (0);
  572         }
  573         mtx_unlock(&kenv_lock);
  574         return (-1);
  575 }
  576 
  577 /*
  578  * Return a string value from an environment variable.
  579  */
  580 int
  581 getenv_string(const char *name, char *data, int size)
  582 {
  583         char *cp;
  584 
  585         if (dynamic_kenv) {
  586                 mtx_lock(&kenv_lock);
  587                 cp = _getenv_dynamic(name, NULL);
  588                 if (cp != NULL)
  589                         strlcpy(data, cp, size);
  590                 mtx_unlock(&kenv_lock);
  591         } else {
  592                 cp = _getenv_static(name);
  593                 if (cp != NULL)
  594                         strlcpy(data, cp, size);
  595         }
  596         return (cp != NULL);
  597 }
  598 
  599 /*
  600  * Return an array of integers at the given type size and signedness.
  601  */
  602 int
  603 getenv_array(const char *name, void *pdata, int size, int *psize,
  604     int type_size, bool allow_signed)
  605 {
  606         char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1];
  607         uint8_t shift;
  608         int64_t value;
  609         int64_t old;
  610         char *end;
  611         char *ptr;
  612         int n;
  613 
  614         if (getenv_string(name, buf, sizeof(buf)) == 0)
  615                 return (0);
  616 
  617         /* get maximum number of elements */
  618         size /= type_size;
  619 
  620         n = 0;
  621 
  622         for (ptr = buf; *ptr != 0; ) {
  623 
  624                 value = strtoq(ptr, &end, 0);
  625 
  626                 /* check if signed numbers are allowed */
  627                 if (value < 0 && !allow_signed)
  628                         goto error;
  629 
  630                 /* check for invalid value */
  631                 if (ptr == end)
  632                         goto error;
  633                 
  634                 /* check for valid suffix */
  635                 switch (*end) {
  636                 case 't':
  637                 case 'T':
  638                         shift = 40;
  639                         end++;
  640                         break;
  641                 case 'g':
  642                 case 'G':
  643                         shift = 30;
  644                         end++;
  645                         break;
  646                 case 'm':
  647                 case 'M':
  648                         shift = 20;
  649                         end++;
  650                         break;
  651                 case 'k':
  652                 case 'K':
  653                         shift = 10;
  654                         end++;
  655                         break;
  656                 case ' ':
  657                 case '\t':
  658                 case ',':
  659                 case 0:
  660                         shift = 0;
  661                         break;
  662                 default:
  663                         /* garbage after numeric value */
  664                         goto error;
  665                 }
  666 
  667                 /* skip till next value, if any */
  668                 while (*end == '\t' || *end == ',' || *end == ' ')
  669                         end++;
  670 
  671                 /* update pointer */
  672                 ptr = end;
  673 
  674                 /* apply shift */
  675                 old = value;
  676                 value <<= shift;
  677 
  678                 /* overflow check */
  679                 if ((value >> shift) != old)
  680                         goto error;
  681 
  682                 /* check for buffer overflow */
  683                 if (n >= size)
  684                         goto error;
  685 
  686                 /* store value according to type size */
  687                 switch (type_size) {
  688                 case 1:
  689                         if (allow_signed) {
  690                                 if (value < SCHAR_MIN || value > SCHAR_MAX)
  691                                         goto error;
  692                         } else {
  693                                 if (value < 0 || value > UCHAR_MAX)
  694                                         goto error;
  695                         }
  696                         ((uint8_t *)pdata)[n] = (uint8_t)value;
  697                         break;
  698                 case 2:
  699                         if (allow_signed) {
  700                                 if (value < SHRT_MIN || value > SHRT_MAX)
  701                                         goto error;
  702                         } else {
  703                                 if (value < 0 || value > USHRT_MAX)
  704                                         goto error;
  705                         }
  706                         ((uint16_t *)pdata)[n] = (uint16_t)value;
  707                         break;
  708                 case 4:
  709                         if (allow_signed) {
  710                                 if (value < INT_MIN || value > INT_MAX)
  711                                         goto error;
  712                         } else {
  713                                 if (value > UINT_MAX)
  714                                         goto error;
  715                         }
  716                         ((uint32_t *)pdata)[n] = (uint32_t)value;
  717                         break;
  718                 case 8:
  719                         ((uint64_t *)pdata)[n] = (uint64_t)value;
  720                         break;
  721                 default:
  722                         goto error;
  723                 }
  724                 n++;
  725         }
  726         *psize = n * type_size;
  727 
  728         if (n != 0)
  729                 return (1);     /* success */
  730 error:
  731         return (0);     /* failure */
  732 }
  733 
  734 /*
  735  * Return an integer value from an environment variable.
  736  */
  737 int
  738 getenv_int(const char *name, int *data)
  739 {
  740         quad_t tmp;
  741         int rval;
  742 
  743         rval = getenv_quad(name, &tmp);
  744         if (rval)
  745                 *data = (int) tmp;
  746         return (rval);
  747 }
  748 
  749 /*
  750  * Return an unsigned integer value from an environment variable.
  751  */
  752 int
  753 getenv_uint(const char *name, unsigned int *data)
  754 {
  755         quad_t tmp;
  756         int rval;
  757 
  758         rval = getenv_quad(name, &tmp);
  759         if (rval)
  760                 *data = (unsigned int) tmp;
  761         return (rval);
  762 }
  763 
  764 /*
  765  * Return an int64_t value from an environment variable.
  766  */
  767 int
  768 getenv_int64(const char *name, int64_t *data)
  769 {
  770         quad_t tmp;
  771         int64_t rval;
  772 
  773         rval = getenv_quad(name, &tmp);
  774         if (rval)
  775                 *data = (int64_t) tmp;
  776         return (rval);
  777 }
  778 
  779 /*
  780  * Return an uint64_t value from an environment variable.
  781  */
  782 int
  783 getenv_uint64(const char *name, uint64_t *data)
  784 {
  785         quad_t tmp;
  786         uint64_t rval;
  787 
  788         rval = getenv_quad(name, &tmp);
  789         if (rval)
  790                 *data = (uint64_t) tmp;
  791         return (rval);
  792 }
  793 
  794 /*
  795  * Return a long value from an environment variable.
  796  */
  797 int
  798 getenv_long(const char *name, long *data)
  799 {
  800         quad_t tmp;
  801         int rval;
  802 
  803         rval = getenv_quad(name, &tmp);
  804         if (rval)
  805                 *data = (long) tmp;
  806         return (rval);
  807 }
  808 
  809 /*
  810  * Return an unsigned long value from an environment variable.
  811  */
  812 int
  813 getenv_ulong(const char *name, unsigned long *data)
  814 {
  815         quad_t tmp;
  816         int rval;
  817 
  818         rval = getenv_quad(name, &tmp);
  819         if (rval)
  820                 *data = (unsigned long) tmp;
  821         return (rval);
  822 }
  823 
  824 /*
  825  * Return a quad_t value from an environment variable.
  826  */
  827 int
  828 getenv_quad(const char *name, quad_t *data)
  829 {
  830         char    value[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1];
  831         char    *vtp;
  832         quad_t  iv;
  833 
  834         if (!getenv_string(name, value, sizeof(value)))
  835                 return (0);
  836         iv = strtoq(value, &vtp, 0);
  837         if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0'))
  838                 return (0);
  839         switch (vtp[0]) {
  840         case 't': case 'T':
  841                 iv *= 1024;
  842         case 'g': case 'G':
  843                 iv *= 1024;
  844         case 'm': case 'M':
  845                 iv *= 1024;
  846         case 'k': case 'K':
  847                 iv *= 1024;
  848         case '\0':
  849                 break;
  850         default:
  851                 return (0);
  852         }
  853         *data = iv;
  854         return (1);
  855 }
  856 
  857 /*
  858  * Find the next entry after the one which (cp) falls within, return a
  859  * pointer to its start or NULL if there are no more.
  860  */
  861 static char *
  862 kernenv_next(char *cp)
  863 {
  864 
  865         if (cp != NULL) {
  866                 while (*cp != 0)
  867                         cp++;
  868                 cp++;
  869                 if (*cp == 0)
  870                         cp = NULL;
  871         }
  872         return (cp);
  873 }
  874 
  875 void
  876 tunable_int_init(void *data)
  877 {
  878         struct tunable_int *d = (struct tunable_int *)data;
  879 
  880         TUNABLE_INT_FETCH(d->path, d->var);
  881 }
  882 
  883 void
  884 tunable_long_init(void *data)
  885 {
  886         struct tunable_long *d = (struct tunable_long *)data;
  887 
  888         TUNABLE_LONG_FETCH(d->path, d->var);
  889 }
  890 
  891 void
  892 tunable_ulong_init(void *data)
  893 {
  894         struct tunable_ulong *d = (struct tunable_ulong *)data;
  895 
  896         TUNABLE_ULONG_FETCH(d->path, d->var);
  897 }
  898 
  899 void
  900 tunable_int64_init(void *data)
  901 {
  902         struct tunable_int64 *d = (struct tunable_int64 *)data;
  903 
  904         TUNABLE_INT64_FETCH(d->path, d->var);
  905 }
  906 
  907 void
  908 tunable_uint64_init(void *data)
  909 {
  910         struct tunable_uint64 *d = (struct tunable_uint64 *)data;
  911 
  912         TUNABLE_UINT64_FETCH(d->path, d->var);
  913 }
  914 
  915 void
  916 tunable_quad_init(void *data)
  917 {
  918         struct tunable_quad *d = (struct tunable_quad *)data;
  919 
  920         TUNABLE_QUAD_FETCH(d->path, d->var);
  921 }
  922 
  923 void
  924 tunable_str_init(void *data)
  925 {
  926         struct tunable_str *d = (struct tunable_str *)data;
  927 
  928         TUNABLE_STR_FETCH(d->path, d->var, d->size);
  929 }

Cache object: 2403adba5c70b6382c449df8fffd3708


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.