Implemented userland env handling; it longer uses syscalls for this - I even
made it thread-safe, although this is not required by POSIX. Implemented unsetenv(), improved putenv(). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11668 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
/*
|
||||
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
|
||||
** Distributed under the terms of the Haiku License.
|
||||
**
|
||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <syscalls.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include <libroot_private.h>
|
||||
#include <user_runtime.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@@ -22,45 +23,212 @@
|
||||
return err;
|
||||
|
||||
|
||||
static sem_id sEnvLock;
|
||||
static bool sCopied;
|
||||
|
||||
char **environ = NULL;
|
||||
|
||||
|
||||
int
|
||||
setenv(const char *name, const char *value, int overwrite)
|
||||
static int32
|
||||
count_variables(void)
|
||||
{
|
||||
status_t status = sys_setenv(name, value, overwrite);
|
||||
int32 i = 0;
|
||||
while (environ[i])
|
||||
i++;
|
||||
|
||||
RETURN_AND_SET_ERRNO(status);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
add_variable(void)
|
||||
{
|
||||
int32 count = count_variables() + 1;
|
||||
char **newEnv = malloc((count + 1) * sizeof(char *));
|
||||
if (newEnv == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memcpy(newEnv, environ, count * sizeof(char *));
|
||||
newEnv[count] = NULL;
|
||||
// null terminate the array
|
||||
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
find_variable(const char *name, int32 length, int32 *_index)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; environ[i] != NULL; i++) {
|
||||
if (!strncmp(name, environ[i], length) && environ[i][length] == '=') {
|
||||
if (_index != NULL)
|
||||
*_index = i;
|
||||
return environ[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
copy_environ_to_heap_if_needed(void)
|
||||
{
|
||||
char **newEnv;
|
||||
int32 i;
|
||||
|
||||
if (sCopied)
|
||||
return B_OK;
|
||||
|
||||
newEnv = malloc((count_variables() + 1) * sizeof(char *));
|
||||
if (newEnv == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
for (i = 0; environ[i]; i++) {
|
||||
newEnv[i] = strdup(environ[i]);
|
||||
}
|
||||
|
||||
newEnv[i] = NULL;
|
||||
// null terminate the array
|
||||
|
||||
sCopied = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
update_variable(const char *name, int32 length, const char *value, bool overwrite)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
bool update = false;
|
||||
int32 index;
|
||||
char *env;
|
||||
|
||||
acquire_sem(sEnvLock);
|
||||
copy_environ_to_heap_if_needed();
|
||||
|
||||
env = find_variable(name, length, &index);
|
||||
if (env != NULL && overwrite) {
|
||||
// change variable
|
||||
free(environ[index]);
|
||||
update = true;
|
||||
} else if (env == NULL) {
|
||||
// add variable
|
||||
index = add_variable();
|
||||
update = true;
|
||||
}
|
||||
|
||||
if (update) {
|
||||
environ[index] = malloc(length + 2 + strlen(value));
|
||||
if (environ[index] != NULL) {
|
||||
memcpy(environ[index], name, length);
|
||||
environ[index][length] = '=';
|
||||
strcpy(environ[index] + length + 1, value);
|
||||
} else
|
||||
status = B_NO_MEMORY;
|
||||
}
|
||||
|
||||
release_sem(sEnvLock);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
environ_fork_hook(void)
|
||||
{
|
||||
sEnvLock = create_sem(1, "env lock");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__init_env(const struct uspace_program_args *args)
|
||||
{
|
||||
// Following POSIX, there is no need to make any of the
|
||||
// environment functions thread-safe - but we do it anyway
|
||||
sEnvLock = create_sem(1, "env lock");
|
||||
environ = args->envp;
|
||||
|
||||
atfork(environ_fork_hook);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
char *
|
||||
getenv(const char *name)
|
||||
{
|
||||
int32 length = strlen(name);
|
||||
char *value;
|
||||
int rc;
|
||||
|
||||
rc = sys_getenv(name, &value);
|
||||
if (rc < 0)
|
||||
|
||||
acquire_sem(sEnvLock);
|
||||
value = find_variable(name, length, NULL);
|
||||
release_sem(sEnvLock);
|
||||
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
return value;
|
||||
|
||||
return value + length + 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL) {
|
||||
errno = B_BAD_VALUE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = update_variable(name, strlen(name), value, overwrite);
|
||||
RETURN_AND_SET_ERRNO(status);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
unsetenv(const char *name)
|
||||
{
|
||||
int32 index, length;
|
||||
char *env;
|
||||
|
||||
if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL) {
|
||||
errno = B_BAD_VALUE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = strlen(name);
|
||||
|
||||
acquire_sem(sEnvLock);
|
||||
copy_environ_to_heap_if_needed();
|
||||
|
||||
env = find_variable(name, length, &index);
|
||||
if (env != NULL) {
|
||||
// we don't free the memory for the slot, we just move the array contents
|
||||
free(env);
|
||||
memmove(environ + index, environ + index + 1, sizeof(char *) * (count_variables() + 1));
|
||||
}
|
||||
|
||||
release_sem(sEnvLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
putenv(const char *string)
|
||||
{
|
||||
char name[64];
|
||||
char *value = strchr(string, '=');
|
||||
status_t status;
|
||||
|
||||
if (value == NULL || value - string >= (int)sizeof(name)) {
|
||||
errno = EINVAL;
|
||||
if (value == NULL) {
|
||||
errno = B_BAD_VALUE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strlcpy(name, string, value + 1 - string);
|
||||
value++;
|
||||
|
||||
return setenv(name, value, true);
|
||||
status = update_variable(string, value - string, value + 1, true);
|
||||
RETURN_AND_SET_ERRNO(status);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user