X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fsetenv.c;h=0a5f67dd044a8ee57c28025564798ae5d6fad6dc;hb=3e460831579f03b5f96703073b02052478b854df;hp=fdbf35434253b6f2766225e959597608ef042f3a;hpb=48dbf2c191cd60b64354849d8e0a8fe4a7d613f2;p=gnulib.git diff --git a/lib/setenv.c b/lib/setenv.c index fdbf35434..0a5f67dd0 100644 --- a/lib/setenv.c +++ b/lib/setenv.c @@ -1,67 +1,59 @@ -/* Copyright (C) 1992,1995-1999,2000-2003 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1995-2003, 2005-2011 Free Software Foundation, Inc. This file is part of the GNU C Library. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. - The GNU C Library is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -#if HAVE_CONFIG_H +#if !_LIBC +# define _GL_USE_STDLIB_ALLOC 1 # include #endif +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the name == NULL test below. */ +#define _GL_ARG_NONNULL(params) + #include +/* Specification. */ +#include + #include -#if !_LIBC -# if !defined errno && !defined HAVE_ERRNO_DECL -extern int errno; -# endif +#ifndef __set_errno # define __set_errno(ev) ((errno) = (ev)) #endif -#if _LIBC || HAVE_STDLIB_H -# include -#endif -#if _LIBC || HAVE_STRING_H -# include -#endif +#include #if _LIBC || HAVE_UNISTD_H # include #endif -/* For those losing systems which don't have 'alloca' we have to add - some additional code emulating it. */ -#if _LIBC || HAVE_ALLOCA -# define freea(p) /* nothing */ -#else -# define alloca(n) malloc (n) -# define freea(p) free (p) +#if !_LIBC +# include "malloca.h" #endif +#if _LIBC || !HAVE_SETENV + #if !_LIBC -# define __environ environ -# ifndef HAVE_ENVIRON_DECL -extern char **environ; -# endif +# define __environ environ #endif #if _LIBC /* This lock protects against simultaneous modifications of `environ'. */ # include __libc_lock_define_initialized (static, envlock) -# define LOCK __libc_lock_lock (envlock) -# define UNLOCK __libc_lock_unlock (envlock) +# define LOCK __libc_lock_lock (envlock) +# define UNLOCK __libc_lock_unlock (envlock) #else # define LOCK # define UNLOCK @@ -80,8 +72,8 @@ __libc_lock_define_initialized (static, envlock) values are from a small set. Outside glibc this will eat up all memory after a while. */ #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ - && defined __GNUC__) -# define USE_TSEARCH 1 + && defined __GNUC__) +# define USE_TSEARCH 1 # include typedef int (*compar_fn_t) (const void *, const void *); @@ -90,9 +82,9 @@ typedef int (*compar_fn_t) (const void *, const void *); static void *known_values; # define KNOWN_VALUE(Str) \ - ({ \ - void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ - value != NULL ? *(char **) value : NULL; \ + ({ \ + void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ + value != NULL ? *(char **) value : NULL; \ }) # define STORE_VALUE(Str) \ tsearch (Str, &known_values, (compar_fn_t) strcmp) @@ -119,10 +111,10 @@ static char **last_environ; free the strings. */ int __add_to_environ (const char *name, const char *value, const char *combined, - int replace) + int replace) { - register char **ep; - register size_t size; + char **ep; + size_t size; const size_t namelen = strlen (name); const size_t vallen = value != NULL ? strlen (value) + 1 : 0; @@ -136,10 +128,10 @@ __add_to_environ (const char *name, const char *value, const char *combined, if (ep != NULL) { for (; *ep != NULL; ++ep) - if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') - break; - else - ++size; + if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; } if (ep == NULL || *ep == NULL) @@ -151,69 +143,79 @@ __add_to_environ (const char *name, const char *value, const char *combined, /* We allocated this space; we can extend it. */ new_environ = - (char **) (last_environ == NULL - ? malloc ((size + 2) * sizeof (char *)) - : realloc (last_environ, (size + 2) * sizeof (char *))); + (char **) (last_environ == NULL + ? malloc ((size + 2) * sizeof (char *)) + : realloc (last_environ, (size + 2) * sizeof (char *))); if (new_environ == NULL) - { - UNLOCK; - return -1; - } + { + /* It's easier to set errno to ENOMEM than to rely on the + 'malloc-posix' and 'realloc-posix' gnulib modules. */ + __set_errno (ENOMEM); + UNLOCK; + return -1; + } /* If the whole entry is given add it. */ if (combined != NULL) - /* We must not add the string to the search tree since it belongs - to the user. */ - new_environ[size] = (char *) combined; + /* We must not add the string to the search tree since it belongs + to the user. */ + new_environ[size] = (char *) combined; else - { - /* See whether the value is already known. */ + { + /* See whether the value is already known. */ #ifdef USE_TSEARCH - new_value = (char *) alloca (namelen + 1 + vallen); # ifdef _LIBC - __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), - value, vallen); + new_value = (char *) alloca (namelen + 1 + vallen); + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); # else - memcpy (new_value, name, namelen); - new_value[namelen] = '='; - memcpy (&new_value[namelen + 1], value, vallen); + new_value = (char *) malloca (namelen + 1 + vallen); + if (new_value == NULL) + { + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); # endif - new_environ[size] = KNOWN_VALUE (new_value); - if (new_environ[size] == NULL) + new_environ[size] = KNOWN_VALUE (new_value); + if (new_environ[size] == NULL) #endif - { - new_environ[size] = (char *) malloc (namelen + 1 + vallen); - if (new_environ[size] == NULL) - { -#ifdef USE_TSEARCH - freea (new_value); + { + new_environ[size] = (char *) malloc (namelen + 1 + vallen); + if (new_environ[size] == NULL) + { +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); #endif - __set_errno (ENOMEM); - UNLOCK; - return -1; - } + __set_errno (ENOMEM); + UNLOCK; + return -1; + } #ifdef USE_TSEARCH - memcpy (new_environ[size], new_value, namelen + 1 + vallen); + memcpy (new_environ[size], new_value, namelen + 1 + vallen); #else - memcpy (new_environ[size], name, namelen); - new_environ[size][namelen] = '='; - memcpy (&new_environ[size][namelen + 1], value, vallen); + memcpy (new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy (&new_environ[size][namelen + 1], value, vallen); #endif - /* And save the value now. We cannot do this when we remove - the string since then we cannot decide whether it is a - user string or not. */ - STORE_VALUE (new_environ[size]); - } -#ifdef USE_TSEARCH - freea (new_value); + /* And save the value now. We cannot do this when we remove + the string since then we cannot decide whether it is a + user string or not. */ + STORE_VALUE (new_environ[size]); + } +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); #endif - } + } if (__environ != last_environ) - memcpy ((char *) new_environ, (char *) __environ, - size * sizeof (char *)); + memcpy ((char *) new_environ, (char *) __environ, + size * sizeof (char *)); new_environ[size + 1] = NULL; @@ -225,48 +227,57 @@ __add_to_environ (const char *name, const char *value, const char *combined, /* Use the user string if given. */ if (combined != NULL) - np = (char *) combined; + np = (char *) combined; else - { + { #ifdef USE_TSEARCH - char *new_value = alloca (namelen + 1 + vallen); + char *new_value; # ifdef _LIBC - __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), - value, vallen); + new_value = alloca (namelen + 1 + vallen); + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); # else - memcpy (new_value, name, namelen); - new_value[namelen] = '='; - memcpy (&new_value[namelen + 1], value, vallen); + new_value = malloca (namelen + 1 + vallen); + if (new_value == NULL) + { + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); # endif - np = KNOWN_VALUE (new_value); - if (np == NULL) + np = KNOWN_VALUE (new_value); + if (np == NULL) #endif - { - np = malloc (namelen + 1 + vallen); - if (np == NULL) - { -#ifdef USE_TSEARCH - freea (new_value); + { + np = (char *) malloc (namelen + 1 + vallen); + if (np == NULL) + { +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); #endif - UNLOCK; - return -1; - } + __set_errno (ENOMEM); + UNLOCK; + return -1; + } #ifdef USE_TSEARCH - memcpy (np, new_value, namelen + 1 + vallen); + memcpy (np, new_value, namelen + 1 + vallen); #else - memcpy (np, name, namelen); - np[namelen] = '='; - memcpy (&np[namelen + 1], value, vallen); + memcpy (np, name, namelen); + np[namelen] = '='; + memcpy (&np[namelen + 1], value, vallen); #endif - /* And remember the value. */ - STORE_VALUE (np); - } -#ifdef USE_TSEARCH - freea (new_value); + /* And remember the value. */ + STORE_VALUE (np); + } +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); #endif - } + } *ep = np; } @@ -279,6 +290,12 @@ __add_to_environ (const char *name, const char *value, const char *combined, int setenv (const char *name, const char *value, int replace) { + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + __set_errno (EINVAL); + return -1; + } + return __add_to_environ (name, value, NULL, replace); } @@ -286,7 +303,7 @@ setenv (const char *name, const char *value, int replace) never made it. Nevertheless the POSIX.9 standard (POSIX bindings for Fortran 77) requires this function. */ int -clearenv () +clearenv (void) { LOCK; @@ -324,3 +341,50 @@ text_set_element (__libc_subfreeres, free_mem); weak_alias (__setenv, setenv) weak_alias (__clearenv, clearenv) #endif + +#endif /* _LIBC || !HAVE_SETENV */ + +/* The rest of this file is called into use when replacing an existing + but buggy setenv. Known bugs include failure to diagnose invalid + name, and consuming a leading '=' from value. */ +#if HAVE_SETENV + +# undef setenv +# if !HAVE_DECL_SETENV +extern int setenv (const char *, const char *, int); +# endif +# define STREQ(a, b) (strcmp (a, b) == 0) + +int +rpl_setenv (const char *name, const char *value, int replace) +{ + int result; + if (!name || !*name || strchr (name, '=')) + { + errno = EINVAL; + return -1; + } + /* Call the real setenv even if replace is 0, in case implementation + has underlying data to update, such as when environ changes. */ + result = setenv (name, value, replace); + if (result == 0 && replace && *value == '=') + { + char *tmp = getenv (name); + if (!STREQ (tmp, value)) + { + int saved_errno; + size_t len = strlen (value); + tmp = malloca (len + 2); + /* Since leading '=' is eaten, double it up. */ + *tmp = '='; + memcpy (tmp + 1, value, len + 1); + result = setenv (name, tmp, replace); + saved_errno = errno; + freea (tmp); + errno = saved_errno; + } + } + return result; +} + +#endif /* HAVE_SETENV */