Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_environment.c
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#include <sys/kenv.h> | #include <sys/kenv.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
static char *_getenv_dynamic_locked(const char *name, int *idx); | static char *_getenv_dynamic_locked(const char *name, int *idx); | ||||
static char *_getenv_dynamic(const char *name, int *idx); | static char *_getenv_dynamic(const char *name, int *idx); | ||||
static char *kenv_acquire(const char *name); | |||||
static void kenv_release(const char *buf); | |||||
static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment"); | static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment"); | ||||
#define KENV_SIZE 512 /* Maximum number of environment strings */ | #define KENV_SIZE 512 /* Maximum number of environment strings */ | ||||
static uma_zone_t kenv_zone; | static uma_zone_t kenv_zone; | ||||
static int kenv_mvallen = KENV_MVALLEN; | static int kenv_mvallen = KENV_MVALLEN; | ||||
/* pointer to the config-generated static environment */ | /* pointer to the config-generated static environment */ | ||||
Show All 13 Lines | |||||
/* | /* | ||||
* No need to protect this with a mutex since SYSINITS are single threaded. | * No need to protect this with a mutex since SYSINITS are single threaded. | ||||
*/ | */ | ||||
bool dynamic_kenv; | bool dynamic_kenv; | ||||
#define KENV_CHECK if (!dynamic_kenv) \ | #define KENV_CHECK if (!dynamic_kenv) \ | ||||
panic("%s: called before SI_SUB_KMEM", __func__) | panic("%s: called before SI_SUB_KMEM", __func__) | ||||
static char *getenv_string_buffer(const char *); | |||||
int | int | ||||
sys_kenv(td, uap) | sys_kenv(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
struct kenv_args /* { | struct kenv_args /* { | ||||
int what; | int what; | ||||
const char *name; | const char *name; | ||||
char *value; | char *value; | ||||
int len; | int len; | ||||
▲ Show 20 Lines • Show All 376 Lines • ▼ Show 20 Lines | |||||
* Look up an environment variable by name. | * Look up an environment variable by name. | ||||
* Return a pointer to the string if found. | * Return a pointer to the string if found. | ||||
* The pointer has to be freed with freeenv() | * The pointer has to be freed with freeenv() | ||||
* after use. | * after use. | ||||
*/ | */ | ||||
char * | char * | ||||
kern_getenv(const char *name) | kern_getenv(const char *name) | ||||
{ | { | ||||
char *ret; | char *cp, *ret; | ||||
int len; | |||||
if (dynamic_kenv) { | if (dynamic_kenv) { | ||||
ret = getenv_string_buffer(name); | len = KENV_MNAMELEN + 1 + kenv_mvallen + 1; | ||||
if (ret == NULL) { | ret = uma_zalloc(kenv_zone, M_WAITOK | M_ZERO); | ||||
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, | mtx_lock(&kenv_lock); | ||||
"getenv"); | cp = _getenv_dynamic(name, NULL); | ||||
if (cp != NULL) | |||||
strlcpy(ret, cp, len); | |||||
mtx_unlock(&kenv_lock); | |||||
if (cp == NULL) { | |||||
uma_zfree(kenv_zone, ret); | |||||
ret = NULL; | |||||
} | } | ||||
} else | } else | ||||
ret = _getenv_static(name); | ret = _getenv_static(name); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | /* | ||||
* Test if an environment variable is defined. | * Test if an environment variable is defined. | ||||
*/ | */ | ||||
int | int | ||||
testenv(const char *name) | testenv(const char *name) | ||||
{ | { | ||||
char *cp; | char *cp; | ||||
if (dynamic_kenv) { | cp = kenv_acquire(name); | ||||
mtx_lock(&kenv_lock); | kenv_release(cp); | ||||
cp = _getenv_dynamic(name, NULL); | |||||
mtx_unlock(&kenv_lock); | |||||
} else | |||||
cp = _getenv_static(name); | |||||
if (cp != NULL) | if (cp != NULL) | ||||
return (1); | return (1); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Set an environment variable in the MD-static environment. This cannot | * Set an environment variable in the MD-static environment. This cannot | ||||
* feasibly be done on config(8)-generated static environments as they don't | * feasibly be done on config(8)-generated static environments as they don't | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | if (cp != NULL) { | ||||
zfree(oldenv, M_KENV); | zfree(oldenv, M_KENV); | ||||
return (0); | return (0); | ||||
} | } | ||||
mtx_unlock(&kenv_lock); | mtx_unlock(&kenv_lock); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* | /* | ||||
* Return a buffer containing the string value from an environment variable | * Return the internal kenv buffer for the variable name, if it exists. | ||||
* If the dynamic kenv is initialized and the name is present, return | |||||
* with kenv_lock held. | |||||
*/ | */ | ||||
static char * | static char * | ||||
getenv_string_buffer(const char *name) | kenv_acquire(const char *name) | ||||
{ | { | ||||
char *cp, *ret; | char *value; | ||||
int len; | |||||
if (dynamic_kenv) { | if (dynamic_kenv) { | ||||
len = KENV_MNAMELEN + 1 + kenv_mvallen + 1; | |||||
ret = uma_zalloc(kenv_zone, M_WAITOK | M_ZERO); | |||||
mtx_lock(&kenv_lock); | mtx_lock(&kenv_lock); | ||||
cp = _getenv_dynamic(name, NULL); | value = _getenv_dynamic(name, NULL); | ||||
if (cp != NULL) | if (value == NULL) | ||||
strlcpy(ret, cp, len); | |||||
mtx_unlock(&kenv_lock); | mtx_unlock(&kenv_lock); | ||||
if (cp == NULL) { | return (value); | ||||
uma_zfree(kenv_zone, ret); | |||||
ret = NULL; | |||||
} | |||||
} else | } else | ||||
ret = _getenv_static(name); | return (_getenv_static(name)); | ||||
} | |||||
return (ret); | /* | ||||
* Undo a previous kenv_acquire() operation | |||||
*/ | |||||
static void | |||||
kenv_release(const char *buf) | |||||
{ | |||||
if ((buf != NULL) && dynamic_kenv) | |||||
mtx_unlock(&kenv_lock); | |||||
} | } | ||||
/* | /* | ||||
* Return a string value from an environment variable. | * Return a string value from an environment variable. | ||||
*/ | */ | ||||
int | int | ||||
getenv_string(const char *name, char *data, int size) | getenv_string(const char *name, char *data, int size) | ||||
{ | { | ||||
char *cp; | char *cp; | ||||
if (dynamic_kenv) { | cp = kenv_acquire(name); | ||||
mtx_lock(&kenv_lock); | |||||
cp = _getenv_dynamic(name, NULL); | |||||
if (cp != NULL) | if (cp != NULL) | ||||
strlcpy(data, cp, size); | strlcpy(data, cp, size); | ||||
mtx_unlock(&kenv_lock); | |||||
} else { | kenv_release(cp); | ||||
cp = _getenv_static(name); | |||||
if (cp != NULL) | |||||
strlcpy(data, cp, size); | |||||
} | |||||
return (cp != NULL); | return (cp != NULL); | ||||
} | } | ||||
/* | /* | ||||
* Return an array of integers at the given type size and signedness. | * Return an array of integers at the given type size and signedness. | ||||
*/ | */ | ||||
int | int | ||||
getenv_array(const char *name, void *pdata, int size, int *psize, | getenv_array(const char *name, void *pdata, int size, int *psize, | ||||
int type_size, bool allow_signed) | int type_size, bool allow_signed) | ||||
{ | { | ||||
uint8_t shift; | uint8_t shift; | ||||
int64_t value; | int64_t value; | ||||
int64_t old; | int64_t old; | ||||
char *buf; | const char *buf; | ||||
char *end; | char *end; | ||||
char *ptr; | const char *ptr; | ||||
int n; | int n; | ||||
int rc; | int rc; | ||||
if ((buf = getenv_string_buffer(name)) == NULL) | |||||
return (0); | |||||
rc = 0; /* assume failure */ | rc = 0; /* assume failure */ | ||||
mjg: This should be folded into a helper similar to what getenv_string_buffer is right now.
Then… | |||||
buf = kenv_acquire(name); | |||||
if (buf == NULL) | |||||
goto error; | |||||
/* get maximum number of elements */ | /* get maximum number of elements */ | ||||
size /= type_size; | size /= type_size; | ||||
n = 0; | n = 0; | ||||
for (ptr = buf; *ptr != 0; ) { | for (ptr = buf; *ptr != 0; ) { | ||||
value = strtoq(ptr, &end, 0); | value = strtoq(ptr, &end, 0); | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | for (ptr = buf; *ptr != 0; ) { | ||||
} | } | ||||
n++; | n++; | ||||
} | } | ||||
*psize = n * type_size; | *psize = n * type_size; | ||||
if (n != 0) | if (n != 0) | ||||
rc = 1; /* success */ | rc = 1; /* success */ | ||||
error: | error: | ||||
if (dynamic_kenv) | kenv_release(buf); | ||||
uma_zfree(kenv_zone, buf); | |||||
return (rc); | return (rc); | ||||
} | } | ||||
/* | /* | ||||
* Return an integer value from an environment variable. | * Return an integer value from an environment variable. | ||||
*/ | */ | ||||
int | int | ||||
getenv_int(const char *name, int *data) | getenv_int(const char *name, int *data) | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Return a quad_t value from an environment variable. | * Return a quad_t value from an environment variable. | ||||
*/ | */ | ||||
int | int | ||||
getenv_quad(const char *name, quad_t *data) | getenv_quad(const char *name, quad_t *data) | ||||
{ | { | ||||
char *value, *vtp; | const char *value; | ||||
char suffix, *vtp; | |||||
quad_t iv; | quad_t iv; | ||||
value = getenv_string_buffer(name); | value = kenv_acquire(name); | ||||
if (value == NULL) | if (value == NULL) { | ||||
return (0); | goto error; | ||||
} | |||||
iv = strtoq(value, &vtp, 0); | iv = strtoq(value, &vtp, 0); | ||||
if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) { | if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) { | ||||
freeenv(value); | goto error; | ||||
return (0); | |||||
} | } | ||||
switch (vtp[0]) { | suffix = vtp[0]; | ||||
kenv_release(value); | |||||
switch (suffix) { | |||||
case 't': case 'T': | case 't': case 'T': | ||||
iv *= 1024; | iv *= 1024; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case 'g': case 'G': | case 'g': case 'G': | ||||
iv *= 1024; | iv *= 1024; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case 'm': case 'M': | case 'm': case 'M': | ||||
iv *= 1024; | iv *= 1024; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case 'k': case 'K': | case 'k': case 'K': | ||||
iv *= 1024; | iv *= 1024; | ||||
case '\0': | case '\0': | ||||
break; | break; | ||||
default: | default: | ||||
freeenv(value); | |||||
return (0); | return (0); | ||||
} | } | ||||
freeenv(value); | |||||
*data = iv; | *data = iv; | ||||
return (1); | return (1); | ||||
error: | |||||
kenv_release(value); | |||||
return (0); | |||||
} | } | ||||
/* | /* | ||||
* Find the next entry after the one which (cp) falls within, return a | * Find the next entry after the one which (cp) falls within, return a | ||||
* pointer to its start or NULL if there are no more. | * pointer to its start or NULL if there are no more. | ||||
*/ | */ | ||||
static char * | static char * | ||||
kernenv_next(char *cp) | kernenv_next(char *cp) | ||||
▲ Show 20 Lines • Show All 67 Lines • Show Last 20 Lines |
This should be folded into a helper similar to what getenv_string_buffer is right now.
Then this and the other caller would be: