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
26 * $FreeBSD: src/sys/kern/kern_environment.c,v 1.10.2.7 2002/05/07 09:57:16 bde Exp $
30 * The unified bootloader passes us a pointer to a preserved copy of
31 * bootstrap/kernel environment variables. We convert them to a dynamic array
32 * of strings later when the VM subsystem is up.
33 * We make these available using sysctl for both in-kernel and
34 * out-of-kernel consumers, as well as the k{get,set,unset,free,test}env()
35 * functions for in-kernel consumers.
37 * Note that the current sysctl infrastructure doesn't allow
38 * dynamic insertion or traversal through handled spaces. Grr.
40 * TODO: implement a sysctl handler to provide the functionality mentioned
44 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/libkern.h>
48 #include <sys/malloc.h>
50 #include <sys/spinlock.h>
51 #include <sys/spinlock2.h>
52 #include <sys/sysproto.h>
53 #include <sys/systm.h>
54 #include <sys/sysctl.h>
56 /* exported variables */
57 char *kern_envp
; /* <sys/systm.h> */
62 struct spinlock kenv_dynlock
;
65 MALLOC_DEFINE(M_KENV
, "kenv", "kernel environment dynamic storage");
66 #define KENV_DYNMAXNUM 512
68 /* local prototypes */
69 static char *kenv_getstring_dynamic(const char *name
, int *idx
);
70 static char *kenv_getstring_static(const char *name
);
71 static char *kernenv_next(char *cp
);
74 sys_kenv(struct kenv_args
*uap
)
76 char *name
, *value
, *buffer
= NULL
;
77 size_t len
, done
, needed
, buflen
;
80 KASSERT(kenv_isdynamic
, ("kenv: kenv_isdynamic = 0"));
83 if (uap
->what
== KENV_DUMP
) {
86 if (buflen
> KENV_DYNMAXNUM
* (KENV_MNAMELEN
+ KENV_MVALLEN
+ 2))
87 buflen
= KENV_DYNMAXNUM
*
88 (KENV_MNAMELEN
+ KENV_MVALLEN
+ 2);
89 if (uap
->len
> 0 && uap
->value
!= NULL
)
90 buffer
= kmalloc(buflen
, M_TEMP
, M_WAITOK
|M_ZERO
);
91 spin_lock(&kenv_dynlock
);
92 for (i
= 0; kenv_dynp
[i
] != NULL
; i
++) {
93 len
= strlen(kenv_dynp
[i
]) + 1;
95 len
= min(len
, buflen
- done
);
97 * If called with a NULL or insufficiently large
98 * buffer, just keep computing the required size.
100 if (uap
->value
!= NULL
&& buffer
!= NULL
&& len
> 0) {
101 bcopy(kenv_dynp
[i
], buffer
+ done
, len
);
105 spin_unlock(&kenv_dynlock
);
106 if (buffer
!= NULL
) {
107 error
= copyout(buffer
, uap
->value
, done
);
108 kfree(buffer
, M_TEMP
);
110 uap
->sysmsg_result
= ((done
== needed
) ? 0 : needed
);
116 error
= priv_check(curthread
, PRIV_KENV_SET
);
122 error
= priv_check(curthread
, PRIV_KENV_UNSET
);
128 name
= kmalloc(KENV_MNAMELEN
+ 1, M_TEMP
, M_WAITOK
);
130 error
= copyinstr(uap
->name
, name
, KENV_MNAMELEN
+ 1, NULL
);
136 value
= kgetenv(name
);
141 len
= strlen(value
) + 1;
144 error
= copyout(value
, uap
->value
, len
);
148 uap
-> sysmsg_result
= len
;
156 if (len
> KENV_MVALLEN
+ 1)
157 len
= KENV_MVALLEN
+ 1;
158 value
= kmalloc(len
, M_TEMP
, M_WAITOK
);
159 error
= copyinstr(uap
->value
, value
, len
, NULL
);
161 kfree(value
, M_TEMP
);
164 ksetenv(name
, value
);
165 kfree(value
, M_TEMP
);
168 error
= kunsetenv(name
);
182 * Look up a string in the dynamic environment array. Must be called with
186 kenv_getstring_dynamic(const char *name
, int *idx
)
192 /* note: kunsetenv() never leaves NULL holes in the array */
193 for (i
= 0; (cp
= kenv_dynp
[i
]) != NULL
; i
++) {
194 if ((strncmp(cp
, name
, len
) == 0) && (cp
[len
] == '=')) {
197 return(cp
+ len
+ 1);
204 * Look up a string in the static environment array.
207 kenv_getstring_static(const char *name
)
212 for (cp
= kern_envp
; cp
!= NULL
; cp
= kernenv_next(cp
)) {
213 for (ep
= cp
; (*ep
!= '=') && (*ep
!= 0); ep
++)
219 if (!strncmp(name
, cp
, len
) && name
[len
] == 0)
226 * Look up an environment variable by name.
229 kgetenv(const char *name
)
231 char buf
[KENV_MNAMELEN
+ 1 + KENV_MVALLEN
+ 1];
235 if (kenv_isdynamic
) {
236 spin_lock(&kenv_dynlock
);
237 cp
= kenv_getstring_dynamic(name
, NULL
);
240 spin_unlock(&kenv_dynlock
);
241 len
= strlen(buf
) + 1;
242 ret
= kmalloc(len
, M_KENV
, M_WAITOK
);
245 spin_unlock(&kenv_dynlock
);
249 ret
= kenv_getstring_static(name
);
254 * Set an environment variable by name.
257 ksetenv(const char *name
, const char *value
)
259 char *cp
, *buf
, *oldenv
;
260 int namelen
, vallen
, i
;
262 if (kenv_isdynamic
) {
263 namelen
= strlen(name
) + 1;
264 vallen
= strlen(value
) + 1;
265 if ((namelen
> KENV_MNAMELEN
) || (vallen
> KENV_MVALLEN
))
267 buf
= kmalloc(namelen
+ vallen
, M_KENV
, M_WAITOK
);
268 ksprintf(buf
, "%s=%s", name
, value
);
269 spin_lock(&kenv_dynlock
);
270 cp
= kenv_getstring_dynamic(name
, &i
);
272 /* replace existing environment variable */
273 oldenv
= kenv_dynp
[i
];
275 spin_unlock(&kenv_dynlock
);
276 kfree(oldenv
, M_KENV
);
278 /* append new environment variable */
279 for (i
= 0; (cp
= kenv_dynp
[i
]) != NULL
; i
++)
281 /* bounds checking */
282 if (i
< 0 || i
>= (KENV_DYNMAXNUM
- 1)) {
284 spin_unlock(&kenv_dynlock
);
288 kenv_dynp
[i
+ 1] = NULL
;
289 spin_unlock(&kenv_dynlock
);
293 kprintf("WARNING: ksetenv: dynamic array not created yet\n");
299 * Unset an environment variable by name.
302 kunsetenv(const char *name
)
307 if (kenv_isdynamic
) {
308 spin_lock(&kenv_dynlock
);
309 cp
= kenv_getstring_dynamic(name
, &i
);
311 oldenv
= kenv_dynp
[i
];
312 /* move all pointers beyond the unset one down 1 step */
313 for (j
= i
+ 1; kenv_dynp
[j
] != NULL
; j
++)
314 kenv_dynp
[i
++] = kenv_dynp
[j
];
316 spin_unlock(&kenv_dynlock
);
317 kfree(oldenv
, M_KENV
);
320 spin_unlock(&kenv_dynlock
);
323 kprintf("WARNING: kunsetenv: dynamic array not created yet\n");
329 * Free an environment variable that has been copied for a consumer.
339 * Test if an environment variable is defined.
342 ktestenv(const char *name
)
346 if (kenv_isdynamic
) {
347 spin_lock(&kenv_dynlock
);
348 cp
= kenv_getstring_dynamic(name
, NULL
);
349 spin_unlock(&kenv_dynlock
);
351 cp
= kenv_getstring_static(name
);
358 * Return a string value from an environment variable.
361 kgetenv_string(const char *name
, char *data
, int size
)
367 strncpy(data
, tmp
, size
);
376 * Return an integer value from an environment variable.
379 kgetenv_int(const char *name
, int *data
)
384 rval
= kgetenv_quad(name
, &tmp
);
391 * Return a long value from an environment variable.
394 kgetenv_long(const char *name
, long *data
)
399 rval
= kgetenv_quad(name
, &tmp
);
406 * Return an unsigned long value from an environment variable.
409 kgetenv_ulong(const char *name
, unsigned long *data
)
414 rval
= kgetenv_quad(name
, &tmp
);
416 *data
= (unsigned long) tmp
;
421 * Return a quad_t value from an environment variable.
423 * A single character kmgtKMGT extension multiplies the value
424 * by 1024, 1024*1024, etc.
427 kgetenv_quad(const char *name
, quad_t
*data
)
433 if ((value
= kgetenv(name
)) == NULL
)
436 iv
= strtoq(value
, &vtp
, 0);
459 if ((vtp
== value
) || (*vtp
!= '\0')) {
470 * Boottime (static) kernel environment sysctl handler.
473 sysctl_kenv_boot(SYSCTL_HANDLER_ARGS
)
475 int *name
= (int *)arg1
;
476 u_int namelen
= arg2
;
480 if (kern_envp
== NULL
)
490 for (i
= 0; i
< name
[0]; i
++) {
491 cp
= kernenv_next(cp
);
499 error
= SYSCTL_OUT(req
, cp
, strlen(cp
) + 1);
503 SYSCTL_NODE(_kern
, OID_AUTO
, environment
, CTLFLAG_RD
, sysctl_kenv_boot
,
504 "boottime (static) kernel environment space");
507 * Find the next entry after the one which (cp) falls within, return a
508 * pointer to its start or NULL if there are no more.
511 kernenv_next(char *cp
)
524 * TUNABLE_INT init functions.
527 tunable_int_init(void *data
)
529 struct tunable_int
*d
= (struct tunable_int
*)data
;
531 TUNABLE_INT_FETCH(d
->path
, d
->var
);
535 tunable_long_init(void *data
)
537 struct tunable_long
*d
= (struct tunable_long
*)data
;
539 TUNABLE_LONG_FETCH(d
->path
, d
->var
);
543 tunable_ulong_init(void *data
)
545 struct tunable_ulong
*d
= (struct tunable_ulong
*)data
;
547 TUNABLE_ULONG_FETCH(d
->path
, d
->var
);
551 tunable_quad_init(void *data
)
553 struct tunable_quad
*d
= (struct tunable_quad
*)data
;
555 TUNABLE_QUAD_FETCH(d
->path
, d
->var
);
559 tunable_str_init(void *data
)
561 struct tunable_str
*d
= (struct tunable_str
*)data
;
563 TUNABLE_STR_FETCH(d
->path
, d
->var
, d
->size
);
567 * Create the dynamic environment array, and copy in the values from the static
568 * environment as passed by the bootloader.
571 kenv_init(void *dummy
)
576 kenv_dynp
= kmalloc(KENV_DYNMAXNUM
* sizeof(char *), M_KENV
,
579 /* copy the static environment to our dynamic environment */
580 for (i
= 0, cp
= kern_envp
; cp
!= NULL
; cp
= kernenv_next(cp
)) {
581 len
= strlen(cp
) + 1;
582 if (i
< (KENV_DYNMAXNUM
- 1)) {
583 kenv_dynp
[i
] = kmalloc(len
, M_KENV
, M_WAITOK
);
584 strcpy(kenv_dynp
[i
++], cp
);
586 kprintf("WARNING: kenv: exhausted dynamic storage, "
587 "ignoring string %s\n", cp
);
591 spin_init(&kenv_dynlock
, "kenvdynlock");
594 SYSINIT(kenv
, SI_BOOT1_POST
, SI_ORDER_ANY
, kenv_init
, NULL
);