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>