* Sean C. Farley made me aware that some of the possible solutions to clear
the environment would crash on Haiku. Added a small test application that just checks every one of those. * Fixed env locking (in userland, you better check against B_INTERRUPTED). * Made our code safe against an environ of NULL. * There is now an additional sManagedEnviron that points to the environment our code actually managed; whenever an application overrides environ, we'll get aware of it with the next *env() function invocation, and will handle it adequately. * Added non-POSIX clearenv() function. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26719 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+15
-14
@@ -22,21 +22,21 @@
|
|||||||
|
|
||||||
/* random data structures (for thread-safe random numbers) */
|
/* random data structures (for thread-safe random numbers) */
|
||||||
struct random_data {
|
struct random_data {
|
||||||
int *fptr;
|
int *fptr;
|
||||||
int *rptr;
|
int *rptr;
|
||||||
int *state;
|
int *state;
|
||||||
int rand_type;
|
int rand_type;
|
||||||
int rand_deg;
|
int rand_deg;
|
||||||
int rand_sep;
|
int rand_sep;
|
||||||
int *end_ptr;
|
int *end_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drand48_data {
|
struct drand48_data {
|
||||||
unsigned short int x[3];
|
unsigned short int x[3];
|
||||||
unsigned short int a[3];
|
unsigned short int a[3];
|
||||||
unsigned short int c;
|
unsigned short int c;
|
||||||
unsigned short int old_x[3];
|
unsigned short int old_x[3];
|
||||||
int init;
|
int init;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -73,6 +73,7 @@ extern char *gcvt(double value, int digits, char *buffer);
|
|||||||
|
|
||||||
/* environment variables */
|
/* environment variables */
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
extern int clearenv(void);
|
||||||
extern char *getenv(const char *name);
|
extern char *getenv(const char *name);
|
||||||
extern int putenv(const char *string);
|
extern int putenv(const char *string);
|
||||||
extern int setenv(char const *name, char const *value, int rewrite);
|
extern int setenv(char const *name, char const *value, int rewrite);
|
||||||
@@ -102,7 +103,7 @@ extern int random_r(struct random_data *data, int *result);
|
|||||||
extern int srandom_r(unsigned int seed, struct random_data *data);
|
extern int srandom_r(unsigned int seed, struct random_data *data);
|
||||||
extern char *initstate(unsigned int seed, char *state, size_t size);
|
extern char *initstate(unsigned int seed, char *state, size_t size);
|
||||||
extern char *setstate(char *state);
|
extern char *setstate(char *state);
|
||||||
extern int initstate_r(unsigned int seed, void *stateBuffer,
|
extern int initstate_r(unsigned int seed, void *stateBuffer,
|
||||||
size_t stateLength, struct random_data *data);
|
size_t stateLength, struct random_data *data);
|
||||||
extern int setstate_r(void *stateBuffer, struct random_data *data);
|
extern int setstate_r(void *stateBuffer, struct random_data *data);
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ extern size_t mbstowcs(wchar_t *pwcs, const char *string, size_t maxSize);
|
|||||||
extern size_t wcstombs(char *string, const wchar_t *pwcs, size_t maxSize);
|
extern size_t wcstombs(char *string, const wchar_t *pwcs, size_t maxSize);
|
||||||
|
|
||||||
/* crypt */
|
/* crypt */
|
||||||
extern void setkey(const char *key);
|
extern void setkey(const char *key);
|
||||||
|
|
||||||
|
|
||||||
/* pty functions */
|
/* pty functions */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004-2007, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -25,15 +25,35 @@
|
|||||||
|
|
||||||
// TODO: Use benaphore!
|
// TODO: Use benaphore!
|
||||||
static sem_id sEnvLock;
|
static sem_id sEnvLock;
|
||||||
|
static char **sManagedEnviron;
|
||||||
static bool sCopied;
|
static bool sCopied;
|
||||||
|
|
||||||
char **environ = NULL;
|
char **environ = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
lock_variables(void)
|
||||||
|
{
|
||||||
|
while (acquire_sem(sEnvLock) == B_INTERRUPTED)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
unlock_variables(void)
|
||||||
|
{
|
||||||
|
release_sem(sEnvLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int32
|
static int32
|
||||||
count_variables(void)
|
count_variables(void)
|
||||||
{
|
{
|
||||||
int32 i = 0;
|
int32 i = 0;
|
||||||
|
|
||||||
|
if (environ == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
while (environ[i])
|
while (environ[i])
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
@@ -52,7 +72,7 @@ add_variable(void)
|
|||||||
newEnv[count] = NULL;
|
newEnv[count] = NULL;
|
||||||
// null terminate the array
|
// null terminate the array
|
||||||
|
|
||||||
environ = newEnv;
|
environ = sManagedEnviron = newEnv;
|
||||||
|
|
||||||
return count - 1;
|
return count - 1;
|
||||||
}
|
}
|
||||||
@@ -63,6 +83,9 @@ find_variable(const char *name, int32 length, int32 *_index)
|
|||||||
{
|
{
|
||||||
int32 i;
|
int32 i;
|
||||||
|
|
||||||
|
if (environ == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; environ[i] != NULL; i++) {
|
for (i = 0; environ[i] != NULL; i++) {
|
||||||
if (!strncmp(name, environ[i], length) && environ[i][length] == '=') {
|
if (!strncmp(name, environ[i], length) && environ[i][length] == '=') {
|
||||||
if (_index != NULL)
|
if (_index != NULL)
|
||||||
@@ -78,38 +101,44 @@ find_variable(const char *name, int32 length, int32 *_index)
|
|||||||
static status_t
|
static status_t
|
||||||
copy_environ_to_heap_if_needed(void)
|
copy_environ_to_heap_if_needed(void)
|
||||||
{
|
{
|
||||||
char **newEnv;
|
int32 i = 0;
|
||||||
int32 i;
|
|
||||||
|
|
||||||
if (sCopied)
|
if (sCopied && environ == sManagedEnviron)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
newEnv = malloc((count_variables() + 1) * sizeof(char *));
|
if (sManagedEnviron != NULL) {
|
||||||
if (newEnv == NULL)
|
// free previously used "environ"; it has been changed by an application
|
||||||
return B_NO_MEMORY;
|
free(sManagedEnviron);
|
||||||
|
|
||||||
for (i = 0; environ[i]; i++) {
|
|
||||||
newEnv[i] = strdup(environ[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newEnv[i] = NULL;
|
sManagedEnviron = malloc((count_variables() + 1) * sizeof(char *));
|
||||||
|
if (sManagedEnviron == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (environ != NULL) {
|
||||||
|
// copy from previous
|
||||||
|
for (; environ[i]; i++) {
|
||||||
|
sManagedEnviron[i] = strdup(environ[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sManagedEnviron[i] = NULL;
|
||||||
// null terminate the array
|
// null terminate the array
|
||||||
|
|
||||||
environ = newEnv;
|
environ = sManagedEnviron;
|
||||||
sCopied = true;
|
sCopied = true;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
update_variable(const char *name, int32 length, const char *value, bool overwrite)
|
update_variable(const char *name, int32 length, const char *value,
|
||||||
|
bool overwrite)
|
||||||
{
|
{
|
||||||
status_t status = B_OK;
|
|
||||||
bool update = false;
|
bool update = false;
|
||||||
int32 index;
|
int32 index;
|
||||||
char *env;
|
char *env;
|
||||||
|
|
||||||
acquire_sem(sEnvLock);
|
|
||||||
copy_environ_to_heap_if_needed();
|
copy_environ_to_heap_if_needed();
|
||||||
|
|
||||||
env = find_variable(name, length, &index);
|
env = find_variable(name, length, &index);
|
||||||
@@ -120,24 +149,23 @@ update_variable(const char *name, int32 length, const char *value, bool overwrit
|
|||||||
} else if (env == NULL) {
|
} else if (env == NULL) {
|
||||||
// add variable
|
// add variable
|
||||||
index = add_variable();
|
index = add_variable();
|
||||||
if (index >= 0)
|
if (index < 0)
|
||||||
update = true;
|
return B_NO_MEMORY;
|
||||||
else
|
|
||||||
status = index;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update) {
|
if (update) {
|
||||||
environ[index] = malloc(length + 2 + strlen(value));
|
environ[index] = malloc(length + 2 + strlen(value));
|
||||||
if (environ[index] != NULL) {
|
if (environ[index] == NULL)
|
||||||
memcpy(environ[index], name, length);
|
return B_NO_MEMORY;
|
||||||
environ[index][length] = '=';
|
|
||||||
strcpy(environ[index] + length + 1, value);
|
memcpy(environ[index], name, length);
|
||||||
} else
|
environ[index][length] = '=';
|
||||||
status = B_NO_MEMORY;
|
strcpy(environ[index] + length + 1, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
release_sem(sEnvLock);
|
return B_OK;
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -148,19 +176,36 @@ environ_fork_hook(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
// #pragma mark - libroot initializer
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
__init_env(const struct user_space_program_args *args)
|
__init_env(const struct user_space_program_args *args)
|
||||||
{
|
{
|
||||||
// Following POSIX, there is no need to make any of the
|
// Following POSIX, there is no need to make any of the environment
|
||||||
// environment functions thread-safe - but we do it anyway
|
// functions thread-safe - but we do it anyway as much as possible to
|
||||||
|
// protect our implementation
|
||||||
sEnvLock = create_sem(1, "env lock");
|
sEnvLock = create_sem(1, "env lock");
|
||||||
environ = args->env;
|
environ = args->env;
|
||||||
|
sManagedEnviron = NULL;
|
||||||
|
|
||||||
atfork(environ_fork_hook);
|
atfork(environ_fork_hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - public API
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
clearenv(void)
|
||||||
|
{
|
||||||
|
lock_variables();
|
||||||
|
|
||||||
|
free(sManagedEnviron);
|
||||||
|
sManagedEnviron = environ = NULL;
|
||||||
|
|
||||||
|
unlock_variables();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
@@ -169,9 +214,10 @@ getenv(const char *name)
|
|||||||
int32 length = strlen(name);
|
int32 length = strlen(name);
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
acquire_sem(sEnvLock);
|
lock_variables();
|
||||||
|
|
||||||
value = find_variable(name, length, NULL);
|
value = find_variable(name, length, NULL);
|
||||||
release_sem(sEnvLock);
|
unlock_variables();
|
||||||
|
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -190,7 +236,10 @@ setenv(const char *name, const char *value, int overwrite)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock_variables();
|
||||||
status = update_variable(name, strlen(name), value, overwrite);
|
status = update_variable(name, strlen(name), value, overwrite);
|
||||||
|
unlock_variables();
|
||||||
|
|
||||||
RETURN_AND_SET_ERRNO(status);
|
RETURN_AND_SET_ERRNO(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +257,8 @@ unsetenv(const char *name)
|
|||||||
|
|
||||||
length = strlen(name);
|
length = strlen(name);
|
||||||
|
|
||||||
acquire_sem(sEnvLock);
|
lock_variables();
|
||||||
|
|
||||||
copy_environ_to_heap_if_needed();
|
copy_environ_to_heap_if_needed();
|
||||||
|
|
||||||
env = find_variable(name, length, &index);
|
env = find_variable(name, length, &index);
|
||||||
@@ -220,7 +270,7 @@ unsetenv(const char *name)
|
|||||||
sizeof(char *) * (count_variables() - index));
|
sizeof(char *) * (count_variables() - index));
|
||||||
}
|
}
|
||||||
|
|
||||||
release_sem(sEnvLock);
|
unlock_variables();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +286,10 @@ putenv(const char *string)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock_variables();
|
||||||
status = update_variable(string, value - string, value + 1, true);
|
status = update_variable(string, value - string, value + 1, true);
|
||||||
|
unlock_variables();
|
||||||
|
|
||||||
RETURN_AND_SET_ERRNO(status);
|
RETURN_AND_SET_ERRNO(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ SimpleTest SyslogTest
|
|||||||
: SyslogTest.cpp syslog.cpp
|
: SyslogTest.cpp syslog.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
|
SimpleTest clearenv
|
||||||
|
: clearenv.cpp
|
||||||
|
;
|
||||||
|
|
||||||
SimpleTest flock_test
|
SimpleTest flock_test
|
||||||
: flock_test.cpp
|
: flock_test.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
int gTestNr;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
set_env()
|
||||||
|
{
|
||||||
|
gTestNr++;
|
||||||
|
printf("Test %d...\n", gTestNr);
|
||||||
|
|
||||||
|
if (setenv("TEST_VARIABLE", "42", true) != 0)
|
||||||
|
fprintf(stderr, "Test %d: setting variable failed!\n", gTestNr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
test_env()
|
||||||
|
{
|
||||||
|
if (getenv("TEST_VARIABLE") != NULL)
|
||||||
|
fprintf(stderr, "Test %d: not cleared!\n", gTestNr);
|
||||||
|
if (setenv("OTHER_VARIABLE", "test", true) != 0)
|
||||||
|
fprintf(stderr, "Test %d: setting other failed!\n", gTestNr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
set_env();
|
||||||
|
environ = NULL;
|
||||||
|
test_env();
|
||||||
|
|
||||||
|
set_env();
|
||||||
|
environ[0] = NULL;
|
||||||
|
test_env();
|
||||||
|
|
||||||
|
static char* emptyEnv[1] = {NULL};
|
||||||
|
set_env();
|
||||||
|
environ = emptyEnv;
|
||||||
|
test_env();
|
||||||
|
|
||||||
|
set_env();
|
||||||
|
environ = (char**)calloc(1, sizeof(*environ));
|
||||||
|
test_env();
|
||||||
|
|
||||||
|
// clearenv() is not part of the POSIX specs
|
||||||
|
#if 1
|
||||||
|
set_env();
|
||||||
|
clearenv();
|
||||||
|
test_env();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user