kern_environment.c revision 94936
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 94936 2002-04-17 13:06:36Z mux $ 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 ; 24194936Smux len = ep - cp; 24294936Smux if (*ep == '=') 24394936Smux ep++; 24494936Smux if (!strncmp(name, cp, len)) 24594936Smux return (ep); 24694936Smux } 24794936Smux return (NULL); 24894936Smux} 24994936Smux 25094936Smux/* 25185385Sjhb * Look up an environment variable by name. 25294936Smux * Return a pointer to the string if found. 25394936Smux * The pointer has to be freed with freeenv() 25494936Smux * after use. 25585385Sjhb */ 25640090Smsmithchar * 25778247Spetergetenv(const char *name) 25840090Smsmith{ 25994936Smux char *ret, *cp; 26094936Smux int len; 26194936Smux 26294936Smux if (dynamic_kenv) { 26394936Smux sx_slock(&kenv_lock); 26494936Smux cp = _getenv_dynamic(name, NULL); 26594936Smux if (cp != NULL) { 26694936Smux len = strlen(cp) + 1; 26794936Smux ret = malloc(len, M_KENV, M_WAITOK); 26894936Smux strcpy(ret, cp); 26994936Smux } else 27094936Smux ret = NULL; 27194936Smux sx_sunlock(&kenv_lock); 27294936Smux } else 27394936Smux ret = _getenv_static(name); 27494936Smux return (ret); 27540090Smsmith} 27640090Smsmith 27742706Smsmith/* 27894936Smux * Test if an environment variable is defined. 27994936Smux */ 28094936Smuxint 28194936Smuxtestenv(const char *name) 28294936Smux{ 28394936Smux char *cp; 28494936Smux 28594936Smux if (dynamic_kenv) { 28694936Smux sx_slock(&kenv_lock); 28794936Smux cp = _getenv_dynamic(name, NULL); 28894936Smux sx_sunlock(&kenv_lock); 28994936Smux } else 29094936Smux cp = _getenv_static(name); 29194936Smux if (cp != NULL) 29294936Smux return (1); 29394936Smux return (0); 29494936Smux} 29594936Smux 29694936Smux/* 29794936Smux * Set an environment variable by name. 29894936Smux */ 29994936Smuxvoid 30094936Smuxsetenv(const char *name, const char *value) 30194936Smux{ 30294936Smux char *buf, *cp; 30394936Smux int len, i; 30494936Smux 30594936Smux KENV_CHECK; 30694936Smux 30794936Smux len = strlen(name) + 1 + strlen(value) + 1; 30894936Smux buf = malloc(len, M_KENV, M_WAITOK); 30994936Smux sprintf(buf, "%s=%s", name, value); 31094936Smux 31194936Smux sx_xlock(&kenv_lock); 31294936Smux cp = _getenv_dynamic(name, &i); 31394936Smux if (cp != NULL) { 31494936Smux free(kenvp[i], M_KENV); 31594936Smux kenvp[i] = buf; 31694936Smux } else { 31794936Smux /* We add the option if it wasn't found */ 31894936Smux for (i = 0; (cp = kenvp[i]) != NULL; i++) 31994936Smux ; 32094936Smux kenvp[i] = buf; 32194936Smux kenvp[i + 1] = NULL; 32294936Smux } 32394936Smux sx_xunlock(&kenv_lock); 32494936Smux} 32594936Smux 32694936Smux/* 32794936Smux * Unset an environment variable string. 32894936Smux */ 32994936Smuxint 33094936Smuxunsetenv(const char *name) 33194936Smux{ 33294936Smux char *cp; 33394936Smux int i, j; 33494936Smux 33594936Smux KENV_CHECK; 33694936Smux 33794936Smux sx_xlock(&kenv_lock); 33894936Smux cp = _getenv_dynamic(name, &i); 33994936Smux if (cp != NULL) { 34094936Smux free(kenvp[i], M_KENV); 34194936Smux for (j = i + 1; kenvp[j] != NULL; j++) 34294936Smux kenvp[i++] = kenvp[j]; 34394936Smux kenvp[i] = NULL; 34494936Smux sx_xunlock(&kenv_lock); 34594936Smux return (0); 34694936Smux } 34794936Smux sx_xunlock(&kenv_lock); 34894936Smux return (-1); 34994936Smux} 35094936Smux 35194936Smux/* 35285385Sjhb * Return a string value from an environment variable. 35385385Sjhb */ 35485385Sjhbint 35585385Sjhbgetenv_string(const char *name, char *data, int size) 35685385Sjhb{ 35785385Sjhb char *tmp; 35885385Sjhb 35985385Sjhb tmp = getenv(name); 36085493Sjhb if (tmp != NULL) { 36185385Sjhb strncpy(data, tmp, size); 36294936Smux freeenv(tmp); 36385385Sjhb data[size - 1] = 0; 36485385Sjhb return (1); 36585385Sjhb } else 36685385Sjhb return (0); 36785385Sjhb} 36885385Sjhb 36985385Sjhb/* 37042706Smsmith * Return an integer value from an environment variable. 37142706Smsmith */ 37242706Smsmithint 37378247Spetergetenv_int(const char *name, int *data) 37442706Smsmith{ 37552947Smjacob quad_t tmp; 37652947Smjacob int rval; 37752947Smjacob 37852947Smjacob rval = getenv_quad(name, &tmp); 37952947Smjacob if (rval) { 38052947Smjacob *data = (int) tmp; 38152947Smjacob } 38252947Smjacob return (rval); 38352947Smjacob} 38452947Smjacob 38552947Smjacob/* 38652947Smjacob * Return a quad_t value from an environment variable. 38752947Smjacob */ 38885385Sjhbint 38978247Spetergetenv_quad(const char *name, quad_t *data) 39052947Smjacob{ 39194936Smux char *value; 39253648Sarchie char *vtp; 39342706Smsmith quad_t iv; 39442706Smsmith 39542706Smsmith if ((value = getenv(name)) == NULL) 39642706Smsmith return(0); 39742706Smsmith 39842706Smsmith iv = strtoq(value, &vtp, 0); 39994936Smux if ((vtp == value) || (*vtp != '\0')) { 40094936Smux freeenv(value); 40142706Smsmith return(0); 40294936Smux } 40342706Smsmith 40494936Smux freeenv(value); 40552947Smjacob *data = iv; 40642706Smsmith return(1); 40742706Smsmith} 40840090Smsmith 40983744Speter/* 41040090Smsmith * Find the next entry after the one which (cp) falls within, return a 41140090Smsmith * pointer to its start or NULL if there are no more. 41240090Smsmith */ 41340090Smsmithstatic char * 41440090Smsmithkernenv_next(char *cp) 41540090Smsmith{ 41640090Smsmith if (cp != NULL) { 41740090Smsmith while (*cp != 0) 41840090Smsmith cp++; 41940090Smsmith cp++; 42040090Smsmith if (*cp == 0) 42140090Smsmith cp = NULL; 42240090Smsmith } 42340090Smsmith return(cp); 42440090Smsmith} 42540090Smsmith 42677900Spetervoid 42777900Spetertunable_int_init(void *data) 42877900Speter{ 42977900Speter struct tunable_int *d = (struct tunable_int *)data; 43077900Speter 43177900Speter TUNABLE_INT_FETCH(d->path, d->var); 43277900Speter} 43377900Speter 43477900Spetervoid 43584783Spstunable_quad_init(void *data) 43684783Sps{ 43784783Sps struct tunable_quad *d = (struct tunable_quad *)data; 43884783Sps 43984783Sps TUNABLE_QUAD_FETCH(d->path, d->var); 44084783Sps} 44184783Sps 44284783Spsvoid 44377900Spetertunable_str_init(void *data) 44477900Speter{ 44577900Speter struct tunable_str *d = (struct tunable_str *)data; 44677900Speter 44777900Speter TUNABLE_STR_FETCH(d->path, d->var, d->size); 44877900Speter} 449