gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

putenv.c
Go to the documentation of this file.
1 /* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2021 Free Software
2  Foundation, Inc.
3 
4  NOTE: The canonical source of this file is maintained with the GNU C
5  Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6 
7  This program is free software: you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 3 of the License, or any
10  later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program. If not, see <https://www.gnu.org/licenses/>. */
19 
20 #include <config.h>
21 
22 /* Specification. */
23 #include <stdlib.h>
24 
25 #include <stddef.h>
26 
27 /* Include errno.h *after* sys/types.h to work around header problems
28  on AIX 3.2.5. */
29 #include <errno.h>
30 #ifndef __set_errno
31 # define __set_errno(ev) ((errno) = (ev))
32 #endif
33 
34 #include <string.h>
35 #include <unistd.h>
36 
37 #if defined _WIN32 && ! defined __CYGWIN__
38 # define WIN32_LEAN_AND_MEAN
39 # include <windows.h>
40 #endif
41 
42 #if _LIBC
43 # if HAVE_GNU_LD
44 # define environ __environ
45 # else
46 extern char **environ;
47 # endif
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 #if defined _WIN32 && ! defined __CYGWIN__
62 /* Don't assume that UNICODE is not defined. */
63 # undef SetEnvironmentVariable
64 # define SetEnvironmentVariable SetEnvironmentVariableA
65 #endif
66 
67 static int
68 _unsetenv (const char *name)
69 {
70  size_t len;
71 #if !HAVE_DECL__PUTENV
72  char **ep;
73 #endif
74 
75  if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
76  {
77  __set_errno (EINVAL);
78  return -1;
79  }
80 
81  len = strlen (name);
82 
83 #if HAVE_DECL__PUTENV
84  {
85  int putenv_result, putenv_errno;
86  char *name_ = malloc (len + 2);
87  memcpy (name_, name, len);
88  name_[len] = '=';
89  name_[len + 1] = 0;
90  putenv_result = _putenv (name_);
91  putenv_errno = errno;
92  free (name_);
93  __set_errno (putenv_errno);
94  return putenv_result;
95  }
96 #else
97 
98  LOCK;
99 
100  ep = environ;
101  while (*ep != NULL)
102  if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
103  {
104  /* Found it. Remove this pointer by moving later ones back. */
105  char **dp = ep;
106 
107  do
108  dp[0] = dp[1];
109  while (*dp++);
110  /* Continue the loop in case NAME appears again. */
111  }
112  else
113  ++ep;
114 
115  UNLOCK;
116 
117  return 0;
118 #endif
119 }
120 
121 
122 /* Put STRING, which is of the form "NAME=VALUE", in the environment.
123  If STRING contains no '=', then remove STRING from the environment. */
124 int
125 putenv (char *string)
126 {
127  const char *name_end = strchr (string, '=');
128  char **ep;
129 
130  if (name_end == NULL)
131  {
132  /* Remove the variable from the environment. */
133  return _unsetenv (string);
134  }
135 
136 #if HAVE_DECL__PUTENV
137  /* Rely on _putenv to allocate the new environment. If other
138  parts of the application use _putenv, the !HAVE_DECL__PUTENV code
139  would fight over who owns the environ vector, causing a crash. */
140  if (name_end[1])
141  return _putenv (string);
142  else
143  {
144  /* _putenv ("NAME=") unsets NAME, so invoke _putenv ("NAME= ")
145  to allocate the environ vector and then replace the new
146  entry with "NAME=". */
147  int putenv_result, putenv_errno;
148  char *name_x = malloc (name_end - string + sizeof "= ");
149  if (!name_x)
150  return -1;
151  memcpy (name_x, string, name_end - string + 1);
152  name_x[name_end - string + 1] = ' ';
153  name_x[name_end - string + 2] = 0;
154  putenv_result = _putenv (name_x);
155  putenv_errno = errno;
156  for (ep = environ; *ep; ep++)
157  if (strcmp (*ep, name_x) == 0)
158  {
159  *ep = string;
160  break;
161  }
162 # if defined _WIN32 && ! defined __CYGWIN__
163  if (putenv_result == 0)
164  {
165  /* _putenv propagated "NAME= " into the subprocess environment;
166  fix that by calling SetEnvironmentVariable directly. */
167  name_x[name_end - string] = 0;
168  putenv_result = SetEnvironmentVariable (name_x, "") ? 0 : -1;
169  putenv_errno = ENOMEM; /* ENOMEM is the only way to fail. */
170  }
171 # endif
172  free (name_x);
173  __set_errno (putenv_errno);
174  return putenv_result;
175  }
176 #else
177  for (ep = environ; *ep; ep++)
178  if (strncmp (*ep, string, name_end - string) == 0
179  && (*ep)[name_end - string] == '=')
180  break;
181 
182  if (*ep)
183  *ep = string;
184  else
185  {
186  static char **last_environ = NULL;
187  size_t size = ep - environ;
188  char **new_environ = malloc ((size + 2) * sizeof *new_environ);
189  if (! new_environ)
190  return -1;
191  new_environ[0] = string;
192  memcpy (new_environ + 1, environ, (size + 1) * sizeof *new_environ);
193  free (last_environ);
194  last_environ = new_environ;
195  environ = new_environ;
196  }
197 
198  return 0;
199 #endif
200 }
#define NULL
Definition: stddef.in.h:72
#define LOCK
Definition: putenv.c:57
static int _unsetenv(const char *name)
Definition: putenv.c:68
int putenv(char *string)
Definition: putenv.c:125
#define UNLOCK
Definition: putenv.c:58
#define __set_errno(ev)
Definition: putenv.c:31
const char * name
Definition: error.c:43
static char ** last_environ
Definition: setenv.c:103