]> git.saurik.com Git - apple/libc.git/blob - stdlib/setenv-fbsd.c
27061ac1fd1e8df314f1cb6ee541c210212844b6
[apple/libc.git] / stdlib / setenv-fbsd.c
1 /*
2 * Copyright (c) 1987, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
36 #endif /* LIBC_SCCS and not lint */
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD: src/lib/libc/stdlib/setenv.c,v 1.9 2002/03/22 21:53:10 obrien Exp $");
39
40 #include <stddef.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <crt_externs.h>
44 #include <errno.h>
45 #include <sys/types.h>
46 #include <fcntl.h>
47 #include <malloc/malloc.h>
48
49 #define ZONE_OWNS_PTR(zone, ptr) (malloc_zone_from_ptr((ptr)) == zone)
50
51 extern malloc_zone_t *__zone0;
52 extern void __malloc_check_env_name(const char *);
53
54 __private_extern__ char *__findenv(const char *, int *, char **);
55 __private_extern__ int __setenv(const char *, const char *, int, int, char ***, malloc_zone_t *);
56 __private_extern__ void __unsetenv(const char *, char **, malloc_zone_t *);
57
58 #ifndef BUILDING_VARIANT
59 /*
60 * Create the environment malloc zone and give it a recognizable name.
61 */
62 __private_extern__ int
63 init__zone0(int should_set_errno)
64 {
65 if (__zone0) return (0);
66
67 __zone0 = malloc_create_zone(0, 0);
68 if (!__zone0) {
69 if (should_set_errno) {
70 errno = ENOMEM;
71 }
72 return (-1);
73 }
74 malloc_set_zone_name(__zone0, "environ");
75 return (0);
76 }
77
78 /*
79 * The copy flag may have 3 values:
80 * 1 - make a copy of the name/value pair
81 * 0 - take the name as a user-supplied name=value string
82 * -1 - like 0, except we copy of the name=value string in name
83 */
84 __private_extern__ int
85 __setenv(name, value, rewrite, copy, environp, envz)
86 const char *name;
87 const char *value;
88 int rewrite, copy;
89 char ***environp;
90 malloc_zone_t *envz;
91 {
92 char *c;
93 int offset;
94
95 if ((c = __findenv(name, &offset, *environp))) { /* find if already exists */
96 char *e;
97 if (!rewrite)
98 return (0);
99 /*
100 * In UNIX03, we can overwrite only if we allocated the
101 * string. Then we can realloc it if it is too small.
102 */
103 e = (*environp)[offset];
104 if (copy > 0 && ZONE_OWNS_PTR(envz, e)) {
105 size_t l_value = strlen(value);
106 if (strlen(c) < l_value) { /* old smaller; resize*/
107 char *r;
108 size_t len = c - e;
109 if ((r = realloc(e, l_value + len + 1)) == NULL)
110 return (-1);
111 if (r != e) {
112 (*environp)[offset] = r;
113 c = r + len;
114 }
115 }
116 while ( (*c++ = *value++) );
117 return (0);
118 }
119 } else { /* create new slot */
120 int cnt;
121 char **p;
122
123 for (p = *environp, cnt = 0; *p; ++p, ++cnt);
124 if (ZONE_OWNS_PTR(envz, *environp)) { /* just increase size */
125 p = (char **)realloc((char *)*environp,
126 (size_t)(sizeof(char *) * (cnt + 2)));
127 if (!p)
128 return (-1);
129 *environp = p;
130 }
131 else { /* get new space */
132 /* copy old entries into it */
133 p = malloc_zone_malloc(envz, (size_t)(sizeof(char *) * (cnt + 2)));
134 if (!p)
135 return (-1);
136 bcopy(*environp, p, cnt * sizeof(char *));
137 *environp = p;
138 }
139 (*environp)[cnt + 1] = NULL;
140 offset = cnt;
141 }
142 /* For non Unix03, or UnixO3 setenv(), we make a copy of the user's
143 * strings. For Unix03 putenv(), we put the string directly in
144 * the environment. */
145 if (copy > 0) {
146 for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
147 if (!((*environp)[offset] = /* name + `=' + value */
148 malloc_zone_malloc(envz, (size_t)((int)(c - name) + strlen(value) + 2))))
149 return (-1);
150 for (c = (*environp)[offset]; (*c = *name++) && *c != '='; ++c);
151 for (*c++ = '='; (*c++ = *value++); );
152 } else {
153 /* the legacy behavior copies the string */
154 if (copy < 0) {
155 size_t len = strlen(name);
156 if((c = malloc_zone_malloc(envz, len + 1)) == NULL)
157 return (-1);
158 memcpy(c, name, len + 1);
159 name = c;
160 }
161 /* if we malloc-ed the previous value, free it first */
162 if ((*environp)[offset] != NULL && ZONE_OWNS_PTR(envz, (*environp)[offset]))
163 free((*environp)[offset]);
164 (*environp)[offset] = (char *)name;
165 }
166 return (0);
167 }
168
169 __private_extern__ void
170 __unsetenv(const char *name, char **environ, malloc_zone_t *envz)
171 {
172 char **p;
173 int offset;
174
175 while (__findenv(name, &offset, environ)) { /* if set multiple times */
176 /* if we malloc-ed it, free it first */
177 if (ZONE_OWNS_PTR(envz, environ[offset]))
178 free(environ[offset]);
179 for (p = &environ[offset];; ++p)
180 if (!(*p = *(p + 1)))
181 break;
182 }
183 }
184
185 /****************************************************************************/
186 /*
187 * _allocenvstate -- SPI that creates a new state (opaque)
188 */
189 void *
190 _allocenvstate(void)
191 {
192 malloc_zone_t *zone;
193 zone = malloc_create_zone(1000 /* unused */, 0 /* unused */);
194 if (zone) {
195 malloc_set_zone_name(zone, "environ");
196 }
197 return (void *)zone;
198 }
199
200 /*
201 * _copyenv -- SPI that copies a NULL-tereminated char * array in a newly
202 * allocated buffer, compatible with the other SPI env routines. If env
203 * is NULL, a char * array composed of a single NULL is returned. NULL
204 * is returned on error. (This isn't needed anymore, as __setenv will
205 * automatically make a copy in the zone.)
206 */
207 char **
208 _copyenv(char **env)
209 {
210 char **p;
211 int cnt = 1;
212
213 if (env)
214 for (p = env; *p; ++p, ++cnt);
215 p = (char **)malloc((size_t)(sizeof(char *) * cnt));
216 if (!p)
217 return (NULL);
218 if (env)
219 bcopy(env, p, cnt * sizeof(char *));
220 else
221 *p = NULL;
222 return p;
223 }
224
225 /*
226 * _deallocenvstate -- SPI that frees all the memory associated with the state
227 * and all allocated strings, including the environment array itself if it
228 * was copied.
229 */
230 int
231 _deallocenvstate(void *state)
232 {
233 malloc_zone_t *envz;
234
235 if (!(envz = (malloc_zone_t *)state) || envz == __zone0) {
236 errno = EINVAL;
237 return -1;
238 }
239 malloc_destroy_zone(envz);
240 return 0;
241 }
242
243 /*
244 * setenvp -- SPI using an arbitrary pointer to string array and an env state,
245 * created by _allocenvstate(). Initial checking is not done.
246 *
247 * Set the value of the environmental variable "name" to be
248 * "value". If rewrite is set, replace any current value.
249 */
250 int
251 _setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state)
252 {
253 if (init__zone0(1)) return (-1);
254 return (__setenv(name, value, rewrite, 1, envp, (state ? (malloc_zone_t *)state : __zone0)));
255 }
256
257 /*
258 * unsetenv(name) -- SPI using an arbitrary pointer to string array and an env
259 * state, created by _allocenvstate(). Initial checking is not done.
260 *
261 * Delete environmental variable "name".
262 */
263 int
264 _unsetenvp(const char *name, char ***envp, void *state)
265 {
266 if (init__zone0(1)) return (-1);
267 __unsetenv(name, *envp, (state ? (malloc_zone_t *)state : __zone0));
268 return 0;
269 }
270
271 #endif /* !BUILD_VARIANT */
272
273 /*
274 * setenv --
275 * Set the value of the environmental variable "name" to be
276 * "value". If rewrite is set, replace any current value.
277 */
278 int
279 setenv(name, value, rewrite)
280 const char *name;
281 const char *value;
282 int rewrite;
283 {
284 /* no null ptr or empty str */
285 if(name == NULL || *name == 0) {
286 errno = EINVAL;
287 return (-1);
288 }
289
290 #if __DARWIN_UNIX03
291 /* no '=' in name */
292 if (strchr(name, '=')) {
293 errno = EINVAL;
294 return (-1);
295 }
296 #endif /* __DARWIN_UNIX03 */
297
298 if (*value == '=') /* no `=' in value */
299 ++value;
300 /* insure __zone0 is set up before calling __malloc_check_env_name */
301 if (init__zone0(1)) return (-1);
302 __malloc_check_env_name(name); /* see if we are changing a malloc environment variable */
303 return (__setenv(name, value, rewrite, 1, _NSGetEnviron(), __zone0));
304 }
305
306 /*
307 * unsetenv(name) --
308 * Delete environmental variable "name".
309 */
310 #if __DARWIN_UNIX03
311 int
312 #else /* !__DARWIN_UNIX03 */
313 void
314 #endif /* __DARWIN_UNIX03 */
315 unsetenv(name)
316 const char *name;
317 {
318 #if __DARWIN_UNIX03
319 /* no null ptr or empty str */
320 if(name == NULL || *name == 0) {
321 errno = EINVAL;
322 return (-1);
323 }
324
325 /* no '=' in name */
326 if (strchr(name, '=')) {
327 errno = EINVAL;
328 return (-1);
329 }
330 /* insure __zone0 is set up before calling __malloc_check_env_name */
331 if (init__zone0(1)) return (-1);
332 #else /* !__DARWIN_UNIX03 */
333 /* no null ptr or empty str */
334 if(name == NULL || *name == 0)
335 return;
336 /* insure __zone0 is set up before calling __malloc_check_env_name */
337 if (init__zone0(0)) return;
338 #endif /* __DARWIN_UNIX03 */
339 __malloc_check_env_name(name); /* see if we are changing a malloc environment variable */
340 __unsetenv(name, *_NSGetEnviron(), __zone0);
341 #if __DARWIN_UNIX03
342 return 0;
343 #endif /* __DARWIN_UNIX03 */
344 }