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