59f00bcc44845650cf637f1bc857ac786c95fe23
[debian/tar] / gnu / setenv.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Copyright (C) 1992, 1995-2003, 2005-2013 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #if !_LIBC
20 /* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
21    optimizes away the name == NULL test below.  */
22 # define _GL_ARG_NONNULL(params)
23
24 # define _GL_USE_STDLIB_ALLOC 1
25 # include <config.h>
26 #endif
27
28 #include <alloca.h>
29
30 /* Specification.  */
31 #include <stdlib.h>
32
33 #include <errno.h>
34 #ifndef __set_errno
35 # define __set_errno(ev) ((errno) = (ev))
36 #endif
37
38 #include <string.h>
39 #if _LIBC || HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42
43 #if !_LIBC
44 # include "malloca.h"
45 #endif
46
47 #if _LIBC || !HAVE_SETENV
48
49 #if !_LIBC
50 # define __environ      environ
51 #endif
52
53 #if _LIBC
54 /* This lock protects against simultaneous modifications of 'environ'.  */
55 # include <bits/libc-lock.h>
56 __libc_lock_define_initialized (static, envlock)
57 # define LOCK   __libc_lock_lock (envlock)
58 # define UNLOCK __libc_lock_unlock (envlock)
59 #else
60 # define LOCK
61 # define UNLOCK
62 #endif
63
64 /* In the GNU C library we must keep the namespace clean.  */
65 #ifdef _LIBC
66 # define setenv __setenv
67 # define clearenv __clearenv
68 # define tfind __tfind
69 # define tsearch __tsearch
70 #endif
71
72 /* In the GNU C library implementation we try to be more clever and
73    allow arbitrarily many changes of the environment given that the used
74    values are from a small set.  Outside glibc this will eat up all
75    memory after a while.  */
76 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
77                       && defined __GNUC__)
78 # define USE_TSEARCH    1
79 # include <search.h>
80 typedef int (*compar_fn_t) (const void *, const void *);
81
82 /* This is a pointer to the root of the search tree with the known
83    values.  */
84 static void *known_values;
85
86 # define KNOWN_VALUE(Str) \
87   ({                                                                          \
88     void *value = tfind (Str, &known_values, (compar_fn_t) strcmp);           \
89     value != NULL ? *(char **) value : NULL;                                  \
90   })
91 # define STORE_VALUE(Str) \
92   tsearch (Str, &known_values, (compar_fn_t) strcmp)
93
94 #else
95 # undef USE_TSEARCH
96
97 # define KNOWN_VALUE(Str) NULL
98 # define STORE_VALUE(Str) do { } while (0)
99
100 #endif
101
102
103 /* If this variable is not a null pointer we allocated the current
104    environment.  */
105 static char **last_environ;
106
107
108 /* This function is used by 'setenv' and 'putenv'.  The difference between
109    the two functions is that for the former must create a new string which
110    is then placed in the environment, while the argument of 'putenv'
111    must be used directly.  This is all complicated by the fact that we try
112    to reuse values once generated for a 'setenv' call since we can never
113    free the strings.  */
114 int
115 __add_to_environ (const char *name, const char *value, const char *combined,
116                   int replace)
117 {
118   char **ep;
119   size_t size;
120   const size_t namelen = strlen (name);
121   const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
122
123   LOCK;
124
125   /* We have to get the pointer now that we have the lock and not earlier
126      since another thread might have created a new environment.  */
127   ep = __environ;
128
129   size = 0;
130   if (ep != NULL)
131     {
132       for (; *ep != NULL; ++ep)
133         if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
134           break;
135         else
136           ++size;
137     }
138
139   if (ep == NULL || *ep == NULL)
140     {
141       char **new_environ;
142 #ifdef USE_TSEARCH
143       char *new_value;
144 #endif
145
146       /* We allocated this space; we can extend it.  */
147       new_environ =
148         (char **) (last_environ == NULL
149                    ? malloc ((size + 2) * sizeof (char *))
150                    : realloc (last_environ, (size + 2) * sizeof (char *)));
151       if (new_environ == NULL)
152         {
153           /* It's easier to set errno to ENOMEM than to rely on the
154              'malloc-posix' and 'realloc-posix' gnulib modules.  */
155           __set_errno (ENOMEM);
156           UNLOCK;
157           return -1;
158         }
159
160       /* If the whole entry is given add it.  */
161       if (combined != NULL)
162         /* We must not add the string to the search tree since it belongs
163            to the user.  */
164         new_environ[size] = (char *) combined;
165       else
166         {
167           /* See whether the value is already known.  */
168 #ifdef USE_TSEARCH
169 # ifdef _LIBC
170           new_value = (char *) alloca (namelen + 1 + vallen);
171           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
172                      value, vallen);
173 # else
174           new_value = (char *) malloca (namelen + 1 + vallen);
175           if (new_value == NULL)
176             {
177               __set_errno (ENOMEM);
178               UNLOCK;
179               return -1;
180             }
181           memcpy (new_value, name, namelen);
182           new_value[namelen] = '=';
183           memcpy (&new_value[namelen + 1], value, vallen);
184 # endif
185
186           new_environ[size] = KNOWN_VALUE (new_value);
187           if (new_environ[size] == NULL)
188 #endif
189             {
190               new_environ[size] = (char *) malloc (namelen + 1 + vallen);
191               if (new_environ[size] == NULL)
192                 {
193 #if defined USE_TSEARCH && !defined _LIBC
194                   freea (new_value);
195 #endif
196                   __set_errno (ENOMEM);
197                   UNLOCK;
198                   return -1;
199                 }
200
201 #ifdef USE_TSEARCH
202               memcpy (new_environ[size], new_value, namelen + 1 + vallen);
203 #else
204               memcpy (new_environ[size], name, namelen);
205               new_environ[size][namelen] = '=';
206               memcpy (&new_environ[size][namelen + 1], value, vallen);
207 #endif
208               /* And save the value now.  We cannot do this when we remove
209                  the string since then we cannot decide whether it is a
210                  user string or not.  */
211               STORE_VALUE (new_environ[size]);
212             }
213 #if defined USE_TSEARCH && !defined _LIBC
214           freea (new_value);
215 #endif
216         }
217
218       if (__environ != last_environ)
219         memcpy ((char *) new_environ, (char *) __environ,
220                 size * sizeof (char *));
221
222       new_environ[size + 1] = NULL;
223
224       last_environ = __environ = new_environ;
225     }
226   else if (replace)
227     {
228       char *np;
229
230       /* Use the user string if given.  */
231       if (combined != NULL)
232         np = (char *) combined;
233       else
234         {
235 #ifdef USE_TSEARCH
236           char *new_value;
237 # ifdef _LIBC
238           new_value = alloca (namelen + 1 + vallen);
239           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
240                      value, vallen);
241 # else
242           new_value = malloca (namelen + 1 + vallen);
243           if (new_value == NULL)
244             {
245               __set_errno (ENOMEM);
246               UNLOCK;
247               return -1;
248             }
249           memcpy (new_value, name, namelen);
250           new_value[namelen] = '=';
251           memcpy (&new_value[namelen + 1], value, vallen);
252 # endif
253
254           np = KNOWN_VALUE (new_value);
255           if (np == NULL)
256 #endif
257             {
258               np = (char *) malloc (namelen + 1 + vallen);
259               if (np == NULL)
260                 {
261 #if defined USE_TSEARCH && !defined _LIBC
262                   freea (new_value);
263 #endif
264                   __set_errno (ENOMEM);
265                   UNLOCK;
266                   return -1;
267                 }
268
269 #ifdef USE_TSEARCH
270               memcpy (np, new_value, namelen + 1 + vallen);
271 #else
272               memcpy (np, name, namelen);
273               np[namelen] = '=';
274               memcpy (&np[namelen + 1], value, vallen);
275 #endif
276               /* And remember the value.  */
277               STORE_VALUE (np);
278             }
279 #if defined USE_TSEARCH && !defined _LIBC
280           freea (new_value);
281 #endif
282         }
283
284       *ep = np;
285     }
286
287   UNLOCK;
288
289   return 0;
290 }
291
292 int
293 setenv (const char *name, const char *value, int replace)
294 {
295   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
296     {
297       __set_errno (EINVAL);
298       return -1;
299     }
300
301   return __add_to_environ (name, value, NULL, replace);
302 }
303
304 /* The 'clearenv' was planned to be added to POSIX.1 but probably
305    never made it.  Nevertheless the POSIX.9 standard (POSIX bindings
306    for Fortran 77) requires this function.  */
307 int
308 clearenv (void)
309 {
310   LOCK;
311
312   if (__environ == last_environ && __environ != NULL)
313     {
314       /* We allocated this environment so we can free it.  */
315       free (__environ);
316       last_environ = NULL;
317     }
318
319   /* Clear the environment pointer removes the whole environment.  */
320   __environ = NULL;
321
322   UNLOCK;
323
324   return 0;
325 }
326
327 #ifdef _LIBC
328 static void
329 free_mem (void)
330 {
331   /* Remove all traces.  */
332   clearenv ();
333
334   /* Now remove the search tree.  */
335   __tdestroy (known_values, free);
336   known_values = NULL;
337 }
338 text_set_element (__libc_subfreeres, free_mem);
339
340
341 # undef setenv
342 # undef clearenv
343 weak_alias (__setenv, setenv)
344 weak_alias (__clearenv, clearenv)
345 #endif
346
347 #endif /* _LIBC || !HAVE_SETENV */
348
349 /* The rest of this file is called into use when replacing an existing
350    but buggy setenv.  Known bugs include failure to diagnose invalid
351    name, and consuming a leading '=' from value.  */
352 #if HAVE_SETENV
353
354 # undef setenv
355 # if !HAVE_DECL_SETENV
356 extern int setenv (const char *, const char *, int);
357 # endif
358 # define STREQ(a, b) (strcmp (a, b) == 0)
359
360 int
361 rpl_setenv (const char *name, const char *value, int replace)
362 {
363   int result;
364   if (!name || !*name || strchr (name, '='))
365     {
366       errno = EINVAL;
367       return -1;
368     }
369   /* Call the real setenv even if replace is 0, in case implementation
370      has underlying data to update, such as when environ changes.  */
371   result = setenv (name, value, replace);
372   if (result == 0 && replace && *value == '=')
373     {
374       char *tmp = getenv (name);
375       if (!STREQ (tmp, value))
376         {
377           int saved_errno;
378           size_t len = strlen (value);
379           tmp = malloca (len + 2);
380           /* Since leading '=' is eaten, double it up.  */
381           *tmp = '=';
382           memcpy (tmp + 1, value, len + 1);
383           result = setenv (name, tmp, replace);
384           saved_errno = errno;
385           freea (tmp);
386           errno = saved_errno;
387         }
388     }
389   return result;
390 }
391
392 #endif /* HAVE_SETENV */