2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
14 #include <errno_private.h>
15 #include <libroot_private.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
;
34 mutex_lock(&sEnvLock
);
39 unlock_variables(void)
41 mutex_unlock(&sEnvLock
);
50 if (sManagedEnviron
== NULL
)
53 for (i
= 0; sManagedEnviron
[i
] != NULL
; i
++) {
54 free(sManagedEnviron
[i
]);
57 free(sManagedEnviron
);
58 sManagedEnviron
= NULL
;
80 int32 count
= count_variables() + 1;
81 char **newEnviron
= (char**)realloc(environ
, (count
+ 1) * sizeof(char *));
82 if (newEnviron
== NULL
)
85 newEnviron
[count
] = NULL
;
86 // null terminate the array
88 environ
= sManagedEnviron
= newEnviron
;
95 find_variable(const char *name
, int32 length
, int32
*_index
)
102 for (i
= 0; environ
[i
] != NULL
; i
++) {
103 if (!strncmp(name
, environ
[i
], length
) && environ
[i
][length
] == '=') {
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
123 copy_environ_to_heap_if_needed(void)
127 if (environ
== sManagedEnviron
)
130 // free previously used "environ" if it has been changed by an application
133 sManagedEnviron
= (char**)malloc((count_variables() + 1) * sizeof(char *));
134 if (sManagedEnviron
== NULL
)
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
;
153 update_variable(const char *name
, int32 length
, const char *value
,
160 copy_environ_to_heap_if_needed();
162 env
= find_variable(name
, length
, &index
);
163 if (env
!= NULL
&& overwrite
) {
165 free(environ
[index
]);
167 } else if (env
== NULL
) {
169 index
= add_variable();
177 environ
[index
] = (char*)malloc(length
+ 2 + strlen(value
));
178 if (environ
[index
] == NULL
)
181 memcpy(environ
[index
], name
, length
);
182 environ
[index
][length
] = '=';
183 strcpy(environ
[index
] + length
+ 1, value
);
191 environ_fork_hook(void)
193 mutex_init(&sEnvLock
, kEnvLockName
);
197 // #pragma mark - libroot initializer
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
207 sManagedEnviron
= NULL
;
212 __init_env_post_heap()
214 atfork(environ_fork_hook
);
218 // #pragma mark - public API
236 getenv(const char *name
)
238 int32 length
= strlen(name
);
243 value
= find_variable(name
, length
, NULL
);
249 return value
+ length
+ 1;
254 setenv(const char *name
, const char *value
, int overwrite
)
258 if (name
== NULL
|| name
[0] == '\0' || strchr(name
, '=') != NULL
) {
259 __set_errno(B_BAD_VALUE
);
264 status
= update_variable(name
, strlen(name
), value
, overwrite
);
267 RETURN_AND_SET_ERRNO(status
);
272 unsetenv(const char *name
)
277 if (name
== NULL
|| name
[0] == '\0' || strchr(name
, '=') != NULL
) {
278 __set_errno(B_BAD_VALUE
);
282 length
= strlen(name
);
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
293 memmove(environ
+ index
, environ
+ index
+ 1,
294 sizeof(char *) * (count_variables() - index
));
296 // search possible another occurence, introduced via putenv()
298 env
= find_variable(name
, length
, &index
);
307 putenv(const char *string
)
309 char *value
= strchr(string
, '=');
313 __set_errno(B_BAD_VALUE
);
318 status
= update_variable(string
, value
- string
, value
+ 1, true);
321 RETURN_AND_SET_ERRNO(status
);
326 __getenv_reentrant(const char* name
, char* buffer
, size_t bufferSize
)
328 size_t nameLength
= strlen(name
);
332 char* value
= find_variable(name
, nameLength
, NULL
);
333 ssize_t result
= value
!= NULL
334 ? strlcpy(buffer
, value
+ nameLength
+ 1, bufferSize
)