2 * Copyright (c) 1998 Michael Smith
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * The unified bootloader passes us a pointer to a preserved copy of
29 * bootstrap/kernel environment variables. We convert them to a
30 * dynamic array of strings later when the VM subsystem is up.
32 * We make these available through the kenv(2) syscall for userland
33 * and through getenv()/freeenv() setenv() unsetenv() testenv() for
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
42 #include <sys/types.h>
43 #include <sys/param.h>
45 #include <sys/queue.h>
47 #include <sys/malloc.h>
48 #include <sys/mutex.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>
57 #include <security/mac/mac_framework.h>
59 static MALLOC_DEFINE(M_KENV
, "kenv", "kernel environment");
61 #define KENV_SIZE 512 /* Maximum number of environment strings */
63 /* pointer to the static environment */
65 static char *kernenv_next(char *);
67 /* dynamic environment variables */
72 * No need to protect this with a mutex since SYSINITS are single threaded.
76 #define KENV_CHECK if (!dynamic_kenv) \
77 panic("%s: called before SI_SUB_KMEM", __func__)
89 char *name
, *value
, *buffer
= NULL
;
90 size_t len
, done
, needed
;
93 KASSERT(dynamic_kenv
, ("kenv: dynamic_kenv = 0"));
96 if (uap
->what
== KENV_DUMP
) {
98 error
= mac_kenv_check_dump(td
->td_ucred
);
103 if (uap
->len
> 0 && uap
->value
!= NULL
)
104 buffer
= malloc(uap
->len
, M_TEMP
, M_WAITOK
|M_ZERO
);
105 mtx_lock(&kenv_lock
);
106 for (i
= 0; kenvp
[i
] != NULL
; i
++) {
107 len
= strlen(kenvp
[i
]) + 1;
109 len
= min(len
, uap
->len
- done
);
111 * If called with a NULL or insufficiently large
112 * buffer, just keep computing the required size.
114 if (uap
->value
!= NULL
&& buffer
!= NULL
&& len
> 0) {
115 bcopy(kenvp
[i
], buffer
+ done
, len
);
119 mtx_unlock(&kenv_lock
);
120 if (buffer
!= NULL
) {
121 error
= copyout(buffer
, uap
->value
, done
);
122 free(buffer
, M_TEMP
);
124 td
->td_retval
[0] = ((done
== needed
) ? 0 : needed
);
130 error
= priv_check(td
, PRIV_KENV_SET
);
136 error
= priv_check(td
, PRIV_KENV_UNSET
);
142 name
= malloc(KENV_MNAMELEN
, M_TEMP
, M_WAITOK
);
144 error
= copyinstr(uap
->name
, name
, KENV_MNAMELEN
, NULL
);
151 error
= mac_kenv_check_get(td
->td_ucred
, name
);
155 value
= getenv(name
);
160 len
= strlen(value
) + 1;
163 error
= copyout(value
, uap
->value
, len
);
167 td
->td_retval
[0] = len
;
175 if (len
> KENV_MVALLEN
)
177 value
= malloc(len
, M_TEMP
, M_WAITOK
);
178 error
= copyinstr(uap
->value
, value
, len
, NULL
);
184 error
= mac_kenv_check_set(td
->td_ucred
, name
, value
);
192 error
= mac_kenv_check_unset(td
->td_ucred
, name
);
196 error
= unsetenv(name
);
210 * Setup the dynamic kernel environment.
213 init_dynamic_kenv(void *data __unused
)
218 kenvp
= malloc((KENV_SIZE
+ 1) * sizeof(char *), M_KENV
,
221 for (cp
= kern_envp
; cp
!= NULL
; cp
= kernenv_next(cp
)) {
222 len
= strlen(cp
) + 1;
224 kenvp
[i
] = malloc(len
, M_KENV
, M_WAITOK
);
225 strcpy(kenvp
[i
++], cp
);
228 "WARNING: too many kenv strings, ignoring %s\n",
233 mtx_init(&kenv_lock
, "kernel environment", NULL
, MTX_DEF
);
236 SYSINIT(kenv
, SI_SUB_KMEM
, SI_ORDER_ANY
, init_dynamic_kenv
, NULL
);
247 * Internal functions for string lookup.
250 _getenv_dynamic(const char *name
, int *idx
)
255 mtx_assert(&kenv_lock
, MA_OWNED
);
257 for (cp
= kenvp
[0], i
= 0; cp
!= NULL
; cp
= kenvp
[++i
]) {
258 if ((strncmp(cp
, name
, len
) == 0) &&
262 return (cp
+ len
+ 1);
269 _getenv_static(const char *name
)
274 for (cp
= kern_envp
; cp
!= NULL
; cp
= kernenv_next(cp
)) {
275 for (ep
= cp
; (*ep
!= '=') && (*ep
!= 0); ep
++)
281 if (!strncmp(name
, cp
, len
) && name
[len
] == 0)
288 * Look up an environment variable by name.
289 * Return a pointer to the string if found.
290 * The pointer has to be freed with freeenv()
294 getenv(const char *name
)
296 char buf
[KENV_MNAMELEN
+ 1 + KENV_MVALLEN
+ 1];
301 mtx_lock(&kenv_lock
);
302 cp
= _getenv_dynamic(name
, NULL
);
305 mtx_unlock(&kenv_lock
);
306 len
= strlen(buf
) + 1;
307 ret
= malloc(len
, M_KENV
, M_WAITOK
);
310 mtx_unlock(&kenv_lock
);
314 ret
= _getenv_static(name
);
319 * Test if an environment variable is defined.
322 testenv(const char *name
)
327 mtx_lock(&kenv_lock
);
328 cp
= _getenv_dynamic(name
, NULL
);
329 mtx_unlock(&kenv_lock
);
331 cp
= _getenv_static(name
);
338 * Set an environment variable by name.
341 setenv(const char *name
, const char *value
)
343 char *buf
, *cp
, *oldenv
;
344 int namelen
, vallen
, i
;
348 namelen
= strlen(name
) + 1;
349 if (namelen
> KENV_MNAMELEN
)
351 vallen
= strlen(value
) + 1;
352 if (vallen
> KENV_MVALLEN
)
354 buf
= malloc(namelen
+ vallen
, M_KENV
, M_WAITOK
);
355 sprintf(buf
, "%s=%s", name
, value
);
357 mtx_lock(&kenv_lock
);
358 cp
= _getenv_dynamic(name
, &i
);
362 mtx_unlock(&kenv_lock
);
363 free(oldenv
, M_KENV
);
365 /* We add the option if it wasn't found */
366 for (i
= 0; (cp
= kenvp
[i
]) != NULL
; i
++)
369 /* Bounds checking */
370 if (i
< 0 || i
>= KENV_SIZE
) {
372 mtx_unlock(&kenv_lock
);
378 mtx_unlock(&kenv_lock
);
384 * Unset an environment variable string.
387 unsetenv(const char *name
)
394 mtx_lock(&kenv_lock
);
395 cp
= _getenv_dynamic(name
, &i
);
398 for (j
= i
+ 1; kenvp
[j
] != NULL
; j
++)
399 kenvp
[i
++] = kenvp
[j
];
401 mtx_unlock(&kenv_lock
);
402 free(oldenv
, M_KENV
);
405 mtx_unlock(&kenv_lock
);
410 * Return a string value from an environment variable.
413 getenv_string(const char *name
, char *data
, int size
)
419 strlcpy(data
, tmp
, size
);
427 * Return an integer value from an environment variable.
430 getenv_int(const char *name
, int *data
)
435 rval
= getenv_quad(name
, &tmp
);
442 * Return an unsigned integer value from an environment variable.
445 getenv_uint(const char *name
, unsigned int *data
)
450 rval
= getenv_quad(name
, &tmp
);
452 *data
= (unsigned int) tmp
;
457 * Return a long value from an environment variable.
460 getenv_long(const char *name
, long *data
)
465 rval
= getenv_quad(name
, &tmp
);
472 * Return an unsigned long value from an environment variable.
475 getenv_ulong(const char *name
, unsigned long *data
)
480 rval
= getenv_quad(name
, &tmp
);
482 *data
= (unsigned long) tmp
;
487 * Return a quad_t value from an environment variable.
490 getenv_quad(const char *name
, quad_t
*data
)
496 value
= getenv(name
);
499 iv
= strtoq(value
, &vtp
, 0);
500 if (vtp
== value
|| (vtp
[0] != '\0' && vtp
[1] != '\0')) {
525 * Find the next entry after the one which (cp) falls within, return a
526 * pointer to its start or NULL if there are no more.
529 kernenv_next(char *cp
)
543 tunable_int_init(void *data
)
545 struct tunable_int
*d
= (struct tunable_int
*)data
;
547 TUNABLE_INT_FETCH(d
->path
, d
->var
);
551 tunable_long_init(void *data
)
553 struct tunable_long
*d
= (struct tunable_long
*)data
;
555 TUNABLE_LONG_FETCH(d
->path
, d
->var
);
559 tunable_ulong_init(void *data
)
561 struct tunable_ulong
*d
= (struct tunable_ulong
*)data
;
563 TUNABLE_ULONG_FETCH(d
->path
, d
->var
);
567 tunable_quad_init(void *data
)
569 struct tunable_quad
*d
= (struct tunable_quad
*)data
;
571 TUNABLE_QUAD_FETCH(d
->path
, d
->var
);
575 tunable_str_init(void *data
)
577 struct tunable_str
*d
= (struct tunable_str
*)data
;
579 TUNABLE_STR_FETCH(d
->path
, d
->var
, d
->size
);