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