diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2009-06-03 15:52:17 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2009-06-03 15:52:17 +0000 |
commit | c50bef089a8be3e801d4e39b60f48add63b4d3b9 (patch) | |
tree | 756f0752a6ad9087fbc495e167a409a17cb5ef7f /lib/libc/stdlib | |
parent | 86ac841d75093dc6c6c71fd00d7ef9e2692a7e7e (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.
Diffstat (limited to 'lib/libc/stdlib')
-rw-r--r-- | lib/libc/stdlib/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/libc/stdlib/getenv.3 | 54 | ||||
-rw-r--r-- | lib/libc/stdlib/getenv.c | 16 | ||||
-rw-r--r-- | lib/libc/stdlib/putenv.c | 50 | ||||
-rw-r--r-- | lib/libc/stdlib/setenv.c | 79 |
5 files changed, 117 insertions, 86 deletions
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); } |