Annotation of embedaddon/libiconv/srclib/setenv.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* Copyright (C) 1992, 1995-2003, 2005-2011 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
15: along with this program. If not, see <http://www.gnu.org/licenses/>. */
16:
17: #if !_LIBC
1.1.1.2 ! misho 18: # define _GL_USE_STDLIB_ALLOC 1
1.1 misho 19: # include <config.h>
20: #endif
1.1.1.2 ! misho 21:
! 22: /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
! 23: optimizes away the name == NULL test below. */
! 24: #define _GL_ARG_NONNULL(params)
! 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
52: /* This lock protects against simultaneous modifications of `environ'. */
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:
106: /* This function is used by `setenv' and `putenv'. The difference between
107: the two functions is that for the former must create a new string which
108: is then placed in the environment, while the argument of `putenv'
109: must be used directly. This is all complicated by the fact that we try
110: to reuse values once generated for a `setenv' call since we can never
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:
302: /* The `clearenv' was planned to be added to POSIX.1 but probably
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>