]> git.saurik.com Git - apple/libc.git/blame - stdlib/FreeBSD/setenv.c.patch
Libc-763.13.tar.gz
[apple/libc.git] / stdlib / FreeBSD / setenv.c.patch
CommitLineData
1f2f436a
A
1--- setenv.c.orig 2011-04-13 01:21:14.000000000 -0700
2+++ setenv.c 2011-04-13 14:44:04.000000000 -0700
3@@ -36,32 +36,115 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/
9385eb3d
A
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <string.h>
7+#include <crt_externs.h>
3d9156a7 8+#include <errno.h>
224c7076
A
9+#include <sys/types.h>
10+#include <fcntl.h>
11+#include <malloc/malloc.h>
9385eb3d 12
224c7076
A
13-char *__findenv(const char *, int *);
14+#define ZONE_OWNS_PTR(zone, ptr) (malloc_zone_from_ptr((ptr)) == zone)
1f2f436a 15+
224c7076
A
16+extern malloc_zone_t *__zone0;
17+extern void __malloc_check_env_name(const char *);
18+
19+__private_extern__ char *__findenv(const char *, int *, char **);
20+__private_extern__ int __setenv(const char *, const char *, int, int, char ***, malloc_zone_t *);
21+__private_extern__ void __unsetenv(const char *, char **, malloc_zone_t *);
1f2f436a
A
22+__private_extern__ int init__zone0(int);
23
224c7076 24 /*
3d9156a7
A
25- * setenv --
26- * Set the value of the environmental variable "name" to be
27- * "value". If rewrite is set, replace any current value.
1f2f436a
A
28+ * _cthread_init_routine used to be called from crt1.o to initialize threads.
29+ * This is no longer needed, as initialization happens in dylib initializers,
30+ * but is provided to maintain backwards compatibility. Normally, for 10.5
31+ * or greater, _cthread_init_routine does nothing.
32+ *
33+ * Before 10.5, the _start routine in crt1.o clobbers environ with the original
34+ * stack value, which effectively undoes any environment changes made in
35+ * initializers. When LEGACY_CRT1_ENVIRON is defined, we replace the
36+ * do-nothing routine with one that attempts to restore the environ value.
37+ * But this only works if the setenv (and family) routines were used
38+ * exclusively, (no direct manipulation of environ). Note that according to
39+ * SUSv3, direct manipulation of environ may result in undefined behavior in
40+ * setenv and family, so we don't support that (on less than 10.5).
34e8f829
A
41 */
42-int
43-setenv(name, value, rewrite)
1f2f436a
A
44+#ifdef BUILDING_VARIANT
45+# ifdef LEGACY_CRT1_ENVIRON
46+extern char **_saved_environ;
47+# endif /* LEGACY_CRT1_ENVIRON */
48+#else /* !BUILDING_VARIANT */
49+# ifdef LEGACY_CRT1_ENVIRON
50+__private_extern__ char **_saved_environ = NULL;
51+
52+static int
53+_legacy_crt1_environ(void)
54+{
55+ if (_saved_environ) *_NSGetEnviron() = _saved_environ;
56+ return 0;
57+}
58+int (*_cthread_init_routine)(void) = _legacy_crt1_environ;
59+
60+# else /* !LEGACY_CRT1_ENVIRON */
61+static int _do_nothing(void) { return 0; }
62+int (*_cthread_init_routine)(void) = _do_nothing;
63+# endif /* !LEGACY_CRT1_ENVIRON */
64+
65+/*
66+ * Create the environment malloc zone and give it a recognizable name.
67+ */
34e8f829
A
68+__private_extern__ int
69+init__zone0(int should_set_errno)
70+{
71+ if (__zone0) return (0);
72+
73+ __zone0 = malloc_create_zone(0, 0);
74+ if (!__zone0) {
75+ if (should_set_errno) {
76+ errno = ENOMEM;
77+ }
78+ return (-1);
79+ }
80+ malloc_set_zone_name(__zone0, "environ");
81+ return (0);
82+}
83+
84+/*
224c7076
A
85+ * The copy flag may have 3 values:
86+ * 1 - make a copy of the name/value pair
87+ * 0 - take the name as a user-supplied name=value string
88+ * -1 - like 0, except we copy of the name=value string in name
34e8f829 89+ */
3d9156a7 90+__private_extern__ int
224c7076 91+__setenv(name, value, rewrite, copy, environp, envz)
3d9156a7 92 const char *name;
9385eb3d 93 const char *value;
3d9156a7
A
94- int rewrite;
95+ int rewrite, copy;
224c7076
A
96+ char ***environp;
97+ malloc_zone_t *envz;
9385eb3d
A
98 {
99- extern char **environ;
224c7076 100- static char **alloced; /* if allocated space before */
9385eb3d 101 char *c;
3d9156a7
A
102- int l_value, offset;
103+ int offset;
104
105- if (*value == '=') /* no `=' in value */
106- ++value;
107- l_value = strlen(value);
224c7076
A
108- if ((c = __findenv(name, &offset))) { /* find if already exists */
109+ if ((c = __findenv(name, &offset, *environp))) { /* find if already exists */
110+ char *e;
3d9156a7
A
111 if (!rewrite)
112 return (0);
113- if (strlen(c) >= l_value) { /* old larger; copy over */
224c7076
A
114+ /*
115+ * In UNIX03, we can overwrite only if we allocated the
116+ * string. Then we can realloc it if it is too small.
117+ */
118+ e = (*environp)[offset];
119+ if (copy > 0 && ZONE_OWNS_PTR(envz, e)) {
120+ size_t l_value = strlen(value);
121+ if (strlen(c) < l_value) { /* old smaller; resize*/
122+ char *r;
123+ size_t len = c - e;
124+ if ((r = realloc(e, l_value + len + 1)) == NULL)
125+ return (-1);
126+ if (r != e) {
127+ (*environp)[offset] = r;
128+ c = r + len;
129+ }
130+ }
131 while ( (*c++ = *value++) );
132 return (0);
133 }
1f2f436a 134@@ -69,48 +152,235 @@ setenv(name, value, rewrite)
9385eb3d
A
135 int cnt;
136 char **p;
137
138- for (p = environ, cnt = 0; *p; ++p, ++cnt);
139- if (alloced == environ) { /* just increase size */
140- p = (char **)realloc((char *)environ,
141+ for (p = *environp, cnt = 0; *p; ++p, ++cnt);
224c7076 142+ if (ZONE_OWNS_PTR(envz, *environp)) { /* just increase size */
9385eb3d
A
143+ p = (char **)realloc((char *)*environp,
144 (size_t)(sizeof(char *) * (cnt + 2)));
145 if (!p)
146 return (-1);
147- alloced = environ = p;
224c7076 148+ *environp = p;
9385eb3d
A
149 }
150 else { /* get new space */
151 /* copy old entries into it */
224c7076
A
152- p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
153+ p = malloc_zone_malloc(envz, (size_t)(sizeof(char *) * (cnt + 2)));
9385eb3d
A
154 if (!p)
155 return (-1);
156- bcopy(environ, p, cnt * sizeof(char *));
157- alloced = environ = p;
158+ bcopy(*environp, p, cnt * sizeof(char *));
224c7076 159+ *environp = p;
9385eb3d
A
160 }
161- environ[cnt + 1] = NULL;
162+ (*environp)[cnt + 1] = NULL;
163 offset = cnt;
164 }
3d9156a7 165- for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
9385eb3d 166- if (!(environ[offset] = /* name + `=' + value */
3d9156a7
A
167- malloc((size_t)((int)(c - name) + l_value + 2))))
168- return (-1);
9385eb3d 169- for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
3d9156a7
A
170- for (*c++ = '='; (*c++ = *value++); );
171+ /* For non Unix03, or UnixO3 setenv(), we make a copy of the user's
172+ * strings. For Unix03 putenv(), we put the string directly in
173+ * the environment. */
224c7076 174+ if (copy > 0) {
3d9156a7
A
175+ for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
176+ if (!((*environp)[offset] = /* name + `=' + value */
224c7076 177+ malloc_zone_malloc(envz, (size_t)((int)(c - name) + strlen(value) + 2))))
3d9156a7
A
178+ return (-1);
179+ for (c = (*environp)[offset]; (*c = *name++) && *c != '='; ++c);
180+ for (*c++ = '='; (*c++ = *value++); );
224c7076
A
181+ } else {
182+ /* the legacy behavior copies the string */
183+ if (copy < 0) {
184+ size_t len = strlen(name);
185+ if((c = malloc_zone_malloc(envz, len + 1)) == NULL)
186+ return (-1);
187+ memcpy(c, name, len + 1);
188+ name = c;
189+ }
190+ /* if we malloc-ed the previous value, free it first */
191+ if ((*environp)[offset] != NULL && ZONE_OWNS_PTR(envz, (*environp)[offset]))
192+ free((*environp)[offset]);
193+ (*environp)[offset] = (char *)name;
194+ }
9385eb3d
A
195 return (0);
196 }
224c7076
A
197
198+__private_extern__ void
199+__unsetenv(const char *name, char **environ, malloc_zone_t *envz)
200+{
201+ char **p;
202+ int offset;
203+
204+ while (__findenv(name, &offset, environ)) { /* if set multiple times */
205+ /* if we malloc-ed it, free it first */
206+ if (ZONE_OWNS_PTR(envz, environ[offset]))
207+ free(environ[offset]);
208+ for (p = &environ[offset];; ++p)
209+ if (!(*p = *(p + 1)))
210+ break;
211+ }
212+}
213+
214+/****************************************************************************/
1f2f436a 215+/*
224c7076
A
216+ * _allocenvstate -- SPI that creates a new state (opaque)
217+ */
218+void *
219+_allocenvstate(void)
220+{
34e8f829
A
221+ malloc_zone_t *zone;
222+ zone = malloc_create_zone(1000 /* unused */, 0 /* unused */);
223+ if (zone) {
224+ malloc_set_zone_name(zone, "environ");
225+ }
226+ return (void *)zone;
224c7076
A
227+}
228+
229+/*
230+ * _copyenv -- SPI that copies a NULL-tereminated char * array in a newly
231+ * allocated buffer, compatible with the other SPI env routines. If env
232+ * is NULL, a char * array composed of a single NULL is returned. NULL
233+ * is returned on error. (This isn't needed anymore, as __setenv will
234+ * automatically make a copy in the zone.)
235+ */
236+char **
237+_copyenv(char **env)
238+{
239+ char **p;
240+ int cnt = 1;
241+
242+ if (env)
243+ for (p = env; *p; ++p, ++cnt);
244+ p = (char **)malloc((size_t)(sizeof(char *) * cnt));
245+ if (!p)
246+ return (NULL);
247+ if (env)
248+ bcopy(env, p, cnt * sizeof(char *));
249+ else
250+ *p = NULL;
251+ return p;
252+}
253+
254+/*
255+ * _deallocenvstate -- SPI that frees all the memory associated with the state
256+ * and all allocated strings, including the environment array itself if it
257+ * was copied.
258+ */
259+int
260+_deallocenvstate(void *state)
261+{
262+ malloc_zone_t *envz;
263+
264+ if (!(envz = (malloc_zone_t *)state) || envz == __zone0) {
265+ errno = EINVAL;
266+ return -1;
267+ }
268+ malloc_destroy_zone(envz);
269+ return 0;
270+}
271+
272+/*
273+ * setenvp -- SPI using an arbitrary pointer to string array and an env state,
274+ * created by _allocenvstate(). Initial checking is not done.
275+ *
276+ * Set the value of the environmental variable "name" to be
277+ * "value". If rewrite is set, replace any current value.
278+ */
279+int
280+_setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state)
281+{
34e8f829 282+ if (init__zone0(1)) return (-1);
224c7076
A
283+ return (__setenv(name, value, rewrite, 1, envp, (state ? (malloc_zone_t *)state : __zone0)));
284+}
285+
286+/*
287+ * unsetenv(name) -- SPI using an arbitrary pointer to string array and an env
288+ * state, created by _allocenvstate(). Initial checking is not done.
289+ *
290+ * Delete environmental variable "name".
291+ */
292+int
293+_unsetenvp(const char *name, char ***envp, void *state)
294+{
34e8f829 295+ if (init__zone0(1)) return (-1);
224c7076
A
296+ __unsetenv(name, *envp, (state ? (malloc_zone_t *)state : __zone0));
297+ return 0;
298+}
299+
3d9156a7
A
300+#endif /* !BUILD_VARIANT */
301+
302+/*
303+ * setenv --
304+ * Set the value of the environmental variable "name" to be
305+ * "value". If rewrite is set, replace any current value.
306+ */
307+int
308+setenv(name, value, rewrite)
309+ const char *name;
310+ const char *value;
311+ int rewrite;
312+{
1f2f436a
A
313+#ifdef LEGACY_CRT1_ENVIRON
314+ int ret;
315+#endif /* LEGACY_CRT1_ENVIRON */
316+
3d9156a7
A
317+ /* no null ptr or empty str */
318+ if(name == NULL || *name == 0) {
319+ errno = EINVAL;
320+ return (-1);
321+ }
322+
323+#if __DARWIN_UNIX03
324+ /* no '=' in name */
325+ if (strchr(name, '=')) {
326+ errno = EINVAL;
327+ return (-1);
328+ }
329+#endif /* __DARWIN_UNIX03 */
330+
331+ if (*value == '=') /* no `=' in value */
332+ ++value;
224c7076 333+ /* insure __zone0 is set up before calling __malloc_check_env_name */
34e8f829 334+ if (init__zone0(1)) return (-1);
224c7076 335+ __malloc_check_env_name(name); /* see if we are changing a malloc environment variable */
1f2f436a
A
336+#ifdef LEGACY_CRT1_ENVIRON
337+ ret = __setenv(name, value, rewrite, 1, _NSGetEnviron(), __zone0);
338+ _saved_environ = *_NSGetEnviron();
339+ return ret;
340+#else /* !LEGACY_CRT1_ENVIRON */
224c7076 341+ return (__setenv(name, value, rewrite, 1, _NSGetEnviron(), __zone0));
1f2f436a 342+#endif /* !LEGACY_CRT1_ENVIRON */
3d9156a7 343+}
224c7076 344+
1f2f436a 345 /*
3d9156a7
A
346 * unsetenv(name) --
347 * Delete environmental variable "name".
348 */
349+#if __DARWIN_UNIX03
350+int
351+#else /* !__DARWIN_UNIX03 */
352 void
353+#endif /* __DARWIN_UNIX03 */
9385eb3d
A
354 unsetenv(name)
355 const char *name;
356 {
357- extern char **environ;
224c7076
A
358- char **p;
359- int offset;
3d9156a7
A
360+#if __DARWIN_UNIX03
361+ /* no null ptr or empty str */
362+ if(name == NULL || *name == 0) {
363+ errno = EINVAL;
364+ return (-1);
365+ }
224c7076
A
366
367- while (__findenv(name, &offset)) /* if set multiple times */
368- for (p = &environ[offset];; ++p)
369- if (!(*p = *(p + 1)))
370- break;
3d9156a7
A
371+ /* no '=' in name */
372+ if (strchr(name, '=')) {
373+ errno = EINVAL;
374+ return (-1);
375+ }
224c7076 376+ /* insure __zone0 is set up before calling __malloc_check_env_name */
34e8f829 377+ if (init__zone0(1)) return (-1);
3d9156a7
A
378+#else /* !__DARWIN_UNIX03 */
379+ /* no null ptr or empty str */
380+ if(name == NULL || *name == 0)
381+ return;
224c7076 382+ /* insure __zone0 is set up before calling __malloc_check_env_name */
34e8f829 383+ if (init__zone0(0)) return;
3d9156a7 384+#endif /* __DARWIN_UNIX03 */
224c7076
A
385+ __malloc_check_env_name(name); /* see if we are changing a malloc environment variable */
386+ __unsetenv(name, *_NSGetEnviron(), __zone0);
3d9156a7
A
387+#if __DARWIN_UNIX03
388+ return 0;
389+#endif /* __DARWIN_UNIX03 */
390 }