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 */