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