S390: Optimize strnlen and wcsnlen.
[glibc.git] / stdlib / setenv.c
blobb9e0ba808df053444cbaac645bee72677e8e6000
1 /* Copyright (C) 1992-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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/>. */
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
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
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
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
51 #if !_LIBC
52 # define __environ environ
53 # ifndef HAVE_ENVIRON_DECL
54 extern char **environ;
55 # endif
56 #endif
58 #if _LIBC
59 /* This lock protects against simultaneous modifications of `environ'. */
60 # include <bits/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
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
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>
87 /* This is a pointer to the root of the search tree with the known
88 values. */
89 static void *known_values;
91 # define KNOWN_VALUE(Str) \
92 ({ \
93 void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \
94 value != NULL ? *(char **) value : NULL; \
96 # define STORE_VALUE(Str) \
97 tsearch (Str, &known_values, (__compar_fn_t) strcmp)
99 #else
100 # undef USE_TSEARCH
102 # define KNOWN_VALUE(Str) NULL
103 # define STORE_VALUE(Str) do { } while (0)
105 #endif
108 /* If this variable is not a null pointer we allocated the current
109 environment. */
110 static char **last_environ;
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. */
120 __add_to_environ (name, value, combined, replace)
121 const char *name;
122 const char *value;
123 const char *combined;
124 int replace;
126 char **ep;
127 size_t size;
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;
140 LOCK;
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;
146 size = 0;
147 if (ep != NULL)
149 for (; *ep != NULL; ++ep)
150 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
151 break;
152 else
153 ++size;
156 if (ep == NULL || __builtin_expect (*ep == NULL, 1))
158 char **new_environ;
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)
165 UNLOCK;
166 return -1;
169 if (__environ != last_environ)
170 memcpy ((char *) new_environ, (char *) __environ,
171 size * sizeof (char *));
173 new_environ[size] = NULL;
174 new_environ[size + 1] = NULL;
175 ep = new_environ + size;
177 last_environ = __environ = new_environ;
179 if (*ep == NULL || replace)
181 char *np;
183 /* Use the user string if given. */
184 if (combined != NULL)
185 np = (char *) combined;
186 else
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
196 new_value = malloc (varlen);
197 if (new_value == NULL)
199 UNLOCK;
200 return -1;
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
212 np = KNOWN_VALUE (new_value);
213 if (__glibc_likely (np == NULL))
214 #endif
216 #ifdef USE_TSEARCH
217 if (__glibc_unlikely (! use_alloca))
218 np = new_value;
219 else
220 #endif
222 np = malloc (varlen);
223 if (__glibc_unlikely (np == NULL))
225 UNLOCK;
226 return -1;
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
237 /* And remember the value. */
238 STORE_VALUE (np);
240 #ifdef USE_TSEARCH
241 else
243 if (__glibc_unlikely (! use_alloca))
244 free (new_value);
246 #endif
249 *ep = np;
252 UNLOCK;
254 return 0;
258 setenv (name, value, replace)
259 const char *name;
260 const char *value;
261 int replace;
263 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
265 __set_errno (EINVAL);
266 return -1;
269 return __add_to_environ (name, value, NULL, replace);
273 unsetenv (name)
274 const char *name;
276 size_t len;
277 char **ep;
279 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
281 __set_errno (EINVAL);
282 return -1;
285 len = strlen (name);
287 LOCK;
289 ep = __environ;
290 if (ep != NULL)
291 while (*ep != NULL)
292 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
294 /* Found it. Remove this pointer by moving later ones back. */
295 char **dp = ep;
298 dp[0] = dp[1];
299 while (*dp++);
300 /* Continue the loop in case NAME appears again. */
302 else
303 ++ep;
305 UNLOCK;
307 return 0;
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. */
314 clearenv (void)
316 LOCK;
318 if (__environ == last_environ && __environ != NULL)
320 /* We allocated this environment so we can free it. */
321 free (__environ);
322 last_environ = NULL;
325 /* Clear the environment pointer removes the whole environment. */
326 __environ = NULL;
328 UNLOCK;
330 return 0;
332 #ifdef _LIBC
333 libc_freeres_fn (free_mem)
335 /* Remove all traces. */
336 clearenv ();
338 /* Now remove the search tree. */
339 __tdestroy (known_values, free);
340 known_values = NULL;
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