File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / setenv.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 13:38:46 2021 UTC (3 years, 3 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_16p0, HEAD
libiconv 1.16

    1: /* Copyright (C) 1992, 1995-2003, 2005-2019 Free Software Foundation, Inc.
    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 <https://www.gnu.org/licenses/>.  */
   16: 
   17: #if !_LIBC
   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: 
   22: # define _GL_USE_STDLIB_ALLOC 1
   23: # include <config.h>
   24: #endif
   25: 
   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: 
   45: #if _LIBC || !HAVE_SETENV
   46: 
   47: #if !_LIBC
   48: # define __environ      environ
   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)
   55: # define LOCK   __libc_lock_lock (envlock)
   56: # define UNLOCK __libc_lock_unlock (envlock)
   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 \
   75:                       && defined __GNUC__)
   76: # define USE_TSEARCH    1
   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) \
   85:   ({                                                                          \
   86:     void *value = tfind (Str, &known_values, (compar_fn_t) strcmp);           \
   87:     value != NULL ? *(char **) value : NULL;                                  \
   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,
  114:                   int replace)
  115: {
  116:   char **ep;
  117:   size_t size;
  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)
  131:         if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
  132:           break;
  133:         else
  134:           ++size;
  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 =
  146:         (char **) (last_environ == NULL
  147:                    ? malloc ((size + 2) * sizeof (char *))
  148:                    : realloc (last_environ, (size + 2) * sizeof (char *)));
  149:       if (new_environ == NULL)
  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:         }
  157: 
  158:       /* If the whole entry is given add it.  */
  159:       if (combined != NULL)
  160:         /* We must not add the string to the search tree since it belongs
  161:            to the user.  */
  162:         new_environ[size] = (char *) combined;
  163:       else
  164:         {
  165:           /* See whether the value is already known.  */
  166: #ifdef USE_TSEARCH
  167: # ifdef _LIBC
  168:           new_value = (char *) alloca (namelen + 1 + vallen);
  169:           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
  170:                      value, vallen);
  171: # else
  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);
  182: # endif
  183: 
  184:           new_environ[size] = KNOWN_VALUE (new_value);
  185:           if (new_environ[size] == NULL)
  186: #endif
  187:             {
  188:               new_environ[size] = (char *) malloc (namelen + 1 + vallen);
  189:               if (new_environ[size] == NULL)
  190:                 {
  191: #if defined USE_TSEARCH && !defined _LIBC
  192:                   freea (new_value);
  193: #endif
  194:                   __set_errno (ENOMEM);
  195:                   UNLOCK;
  196:                   return -1;
  197:                 }
  198: 
  199: #ifdef USE_TSEARCH
  200:               memcpy (new_environ[size], new_value, namelen + 1 + vallen);
  201: #else
  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:             }
  211: #if defined USE_TSEARCH && !defined _LIBC
  212:           freea (new_value);
  213: #endif
  214:         }
  215: 
  216:       if (__environ != last_environ)
  217:         memcpy ((char *) new_environ, (char *) __environ,
  218:                 size * sizeof (char *));
  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)
  230:         np = (char *) combined;
  231:       else
  232:         {
  233: #ifdef USE_TSEARCH
  234:           char *new_value;
  235: # ifdef _LIBC
  236:           new_value = alloca (namelen + 1 + vallen);
  237:           __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
  238:                      value, vallen);
  239: # else
  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);
  250: # endif
  251: 
  252:           np = KNOWN_VALUE (new_value);
  253:           if (np == NULL)
  254: #endif
  255:             {
  256:               np = (char *) malloc (namelen + 1 + vallen);
  257:               if (np == NULL)
  258:                 {
  259: #if defined USE_TSEARCH && !defined _LIBC
  260:                   freea (new_value);
  261: #endif
  262:                   __set_errno (ENOMEM);
  263:                   UNLOCK;
  264:                   return -1;
  265:                 }
  266: 
  267: #ifdef USE_TSEARCH
  268:               memcpy (np, new_value, namelen + 1 + vallen);
  269: #else
  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:             }
  277: #if defined USE_TSEARCH && !defined _LIBC
  278:           freea (new_value);
  279: #endif
  280:         }
  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: {
  293:   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
  294:     {
  295:       __set_errno (EINVAL);
  296:       return -1;
  297:     }
  298: 
  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 */
  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>