1/* Copyright (C) 1992,1995-1999,2000-2003,2005,2006 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 35# include "allocsa.h" 36#endif 37 38#if !_LIBC 39# define __environ environ 40# ifndef HAVE_ENVIRON_DECL 41extern 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> 72typedef 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. */ 76static 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. */ 97static 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. */ 106int 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 281int 282setenv (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. */ 290int 291clearenv (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 311static void 312free_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} 321text_set_element (__libc_subfreeres, free_mem); 322 323 324# undef setenv 325# undef clearenv 326weak_alias (__setenv, setenv) 327weak_alias (__clearenv, clearenv) 328#endif 329