Mercurial > hg > octave-kai > gnulib-hg
annotate lib/setenv.c @ 12300:c8288fd3f281
setenv, unsetenv: work around various bugs
POSIX requires setenv(NULL,"",0), setenv("a=b","",0),
unsetenv(NULL), and unsetenv("a=b") to fail with EINVAL, but
many BSD implementations lack validation. The gnulib
replacement for void unsetenv did not do validation, and the
replacement for setenv was out of sync with glibc. Also, some
BSD implementations of setenv("a","==",1) eat the leading '='.
See also some recent Austin Group interpretations on environ:
http://austingroupbugs.net/view.php?id=167
http://austingroupbugs.net/view.php?id=185
* lib/setenv.c (setenv) [!HAVE_SETENV]: Resync from glibc.
(setenv) [HAVE_SETENV]: Work around bugs.
* lib/unsetenv.c (unsetenv) [HAVE_UNSETENV]: Work around bugs.
* m4/setenv.m4 (gl_FUNC_SETENV_SEPARATE, gl_FUNC_UNSETENV): Check
for bugs.
(gl_FUNC_SETENV): Write in terms of gl_FUNC_SETENV_SEPARATE.
* m4/environ.m4 (gl_ENVIRON): Avoid expand-before-require.
* m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Update defaults.
* modules/stdlib (Makefile.am): Update substitutions.
* lib/stdlib.in.h (setenv, unsetenv): Update prototypes.
* doc/posix-functions/setenv.texi (setenv): Document the bugs.
* doc/posix-functions/unsetenv.texi (unsetenv): Likewise.
* modules/setenv-tests: New test.
* modules/unsetenv-tests: Likewise.
* tests/test-setenv.c: New file.
* tests/test-unsetenv.c: Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Sat, 14 Nov 2009 22:13:10 -0700 |
parents | 1d443a80afc4 |
children | e8d2c6fc33ad |
rev | line source |
---|---|
12300
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
1 /* Copyright (C) 1992,1995-1999,2000-2003,2005-2009 Free Software Foundation, Inc. |
4080 | 2 This file is part of the GNU C Library. |
574 | 3 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8948
diff
changeset
|
4 This program is free software: you can redistribute it and/or modify |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
5 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8948
diff
changeset
|
6 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8948
diff
changeset
|
7 (at your option) any later version. |
574 | 8 |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
9 This program is distributed in the hope that it will be useful, |
4080 | 10 but WITHOUT ANY WARRANTY; without even the implied warranty of |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
12 GNU General Public License for more details. |
574 | 13 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8948
diff
changeset
|
14 You should have received a copy of the GNU General Public License |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8948
diff
changeset
|
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
574 | 16 |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
7074
diff
changeset
|
17 #if !_LIBC |
653 | 18 # include <config.h> |
574 | 19 #endif |
4156
99ea86c79f44
Make it possibly to simply write: #include <alloca.h>.
Bruno Haible <bruno@clisp.org>
parents:
4080
diff
changeset
|
20 #include <alloca.h> |
4080 | 21 |
9545
c596ca4e89b4
Split setenv module into setenv and unsetenv. Get rid of setenv.h.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
22 /* Specification. */ |
c596ca4e89b4
Split setenv module into setenv and unsetenv. Get rid of setenv.h.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
23 #include <stdlib.h> |
c596ca4e89b4
Split setenv module into setenv and unsetenv. Get rid of setenv.h.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
24 |
574 | 25 #include <errno.h> |
5159 | 26 #ifndef __set_errno |
4080 | 27 # define __set_errno(ev) ((errno) = (ev)) |
28 #endif | |
574 | 29 |
4683
4452e4c45cc4
Assume ANSI C <string.h>, <stdlib.h>.
Bruno Haible <bruno@clisp.org>
parents:
4440
diff
changeset
|
30 #include <string.h> |
7074
75561a6a4a30
setenv.c comes from gettext / libiconv again.
Bruno Haible <bruno@clisp.org>
parents:
6711
diff
changeset
|
31 #if _LIBC || HAVE_UNISTD_H |
75561a6a4a30
setenv.c comes from gettext / libiconv again.
Bruno Haible <bruno@clisp.org>
parents:
6711
diff
changeset
|
32 # include <unistd.h> |
75561a6a4a30
setenv.c comes from gettext / libiconv again.
Bruno Haible <bruno@clisp.org>
parents:
6711
diff
changeset
|
33 #endif |
574 | 34 |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
35 #if !_LIBC |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
36 # include "malloca.h" |
4080 | 37 #endif |
38 | |
12300
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
39 #if _LIBC || !HAVE_SETENV |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
40 |
4080 | 41 #if !_LIBC |
2718 | 42 # define __environ environ |
4080 | 43 #endif |
44 | |
45 #if _LIBC | |
46 /* This lock protects against simultaneous modifications of `environ'. */ | |
47 # include <bits/libc-lock.h> | |
48 __libc_lock_define_initialized (static, envlock) | |
49 # define LOCK __libc_lock_lock (envlock) | |
50 # define UNLOCK __libc_lock_unlock (envlock) | |
51 #else | |
52 # define LOCK | |
53 # define UNLOCK | |
54 #endif | |
55 | |
56 /* In the GNU C library we must keep the namespace clean. */ | |
57 #ifdef _LIBC | |
58 # define setenv __setenv | |
59 # define clearenv __clearenv | |
60 # define tfind __tfind | |
61 # define tsearch __tsearch | |
574 | 62 #endif |
63 | |
4080 | 64 /* In the GNU C library implementation we try to be more clever and |
65 allow arbitrarily many changes of the environment given that the used | |
66 values are from a small set. Outside glibc this will eat up all | |
67 memory after a while. */ | |
68 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ | |
69 && defined __GNUC__) | |
70 # define USE_TSEARCH 1 | |
71 # include <search.h> | |
72 typedef int (*compar_fn_t) (const void *, const void *); | |
73 | |
74 /* This is a pointer to the root of the search tree with the known | |
75 values. */ | |
76 static void *known_values; | |
77 | |
78 # define KNOWN_VALUE(Str) \ | |
79 ({ \ | |
80 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ | |
81 value != NULL ? *(char **) value : NULL; \ | |
82 }) | |
83 # define STORE_VALUE(Str) \ | |
84 tsearch (Str, &known_values, (compar_fn_t) strcmp) | |
85 | |
86 #else | |
87 # undef USE_TSEARCH | |
88 | |
89 # define KNOWN_VALUE(Str) NULL | |
90 # define STORE_VALUE(Str) do { } while (0) | |
91 | |
92 #endif | |
93 | |
94 | |
95 /* If this variable is not a null pointer we allocated the current | |
96 environment. */ | |
97 static char **last_environ; | |
98 | |
99 | |
100 /* This function is used by `setenv' and `putenv'. The difference between | |
101 the two functions is that for the former must create a new string which | |
102 is then placed in the environment, while the argument of `putenv' | |
103 must be used directly. This is all complicated by the fact that we try | |
104 to reuse values once generated for a `setenv' call since we can never | |
105 free the strings. */ | |
574 | 106 int |
4080 | 107 __add_to_environ (const char *name, const char *value, const char *combined, |
108 int replace) | |
574 | 109 { |
110 register char **ep; | |
111 register size_t size; | |
112 const size_t namelen = strlen (name); | |
4080 | 113 const size_t vallen = value != NULL ? strlen (value) + 1 : 0; |
114 | |
115 LOCK; | |
116 | |
117 /* We have to get the pointer now that we have the lock and not earlier | |
118 since another thread might have created a new environment. */ | |
119 ep = __environ; | |
574 | 120 |
121 size = 0; | |
4080 | 122 if (ep != NULL) |
123 { | |
124 for (; *ep != NULL; ++ep) | |
125 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') | |
126 break; | |
127 else | |
128 ++size; | |
129 } | |
574 | 130 |
4080 | 131 if (ep == NULL || *ep == NULL) |
574 | 132 { |
133 char **new_environ; | |
4080 | 134 #ifdef USE_TSEARCH |
135 char *new_value; | |
136 #endif | |
574 | 137 |
4080 | 138 /* We allocated this space; we can extend it. */ |
139 new_environ = | |
140 (char **) (last_environ == NULL | |
141 ? malloc ((size + 2) * sizeof (char *)) | |
142 : realloc (last_environ, (size + 2) * sizeof (char *))); | |
574 | 143 if (new_environ == NULL) |
4080 | 144 { |
145 UNLOCK; | |
146 return -1; | |
147 } | |
148 | |
149 /* If the whole entry is given add it. */ | |
150 if (combined != NULL) | |
151 /* We must not add the string to the search tree since it belongs | |
152 to the user. */ | |
153 new_environ[size] = (char *) combined; | |
154 else | |
155 { | |
156 /* See whether the value is already known. */ | |
157 #ifdef USE_TSEARCH | |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
158 # ifdef _LIBC |
4080 | 159 new_value = (char *) alloca (namelen + 1 + vallen); |
160 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), | |
161 value, vallen); | |
162 # else | |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
163 new_value = (char *) malloca (namelen + 1 + vallen); |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
164 if (new_value == NULL) |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
165 { |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
166 __set_errno (ENOMEM); |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
167 UNLOCK; |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
168 return -1; |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
169 } |
4080 | 170 memcpy (new_value, name, namelen); |
171 new_value[namelen] = '='; | |
172 memcpy (&new_value[namelen + 1], value, vallen); | |
173 # endif | |
574 | 174 |
4080 | 175 new_environ[size] = KNOWN_VALUE (new_value); |
176 if (new_environ[size] == NULL) | |
177 #endif | |
178 { | |
179 new_environ[size] = (char *) malloc (namelen + 1 + vallen); | |
180 if (new_environ[size] == NULL) | |
181 { | |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
182 #if defined USE_TSEARCH && !defined _LIBC |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
183 freea (new_value); |
4080 | 184 #endif |
185 __set_errno (ENOMEM); | |
186 UNLOCK; | |
187 return -1; | |
188 } | |
189 | |
190 #ifdef USE_TSEARCH | |
191 memcpy (new_environ[size], new_value, namelen + 1 + vallen); | |
192 #else | |
193 memcpy (new_environ[size], name, namelen); | |
194 new_environ[size][namelen] = '='; | |
195 memcpy (&new_environ[size][namelen + 1], value, vallen); | |
196 #endif | |
197 /* And save the value now. We cannot do this when we remove | |
198 the string since then we cannot decide whether it is a | |
199 user string or not. */ | |
200 STORE_VALUE (new_environ[size]); | |
201 } | |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
202 #if defined USE_TSEARCH && !defined _LIBC |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
203 freea (new_value); |
4080 | 204 #endif |
574 | 205 } |
206 | |
207 if (__environ != last_environ) | |
208 memcpy ((char *) new_environ, (char *) __environ, | |
209 size * sizeof (char *)); | |
210 | |
211 new_environ[size + 1] = NULL; | |
212 | |
213 last_environ = __environ = new_environ; | |
214 } | |
215 else if (replace) | |
216 { | |
4080 | 217 char *np; |
218 | |
219 /* Use the user string if given. */ | |
220 if (combined != NULL) | |
221 np = (char *) combined; | |
222 else | |
574 | 223 { |
4080 | 224 #ifdef USE_TSEARCH |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
225 char *new_value; |
4080 | 226 # ifdef _LIBC |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
227 new_value = alloca (namelen + 1 + vallen); |
4080 | 228 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), |
229 value, vallen); | |
230 # else | |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
231 new_value = malloca (namelen + 1 + vallen); |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
232 if (new_value == NULL) |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
233 { |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
234 __set_errno (ENOMEM); |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
235 UNLOCK; |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
236 return -1; |
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
237 } |
4080 | 238 memcpy (new_value, name, namelen); |
239 new_value[namelen] = '='; | |
240 memcpy (&new_value[namelen + 1], value, vallen); | |
241 # endif | |
242 | |
243 np = KNOWN_VALUE (new_value); | |
244 if (np == NULL) | |
245 #endif | |
246 { | |
247 np = malloc (namelen + 1 + vallen); | |
248 if (np == NULL) | |
249 { | |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
250 #if defined USE_TSEARCH && !defined _LIBC |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
251 freea (new_value); |
4080 | 252 #endif |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
253 __set_errno (ENOMEM); |
4080 | 254 UNLOCK; |
255 return -1; | |
256 } | |
257 | |
258 #ifdef USE_TSEARCH | |
259 memcpy (np, new_value, namelen + 1 + vallen); | |
260 #else | |
261 memcpy (np, name, namelen); | |
262 np[namelen] = '='; | |
263 memcpy (&np[namelen + 1], value, vallen); | |
264 #endif | |
265 /* And remember the value. */ | |
266 STORE_VALUE (np); | |
267 } | |
4929
4192ff0fff14
Use allocsa instead of alloca.
Bruno Haible <bruno@clisp.org>
parents:
4691
diff
changeset
|
268 #if defined USE_TSEARCH && !defined _LIBC |
8948
a162347a0232
Update after allocsa -> malloca renaming.
Bruno Haible <bruno@clisp.org>
parents:
8307
diff
changeset
|
269 freea (new_value); |
4080 | 270 #endif |
574 | 271 } |
4080 | 272 |
273 *ep = np; | |
574 | 274 } |
275 | |
4080 | 276 UNLOCK; |
277 | |
574 | 278 return 0; |
279 } | |
280 | |
4080 | 281 int |
282 setenv (const char *name, const char *value, int replace) | |
283 { | |
12300
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
284 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
285 { |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
286 __set_errno (EINVAL); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
287 return -1; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
288 } |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
289 |
4080 | 290 return __add_to_environ (name, value, NULL, replace); |
291 } | |
292 | |
293 /* The `clearenv' was planned to be added to POSIX.1 but probably | |
294 never made it. Nevertheless the POSIX.9 standard (POSIX bindings | |
295 for Fortran 77) requires this function. */ | |
296 int | |
4691 | 297 clearenv (void) |
574 | 298 { |
4080 | 299 LOCK; |
300 | |
301 if (__environ == last_environ && __environ != NULL) | |
302 { | |
303 /* We allocated this environment so we can free it. */ | |
304 free (__environ); | |
305 last_environ = NULL; | |
306 } | |
307 | |
308 /* Clear the environment pointer removes the whole environment. */ | |
309 __environ = NULL; | |
574 | 310 |
4080 | 311 UNLOCK; |
312 | |
313 return 0; | |
574 | 314 } |
4080 | 315 |
316 #ifdef _LIBC | |
317 static void | |
318 free_mem (void) | |
319 { | |
320 /* Remove all traces. */ | |
321 clearenv (); | |
322 | |
323 /* Now remove the search tree. */ | |
324 __tdestroy (known_values, free); | |
325 known_values = NULL; | |
326 } | |
327 text_set_element (__libc_subfreeres, free_mem); | |
328 | |
329 | |
330 # undef setenv | |
331 # undef clearenv | |
332 weak_alias (__setenv, setenv) | |
333 weak_alias (__clearenv, clearenv) | |
334 #endif | |
8307
330dcd891960
Make it possible to compile setenv.c separately, unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
335 |
330dcd891960
Make it possible to compile setenv.c separately, unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
336 #endif /* _LIBC || !HAVE_SETENV */ |
12300
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
337 |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
338 /* The rest of this file is called into use when replacing an existing |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
339 but buggy setenv. Known bugs include failure to diagnose invalid |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
340 name, and consuming a leading '=' from value. */ |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
341 #if HAVE_SETENV |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
342 |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
343 # undef setenv |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
344 # define STREQ(a, b) (strcmp (a, b) == 0) |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
345 |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
346 int |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
347 rpl_setenv (const char *name, const char *value, int replace) |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
348 { |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
349 int result; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
350 if (!name || !*name || strchr (name, '=')) |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
351 { |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
352 errno = EINVAL; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
353 return -1; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
354 } |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
355 /* Call the real setenv even if replace is 0, in case implementation |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
356 has underlying data to update, such as when environ changes. */ |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
357 result = setenv (name, value, replace); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
358 if (result == 0 && replace && *value == '=') |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
359 { |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
360 char *tmp = getenv (name); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
361 if (!STREQ (tmp, value)) |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
362 { |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
363 int saved_errno; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
364 size_t len = strlen (value); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
365 tmp = malloca (len + 2); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
366 /* Since leading '=' is eaten, double it up. */ |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
367 *tmp = '='; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
368 memcpy (tmp + 1, value, len + 1); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
369 result = setenv (name, tmp, replace); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
370 saved_errno = errno; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
371 freea (tmp); |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
372 errno = saved_errno; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
373 } |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
374 } |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
375 return result; |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
376 } |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
377 |
c8288fd3f281
setenv, unsetenv: work around various bugs
Eric Blake <ebb9@byu.net>
parents:
9721
diff
changeset
|
378 #endif /* HAVE_SETENV */ |