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 static void
  363 init_dynamic_kenv_from(char *init_env, int *curpos)
  364 {
  365         char *cp, *cpnext, *eqpos, *found;
  366         size_t len;
  367         int i;
  368 
  369         if (init_env && *init_env != '\0') {
  370                 found = NULL;
  371                 i = *curpos;
  372                 for (cp = init_env; cp != NULL; cp = cpnext) {
  373                         cpnext = kernenv_next(cp);
  374                         len = strlen(cp) + 1;
  375                         if (len > KENV_MNAMELEN + 1 + kenv_mvallen + 1) {
  376                                 printf(
  377                                 "WARNING: too long kenv string, ignoring %s\n",
  378                                     cp);
  379                                 goto sanitize;
  380                         }
  381                         eqpos = strchr(cp, '=');
  382                         if (eqpos == NULL) {
  383                                 printf(
  384                                 "WARNING: malformed static env value, ignoring %s\n",
  385                                     cp);
  386                                 goto sanitize;
  387                         }
  388                         *eqpos = 0;
  389                         /*
  390                          * De-dupe the environment as we go.  We don't add the
  391                          * duplicated assignments because config(8) will flip
  392                          * the order of the static environment around to make
  393                          * kernel processing match the order of specification
  394                          * in the kernel config.
  395                          */
  396                         found = _getenv_dynamic_locked(cp, NULL);
  397                         *eqpos = '=';
  398                         if (found != NULL)
  399                                 goto sanitize;
  400                         if (i > KENV_SIZE) {
  401                                 printf(
  402                                 "WARNING: too many kenv strings, ignoring %s\n",
  403                                     cp);
  404                                 goto sanitize;
  405                         }
  406 
  407                         kenvp[i] = malloc(len, M_KENV, M_WAITOK);
  408                         strcpy(kenvp[i++], cp);
  409 sanitize:
  410 #ifdef PRESERVE_EARLY_KENV
  411                         continue;
  412 #else
  413                         explicit_bzero(cp, len - 1);
  414 #endif
  415                 }
  416                 *curpos = i;
  417         }
  418 }
  419 
  420 /*
  421  * Setup the dynamic kernel environment.
  422  */
  423 static void
  424 init_dynamic_kenv(void *data __unused)
  425 {
  426         int dynamic_envpos;
  427         int size;
  428 
  429         TUNABLE_INT_FETCH("kenv_mvallen", &kenv_mvallen);
  430         size = KENV_MNAMELEN + 1 + kenv_mvallen + 1;
  431 
  432         kenv_zone = uma_zcreate("kenv", size, NULL, NULL, NULL, NULL,
  433             UMA_ALIGN_PTR, 0);
  434 
  435         kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
  436                 M_WAITOK | M_ZERO);
  437 
  438         dynamic_envpos = 0;
  439         init_dynamic_kenv_from(md_envp, &dynamic_envpos);
  440         init_dynamic_kenv_from(kern_envp, &dynamic_envpos);
  441         kenvp[dynamic_envpos] = NULL;
  442 
  443         mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
  444         dynamic_kenv = true;
  445 }
  446 SYSINIT(kenv, SI_SUB_KMEM + 1, SI_ORDER_FIRST, init_dynamic_kenv, NULL);
  447 
  448 void
  449 freeenv(char *env)
  450 {
  451 
  452         if (dynamic_kenv && env != NULL) {
  453                 explicit_bzero(env, strlen(env));
  454                 uma_zfree(kenv_zone, env);
  455         }
  456 }
  457 
  458 /*
  459  * Internal functions for string lookup.
  460  */
  461 static char *
  462 _getenv_dynamic_locked(const char *name, int *idx)
  463 {
  464         char *cp;
  465         int len, i;
  466 
  467         len = strlen(name);
  468         for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
  469                 if ((strncmp(cp, name, len) == 0) &&
  470                     (cp[len] == '=')) {
  471                         if (idx != NULL)
  472                                 *idx = i;
  473                         return (cp + len + 1);
  474                 }
  475         }
  476         return (NULL);
  477 }
  478 
  479 static char *
  480 _getenv_dynamic(const char *name, int *idx)
  481 {
  482 
  483         mtx_assert(&kenv_lock, MA_OWNED);
  484         return (_getenv_dynamic_locked(name, idx));
  485 }
  486 
  487 static char *
  488 _getenv_static_from(char *chkenv, const char *name)
  489 {
  490         char *cp, *ep;
  491         int len;
  492 
  493         for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) {
  494                 for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
  495                         ;
  496                 if (*ep != '=')
  497                         continue;
  498                 len = ep - cp;
  499                 ep++;
  500                 if (!strncmp(name, cp, len) && name[len] == 0)
  501                         return (ep);
  502         }
  503         return (NULL);
  504 }
  505 
  506 static char *
  507 _getenv_static(const char *name)
  508 {
  509         char *val;
  510 
  511         val = _getenv_static_from(md_envp, name);
  512         if (val != NULL)
  513                 return (val);
  514         val = _getenv_static_from(kern_envp, name);
  515         if (val != NULL)
  516                 return (val);
  517         return (NULL);
  518 }
  519 
  520 /*
  521  * Look up an environment variable by name.
  522  * Return a pointer to the string if found.
  523  * The pointer has to be freed with freeenv()
  524  * after use.
  525  */
  526 char *
  527 kern_getenv(const char *name)
  528 {
  529         char *cp, *ret;
  530         int len;
  531 
  532         if (dynamic_kenv) {
  533                 len = KENV_MNAMELEN + 1 + kenv_mvallen + 1;
  534                 ret = uma_zalloc(kenv_zone, M_WAITOK | M_ZERO);
  535                 mtx_lock(&kenv_lock);
  536                 cp = _getenv_dynamic(name, NULL);
  537                 if (cp != NULL)
  538                         strlcpy(ret, cp, len);
  539                 mtx_unlock(&kenv_lock);
  540                 if (cp == NULL) {
  541                         uma_zfree(kenv_zone, ret);
  542                         ret = NULL;
  543                 }
  544         } else
  545                 ret = _getenv_static(name);
  546 
  547         return (ret);
  548 }
  549 
  550 /*
  551  * Test if an environment variable is defined.
  552  */
  553 int
  554 testenv(const char *name)
  555 {
  556         char *cp;
  557 
  558         cp = kenv_acquire(name);
  559         kenv_release(cp);
  560 
  561         if (cp != NULL)
  562                 return (1);
  563         return (0);
  564 }
  565 
  566 /*
  567  * Set an environment variable in the MD-static environment.  This cannot
  568  * feasibly be done on config(8)-generated static environments as they don't
  569  * generally include space for extra variables.
  570  */
  571 static int
  572 setenv_static(const char *name, const char *value)
  573 {
  574         int len;
  575 
  576         if (md_env_pos >= md_env_len)
  577                 return (-1);
  578 
  579         /* Check space for x=y and two nuls */
  580         len = strlen(name) + strlen(value);
  581         if (len + 3 < md_env_len - md_env_pos) {
  582                 len = sprintf(&md_envp[md_env_pos], "%s=%s", name, value);
  583                 md_env_pos += len+1;
  584                 md_envp[md_env_pos] = '\0';
  585                 return (0);
  586         } else
  587                 return (-1);
  588 
  589 }
  590 
  591 /*
  592  * Set an environment variable by name.
  593  */
  594 int
  595 kern_setenv(const char *name, const char *value)
  596 {
  597         char *buf, *cp, *oldenv;
  598         int namelen, vallen, i;
  599 
  600         if (!dynamic_kenv && md_env_len > 0)
  601                 return (setenv_static(name, value));
  602 
  603         KENV_CHECK;
  604 
  605         namelen = strlen(name) + 1;
  606         if (namelen > KENV_MNAMELEN + 1)
  607                 return (-1);
  608         vallen = strlen(value) + 1;
  609         if (vallen > kenv_mvallen + 1)
  610                 return (-1);
  611         buf = malloc(namelen + vallen, M_KENV, M_WAITOK);
  612         sprintf(buf, "%s=%s", name, value);
  613 
  614         mtx_lock(&kenv_lock);
  615         cp = _getenv_dynamic(name, &i);
  616         if (cp != NULL) {
  617                 oldenv = kenvp[i];
  618                 kenvp[i] = buf;
  619                 mtx_unlock(&kenv_lock);
  620                 free(oldenv, M_KENV);
  621         } else {
  622                 /* We add the option if it wasn't found */
  623                 for (i = 0; (cp = kenvp[i]) != NULL; i++)
  624                         ;
  625 
  626                 /* Bounds checking */
  627                 if (i < 0 || i >= KENV_SIZE) {
  628                         free(buf, M_KENV);
  629                         mtx_unlock(&kenv_lock);
  630                         return (-1);
  631                 }
  632 
  633                 kenvp[i] = buf;
  634                 kenvp[i + 1] = NULL;
  635                 mtx_unlock(&kenv_lock);
  636         }
  637         return (0);
  638 }
  639 
  640 /*
  641  * Unset an environment variable string.
  642  */
  643 int
  644 kern_unsetenv(const char *name)
  645 {
  646         char *cp, *oldenv;
  647         int i, j;
  648 
  649         KENV_CHECK;
  650 
  651         mtx_lock(&kenv_lock);
  652         cp = _getenv_dynamic(name, &i);
  653         if (cp != NULL) {
  654                 oldenv = kenvp[i];
  655                 for (j = i + 1; kenvp[j] != NULL; j++)
  656                         kenvp[i++] = kenvp[j];
  657                 kenvp[i] = NULL;
  658                 mtx_unlock(&kenv_lock);
  659                 zfree(oldenv, M_KENV);
  660                 return (0);
  661         }
  662         mtx_unlock(&kenv_lock);
  663         return (-1);
  664 }
  665 
  666 /*
  667  * Return the internal kenv buffer for the variable name, if it exists.
  668  * If the dynamic kenv is initialized and the name is present, return
  669  * with kenv_lock held.
  670  */
  671 static char *
  672 kenv_acquire(const char *name)
  673 {
  674         char *value;
  675 
  676         if (dynamic_kenv) {
  677                 mtx_lock(&kenv_lock);
  678                 value = _getenv_dynamic(name, NULL);
  679                 if (value == NULL)
  680                         mtx_unlock(&kenv_lock);
  681                 return (value);
  682         } else
  683                 return (_getenv_static(name));
  684 }
  685 
  686 /*
  687  * Undo a previous kenv_acquire() operation
  688  */
  689 static void
  690 kenv_release(const char *buf)
  691 {
  692         if ((buf != NULL) && dynamic_kenv)
  693                 mtx_unlock(&kenv_lock);
  694 }
  695 
  696 /*
  697  * Return a string value from an environment variable.
  698  */
  699 int
  700 getenv_string(const char *name, char *data, int size)
  701 {
  702         char *cp;
  703 
  704         cp = kenv_acquire(name);
  705 
  706         if (cp != NULL)
  707                 strlcpy(data, cp, size);
  708 
  709         kenv_release(cp);
  710 
  711         return (cp != NULL);
  712 }
  713 
  714 /*
  715  * Return an array of integers at the given type size and signedness.
  716  */
  717 int
  718 getenv_array(const char *name, void *pdata, int size, int *psize,
  719     int type_size, bool allow_signed)
  720 {
  721         uint8_t shift;
  722         int64_t value;
  723         int64_t old;
  724         const char *buf;
  725         char *end;
  726         const char *ptr;
  727         int n;
  728         int rc;
  729 
  730         rc = 0;                   /* assume failure */
  731 
  732         buf = kenv_acquire(name);
  733         if (buf == NULL)
  734                 goto error;
  735 
  736         /* get maximum number of elements */
  737         size /= type_size;
  738 
  739         n = 0;
  740 
  741         for (ptr = buf; *ptr != 0; ) {
  742                 value = strtoq(ptr, &end, 0);
  743 
  744                 /* check if signed numbers are allowed */
  745                 if (value < 0 && !allow_signed)
  746                         goto error;
  747 
  748                 /* check for invalid value */
  749                 if (ptr == end)
  750                         goto error;
  751                 
  752                 /* check for valid suffix */
  753                 switch (*end) {
  754                 case 't':
  755                 case 'T':
  756                         shift = 40;
  757                         end++;
  758                         break;
  759                 case 'g':
  760                 case 'G':
  761                         shift = 30;
  762                         end++;
  763                         break;
  764                 case 'm':
  765                 case 'M':
  766                         shift = 20;
  767                         end++;
  768                         break;
  769                 case 'k':
  770                 case 'K':
  771                         shift = 10;
  772                         end++;
  773                         break;
  774                 case ' ':
  775                 case '\t':
  776                 case ',':
  777                 case 0:
  778                         shift = 0;
  779                         break;
  780                 default:
  781                         /* garbage after numeric value */
  782                         goto error;
  783                 }
  784 
  785                 /* skip till next value, if any */
  786                 while (*end == '\t' || *end == ',' || *end == ' ')
  787                         end++;
  788 
  789                 /* update pointer */
  790                 ptr = end;
  791 
  792                 /* apply shift */
  793                 old = value;
  794                 value <<= shift;
  795 
  796                 /* overflow check */
  797                 if ((value >> shift) != old)
  798                         goto error;
  799 
  800                 /* check for buffer overflow */
  801                 if (n >= size)
  802                         goto error;
  803 
  804                 /* store value according to type size */
  805                 switch (type_size) {
  806                 case 1:
  807                         if (allow_signed) {
  808                                 if (value < SCHAR_MIN || value > SCHAR_MAX)
  809                                         goto error;
  810                         } else {
  811                                 if (value < 0 || value > UCHAR_MAX)
  812                                         goto error;
  813                         }
  814                         ((uint8_t *)pdata)[n] = (uint8_t)value;
  815                         break;
  816                 case 2:
  817                         if (allow_signed) {
  818                                 if (value < SHRT_MIN || value > SHRT_MAX)
  819                                         goto error;
  820                         } else {
  821                                 if (value < 0 || value > USHRT_MAX)
  822                                         goto error;
  823                         }
  824                         ((uint16_t *)pdata)[n] = (uint16_t)value;
  825                         break;
  826                 case 4:
  827                         if (allow_signed) {
  828                                 if (value < INT_MIN || value > INT_MAX)
  829                                         goto error;
  830                         } else {
  831                                 if (value > UINT_MAX)
  832                                         goto error;
  833                         }
  834                         ((uint32_t *)pdata)[n] = (uint32_t)value;
  835                         break;
  836                 case 8:
  837                         ((uint64_t *)pdata)[n] = (uint64_t)value;
  838                         break;
  839                 default:
  840                         goto error;
  841                 }
  842                 n++;
  843         }
  844         *psize = n * type_size;
  845 
  846         if (n != 0)
  847                 rc = 1; /* success */
  848 error:
  849         kenv_release(buf);
  850         return (rc);
  851 }
  852 
  853 /*
  854  * Return an integer value from an environment variable.
  855  */
  856 int
  857 getenv_int(const char *name, int *data)
  858 {
  859         quad_t tmp;
  860         int rval;
  861 
  862         rval = getenv_quad(name, &tmp);
  863         if (rval)
  864                 *data = (int) tmp;
  865         return (rval);
  866 }
  867 
  868 /*
  869  * Return an unsigned integer value from an environment variable.
  870  */
  871 int
  872 getenv_uint(const char *name, unsigned int *data)
  873 {
  874         quad_t tmp;
  875         int rval;
  876 
  877         rval = getenv_quad(name, &tmp);
  878         if (rval)
  879                 *data = (unsigned int) tmp;
  880         return (rval);
  881 }
  882 
  883 /*
  884  * Return an int64_t value from an environment variable.
  885  */
  886 int
  887 getenv_int64(const char *name, int64_t *data)
  888 {
  889         quad_t tmp;
  890         int64_t rval;
  891 
  892         rval = getenv_quad(name, &tmp);
  893         if (rval)
  894                 *data = (int64_t) tmp;
  895         return (rval);
  896 }
  897 
  898 /*
  899  * Return an uint64_t value from an environment variable.
  900  */
  901 int
  902 getenv_uint64(const char *name, uint64_t *data)
  903 {
  904         quad_t tmp;
  905         uint64_t rval;
  906 
  907         rval = getenv_quad(name, &tmp);
  908         if (rval)
  909                 *data = (uint64_t) tmp;
  910         return (rval);
  911 }
  912 
  913 /*
  914  * Return a long value from an environment variable.
  915  */
  916 int
  917 getenv_long(const char *name, long *data)
  918 {
  919         quad_t tmp;
  920         int rval;
  921 
  922         rval = getenv_quad(name, &tmp);
  923         if (rval)
  924                 *data = (long) tmp;
  925         return (rval);
  926 }
  927 
  928 /*
  929  * Return an unsigned long value from an environment variable.
  930  */
  931 int
  932 getenv_ulong(const char *name, unsigned long *data)
  933 {
  934         quad_t tmp;
  935         int rval;
  936 
  937         rval = getenv_quad(name, &tmp);
  938         if (rval)
  939                 *data = (unsigned long) tmp;
  940         return (rval);
  941 }
  942 
  943 /*
  944  * Return a quad_t value from an environment variable.
  945  */
  946 int
  947 getenv_quad(const char *name, quad_t *data)
  948 {
  949         const char      *value;
  950         char            suffix, *vtp;
  951         quad_t          iv;
  952 
  953         value = kenv_acquire(name);
  954         if (value == NULL) {
  955                 goto error;
  956         }
  957         iv = strtoq(value, &vtp, 0);
  958         if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
  959                 goto error;
  960         }
  961         suffix = vtp[0];
  962         kenv_release(value);
  963         switch (suffix) {
  964         case 't': case 'T':
  965                 iv *= 1024;
  966                 /* FALLTHROUGH */
  967         case 'g': case 'G':
  968                 iv *= 1024;
  969                 /* FALLTHROUGH */
  970         case 'm': case 'M':
  971                 iv *= 1024;
  972                 /* FALLTHROUGH */
  973         case 'k': case 'K':
  974                 iv *= 1024;
  975         case '\0':
  976                 break;
  977         default:
  978                 return (0);
  979         }
  980         *data = iv;
  981         return (1);
  982 error:
  983         kenv_release(value);
  984         return (0);
  985 }
  986 
  987 /*
  988  * Return a boolean value from an environment variable. This can be in
  989  * numerical or string form, i.e. "1" or "true".
  990  */
  991 int
  992 getenv_bool(const char *name, bool *data)
  993 {
  994         char *val;
  995         int ret = 0;
  996 
  997         if (name == NULL)
  998                 return (0);
  999 
 1000         val = kern_getenv(name);
 1001         if (val == NULL)
 1002                 return (0);
 1003 
 1004         if ((strcmp(val, "1") == 0) || (strcasecmp(val, "true") == 0)) {
 1005                 *data = true;
 1006                 ret = 1;
 1007         } else if ((strcmp(val, "") == 0) || (strcasecmp(val, "false") == 0)) {
 1008                 *data = false;
 1009                 ret = 1;
 1010         } else {
 1011                 /* Spit out a warning for malformed boolean variables. */
 1012                 printf("Environment variable %s has non-boolean value \"%s\"\n",
 1013                     name, val);
 1014         }
 1015         freeenv(val);
 1016 
 1017         return (ret);
 1018 }
 1019 
 1020 /*
 1021  * Wrapper around getenv_bool to easily check for true.
 1022  */
 1023 bool
 1024 getenv_is_true(const char *name)
 1025 {
 1026         bool val;
 1027 
 1028         if (getenv_bool(name, &val) != 0)
 1029                 return (val);
 1030         return (false);
 1031 }
 1032 
 1033 /*
 1034  * Wrapper around getenv_bool to easily check for false.
 1035  */
 1036 bool
 1037 getenv_is_false(const char *name)
 1038 {
 1039         bool val;
 1040 
 1041         if (getenv_bool(name, &val) != 0)
 1042                 return (!val);
 1043         return (false);
 1044 }
 1045 
 1046 /*
 1047  * Find the next entry after the one which (cp) falls within, return a
 1048  * pointer to its start or NULL if there are no more.
 1049  */
 1050 static char *
 1051 kernenv_next(char *cp)
 1052 {
 1053 
 1054         if (cp != NULL) {
 1055                 while (*cp != 0)
 1056                         cp++;
 1057                 cp++;
 1058                 if (*cp == 0)
 1059                         cp = NULL;
 1060         }
 1061         return (cp);
 1062 }
 1063 
 1064 void
 1065 tunable_int_init(void *data)
 1066 {
 1067         struct tunable_int *d = (struct tunable_int *)data;
 1068 
 1069         TUNABLE_INT_FETCH(d->path, d->var);
 1070 }
 1071 
 1072 void
 1073 tunable_long_init(void *data)
 1074 {
 1075         struct tunable_long *d = (struct tunable_long *)data;
 1076 
 1077         TUNABLE_LONG_FETCH(d->path, d->var);
 1078 }
 1079 
 1080 void
 1081 tunable_ulong_init(void *data)
 1082 {
 1083         struct tunable_ulong *d = (struct tunable_ulong *)data;
 1084 
 1085         TUNABLE_ULONG_FETCH(d->path, d->var);
 1086 }
 1087 
 1088 void
 1089 tunable_int64_init(void *data)
 1090 {
 1091         struct tunable_int64 *d = (struct tunable_int64 *)data;
 1092 
 1093         TUNABLE_INT64_FETCH(d->path, d->var);
 1094 }
 1095 
 1096 void
 1097 tunable_uint64_init(void *data)
 1098 {
 1099         struct tunable_uint64 *d = (struct tunable_uint64 *)data;
 1100 
 1101         TUNABLE_UINT64_FETCH(d->path, d->var);
 1102 }
 1103 
 1104 void
 1105 tunable_quad_init(void *data)
 1106 {
 1107         struct tunable_quad *d = (struct tunable_quad *)data;
 1108 
 1109         TUNABLE_QUAD_FETCH(d->path, d->var);
 1110 }
 1111 
 1112 void
 1113 tunable_bool_init(void *data)
 1114 {
 1115         struct tunable_bool *d = (struct tunable_bool *)data;
 1116 
 1117         TUNABLE_BOOL_FETCH(d->path, d->var);
 1118 }
 1119 
 1120 void
 1121 tunable_str_init(void *data)
 1122 {
 1123         struct tunable_str *d = (struct tunable_str *)data;
 1124 
 1125         TUNABLE_STR_FETCH(d->path, d->var, d->size);
 1126 }

Cache object: 5a612836961756bb80cf4c581ecd077f


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