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