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

Cache object: 1b011e52c33ef50764c267e05ba06908


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