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