Mercurial > hg > octave-kai > gnulib-hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
12299:7bc45f101cfd | 12300:c8288fd3f281 |
---|---|
1 /* Copyright (C) 1992,1995-1999,2000-2003,2005-2008 Free Software Foundation, Inc. | 1 /* Copyright (C) 1992,1995-1999,2000-2003,2005-2009 Free Software Foundation, Inc. |
2 This file is part of the GNU C Library. | 2 This file is part of the GNU C Library. |
3 | 3 |
4 This program is free software: you can redistribute it and/or modify | 4 This program is free software: you can redistribute it and/or modify |
5 it under the terms of the GNU General Public License as published by | 5 it under the terms of the GNU General Public License as published by |
6 the Free Software Foundation; either version 3 of the License, or | 6 the Free Software Foundation; either version 3 of the License, or |
30 #include <string.h> | 30 #include <string.h> |
31 #if _LIBC || HAVE_UNISTD_H | 31 #if _LIBC || HAVE_UNISTD_H |
32 # include <unistd.h> | 32 # include <unistd.h> |
33 #endif | 33 #endif |
34 | 34 |
35 #if _LIBC || !HAVE_SETENV | |
36 | |
37 #if !_LIBC | 35 #if !_LIBC |
38 # include "malloca.h" | 36 # include "malloca.h" |
39 #endif | 37 #endif |
38 | |
39 #if _LIBC || !HAVE_SETENV | |
40 | 40 |
41 #if !_LIBC | 41 #if !_LIBC |
42 # define __environ environ | 42 # define __environ environ |
43 #endif | 43 #endif |
44 | 44 |
279 } | 279 } |
280 | 280 |
281 int | 281 int |
282 setenv (const char *name, const char *value, int replace) | 282 setenv (const char *name, const char *value, int replace) |
283 { | 283 { |
284 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) | |
285 { | |
286 __set_errno (EINVAL); | |
287 return -1; | |
288 } | |
289 | |
284 return __add_to_environ (name, value, NULL, replace); | 290 return __add_to_environ (name, value, NULL, replace); |
285 } | 291 } |
286 | 292 |
287 /* The `clearenv' was planned to be added to POSIX.1 but probably | 293 /* The `clearenv' was planned to be added to POSIX.1 but probably |
288 never made it. Nevertheless the POSIX.9 standard (POSIX bindings | 294 never made it. Nevertheless the POSIX.9 standard (POSIX bindings |
326 weak_alias (__setenv, setenv) | 332 weak_alias (__setenv, setenv) |
327 weak_alias (__clearenv, clearenv) | 333 weak_alias (__clearenv, clearenv) |
328 #endif | 334 #endif |
329 | 335 |
330 #endif /* _LIBC || !HAVE_SETENV */ | 336 #endif /* _LIBC || !HAVE_SETENV */ |
337 | |
338 /* The rest of this file is called into use when replacing an existing | |
339 but buggy setenv. Known bugs include failure to diagnose invalid | |
340 name, and consuming a leading '=' from value. */ | |
341 #if HAVE_SETENV | |
342 | |
343 # undef setenv | |
344 # define STREQ(a, b) (strcmp (a, b) == 0) | |
345 | |
346 int | |
347 rpl_setenv (const char *name, const char *value, int replace) | |
348 { | |
349 int result; | |
350 if (!name || !*name || strchr (name, '=')) | |
351 { | |
352 errno = EINVAL; | |
353 return -1; | |
354 } | |
355 /* Call the real setenv even if replace is 0, in case implementation | |
356 has underlying data to update, such as when environ changes. */ | |
357 result = setenv (name, value, replace); | |
358 if (result == 0 && replace && *value == '=') | |
359 { | |
360 char *tmp = getenv (name); | |
361 if (!STREQ (tmp, value)) | |
362 { | |
363 int saved_errno; | |
364 size_t len = strlen (value); | |
365 tmp = malloca (len + 2); | |
366 /* Since leading '=' is eaten, double it up. */ | |
367 *tmp = '='; | |
368 memcpy (tmp + 1, value, len + 1); | |
369 result = setenv (name, tmp, replace); | |
370 saved_errno = errno; | |
371 freea (tmp); | |
372 errno = saved_errno; | |
373 } | |
374 } | |
375 return result; | |
376 } | |
377 | |
378 #endif /* HAVE_SETENV */ |