1/* Copyright (C) 1992, 1995-2003, 2005-2010 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 3 of the License, or 7 (at your option) 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 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17#if !_LIBC 18# include <config.h> 19#endif 20 21/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc 22 optimizes away the name == NULL test below. */ 23#define _GL_ARG_NONNULL(params) 24 25#include <alloca.h> 26 27/* Specification. */ 28#include <stdlib.h> 29 30#include <errno.h> 31#ifndef __set_errno 32# define __set_errno(ev) ((errno) = (ev)) 33#endif 34 35#include <string.h> 36#if _LIBC || HAVE_UNISTD_H 37# include <unistd.h> 38#endif 39 40#if !_LIBC 41# include "malloca.h" 42#endif 43 44#if _LIBC || !HAVE_SETENV 45 46#if !_LIBC 47# define __environ environ 48#endif 49 50#if _LIBC 51/* This lock protects against simultaneous modifications of `environ'. */ 52# include <bits/libc-lock.h> 53__libc_lock_define_initialized (static, envlock) 54# define LOCK __libc_lock_lock (envlock) 55# define UNLOCK __libc_lock_unlock (envlock) 56#else 57# define LOCK 58# define UNLOCK 59#endif 60 61/* In the GNU C library we must keep the namespace clean. */ 62#ifdef _LIBC 63# define setenv __setenv 64# define clearenv __clearenv 65# define tfind __tfind 66# define tsearch __tsearch 67#endif 68 69/* In the GNU C library implementation we try to be more clever and 70 allow arbitrarily many changes of the environment given that the used 71 values are from a small set. Outside glibc this will eat up all 72 memory after a while. */ 73#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ 74 && defined __GNUC__) 75# define USE_TSEARCH 1 76# include <search.h> 77typedef int (*compar_fn_t) (const void *, const void *); 78 79/* This is a pointer to the root of the search tree with the known 80 values. */ 81static void *known_values; 82 83# define KNOWN_VALUE(Str) \ 84 ({ \ 85 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ 86 value != NULL ? *(char **) value : NULL; \ 87 }) 88# define STORE_VALUE(Str) \ 89 tsearch (Str, &known_values, (compar_fn_t) strcmp) 90 91#else 92# undef USE_TSEARCH 93 94# define KNOWN_VALUE(Str) NULL 95# define STORE_VALUE(Str) do { } while (0) 96 97#endif 98 99 100/* If this variable is not a null pointer we allocated the current 101 environment. */ 102static char **last_environ; 103 104 105/* This function is used by `setenv' and `putenv'. The difference between 106 the two functions is that for the former must create a new string which 107 is then placed in the environment, while the argument of `putenv' 108 must be used directly. This is all complicated by the fact that we try 109 to reuse values once generated for a `setenv' call since we can never 110 free the strings. */ 111int 112__add_to_environ (const char *name, const char *value, const char *combined, 113 int replace) 114{ 115 char **ep; 116 size_t size; 117 const size_t namelen = strlen (name); 118 const size_t vallen = value != NULL ? strlen (value) + 1 : 0; 119 120 LOCK; 121 122 /* We have to get the pointer now that we have the lock and not earlier 123 since another thread might have created a new environment. */ 124 ep = __environ; 125 126 size = 0; 127 if (ep != NULL) 128 { 129 for (; *ep != NULL; ++ep) 130 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') 131 break; 132 else 133 ++size; 134 } 135 136 if (ep == NULL || *ep == NULL) 137 { 138 char **new_environ; 139#ifdef USE_TSEARCH 140 char *new_value; 141#endif 142 143 /* We allocated this space; we can extend it. */ 144 new_environ = 145 (char **) (last_environ == NULL 146 ? malloc ((size + 2) * sizeof (char *)) 147 : realloc (last_environ, (size + 2) * sizeof (char *))); 148 if (new_environ == NULL) 149 { 150 UNLOCK; 151 return -1; 152 } 153 154 /* If the whole entry is given add it. */ 155 if (combined != NULL) 156 /* We must not add the string to the search tree since it belongs 157 to the user. */ 158 new_environ[size] = (char *) combined; 159 else 160 { 161 /* See whether the value is already known. */ 162#ifdef USE_TSEARCH 163# ifdef _LIBC 164 new_value = (char *) alloca (namelen + 1 + vallen); 165 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), 166 value, vallen); 167# else 168 new_value = (char *) malloca (namelen + 1 + vallen); 169 if (new_value == NULL) 170 { 171 __set_errno (ENOMEM); 172 UNLOCK; 173 return -1; 174 } 175 memcpy (new_value, name, namelen); 176 new_value[namelen] = '='; 177 memcpy (&new_value[namelen + 1], value, vallen); 178# endif 179 180 new_environ[size] = KNOWN_VALUE (new_value); 181 if (new_environ[size] == NULL) 182#endif 183 { 184 new_environ[size] = (char *) malloc (namelen + 1 + vallen); 185 if (new_environ[size] == NULL) 186 { 187#if defined USE_TSEARCH && !defined _LIBC 188 freea (new_value); 189#endif 190 __set_errno (ENOMEM); 191 UNLOCK; 192 return -1; 193 } 194 195#ifdef USE_TSEARCH 196 memcpy (new_environ[size], new_value, namelen + 1 + vallen); 197#else 198 memcpy (new_environ[size], name, namelen); 199 new_environ[size][namelen] = '='; 200 memcpy (&new_environ[size][namelen + 1], value, vallen); 201#endif 202 /* And save the value now. We cannot do this when we remove 203 the string since then we cannot decide whether it is a 204 user string or not. */ 205 STORE_VALUE (new_environ[size]); 206 } 207#if defined USE_TSEARCH && !defined _LIBC 208 freea (new_value); 209#endif 210 } 211 212 if (__environ != last_environ) 213 memcpy ((char *) new_environ, (char *) __environ, 214 size * sizeof (char *)); 215 216 new_environ[size + 1] = NULL; 217 218 last_environ = __environ = new_environ; 219 } 220 else if (replace) 221 { 222 char *np; 223 224 /* Use the user string if given. */ 225 if (combined != NULL) 226 np = (char *) combined; 227 else 228 { 229#ifdef USE_TSEARCH 230 char *new_value; 231# ifdef _LIBC 232 new_value = alloca (namelen + 1 + vallen); 233 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), 234 value, vallen); 235# else 236 new_value = malloca (namelen + 1 + vallen); 237 if (new_value == NULL) 238 { 239 __set_errno (ENOMEM); 240 UNLOCK; 241 return -1; 242 } 243 memcpy (new_value, name, namelen); 244 new_value[namelen] = '='; 245 memcpy (&new_value[namelen + 1], value, vallen); 246# endif 247 248 np = KNOWN_VALUE (new_value); 249 if (np == NULL) 250#endif 251 { 252 np = (char *) malloc (namelen + 1 + vallen); 253 if (np == NULL) 254 { 255#if defined USE_TSEARCH && !defined _LIBC 256 freea (new_value); 257#endif 258 __set_errno (ENOMEM); 259 UNLOCK; 260 return -1; 261 } 262 263#ifdef USE_TSEARCH 264 memcpy (np, new_value, namelen + 1 + vallen); 265#else 266 memcpy (np, name, namelen); 267 np[namelen] = '='; 268 memcpy (&np[namelen + 1], value, vallen); 269#endif 270 /* And remember the value. */ 271 STORE_VALUE (np); 272 } 273#if defined USE_TSEARCH && !defined _LIBC 274 freea (new_value); 275#endif 276 } 277 278 *ep = np; 279 } 280 281 UNLOCK; 282 283 return 0; 284} 285 286int 287setenv (const char *name, const char *value, int replace) 288{ 289 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) 290 { 291 __set_errno (EINVAL); 292 return -1; 293 } 294 295 return __add_to_environ (name, value, NULL, replace); 296} 297 298/* The `clearenv' was planned to be added to POSIX.1 but probably 299 never made it. Nevertheless the POSIX.9 standard (POSIX bindings 300 for Fortran 77) requires this function. */ 301int 302clearenv (void) 303{ 304 LOCK; 305 306 if (__environ == last_environ && __environ != NULL) 307 { 308 /* We allocated this environment so we can free it. */ 309 free (__environ); 310 last_environ = NULL; 311 } 312 313 /* Clear the environment pointer removes the whole environment. */ 314 __environ = NULL; 315 316 UNLOCK; 317 318 return 0; 319} 320 321#ifdef _LIBC 322static void 323free_mem (void) 324{ 325 /* Remove all traces. */ 326 clearenv (); 327 328 /* Now remove the search tree. */ 329 __tdestroy (known_values, free); 330 known_values = NULL; 331} 332text_set_element (__libc_subfreeres, free_mem); 333 334 335# undef setenv 336# undef clearenv 337weak_alias (__setenv, setenv) 338weak_alias (__clearenv, clearenv) 339#endif 340 341#endif /* _LIBC || !HAVE_SETENV */ 342 343/* The rest of this file is called into use when replacing an existing 344 but buggy setenv. Known bugs include failure to diagnose invalid 345 name, and consuming a leading '=' from value. */ 346#if HAVE_SETENV 347 348# undef setenv 349# define STREQ(a, b) (strcmp (a, b) == 0) 350 351int 352rpl_setenv (const char *name, const char *value, int replace) 353{ 354 int result; 355 if (!name || !*name || strchr (name, '=')) 356 { 357 errno = EINVAL; 358 return -1; 359 } 360 /* Call the real setenv even if replace is 0, in case implementation 361 has underlying data to update, such as when environ changes. */ 362 result = setenv (name, value, replace); 363 if (result == 0 && replace && *value == '=') 364 { 365 char *tmp = getenv (name); 366 if (!STREQ (tmp, value)) 367 { 368 int saved_errno; 369 size_t len = strlen (value); 370 tmp = malloca (len + 2); 371 /* Since leading '=' is eaten, double it up. */ 372 *tmp = '='; 373 memcpy (tmp + 1, value, len + 1); 374 result = setenv (name, tmp, replace); 375 saved_errno = errno; 376 freea (tmp); 377 errno = saved_errno; 378 } 379 } 380 return result; 381} 382 383#endif /* HAVE_SETENV */ 384