* 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:
parent
2accd07be4
commit
cc6c784ae7
@ -22,21 +22,21 @@
|
||||
|
||||
/* random data structures (for thread-safe random numbers) */
|
||||
struct random_data {
|
||||
int *fptr;
|
||||
int *rptr;
|
||||
int *state;
|
||||
int rand_type;
|
||||
int rand_deg;
|
||||
int rand_sep;
|
||||
int *end_ptr;
|
||||
int *fptr;
|
||||
int *rptr;
|
||||
int *state;
|
||||
int rand_type;
|
||||
int rand_deg;
|
||||
int rand_sep;
|
||||
int *end_ptr;
|
||||
};
|
||||
|
||||
struct drand48_data {
|
||||
unsigned short int x[3];
|
||||
unsigned short int a[3];
|
||||
unsigned short int c;
|
||||
unsigned short int old_x[3];
|
||||
int init;
|
||||
unsigned short int x[3];
|
||||
unsigned short int a[3];
|
||||
unsigned short int c;
|
||||
unsigned short int old_x[3];
|
||||
int init;
|
||||
};
|
||||
|
||||
|
||||
@ -73,6 +73,7 @@ extern char *gcvt(double value, int digits, char *buffer);
|
||||
|
||||
/* environment variables */
|
||||
extern char **environ;
|
||||
extern int clearenv(void);
|
||||
extern char *getenv(const char *name);
|
||||
extern int putenv(const char *string);
|
||||
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 char *initstate(unsigned int seed, char *state, size_t size);
|
||||
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);
|
||||
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);
|
||||
|
||||
/* crypt */
|
||||
extern void setkey(const char *key);
|
||||
extern void setkey(const char *key);
|
||||
|
||||
|
||||
/* pty functions */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -25,15 +25,35 @@
|
||||
|
||||
// TODO: Use benaphore!
|
||||
static sem_id sEnvLock;
|
||||
static char **sManagedEnviron;
|
||||
static bool sCopied;
|
||||
|
||||
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
|
||||
count_variables(void)
|
||||
{
|
||||
int32 i = 0;
|
||||
|
||||
if (environ == NULL)
|
||||
return 0;
|
||||
|
||||
while (environ[i])
|
||||
i++;
|
||||
|
||||
@ -52,7 +72,7 @@ add_variable(void)
|
||||
newEnv[count] = NULL;
|
||||
// null terminate the array
|
||||
|
||||
environ = newEnv;
|
||||
environ = sManagedEnviron = newEnv;
|
||||
|
||||
return count - 1;
|
||||
}
|
||||
@ -63,6 +83,9 @@ find_variable(const char *name, int32 length, int32 *_index)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (environ == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; environ[i] != NULL; i++) {
|
||||
if (!strncmp(name, environ[i], length) && environ[i][length] == '=') {
|
||||
if (_index != NULL)
|
||||
@ -78,38 +101,44 @@ find_variable(const char *name, int32 length, int32 *_index)
|
||||
static status_t
|
||||
copy_environ_to_heap_if_needed(void)
|
||||
{
|
||||
char **newEnv;
|
||||
int32 i;
|
||||
int32 i = 0;
|
||||
|
||||
if (sCopied)
|
||||
if (sCopied && environ == sManagedEnviron)
|
||||
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]);
|
||||
if (sManagedEnviron != NULL) {
|
||||
// free previously used "environ"; it has been changed by an application
|
||||
free(sManagedEnviron);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
environ = newEnv;
|
||||
environ = sManagedEnviron;
|
||||
sCopied = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
int32 index;
|
||||
char *env;
|
||||
|
||||
acquire_sem(sEnvLock);
|
||||
copy_environ_to_heap_if_needed();
|
||||
|
||||
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) {
|
||||
// add variable
|
||||
index = add_variable();
|
||||
if (index >= 0)
|
||||
update = true;
|
||||
else
|
||||
status = index;
|
||||
if (index < 0)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
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;
|
||||
if (environ[index] == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memcpy(environ[index], name, length);
|
||||
environ[index][length] = '=';
|
||||
strcpy(environ[index] + length + 1, value);
|
||||
}
|
||||
|
||||
release_sem(sEnvLock);
|
||||
return status;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -148,19 +176,36 @@ environ_fork_hook(void)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
// #pragma mark - libroot initializer
|
||||
|
||||
|
||||
void
|
||||
__init_env(const struct user_space_program_args *args)
|
||||
{
|
||||
// Following POSIX, there is no need to make any of the
|
||||
// environment functions thread-safe - but we do it anyway
|
||||
// Following POSIX, there is no need to make any of the environment
|
||||
// functions thread-safe - but we do it anyway as much as possible to
|
||||
// protect our implementation
|
||||
sEnvLock = create_sem(1, "env lock");
|
||||
environ = args->env;
|
||||
sManagedEnviron = NULL;
|
||||
|
||||
atfork(environ_fork_hook);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark - public API
|
||||
|
||||
|
||||
int
|
||||
clearenv(void)
|
||||
{
|
||||
lock_variables();
|
||||
|
||||
free(sManagedEnviron);
|
||||
sManagedEnviron = environ = NULL;
|
||||
|
||||
unlock_variables();
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
@ -169,9 +214,10 @@ getenv(const char *name)
|
||||
int32 length = strlen(name);
|
||||
char *value;
|
||||
|
||||
acquire_sem(sEnvLock);
|
||||
lock_variables();
|
||||
|
||||
value = find_variable(name, length, NULL);
|
||||
release_sem(sEnvLock);
|
||||
unlock_variables();
|
||||
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
@ -190,7 +236,10 @@ setenv(const char *name, const char *value, int overwrite)
|
||||
return -1;
|
||||
}
|
||||
|
||||
lock_variables();
|
||||
status = update_variable(name, strlen(name), value, overwrite);
|
||||
unlock_variables();
|
||||
|
||||
RETURN_AND_SET_ERRNO(status);
|
||||
}
|
||||
|
||||
@ -208,7 +257,8 @@ unsetenv(const char *name)
|
||||
|
||||
length = strlen(name);
|
||||
|
||||
acquire_sem(sEnvLock);
|
||||
lock_variables();
|
||||
|
||||
copy_environ_to_heap_if_needed();
|
||||
|
||||
env = find_variable(name, length, &index);
|
||||
@ -220,7 +270,7 @@ unsetenv(const char *name)
|
||||
sizeof(char *) * (count_variables() - index));
|
||||
}
|
||||
|
||||
release_sem(sEnvLock);
|
||||
unlock_variables();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -236,7 +286,10 @@ putenv(const char *string)
|
||||
return -1;
|
||||
}
|
||||
|
||||
lock_variables();
|
||||
status = update_variable(string, value - string, value + 1, true);
|
||||
unlock_variables();
|
||||
|
||||
RETURN_AND_SET_ERRNO(status);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,10 @@ SimpleTest SyslogTest
|
||||
: SyslogTest.cpp syslog.cpp
|
||||
;
|
||||
|
||||
SimpleTest clearenv
|
||||
: clearenv.cpp
|
||||
;
|
||||
|
||||
SimpleTest flock_test
|
||||
: flock_test.cpp
|
||||
;
|
||||
|
64
src/tests/system/libroot/posix/clearenv.cpp
Normal file
64
src/tests/system/libroot/posix/clearenv.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user