]> git.saurik.com Git - apple/libc.git/blame - stdlib/setenv-fbsd.c
Libc-594.1.4.tar.gz
[apple/libc.git] / stdlib / setenv-fbsd.c
CommitLineData
224c7076
A
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)
35static 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
51extern malloc_zone_t *__zone0;
52extern 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
34e8f829
A
59/*
60 * Create the environment malloc zone and give it a recognizable name.
61 */
62__private_extern__ int
63init__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
224c7076
A
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 */
189void *
190_allocenvstate(void)
191{
34e8f829
A
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;
224c7076
A
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 */
207char **
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 */
230int
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 */
250int
251_setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state)
252{
34e8f829 253 if (init__zone0(1)) return (-1);
224c7076
A
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 */
263int
264_unsetenvp(const char *name, char ***envp, void *state)
265{
34e8f829 266 if (init__zone0(1)) return (-1);
224c7076
A
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 */
278int
279setenv(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 */
34e8f829 301 if (init__zone0(1)) return (-1);
224c7076
A
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
311int
312#else /* !__DARWIN_UNIX03 */
313void
314#endif /* __DARWIN_UNIX03 */
315unsetenv(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 */
34e8f829 331 if (init__zone0(1)) return (-1);
224c7076
A
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 */
34e8f829 337 if (init__zone0(0)) return;
224c7076
A
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}