summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2009-06-03 15:52:17 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2009-06-03 15:52:17 +0000
commitc50bef089a8be3e801d4e39b60f48add63b4d3b9 (patch)
tree756f0752a6ad9087fbc495e167a409a17cb5ef7f
parent86ac841d75093dc6c6c71fd00d7ef9e2692a7e7e (diff)
Make putenv(), setenv() and unsetenv() standards compliant. The
standard explicitly disallows passing setenv a name with a '=' in it but historic BSD behavior is to allow this but to ignore the '=' and anything after it.
-rw-r--r--include/stdlib.h6
-rw-r--r--lib/libc/stdlib/Makefile.inc4
-rw-r--r--lib/libc/stdlib/getenv.354
-rw-r--r--lib/libc/stdlib/getenv.c16
-rw-r--r--lib/libc/stdlib/putenv.c50
-rw-r--r--lib/libc/stdlib/setenv.c79
6 files changed, 120 insertions, 89 deletions
diff --git a/include/stdlib.h b/include/stdlib.h
index 496090a50db..840d381aa1f 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: stdlib.h,v 1.45 2008/09/07 20:36:07 martynas Exp $ */
+/* $OpenBSD: stdlib.h,v 1.46 2009/06/03 15:52:16 millert Exp $ */
/* $NetBSD: stdlib.h,v 1.25 1995/12/27 21:19:08 jtc Exp $ */
/*-
@@ -164,7 +164,7 @@ long nrand48(unsigned short[3]);
unsigned short *seed48(unsigned short[3]);
void srand48(long);
-int putenv(const char *);
+int putenv(char *);
#endif
#if __BSD_VISIBLE || __XPG_VISIBLE >= 420
@@ -210,7 +210,7 @@ unsigned long long
*/
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XPG_VISIBLE >= 600
int setenv(const char *, const char *, int);
-void unsetenv(const char *);
+int unsetenv(const char *);
#endif
#if __BSD_VISIBLE
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index c149aeef0a1..3b9b36a1ed8 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile.inc,v 1.41 2008/09/13 22:48:45 martynas Exp $
+# $OpenBSD: Makefile.inc,v 1.42 2009/06/03 15:52:16 millert Exp $
# stdlib sources
.PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/stdlib ${LIBCSRCDIR}/stdlib
@@ -6,7 +6,7 @@
SRCS+= a64l.c abort.c atexit.c atoi.c atof.c atol.c atoll.c bsearch.c \
cfree.c exit.c ecvt.c gcvt.c getenv.c getopt_long.c \
getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c l64a.c llabs.c \
- lldiv.c lsearch.c malloc.c merge.c putenv.c qsort.c radixsort.c rand.c \
+ lldiv.c lsearch.c malloc.c merge.c qsort.c radixsort.c rand.c \
random.c realpath.c setenv.c strtoimax.c strtol.c \
strtoll.c strtonum.c strtoul.c strtoull.c strtoumax.c system.c \
tfind.c tsearch.c _rand48.c drand48.c erand48.c jrand48.c lcong48.c \
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
index 1d8546997f4..484ff991dc1 100644
--- a/lib/libc/stdlib/getenv.3
+++ b/lib/libc/stdlib/getenv.3
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $OpenBSD: getenv.3,v 1.12 2007/05/31 19:19:31 jmc Exp $
+.\" $OpenBSD: getenv.3,v 1.13 2009/06/03 15:52:16 millert Exp $
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: June 3 2009 $
.Dt GETENV 3
.Os
.Sh NAME
@@ -47,8 +47,8 @@
.Ft int
.Fn setenv "const char *name" "const char *value" "int overwrite"
.Ft int
-.Fn putenv "const char *string"
-.Ft void
+.Fn putenv "char *string"
+.Ft int
.Fn unsetenv "const char *name"
.Sh DESCRIPTION
These functions set, unset, and fetch environment variables from the host
@@ -87,11 +87,20 @@ is zero, the variable is not reset, otherwise it is reset to the given
The
.Fn putenv
function takes an argument of the form
-.Ar name Ns = Ns Ar value
-and is equivalent to:
-.Bd -literal -offset indent
-setenv(name, value, 1);
-.Ed
+.Ar name Ns = Ns Ar value .
+The memory pointed to by
+.Ar string
+becomes part of the environment and must not be deallocated by the caller.
+If the variable already exists, it will be overwritten.
+A common source of bugs is to pass a
+.Ar string
+argument that is a locally scoped string buffer.
+This will result in corruption of the environment after leaving
+the scope in which the variable is defined.
+For this reason, the
+.Fn setenv
+function is preferred over
+.Fn putenv .
.Pp
The
.Fn unsetenv
@@ -99,10 +108,7 @@ function deletes all instances of the variable name pointed to by
.Fa name
from the list.
.Sh RETURN VALUES
-The functions
-.Fn setenv
-and
-.Fn putenv
+These functions
return zero if successful; otherwise the global variable
.Va errno
is set to indicate the error and \-1 is returned.
@@ -112,12 +118,30 @@ If
is successful, the string returned should be considered read-only.
.Sh ERRORS
.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fn setenv
+or
+.Fn putenv
+function was passed a
+.Ar name
+containing an
+.Sq =
+character.
+.Pp
+The
+.Fn putenv
+function was passed a
+.Ar string
+that did not contain an
+.Sq =
+character.
.It Bq Er ENOMEM
-The function
+The
.Fn setenv
or
.Fn putenv
-failed because they were unable to allocate memory for the environment.
+function failed because it was unable to allocate memory for the environment.
.El
.Sh SEE ALSO
.Xr csh 1 ,
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index 72367b34e27..5aff11c61ac 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: getenv.c,v 1.8 2005/08/08 08:05:36 espie Exp $ */
+/* $OpenBSD: getenv.c,v 1.9 2009/06/03 15:52:16 millert Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
@@ -31,7 +31,7 @@
#include <stdlib.h>
#include <string.h>
-char *__findenv(const char *name, int *offset);
+char *__findenv(const char *name, int len, int *offset);
/*
* __findenv --
@@ -43,18 +43,15 @@ char *__findenv(const char *name, int *offset);
* This routine *should* be a static; don't use it.
*/
char *
-__findenv(const char *name, int *offset)
+__findenv(const char *name, int len, int *offset)
{
extern char **environ;
- int len, i;
+ int i;
const char *np;
char **p, *cp;
if (name == NULL || environ == NULL)
return (NULL);
- for (np = name; *np && *np != '='; ++np)
- ;
- len = np - name;
for (p = environ; (cp = *p) != NULL; ++p) {
for (np = name, i = len; i && *cp; i--)
if (*cp++ != *np++)
@@ -75,6 +72,9 @@ char *
getenv(const char *name)
{
int offset;
+ const char *np;
- return (__findenv(name, &offset));
+ for (np = name; *np && *np != '='; ++np)
+ ;
+ return (__findenv(name, (int)(np - name), &offset));
}
diff --git a/lib/libc/stdlib/putenv.c b/lib/libc/stdlib/putenv.c
deleted file mode 100644
index 54482f6a144..00000000000
--- a/lib/libc/stdlib/putenv.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* $OpenBSD: putenv.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
-/*-
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-int
-putenv(const char *str)
-{
- char *p, *equal;
- int rval;
-
- if ((p = strdup(str)) == NULL)
- return (-1);
- if ((equal = strchr(p, '=')) == NULL) {
- (void)free(p);
- return (-1);
- }
- *equal = '\0';
- rval = setenv(p, equal + 1, 1);
- (void)free(p);
- return (rval);
-}
diff --git a/lib/libc/stdlib/setenv.c b/lib/libc/stdlib/setenv.c
index 36540ebb0c8..242830d7b9a 100644
--- a/lib/libc/stdlib/setenv.c
+++ b/lib/libc/stdlib/setenv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: setenv.c,v 1.9 2005/08/08 08:05:37 espie Exp $ */
+/* $OpenBSD: setenv.c,v 1.10 2009/06/03 15:52:16 millert Exp $ */
/*
* Copyright (c) 1987 Regents of the University of California.
* All rights reserved.
@@ -28,12 +28,53 @@
* SUCH DAMAGE.
*/
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
-char *__findenv(const char *name, int *offset);
+char *__findenv(const char *name, int len, int *offset);
extern char **environ;
+static char **lastenv; /* last value of environ */
+
+/*
+ * putenv --
+ * Add a name=value string directly to the environmental, replacing
+ * any current value.
+ */
+int
+putenv(char *str)
+{
+ char **P, *cp;
+ size_t cnt;
+ int offset;
+
+ for (cp = str; *cp && *cp != '='; ++cp)
+ ;
+ if (*cp != '=') {
+ errno = EINVAL;
+ return (-1); /* missing `=' in string */
+ }
+
+ if (__findenv(str, (int)(cp - str), &offset) != NULL) {
+ environ[offset] = str;
+ return (0);
+ }
+
+ /* create new slot for string */
+ for (P = environ; *P != NULL; P++)
+ ;
+ cnt = P - environ;
+ P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
+ if (!P)
+ return (-1);
+ if (lastenv != environ)
+ memcpy(P, environ, cnt * sizeof(char *));
+ lastenv = environ = P;
+ environ[cnt] = str;
+ environ[cnt + 1] = NULL;
+ return (0);
+}
/*
* setenv --
@@ -43,14 +84,21 @@ extern char **environ;
int
setenv(const char *name, const char *value, int rewrite)
{
- static char **lastenv; /* last value of environ */
char *C;
+ const char *np;
int l_value, offset;
- if (*value == '=') /* no `=' in value */
- ++value;
+ for (np = name; *np && *np != '='; ++np)
+ ;
+#ifdef notyet
+ if (*np) {
+ errno = EINVAL;
+ return (-1); /* has `=' in name */
+ }
+#endif
+
l_value = strlen(value);
- if ((C = __findenv(name, &offset))) { /* find if already exists */
+ if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) {
if (!rewrite)
return (0);
if (strlen(C) >= l_value) { /* old larger; copy over */
@@ -74,10 +122,8 @@ setenv(const char *name, const char *value, int rewrite)
offset = cnt;
environ[cnt + 1] = NULL;
}
- for (C = (char *)name; *C && *C != '='; ++C)
- ; /* no `=' in name */
if (!(environ[offset] = /* name + `=' + value */
- malloc((size_t)((int)(C - name) + l_value + 2))))
+ malloc((size_t)((int)(np - name) + l_value + 2))))
return (-1);
for (C = environ[offset]; (*C = *name++) && *C != '='; ++C)
;
@@ -90,14 +136,25 @@ setenv(const char *name, const char *value, int rewrite)
* unsetenv(name) --
* Delete environmental variable "name".
*/
-void
+int
unsetenv(const char *name)
{
char **P;
+ const char *np;
int offset;
- while (__findenv(name, &offset)) /* if set multiple times */
+ for (np = name; *np && *np != '='; ++np)
+ ;
+ if (*np) {
+ errno = EINVAL;
+ return (-1); /* has `=' in name */
+ }
+
+ /* could be set multiple times */
+ while (__findenv(name, (int)(np - name), &offset)) {
for (P = &environ[offset];; ++P)
if (!(*P = *(P + 1)))
break;
+ }
+ return (0);
}