]> git.saurik.com Git - apple/libc.git/blob - stdlib/FreeBSD/setenv.c.patch
bbdda18d4cb75bda50af7dd4533943b339b91558
[apple/libc.git] / stdlib / FreeBSD / setenv.c.patch
1 Index: setenv.c
2 ===================================================================
3 --- setenv.c (revision 41051)
4 +++ setenv.c (working copy)
5 @@ -40,32 +40,79 @@
6 #include <stddef.h>
7 #include <stdlib.h>
8 #include <string.h>
9 +#include <crt_externs.h>
10 +#include <errno.h>
11 +#include <sys/types.h>
12 +#include <fcntl.h>
13 +#include <malloc/malloc.h>
14
15 -char *__findenv(const char *, int *);
16 +#define ZONE_OWNS_PTR(zone, ptr) (malloc_zone_from_ptr((ptr)) == zone)
17
18 +extern malloc_zone_t *__zone0;
19 +extern void __malloc_check_env_name(const char *);
20 +
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 *);
24 +
25 +#ifndef BUILDING_VARIANT
26 /*
27 - * setenv --
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.
31 */
32 -int
33 -setenv(name, value, rewrite)
34 +__private_extern__ int
35 +init__zone0(int should_set_errno)
36 +{
37 + if (__zone0) return (0);
38 +
39 + __zone0 = malloc_create_zone(0, 0);
40 + if (!__zone0) {
41 + if (should_set_errno) {
42 + errno = ENOMEM;
43 + }
44 + return (-1);
45 + }
46 + malloc_set_zone_name(__zone0, "environ");
47 + return (0);
48 +}
49 +
50 +/*
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
55 + */
56 +__private_extern__ int
57 +__setenv(name, value, rewrite, copy, environp, envz)
58 const char *name;
59 const char *value;
60 - int rewrite;
61 + int rewrite, copy;
62 + char ***environp;
63 + malloc_zone_t *envz;
64 {
65 - extern char **environ;
66 - static char **alloced; /* if allocated space before */
67 char *c;
68 - int l_value, offset;
69 + int offset;
70
71 - if (*value == '=') /* no `=' in value */
72 - ++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 */
76 + char *e;
77 if (!rewrite)
78 return (0);
79 - if (strlen(c) >= l_value) { /* old larger; copy over */
80 + /*
81 + * In UNIX03, we can overwrite only if we allocated the
82 + * string. Then we can realloc it if it is too small.
83 + */
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*/
88 + char *r;
89 + size_t len = c - e;
90 + if ((r = realloc(e, l_value + len + 1)) == NULL)
91 + return (-1);
92 + if (r != e) {
93 + (*environp)[offset] = r;
94 + c = r + len;
95 + }
96 + }
97 while ( (*c++ = *value++) );
98 return (0);
99 }
100 @@ -73,48 +120,225 @@
101 int cnt;
102 char **p;
103
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)));
111 if (!p)
112 return (-1);
113 - alloced = environ = p;
114 + *environp = p;
115 }
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)));
120 if (!p)
121 return (-1);
122 - bcopy(environ, p, cnt * sizeof(char *));
123 - alloced = environ = p;
124 + bcopy(*environp, p, cnt * sizeof(char *));
125 + *environp = p;
126 }
127 - environ[cnt + 1] = NULL;
128 + (*environp)[cnt + 1] = NULL;
129 offset = cnt;
130 }
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))))
134 - return (-1);
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. */
140 + if (copy > 0) {
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))))
144 + return (-1);
145 + for (c = (*environp)[offset]; (*c = *name++) && *c != '='; ++c);
146 + for (*c++ = '='; (*c++ = *value++); );
147 + } else {
148 + /* the legacy behavior copies the string */
149 + if (copy < 0) {
150 + size_t len = strlen(name);
151 + if((c = malloc_zone_malloc(envz, len + 1)) == NULL)
152 + return (-1);
153 + memcpy(c, name, len + 1);
154 + name = c;
155 + }
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;
160 + }
161 return (0);
162 }
163
164 +__private_extern__ void
165 +__unsetenv(const char *name, char **environ, malloc_zone_t *envz)
166 +{
167 + char **p;
168 + int offset;
169 +
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)))
176 + break;
177 + }
178 +}
179 +
180 +/****************************************************************************/
181 /*
182 + * _allocenvstate -- SPI that creates a new state (opaque)
183 + */
184 +void *
185 +_allocenvstate(void)
186 +{
187 + malloc_zone_t *zone;
188 + zone = malloc_create_zone(1000 /* unused */, 0 /* unused */);
189 + if (zone) {
190 + malloc_set_zone_name(zone, "environ");
191 + }
192 + return (void *)zone;
193 +}
194 +
195 +/*
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.)
201 + */
202 +char **
203 +_copyenv(char **env)
204 +{
205 + char **p;
206 + int cnt = 1;
207 +
208 + if (env)
209 + for (p = env; *p; ++p, ++cnt);
210 + p = (char **)malloc((size_t)(sizeof(char *) * cnt));
211 + if (!p)
212 + return (NULL);
213 + if (env)
214 + bcopy(env, p, cnt * sizeof(char *));
215 + else
216 + *p = NULL;
217 + return p;
218 +}
219 +
220 +/*
221 + * _deallocenvstate -- SPI that frees all the memory associated with the state
222 + * and all allocated strings, including the environment array itself if it
223 + * was copied.
224 + */
225 +int
226 +_deallocenvstate(void *state)
227 +{
228 + malloc_zone_t *envz;
229 +
230 + if (!(envz = (malloc_zone_t *)state) || envz == __zone0) {
231 + errno = EINVAL;
232 + return -1;
233 + }
234 + malloc_destroy_zone(envz);
235 + return 0;
236 +}
237 +
238 +/*
239 + * setenvp -- SPI using an arbitrary pointer to string array and an env state,
240 + * created by _allocenvstate(). Initial checking is not done.
241 + *
242 + * Set the value of the environmental variable "name" to be
243 + * "value". If rewrite is set, replace any current value.
244 + */
245 +int
246 +_setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state)
247 +{
248 + if (init__zone0(1)) return (-1);
249 + return (__setenv(name, value, rewrite, 1, envp, (state ? (malloc_zone_t *)state : __zone0)));
250 +}
251 +
252 +/*
253 + * unsetenv(name) -- SPI using an arbitrary pointer to string array and an env
254 + * state, created by _allocenvstate(). Initial checking is not done.
255 + *
256 + * Delete environmental variable "name".
257 + */
258 +int
259 +_unsetenvp(const char *name, char ***envp, void *state)
260 +{
261 + if (init__zone0(1)) return (-1);
262 + __unsetenv(name, *envp, (state ? (malloc_zone_t *)state : __zone0));
263 + return 0;
264 +}
265 +
266 +#endif /* !BUILD_VARIANT */
267 +
268 +/*
269 + * setenv --
270 + * Set the value of the environmental variable "name" to be
271 + * "value". If rewrite is set, replace any current value.
272 + */
273 +int
274 +setenv(name, value, rewrite)
275 + const char *name;
276 + const char *value;
277 + int rewrite;
278 +{
279 + /* no null ptr or empty str */
280 + if(name == NULL || *name == 0) {
281 + errno = EINVAL;
282 + return (-1);
283 + }
284 +
285 +#if __DARWIN_UNIX03
286 + /* no '=' in name */
287 + if (strchr(name, '=')) {
288 + errno = EINVAL;
289 + return (-1);
290 + }
291 +#endif /* __DARWIN_UNIX03 */
292 +
293 + if (*value == '=') /* no `=' in value */
294 + ++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));
299 +}
300 +
301 +/*
302 * unsetenv(name) --
303 * Delete environmental variable "name".
304 */
305 +#if __DARWIN_UNIX03
306 +int
307 +#else /* !__DARWIN_UNIX03 */
308 void
309 +#endif /* __DARWIN_UNIX03 */
310 unsetenv(name)
311 const char *name;
312 {
313 - extern char **environ;
314 - char **p;
315 - int offset;
316 +#if __DARWIN_UNIX03
317 + /* no null ptr or empty str */
318 + if(name == NULL || *name == 0) {
319 + errno = EINVAL;
320 + return (-1);
321 + }
322
323 - while (__findenv(name, &offset)) /* if set multiple times */
324 - for (p = &environ[offset];; ++p)
325 - if (!(*p = *(p + 1)))
326 - break;
327 + /* no '=' in name */
328 + if (strchr(name, '=')) {
329 + errno = EINVAL;
330 + return (-1);
331 + }
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)
337 + return;
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);
343 +#if __DARWIN_UNIX03
344 + return 0;
345 +#endif /* __DARWIN_UNIX03 */
346 }