]> git.cworth.org Git - tar/blob - gnu/setenv.c
Imported Upstream version 1.24
[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 #else
70 /* Use the system functions, not the gnulib overrides in this file.  */
71 # undef malloc
72 # undef realloc
73 #endif
74
75 /* In the GNU C library implementation we try to be more clever and
76    allow arbitrarily many changes of the environment given that the used
77    values are from a small set.  Outside glibc this will eat up all
78    memory after a while.  */
79 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
80                       && defined __GNUC__)
81 # define USE_TSEARCH    1
82 # include <search.h>
83 typedef int (*compar_fn_t) (const void *, const void *);
84
85 /* This is a pointer to the root of the search tree with the known
86    values.  */
87 static void *known_values;
88
89 # define KNOWN_VALUE(Str) \
90   ({                                                                          \
91     void *value = tfind (Str, &known_values, (compar_fn_t) strcmp);           \
92     value != NULL ? *(char **) value : NULL;                                  \
93   })
94 # define STORE_VALUE(Str) \
95   tsearch (Str, &known_values, (compar_fn_t) strcmp)
96
97 #else
98 # undef USE_TSEARCH
99
100 # define KNOWN_VALUE(Str) NULL
101 # define STORE_VALUE(Str) do { } while (0)
102
103 #endif
104
105
106 /* If this variable is not a null pointer we allocated the current
107    environment.  */
108 static char **last_environ;
109
110
111 /* This function is used by `setenv' and `putenv'.  The difference between
112    the two functions is that for the former must create a new string which
113    is then placed in the environment, while the argument of `putenv'
114    must be used directly.  This is all complicated by the fact that we try
115    to reuse values once generated for a `setenv' call since we can never
116    free the strings.  */
117 int
118 __add_to_environ (const char *name, const char *value, const char *combined,
119                   int replace)
120 {
121   char **ep;
122   size_t size;
123   const size_t namelen = strlen (name);
124   const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
125
126   LOCK;
127
128   /* We have to get the pointer now that we have the lock and not earlier
129      since another thread might have created a new environment.  */
130   ep = __environ;
131
132   size = 0;
133   if (ep != NULL)
134     {
135       for (; *ep != NULL; ++ep)
136         if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
137           break;
138         else
139           ++size;
140     }
141
142   if (ep == NULL || *ep == NULL)
143     {
144       char **new_environ;
145 #ifdef USE_TSEARCH
146       char *new_value;
147 #endif
148
149       /* We allocated this space; we can extend it.  */
150       new_environ =
151         (char **) (last_environ == NULL
152                    ? malloc ((size + 2) * sizeof (char *))
153                    : realloc (last_environ, (size + 2) * sizeof (char *)));
154       if (new_environ == NULL)
155         {
156           /* It's easier to set errno to ENOMEM than to rely on the
157              'malloc-posix' and 'realloc-posix' gnulib modules.  */
158           __set_errno (ENOMEM);
159           UNLOCK;
160           return -1;
161         }
162
163       /* If the whole entry is given add it.  */
164       if (combined != NULL)
165         /* We must not add the string to the search tree since it belongs
166            to the user.  */
167         new_environ[size] = (char *) combined;
168       else
169         {
170           /* See whether the value is already known.  */
171 #ifdef USE_TSEARCH
172 # ifdef _LIBC
173           new_value = (char *) alloca (namelen + 1 + vallen);
174           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
175                      value, vallen);
176 # else
177           new_value = (char *) malloca (namelen + 1 + vallen);
178           if (new_value == NULL)
179             {
180               __set_errno (ENOMEM);
181               UNLOCK;
182               return -1;
183             }
184           memcpy (new_value, name, namelen);
185           new_value[namelen] = '=';
186           memcpy (&new_value[namelen + 1], value, vallen);
187 # endif
188
189           new_environ[size] = KNOWN_VALUE (new_value);
190           if (new_environ[size] == NULL)
191 #endif
192             {
193               new_environ[size] = (char *) malloc (namelen + 1 + vallen);
194               if (new_environ[size] == NULL)
195                 {
196 #if defined USE_TSEARCH && !defined _LIBC
197                   freea (new_value);
198 #endif
199                   __set_errno (ENOMEM);
200                   UNLOCK;
201                   return -1;
202                 }
203
204 #ifdef USE_TSEARCH
205               memcpy (new_environ[size], new_value, namelen + 1 + vallen);
206 #else
207               memcpy (new_environ[size], name, namelen);
208               new_environ[size][namelen] = '=';
209               memcpy (&new_environ[size][namelen + 1], value, vallen);
210 #endif
211               /* And save the value now.  We cannot do this when we remove
212                  the string since then we cannot decide whether it is a
213                  user string or not.  */
214               STORE_VALUE (new_environ[size]);
215             }
216 #if defined USE_TSEARCH && !defined _LIBC
217           freea (new_value);
218 #endif
219         }
220
221       if (__environ != last_environ)
222         memcpy ((char *) new_environ, (char *) __environ,
223                 size * sizeof (char *));
224
225       new_environ[size + 1] = NULL;
226
227       last_environ = __environ = new_environ;
228     }
229   else if (replace)
230     {
231       char *np;
232
233       /* Use the user string if given.  */
234       if (combined != NULL)
235         np = (char *) combined;
236       else
237         {
238 #ifdef USE_TSEARCH
239           char *new_value;
240 # ifdef _LIBC
241           new_value = alloca (namelen + 1 + vallen);
242           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
243                      value, vallen);
244 # else
245           new_value = malloca (namelen + 1 + vallen);
246           if (new_value == NULL)
247             {
248               __set_errno (ENOMEM);
249               UNLOCK;
250               return -1;
251             }
252           memcpy (new_value, name, namelen);
253           new_value[namelen] = '=';
254           memcpy (&new_value[namelen + 1], value, vallen);
255 # endif
256
257           np = KNOWN_VALUE (new_value);
258           if (np == NULL)
259 #endif
260             {
261               np = (char *) malloc (namelen + 1 + vallen);
262               if (np == NULL)
263                 {
264 #if defined USE_TSEARCH && !defined _LIBC
265                   freea (new_value);
266 #endif
267                   __set_errno (ENOMEM);
268                   UNLOCK;
269                   return -1;
270                 }
271
272 #ifdef USE_TSEARCH
273               memcpy (np, new_value, namelen + 1 + vallen);
274 #else
275               memcpy (np, name, namelen);
276               np[namelen] = '=';
277               memcpy (&np[namelen + 1], value, vallen);
278 #endif
279               /* And remember the value.  */
280               STORE_VALUE (np);
281             }
282 #if defined USE_TSEARCH && !defined _LIBC
283           freea (new_value);
284 #endif
285         }
286
287       *ep = np;
288     }
289
290   UNLOCK;
291
292   return 0;
293 }
294
295 int
296 setenv (const char *name, const char *value, int replace)
297 {
298   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
299     {
300       __set_errno (EINVAL);
301       return -1;
302     }
303
304   return __add_to_environ (name, value, NULL, replace);
305 }
306
307 /* The `clearenv' was planned to be added to POSIX.1 but probably
308    never made it.  Nevertheless the POSIX.9 standard (POSIX bindings
309    for Fortran 77) requires this function.  */
310 int
311 clearenv (void)
312 {
313   LOCK;
314
315   if (__environ == last_environ && __environ != NULL)
316     {
317       /* We allocated this environment so we can free it.  */
318       free (__environ);
319       last_environ = NULL;
320     }
321
322   /* Clear the environment pointer removes the whole environment.  */
323   __environ = NULL;
324
325   UNLOCK;
326
327   return 0;
328 }
329
330 #ifdef _LIBC
331 static void
332 free_mem (void)
333 {
334   /* Remove all traces.  */
335   clearenv ();
336
337   /* Now remove the search tree.  */
338   __tdestroy (known_values, free);
339   known_values = NULL;
340 }
341 text_set_element (__libc_subfreeres, free_mem);
342
343
344 # undef setenv
345 # undef clearenv
346 weak_alias (__setenv, setenv)
347 weak_alias (__clearenv, clearenv)
348 #endif
349
350 #endif /* _LIBC || !HAVE_SETENV */
351
352 /* The rest of this file is called into use when replacing an existing
353    but buggy setenv.  Known bugs include failure to diagnose invalid
354    name, and consuming a leading '=' from value.  */
355 #if HAVE_SETENV
356
357 # undef setenv
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 */