]> git.ipfire.org Git - thirdparty/glibc.git/blob - stdlib/setenv.c
Move bits/libc-lock.h and bits/libc-lockP.h out of bits/ (bug 14912).
[thirdparty/glibc.git] / stdlib / setenv.c
1 /* Copyright (C) 1992-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library 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 GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 /* Pacify GCC; see the commentary about VALLEN below. This is needed
23 at least through GCC 4.9.2. Pacify GCC for the entire file, as
24 there seems to be no way to pacify GCC selectively, only for the
25 place where it's needed. Do not use DIAG_IGNORE_NEEDS_COMMENT
26 here, as it's not defined yet. */
27 #if ((__GNUC__ << 16) + __GNUC_MINOR__) >= ((4 << 16) + 7)
28 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
29 #else
30 # pragma GCC diagnostic ignored "-Wuninitialized"
31 #endif
32
33 #include <errno.h>
34 #if !_LIBC
35 # if !defined errno && !defined HAVE_ERRNO_DECL
36 extern int errno;
37 # endif
38 # define __set_errno(ev) ((errno) = (ev))
39 #endif
40
41 #if _LIBC || HAVE_STDLIB_H
42 # include <stdlib.h>
43 #endif
44 #if _LIBC || HAVE_STRING_H
45 # include <string.h>
46 #endif
47 #if _LIBC || HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50
51 #if !_LIBC
52 # define __environ environ
53 # ifndef HAVE_ENVIRON_DECL
54 extern char **environ;
55 # endif
56 #endif
57
58 #if _LIBC
59 /* This lock protects against simultaneous modifications of `environ'. */
60 # include <libc-lock.h>
61 __libc_lock_define_initialized (static, envlock)
62 # define LOCK __libc_lock_lock (envlock)
63 # define UNLOCK __libc_lock_unlock (envlock)
64 #else
65 # define LOCK
66 # define UNLOCK
67 #endif
68
69 /* In the GNU C library we must keep the namespace clean. */
70 #ifdef _LIBC
71 # define setenv __setenv
72 # define unsetenv __unsetenv
73 # define clearenv __clearenv
74 # define tfind __tfind
75 # define tsearch __tsearch
76 #endif
77
78 /* In the GNU C library implementation we try to be more clever and
79 allow arbitrarily many changes of the environment given that the used
80 values are from a small set. Outside glibc this will eat up all
81 memory after a while. */
82 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
83 && defined __GNUC__)
84 # define USE_TSEARCH 1
85 # include <search.h>
86
87 /* This is a pointer to the root of the search tree with the known
88 values. */
89 static void *known_values;
90
91 # define KNOWN_VALUE(Str) \
92 ({ \
93 void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \
94 value != NULL ? *(char **) value : NULL; \
95 })
96 # define STORE_VALUE(Str) \
97 tsearch (Str, &known_values, (__compar_fn_t) strcmp)
98
99 #else
100 # undef USE_TSEARCH
101
102 # define KNOWN_VALUE(Str) NULL
103 # define STORE_VALUE(Str) do { } while (0)
104
105 #endif
106
107
108 /* If this variable is not a null pointer we allocated the current
109 environment. */
110 static char **last_environ;
111
112
113 /* This function is used by `setenv' and `putenv'. The difference between
114 the two functions is that for the former must create a new string which
115 is then placed in the environment, while the argument of `putenv'
116 must be used directly. This is all complicated by the fact that we try
117 to reuse values once generated for a `setenv' call since we can never
118 free the strings. */
119 int
120 __add_to_environ (name, value, combined, replace)
121 const char *name;
122 const char *value;
123 const char *combined;
124 int replace;
125 {
126 char **ep;
127 size_t size;
128
129 /* Compute lengths before locking, so that the critical section is
130 less of a performance bottleneck. VALLEN is needed only if
131 COMBINED is null (unfortunately GCC is not smart enough to deduce
132 this; see the #pragma at the start of this file). Testing
133 COMBINED instead of VALUE causes setenv (..., NULL, ...) to dump
134 core now instead of corrupting memory later. */
135 const size_t namelen = strlen (name);
136 size_t vallen;
137 if (combined == NULL)
138 vallen = strlen (value) + 1;
139
140 LOCK;
141
142 /* We have to get the pointer now that we have the lock and not earlier
143 since another thread might have created a new environment. */
144 ep = __environ;
145
146 size = 0;
147 if (ep != NULL)
148 {
149 for (; *ep != NULL; ++ep)
150 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
151 break;
152 else
153 ++size;
154 }
155
156 if (ep == NULL || __builtin_expect (*ep == NULL, 1))
157 {
158 char **new_environ;
159
160 /* We allocated this space; we can extend it. */
161 new_environ = (char **) realloc (last_environ,
162 (size + 2) * sizeof (char *));
163 if (new_environ == NULL)
164 {
165 UNLOCK;
166 return -1;
167 }
168
169 if (__environ != last_environ)
170 memcpy ((char *) new_environ, (char *) __environ,
171 size * sizeof (char *));
172
173 new_environ[size] = NULL;
174 new_environ[size + 1] = NULL;
175 ep = new_environ + size;
176
177 last_environ = __environ = new_environ;
178 }
179 if (*ep == NULL || replace)
180 {
181 char *np;
182
183 /* Use the user string if given. */
184 if (combined != NULL)
185 np = (char *) combined;
186 else
187 {
188 const size_t varlen = namelen + 1 + vallen;
189 #ifdef USE_TSEARCH
190 char *new_value;
191 int use_alloca = __libc_use_alloca (varlen);
192 if (__builtin_expect (use_alloca, 1))
193 new_value = (char *) alloca (varlen);
194 else
195 {
196 new_value = malloc (varlen);
197 if (new_value == NULL)
198 {
199 UNLOCK;
200 return -1;
201 }
202 }
203 # ifdef _LIBC
204 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
205 value, vallen);
206 # else
207 memcpy (new_value, name, namelen);
208 new_value[namelen] = '=';
209 memcpy (&new_value[namelen + 1], value, vallen);
210 # endif
211
212 np = KNOWN_VALUE (new_value);
213 if (__glibc_likely (np == NULL))
214 #endif
215 {
216 #ifdef USE_TSEARCH
217 if (__glibc_unlikely (! use_alloca))
218 np = new_value;
219 else
220 #endif
221 {
222 np = malloc (varlen);
223 if (__glibc_unlikely (np == NULL))
224 {
225 UNLOCK;
226 return -1;
227 }
228
229 #ifdef USE_TSEARCH
230 memcpy (np, new_value, varlen);
231 #else
232 memcpy (np, name, namelen);
233 np[namelen] = '=';
234 memcpy (&np[namelen + 1], value, vallen);
235 #endif
236 }
237 /* And remember the value. */
238 STORE_VALUE (np);
239 }
240 #ifdef USE_TSEARCH
241 else
242 {
243 if (__glibc_unlikely (! use_alloca))
244 free (new_value);
245 }
246 #endif
247 }
248
249 *ep = np;
250 }
251
252 UNLOCK;
253
254 return 0;
255 }
256
257 int
258 setenv (name, value, replace)
259 const char *name;
260 const char *value;
261 int replace;
262 {
263 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
264 {
265 __set_errno (EINVAL);
266 return -1;
267 }
268
269 return __add_to_environ (name, value, NULL, replace);
270 }
271
272 int
273 unsetenv (name)
274 const char *name;
275 {
276 size_t len;
277 char **ep;
278
279 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
280 {
281 __set_errno (EINVAL);
282 return -1;
283 }
284
285 len = strlen (name);
286
287 LOCK;
288
289 ep = __environ;
290 if (ep != NULL)
291 while (*ep != NULL)
292 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
293 {
294 /* Found it. Remove this pointer by moving later ones back. */
295 char **dp = ep;
296
297 do
298 dp[0] = dp[1];
299 while (*dp++);
300 /* Continue the loop in case NAME appears again. */
301 }
302 else
303 ++ep;
304
305 UNLOCK;
306
307 return 0;
308 }
309
310 /* The `clearenv' was planned to be added to POSIX.1 but probably
311 never made it. Nevertheless the POSIX.9 standard (POSIX bindings
312 for Fortran 77) requires this function. */
313 int
314 clearenv (void)
315 {
316 LOCK;
317
318 if (__environ == last_environ && __environ != NULL)
319 {
320 /* We allocated this environment so we can free it. */
321 free (__environ);
322 last_environ = NULL;
323 }
324
325 /* Clear the environment pointer removes the whole environment. */
326 __environ = NULL;
327
328 UNLOCK;
329
330 return 0;
331 }
332 #ifdef _LIBC
333 libc_freeres_fn (free_mem)
334 {
335 /* Remove all traces. */
336 clearenv ();
337
338 /* Now remove the search tree. */
339 __tdestroy (known_values, free);
340 known_values = NULL;
341 }
342
343 # undef setenv
344 # undef unsetenv
345 # undef clearenv
346 weak_alias (__setenv, setenv)
347 weak_alias (__unsetenv, unsetenv)
348 weak_alias (__clearenv, clearenv)
349 #endif