1 /* Copyright (C) 1992-2021 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library 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 GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 /* Pacify GCC; see the commentary about VALLEN below.  This is needed
23    at least through GCC 4.9.2.  Pacify GCC for the entire file, as
24    there seems to be no way to pacify GCC selectively, only for the
25    place where it's needed.  Do not use DIAG_IGNORE_NEEDS_COMMENT
26    here, as it's not defined yet.  */
27 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
28 
29 #include <errno.h>
30 #if !_LIBC
31 # if !defined errno && !defined HAVE_ERRNO_DECL
32 extern int errno;
33 # endif
34 # define __set_errno(ev) ((errno) = (ev))
35 #endif
36 
37 #if _LIBC || HAVE_STDLIB_H
38 # include <stdlib.h>
39 #endif
40 #if _LIBC || HAVE_STRING_H
41 # include <string.h>
42 #endif
43 #if _LIBC || HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 
47 #if !_LIBC
48 # define __environ	environ
49 # ifndef HAVE_ENVIRON_DECL
50 extern char **environ;
51 # endif
52 #endif
53 
54 #if _LIBC
55 /* This lock protects against simultaneous modifications of `environ'.  */
56 # include <libc-lock.h>
57 __libc_lock_define_initialized (static, envlock)
58 # define LOCK	__libc_lock_lock (envlock)
59 # define UNLOCK	__libc_lock_unlock (envlock)
60 #else
61 # define LOCK
62 # define UNLOCK
63 #endif
64 
65 /* In the GNU C library we must keep the namespace clean.  */
66 #ifdef _LIBC
67 # define setenv __setenv
68 # define unsetenv __unsetenv
69 # define clearenv __clearenv
70 # define tfind __tfind
71 # define tsearch __tsearch
72 #endif
73 
74 /* In the GNU C library implementation we try to be more clever and
75    allow arbitrarily many changes of the environment given that the used
76    values are from a small set.  Outside glibc this will eat up all
77    memory after a while.  */
78 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
79 		      && defined __GNUC__)
80 # define USE_TSEARCH	1
81 # include <search.h>
82 
83 /* This is a pointer to the root of the search tree with the known
84    values.  */
85 static void *known_values;
86 
87 # define KNOWN_VALUE(Str) \
88   ({									      \
89     void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp);	      \
90     value != NULL ? *(char **) value : NULL;				      \
91   })
92 # define STORE_VALUE(Str) \
93   tsearch (Str, &known_values, (__compar_fn_t) strcmp)
94 
95 #else
96 # undef USE_TSEARCH
97 
98 # define KNOWN_VALUE(Str) NULL
99 # define STORE_VALUE(Str) do { } while (0)
100 
101 #endif
102 
103 
104 /* If this variable is not a null pointer we allocated the current
105    environment.  */
106 static char **last_environ;
107 
108 
109 /* This function is used by `setenv' and `putenv'.  The difference between
110    the two functions is that for the former must create a new string which
111    is then placed in the environment, while the argument of `putenv'
112    must be used directly.  This is all complicated by the fact that we try
113    to reuse values once generated for a `setenv' call since we can never
114    free the strings.  */
115 int
__add_to_environ(const char * name,const char * value,const char * combined,int replace)116 __add_to_environ (const char *name, const char *value, const char *combined,
117 		  int replace)
118 {
119   char **ep;
120   size_t size;
121 
122   /* Compute lengths before locking, so that the critical section is
123      less of a performance bottleneck.  VALLEN is needed only if
124      COMBINED is null (unfortunately GCC is not smart enough to deduce
125      this; see the #pragma at the start of this file).  Testing
126      COMBINED instead of VALUE causes setenv (..., NULL, ...)  to dump
127      core now instead of corrupting memory later.  */
128   const size_t namelen = strlen (name);
129   size_t vallen;
130   if (combined == NULL)
131     vallen = strlen (value) + 1;
132 
133   LOCK;
134 
135   /* We have to get the pointer now that we have the lock and not earlier
136      since another thread might have created a new environment.  */
137   ep = __environ;
138 
139   size = 0;
140   if (ep != NULL)
141     {
142       for (; *ep != NULL; ++ep)
143 	if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
144 	  break;
145 	else
146 	  ++size;
147     }
148 
149   if (ep == NULL || __builtin_expect (*ep == NULL, 1))
150     {
151       char **new_environ;
152 
153       /* We allocated this space; we can extend it.  */
154       new_environ = (char **) realloc (last_environ,
155 				       (size + 2) * sizeof (char *));
156       if (new_environ == NULL)
157 	{
158 	  UNLOCK;
159 	  return -1;
160 	}
161 
162       if (__environ != last_environ)
163 	memcpy ((char *) new_environ, (char *) __environ,
164 		size * sizeof (char *));
165 
166       new_environ[size] = NULL;
167       new_environ[size + 1] = NULL;
168       ep = new_environ + size;
169 
170       last_environ = __environ = new_environ;
171     }
172   if (*ep == NULL || replace)
173     {
174       char *np;
175 
176       /* Use the user string if given.  */
177       if (combined != NULL)
178 	np = (char *) combined;
179       else
180 	{
181 	  const size_t varlen = namelen + 1 + vallen;
182 #ifdef USE_TSEARCH
183 	  char *new_value;
184 	  int use_alloca = __libc_use_alloca (varlen);
185 	  if (__builtin_expect (use_alloca, 1))
186 	    new_value = (char *) alloca (varlen);
187 	  else
188 	    {
189 	      new_value = malloc (varlen);
190 	      if (new_value == NULL)
191 		{
192 		  UNLOCK;
193 		  return -1;
194 		}
195 	    }
196 # ifdef _LIBC
197 	  __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
198 		     value, vallen);
199 # else
200 	  memcpy (new_value, name, namelen);
201 	  new_value[namelen] = '=';
202 	  memcpy (&new_value[namelen + 1], value, vallen);
203 # endif
204 
205 	  np = KNOWN_VALUE (new_value);
206 	  if (__glibc_likely (np == NULL))
207 #endif
208 	    {
209 #ifdef USE_TSEARCH
210 	      if (__glibc_unlikely (! use_alloca))
211 		np = new_value;
212 	      else
213 #endif
214 		{
215 		  np = malloc (varlen);
216 		  if (__glibc_unlikely (np == NULL))
217 		    {
218 		      UNLOCK;
219 		      return -1;
220 		    }
221 
222 #ifdef USE_TSEARCH
223 		  memcpy (np, new_value, varlen);
224 #else
225 		  memcpy (np, name, namelen);
226 		  np[namelen] = '=';
227 		  memcpy (&np[namelen + 1], value, vallen);
228 #endif
229 		}
230 	      /* And remember the value.  */
231 	      STORE_VALUE (np);
232 	    }
233 #ifdef USE_TSEARCH
234 	  else
235 	    {
236 	      if (__glibc_unlikely (! use_alloca))
237 		free (new_value);
238 	    }
239 #endif
240 	}
241 
242       *ep = np;
243     }
244 
245   UNLOCK;
246 
247   return 0;
248 }
249 
250 int
setenv(const char * name,const char * value,int replace)251 setenv (const char *name, const char *value, int replace)
252 {
253   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
254     {
255       __set_errno (EINVAL);
256       return -1;
257     }
258 
259   return __add_to_environ (name, value, NULL, replace);
260 }
261 
262 int
unsetenv(const char * name)263 unsetenv (const char *name)
264 {
265   size_t len;
266   char **ep;
267 
268   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
269     {
270       __set_errno (EINVAL);
271       return -1;
272     }
273 
274   len = strlen (name);
275 
276   LOCK;
277 
278   ep = __environ;
279   if (ep != NULL)
280     while (*ep != NULL)
281       {
282 	if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
283 	  {
284 	    /* Found it.  Remove this pointer by moving later ones back.  */
285 	    char **dp = ep;
286 
287 	    do
288 		dp[0] = dp[1];
289 	    while (*dp++);
290 	    /* Continue the loop in case NAME appears again.  */
291 	  }
292 	else
293 	  ++ep;
294       }
295 
296   UNLOCK;
297 
298   return 0;
299 }
300 
301 /* The `clearenv' was planned to be added to POSIX.1 but probably
302    never made it.  Nevertheless the POSIX.9 standard (POSIX bindings
303    for Fortran 77) requires this function.  */
304 int
clearenv(void)305 clearenv (void)
306 {
307   LOCK;
308 
309   if (__environ == last_environ && __environ != NULL)
310     {
311       /* We allocated this environment so we can free it.  */
312       free (__environ);
313       last_environ = NULL;
314     }
315 
316   /* Clear the environment pointer removes the whole environment.  */
317   __environ = NULL;
318 
319   UNLOCK;
320 
321   return 0;
322 }
323 #ifdef _LIBC
libc_freeres_fn(free_mem)324 libc_freeres_fn (free_mem)
325 {
326   /* Remove all traces.  */
327   clearenv ();
328 
329   /* Now remove the search tree.  */
330   __tdestroy (known_values, free);
331   known_values = NULL;
332 }
333 
334 # undef setenv
335 # undef unsetenv
336 # undef clearenv
337 weak_alias (__setenv, setenv)
338 weak_alias (__unsetenv, unsetenv)
339 weak_alias (__clearenv, clearenv)
340 #endif
341