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$");
   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/kenv.h>
   50 #include <sys/kernel.h>
   51 #include <sys/systm.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 char *kenv_acquire(const char *name);
   63 static void kenv_release(const char *buf);
   64 
   65 static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
   66 
   67 #define KENV_SIZE       512     /* Maximum number of environment strings */
   68 
   69 static uma_zone_t kenv_zone;
   70 static int      kenv_mvallen = KENV_MVALLEN;
   71 
   72 /* pointer to the config-generated static environment */
   73 char            *kern_envp;
   74 
   75 /* pointer to the md-static environment */
   76 char            *md_envp;
   77 static int      md_env_len;
   78 static int      md_env_pos;
   79 
   80 static char     *kernenv_next(char *);
   81 
   82 /* dynamic environment variables */
   83 char            **kenvp;
   84 struct mtx      kenv_lock;
   85 
   86 /*
   87  * No need to protect this with a mutex since SYSINITS are single threaded.
   88  */
   89 bool    dynamic_kenv;
   90 
   91 #define KENV_CHECK      if (!dynamic_kenv) \
   92                             panic("%s: called before SI_SUB_KMEM", __func__)
   93 
   94 static int
   95 kenv_dump(struct thread *td, char **envp, int what, char *value, int len)
   96 {
   97         char *buffer, *senv;
   98         size_t done, needed, buflen;
   99         int error;
  100 
  101         error = 0;
  102         buffer = NULL;
  103         done = needed = 0;
  104 
  105         MPASS(what == KENV_DUMP || what == KENV_DUMP_LOADER ||
  106             what == KENV_DUMP_STATIC);
  107 
  108         /*
  109          * For non-dynamic kernel environment, we pass in either md_envp or
  110          * kern_envp and we must traverse with kernenv_next().  This shuffling
  111          * of pointers simplifies the below loop by only differing in how envp
  112          * is modified.
  113          */
  114         if (what != KENV_DUMP) {
  115                 senv = (char *)envp;
  116                 envp = &senv;
  117         }
  118 
  119         buflen = len;
  120         if (buflen > KENV_SIZE * (KENV_MNAMELEN + kenv_mvallen + 2))
  121                 buflen = KENV_SIZE * (KENV_MNAMELEN +
  122                     kenv_mvallen + 2);
  123         if (len > 0 && value != NULL)
  124                 buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO);
  125 
  126         /* Only take the lock for the dynamic kenv. */
  127         if (what == KENV_DUMP)
  128                 mtx_lock(&kenv_lock);
  129         while (*envp != NULL) {
  130                 len = strlen(*envp) + 1;
  131                 needed += len;
  132                 len = min(len, buflen - done);
  133                 /*
  134                  * If called with a NULL or insufficiently large
  135                  * buffer, just keep computing the required size.
  136                  */
  137                 if (value != NULL && buffer != NULL && len > 0) {
  138                         bcopy(*envp, buffer + done, len);
  139                         done += len;
  140                 }
  141 
  142                 /* Advance the pointer depending on the kenv format. */
  143                 if (what == KENV_DUMP)
  144                         envp++;
  145                 else
  146                         senv = kernenv_next(senv);
  147         }
  148         if (what == KENV_DUMP)
  149                 mtx_unlock(&kenv_lock);
  150         if (buffer != NULL) {
  151                 error = copyout(buffer, value, done);
  152                 free(buffer, M_TEMP);
  153         }
  154         td->td_retval[0] = ((done == needed) ? 0 : needed);
  155         return (error);
  156 }
  157 
  158 int
  159 sys_kenv(struct thread *td, struct kenv_args *uap)
  160 {
  161         char *name, *value;
  162         size_t len;
  163         int error;
  164 
  165         KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = false"));
  166 
  167         error = 0;
  168 
  169         switch (uap->what) {
  170         case KENV_DUMP:
  171 #ifdef MAC
  172                 error = mac_kenv_check_dump(td->td_ucred);
  173                 if (error)
  174                         return (error);
  175 #endif
  176                 return (kenv_dump(td, kenvp, uap->what, uap->value, uap->len));
  177         case KENV_DUMP_LOADER:
  178         case KENV_DUMP_STATIC:
  179 #ifdef MAC
  180                 error = mac_kenv_check_dump(td->td_ucred);
  181                 if (error)
  182                         return (error);
  183 #endif
  184 #ifdef PRESERVE_EARLY_KENV
  185                 return (kenv_dump(td,
  186                     uap->what == KENV_DUMP_LOADER ? (char **)md_envp :
  187                     (char **)kern_envp, uap->what, uap->value, uap->len));
  188 #else
  189                 return (ENOENT);
  190 #endif
  191         case KENV_SET:
  192                 error = priv_check(td, PRIV_KENV_SET);
  193                 if (error)
  194                         return (error);
  195                 break;
  196 
  197         case KENV_UNSET:
  198                 error = priv_check(td, PRIV_KENV_UNSET);
  199                 if (error)
  200                         return (error);
  201                 break;
  202         }
  203 
  204         name = malloc(KENV_MNAMELEN + 1, M_TEMP, M_WAITOK);
  205 
  206         error = copyinstr(uap->name, name, KENV_MNAMELEN + 1, NULL);
  207         if (error)
  208                 goto done;
  209 
  210         switch (uap->what) {
  211         case KENV_GET:
  212 #ifdef MAC
  213                 error = mac_kenv_check_get(td->td_ucred, name);
  214                 if (error)
  215                         goto done;
  216 #endif
  217                 value = kern_getenv(name);
  218                 if (value == NULL) {
  219                         error = ENOENT;
  220                         goto done;
  221                 }
  222                 len = strlen(value) + 1;
  223                 if (len > uap->len)
  224                         len = uap->len;
  225                 error = copyout(value, uap->value, len);
  226                 freeenv(value);
  227                 if (error)
  228                         goto done;
  229                 td->td_retval[0] = len;
  230                 break;
  231         case KENV_SET:
  232                 len = uap->len;
  233                 if (len < 1) {
  234                         error = EINVAL;
  235                         goto done;
  236                 }
  237                 if (len > kenv_mvallen + 1)
  238                         len = kenv_mvallen + 1;
  239                 value = malloc(len, M_TEMP, M_WAITOK);
  240                 error = copyinstr(uap->value, value, len, NULL);
  241                 if (error) {
  242                         free(value, M_TEMP);
  243                         goto done;
  244                 }
  245 #ifdef MAC
  246                 error = mac_kenv_check_set(td->td_ucred, name, value);
  247                 if (error == 0)
  248 #endif
  249                         kern_setenv(name, value);
  250                 free(value, M_TEMP);
  251                 break;
  252         case KENV_UNSET:
  253 #ifdef MAC
  254                 error = mac_kenv_check_unset(td->td_ucred, name);
  255                 if (error)
  256                         goto done;
  257 #endif
  258                 error = kern_unsetenv(name);
  259                 if (error)
  260                         error = ENOENT;
  261                 break;
  262         default:
  263                 error = EINVAL;
  264                 break;
  265         }
  266 done:
  267         free(name, M_TEMP);
  268         return (error);
  269 }
  270 
  271 /*
  272  * Populate the initial kernel environment.
  273  *
  274  * This is called very early in MD startup, either to provide a copy of the
  275  * environment obtained from a boot loader, or to provide an empty buffer into
  276  * which MD code can store an initial environment using kern_setenv() calls.
  277  *
  278  * kern_envp is set to the static_env generated by config(8).  This implements
  279  * the env keyword described in config(5).
  280  *
  281  * If len is non-zero, the caller is providing an empty buffer.  The caller will
  282  * subsequently use kern_setenv() to add up to len bytes of initial environment
  283  * before the dynamic environment is available.
  284  *
  285  * If len is zero, the caller is providing a pre-loaded buffer containing
  286  * environment strings.  Additional strings cannot be added until the dynamic
  287  * environment is available.  The memory pointed to must remain stable at least
  288  * until sysinit runs init_dynamic_kenv() and preferably until after SI_SUB_KMEM
  289  * is finished so that subr_hints routines may continue to use it until the
  290  * environments have been fully merged at the end of the pass.  If no initial
  291  * environment is available from the boot loader, passing a NULL pointer allows
  292  * the static_env to be installed if it is configured.  In this case, any call
  293  * to kern_setenv() prior to the setup of the dynamic environment will result in
  294  * a panic.
  295  */
  296 void
  297 init_static_kenv(char *buf, size_t len)
  298 {
  299 
  300         KASSERT(!dynamic_kenv, ("kenv: dynamic_kenv already initialized"));
  301         /*
  302          * Suitably sized means it must be able to hold at least one empty
  303          * variable, otherwise things go belly up if a kern_getenv call is
  304          * made without a prior call to kern_setenv as we have a malformed
  305          * environment.
  306          */
  307         KASSERT(len == 0 || len >= 2,
  308             ("kenv: static env must be initialized or suitably sized"));
  309         KASSERT(len == 0 || (*buf == '\0' && *(buf + 1) == '\0'),
  310             ("kenv: sized buffer must be initially empty"));
  311 
  312         /*
  313          * We may be called twice, with the second call needed to relocate
  314          * md_envp after enabling paging.  md_envp is then garbage if it is
  315          * not null and the relocation will move it.  Discard it so as to
  316          * not crash using its old value in our first call to kern_getenv().
  317          *
  318          * The second call gives the same environment as the first except
  319          * in silly configurations where the static env disables itself.
  320          *
  321          * Other env calls don't handle possibly-garbage pointers, so must
  322          * not be made between enabling paging and calling here.
  323          */
  324         md_envp = NULL;
  325         md_env_len = 0;
  326         md_env_pos = 0;
  327 
  328         /*
  329          * Give the static environment a chance to disable the loader(8)
  330          * environment first.  This is done with loader_env.disabled=1.
  331          *
  332          * static_env and static_hints may both be disabled, but in slightly
  333          * different ways.  For static_env, we just don't setup kern_envp and
  334          * it's as if a static env wasn't even provided.  For static_hints,
  335          * we effectively zero out the buffer to stop the rest of the kernel
  336          * from being able to use it.
  337          *
  338          * We're intentionally setting this up so that static_hints.disabled may
  339          * be specified in either the MD env or the static env. This keeps us
  340          * consistent in our new world view.
  341          *
  342          * As a warning, the static environment may not be disabled in any way
  343          * if the static environment has disabled the loader environment.
  344          */
  345         kern_envp = static_env;
  346         if (!getenv_is_true("loader_env.disabled")) {
  347                 md_envp = buf;
  348                 md_env_len = len;
  349                 md_env_pos = 0;
  350 
  351                 if (getenv_is_true("static_env.disabled")) {
  352                         kern_envp[0] = '\0';
  353                         kern_envp[1] = '\0';
  354                 }
  355         }
  356         if (getenv_is_true("static_hints.disabled")) {
  357                 static_hints[0] = '\0';
  358                 static_hints[1] = '\0';
  359         }
  360 }
  361 
  362 /* Maximum suffix number appended for duplicate environment variable names. */
  363 #define MAXSUFFIX 9999
  364 #define SUFFIXLEN strlen("_" __XSTRING(MAXSUFFIX))
  365 
  366 static void
  367 getfreesuffix(char *cp, size_t *n)
  368 {
  369         size_t len = strlen(cp);
  370         char * ncp;
  371 
  372         ncp = malloc(len + SUFFIXLEN + 1, M_KENV, M_WAITOK);
  373         memcpy(ncp, cp, len);
  374         for (*n = 1; *n <= MAXSUFFIX; (*n)++) {
  375                 sprintf(&ncp[len], "_%zu", *n);
  376                 if (!_getenv_dynamic_locked(ncp, NULL))
  377                         break;
  378         }
  379         free(ncp, M_KENV);
  380         if (*n > MAXSUFFIX)
  381                 panic("Too many duplicate kernel environment values: %s", cp);
  382 }
  383 
  384 static void
  385 init_dynamic_kenv_from(char *init_env, int *curpos)
  386 {
  387         char *cp, *cpnext, *eqpos, *found;
  388         size_t len, n;
  389         int i;
  390 
  391         if (init_env && *init_env != '\0') {
  392                 found = NULL;
  393                 i = *curpos;
  394                 for (cp = init_env; cp != NULL; cp = cpnext) {
  395                         cpnext = kernenv_next(cp);
  396                         len = strlen(cp) + 1;
  397                         if (i > KENV_SIZE) {
  398                                 printf(
  399                                 "WARNING: too many kenv strings, ignoring %s\n",
  400                                     cp);
  401                                 goto sanitize;
  402                         }
  403                         if (len > KENV_MNAMELEN + 1 + kenv_mvallen + 1) {
  404                                 printf(
  405                                 "WARNING: too long kenv string, ignoring %s\n",
  406                                     cp);
  407                                 goto sanitize;
  408                         }
  409                         eqpos = strchr(cp, '=');
  410                         if (eqpos == NULL) {
  411                                 printf(
  412                                 "WARNING: malformed static env value, ignoring %s\n",
  413                                     cp);
  414                                 goto sanitize;
  415                         }
  416                         *eqpos = 0;
  417                         /*
  418                          * Handle duplicates in the environment as we go; we
  419                          * add the duplicated assignments with _N suffixes.
  420                          * This ensures that (a) if a variable is set in the
  421                          * static environment and in the "loader" environment
  422                          * provided by MD code, the value from the loader will
  423                          * have the expected variable name and the value from
  424                          * the static environment will have the suffix; and (b)
  425                          * if the "loader" environment has the same variable
  426                          * set multiple times (as is possible with values being
  427                          * passed via the kernel "command line") the extra
  428                          * values are visible to code which knows where to look
  429                          * for them.
  430                          */
  431                         found = _getenv_dynamic_locked(cp, NULL);
  432                         if (found != NULL) {
  433                                 getfreesuffix(cp, &n);
  434                                 kenvp[i] = malloc(len + SUFFIXLEN,
  435                                     M_KENV, M_WAITOK);
  436                                 sprintf(kenvp[i++], "%s_%zu=%s", cp, n,
  437                                     &eqpos[1]);
  438                         } else {
  439                                 kenvp[i] = malloc(len, M_KENV, M_WAITOK);
  440                                 *eqpos = '=';
  441                                 strcpy(kenvp[i++], cp);
  442                         }
  443 sanitize:
  444 #ifdef PRESERVE_EARLY_KENV
  445                         continue;
  446 #else
  447                         explicit_bzero(cp, len - 1);
  448 #endif
  449                 }
  450                 *curpos = i;
  451         }
  452 }
  453 
  454 /*
  455  * Setup the dynamic kernel environment.
  456  */
  457 static void
  458 init_dynamic_kenv(void *data __unused)
  459 {
  460         int dynamic_envpos;
  461         int size;
  462 
  463         TUNABLE_INT_FETCH("kenv_mvallen", &kenv_mvallen);
  464         size = KENV_MNAMELEN + 1 + kenv_mvallen + 1;
  465 
  466         kenv_zone = uma_zcreate("kenv", size, NULL, NULL, NULL, NULL,
  467             UMA_ALIGN_PTR, 0);
  468 
  469         kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
  470                 M_WAITOK | M_ZERO);
  471 
  472         dynamic_envpos = 0;
  473         init_dynamic_kenv_from(md_envp, &dynamic_envpos);
  474         init_dynamic_kenv_from(kern_envp, &dynamic_envpos);
  475         kenvp[dynamic_envpos] = NULL;
  476 
  477         mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
  478         dynamic_kenv = true;
  479 }
  480 SYSINIT(kenv, SI_SUB_KMEM + 1, SI_ORDER_FIRST, init_dynamic_kenv, NULL);
  481 
  482 void
  483 freeenv(char *env)
  484 {
  485 
  486         if (dynamic_kenv && env != NULL) {
  487                 explicit_bzero(env, strlen(env));
  488                 uma_zfree(kenv_zone, env);
  489         }
  490 }
  491 
  492 /*
  493  * Internal functions for string lookup.
  494  */
  495 static char *
  496 _getenv_dynamic_locked(const char *name, int *idx)
  497 {
  498         char *cp;
  499         int len, i;
  500 
  501         len = strlen(name);
  502         for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
  503                 if ((strncmp(cp, name, len) == 0) &&
  504                     (cp[len] == '=')) {
  505                         if (idx != NULL)
  506                                 *idx = i;
  507                         return (cp + len + 1);
  508                 }
  509         }
  510         return (NULL);
  511 }
  512 
  513 static char *
  514 _getenv_dynamic(const char *name, int *idx)
  515 {
  516 
  517         mtx_assert(&kenv_lock, MA_OWNED);
  518         return (_getenv_dynamic_locked(name, idx));
  519 }
  520 
  521 static char *
  522 _getenv_static_from(char *chkenv, const char *name)
  523 {
  524         char *cp, *ep;
  525         int len;
  526 
  527         for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) {
  528                 for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
  529                         ;
  530                 if (*ep != '=')
  531                         continue;
  532                 len = ep - cp;
  533                 ep++;
  534                 if (!strncmp(name, cp, len) && name[len] == 0)
  535                         return (ep);
  536         }
  537         return (NULL);
  538 }
  539 
  540 static char *
  541 _getenv_static(const char *name)
  542 {
  543         char *val;
  544 
  545         val = _getenv_static_from(md_envp, name);
  546         if (val != NULL)
  547                 return (val);
  548         val = _getenv_static_from(kern_envp, name);
  549         if (val != NULL)
  550                 return (val);
  551         return (NULL);
  552 }
  553 
  554 /*
  555  * Look up an environment variable by name.
  556  * Return a pointer to the string if found.
  557  * The pointer has to be freed with freeenv()
  558  * after use.
  559  */
  560 char *
  561 kern_getenv(const char *name)
  562 {
  563         char *cp, *ret;
  564         int len;
  565 
  566         if (dynamic_kenv) {
  567                 len = KENV_MNAMELEN + 1 + kenv_mvallen + 1;
  568                 ret = uma_zalloc(kenv_zone, M_WAITOK | M_ZERO);
  569                 mtx_lock(&kenv_lock);
  570                 cp = _getenv_dynamic(name, NULL);
  571                 if (cp != NULL)
  572                         strlcpy(ret, cp, len);
  573                 mtx_unlock(&kenv_lock);
  574                 if (cp == NULL) {
  575                         uma_zfree(kenv_zone, ret);
  576                         ret = NULL;
  577                 }
  578         } else
  579                 ret = _getenv_static(name);
  580 
  581         return (ret);
  582 }
  583 
  584 /*
  585  * Test if an environment variable is defined.
  586  */
  587 int
  588 testenv(const char *name)
  589 {
  590         char *cp;
  591 
  592         cp = kenv_acquire(name);
  593         kenv_release(cp);
  594 
  595         if (cp != NULL)
  596                 return (1);
  597         return (0);
  598 }
  599 
  600 /*
  601  * Set an environment variable in the MD-static environment.  This cannot
  602  * feasibly be done on config(8)-generated static environments as they don't
  603  * generally include space for extra variables.
  604  */
  605 static int
  606 setenv_static(const char *name, const char *value)
  607 {
  608         int len;
  609 
  610         if (md_env_pos >= md_env_len)
  611                 return (-1);
  612 
  613         /* Check space for x=y and two nuls */
  614         len = strlen(name) + strlen(value);
  615         if (len + 3 < md_env_len - md_env_pos) {
  616                 len = sprintf(&md_envp[md_env_pos], "%s=%s", name, value);
  617                 md_env_pos += len+1;
  618                 md_envp[md_env_pos] = '\0';
  619                 return (0);
  620         } else
  621                 return (-1);
  622 
  623 }
  624 
  625 /*
  626  * Set an environment variable by name.
  627  */
  628 int
  629 kern_setenv(const char *name, const char *value)
  630 {
  631         char *buf, *cp, *oldenv;
  632         int namelen, vallen, i;
  633 
  634         if (!dynamic_kenv && md_env_len > 0)
  635                 return (setenv_static(name, value));
  636 
  637         KENV_CHECK;
  638 
  639         namelen = strlen(name) + 1;
  640         if (namelen > KENV_MNAMELEN + 1)
  641                 return (-1);
  642         vallen = strlen(value) + 1;
  643         if (vallen > kenv_mvallen + 1)
  644                 return (-1);
  645         buf = malloc(namelen + vallen, M_KENV, M_WAITOK);
  646         sprintf(buf, "%s=%s", name, value);
  647 
  648         mtx_lock(&kenv_lock);
  649         cp = _getenv_dynamic(name, &i);
  650         if (cp != NULL) {
  651                 oldenv = kenvp[i];
  652                 kenvp[i] = buf;
  653                 mtx_unlock(&kenv_lock);
  654                 free(oldenv, M_KENV);
  655         } else {
  656                 /* We add the option if it wasn't found */
  657                 for (i = 0; (cp = kenvp[i]) != NULL; i++)
  658                         ;
  659 
  660                 /* Bounds checking */
  661                 if (i < 0 || i >= KENV_SIZE) {
  662                         free(buf, M_KENV);
  663                         mtx_unlock(&kenv_lock);
  664                         return (-1);
  665                 }
  666 
  667                 kenvp[i] = buf;
  668                 kenvp[i + 1] = NULL;
  669                 mtx_unlock(&kenv_lock);
  670         }
  671         return (0);
  672 }
  673 
  674 /*
  675  * Unset an environment variable string.
  676  */
  677 int
  678 kern_unsetenv(const char *name)
  679 {
  680         char *cp, *oldenv;
  681         int i, j;
  682 
  683         KENV_CHECK;
  684 
  685         mtx_lock(&kenv_lock);
  686         cp = _getenv_dynamic(name, &i);
  687         if (cp != NULL) {
  688                 oldenv = kenvp[i];
  689                 for (j = i + 1; kenvp[j] != NULL; j++)
  690                         kenvp[i++] = kenvp[j];
  691                 kenvp[i] = NULL;
  692                 mtx_unlock(&kenv_lock);
  693                 zfree(oldenv, M_KENV);
  694                 return (0);
  695         }
  696         mtx_unlock(&kenv_lock);
  697         return (-1);
  698 }
  699 
  700 /*
  701  * Return the internal kenv buffer for the variable name, if it exists.
  702  * If the dynamic kenv is initialized and the name is present, return
  703  * with kenv_lock held.
  704  */
  705 static char *
  706 kenv_acquire(const char *name)
  707 {
  708         char *value;
  709 
  710         if (dynamic_kenv) {
  711                 mtx_lock(&kenv_lock);
  712                 value = _getenv_dynamic(name, NULL);
  713                 if (value == NULL)
  714                         mtx_unlock(&kenv_lock);
  715                 return (value);
  716         } else
  717                 return (_getenv_static(name));
  718 }
  719 
  720 /*
  721  * Undo a previous kenv_acquire() operation
  722  */
  723 static void
  724 kenv_release(const char *buf)
  725 {
  726         if ((buf != NULL) && dynamic_kenv)
  727                 mtx_unlock(&kenv_lock);
  728 }
  729 
  730 /*
  731  * Return a string value from an environment variable.
  732  */
  733 int
  734 getenv_string(const char *name, char *data, int size)
  735 {
  736         char *cp;
  737 
  738         cp = kenv_acquire(name);
  739 
  740         if (cp != NULL)
  741                 strlcpy(data, cp, size);
  742 
  743         kenv_release(cp);
  744 
  745         return (cp != NULL);
  746 }
  747 
  748 /*
  749  * Return an array of integers at the given type size and signedness.
  750  */
  751 int
  752 getenv_array(const char *name, void *pdata, int size, int *psize,
  753     int type_size, bool allow_signed)
  754 {
  755         uint8_t shift;
  756         int64_t value;
  757         int64_t old;
  758         const char *buf;
  759         char *end;
  760         const char *ptr;
  761         int n;
  762         int rc;
  763 
  764         rc = 0;                   /* assume failure */
  765 
  766         buf = kenv_acquire(name);
  767         if (buf == NULL)
  768                 goto error;
  769 
  770         /* get maximum number of elements */
  771         size /= type_size;
  772 
  773         n = 0;
  774 
  775         for (ptr = buf; *ptr != 0; ) {
  776                 value = strtoq(ptr, &end, 0);
  777 
  778                 /* check if signed numbers are allowed */
  779                 if (value < 0 && !allow_signed)
  780                         goto error;
  781 
  782                 /* check for invalid value */
  783                 if (ptr == end)
  784                         goto error;
  785                 
  786                 /* check for valid suffix */
  787                 switch (*end) {
  788                 case 't':
  789                 case 'T':
  790                         shift = 40;
  791                         end++;
  792                         break;
  793                 case 'g':
  794                 case 'G':
  795                         shift = 30;
  796                         end++;
  797                         break;
  798                 case 'm':
  799                 case 'M':
  800                         shift = 20;
  801                         end++;
  802                         break;
  803                 case 'k':
  804                 case 'K':
  805                         shift = 10;
  806                         end++;
  807                         break;
  808                 case ' ':
  809                 case '\t':
  810                 case ',':
  811                 case 0:
  812                         shift = 0;
  813                         break;
  814                 default:
  815                         /* garbage after numeric value */
  816                         goto error;
  817                 }
  818 
  819                 /* skip till next value, if any */
  820                 while (*end == '\t' || *end == ',' || *end == ' ')
  821                         end++;
  822 
  823                 /* update pointer */
  824                 ptr = end;
  825 
  826                 /* apply shift */
  827                 old = value;
  828                 value <<= shift;
  829 
  830                 /* overflow check */
  831                 if ((value >> shift) != old)
  832                         goto error;
  833 
  834                 /* check for buffer overflow */
  835                 if (n >= size)
  836                         goto error;
  837 
  838                 /* store value according to type size */
  839                 switch (type_size) {
  840                 case 1:
  841                         if (allow_signed) {
  842                                 if (value < SCHAR_MIN || value > SCHAR_MAX)
  843                                         goto error;
  844                         } else {
  845                                 if (value < 0 || value > UCHAR_MAX)
  846                                         goto error;
  847                         }
  848                         ((uint8_t *)pdata)[n] = (uint8_t)value;
  849                         break;
  850                 case 2:
  851                         if (allow_signed) {
  852                                 if (value < SHRT_MIN || value > SHRT_MAX)
  853                                         goto error;
  854                         } else {
  855                                 if (value < 0 || value > USHRT_MAX)
  856                                         goto error;
  857                         }
  858                         ((uint16_t *)pdata)[n] = (uint16_t)value;
  859                         break;
  860                 case 4:
  861                         if (allow_signed) {
  862                                 if (value < INT_MIN || value > INT_MAX)
  863                                         goto error;
  864                         } else {
  865                                 if (value > UINT_MAX)
  866                                         goto error;
  867                         }
  868                         ((uint32_t *)pdata)[n] = (uint32_t)value;
  869                         break;
  870                 case 8:
  871                         ((uint64_t *)pdata)[n] = (uint64_t)value;
  872                         break;
  873                 default:
  874                         goto error;
  875                 }
  876                 n++;
  877         }
  878         *psize = n * type_size;
  879 
  880         if (n != 0)
  881                 rc = 1; /* success */
  882 error:
  883         kenv_release(buf);
  884         return (rc);
  885 }
  886 
  887 /*
  888  * Return an integer value from an environment variable.
  889  */
  890 int
  891 getenv_int(const char *name, int *data)
  892 {
  893         quad_t tmp;
  894         int rval;
  895 
  896         rval = getenv_quad(name, &tmp);
  897         if (rval)
  898                 *data = (int) tmp;
  899         return (rval);
  900 }
  901 
  902 /*
  903  * Return an unsigned integer value from an environment variable.
  904  */
  905 int
  906 getenv_uint(const char *name, unsigned int *data)
  907 {
  908         quad_t tmp;
  909         int rval;
  910 
  911         rval = getenv_quad(name, &tmp);
  912         if (rval)
  913                 *data = (unsigned int) tmp;
  914         return (rval);
  915 }
  916 
  917 /*
  918  * Return an int64_t value from an environment variable.
  919  */
  920 int
  921 getenv_int64(const char *name, int64_t *data)
  922 {
  923         quad_t tmp;
  924         int64_t rval;
  925 
  926         rval = getenv_quad(name, &tmp);
  927         if (rval)
  928                 *data = (int64_t) tmp;
  929         return (rval);
  930 }
  931 
  932 /*
  933  * Return an uint64_t value from an environment variable.
  934  */
  935 int
  936 getenv_uint64(const char *name, uint64_t *data)
  937 {
  938         quad_t tmp;
  939         uint64_t rval;
  940 
  941         rval = getenv_quad(name, &tmp);
  942         if (rval)
  943                 *data = (uint64_t) tmp;
  944         return (rval);
  945 }
  946 
  947 /*
  948  * Return a long value from an environment variable.
  949  */
  950 int
  951 getenv_long(const char *name, long *data)
  952 {
  953         quad_t tmp;
  954         int rval;
  955 
  956         rval = getenv_quad(name, &tmp);
  957         if (rval)
  958                 *data = (long) tmp;
  959         return (rval);
  960 }
  961 
  962 /*
  963  * Return an unsigned long value from an environment variable.
  964  */
  965 int
  966 getenv_ulong(const char *name, unsigned long *data)
  967 {
  968         quad_t tmp;
  969         int rval;
  970 
  971         rval = getenv_quad(name, &tmp);
  972         if (rval)
  973                 *data = (unsigned long) tmp;
  974         return (rval);
  975 }
  976 
  977 /*
  978  * Return a quad_t value from an environment variable.
  979  */
  980 int
  981 getenv_quad(const char *name, quad_t *data)
  982 {
  983         const char      *value;
  984         char            suffix, *vtp;
  985         quad_t          iv;
  986 
  987         value = kenv_acquire(name);
  988         if (value == NULL) {
  989                 goto error;
  990         }
  991         iv = strtoq(value, &vtp, 0);
  992         if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
  993                 goto error;
  994         }
  995         suffix = vtp[0];
  996         kenv_release(value);
  997         switch (suffix) {
  998         case 't': case 'T':
  999                 iv *= 1024;
 1000                 /* FALLTHROUGH */
 1001         case 'g': case 'G':
 1002                 iv *= 1024;
 1003                 /* FALLTHROUGH */
 1004         case 'm': case 'M':
 1005                 iv *= 1024;
 1006                 /* FALLTHROUGH */
 1007         case 'k': case 'K':
 1008                 iv *= 1024;
 1009         case '\0':
 1010                 break;
 1011         default:
 1012                 return (0);
 1013         }
 1014         *data = iv;
 1015         return (1);
 1016 error:
 1017         kenv_release(value);
 1018         return (0);
 1019 }
 1020 
 1021 /*
 1022  * Return a boolean value from an environment variable. This can be in
 1023  * numerical or string form, i.e. "1" or "true".
 1024  */
 1025 int
 1026 getenv_bool(const char *name, bool *data)
 1027 {
 1028         char *val;
 1029         int ret = 0;
 1030 
 1031         if (name == NULL)
 1032                 return (0);
 1033 
 1034         val = kern_getenv(name);
 1035         if (val == NULL)
 1036                 return (0);
 1037 
 1038         if ((strcmp(val, "1") == 0) || (strcasecmp(val, "true") == 0)) {
 1039                 *data = true;
 1040                 ret = 1;
 1041         } else if ((strcmp(val, "") == 0) || (strcasecmp(val, "false") == 0)) {
 1042                 *data = false;
 1043                 ret = 1;
 1044         } else {
 1045                 /* Spit out a warning for malformed boolean variables. */
 1046                 printf("Environment variable %s has non-boolean value \"%s\"\n",
 1047                     name, val);
 1048         }
 1049         freeenv(val);
 1050 
 1051         return (ret);
 1052 }
 1053 
 1054 /*
 1055  * Wrapper around getenv_bool to easily check for true.
 1056  */
 1057 bool
 1058 getenv_is_true(const char *name)
 1059 {
 1060         bool val;
 1061 
 1062         if (getenv_bool(name, &val) != 0)
 1063                 return (val);
 1064         return (false);
 1065 }
 1066 
 1067 /*
 1068  * Wrapper around getenv_bool to easily check for false.
 1069  */
 1070 bool
 1071 getenv_is_false(const char *name)
 1072 {
 1073         bool val;
 1074 
 1075         if (getenv_bool(name, &val) != 0)
 1076                 return (!val);
 1077         return (false);
 1078 }
 1079 
 1080 /*
 1081  * Find the next entry after the one which (cp) falls within, return a
 1082  * pointer to its start or NULL if there are no more.
 1083  */
 1084 static char *
 1085 kernenv_next(char *cp)
 1086 {
 1087 
 1088         if (cp != NULL) {
 1089                 while (*cp != 0)
 1090                         cp++;
 1091                 cp++;
 1092                 if (*cp == 0)
 1093                         cp = NULL;
 1094         }
 1095         return (cp);
 1096 }
 1097 
 1098 void
 1099 tunable_int_init(void *data)
 1100 {
 1101         struct tunable_int *d = (struct tunable_int *)data;
 1102 
 1103         TUNABLE_INT_FETCH(d->path, d->var);
 1104 }
 1105 
 1106 void
 1107 tunable_long_init(void *data)
 1108 {
 1109         struct tunable_long *d = (struct tunable_long *)data;
 1110 
 1111         TUNABLE_LONG_FETCH(d->path, d->var);
 1112 }
 1113 
 1114 void
 1115 tunable_ulong_init(void *data)
 1116 {
 1117         struct tunable_ulong *d = (struct tunable_ulong *)data;
 1118 
 1119         TUNABLE_ULONG_FETCH(d->path, d->var);
 1120 }
 1121 
 1122 void
 1123 tunable_int64_init(void *data)
 1124 {
 1125         struct tunable_int64 *d = (struct tunable_int64 *)data;
 1126 
 1127         TUNABLE_INT64_FETCH(d->path, d->var);
 1128 }
 1129 
 1130 void
 1131 tunable_uint64_init(void *data)
 1132 {
 1133         struct tunable_uint64 *d = (struct tunable_uint64 *)data;
 1134 
 1135         TUNABLE_UINT64_FETCH(d->path, d->var);
 1136 }
 1137 
 1138 void
 1139 tunable_quad_init(void *data)
 1140 {
 1141         struct tunable_quad *d = (struct tunable_quad *)data;
 1142 
 1143         TUNABLE_QUAD_FETCH(d->path, d->var);
 1144 }
 1145 
 1146 void
 1147 tunable_bool_init(void *data)
 1148 {
 1149         struct tunable_bool *d = (struct tunable_bool *)data;
 1150 
 1151         TUNABLE_BOOL_FETCH(d->path, d->var);
 1152 }
 1153 
 1154 void
 1155 tunable_str_init(void *data)
 1156 {
 1157         struct tunable_str *d = (struct tunable_str *)data;
 1158 
 1159         TUNABLE_STR_FETCH(d->path, d->var, d->size);
 1160 }

Cache object: 46c224e2e53ef1a9cd93e7f1088f5ab9


[ 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.