summaryrefslogtreecommitdiff
path: root/LibC
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-05-30 02:51:15 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-05-30 03:22:18 +0200
commit96db775ac1ff5df64957d1a9873f0955c3d4cb17 (patch)
tree8b788ebcd509910dde90862fc22688565d3ea48d /LibC
parentd31ce9eccdc051cb38b414c1c72aeee21af8a086 (diff)
downloadserenity-96db775ac1ff5df64957d1a9873f0955c3d4cb17.zip
LibC: Add setenv().
If I'm understanding the standard C library correctly, setenv() copies while putenv() does not. That's really confusing and putenv() basically sucks. To know which environment variables to free on replacement and which ones to leave alone, we keep track of the ones malloced by setenv in a side table. This patch also moves Shell to using setenv() instead of putenv(). Fixes #29.
Diffstat (limited to 'LibC')
-rw-r--r--LibC/stdlib.cpp24
-rw-r--r--LibC/stdlib.h1
2 files changed, 25 insertions, 0 deletions
diff --git a/LibC/stdlib.cpp b/LibC/stdlib.cpp
index cabcda573d..74d7d07939 100644
--- a/LibC/stdlib.cpp
+++ b/LibC/stdlib.cpp
@@ -46,6 +46,16 @@ void abort()
raise(SIGABRT);
}
+static HashTable<char*> s_malloced_environment_variables;
+
+static void free_environment_variable_if_needed(const char* var)
+{
+ if (!s_malloced_environment_variables.contains((char*)var))
+ return;
+ free((void*)var);
+ s_malloced_environment_variables.remove((char*)var);
+}
+
char* getenv(const char* name)
{
size_t vl = strlen(name);
@@ -89,9 +99,22 @@ int unsetenv(const char* name)
// Shuffle the existing array down by one.
memmove(&environ[skip], &environ[skip+1], ((environ_size-1)-skip) * sizeof(environ[0]));
environ[environ_size-1] = nullptr;
+
+ free_environment_variable_if_needed(name);
return 0;
}
+int setenv(const char* name, const char* value, int overwrite)
+{
+ if (!overwrite && !getenv(name))
+ return 0;
+ auto length = strlen(name) + strlen(value) + 2;
+ auto* var = (char*)malloc(length);
+ snprintf(var, length, "%s=%s", name, value);
+ s_malloced_environment_variables.set(var);
+ return putenv(var);
+}
+
int putenv(char* new_var)
{
char* new_eq = strchr(new_var, '=');
@@ -111,6 +134,7 @@ int putenv(char* new_var)
continue; // can't match
if (strncmp(new_var, old_var, new_var_len) == 0) {
+ free_environment_variable_if_needed(old_var);
environ[environ_size] = new_var;
return 0;
}
diff --git a/LibC/stdlib.h b/LibC/stdlib.h
index 946a1d8274..a310ee5e11 100644
--- a/LibC/stdlib.h
+++ b/LibC/stdlib.h
@@ -18,6 +18,7 @@ void* realloc(void* ptr, size_t);
char* getenv(const char* name);
int putenv(char*);
int unsetenv(const char*);
+int setenv(const char* name, const char* value, int overwrite);
int atoi(const char*);
long atol(const char*);
long long atoll(const char*);