source: rtems-libbsd/freebsd/sys/kern/kern_environment.c @ bceabc9

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since bceabc9 was bceabc9, checked in by Sebastian Huber <sebastian.huber@…>, on 10/09/13 at 20:42:09

Move files to match FreeBSD layout

  • Property mode set to 100644
File size: 11.7 KB
Line 
1#include <freebsd/machine/rtems-bsd-config.h>
2
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 getenv()/freeenv() setenv() unsetenv() testenv() for
36 * the kernel.
37 */
38
39#include <freebsd/sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42#include <freebsd/sys/types.h>
43#include <freebsd/sys/param.h>
44#include <freebsd/sys/proc.h>
45#include <freebsd/sys/queue.h>
46#include <freebsd/sys/lock.h>
47#include <freebsd/sys/malloc.h>
48#include <freebsd/sys/mutex.h>
49#include <freebsd/sys/priv.h>
50#include <freebsd/sys/kernel.h>
51#include <freebsd/sys/systm.h>
52#include <freebsd/sys/sysent.h>
53#include <freebsd/sys/sysproto.h>
54#include <freebsd/sys/libkern.h>
55#include <freebsd/sys/kenv.h>
56
57#include <freebsd/security/mac/mac_framework.h>
58
59static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
60
61#define KENV_SIZE       512     /* Maximum number of environment strings */
62
63/* pointer to the static environment */
64char            *kern_envp;
65static char     *kernenv_next(char *);
66
67/* dynamic environment variables */
68char            **kenvp;
69struct mtx      kenv_lock;
70
71/*
72 * No need to protect this with a mutex since SYSINITS are single threaded.
73 */
74int     dynamic_kenv = 0;
75
76#define KENV_CHECK      if (!dynamic_kenv) \
77                            panic("%s: called before SI_SUB_KMEM", __func__)
78#ifndef __rtems__
79int
80kenv(td, uap)
81        struct thread *td;
82        struct kenv_args /* {
83                int what;
84                const char *name;
85                char *value;
86                int len;
87        } */ *uap;
88{
89        char *name, *value, *buffer = NULL;
90        size_t len, done, needed, buflen;
91        int error, i;
92
93        KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = 0"));
94
95        error = 0;
96        if (uap->what == KENV_DUMP) {
97#ifdef MAC
98                error = mac_kenv_check_dump(td->td_ucred);
99                if (error)
100                        return (error);
101#endif
102                done = needed = 0;
103                buflen = uap->len;
104                if (buflen > KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2))
105                        buflen = KENV_SIZE * (KENV_MNAMELEN +
106                            KENV_MVALLEN + 2);
107                if (uap->len > 0 && uap->value != NULL)
108                        buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO);
109                mtx_lock(&kenv_lock);
110                for (i = 0; kenvp[i] != NULL; i++) {
111                        len = strlen(kenvp[i]) + 1;
112                        needed += len;
113                        len = min(len, buflen - done);
114                        /*
115                         * If called with a NULL or insufficiently large
116                         * buffer, just keep computing the required size.
117                         */
118                        if (uap->value != NULL && buffer != NULL && len > 0) {
119                                bcopy(kenvp[i], buffer + done, len);
120                                done += len;
121                        }
122                }
123                mtx_unlock(&kenv_lock);
124                if (buffer != NULL) {
125                        error = copyout(buffer, uap->value, done);
126                        free(buffer, M_TEMP);
127                }
128                td->td_retval[0] = ((done == needed) ? 0 : needed);
129                return (error);
130        }
131
132        switch (uap->what) {
133        case KENV_SET:
134                error = priv_check(td, PRIV_KENV_SET);
135                if (error)
136                        return (error);
137                break;
138
139        case KENV_UNSET:
140                error = priv_check(td, PRIV_KENV_UNSET);
141                if (error)
142                        return (error);
143                break;
144        }
145
146        name = malloc(KENV_MNAMELEN, M_TEMP, M_WAITOK);
147
148        error = copyinstr(uap->name, name, KENV_MNAMELEN, NULL);
149        if (error)
150                goto done;
151
152        switch (uap->what) {
153        case KENV_GET:
154#ifdef MAC
155                error = mac_kenv_check_get(td->td_ucred, name);
156                if (error)
157                        goto done;
158#endif
159                value = getenv(name);
160                if (value == NULL) {
161                        error = ENOENT;
162                        goto done;
163                }
164                len = strlen(value) + 1;
165                if (len > uap->len)
166                        len = uap->len;
167                error = copyout(value, uap->value, len);
168                freeenv(value);
169                if (error)
170                        goto done;
171                td->td_retval[0] = len;
172                break;
173        case KENV_SET:
174                len = uap->len;
175                if (len < 1) {
176                        error = EINVAL;
177                        goto done;
178                }
179                if (len > KENV_MVALLEN)
180                        len = KENV_MVALLEN;
181                value = malloc(len, M_TEMP, M_WAITOK);
182                error = copyinstr(uap->value, value, len, NULL);
183                if (error) {
184                        free(value, M_TEMP);
185                        goto done;
186                }
187#ifdef MAC
188                error = mac_kenv_check_set(td->td_ucred, name, value);
189                if (error == 0)
190#endif
191                        setenv(name, value);
192                free(value, M_TEMP);
193                break;
194        case KENV_UNSET:
195#ifdef MAC
196                error = mac_kenv_check_unset(td->td_ucred, name);
197                if (error)
198                        goto done;
199#endif
200                error = unsetenv(name);
201                if (error)
202                        error = ENOENT;
203                break;
204        default:
205                error = EINVAL;
206                break;
207        }
208done:
209        free(name, M_TEMP);
210        return (error);
211}
212
213/*
214 * Setup the dynamic kernel environment.
215 */
216static void
217init_dynamic_kenv(void *data __unused)
218{
219        char *cp;
220        int len, i;
221
222        kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
223                M_WAITOK | M_ZERO);
224        i = 0;
225        for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
226                len = strlen(cp) + 1;
227                if (i < KENV_SIZE) {
228                        kenvp[i] = malloc(len, M_KENV, M_WAITOK);
229                        strcpy(kenvp[i++], cp);
230                } else
231                        printf(
232                            "WARNING: too many kenv strings, ignoring %s\n",
233                            cp);
234        }
235        kenvp[i] = NULL;
236
237        mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
238        dynamic_kenv = 1;
239}
240SYSINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, init_dynamic_kenv, NULL);
241
242void
243freeenv(char *env)
244{
245
246        if (dynamic_kenv)
247                free(env, M_KENV);
248}
249
250/*
251 * Internal functions for string lookup.
252 */
253static char *
254_getenv_dynamic(const char *name, int *idx)
255{
256        char *cp;
257        int len, i;
258
259        mtx_assert(&kenv_lock, MA_OWNED);
260        len = strlen(name);
261        for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
262                if ((strncmp(cp, name, len) == 0) &&
263                    (cp[len] == '=')) {
264                        if (idx != NULL)
265                                *idx = i;
266                        return (cp + len + 1);
267                }
268        }
269        return (NULL);
270}
271
272static char *
273_getenv_static(const char *name)
274{
275        char *cp, *ep;
276        int len;
277
278        for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
279                for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
280                        ;
281                if (*ep != '=')
282                        continue;
283                len = ep - cp;
284                ep++;
285                if (!strncmp(name, cp, len) && name[len] == 0)
286                        return (ep);
287        }
288        return (NULL);
289}
290
291/*
292 * Look up an environment variable by name.
293 * Return a pointer to the string if found.
294 * The pointer has to be freed with freeenv()
295 * after use.
296 */
297char *
298getenv(const char *name)
299{
300        char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1];
301        char *ret, *cp;
302        int len;
303
304        if (dynamic_kenv) {
305                mtx_lock(&kenv_lock);
306                cp = _getenv_dynamic(name, NULL);
307                if (cp != NULL) {
308                        strcpy(buf, cp);
309                        mtx_unlock(&kenv_lock);
310                        len = strlen(buf) + 1;
311                        ret = malloc(len, M_KENV, M_WAITOK);
312                        strcpy(ret, buf);
313                } else {
314                        mtx_unlock(&kenv_lock);
315                        ret = NULL;
316                }
317        } else
318                ret = _getenv_static(name);
319        return (ret);
320}
321
322/*
323 * Test if an environment variable is defined.
324 */
325int
326testenv(const char *name)
327{
328        char *cp;
329
330        if (dynamic_kenv) {
331                mtx_lock(&kenv_lock);
332                cp = _getenv_dynamic(name, NULL);
333                mtx_unlock(&kenv_lock);
334        } else
335                cp = _getenv_static(name);
336        if (cp != NULL)
337                return (1);
338        return (0);
339}
340
341/*
342 * Set an environment variable by name.
343 */
344int
345setenv(const char *name, const char *value)
346{
347        char *buf, *cp, *oldenv;
348        int namelen, vallen, i;
349
350        KENV_CHECK;
351
352        namelen = strlen(name) + 1;
353        if (namelen > KENV_MNAMELEN)
354                return (-1);
355        vallen = strlen(value) + 1;
356        if (vallen > KENV_MVALLEN)
357                return (-1);
358        buf = malloc(namelen + vallen, M_KENV, M_WAITOK);
359        sprintf(buf, "%s=%s", name, value);
360
361        mtx_lock(&kenv_lock);
362        cp = _getenv_dynamic(name, &i);
363        if (cp != NULL) {
364                oldenv = kenvp[i];
365                kenvp[i] = buf;
366                mtx_unlock(&kenv_lock);
367                free(oldenv, M_KENV);
368        } else {
369                /* We add the option if it wasn't found */
370                for (i = 0; (cp = kenvp[i]) != NULL; i++)
371                        ;
372
373                /* Bounds checking */
374                if (i < 0 || i >= KENV_SIZE) {
375                        free(buf, M_KENV);
376                        mtx_unlock(&kenv_lock);
377                        return (-1);
378                }
379
380                kenvp[i] = buf;
381                kenvp[i + 1] = NULL;
382                mtx_unlock(&kenv_lock);
383        }
384        return (0);
385}
386
387/*
388 * Unset an environment variable string.
389 */
390int
391unsetenv(const char *name)
392{
393        char *cp, *oldenv;
394        int i, j;
395
396        KENV_CHECK;
397
398        mtx_lock(&kenv_lock);
399        cp = _getenv_dynamic(name, &i);
400        if (cp != NULL) {
401                oldenv = kenvp[i];
402                for (j = i + 1; kenvp[j] != NULL; j++)
403                        kenvp[i++] = kenvp[j];
404                kenvp[i] = NULL;
405                mtx_unlock(&kenv_lock);
406                free(oldenv, M_KENV);
407                return (0);
408        }
409        mtx_unlock(&kenv_lock);
410        return (-1);
411}
412
413/*
414 * Return a string value from an environment variable.
415 */
416int
417getenv_string(const char *name, char *data, int size)
418{
419        char *tmp;
420
421        tmp = getenv(name);
422        if (tmp != NULL) {
423                strlcpy(data, tmp, size);
424                freeenv(tmp);
425                return (1);
426        } else
427                return (0);
428}
429
430/*
431 * Return an integer value from an environment variable.
432 */
433int
434getenv_int(const char *name, int *data)
435{
436        quad_t tmp;
437        int rval;
438
439        rval = getenv_quad(name, &tmp);
440        if (rval)
441                *data = (int) tmp;
442        return (rval);
443}
444
445/*
446 * Return an unsigned integer value from an environment variable.
447 */
448int
449getenv_uint(const char *name, unsigned int *data)
450{
451        quad_t tmp;
452        int rval;
453
454        rval = getenv_quad(name, &tmp);
455        if (rval)
456                *data = (unsigned int) tmp;
457        return (rval);
458}
459
460/*
461 * Return a long value from an environment variable.
462 */
463int
464getenv_long(const char *name, long *data)
465{
466        quad_t tmp;
467        int rval;
468
469        rval = getenv_quad(name, &tmp);
470        if (rval)
471                *data = (long) tmp;
472        return (rval);
473}
474
475/*
476 * Return an unsigned long value from an environment variable.
477 */
478int
479getenv_ulong(const char *name, unsigned long *data)
480{
481        quad_t tmp;
482        int rval;
483
484        rval = getenv_quad(name, &tmp);
485        if (rval)
486                *data = (unsigned long) tmp;
487        return (rval);
488}
489
490/*
491 * Return a quad_t value from an environment variable.
492 */
493int
494getenv_quad(const char *name, quad_t *data)
495{
496        char    *value;
497        char    *vtp;
498        quad_t  iv;
499
500        value = getenv(name);
501        if (value == NULL)
502                return (0);
503        iv = strtoq(value, &vtp, 0);
504        if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
505                freeenv(value);
506                return (0);
507        }
508        switch (vtp[0]) {
509        case 't': case 'T':
510                iv *= 1024;
511        case 'g': case 'G':
512                iv *= 1024;
513        case 'm': case 'M':
514                iv *= 1024;
515        case 'k': case 'K':
516                iv *= 1024;
517        case '\0':
518                break;
519        default:
520                freeenv(value);
521                return (0);
522        }
523        *data = iv;
524        freeenv(value);
525        return (1);
526}
527
528/*
529 * Find the next entry after the one which (cp) falls within, return a
530 * pointer to its start or NULL if there are no more.
531 */
532static char *
533kernenv_next(char *cp)
534{
535
536        if (cp != NULL) {
537                while (*cp != 0)
538                        cp++;
539                cp++;
540                if (*cp == 0)
541                        cp = NULL;
542        }
543        return (cp);
544}
545
546void
547tunable_int_init(void *data)
548{
549        struct tunable_int *d = (struct tunable_int *)data;
550
551        TUNABLE_INT_FETCH(d->path, d->var);
552}
553
554void
555tunable_long_init(void *data)
556{
557        struct tunable_long *d = (struct tunable_long *)data;
558
559        TUNABLE_LONG_FETCH(d->path, d->var);
560}
561
562void
563tunable_ulong_init(void *data)
564{
565        struct tunable_ulong *d = (struct tunable_ulong *)data;
566
567        TUNABLE_ULONG_FETCH(d->path, d->var);
568}
569
570void
571tunable_quad_init(void *data)
572{
573        struct tunable_quad *d = (struct tunable_quad *)data;
574
575        TUNABLE_QUAD_FETCH(d->path, d->var);
576}
577
578void
579tunable_str_init(void *data)
580{
581        struct tunable_str *d = (struct tunable_str *)data;
582
583        TUNABLE_STR_FETCH(d->path, d->var, d->size);
584}
585#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.