2 ===================================================================
3 --- setenv.c (revision 41051)
4 +++ setenv.c (working copy)
9 +#include <crt_externs.h>
11 +#include <sys/types.h>
13 +#include <malloc/malloc.h>
15 -char *__findenv(const char *, int *);
16 +#define ZONE_OWNS_PTR(zone, ptr) (malloc_zone_from_ptr((ptr)) == zone)
18 +extern malloc_zone_t *__zone0;
19 +extern void __malloc_check_env_name(const char *);
21 +__private_extern__ char *__findenv(const char *, int *, char **);
22 +__private_extern__ int __setenv(const char *, const char *, int, int, char ***, malloc_zone_t *);
23 +__private_extern__ void __unsetenv(const char *, char **, malloc_zone_t *);
25 +#ifndef BUILDING_VARIANT
28 - * Set the value of the environmental variable "name" to be
29 - * "value". If rewrite is set, replace any current value.
30 + * Create the environment malloc zone and give it a recognizable name.
33 -setenv(name, value, rewrite)
34 +__private_extern__ int
35 +init__zone0(int should_set_errno)
37 + if (__zone0) return (0);
39 + __zone0 = malloc_create_zone(0, 0);
41 + if (should_set_errno) {
46 + malloc_set_zone_name(__zone0, "environ");
51 + * The copy flag may have 3 values:
52 + * 1 - make a copy of the name/value pair
53 + * 0 - take the name as a user-supplied name=value string
54 + * -1 - like 0, except we copy of the name=value string in name
56 +__private_extern__ int
57 +__setenv(name, value, rewrite, copy, environp, envz)
63 + malloc_zone_t *envz;
65 - extern char **environ;
66 - static char **alloced; /* if allocated space before */
68 - int l_value, offset;
71 - if (*value == '=') /* no `=' in value */
73 - l_value = strlen(value);
74 - if ((c = __findenv(name, &offset))) { /* find if already exists */
75 + if ((c = __findenv(name, &offset, *environp))) { /* find if already exists */
79 - if (strlen(c) >= l_value) { /* old larger; copy over */
81 + * In UNIX03, we can overwrite only if we allocated the
82 + * string. Then we can realloc it if it is too small.
84 + e = (*environp)[offset];
85 + if (copy > 0 && ZONE_OWNS_PTR(envz, e)) {
86 + size_t l_value = strlen(value);
87 + if (strlen(c) < l_value) { /* old smaller; resize*/
90 + if ((r = realloc(e, l_value + len + 1)) == NULL)
93 + (*environp)[offset] = r;
97 while ( (*c++ = *value++) );
100 @@ -73,48 +120,225 @@
104 - for (p = environ, cnt = 0; *p; ++p, ++cnt);
105 - if (alloced == environ) { /* just increase size */
106 - p = (char **)realloc((char *)environ,
107 + for (p = *environp, cnt = 0; *p; ++p, ++cnt);
108 + if (ZONE_OWNS_PTR(envz, *environp)) { /* just increase size */
109 + p = (char **)realloc((char *)*environp,
110 (size_t)(sizeof(char *) * (cnt + 2)));
113 - alloced = environ = p;
116 else { /* get new space */
117 /* copy old entries into it */
118 - p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
119 + p = malloc_zone_malloc(envz, (size_t)(sizeof(char *) * (cnt + 2)));
122 - bcopy(environ, p, cnt * sizeof(char *));
123 - alloced = environ = p;
124 + bcopy(*environp, p, cnt * sizeof(char *));
127 - environ[cnt + 1] = NULL;
128 + (*environp)[cnt + 1] = NULL;
131 - for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
132 - if (!(environ[offset] = /* name + `=' + value */
133 - malloc((size_t)((int)(c - name) + l_value + 2))))
135 - for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
136 - for (*c++ = '='; (*c++ = *value++); );
137 + /* For non Unix03, or UnixO3 setenv(), we make a copy of the user's
138 + * strings. For Unix03 putenv(), we put the string directly in
139 + * the environment. */
141 + for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
142 + if (!((*environp)[offset] = /* name + `=' + value */
143 + malloc_zone_malloc(envz, (size_t)((int)(c - name) + strlen(value) + 2))))
145 + for (c = (*environp)[offset]; (*c = *name++) && *c != '='; ++c);
146 + for (*c++ = '='; (*c++ = *value++); );
148 + /* the legacy behavior copies the string */
150 + size_t len = strlen(name);
151 + if((c = malloc_zone_malloc(envz, len + 1)) == NULL)
153 + memcpy(c, name, len + 1);
156 + /* if we malloc-ed the previous value, free it first */
157 + if ((*environp)[offset] != NULL && ZONE_OWNS_PTR(envz, (*environp)[offset]))
158 + free((*environp)[offset]);
159 + (*environp)[offset] = (char *)name;
164 +__private_extern__ void
165 +__unsetenv(const char *name, char **environ, malloc_zone_t *envz)
170 + while (__findenv(name, &offset, environ)) { /* if set multiple times */
171 + /* if we malloc-ed it, free it first */
172 + if (ZONE_OWNS_PTR(envz, environ[offset]))
173 + free(environ[offset]);
174 + for (p = &environ[offset];; ++p)
175 + if (!(*p = *(p + 1)))
180 +/****************************************************************************/
182 + * _allocenvstate -- SPI that creates a new state (opaque)
185 +_allocenvstate(void)
187 + malloc_zone_t *zone;
188 + zone = malloc_create_zone(1000 /* unused */, 0 /* unused */);
190 + malloc_set_zone_name(zone, "environ");
192 + return (void *)zone;
196 + * _copyenv -- SPI that copies a NULL-tereminated char * array in a newly
197 + * allocated buffer, compatible with the other SPI env routines. If env
198 + * is NULL, a char * array composed of a single NULL is returned. NULL
199 + * is returned on error. (This isn't needed anymore, as __setenv will
200 + * automatically make a copy in the zone.)
203 +_copyenv(char **env)
209 + for (p = env; *p; ++p, ++cnt);
210 + p = (char **)malloc((size_t)(sizeof(char *) * cnt));
214 + bcopy(env, p, cnt * sizeof(char *));
221 + * _deallocenvstate -- SPI that frees all the memory associated with the state
222 + * and all allocated strings, including the environment array itself if it
226 +_deallocenvstate(void *state)
228 + malloc_zone_t *envz;
230 + if (!(envz = (malloc_zone_t *)state) || envz == __zone0) {
234 + malloc_destroy_zone(envz);
239 + * setenvp -- SPI using an arbitrary pointer to string array and an env state,
240 + * created by _allocenvstate(). Initial checking is not done.
242 + * Set the value of the environmental variable "name" to be
243 + * "value". If rewrite is set, replace any current value.
246 +_setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state)
248 + if (init__zone0(1)) return (-1);
249 + return (__setenv(name, value, rewrite, 1, envp, (state ? (malloc_zone_t *)state : __zone0)));
253 + * unsetenv(name) -- SPI using an arbitrary pointer to string array and an env
254 + * state, created by _allocenvstate(). Initial checking is not done.
256 + * Delete environmental variable "name".
259 +_unsetenvp(const char *name, char ***envp, void *state)
261 + if (init__zone0(1)) return (-1);
262 + __unsetenv(name, *envp, (state ? (malloc_zone_t *)state : __zone0));
266 +#endif /* !BUILD_VARIANT */
270 + * Set the value of the environmental variable "name" to be
271 + * "value". If rewrite is set, replace any current value.
274 +setenv(name, value, rewrite)
279 + /* no null ptr or empty str */
280 + if(name == NULL || *name == 0) {
286 + /* no '=' in name */
287 + if (strchr(name, '=')) {
291 +#endif /* __DARWIN_UNIX03 */
293 + if (*value == '=') /* no `=' in value */
295 + /* insure __zone0 is set up before calling __malloc_check_env_name */
296 + if (init__zone0(1)) return (-1);
297 + __malloc_check_env_name(name); /* see if we are changing a malloc environment variable */
298 + return (__setenv(name, value, rewrite, 1, _NSGetEnviron(), __zone0));
303 * Delete environmental variable "name".
307 +#else /* !__DARWIN_UNIX03 */
309 +#endif /* __DARWIN_UNIX03 */
313 - extern char **environ;
317 + /* no null ptr or empty str */
318 + if(name == NULL || *name == 0) {
323 - while (__findenv(name, &offset)) /* if set multiple times */
324 - for (p = &environ[offset];; ++p)
325 - if (!(*p = *(p + 1)))
327 + /* no '=' in name */
328 + if (strchr(name, '=')) {
332 + /* insure __zone0 is set up before calling __malloc_check_env_name */
333 + if (init__zone0(1)) return (-1);
334 +#else /* !__DARWIN_UNIX03 */
335 + /* no null ptr or empty str */
336 + if(name == NULL || *name == 0)
338 + /* insure __zone0 is set up before calling __malloc_check_env_name */
339 + if (init__zone0(0)) return;
340 +#endif /* __DARWIN_UNIX03 */
341 + __malloc_check_env_name(name); /* see if we are changing a malloc environment variable */
342 + __unsetenv(name, *_NSGetEnviron(), __zone0);
345 +#endif /* __DARWIN_UNIX03 */