X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fsetenv.c;h=995a0f26a1c7c9df954101aa57bc72db751503cf;hb=a8a1dc286152661e640f0839e3ccd79e0898db6d;hp=335d1d2f9a73280fe01ed0c40a6966eaac80a269;hpb=caf80066789b1abb3014ae2b916f277122b64451;p=gnulib.git diff --git a/lib/setenv.c b/lib/setenv.c index 335d1d2f9..995a0f26a 100644 --- a/lib/setenv.c +++ b/lib/setenv.c @@ -1,53 +1,59 @@ -/* Copyright (C) 1992,1995-1999,2000-2003,2005 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1995-2003, 2005-2013 Free Software Foundation, Inc. This file is part of the GNU C Library. - This program is free software; you can redistribute it and/or modify + 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 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. 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 General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -#ifdef HAVE_CONFIG_H +#if !_LIBC +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the name == NULL test below. */ +# define _GL_ARG_NONNULL(params) + +# define _GL_USE_STDLIB_ALLOC 1 # include #endif + #include +/* Specification. */ +#include + #include #ifndef __set_errno # define __set_errno(ev) ((errno) = (ev)) #endif -#include #include #if _LIBC || HAVE_UNISTD_H # include #endif #if !_LIBC -# include "allocsa.h" +# 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'. */ +/* 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 @@ -66,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 *); @@ -76,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) @@ -97,18 +103,18 @@ static void *known_values; static char **last_environ; -/* This function is used by `setenv' and `putenv'. The difference between +/* This function is used by 'setenv' and 'putenv'. The difference between the two functions is that for the former must create a new string which - is then placed in the environment, while the argument of `putenv' + is then placed in the environment, while the argument of 'putenv' must be used directly. This is all complicated by the fact that we try - to reuse values once generated for a `setenv' call since we can never + to reuse values once generated for a 'setenv' call since we can never 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; @@ -122,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) @@ -137,76 +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 # ifdef _LIBC - new_value = (char *) alloca (namelen + 1 + vallen); - __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 - new_value = (char *) allocsa (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); + 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) - { + { + new_environ[size] = (char *) malloc (namelen + 1 + vallen); + if (new_environ[size] == NULL) + { #if defined USE_TSEARCH && !defined _LIBC - freesa (new_value); + 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]); - } + /* 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 - freesa (new_value); + 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; @@ -218,57 +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; + char *new_value; # ifdef _LIBC - new_value = alloca (namelen + 1 + vallen); - __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 - new_value = allocsa (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); + 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) - { + { + np = (char *) malloc (namelen + 1 + vallen); + if (np == NULL) + { #if defined USE_TSEARCH && !defined _LIBC - freesa (new_value); + freea (new_value); #endif - __set_errno (ENOMEM); - 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); - } + /* And remember the value. */ + STORE_VALUE (np); + } #if defined USE_TSEARCH && !defined _LIBC - freesa (new_value); + freea (new_value); #endif - } + } *ep = np; } @@ -281,10 +290,16 @@ __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); } -/* The `clearenv' was planned to be added to POSIX.1 but probably +/* The 'clearenv' was planned to be added to POSIX.1 but probably never made it. Nevertheless the POSIX.9 standard (POSIX bindings for Fortran 77) requires this function. */ int @@ -326,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 */