FreeBSD kernel kern code
kern_environment.c
Go to the documentation of this file.
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
60static char *_getenv_dynamic_locked(const char *name, int *idx);
61static char *_getenv_dynamic(const char *name, int *idx);
62
63static char *kenv_acquire(const char *name);
64static void kenv_release(const char *buf);
65
66static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
67
68#define KENV_SIZE 512 /* Maximum number of environment strings */
69
70static uma_zone_t kenv_zone;
71static int kenv_mvallen = KENV_MVALLEN;
72
73/* pointer to the config-generated static environment */
75
76/* pointer to the md-static environment */
77char *md_envp;
78static int md_env_len;
79static int md_env_pos;
80
81static char *kernenv_next(char *);
82
83/* dynamic environment variables */
84char **kenvp;
86
87/*
88 * No need to protect this with a mutex since SYSINITS are single threaded.
89 */
91
92#define KENV_CHECK if (!dynamic_kenv) \
93 panic("%s: called before SI_SUB_KMEM", __func__)
94
95static int
96kenv_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
159int
160sys_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
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
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 }
267done:
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 */
297void
298init_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
363static void
364init_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);
410sanitize:
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 */
424static void
425init_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}
447SYSINIT(kenv, SI_SUB_KMEM + 1, SI_ORDER_FIRST, init_dynamic_kenv, NULL);
448
449void
450freeenv(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 */
462static 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
480static 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
488static 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
507static char *
509{
510 char *val;
511
513 if (val != NULL)
514 return (val);
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 */
527char *
528kern_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 */
554int
555testenv(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 */
572static int
573setenv_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 */
595int
596kern_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
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 */
644int
645kern_unsetenv(const char *name)
646{
647 char *cp, *oldenv;
648 int i, j;
649
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 */
672static char *
673kenv_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 */
690static void
691kenv_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 */
700int
701getenv_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 */
718int
719getenv_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
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 */
849error:
851 return (rc);
852}
853
854/*
855 * Return an integer value from an environment variable.
856 */
857int
858getenv_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 */
872int
873getenv_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 */
887int
888getenv_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 */
902int
903getenv_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 */
917int
918getenv_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 */
932int
933getenv_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 */
947int
948getenv_quad(const char *name, quad_t *data)
949{
950 const char *value;
951 char suffix, *vtp;
952 quad_t iv;
953
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];
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);
983error:
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 */
992int
993getenv_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 */
1024bool
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 */
1037bool
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 */
1051static char *
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
1065void
1067{
1068 struct tunable_int *d = (struct tunable_int *)data;
1069
1070 TUNABLE_INT_FETCH(d->path, d->var);
1071}
1072
1073void
1075{
1076 struct tunable_long *d = (struct tunable_long *)data;
1077
1078 TUNABLE_LONG_FETCH(d->path, d->var);
1079}
1080
1081void
1083{
1084 struct tunable_ulong *d = (struct tunable_ulong *)data;
1085
1086 TUNABLE_ULONG_FETCH(d->path, d->var);
1087}
1088
1089void
1091{
1092 struct tunable_int64 *d = (struct tunable_int64 *)data;
1093
1094 TUNABLE_INT64_FETCH(d->path, d->var);
1095}
1096
1097void
1099{
1100 struct tunable_uint64 *d = (struct tunable_uint64 *)data;
1101
1102 TUNABLE_UINT64_FETCH(d->path, d->var);
1103}
1104
1105void
1107{
1108 struct tunable_quad *d = (struct tunable_quad *)data;
1109
1110 TUNABLE_QUAD_FETCH(d->path, d->var);
1111}
1112
1113void
1115{
1116 struct tunable_bool *d = (struct tunable_bool *)data;
1117
1118 TUNABLE_BOOL_FETCH(d->path, d->var);
1119}
1120
1121void
1123{
1124 struct tunable_str *d = (struct tunable_str *)data;
1125
1126 TUNABLE_STR_FETCH(d->path, d->var, d->size);
1127}
const char * name
Definition: kern_fail.c:145
int getenv_bool(const char *name, bool *data)
char * md_envp
int getenv_array(const char *name, void *pdata, int size, int *psize, int type_size, bool allow_signed)
void init_static_kenv(char *buf, size_t len)
void tunable_quad_init(void *data)
static void init_dynamic_kenv_from(char *init_env, int *curpos)
static void init_dynamic_kenv(void *data __unused)
int getenv_ulong(const char *name, unsigned long *data)
bool getenv_is_true(const char *name)
SYSINIT(kenv, SI_SUB_KMEM+1, SI_ORDER_FIRST, init_dynamic_kenv, NULL)
int getenv_long(const char *name, long *data)
static char * _getenv_dynamic_locked(const char *name, int *idx)
void freeenv(char *env)
static char * kenv_acquire(const char *name)
char * kern_getenv(const char *name)
static void kenv_release(const char *buf)
struct mtx kenv_lock
int testenv(const char *name)
void tunable_ulong_init(void *data)
int getenv_string(const char *name, char *data, int size)
static char * kernenv_next(char *)
static int md_env_pos
int kern_setenv(const char *name, const char *value)
static char * _getenv_dynamic(const char *name, int *idx)
static char * _getenv_static(const char *name)
static int kenv_mvallen
void tunable_bool_init(void *data)
char * kern_envp
int getenv_quad(const char *name, quad_t *data)
int getenv_int(const char *name, int *data)
void tunable_int_init(void *data)
int getenv_uint64(const char *name, uint64_t *data)
static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment")
__FBSDID("$FreeBSD$")
#define KENV_SIZE
int getenv_int64(const char *name, int64_t *data)
bool dynamic_kenv
char ** kenvp
static int setenv_static(const char *name, const char *value)
static uma_zone_t kenv_zone
static char * _getenv_static_from(char *chkenv, const char *name)
bool getenv_is_false(const char *name)
static int md_env_len
void tunable_long_init(void *data)
int kern_unsetenv(const char *name)
void tunable_str_init(void *data)
int sys_kenv(struct thread *td, struct kenv_args *uap)
void tunable_uint64_init(void *data)
static int kenv_dump(struct thread *td, char **envp, int what, char *value, int len)
void tunable_int64_init(void *data)
int getenv_uint(const char *name, unsigned int *data)
#define KENV_CHECK
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
Definition: kern_malloc.c:632
void zfree(void *addr, struct malloc_type *mtp)
Definition: kern_malloc.c:947
void free(void *addr, struct malloc_type *mtp)
Definition: kern_malloc.c:907
int priv_check(struct thread *td, int priv)
Definition: kern_priv.c:271
caddr_t value
Definition: linker_if.m:63
uint32_t * data
Definition: msi_if.m:90
int printf(const char *fmt,...)
Definition: subr_prf.c:397
int sprintf(char *buf, const char *cfmt,...)
Definition: subr_prf.c:521
struct mtx mtx
Definition: uipc_ktls.c:0
struct stat * buf