summaryrefslogtreecommitdiffstats
path: root/gl/setenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/setenv.c')
-rw-r--r--gl/setenv.c117
1 files changed, 99 insertions, 18 deletions
diff --git a/gl/setenv.c b/gl/setenv.c
index 9e2e9e2f..ae53146f 100644
--- a/gl/setenv.c
+++ b/gl/setenv.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992, 1995-2003, 2005-2024 Free Software Foundation, Inc. 1/* Copyright (C) 1992, 1995-2003, 2005-2026 Free Software Foundation, Inc.
2 This file is part of the GNU C Library. 2 This file is part of the GNU C Library.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
@@ -38,11 +38,23 @@
38# include <unistd.h> 38# include <unistd.h>
39#endif 39#endif
40 40
41#if defined _WIN32 && ! defined __CYGWIN__
42# define WIN32_LEAN_AND_MEAN
43# include <windows.h>
44#endif
45
41#if !_LIBC 46#if !_LIBC
42# include "malloca.h" 47# include "malloca.h"
43#endif 48#endif
44 49
50#if defined _WIN32 && ! defined __CYGWIN__
51/* Don't assume that UNICODE is not defined. */
52# undef SetEnvironmentVariable
53# define SetEnvironmentVariable SetEnvironmentVariableA
54#endif
55
45#if _LIBC || !HAVE_SETENV 56#if _LIBC || !HAVE_SETENV
57#if !HAVE_DECL__PUTENV
46 58
47#if !_LIBC 59#if !_LIBC
48# define __environ environ 60# define __environ environ
@@ -114,8 +126,6 @@ int
114__add_to_environ (const char *name, const char *value, const char *combined, 126__add_to_environ (const char *name, const char *value, const char *combined,
115 int replace) 127 int replace)
116{ 128{
117 char **ep;
118 size_t size;
119 const size_t namelen = strlen (name); 129 const size_t namelen = strlen (name);
120 const size_t vallen = value != NULL ? strlen (value) + 1 : 0; 130 const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
121 131
@@ -123,9 +133,9 @@ __add_to_environ (const char *name, const char *value, const char *combined,
123 133
124 /* We have to get the pointer now that we have the lock and not earlier 134 /* We have to get the pointer now that we have the lock and not earlier
125 since another thread might have created a new environment. */ 135 since another thread might have created a new environment. */
126 ep = __environ; 136 char **ep = __environ;
127 137
128 size = 0; 138 size_t size = 0;
129 if (ep != NULL) 139 if (ep != NULL)
130 { 140 {
131 for (; *ep != NULL; ++ep) 141 for (; *ep != NULL; ++ep)
@@ -137,13 +147,8 @@ __add_to_environ (const char *name, const char *value, const char *combined,
137 147
138 if (ep == NULL || *ep == NULL) 148 if (ep == NULL || *ep == NULL)
139 { 149 {
140 char **new_environ;
141#ifdef USE_TSEARCH
142 char *new_value;
143#endif
144
145 /* We allocated this space; we can extend it. */ 150 /* We allocated this space; we can extend it. */
146 new_environ = 151 char **new_environ =
147 (char **) (last_environ == NULL 152 (char **) (last_environ == NULL
148 ? malloc ((size + 2) * sizeof (char *)) 153 ? malloc ((size + 2) * sizeof (char *))
149 : realloc (last_environ, (size + 2) * sizeof (char *))); 154 : realloc (last_environ, (size + 2) * sizeof (char *)));
@@ -165,6 +170,7 @@ __add_to_environ (const char *name, const char *value, const char *combined,
165 { 170 {
166 /* See whether the value is already known. */ 171 /* See whether the value is already known. */
167#ifdef USE_TSEARCH 172#ifdef USE_TSEARCH
173 char *new_value;
168# ifdef _LIBC 174# ifdef _LIBC
169 new_value = (char *) alloca (namelen + 1 + vallen); 175 new_value = (char *) alloca (namelen + 1 + vallen);
170 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), 176 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
@@ -215,8 +221,7 @@ __add_to_environ (const char *name, const char *value, const char *combined,
215 } 221 }
216 222
217 if (__environ != last_environ) 223 if (__environ != last_environ)
218 memcpy ((char *) new_environ, (char *) __environ, 224 memcpy (new_environ, __environ, size * sizeof (char *));
219 size * sizeof (char *));
220 225
221 new_environ[size + 1] = NULL; 226 new_environ[size + 1] = NULL;
222 227
@@ -343,6 +348,84 @@ weak_alias (__setenv, setenv)
343weak_alias (__clearenv, clearenv) 348weak_alias (__clearenv, clearenv)
344#endif 349#endif
345 350
351#else /* HAVE_DECL__PUTENV */
352/* Native Windows */
353
354int
355setenv (const char *name, const char *value, int replace)
356{
357 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
358 {
359 errno = EINVAL;
360 return -1;
361 }
362
363 /* The Microsoft documentation
364 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
365 says:
366 "Don't change an environment entry directly: instead,
367 use _putenv or _wputenv to change it."
368 Note: Microsoft's _putenv updates not only the contents of _environ but
369 also the contents of _wenviron, so that both are in kept in sync. */
370 const char *existing_value = getenv (name);
371 if (existing_value != NULL)
372 {
373 if (replace)
374 {
375 if (strcmp (existing_value, value) == 0)
376 /* No need to allocate memory. */
377 return 0;
378 }
379 else
380 /* Keep the existing value. */
381 return 0;
382 }
383 /* Allocate a new environment entry in the heap. */
384 /* _putenv ("NAME=") unsets NAME, so if VALUE is the empty string, invoke
385 _putenv ("NAME= ") and fix up the result afterwards. */
386 const char *value_ = (value[0] == '\0' ? " " : value);
387 size_t name_len = strlen (name);
388 size_t value_len = strlen (value_);
389 char *string = (char *) malloc (name_len + 1 + value_len + 1);
390 if (string == NULL)
391 return -1;
392 memcpy (string, name, name_len);
393 string[name_len] = '=';
394 memcpy (&string[name_len + 1], value_, value_len + 1);
395 /* Use _putenv. */
396 if (_putenv (string) < 0)
397 return -1;
398 if (value[0] == '\0')
399 {
400 /* Fix up the result. */
401 char *new_value = getenv (name);
402 if (new_value != NULL && new_value[0] == ' ' && new_value[1] == '\0')
403 new_value[0] = '\0';
404# if defined _WIN32 && ! defined __CYGWIN__
405 /* _putenv propagated "NAME= " into the subprocess environment;
406 fix that by calling SetEnvironmentVariable directly. */
407 /* Documentation:
408 <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable> */
409 if (!SetEnvironmentVariable (name, ""))
410 {
411 switch (GetLastError ())
412 {
413 case ERROR_NOT_ENOUGH_MEMORY:
414 case ERROR_OUTOFMEMORY:
415 errno = ENOMEM;
416 break;
417 default:
418 errno = EINVAL;
419 break;
420 }
421 return -1;
422 }
423# endif
424 }
425 return 0;
426}
427
428#endif /* HAVE_DECL__PUTENV */
346#endif /* _LIBC || !HAVE_SETENV */ 429#endif /* _LIBC || !HAVE_SETENV */
347 430
348/* The rest of this file is called into use when replacing an existing 431/* The rest of this file is called into use when replacing an existing
@@ -359,21 +442,19 @@ extern int setenv (const char *, const char *, int);
359int 442int
360rpl_setenv (const char *name, const char *value, int replace) 443rpl_setenv (const char *name, const char *value, int replace)
361{ 444{
362 int result; 445 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
363 if (!name || !*name || strchr (name, '='))
364 { 446 {
365 errno = EINVAL; 447 errno = EINVAL;
366 return -1; 448 return -1;
367 } 449 }
368 /* Call the real setenv even if replace is 0, in case implementation 450 /* Call the real setenv even if replace is 0, in case implementation
369 has underlying data to update, such as when environ changes. */ 451 has underlying data to update, such as when environ changes. */
370 result = setenv (name, value, replace); 452 int result = setenv (name, value, replace);
371 if (result == 0 && replace && *value == '=') 453 if (result == 0 && replace && *value == '=')
372 { 454 {
373 char *tmp = getenv (name); 455 char *tmp = getenv (name);
374 if (!STREQ (tmp, value)) 456 if (!STREQ (tmp, value))
375 { 457 {
376 int saved_errno;
377 size_t len = strlen (value); 458 size_t len = strlen (value);
378 tmp = malloca (len + 2); 459 tmp = malloca (len + 2);
379 if (tmp == NULL) 460 if (tmp == NULL)
@@ -385,7 +466,7 @@ rpl_setenv (const char *name, const char *value, int replace)
385 *tmp = '='; 466 *tmp = '=';
386 memcpy (tmp + 1, value, len + 1); 467 memcpy (tmp + 1, value, len + 1);
387 result = setenv (name, tmp, replace); 468 result = setenv (name, tmp, replace);
388 saved_errno = errno; 469 int saved_errno = errno;
389 freea (tmp); 470 freea (tmp);
390 errno = saved_errno; 471 errno = saved_errno;
391 } 472 }