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