kern_environment.c revision 95467
140090Smsmith/*- 240090Smsmith * Copyright (c) 1998 Michael Smith 340090Smsmith * All rights reserved. 440090Smsmith * 540090Smsmith * Redistribution and use in source and binary forms, with or without 640090Smsmith * modification, are permitted provided that the following conditions 740090Smsmith * are met: 840090Smsmith * 1. Redistributions of source code must retain the above copyright 940090Smsmith * notice, this list of conditions and the following disclaimer. 1040090Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1140090Smsmith * notice, this list of conditions and the following disclaimer in the 1240090Smsmith * documentation and/or other materials provided with the distribution. 1340090Smsmith * 1440090Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1540090Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1640090Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1740090Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1840090Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1940090Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2040090Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2140090Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2240090Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2340090Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2440090Smsmith * SUCH DAMAGE. 2540090Smsmith * 2650477Speter * $FreeBSD: head/sys/kern/kern_environment.c 95467 2002-04-25 20:25:15Z bde $ 2740116Sjkh */ 2840090Smsmith 2940090Smsmith/* 3040090Smsmith * The unified bootloader passes us a pointer to a preserved copy of 3194936Smux * bootstrap/kernel environment variables. We convert them to a 3294936Smux * dynamic array of strings later when the VM subsystem is up. 3340090Smsmith * 3494936Smux * We make these available through the kenv(2) syscall for userland 3594936Smux * and through getenv()/freeenv() setenv() unsetenv() testenv() for 3694936Smux * the kernel. 3740090Smsmith */ 3840090Smsmith 3994936Smux#include <sys/types.h> 4040090Smsmith#include <sys/param.h> 4194936Smux#include <sys/proc.h> 4294936Smux#include <sys/queue.h> 4394936Smux#include <sys/lock.h> 4494936Smux#include <sys/malloc.h> 4594936Smux#include <sys/mutex.h> 4640090Smsmith#include <sys/kernel.h> 4794936Smux#include <sys/sx.h> 4840090Smsmith#include <sys/systm.h> 4994936Smux#include <sys/sysent.h> 5094936Smux#include <sys/sysproto.h> 5140090Smsmith#include <sys/libkern.h> 5294936Smux#include <sys/kenv.h> 5340090Smsmith 5494936SmuxMALLOC_DEFINE(M_KENV, "kenv", "kernel environment"); 5540090Smsmith 5694936Smux#define KENV_SIZE 512 /* Maximum number of environment strings */ 5740090Smsmith 5894936Smux/* pointer to the static environment */ 5994936Smuxchar *kern_envp; 6094936Smuxstatic char *kernenv_next(char *); 6194936Smux 6294936Smux/* dynamic environment variables */ 6394936Smuxchar **kenvp; 6494936Smuxstruct sx kenv_lock; 6594936Smux 6685385Sjhb/* 6794936Smux * No need to protect this with a mutex 6894936Smux * since SYSINITS are single threaded. 6994936Smux */ 7094936Smuxint dynamic_kenv = 0; 7194936Smux 7294936Smux#define KENV_CHECK if (!dynamic_kenv) \ 7394936Smux panic("%s: called before SI_SUB_KMEM", __func__) 7494936Smux 7594936Smuxint 7694936Smuxkenv(td, uap) 7794936Smux struct thread *td; 7894936Smux struct kenv_args /* { 7994936Smux syscallarg(int) what; 8094936Smux syscallarg(const char *) name; 8194936Smux syscallarg(char *) value; 8294936Smux syscallarg(int) len; 8394936Smux } */ *uap; 8494936Smux{ 8594936Smux char *name, *value; 8694936Smux size_t len, done; 8794936Smux int error, i; 8894936Smux 8994936Smux KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = 0")); 9094936Smux 9194936Smux error = 0; 9294936Smux if (SCARG(uap, what) == KENV_DUMP) { 9394936Smux len = 0; 9494936Smux /* Return the size if called with a NULL buffer */ 9594936Smux if (SCARG(uap, value) == NULL) { 9694936Smux sx_slock(&kenv_lock); 9794936Smux for (i = 0; kenvp[i] != NULL; i++) 9894936Smux len += strlen(kenvp[i]) + 1; 9994936Smux sx_sunlock(&kenv_lock); 10094936Smux td->td_retval[0] = len; 10194936Smux return (0); 10294936Smux } 10394936Smux done = 0; 10494936Smux sx_slock(&kenv_lock); 10594936Smux for (i = 0; kenvp[i] != NULL && done < SCARG(uap, len); i++) { 10694936Smux len = min(strlen(kenvp[i]) + 1, SCARG(uap, len) - done); 10794936Smux error = copyout(kenvp[i], SCARG(uap, value) + done, 10894936Smux len); 10994936Smux if (error) { 11094936Smux sx_sunlock(&kenv_lock); 11194936Smux return (error); 11294936Smux } 11394936Smux done += len; 11494936Smux } 11594936Smux sx_sunlock(&kenv_lock); 11694936Smux return (0); 11794936Smux } 11894936Smux 11994936Smux if ((SCARG(uap, what) == KENV_SET) || 12094936Smux (SCARG(uap, what) == KENV_UNSET)) { 12194936Smux error = suser(td); 12294936Smux if (error) 12394936Smux return (error); 12494936Smux } 12594936Smux 12694936Smux name = malloc(KENV_MNAMELEN, M_TEMP, M_WAITOK); 12794936Smux 12894936Smux error = copyinstr(SCARG(uap, name), name, KENV_MNAMELEN, NULL); 12994936Smux if (error) 13094936Smux goto done; 13194936Smux 13294936Smux switch (SCARG(uap, what)) { 13394936Smux case KENV_GET: 13494936Smux value = getenv(name); 13594936Smux if (value == NULL) { 13694936Smux error = ENOENT; 13794936Smux goto done; 13894936Smux } 13994936Smux len = strlen(value) + 1; 14094936Smux if (len > SCARG(uap, len)) 14194936Smux len = SCARG(uap, len); 14294936Smux error = copyout(value, SCARG(uap, value), len); 14394936Smux freeenv(value); 14494936Smux if (error) 14594936Smux goto done; 14694936Smux td->td_retval[0] = len; 14794936Smux break; 14894936Smux case KENV_SET: 14994936Smux len = SCARG(uap, len); 15094936Smux if (len < 1) { 15194936Smux error = EINVAL; 15294936Smux goto done; 15394936Smux } 15494936Smux if (len > KENV_MVALLEN) 15594936Smux len = KENV_MVALLEN; 15694936Smux value = malloc(len, M_TEMP, M_WAITOK); 15794936Smux error = copyinstr(SCARG(uap, value), value, len, NULL); 15894936Smux if (error) { 15994936Smux free(value, M_TEMP); 16094936Smux goto done; 16194936Smux } 16294936Smux setenv(name, value); 16394936Smux free(value, M_TEMP); 16494936Smux break; 16594936Smux case KENV_UNSET: 16694936Smux error = unsetenv(name); 16794936Smux if (error) 16894936Smux error = ENOENT; 16994936Smux break; 17094936Smux default: 17194936Smux error = EINVAL; 17294936Smux break; 17394936Smux } 17494936Smuxdone: 17594936Smux free(name, M_TEMP); 17694936Smux return (error); 17794936Smux} 17894936Smux 17994936Smux/* 18094936Smux * Setup the dynamic kernel environment. 18194936Smux */ 18294936Smuxstatic void 18394936Smuxinit_dynamic_kenv(void *data __unused) 18494936Smux{ 18594936Smux char *cp; 18694936Smux int len, i; 18794936Smux 18894936Smux kenvp = malloc(KENV_SIZE * sizeof(char *), M_KENV, M_WAITOK | M_ZERO); 18994936Smux i = 0; 19094936Smux for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { 19194936Smux len = strlen(cp) + 1; 19294936Smux kenvp[i] = malloc(len, M_KENV, M_WAITOK); 19394936Smux strcpy(kenvp[i++], cp); 19494936Smux } 19594936Smux kenvp[i] = NULL; 19694936Smux 19794936Smux sx_init(&kenv_lock, "kernel environment"); 19894936Smux dynamic_kenv = 1; 19994936Smux} 20094936SmuxSYSINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, init_dynamic_kenv, NULL); 20194936Smux 20294936Smuxvoid 20394936Smuxfreeenv(char *env) 20494936Smux{ 20594936Smux 20694936Smux if (dynamic_kenv) 20794936Smux free(env, M_KENV); 20894936Smux} 20994936Smux 21094936Smux/* 21194936Smux * Internal functions for string lookup. 21294936Smux */ 21394936Smuxstatic char * 21494936Smux_getenv_dynamic(const char *name, int *idx) 21594936Smux{ 21694936Smux char *cp; 21794936Smux int len, i; 21894936Smux 21994936Smux sx_assert(&kenv_lock, SX_LOCKED); 22094936Smux len = strlen(name); 22194936Smux for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) { 22294936Smux if ((cp[len] == '=') && 22394936Smux (strncmp(cp, name, len) == 0)) { 22494936Smux if (idx != NULL) 22594936Smux *idx = i; 22694936Smux return (cp + len + 1); 22794936Smux } 22894936Smux } 22994936Smux return (NULL); 23094936Smux} 23194936Smux 23294936Smuxstatic char * 23394936Smux_getenv_static(const char *name) 23494936Smux{ 23594936Smux char *cp, *ep; 23694936Smux int len; 23794936Smux 23894936Smux for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { 23994936Smux for (ep = cp; (*ep != '=') && (*ep != 0); ep++) 24094936Smux ; 24195467Sbde if (*ep != '=') 24295467Sbde continue; 24394936Smux len = ep - cp; 24495467Sbde ep++; 24595467Sbde if (!strncmp(name, cp, len) && name[len] == 0) 24694936Smux return (ep); 24794936Smux } 24894936Smux return (NULL); 24994936Smux} 25094936Smux 25194936Smux/* 25285385Sjhb * Look up an environment variable by name. 25394936Smux * Return a pointer to the string if found. 25494936Smux * The pointer has to be freed with freeenv() 25594936Smux * after use. 25685385Sjhb */ 25740090Smsmithchar * 25878247Spetergetenv(const char *name) 25940090Smsmith{ 26094959Smux char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1]; 26194936Smux char *ret, *cp; 26294936Smux int len; 26394936Smux 26494936Smux if (dynamic_kenv) { 26594936Smux sx_slock(&kenv_lock); 26694936Smux cp = _getenv_dynamic(name, NULL); 26794936Smux if (cp != NULL) { 26894959Smux strcpy(buf, cp); 26994959Smux sx_sunlock(&kenv_lock); 27094959Smux len = strlen(buf) + 1; 27194936Smux ret = malloc(len, M_KENV, M_WAITOK); 27294959Smux strcpy(ret, buf); 27394959Smux } else { 27494959Smux sx_sunlock(&kenv_lock); 27594936Smux ret = NULL; 27694959Smux } 27794936Smux } else 27894936Smux ret = _getenv_static(name); 27994936Smux return (ret); 28040090Smsmith} 28140090Smsmith 28242706Smsmith/* 28394936Smux * Test if an environment variable is defined. 28494936Smux */ 28594936Smuxint 28694936Smuxtestenv(const char *name) 28794936Smux{ 28894936Smux char *cp; 28994936Smux 29094936Smux if (dynamic_kenv) { 29194936Smux sx_slock(&kenv_lock); 29294936Smux cp = _getenv_dynamic(name, NULL); 29394936Smux sx_sunlock(&kenv_lock); 29494936Smux } else 29594936Smux cp = _getenv_static(name); 29694936Smux if (cp != NULL) 29794936Smux return (1); 29894936Smux return (0); 29994936Smux} 30094936Smux 30194936Smux/* 30294936Smux * Set an environment variable by name. 30394936Smux */ 30494959Smuxint 30594936Smuxsetenv(const char *name, const char *value) 30694936Smux{ 30794959Smux char *buf, *cp, *oldenv; 30894959Smux int namelen, vallen, i; 30994936Smux 31094936Smux KENV_CHECK; 31194936Smux 31294959Smux namelen = strlen(name) + 1; 31394959Smux if (namelen > KENV_MNAMELEN) 31494959Smux return (-1); 31594959Smux vallen = strlen(value) + 1; 31694959Smux if (vallen > KENV_MVALLEN) 31794959Smux return (-1); 31894959Smux buf = malloc(namelen + vallen, M_KENV, M_WAITOK); 31994936Smux sprintf(buf, "%s=%s", name, value); 32094936Smux 32194936Smux sx_xlock(&kenv_lock); 32294936Smux cp = _getenv_dynamic(name, &i); 32394936Smux if (cp != NULL) { 32494959Smux oldenv = kenvp[i]; 32594936Smux kenvp[i] = buf; 32694959Smux sx_xunlock(&kenv_lock); 32794959Smux free(oldenv, M_KENV); 32894936Smux } else { 32994936Smux /* We add the option if it wasn't found */ 33094936Smux for (i = 0; (cp = kenvp[i]) != NULL; i++) 33194936Smux ; 33294936Smux kenvp[i] = buf; 33394936Smux kenvp[i + 1] = NULL; 33494959Smux sx_xunlock(&kenv_lock); 33594936Smux } 33694959Smux return (0); 33794936Smux} 33894936Smux 33994936Smux/* 34094936Smux * Unset an environment variable string. 34194936Smux */ 34294936Smuxint 34394936Smuxunsetenv(const char *name) 34494936Smux{ 34594959Smux char *cp, *oldenv; 34694936Smux int i, j; 34794936Smux 34894936Smux KENV_CHECK; 34994936Smux 35094936Smux sx_xlock(&kenv_lock); 35194936Smux cp = _getenv_dynamic(name, &i); 35294936Smux if (cp != NULL) { 35394959Smux oldenv = kenvp[i]; 35494936Smux for (j = i + 1; kenvp[j] != NULL; j++) 35594936Smux kenvp[i++] = kenvp[j]; 35694936Smux kenvp[i] = NULL; 35794936Smux sx_xunlock(&kenv_lock); 35894959Smux free(oldenv, M_KENV); 35994936Smux return (0); 36094936Smux } 36194936Smux sx_xunlock(&kenv_lock); 36294936Smux return (-1); 36394936Smux} 36494936Smux 36594936Smux/* 36685385Sjhb * Return a string value from an environment variable. 36785385Sjhb */ 36885385Sjhbint 36985385Sjhbgetenv_string(const char *name, char *data, int size) 37085385Sjhb{ 37185385Sjhb char *tmp; 37285385Sjhb 37385385Sjhb tmp = getenv(name); 37485493Sjhb if (tmp != NULL) { 37585385Sjhb strncpy(data, tmp, size); 37694936Smux freeenv(tmp); 37785385Sjhb data[size - 1] = 0; 37885385Sjhb return (1); 37985385Sjhb } else 38085385Sjhb return (0); 38185385Sjhb} 38285385Sjhb 38385385Sjhb/* 38442706Smsmith * Return an integer value from an environment variable. 38542706Smsmith */ 38642706Smsmithint 38778247Spetergetenv_int(const char *name, int *data) 38842706Smsmith{ 38952947Smjacob quad_t tmp; 39052947Smjacob int rval; 39152947Smjacob 39252947Smjacob rval = getenv_quad(name, &tmp); 39352947Smjacob if (rval) { 39452947Smjacob *data = (int) tmp; 39552947Smjacob } 39652947Smjacob return (rval); 39752947Smjacob} 39852947Smjacob 39952947Smjacob/* 40052947Smjacob * Return a quad_t value from an environment variable. 40152947Smjacob */ 40285385Sjhbint 40378247Spetergetenv_quad(const char *name, quad_t *data) 40452947Smjacob{ 40594936Smux char *value; 40653648Sarchie char *vtp; 40742706Smsmith quad_t iv; 40842706Smsmith 40942706Smsmith if ((value = getenv(name)) == NULL) 41042706Smsmith return(0); 41142706Smsmith 41242706Smsmith iv = strtoq(value, &vtp, 0); 41394936Smux if ((vtp == value) || (*vtp != '\0')) { 41494936Smux freeenv(value); 41542706Smsmith return(0); 41694936Smux } 41742706Smsmith 41894936Smux freeenv(value); 41952947Smjacob *data = iv; 42042706Smsmith return(1); 42142706Smsmith} 42240090Smsmith 42383744Speter/* 42440090Smsmith * Find the next entry after the one which (cp) falls within, return a 42540090Smsmith * pointer to its start or NULL if there are no more. 42640090Smsmith */ 42740090Smsmithstatic char * 42840090Smsmithkernenv_next(char *cp) 42940090Smsmith{ 43040090Smsmith if (cp != NULL) { 43140090Smsmith while (*cp != 0) 43240090Smsmith cp++; 43340090Smsmith cp++; 43440090Smsmith if (*cp == 0) 43540090Smsmith cp = NULL; 43640090Smsmith } 43740090Smsmith return(cp); 43840090Smsmith} 43940090Smsmith 44077900Spetervoid 44177900Spetertunable_int_init(void *data) 44277900Speter{ 44377900Speter struct tunable_int *d = (struct tunable_int *)data; 44477900Speter 44577900Speter TUNABLE_INT_FETCH(d->path, d->var); 44677900Speter} 44777900Speter 44877900Spetervoid 44984783Spstunable_quad_init(void *data) 45084783Sps{ 45184783Sps struct tunable_quad *d = (struct tunable_quad *)data; 45284783Sps 45384783Sps TUNABLE_QUAD_FETCH(d->path, d->var); 45484783Sps} 45584783Sps 45684783Spsvoid 45777900Spetertunable_str_init(void *data) 45877900Speter{ 45977900Speter struct tunable_str *d = (struct tunable_str *)data; 46077900Speter 46177900Speter TUNABLE_STR_FETCH(d->path, d->var, d->size); 46277900Speter} 463