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>