Home | History | Annotate | Line # | Download | only in gnulib-lib
      1  1.1  christos /* Copyright (C) 1992,1995-1999,2000-2003,2005,2006 Free Software Foundation, Inc.
      2  1.1  christos    This file is part of the GNU C Library.
      3  1.1  christos 
      4  1.1  christos    This program is free software; you can redistribute it and/or modify
      5  1.1  christos    it under the terms of the GNU General Public License as published by
      6  1.1  christos    the Free Software Foundation; either version 2, or (at your option)
      7  1.1  christos    any later version.
      8  1.1  christos 
      9  1.1  christos    This program is distributed in the hope that it will be useful,
     10  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  1.1  christos    GNU General Public License for more details.
     13  1.1  christos 
     14  1.1  christos    You should have received a copy of the GNU General Public License along
     15  1.1  christos    with this program; if not, write to the Free Software Foundation,
     16  1.1  christos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
     17  1.1  christos 
     18  1.1  christos #if !_LIBC
     19  1.1  christos # include <config.h>
     20  1.1  christos #endif
     21  1.1  christos #include <alloca.h>
     22  1.1  christos 
     23  1.1  christos #include <errno.h>
     24  1.1  christos #ifndef __set_errno
     25  1.1  christos # define __set_errno(ev) ((errno) = (ev))
     26  1.1  christos #endif
     27  1.1  christos 
     28  1.1  christos #include <stdlib.h>
     29  1.1  christos #include <string.h>
     30  1.1  christos #if _LIBC || HAVE_UNISTD_H
     31  1.1  christos # include <unistd.h>
     32  1.1  christos #endif
     33  1.1  christos 
     34  1.1  christos #if !_LIBC
     35  1.1  christos # include "allocsa.h"
     36  1.1  christos #endif
     37  1.1  christos 
     38  1.1  christos #if !_LIBC
     39  1.1  christos # define __environ	environ
     40  1.1  christos # ifndef HAVE_ENVIRON_DECL
     41  1.1  christos extern char **environ;
     42  1.1  christos # endif
     43  1.1  christos #endif
     44  1.1  christos 
     45  1.1  christos #if _LIBC
     46  1.1  christos /* This lock protects against simultaneous modifications of `environ'.  */
     47  1.1  christos # include <bits/libc-lock.h>
     48  1.1  christos __libc_lock_define_initialized (static, envlock)
     49  1.1  christos # define LOCK	__libc_lock_lock (envlock)
     50  1.1  christos # define UNLOCK	__libc_lock_unlock (envlock)
     51  1.1  christos #else
     52  1.1  christos # define LOCK
     53  1.1  christos # define UNLOCK
     54  1.1  christos #endif
     55  1.1  christos 
     56  1.1  christos /* In the GNU C library we must keep the namespace clean.  */
     57  1.1  christos #ifdef _LIBC
     58  1.1  christos # define setenv __setenv
     59  1.1  christos # define clearenv __clearenv
     60  1.1  christos # define tfind __tfind
     61  1.1  christos # define tsearch __tsearch
     62  1.1  christos #endif
     63  1.1  christos 
     64  1.1  christos /* In the GNU C library implementation we try to be more clever and
     65  1.1  christos    allow arbitrarily many changes of the environment given that the used
     66  1.1  christos    values are from a small set.  Outside glibc this will eat up all
     67  1.1  christos    memory after a while.  */
     68  1.1  christos #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
     69  1.1  christos 		      && defined __GNUC__)
     70  1.1  christos # define USE_TSEARCH	1
     71  1.1  christos # include <search.h>
     72  1.1  christos typedef int (*compar_fn_t) (const void *, const void *);
     73  1.1  christos 
     74  1.1  christos /* This is a pointer to the root of the search tree with the known
     75  1.1  christos    values.  */
     76  1.1  christos static void *known_values;
     77  1.1  christos 
     78  1.1  christos # define KNOWN_VALUE(Str) \
     79  1.1  christos   ({									      \
     80  1.1  christos     void *value = tfind (Str, &known_values, (compar_fn_t) strcmp);	      \
     81  1.1  christos     value != NULL ? *(char **) value : NULL;				      \
     82  1.1  christos   })
     83  1.1  christos # define STORE_VALUE(Str) \
     84  1.1  christos   tsearch (Str, &known_values, (compar_fn_t) strcmp)
     85  1.1  christos 
     86  1.1  christos #else
     87  1.1  christos # undef USE_TSEARCH
     88  1.1  christos 
     89  1.1  christos # define KNOWN_VALUE(Str) NULL
     90  1.1  christos # define STORE_VALUE(Str) do { } while (0)
     91  1.1  christos 
     92  1.1  christos #endif
     93  1.1  christos 
     94  1.1  christos 
     95  1.1  christos /* If this variable is not a null pointer we allocated the current
     96  1.1  christos    environment.  */
     97  1.1  christos static char **last_environ;
     98  1.1  christos 
     99  1.1  christos 
    100  1.1  christos /* This function is used by `setenv' and `putenv'.  The difference between
    101  1.1  christos    the two functions is that for the former must create a new string which
    102  1.1  christos    is then placed in the environment, while the argument of `putenv'
    103  1.1  christos    must be used directly.  This is all complicated by the fact that we try
    104  1.1  christos    to reuse values once generated for a `setenv' call since we can never
    105  1.1  christos    free the strings.  */
    106  1.1  christos int
    107  1.1  christos __add_to_environ (const char *name, const char *value, const char *combined,
    108  1.1  christos 		  int replace)
    109  1.1  christos {
    110  1.1  christos   register char **ep;
    111  1.1  christos   register size_t size;
    112  1.1  christos   const size_t namelen = strlen (name);
    113  1.1  christos   const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
    114  1.1  christos 
    115  1.1  christos   LOCK;
    116  1.1  christos 
    117  1.1  christos   /* We have to get the pointer now that we have the lock and not earlier
    118  1.1  christos      since another thread might have created a new environment.  */
    119  1.1  christos   ep = __environ;
    120  1.1  christos 
    121  1.1  christos   size = 0;
    122  1.1  christos   if (ep != NULL)
    123  1.1  christos     {
    124  1.1  christos       for (; *ep != NULL; ++ep)
    125  1.1  christos 	if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
    126  1.1  christos 	  break;
    127  1.1  christos 	else
    128  1.1  christos 	  ++size;
    129  1.1  christos     }
    130  1.1  christos 
    131  1.1  christos   if (ep == NULL || *ep == NULL)
    132  1.1  christos     {
    133  1.1  christos       char **new_environ;
    134  1.1  christos #ifdef USE_TSEARCH
    135  1.1  christos       char *new_value;
    136  1.1  christos #endif
    137  1.1  christos 
    138  1.1  christos       /* We allocated this space; we can extend it.  */
    139  1.1  christos       new_environ =
    140  1.1  christos 	(char **) (last_environ == NULL
    141  1.1  christos 		   ? malloc ((size + 2) * sizeof (char *))
    142  1.1  christos 		   : realloc (last_environ, (size + 2) * sizeof (char *)));
    143  1.1  christos       if (new_environ == NULL)
    144  1.1  christos 	{
    145  1.1  christos 	  UNLOCK;
    146  1.1  christos 	  return -1;
    147  1.1  christos 	}
    148  1.1  christos 
    149  1.1  christos       /* If the whole entry is given add it.  */
    150  1.1  christos       if (combined != NULL)
    151  1.1  christos 	/* We must not add the string to the search tree since it belongs
    152  1.1  christos 	   to the user.  */
    153  1.1  christos 	new_environ[size] = (char *) combined;
    154  1.1  christos       else
    155  1.1  christos 	{
    156  1.1  christos 	  /* See whether the value is already known.  */
    157  1.1  christos #ifdef USE_TSEARCH
    158  1.1  christos # ifdef _LIBC
    159  1.1  christos 	  new_value = (char *) alloca (namelen + 1 + vallen);
    160  1.1  christos 	  __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
    161  1.1  christos 		     value, vallen);
    162  1.1  christos # else
    163  1.1  christos 	  new_value = (char *) allocsa (namelen + 1 + vallen);
    164  1.1  christos 	  if (new_value == NULL)
    165  1.1  christos 	    {
    166  1.1  christos 	      __set_errno (ENOMEM);
    167  1.1  christos 	      UNLOCK;
    168  1.1  christos 	      return -1;
    169  1.1  christos 	    }
    170  1.1  christos 	  memcpy (new_value, name, namelen);
    171  1.1  christos 	  new_value[namelen] = '=';
    172  1.1  christos 	  memcpy (&new_value[namelen + 1], value, vallen);
    173  1.1  christos # endif
    174  1.1  christos 
    175  1.1  christos 	  new_environ[size] = KNOWN_VALUE (new_value);
    176  1.1  christos 	  if (new_environ[size] == NULL)
    177  1.1  christos #endif
    178  1.1  christos 	    {
    179  1.1  christos 	      new_environ[size] = (char *) malloc (namelen + 1 + vallen);
    180  1.1  christos 	      if (new_environ[size] == NULL)
    181  1.1  christos 		{
    182  1.1  christos #if defined USE_TSEARCH && !defined _LIBC
    183  1.1  christos 		  freesa (new_value);
    184  1.1  christos #endif
    185  1.1  christos 		  __set_errno (ENOMEM);
    186  1.1  christos 		  UNLOCK;
    187  1.1  christos 		  return -1;
    188  1.1  christos 		}
    189  1.1  christos 
    190  1.1  christos #ifdef USE_TSEARCH
    191  1.1  christos 	      memcpy (new_environ[size], new_value, namelen + 1 + vallen);
    192  1.1  christos #else
    193  1.1  christos 	      memcpy (new_environ[size], name, namelen);
    194  1.1  christos 	      new_environ[size][namelen] = '=';
    195  1.1  christos 	      memcpy (&new_environ[size][namelen + 1], value, vallen);
    196  1.1  christos #endif
    197  1.1  christos 	      /* And save the value now.  We cannot do this when we remove
    198  1.1  christos 		 the string since then we cannot decide whether it is a
    199  1.1  christos 		 user string or not.  */
    200  1.1  christos 	      STORE_VALUE (new_environ[size]);
    201  1.1  christos 	    }
    202  1.1  christos #if defined USE_TSEARCH && !defined _LIBC
    203  1.1  christos 	  freesa (new_value);
    204  1.1  christos #endif
    205  1.1  christos 	}
    206  1.1  christos 
    207  1.1  christos       if (__environ != last_environ)
    208  1.1  christos 	memcpy ((char *) new_environ, (char *) __environ,
    209  1.1  christos 		size * sizeof (char *));
    210  1.1  christos 
    211  1.1  christos       new_environ[size + 1] = NULL;
    212  1.1  christos 
    213  1.1  christos       last_environ = __environ = new_environ;
    214  1.1  christos     }
    215  1.1  christos   else if (replace)
    216  1.1  christos     {
    217  1.1  christos       char *np;
    218  1.1  christos 
    219  1.1  christos       /* Use the user string if given.  */
    220  1.1  christos       if (combined != NULL)
    221  1.1  christos 	np = (char *) combined;
    222  1.1  christos       else
    223  1.1  christos 	{
    224  1.1  christos #ifdef USE_TSEARCH
    225  1.1  christos 	  char *new_value;
    226  1.1  christos # ifdef _LIBC
    227  1.1  christos 	  new_value = alloca (namelen + 1 + vallen);
    228  1.1  christos 	  __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
    229  1.1  christos 		     value, vallen);
    230  1.1  christos # else
    231  1.1  christos 	  new_value = allocsa (namelen + 1 + vallen);
    232  1.1  christos 	  if (new_value == NULL)
    233  1.1  christos 	    {
    234  1.1  christos 	      __set_errno (ENOMEM);
    235  1.1  christos 	      UNLOCK;
    236  1.1  christos 	      return -1;
    237  1.1  christos 	    }
    238  1.1  christos 	  memcpy (new_value, name, namelen);
    239  1.1  christos 	  new_value[namelen] = '=';
    240  1.1  christos 	  memcpy (&new_value[namelen + 1], value, vallen);
    241  1.1  christos # endif
    242  1.1  christos 
    243  1.1  christos 	  np = KNOWN_VALUE (new_value);
    244  1.1  christos 	  if (np == NULL)
    245  1.1  christos #endif
    246  1.1  christos 	    {
    247  1.1  christos 	      np = malloc (namelen + 1 + vallen);
    248  1.1  christos 	      if (np == NULL)
    249  1.1  christos 		{
    250  1.1  christos #if defined USE_TSEARCH && !defined _LIBC
    251  1.1  christos 		  freesa (new_value);
    252  1.1  christos #endif
    253  1.1  christos 		  __set_errno (ENOMEM);
    254  1.1  christos 		  UNLOCK;
    255  1.1  christos 		  return -1;
    256  1.1  christos 		}
    257  1.1  christos 
    258  1.1  christos #ifdef USE_TSEARCH
    259  1.1  christos 	      memcpy (np, new_value, namelen + 1 + vallen);
    260  1.1  christos #else
    261  1.1  christos 	      memcpy (np, name, namelen);
    262  1.1  christos 	      np[namelen] = '=';
    263  1.1  christos 	      memcpy (&np[namelen + 1], value, vallen);
    264  1.1  christos #endif
    265  1.1  christos 	      /* And remember the value.  */
    266  1.1  christos 	      STORE_VALUE (np);
    267  1.1  christos 	    }
    268  1.1  christos #if defined USE_TSEARCH && !defined _LIBC
    269  1.1  christos 	  freesa (new_value);
    270  1.1  christos #endif
    271  1.1  christos 	}
    272  1.1  christos 
    273  1.1  christos       *ep = np;
    274  1.1  christos     }
    275  1.1  christos 
    276  1.1  christos   UNLOCK;
    277  1.1  christos 
    278  1.1  christos   return 0;
    279  1.1  christos }
    280  1.1  christos 
    281  1.1  christos int
    282  1.1  christos setenv (const char *name, const char *value, int replace)
    283  1.1  christos {
    284  1.1  christos   return __add_to_environ (name, value, NULL, replace);
    285  1.1  christos }
    286  1.1  christos 
    287  1.1  christos /* The `clearenv' was planned to be added to POSIX.1 but probably
    288  1.1  christos    never made it.  Nevertheless the POSIX.9 standard (POSIX bindings
    289  1.1  christos    for Fortran 77) requires this function.  */
    290  1.1  christos int
    291  1.1  christos clearenv (void)
    292  1.1  christos {
    293  1.1  christos   LOCK;
    294  1.1  christos 
    295  1.1  christos   if (__environ == last_environ && __environ != NULL)
    296  1.1  christos     {
    297  1.1  christos       /* We allocated this environment so we can free it.  */
    298  1.1  christos       free (__environ);
    299  1.1  christos       last_environ = NULL;
    300  1.1  christos     }
    301  1.1  christos 
    302  1.1  christos   /* Clear the environment pointer removes the whole environment.  */
    303  1.1  christos   __environ = NULL;
    304  1.1  christos 
    305  1.1  christos   UNLOCK;
    306  1.1  christos 
    307  1.1  christos   return 0;
    308  1.1  christos }
    309  1.1  christos 
    310  1.1  christos #ifdef _LIBC
    311  1.1  christos static void
    312  1.1  christos free_mem (void)
    313  1.1  christos {
    314  1.1  christos   /* Remove all traces.  */
    315  1.1  christos   clearenv ();
    316  1.1  christos 
    317  1.1  christos   /* Now remove the search tree.  */
    318  1.1  christos   __tdestroy (known_values, free);
    319  1.1  christos   known_values = NULL;
    320  1.1  christos }
    321  1.1  christos text_set_element (__libc_subfreeres, free_mem);
    322  1.1  christos 
    323  1.1  christos 
    324  1.1  christos # undef setenv
    325  1.1  christos # undef clearenv
    326  1.1  christos weak_alias (__setenv, setenv)
    327  1.1  christos weak_alias (__clearenv, clearenv)
    328  1.1  christos #endif
    329