1/* Copyright (C) 1992,1995-1999,2000-2003,2005-2007 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 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 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with this program; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 17 18#if !_LIBC 19# include <config.h> 20#endif 21#include <alloca.h> 22 23#include <errno.h> 24#ifndef __set_errno 25# define __set_errno(ev) ((errno) = (ev)) 26#endif 27 28#include <stdlib.h> 29#include <string.h> 30#if _LIBC || HAVE_UNISTD_H 31# include <unistd.h> 32#endif 33 34#if _LIBC || !HAVE_SETENV 35 36#if !_LIBC 37# include "allocsa.h" 38#endif 39 40#if !_LIBC 41# define __environ environ 42# ifndef HAVE_ENVIRON_DECL 43extern char **environ; 44# endif 45#endif 46 47#if _LIBC 48/* This lock protects against simultaneous modifications of `environ'. */ 49# include <bits/libc-lock.h> 50__libc_lock_define_initialized (static, envlock) 51# define LOCK __libc_lock_lock (envlock) 52# define UNLOCK __libc_lock_unlock (envlock) 53#else 54# define LOCK 55# define UNLOCK 56#endif 57 58/* In the GNU C library we must keep the namespace clean. */ 59#ifdef _LIBC 60# define setenv __setenv 61# define clearenv __clearenv 62# define tfind __tfind 63# define tsearch __tsearch 64#endif 65 66/* In the GNU C library implementation we try to be more clever and 67 allow arbitrarily many changes of the environment given that the used 68 values are from a small set. Outside glibc this will eat up all 69 memory after a while. */ 70#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ 71 && defined __GNUC__) 72# define USE_TSEARCH 1 73# include <search.h> 74typedef int (*compar_fn_t) (const void *, const void *); 75 76/* This is a pointer to the root of the search tree with the known 77 values. */ 78static void *known_values; 79 80# define KNOWN_VALUE(Str) \ 81 ({ \ 82 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ 83 value != NULL ? *(char **) value : NULL; \ 84 }) 85# define STORE_VALUE(Str) \ 86 tsearch (Str, &known_values, (compar_fn_t) strcmp) 87 88#else 89# undef USE_TSEARCH 90 91# define KNOWN_VALUE(Str) NULL 92# define STORE_VALUE(Str) do { } while (0) 93 94#endif 95 96 97/* If this variable is not a null pointer we allocated the current 98 environment. */ 99static char **last_environ; 100 101 102/* This function is used by `setenv' and `putenv'. The difference between 103 the two functions is that for the former must create a new string which 104 is then placed in the environment, while the argument of `putenv' 105 must be used directly. This is all complicated by the fact that we try 106 to reuse values once generated for a `setenv' call since we can never 107 free the strings. */ 108int 109__add_to_environ (const char *name, const char *value, const char *combined, 110 int replace) 111{ 112 register char **ep; 113 register size_t size; 114 const size_t namelen = strlen (name); 115 const size_t vallen = value != NULL ? strlen (value) + 1 : 0; 116 117 LOCK; 118 119 /* We have to get the pointer now that we have the lock and not earlier 120 since another thread might have created a new environment. */ 121 ep = __environ; 122 123 size = 0; 124 if (ep != NULL) 125 { 126 for (; *ep != NULL; ++ep) 127 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') 128 break; 129 else 130 ++size; 131 } 132 133 if (ep == NULL || *ep == NULL) 134 { 135 char **new_environ; 136#ifdef USE_TSEARCH 137 char *new_value; 138#endif 139 140 /* We allocated this space; we can extend it. */ 141 new_environ = 142 (char **) (last_environ == NULL 143 ? malloc ((size + 2) * sizeof (char *)) 144 : realloc (last_environ, (size + 2) * sizeof (char *))); 145 if (new_environ == NULL) 146 { 147 UNLOCK; 148 return -1; 149 } 150 151 /* If the whole entry is given add it. */ 152 if (combined != NULL) 153 /* We must not add the string to the search tree since it belongs 154 to the user. */ 155 new_environ[size] = (char *) combined; 156 else 157 { 158 /* See whether the value is already known. */ 159#ifdef USE_TSEARCH 160# ifdef _LIBC 161 new_value = (char *) alloca (namelen + 1 + vallen); 162 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), 163 value, vallen); 164# else 165 new_value = (char *) allocsa (namelen + 1 + vallen); 166 if (new_value == NULL) 167 { 168 __set_errno (ENOMEM); 169 UNLOCK; 170 return -1; 171 } 172 memcpy (new_value, name, namelen); 173 new_value[namelen] = '='; 174 memcpy (&new_value[namelen + 1], value, vallen); 175# endif 176 177 new_environ[size] = KNOWN_VALUE (new_value); 178 if (new_environ[size] == NULL) 179#endif 180 { 181 new_environ[size] = (char *) malloc (namelen + 1 + vallen); 182 if (new_environ[size] == NULL) 183 { 184#if defined USE_TSEARCH && !defined _LIBC 185 freesa (new_value); 186#endif 187 __set_errno (ENOMEM); 188 UNLOCK; 189 return -1; 190 } 191 192#ifdef USE_TSEARCH 193 memcpy (new_environ[size], new_value, namelen + 1 + vallen); 194#else 195 memcpy (new_environ[size], name, namelen); 196 new_environ[size][namelen] = '='; 197 memcpy (&new_environ[size][namelen + 1], value, vallen); 198#endif 199 /* And save the value now. We cannot do this when we remove 200 the string since then we cannot decide whether it is a 201 user string or not. */ 202 STORE_VALUE (new_environ[size]); 203 } 204#if defined USE_TSEARCH && !defined _LIBC 205 freesa (new_value); 206#endif 207 } 208 209 if (__environ != last_environ) 210 memcpy ((char *) new_environ, (char *) __environ, 211 size * sizeof (char *)); 212 213 new_environ[size + 1] = NULL; 214 215 last_environ = __environ = new_environ; 216 } 217 else if (replace) 218 { 219 char *np; 220 221 /* Use the user string if given. */ 222 if (combined != NULL) 223 np = (char *) combined; 224 else 225 { 226#ifdef USE_TSEARCH 227 char *new_value; 228# ifdef _LIBC 229 new_value = alloca (namelen + 1 + vallen); 230 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), 231 value, vallen); 232# else 233 new_value = allocsa (namelen + 1 + vallen); 234 if (new_value == NULL) 235 { 236 __set_errno (ENOMEM); 237 UNLOCK; 238 return -1; 239 } 240 memcpy (new_value, name, namelen); 241 new_value[namelen] = '='; 242 memcpy (&new_value[namelen + 1], value, vallen); 243# endif 244 245 np = KNOWN_VALUE (new_value); 246 if (np == NULL) 247#endif 248 { 249 np = malloc (namelen + 1 + vallen); 250 if (np == NULL) 251 { 252#if defined USE_TSEARCH && !defined _LIBC 253 freesa (new_value); 254#endif 255 __set_errno (ENOMEM); 256 UNLOCK; 257 return -1; 258 } 259 260#ifdef USE_TSEARCH 261 memcpy (np, new_value, namelen + 1 + vallen); 262#else 263 memcpy (np, name, namelen); 264 np[namelen] = '='; 265 memcpy (&np[namelen + 1], value, vallen); 266#endif 267 /* And remember the value. */ 268 STORE_VALUE (np); 269 } 270#if defined USE_TSEARCH && !defined _LIBC 271 freesa (new_value); 272#endif 273 } 274 275 *ep = np; 276 } 277 278 UNLOCK; 279 280 return 0; 281} 282 283int 284setenv (const char *name, const char *value, int replace) 285{ 286 return __add_to_environ (name, value, NULL, replace); 287} 288 289/* The `clearenv' was planned to be added to POSIX.1 but probably 290 never made it. Nevertheless the POSIX.9 standard (POSIX bindings 291 for Fortran 77) requires this function. */ 292int 293clearenv (void) 294{ 295 LOCK; 296 297 if (__environ == last_environ && __environ != NULL) 298 { 299 /* We allocated this environment so we can free it. */ 300 free (__environ); 301 last_environ = NULL; 302 } 303 304 /* Clear the environment pointer removes the whole environment. */ 305 __environ = NULL; 306 307 UNLOCK; 308 309 return 0; 310} 311 312#ifdef _LIBC 313static void 314free_mem (void) 315{ 316 /* Remove all traces. */ 317 clearenv (); 318 319 /* Now remove the search tree. */ 320 __tdestroy (known_values, free); 321 known_values = NULL; 322} 323text_set_element (__libc_subfreeres, free_mem); 324 325 326# undef setenv 327# undef clearenv 328weak_alias (__setenv, setenv) 329weak_alias (__clearenv, clearenv) 330#endif 331 332#endif /* _LIBC || !HAVE_SETENV */ 333