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