Annotation of embedaddon/libiconv/srclib/setenv.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* Copyright (C) 1992, 1995-2003, 2005-2019 Free Software Foundation, Inc.
1.1 misho 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 of the License, or
7: (at your option) 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
1.1.1.3 ! misho 15: along with this program. If not, see <https://www.gnu.org/licenses/>. */
1.1 misho 16:
17: #if !_LIBC
1.1.1.3 ! misho 18: /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
! 19: optimizes away the name == NULL test below. */
! 20: # define _GL_ARG_NONNULL(params)
! 21:
1.1.1.2 misho 22: # define _GL_USE_STDLIB_ALLOC 1
1.1 misho 23: # include <config.h>
24: #endif
1.1.1.2 misho 25:
1.1 misho 26: #include <alloca.h>
27:
28: /* Specification. */
29: #include <stdlib.h>
30:
31: #include <errno.h>
32: #ifndef __set_errno
33: # define __set_errno(ev) ((errno) = (ev))
34: #endif
35:
36: #include <string.h>
37: #if _LIBC || HAVE_UNISTD_H
38: # include <unistd.h>
39: #endif
40:
41: #if !_LIBC
42: # include "malloca.h"
43: #endif
44:
1.1.1.2 misho 45: #if _LIBC || !HAVE_SETENV
46:
1.1 misho 47: #if !_LIBC
1.1.1.2 misho 48: # define __environ environ
1.1 misho 49: #endif
50:
51: #if _LIBC
1.1.1.3 ! misho 52: /* This lock protects against simultaneous modifications of 'environ'. */
1.1 misho 53: # include <bits/libc-lock.h>
54: __libc_lock_define_initialized (static, envlock)
1.1.1.2 misho 55: # define LOCK __libc_lock_lock (envlock)
56: # define UNLOCK __libc_lock_unlock (envlock)
1.1 misho 57: #else
58: # define LOCK
59: # define UNLOCK
60: #endif
61:
62: /* In the GNU C library we must keep the namespace clean. */
63: #ifdef _LIBC
64: # define setenv __setenv
65: # define clearenv __clearenv
66: # define tfind __tfind
67: # define tsearch __tsearch
68: #endif
69:
70: /* In the GNU C library implementation we try to be more clever and
71: allow arbitrarily many changes of the environment given that the used
72: values are from a small set. Outside glibc this will eat up all
73: memory after a while. */
74: #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
1.1.1.2 misho 75: && defined __GNUC__)
76: # define USE_TSEARCH 1
1.1 misho 77: # include <search.h>
78: typedef int (*compar_fn_t) (const void *, const void *);
79:
80: /* This is a pointer to the root of the search tree with the known
81: values. */
82: static void *known_values;
83:
84: # define KNOWN_VALUE(Str) \
1.1.1.2 misho 85: ({ \
86: void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
87: value != NULL ? *(char **) value : NULL; \
1.1 misho 88: })
89: # define STORE_VALUE(Str) \
90: tsearch (Str, &known_values, (compar_fn_t) strcmp)
91:
92: #else
93: # undef USE_TSEARCH
94:
95: # define KNOWN_VALUE(Str) NULL
96: # define STORE_VALUE(Str) do { } while (0)
97:
98: #endif
99:
100:
101: /* If this variable is not a null pointer we allocated the current
102: environment. */
103: static char **last_environ;
104:
105:
1.1.1.3 ! misho 106: /* This function is used by 'setenv' and 'putenv'. The difference between
1.1 misho 107: the two functions is that for the former must create a new string which
1.1.1.3 ! misho 108: is then placed in the environment, while the argument of 'putenv'
1.1 misho 109: must be used directly. This is all complicated by the fact that we try
1.1.1.3 ! misho 110: to reuse values once generated for a 'setenv' call since we can never
1.1 misho 111: free the strings. */
112: int
113: __add_to_environ (const char *name, const char *value, const char *combined,
1.1.1.2 misho 114: int replace)
1.1 misho 115: {
1.1.1.2 misho 116: char **ep;
117: size_t size;
1.1 misho 118: const size_t namelen = strlen (name);
119: const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
120:
121: LOCK;
122:
123: /* We have to get the pointer now that we have the lock and not earlier
124: since another thread might have created a new environment. */
125: ep = __environ;
126:
127: size = 0;
128: if (ep != NULL)
129: {
130: for (; *ep != NULL; ++ep)
1.1.1.2 misho 131: if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
132: break;
133: else
134: ++size;
1.1 misho 135: }
136:
137: if (ep == NULL || *ep == NULL)
138: {
139: char **new_environ;
140: #ifdef USE_TSEARCH
141: char *new_value;
142: #endif
143:
144: /* We allocated this space; we can extend it. */
145: new_environ =
1.1.1.2 misho 146: (char **) (last_environ == NULL
147: ? malloc ((size + 2) * sizeof (char *))
148: : realloc (last_environ, (size + 2) * sizeof (char *)));
1.1 misho 149: if (new_environ == NULL)
1.1.1.2 misho 150: {
151: /* It's easier to set errno to ENOMEM than to rely on the
152: 'malloc-posix' and 'realloc-posix' gnulib modules. */
153: __set_errno (ENOMEM);
154: UNLOCK;
155: return -1;
156: }
1.1 misho 157:
158: /* If the whole entry is given add it. */
159: if (combined != NULL)
1.1.1.2 misho 160: /* We must not add the string to the search tree since it belongs
161: to the user. */
162: new_environ[size] = (char *) combined;
1.1 misho 163: else
1.1.1.2 misho 164: {
165: /* See whether the value is already known. */
1.1 misho 166: #ifdef USE_TSEARCH
167: # ifdef _LIBC
1.1.1.2 misho 168: new_value = (char *) alloca (namelen + 1 + vallen);
169: __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
170: value, vallen);
1.1 misho 171: # else
1.1.1.2 misho 172: new_value = (char *) malloca (namelen + 1 + vallen);
173: if (new_value == NULL)
174: {
175: __set_errno (ENOMEM);
176: UNLOCK;
177: return -1;
178: }
179: memcpy (new_value, name, namelen);
180: new_value[namelen] = '=';
181: memcpy (&new_value[namelen + 1], value, vallen);
1.1 misho 182: # endif
183:
1.1.1.2 misho 184: new_environ[size] = KNOWN_VALUE (new_value);
185: if (new_environ[size] == NULL)
1.1 misho 186: #endif
1.1.1.2 misho 187: {
188: new_environ[size] = (char *) malloc (namelen + 1 + vallen);
189: if (new_environ[size] == NULL)
190: {
1.1 misho 191: #if defined USE_TSEARCH && !defined _LIBC
1.1.1.2 misho 192: freea (new_value);
1.1 misho 193: #endif
1.1.1.2 misho 194: __set_errno (ENOMEM);
195: UNLOCK;
196: return -1;
197: }
1.1 misho 198:
199: #ifdef USE_TSEARCH
1.1.1.2 misho 200: memcpy (new_environ[size], new_value, namelen + 1 + vallen);
1.1 misho 201: #else
1.1.1.2 misho 202: memcpy (new_environ[size], name, namelen);
203: new_environ[size][namelen] = '=';
204: memcpy (&new_environ[size][namelen + 1], value, vallen);
205: #endif
206: /* And save the value now. We cannot do this when we remove
207: the string since then we cannot decide whether it is a
208: user string or not. */
209: STORE_VALUE (new_environ[size]);
210: }
1.1 misho 211: #if defined USE_TSEARCH && !defined _LIBC
1.1.1.2 misho 212: freea (new_value);
1.1 misho 213: #endif
1.1.1.2 misho 214: }
1.1 misho 215:
216: if (__environ != last_environ)
1.1.1.2 misho 217: memcpy ((char *) new_environ, (char *) __environ,
218: size * sizeof (char *));
1.1 misho 219:
220: new_environ[size + 1] = NULL;
221:
222: last_environ = __environ = new_environ;
223: }
224: else if (replace)
225: {
226: char *np;
227:
228: /* Use the user string if given. */
229: if (combined != NULL)
1.1.1.2 misho 230: np = (char *) combined;
1.1 misho 231: else
1.1.1.2 misho 232: {
1.1 misho 233: #ifdef USE_TSEARCH
1.1.1.2 misho 234: char *new_value;
1.1 misho 235: # ifdef _LIBC
1.1.1.2 misho 236: new_value = alloca (namelen + 1 + vallen);
237: __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
238: value, vallen);
1.1 misho 239: # else
1.1.1.2 misho 240: new_value = malloca (namelen + 1 + vallen);
241: if (new_value == NULL)
242: {
243: __set_errno (ENOMEM);
244: UNLOCK;
245: return -1;
246: }
247: memcpy (new_value, name, namelen);
248: new_value[namelen] = '=';
249: memcpy (&new_value[namelen + 1], value, vallen);
1.1 misho 250: # endif
251:
1.1.1.2 misho 252: np = KNOWN_VALUE (new_value);
253: if (np == NULL)
1.1 misho 254: #endif
1.1.1.2 misho 255: {
256: np = (char *) malloc (namelen + 1 + vallen);
257: if (np == NULL)
258: {
1.1 misho 259: #if defined USE_TSEARCH && !defined _LIBC
1.1.1.2 misho 260: freea (new_value);
1.1 misho 261: #endif
1.1.1.2 misho 262: __set_errno (ENOMEM);
263: UNLOCK;
264: return -1;
265: }
1.1 misho 266:
267: #ifdef USE_TSEARCH
1.1.1.2 misho 268: memcpy (np, new_value, namelen + 1 + vallen);
1.1 misho 269: #else
1.1.1.2 misho 270: memcpy (np, name, namelen);
271: np[namelen] = '=';
272: memcpy (&np[namelen + 1], value, vallen);
273: #endif
274: /* And remember the value. */
275: STORE_VALUE (np);
276: }
1.1 misho 277: #if defined USE_TSEARCH && !defined _LIBC
1.1.1.2 misho 278: freea (new_value);
1.1 misho 279: #endif
1.1.1.2 misho 280: }
1.1 misho 281:
282: *ep = np;
283: }
284:
285: UNLOCK;
286:
287: return 0;
288: }
289:
290: int
291: setenv (const char *name, const char *value, int replace)
292: {
1.1.1.2 misho 293: if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
294: {
295: __set_errno (EINVAL);
296: return -1;
297: }
298:
1.1 misho 299: return __add_to_environ (name, value, NULL, replace);
300: }
301:
1.1.1.3 ! misho 302: /* The 'clearenv' was planned to be added to POSIX.1 but probably
1.1 misho 303: never made it. Nevertheless the POSIX.9 standard (POSIX bindings
304: for Fortran 77) requires this function. */
305: int
306: clearenv (void)
307: {
308: LOCK;
309:
310: if (__environ == last_environ && __environ != NULL)
311: {
312: /* We allocated this environment so we can free it. */
313: free (__environ);
314: last_environ = NULL;
315: }
316:
317: /* Clear the environment pointer removes the whole environment. */
318: __environ = NULL;
319:
320: UNLOCK;
321:
322: return 0;
323: }
324:
325: #ifdef _LIBC
326: static void
327: free_mem (void)
328: {
329: /* Remove all traces. */
330: clearenv ();
331:
332: /* Now remove the search tree. */
333: __tdestroy (known_values, free);
334: known_values = NULL;
335: }
336: text_set_element (__libc_subfreeres, free_mem);
337:
338:
339: # undef setenv
340: # undef clearenv
341: weak_alias (__setenv, setenv)
342: weak_alias (__clearenv, clearenv)
343: #endif
344:
345: #endif /* _LIBC || !HAVE_SETENV */
1.1.1.2 misho 346:
347: /* The rest of this file is called into use when replacing an existing
348: but buggy setenv. Known bugs include failure to diagnose invalid
349: name, and consuming a leading '=' from value. */
350: #if HAVE_SETENV
351:
352: # undef setenv
353: # if !HAVE_DECL_SETENV
354: extern int setenv (const char *, const char *, int);
355: # endif
356: # define STREQ(a, b) (strcmp (a, b) == 0)
357:
358: int
359: rpl_setenv (const char *name, const char *value, int replace)
360: {
361: int result;
362: if (!name || !*name || strchr (name, '='))
363: {
364: errno = EINVAL;
365: return -1;
366: }
367: /* Call the real setenv even if replace is 0, in case implementation
368: has underlying data to update, such as when environ changes. */
369: result = setenv (name, value, replace);
370: if (result == 0 && replace && *value == '=')
371: {
372: char *tmp = getenv (name);
373: if (!STREQ (tmp, value))
374: {
375: int saved_errno;
376: size_t len = strlen (value);
377: tmp = malloca (len + 2);
378: /* Since leading '=' is eaten, double it up. */
379: *tmp = '=';
380: memcpy (tmp + 1, value, len + 1);
381: result = setenv (name, tmp, replace);
382: saved_errno = errno;
383: freea (tmp);
384: errno = saved_errno;
385: }
386: }
387: return result;
388: }
389:
390: #endif /* HAVE_SETENV */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>