xref: /openbsd-src/gnu/lib/libiberty/src/setenv.c (revision 150b7e42cfa21e6546d96ae514ca23e80d970ac7)
137c53322Sespie /* Copyright (C) 1992, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
200bf4279Sespie    This file based on setenv.c in the GNU C Library.
300bf4279Sespie 
400bf4279Sespie    The GNU C Library is free software; you can redistribute it and/or
500bf4279Sespie    modify it under the terms of the GNU Library General Public License as
600bf4279Sespie    published by the Free Software Foundation; either version 2 of the
700bf4279Sespie    License, or (at your option) any later version.
800bf4279Sespie 
900bf4279Sespie    The GNU C Library is distributed in the hope that it will be useful,
1000bf4279Sespie    but WITHOUT ANY WARRANTY; without even the implied warranty of
1100bf4279Sespie    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1200bf4279Sespie    Library General Public License for more details.
1300bf4279Sespie 
1400bf4279Sespie    You should have received a copy of the GNU Library General Public
1500bf4279Sespie    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16*150b7e42Smiod    write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
17*150b7e42Smiod    Boston, MA 02110-1301, USA.  */
1800bf4279Sespie 
1937c53322Sespie 
2037c53322Sespie /*
2137c53322Sespie 
2237c53322Sespie @deftypefn Supplemental int setenv (const char *@var{name}, const char *@var{value}, int @var{overwrite})
2337c53322Sespie @deftypefnx Supplemental void unsetenv (const char *@var{name})
2437c53322Sespie 
2537c53322Sespie @code{setenv} adds @var{name} to the environment with value
2637c53322Sespie @var{value}.  If the name was already present in the environment,
2737c53322Sespie the new value will be stored only if @var{overwrite} is nonzero.
2837c53322Sespie The companion @code{unsetenv} function removes @var{name} from the
2937c53322Sespie environment.  This implementation is not safe for multithreaded code.
3037c53322Sespie 
3137c53322Sespie @end deftypefn
3237c53322Sespie 
3337c53322Sespie */
3437c53322Sespie 
3500bf4279Sespie #if HAVE_CONFIG_H
3600bf4279Sespie # include <config.h>
3700bf4279Sespie #endif
3800bf4279Sespie 
3937c53322Sespie #define setenv libiberty_setenv
4037c53322Sespie #define unsetenv libiberty_unsetenv
4137c53322Sespie 
4200bf4279Sespie #include "ansidecl.h"
4300bf4279Sespie #include <sys/types.h> /* For `size_t' */
4400bf4279Sespie #include <stdio.h>     /* For `NULL' */
4500bf4279Sespie 
4600bf4279Sespie #include <errno.h>
4700bf4279Sespie #if !defined(errno) && !defined(HAVE_ERRNO_DECL)
4800bf4279Sespie extern int errno;
4900bf4279Sespie #endif
5000bf4279Sespie #define __set_errno(ev) ((errno) = (ev))
5100bf4279Sespie 
5200bf4279Sespie #if HAVE_STDLIB_H
5300bf4279Sespie # include <stdlib.h>
5400bf4279Sespie #endif
5500bf4279Sespie #if HAVE_STRING_H
5600bf4279Sespie # include <string.h>
5700bf4279Sespie #endif
5800bf4279Sespie #if HAVE_UNISTD_H
5900bf4279Sespie # include <unistd.h>
6000bf4279Sespie #endif
6100bf4279Sespie 
6200bf4279Sespie #define __environ	environ
6300bf4279Sespie #ifndef HAVE_ENVIRON_DECL
6400bf4279Sespie extern char **environ;
6500bf4279Sespie #endif
6600bf4279Sespie 
6737c53322Sespie #undef setenv
6837c53322Sespie #undef unsetenv
6937c53322Sespie 
7000bf4279Sespie /* LOCK and UNLOCK are defined as no-ops.  This makes the libiberty
7100bf4279Sespie  * implementation MT-Unsafe. */
7200bf4279Sespie #define LOCK
7300bf4279Sespie #define UNLOCK
7400bf4279Sespie 
7500bf4279Sespie /* Below this point, it's verbatim code from the glibc-2.0 implementation */
7600bf4279Sespie 
7700bf4279Sespie /* If this variable is not a null pointer we allocated the current
7800bf4279Sespie    environment.  */
7900bf4279Sespie static char **last_environ;
8000bf4279Sespie 
8100bf4279Sespie 
8200bf4279Sespie int
setenv(const char * name,const char * value,int replace)83*150b7e42Smiod setenv (const char *name, const char *value, int replace)
8400bf4279Sespie {
85f5dd06f4Sespie   register char **ep = 0;
8600bf4279Sespie   register size_t size;
8700bf4279Sespie   const size_t namelen = strlen (name);
8800bf4279Sespie   const size_t vallen = strlen (value) + 1;
8900bf4279Sespie 
9000bf4279Sespie   LOCK;
9100bf4279Sespie 
9200bf4279Sespie   size = 0;
9300bf4279Sespie   if (__environ != NULL)
94f5dd06f4Sespie     {
9500bf4279Sespie       for (ep = __environ; *ep != NULL; ++ep)
9600bf4279Sespie 	if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
9700bf4279Sespie 	  break;
9800bf4279Sespie 	else
9900bf4279Sespie 	  ++size;
100f5dd06f4Sespie     }
10100bf4279Sespie 
10200bf4279Sespie   if (__environ == NULL || *ep == NULL)
10300bf4279Sespie     {
10400bf4279Sespie       char **new_environ;
10500bf4279Sespie       if (__environ == last_environ && __environ != NULL)
10600bf4279Sespie 	/* We allocated this space; we can extend it.  */
10700bf4279Sespie 	new_environ = (char **) realloc (last_environ,
10800bf4279Sespie 					 (size + 2) * sizeof (char *));
10900bf4279Sespie       else
11000bf4279Sespie 	new_environ = (char **) malloc ((size + 2) * sizeof (char *));
11100bf4279Sespie 
11200bf4279Sespie       if (new_environ == NULL)
11300bf4279Sespie 	{
11400bf4279Sespie 	  UNLOCK;
11500bf4279Sespie 	  return -1;
11600bf4279Sespie 	}
11700bf4279Sespie 
118*150b7e42Smiod       new_environ[size] = (char *) malloc (namelen + 1 + vallen);
11900bf4279Sespie       if (new_environ[size] == NULL)
12000bf4279Sespie 	{
12100bf4279Sespie 	  free ((char *) new_environ);
12200bf4279Sespie 	  __set_errno (ENOMEM);
12300bf4279Sespie 	  UNLOCK;
12400bf4279Sespie 	  return -1;
12500bf4279Sespie 	}
12600bf4279Sespie 
12700bf4279Sespie       if (__environ != last_environ)
12800bf4279Sespie 	memcpy ((char *) new_environ, (char *) __environ,
12900bf4279Sespie 		size * sizeof (char *));
13000bf4279Sespie 
13100bf4279Sespie       memcpy (new_environ[size], name, namelen);
13200bf4279Sespie       new_environ[size][namelen] = '=';
13300bf4279Sespie       memcpy (&new_environ[size][namelen + 1], value, vallen);
13400bf4279Sespie 
13500bf4279Sespie       new_environ[size + 1] = NULL;
13600bf4279Sespie 
13700bf4279Sespie       last_environ = __environ = new_environ;
13800bf4279Sespie     }
13900bf4279Sespie   else if (replace)
14000bf4279Sespie     {
14100bf4279Sespie       size_t len = strlen (*ep);
14200bf4279Sespie       if (len + 1 < namelen + 1 + vallen)
14300bf4279Sespie 	{
14400bf4279Sespie 	  /* The existing string is too short; malloc a new one.  */
145*150b7e42Smiod 	  char *new_string = (char *) malloc (namelen + 1 + vallen);
146*150b7e42Smiod 	  if (new_string == NULL)
14700bf4279Sespie 	    {
14800bf4279Sespie 	      UNLOCK;
14900bf4279Sespie 	      return -1;
15000bf4279Sespie 	    }
151*150b7e42Smiod 	  *ep = new_string;
15200bf4279Sespie 	}
15300bf4279Sespie       memcpy (*ep, name, namelen);
15400bf4279Sespie       (*ep)[namelen] = '=';
15500bf4279Sespie       memcpy (&(*ep)[namelen + 1], value, vallen);
15600bf4279Sespie     }
15700bf4279Sespie 
15800bf4279Sespie   UNLOCK;
15900bf4279Sespie 
16000bf4279Sespie   return 0;
16100bf4279Sespie }
16200bf4279Sespie 
16300bf4279Sespie void
unsetenv(const char * name)164*150b7e42Smiod unsetenv (const char *name)
16500bf4279Sespie {
16600bf4279Sespie   const size_t len = strlen (name);
16700bf4279Sespie   char **ep;
16800bf4279Sespie 
16900bf4279Sespie   LOCK;
17000bf4279Sespie 
17100bf4279Sespie   for (ep = __environ; *ep; ++ep)
17200bf4279Sespie     if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
17300bf4279Sespie       {
17400bf4279Sespie 	/* Found it.  Remove this pointer by moving later ones back.  */
17500bf4279Sespie 	char **dp = ep;
17600bf4279Sespie 	do
17700bf4279Sespie 	  dp[0] = dp[1];
17800bf4279Sespie 	while (*dp++);
17900bf4279Sespie 	/* Continue the loop in case NAME appears again.  */
18000bf4279Sespie       }
18100bf4279Sespie 
18200bf4279Sespie   UNLOCK;
18300bf4279Sespie }
184