1 /* Copyright (C) 1992, 1995-2003, 2005-2025 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
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)
22 # define _GL_USE_STDLIB_ALLOC 1
33 # define __set_errno(ev) ((errno) = (ev))
37 #if _LIBC || HAVE_UNISTD_H
41 #if defined _WIN32 && ! defined __CYGWIN__
42 # define WIN32_LEAN_AND_MEAN
50 #if defined _WIN32 && ! defined __CYGWIN__
51 /* Don't assume that UNICODE is not defined. */
52 # undef SetEnvironmentVariable
53 # define SetEnvironmentVariable SetEnvironmentVariableA
56 #if _LIBC || !HAVE_SETENV
57 #if !HAVE_DECL__PUTENV
60 # define __environ environ
64 /* This lock protects against simultaneous modifications of 'environ'. */
65 # include <bits/libc-lock.h>
66 __libc_lock_define_initialized (static, envlock
)
67 # define LOCK __libc_lock_lock (envlock)
68 # define UNLOCK __libc_lock_unlock (envlock)
74 /* In the GNU C library we must keep the namespace clean. */
76 # define setenv __setenv
77 # define clearenv __clearenv
78 # define tfind __tfind
79 # define tsearch __tsearch
82 /* In the GNU C library implementation we try to be more clever and
83 allow arbitrarily many changes of the environment given that the used
84 values are from a small set. Outside glibc this will eat up all
85 memory after a while. */
86 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
87 && (defined __GNUC__ || defined __clang__))
88 # define USE_TSEARCH 1
90 typedef int (*compar_fn_t
) (const void *, const void *);
92 /* This is a pointer to the root of the search tree with the known
94 static void *known_values
;
96 # define KNOWN_VALUE(Str) \
99 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
100 value != NULL ? *(char **) value : NULL; \
102 # define STORE_VALUE(Str) \
103 tsearch (Str, &known_values, (compar_fn_t) strcmp)
108 # define KNOWN_VALUE(Str) NULL
109 # define STORE_VALUE(Str) do { } while (0)
114 /* If this variable is not a null pointer we allocated the current
116 static char **last_environ
;
119 /* This function is used by 'setenv' and 'putenv'. The difference between
120 the two functions is that for the former must create a new string which
121 is then placed in the environment, while the argument of 'putenv'
122 must be used directly. This is all complicated by the fact that we try
123 to reuse values once generated for a 'setenv' call since we can never
126 __add_to_environ (const char *name
, const char *value
, const char *combined
,
131 const size_t namelen
= strlen (name
);
132 const size_t vallen
= value
!= NULL
? strlen (value
) + 1 : 0;
136 /* We have to get the pointer now that we have the lock and not earlier
137 since another thread might have created a new environment. */
143 for (; *ep
!= NULL
; ++ep
)
144 if (!strncmp (*ep
, name
, namelen
) && (*ep
)[namelen
] == '=')
150 if (ep
== NULL
|| *ep
== NULL
)
157 /* We allocated this space; we can extend it. */
159 (char **) (last_environ
== NULL
160 ? malloc ((size
+ 2) * sizeof (char *))
161 : realloc (last_environ
, (size
+ 2) * sizeof (char *)));
162 if (new_environ
== NULL
)
164 /* It's easier to set errno to ENOMEM than to rely on the
165 'malloc-posix' and 'realloc-posix' gnulib modules. */
166 __set_errno (ENOMEM
);
171 /* If the whole entry is given add it. */
172 if (combined
!= NULL
)
173 /* We must not add the string to the search tree since it belongs
175 new_environ
[size
] = (char *) combined
;
178 /* See whether the value is already known. */
181 new_value
= (char *) alloca (namelen
+ 1 + vallen
);
182 __mempcpy (__mempcpy (__mempcpy (new_value
, name
, namelen
), "=", 1),
185 new_value
= (char *) malloca (namelen
+ 1 + vallen
);
186 if (new_value
== NULL
)
188 __set_errno (ENOMEM
);
192 memcpy (new_value
, name
, namelen
);
193 new_value
[namelen
] = '=';
194 memcpy (&new_value
[namelen
+ 1], value
, vallen
);
197 new_environ
[size
] = KNOWN_VALUE (new_value
);
198 if (new_environ
[size
] == NULL
)
201 new_environ
[size
] = (char *) malloc (namelen
+ 1 + vallen
);
202 if (new_environ
[size
] == NULL
)
204 #if defined USE_TSEARCH && !defined _LIBC
207 __set_errno (ENOMEM
);
213 memcpy (new_environ
[size
], new_value
, namelen
+ 1 + vallen
);
215 memcpy (new_environ
[size
], name
, namelen
);
216 new_environ
[size
][namelen
] = '=';
217 memcpy (&new_environ
[size
][namelen
+ 1], value
, vallen
);
219 /* And save the value now. We cannot do this when we remove
220 the string since then we cannot decide whether it is a
221 user string or not. */
222 STORE_VALUE (new_environ
[size
]);
224 #if defined USE_TSEARCH && !defined _LIBC
229 if (__environ
!= last_environ
)
230 memcpy (new_environ
, __environ
, size
* sizeof (char *));
232 new_environ
[size
+ 1] = NULL
;
234 last_environ
= __environ
= new_environ
;
240 /* Use the user string if given. */
241 if (combined
!= NULL
)
242 np
= (char *) combined
;
248 new_value
= alloca (namelen
+ 1 + vallen
);
249 __mempcpy (__mempcpy (__mempcpy (new_value
, name
, namelen
), "=", 1),
252 new_value
= malloca (namelen
+ 1 + vallen
);
253 if (new_value
== NULL
)
255 __set_errno (ENOMEM
);
259 memcpy (new_value
, name
, namelen
);
260 new_value
[namelen
] = '=';
261 memcpy (&new_value
[namelen
+ 1], value
, vallen
);
264 np
= KNOWN_VALUE (new_value
);
268 np
= (char *) malloc (namelen
+ 1 + vallen
);
271 #if defined USE_TSEARCH && !defined _LIBC
274 __set_errno (ENOMEM
);
280 memcpy (np
, new_value
, namelen
+ 1 + vallen
);
282 memcpy (np
, name
, namelen
);
284 memcpy (&np
[namelen
+ 1], value
, vallen
);
286 /* And remember the value. */
289 #if defined USE_TSEARCH && !defined _LIBC
303 setenv (const char *name
, const char *value
, int replace
)
305 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
307 __set_errno (EINVAL
);
311 return __add_to_environ (name
, value
, NULL
, replace
);
314 /* The 'clearenv' was planned to be added to POSIX.1 but probably
315 never made it. Nevertheless the POSIX.9 standard (POSIX bindings
316 for Fortran 77) requires this function. */
322 if (__environ
== last_environ
&& __environ
!= NULL
)
324 /* We allocated this environment so we can free it. */
329 /* Clear the environment pointer removes the whole environment. */
341 /* Remove all traces. */
344 /* Now remove the search tree. */
345 __tdestroy (known_values
, free
);
348 text_set_element (__libc_subfreeres
, free_mem
);
353 weak_alias (__setenv
, setenv
)
354 weak_alias (__clearenv
, clearenv
)
357 #else /* HAVE_DECL__PUTENV */
361 setenv (const char *name
, const char *value
, int replace
)
363 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
369 /* The Microsoft documentation
370 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
372 "Don't change an environment entry directly: instead,
373 use _putenv or _wputenv to change it."
374 Note: Microsoft's _putenv updates not only the contents of _environ but
375 also the contents of _wenviron, so that both are in kept in sync. */
376 const char *existing_value
= getenv (name
);
377 if (existing_value
!= NULL
)
381 if (strcmp (existing_value
, value
) == 0)
382 /* No need to allocate memory. */
386 /* Keep the existing value. */
389 /* Allocate a new environment entry in the heap. */
390 /* _putenv ("NAME=") unsets NAME, so if VALUE is the empty string, invoke
391 _putenv ("NAME= ") and fix up the result afterwards. */
392 const char *value_
= (value
[0] == '\0' ? " " : value
);
393 size_t name_len
= strlen (name
);
394 size_t value_len
= strlen (value_
);
395 char *string
= (char *) malloc (name_len
+ 1 + value_len
+ 1);
398 memcpy (string
, name
, name_len
);
399 string
[name_len
] = '=';
400 memcpy (&string
[name_len
+ 1], value_
, value_len
+ 1);
402 if (_putenv (string
) < 0)
404 if (value
[0] == '\0')
406 /* Fix up the result. */
407 char *new_value
= getenv (name
);
408 if (new_value
!= NULL
&& new_value
[0] == ' ' && new_value
[1] == '\0')
410 # if defined _WIN32 && ! defined __CYGWIN__
411 /* _putenv propagated "NAME= " into the subprocess environment;
412 fix that by calling SetEnvironmentVariable directly. */
414 <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable> */
415 if (!SetEnvironmentVariable (name
, ""))
417 switch (GetLastError ())
419 case ERROR_NOT_ENOUGH_MEMORY
:
420 case ERROR_OUTOFMEMORY
:
434 #endif /* HAVE_DECL__PUTENV */
435 #endif /* _LIBC || !HAVE_SETENV */
437 /* The rest of this file is called into use when replacing an existing
438 but buggy setenv. Known bugs include failure to diagnose invalid
439 name, and consuming a leading '=' from value. */
443 # if !HAVE_DECL_SETENV
444 extern int setenv (const char *, const char *, int);
446 # define STREQ(a, b) (strcmp (a, b) == 0)
449 rpl_setenv (const char *name
, const char *value
, int replace
)
452 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
457 /* Call the real setenv even if replace is 0, in case implementation
458 has underlying data to update, such as when environ changes. */
459 result
= setenv (name
, value
, replace
);
460 if (result
== 0 && replace
&& *value
== '=')
462 char *tmp
= getenv (name
);
463 if (!STREQ (tmp
, value
))
466 size_t len
= strlen (value
);
467 tmp
= malloca (len
+ 2);
473 /* Since leading '=' is eaten, double it up. */
475 memcpy (tmp
+ 1, value
, len
+ 1);
476 result
= setenv (name
, tmp
, replace
);
485 #endif /* HAVE_SETENV */