maint: update copyright
[gnulib.git] / lib / setenv.c
1 /* Copyright (C) 1992, 1995-2003, 2005-2014 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 <http://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>
78 typedef 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.  */
82 static 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.  */
103 static 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.  */
112 int
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
290 int
291 setenv (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.  */
305 int
306 clearenv (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
326 static void
327 free_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 }
336 text_set_element (__libc_subfreeres, free_mem);
337
338
339 # undef setenv
340 # undef clearenv
341 weak_alias (__setenv, setenv)
342 weak_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
354 extern int setenv (const char *, const char *, int);
355 # endif
356 # define STREQ(a, b) (strcmp (a, b) == 0)
357
358 int
359 rpl_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 */