Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / system / libroot / posix / stdlib / env.cpp
blobe811eeb6f5ac2f312c90bbd1419ef1e3f4b7a368
1 /*
2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <errno.h>
8 #include <pthread.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <OS.h>
14 #include <errno_private.h>
15 #include <libroot_private.h>
16 #include <locks.h>
17 #include <runtime_loader.h>
18 #include <stdlib_private.h>
19 #include <syscall_utils.h>
20 #include <user_runtime.h>
23 static const char* const kEnvLockName = "env lock";
25 static mutex sEnvLock = MUTEX_INITIALIZER(kEnvLockName);
26 static char **sManagedEnviron;
28 char **environ = NULL;
31 static inline void
32 lock_variables(void)
34 mutex_lock(&sEnvLock);
38 static inline void
39 unlock_variables(void)
41 mutex_unlock(&sEnvLock);
45 static void
46 free_variables(void)
48 int32 i;
50 if (sManagedEnviron == NULL)
51 return;
53 for (i = 0; sManagedEnviron[i] != NULL; i++) {
54 free(sManagedEnviron[i]);
57 free(sManagedEnviron);
58 sManagedEnviron = NULL;
62 static int32
63 count_variables(void)
65 int32 i = 0;
67 if (environ == NULL)
68 return 0;
70 while (environ[i])
71 i++;
73 return i;
77 static int32
78 add_variable(void)
80 int32 count = count_variables() + 1;
81 char **newEnviron = (char**)realloc(environ, (count + 1) * sizeof(char *));
82 if (newEnviron == NULL)
83 return B_NO_MEMORY;
85 newEnviron[count] = NULL;
86 // null terminate the array
88 environ = sManagedEnviron = newEnviron;
90 return count - 1;
94 static char *
95 find_variable(const char *name, int32 length, int32 *_index)
97 int32 i;
99 if (environ == NULL)
100 return NULL;
102 for (i = 0; environ[i] != NULL; i++) {
103 if (!strncmp(name, environ[i], length) && environ[i][length] == '=') {
104 if (_index != NULL)
105 *_index = i;
106 return environ[i];
110 return NULL;
114 /*! Copies the environment from its current location into a heap managed
115 environment, if it's not already there.
117 This is needed whenever the environment is changed, that is, when one
118 of the POSIX *env() functions is called, and we either used the environment
119 provided by the kernel, or by an application that changed \c environ
120 directly.
122 static status_t
123 copy_environ_to_heap_if_needed(void)
125 int32 i = 0;
127 if (environ == sManagedEnviron)
128 return B_OK;
130 // free previously used "environ" if it has been changed by an application
131 free_variables();
133 sManagedEnviron = (char**)malloc((count_variables() + 1) * sizeof(char *));
134 if (sManagedEnviron == NULL)
135 return B_NO_MEMORY;
137 if (environ != NULL) {
138 // copy from previous
139 for (; environ[i]; i++) {
140 sManagedEnviron[i] = strdup(environ[i]);
144 sManagedEnviron[i] = NULL;
145 // null terminate the array
147 environ = sManagedEnviron;
148 return B_OK;
152 static status_t
153 update_variable(const char *name, int32 length, const char *value,
154 bool overwrite)
156 bool update = false;
157 int32 index;
158 char *env;
160 copy_environ_to_heap_if_needed();
162 env = find_variable(name, length, &index);
163 if (env != NULL && overwrite) {
164 // change variable
165 free(environ[index]);
166 update = true;
167 } else if (env == NULL) {
168 // add variable
169 index = add_variable();
170 if (index < 0)
171 return B_NO_MEMORY;
173 update = true;
176 if (update) {
177 environ[index] = (char*)malloc(length + 2 + strlen(value));
178 if (environ[index] == NULL)
179 return B_NO_MEMORY;
181 memcpy(environ[index], name, length);
182 environ[index][length] = '=';
183 strcpy(environ[index] + length + 1, value);
186 return B_OK;
190 static void
191 environ_fork_hook(void)
193 mutex_init(&sEnvLock, kEnvLockName);
197 // #pragma mark - libroot initializer
200 void
201 __init_env(const struct user_space_program_args *args)
203 // Following POSIX, there is no need to make any of the environment
204 // functions thread-safe - but we do it anyway as much as possible to
205 // protect our implementation
206 environ = args->env;
207 sManagedEnviron = NULL;
211 void
212 __init_env_post_heap()
214 atfork(environ_fork_hook);
218 // #pragma mark - public API
222 clearenv(void)
224 lock_variables();
226 free_variables();
227 environ = NULL;
229 unlock_variables();
231 return 0;
235 char *
236 getenv(const char *name)
238 int32 length = strlen(name);
239 char *value;
241 lock_variables();
243 value = find_variable(name, length, NULL);
244 unlock_variables();
246 if (value == NULL)
247 return NULL;
249 return value + length + 1;
254 setenv(const char *name, const char *value, int overwrite)
256 status_t status;
258 if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL) {
259 __set_errno(B_BAD_VALUE);
260 return -1;
263 lock_variables();
264 status = update_variable(name, strlen(name), value, overwrite);
265 unlock_variables();
267 RETURN_AND_SET_ERRNO(status);
272 unsetenv(const char *name)
274 int32 index, length;
275 char *env;
277 if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL) {
278 __set_errno(B_BAD_VALUE);
279 return -1;
282 length = strlen(name);
284 lock_variables();
286 copy_environ_to_heap_if_needed();
288 env = find_variable(name, length, &index);
289 while (env != NULL) {
290 // we don't free the memory for the slot, we just move the array
291 // contents
292 free(env);
293 memmove(environ + index, environ + index + 1,
294 sizeof(char *) * (count_variables() - index));
296 // search possible another occurence, introduced via putenv()
297 // and renamed since
298 env = find_variable(name, length, &index);
301 unlock_variables();
302 return 0;
307 putenv(const char *string)
309 char *value = strchr(string, '=');
310 status_t status;
312 if (value == NULL) {
313 __set_errno(B_BAD_VALUE);
314 return -1;
317 lock_variables();
318 status = update_variable(string, value - string, value + 1, true);
319 unlock_variables();
321 RETURN_AND_SET_ERRNO(status);
325 ssize_t
326 __getenv_reentrant(const char* name, char* buffer, size_t bufferSize)
328 size_t nameLength = strlen(name);
330 lock_variables();
332 char* value = find_variable(name, nameLength, NULL);
333 ssize_t result = value != NULL
334 ? strlcpy(buffer, value + nameLength + 1, bufferSize)
335 : B_NAME_NOT_FOUND;
337 unlock_variables();
339 return result;