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