]> git.ipfire.org Git - thirdparty/glibc.git/blame - stdlib/setenv.c
use -fstack-protector-strong when available
[thirdparty/glibc.git] / stdlib / setenv.c
CommitLineData
b168057a 1/* Copyright (C) 1992-2015 Free Software Foundation, Inc.
f0e44959 2 This file is part of the GNU C Library.
28f540f4 3
f0e44959 4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
28f540f4 8
f0e44959
UD
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
41bdb6e2 12 Lesser General Public License for more details.
28f540f4 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
28f540f4 17
f0e44959
UD
18#if HAVE_CONFIG_H
19# include <config.h>
196980f5
RM
20#endif
21
03c1e456
PE
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. */
6cfae52e
RM
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
03c1e456 32
196980f5 33#include <errno.h>
61c162b5 34#if !_LIBC
ff152e3f 35# if !defined errno && !defined HAVE_ERRNO_DECL
61c162b5
UD
36extern int errno;
37# endif
38# define __set_errno(ev) ((errno) = (ev))
39#endif
196980f5
RM
40
41#if _LIBC || HAVE_STDLIB_H
f0e44959 42# include <stdlib.h>
196980f5
RM
43#endif
44#if _LIBC || HAVE_STRING_H
f0e44959 45# include <string.h>
196980f5
RM
46#endif
47#if _LIBC || HAVE_UNISTD_H
f0e44959 48# include <unistd.h>
196980f5 49#endif
28f540f4 50
61c162b5 51#if !_LIBC
f0e44959 52# define __environ environ
61c162b5
UD
53# ifndef HAVE_ENVIRON_DECL
54extern char **environ;
55# endif
28f540f4
RM
56#endif
57
61c162b5 58#if _LIBC
9e0f4072 59/* This lock protects against simultaneous modifications of `environ'. */
ec999b8e 60# include <libc-lock.h>
9e0f4072 61__libc_lock_define_initialized (static, envlock)
f0e44959
UD
62# define LOCK __libc_lock_lock (envlock)
63# define UNLOCK __libc_lock_unlock (envlock)
9e0f4072 64#else
f0e44959
UD
65# define LOCK
66# define UNLOCK
9e0f4072
RM
67#endif
68
3e5f5557
UD
69/* In the GNU C library we must keep the namespace clean. */
70#ifdef _LIBC
ff152e3f
UD
71# define setenv __setenv
72# define unsetenv __unsetenv
3e5f5557 73# define clearenv __clearenv
b17277cf
UD
74# define tfind __tfind
75# define tsearch __tsearch
3e5f5557
UD
76#endif
77
ff152e3f 78/* In the GNU C library implementation we try to be more clever and
49c091e5 79 allow arbitrarily many changes of the environment given that the used
ff152e3f
UD
80 values are from a small set. Outside glibc this will eat up all
81 memory after a while. */
a709dd43
UD
82#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
83 && defined __GNUC__)
ff152e3f
UD
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. */
89static void *known_values;
90
b17277cf
UD
91# define KNOWN_VALUE(Str) \
92 ({ \
a709dd43
UD
93 void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \
94 value != NULL ? *(char **) value : NULL; \
b17277cf
UD
95 })
96# define STORE_VALUE(Str) \
a709dd43 97 tsearch (Str, &known_values, (__compar_fn_t) strcmp)
ff152e3f
UD
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
3e5f5557 107
f0e44959
UD
108/* If this variable is not a null pointer we allocated the current
109 environment. */
110static char **last_environ;
111
112
de4a40d0
UD
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. */
28f540f4 119int
de4a40d0 120__add_to_environ (name, value, combined, replace)
196980f5
RM
121 const char *name;
122 const char *value;
de4a40d0 123 const char *combined;
196980f5 124 int replace;
28f540f4 125{
2e09a79a
JM
126 char **ep;
127 size_t size;
03c1e456
PE
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. */
196980f5 135 const size_t namelen = strlen (name);
03c1e456
PE
136 size_t vallen;
137 if (combined == NULL)
138 vallen = strlen (value) + 1;
28f540f4 139
9e0f4072
RM
140 LOCK;
141
7195db12
UD
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
28f540f4 146 size = 0;
96ff4937 147 if (ep != NULL)
b0772d3b 148 {
96ff4937 149 for (; *ep != NULL; ++ep)
b0772d3b
UD
150 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
151 break;
152 else
153 ++size;
154 }
196980f5 155
3504e5a6 156 if (ep == NULL || __builtin_expect (*ep == NULL, 1))
28f540f4 157 {
196980f5 158 char **new_environ;
86187531 159
ff152e3f
UD
160 /* We allocated this space; we can extend it. */
161 new_environ = (char **) realloc (last_environ,
162 (size + 2) * sizeof (char *));
28f540f4 163 if (new_environ == NULL)
9e0f4072
RM
164 {
165 UNLOCK;
166 return -1;
167 }
1448f324
OB
168
169 if (__environ != last_environ)
170 memcpy ((char *) new_environ, (char *) __environ,
171 size * sizeof (char *));
172
f3d338c9 173 new_environ[size] = NULL;
28f540f4 174 new_environ[size + 1] = NULL;
f3d338c9 175 ep = new_environ + size;
28f540f4 176
196980f5 177 last_environ = __environ = new_environ;
28f540f4 178 }
f3d338c9 179 if (*ep == NULL || replace)
28f540f4 180 {
cb37d842 181 char *np;
ff152e3f 182
de4a40d0
UD
183 /* Use the user string if given. */
184 if (combined != NULL)
185 np = (char *) combined;
186 else
187 {
c63bfa79 188 const size_t varlen = namelen + 1 + vallen;
ff152e3f 189#ifdef USE_TSEARCH
c63bfa79
UD
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 }
ff152e3f 203# ifdef _LIBC
de4a40d0
UD
204 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
205 value, vallen);
ff152e3f 206# else
de4a40d0
UD
207 memcpy (new_value, name, namelen);
208 new_value[namelen] = '=';
209 memcpy (&new_value[namelen + 1], value, vallen);
ff152e3f
UD
210# endif
211
de4a40d0 212 np = KNOWN_VALUE (new_value);
a1ffb40e 213 if (__glibc_likely (np == NULL))
de4a40d0 214#endif
9e0f4072 215 {
c63bfa79 216#ifdef USE_TSEARCH
a1ffb40e 217 if (__glibc_unlikely (! use_alloca))
c63bfa79
UD
218 np = new_value;
219 else
220#endif
de4a40d0 221 {
c63bfa79 222 np = malloc (varlen);
a1ffb40e 223 if (__glibc_unlikely (np == NULL))
c63bfa79
UD
224 {
225 UNLOCK;
226 return -1;
227 }
ff152e3f
UD
228
229#ifdef USE_TSEARCH
c63bfa79 230 memcpy (np, new_value, varlen);
86187531 231#else
c63bfa79
UD
232 memcpy (np, name, namelen);
233 np[namelen] = '=';
234 memcpy (&np[namelen + 1], value, vallen);
86187531 235#endif
c63bfa79 236 }
de4a40d0
UD
237 /* And remember the value. */
238 STORE_VALUE (np);
239 }
d5b1c5ed
EB
240#ifdef USE_TSEARCH
241 else
242 {
243 if (__glibc_unlikely (! use_alloca))
244 free (new_value);
245 }
246#endif
28f540f4 247 }
cb37d842 248
cb37d842 249 *ep = np;
28f540f4
RM
250 }
251
9e0f4072
RM
252 UNLOCK;
253
28f540f4
RM
254 return 0;
255}
196980f5 256
de4a40d0 257int
9d46370c 258setenv (const char *name, const char *value, int replace)
de4a40d0 259{
e17f8b61
RM
260 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
261 {
262 __set_errno (EINVAL);
263 return -1;
264 }
265
de4a40d0
UD
266 return __add_to_environ (name, value, NULL, replace);
267}
268
61f9d0a3 269int
9d46370c 270unsetenv (const char *name)
196980f5 271{
7c5bb945 272 size_t len;
196980f5
RM
273 char **ep;
274
61f9d0a3
UD
275 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
276 {
277 __set_errno (EINVAL);
278 return -1;
279 }
280
281 len = strlen (name);
282
9e0f4072
RM
283 LOCK;
284
de4a40d0 285 ep = __environ;
1fa7ae05
UD
286 if (ep != NULL)
287 while (*ep != NULL)
288 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
289 {
290 /* Found it. Remove this pointer by moving later ones back. */
291 char **dp = ep;
292
293 do
294 dp[0] = dp[1];
295 while (*dp++);
296 /* Continue the loop in case NAME appears again. */
297 }
298 else
299 ++ep;
9e0f4072
RM
300
301 UNLOCK;
61f9d0a3
UD
302
303 return 0;
196980f5 304}
f0e44959
UD
305
306/* The `clearenv' was planned to be added to POSIX.1 but probably
307 never made it. Nevertheless the POSIX.9 standard (POSIX bindings
308 for Fortran 77) requires this function. */
309int
60d2f8f3 310clearenv (void)
f0e44959
UD
311{
312 LOCK;
313
314 if (__environ == last_environ && __environ != NULL)
315 {
de4a40d0 316 /* We allocated this environment so we can free it. */
f0e44959
UD
317 free (__environ);
318 last_environ = NULL;
319 }
320
321 /* Clear the environment pointer removes the whole environment. */
322 __environ = NULL;
323
324 UNLOCK;
325
326 return 0;
327}
3e5f5557 328#ifdef _LIBC
c877418f 329libc_freeres_fn (free_mem)
69071b2a
UD
330{
331 /* Remove all traces. */
332 clearenv ();
333
334 /* Now remove the search tree. */
335 __tdestroy (known_values, free);
336 known_values = NULL;
337}
69071b2a 338
ff152e3f
UD
339# undef setenv
340# undef unsetenv
3e5f5557 341# undef clearenv
ff152e3f
UD
342weak_alias (__setenv, setenv)
343weak_alias (__unsetenv, unsetenv)
3e5f5557
UD
344weak_alias (__clearenv, clearenv)
345#endif