Convert doc/DETAILS to org-mode
[gnupg.git] / gl / setenv.c
1 /* Copyright (C) 1992,1995-1999,2000-2003,2005,2006 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, or (at your option)
7    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 along
15    with this program; if not, see <http://www.gnu.org/licenses/>.  */
16
17 #if !_LIBC
18 # include <config.h>
19 #endif
20 #include <alloca.h>
21
22 #include <errno.h>
23 #ifndef __set_errno
24 # ifdef HAVE_W32CE_SYSTEM
25 #  include <gpg-error.h>
26 #  define __set_errno(ev) gpg_err_set_errno ((ev))
27 # else
28 #  define __set_errno(ev) ((errno) = (ev))
29 # endif
30 #endif
31
32 #include <stdlib.h>
33 #include <string.h>
34 #if _LIBC || HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37
38 #if !_LIBC
39 # include "allocsa.h"
40 #endif
41
42 #if !_LIBC
43 # define __environ      environ
44 # ifndef HAVE_ENVIRON_DECL
45 extern char **environ;
46 # endif
47 #endif
48
49 #if _LIBC
50 /* This lock protects against simultaneous modifications of 'environ'.  */
51 # include <bits/libc-lock.h>
52 __libc_lock_define_initialized (static, envlock)
53 # define LOCK   __libc_lock_lock (envlock)
54 # define UNLOCK __libc_lock_unlock (envlock)
55 #else
56 # define LOCK
57 # define UNLOCK
58 #endif
59
60 /* In the GNU C library we must keep the namespace clean.  */
61 #ifdef _LIBC
62 # define setenv __setenv
63 # define clearenv __clearenv
64 # define tfind __tfind
65 # define tsearch __tsearch
66 #endif
67
68 /* In the GNU C library implementation we try to be more clever and
69    allow arbitrarily many changes of the environment given that the used
70    values are from a small set.  Outside glibc this will eat up all
71    memory after a while.  */
72 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
73                       && defined __GNUC__)
74 # define USE_TSEARCH    1
75 # include <search.h>
76 typedef int (*compar_fn_t) (const void *, const void *);
77
78 /* This is a pointer to the root of the search tree with the known
79    values.  */
80 static void *known_values;
81
82 # define KNOWN_VALUE(Str) \
83   ({                                                                          \
84     void *value = tfind (Str, &known_values, (compar_fn_t) strcmp);           \
85     value != NULL ? *(char **) value : NULL;                                  \
86   })
87 # define STORE_VALUE(Str) \
88   tsearch (Str, &known_values, (compar_fn_t) strcmp)
89
90 #else
91 # undef USE_TSEARCH
92
93 # define KNOWN_VALUE(Str) NULL
94 # define STORE_VALUE(Str) do { } while (0)
95
96 #endif
97
98
99 /* If this variable is not a null pointer we allocated the current
100    environment.  */
101 static char **last_environ;
102
103
104 /* This function is used by 'setenv' and 'putenv'.  The difference between
105    the two functions is that for the former must create a new string which
106    is then placed in the environment, while the argument of 'putenv'
107    must be used directly.  This is all complicated by the fact that we try
108    to reuse values once generated for a 'setenv' call since we can never
109    free the strings.  */
110 int
111 __add_to_environ (const char *name, const char *value, const char *combined,
112                   int replace)
113 {
114   register char **ep;
115   register size_t size;
116   const size_t namelen = strlen (name);
117   const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
118
119   LOCK;
120
121   /* We have to get the pointer now that we have the lock and not earlier
122      since another thread might have created a new environment.  */
123   ep = __environ;
124
125   size = 0;
126   if (ep != NULL)
127     {
128       for (; *ep != NULL; ++ep)
129         if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
130           break;
131         else
132           ++size;
133     }
134
135   if (ep == NULL || *ep == NULL)
136     {
137       char **new_environ;
138 #ifdef USE_TSEARCH
139       char *new_value;
140 #endif
141
142       /* We allocated this space; we can extend it.  */
143       new_environ =
144         (char **) (last_environ == NULL
145                    ? malloc ((size + 2) * sizeof (char *))
146                    : realloc (last_environ, (size + 2) * sizeof (char *)));
147       if (new_environ == NULL)
148         {
149           UNLOCK;
150           return -1;
151         }
152
153       /* If the whole entry is given add it.  */
154       if (combined != NULL)
155         /* We must not add the string to the search tree since it belongs
156            to the user.  */
157         new_environ[size] = (char *) combined;
158       else
159         {
160           /* See whether the value is already known.  */
161 #ifdef USE_TSEARCH
162 # ifdef _LIBC
163           new_value = (char *) alloca (namelen + 1 + vallen);
164           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
165                      value, vallen);
166 # else
167           new_value = (char *) allocsa (namelen + 1 + vallen);
168           if (new_value == NULL)
169             {
170               __set_errno (ENOMEM);
171               UNLOCK;
172               return -1;
173             }
174           memcpy (new_value, name, namelen);
175           new_value[namelen] = '=';
176           memcpy (&new_value[namelen + 1], value, vallen);
177 # endif
178
179           new_environ[size] = KNOWN_VALUE (new_value);
180           if (new_environ[size] == NULL)
181 #endif
182             {
183               new_environ[size] = (char *) malloc (namelen + 1 + vallen);
184               if (new_environ[size] == NULL)
185                 {
186 #if defined USE_TSEARCH && !defined _LIBC
187                   freesa (new_value);
188 #endif
189                   __set_errno (ENOMEM);
190                   UNLOCK;
191                   return -1;
192                 }
193
194 #ifdef USE_TSEARCH
195               memcpy (new_environ[size], new_value, namelen + 1 + vallen);
196 #else
197               memcpy (new_environ[size], name, namelen);
198               new_environ[size][namelen] = '=';
199               memcpy (&new_environ[size][namelen + 1], value, vallen);
200 #endif
201               /* And save the value now.  We cannot do this when we remove
202                  the string since then we cannot decide whether it is a
203                  user string or not.  */
204               STORE_VALUE (new_environ[size]);
205             }
206 #if defined USE_TSEARCH && !defined _LIBC
207           freesa (new_value);
208 #endif
209         }
210
211       if (__environ != last_environ)
212         memcpy ((char *) new_environ, (char *) __environ,
213                 size * sizeof (char *));
214
215       new_environ[size + 1] = NULL;
216
217       last_environ = __environ = new_environ;
218     }
219   else if (replace)
220     {
221       char *np;
222
223       /* Use the user string if given.  */
224       if (combined != NULL)
225         np = (char *) combined;
226       else
227         {
228 #ifdef USE_TSEARCH
229           char *new_value;
230 # ifdef _LIBC
231           new_value = alloca (namelen + 1 + vallen);
232           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
233                      value, vallen);
234 # else
235           new_value = allocsa (namelen + 1 + vallen);
236           if (new_value == NULL)
237             {
238               __set_errno (ENOMEM);
239               UNLOCK;
240               return -1;
241             }
242           memcpy (new_value, name, namelen);
243           new_value[namelen] = '=';
244           memcpy (&new_value[namelen + 1], value, vallen);
245 # endif
246
247           np = KNOWN_VALUE (new_value);
248           if (np == NULL)
249 #endif
250             {
251               np = malloc (namelen + 1 + vallen);
252               if (np == NULL)
253                 {
254 #if defined USE_TSEARCH && !defined _LIBC
255                   freesa (new_value);
256 #endif
257                   __set_errno (ENOMEM);
258                   UNLOCK;
259                   return -1;
260                 }
261
262 #ifdef USE_TSEARCH
263               memcpy (np, new_value, namelen + 1 + vallen);
264 #else
265               memcpy (np, name, namelen);
266               np[namelen] = '=';
267               memcpy (&np[namelen + 1], value, vallen);
268 #endif
269               /* And remember the value.  */
270               STORE_VALUE (np);
271             }
272 #if defined USE_TSEARCH && !defined _LIBC
273           freesa (new_value);
274 #endif
275         }
276
277       *ep = np;
278     }
279
280   UNLOCK;
281
282   return 0;
283 }
284
285 int
286 setenv (const char *name, const char *value, int replace)
287 {
288   return __add_to_environ (name, value, NULL, replace);
289 }
290
291 /* The 'clearenv' was planned to be added to POSIX.1 but probably
292    never made it.  Nevertheless the POSIX.9 standard (POSIX bindings
293    for Fortran 77) requires this function.  */
294 int
295 clearenv (void)
296 {
297   LOCK;
298
299   if (__environ == last_environ && __environ != NULL)
300     {
301       /* We allocated this environment so we can free it.  */
302       free (__environ);
303       last_environ = NULL;
304     }
305
306   /* Clear the environment pointer removes the whole environment.  */
307   __environ = NULL;
308
309   UNLOCK;
310
311   return 0;
312 }
313
314 #ifdef _LIBC
315 static void
316 free_mem (void)
317 {
318   /* Remove all traces.  */
319   clearenv ();
320
321   /* Now remove the search tree.  */
322   __tdestroy (known_values, free);
323   known_values = NULL;
324 }
325 text_set_element (__libc_subfreeres, free_mem);
326
327
328 # undef setenv
329 # undef clearenv
330 weak_alias (__setenv, setenv)
331 weak_alias (__clearenv, clearenv)
332 #endif