changeset 4364:842bd108d7f6

Merge from coreutils. This avoids a core dump on systems without GNU putenv, when running `env -u SOME_ALREADY_UNSET_VARIABLE'. (__set_errno, LOCK, UNLOCK): Define. (unsetenv): New static function, from GNU libc. (rpl_putenv): Use it.
author Jim Meyering <jim@meyering.net>
date Fri, 06 Jun 2003 20:50:35 +0000
parents 04e1f040287d
children a169895d3bfd
files lib/putenv.c
diffstat 1 files changed, 58 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/lib/putenv.c
+++ b/lib/putenv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1994, 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
 
    NOTE: The canonical source of this file is maintained with the GNU C
    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
@@ -26,6 +26,12 @@
 /* Include errno.h *after* sys/types.h to work around header problems
    on AIX 3.2.5.  */
 #include <errno.h>
+#if !_LIBC
+# if !defined errno
+extern int errno;
+# endif
+# define __set_errno(ev) ((errno) = (ev))
+#endif
 
 /* Don't include stdlib.h because some (e.g., Solaris 2.7) declare putenv
    with a non-const argument.  That would conflict with the declaration of
@@ -54,12 +60,60 @@
 extern char **environ;
 #endif
 
+#if _LIBC
+/* This lock protects against simultaneous modifications of `environ'.  */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK	__libc_lock_lock (envlock)
+# define UNLOCK	__libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
 #ifndef NULL
 # define NULL 0
 #endif
 
+static int
+unsetenv (const char *name)
+{
+  size_t len;
+  char **ep;
 
-/* Put STRING, which is of the form "NAME=VALUE", in the environment.  */
+  if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  len = strlen (name);
+
+  LOCK;
+
+  ep = environ;
+  while (*ep != NULL)
+    if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
+      {
+	/* Found it.  Remove this pointer by moving later ones back.  */
+	char **dp = ep;
+
+	do
+	  dp[0] = dp[1];
+	while (*dp++);
+	/* Continue the loop in case NAME appears again.  */
+      }
+    else
+      ++ep;
+
+  UNLOCK;
+
+  return 0;
+}
+
+
+/* Put STRING, which is of the form "NAME=VALUE", in the environment.
+   If STRING contains no `=', then remove STRING from the environment.  */
 int
 rpl_putenv (const char *string)
 {
@@ -70,18 +124,7 @@
   if (name_end == NULL)
     {
       /* Remove the variable from the environment.  */
-      size = strlen (string);
-      for (ep = environ; *ep != NULL; ++ep)
-	if (!strncmp (*ep, string, size) && (*ep)[size] == '=')
-	  {
-	    while (ep[1] != NULL)
-	      {
-		ep[0] = ep[1];
-		++ep;
-	      }
-	    *ep = NULL;
-	    return 0;
-	  }
+      return unsetenv (string);
     }
 
   size = 0;
@@ -103,7 +146,7 @@
       new_environ[size] = (char *) string;
       new_environ[size + 1] = NULL;
       if (last_environ != NULL)
-	free ((void *) last_environ);
+	free (last_environ);
       last_environ = new_environ;
       environ = new_environ;
     }