summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/df/df.c8
-rw-r--r--bin/sh/var.c16
-rw-r--r--include/stdlib.h4
-rw-r--r--lib/libc/stdlib/Makefile.inc8
-rw-r--r--lib/libc/stdlib/getenv.3104
-rw-r--r--lib/libc/stdlib/getenv.c597
-rw-r--r--lib/libc/stdlib/putenv.c56
-rw-r--r--lib/libc/stdlib/setenv.c116
-rw-r--r--libexec/pppoed/pppoed.c8
-rw-r--r--sys/sys/param.h2
-rw-r--r--tools/regression/environ/Makefile14
-rw-r--r--tools/regression/environ/Makefile.envctl16
-rw-r--r--tools/regression/environ/Makefile.retention16
-rw-r--r--tools/regression/environ/Makefile.timings16
-rw-r--r--tools/regression/environ/envctl.c154
-rw-r--r--tools/regression/environ/envtest.t182
-rw-r--r--tools/regression/environ/retention.c109
-rw-r--r--tools/regression/environ/timings.c195
-rw-r--r--usr.bin/du/du.c6
-rw-r--r--usr.bin/env/env.c7
-rw-r--r--usr.bin/limits/limits.c10
-rw-r--r--usr.bin/login/login.c7
-rw-r--r--usr.bin/su/su.c8
-rw-r--r--usr.sbin/pstat/pstat.c6
-rw-r--r--usr.sbin/sade/main.c2
-rw-r--r--usr.sbin/sade/variable.c5
-rw-r--r--usr.sbin/sysinstall/main.c2
-rw-r--r--usr.sbin/sysinstall/variable.c5
28 files changed, 1389 insertions, 290 deletions
diff --git a/bin/df/df.c b/bin/df/df.c
index 5420da9..f48c8c9 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -131,14 +131,14 @@ main(int argc, char *argv[])
*/
if (kflag)
break;
- putenv("BLOCKSIZE=512");
+ setenv("BLOCKSIZE", "512", 1);
hflag = 0;
break;
case 'c':
cflag = 1;
break;
case 'g':
- putenv("BLOCKSIZE=1g");
+ setenv("BLOCKSIZE", "1g", 1);
hflag = 0;
break;
case 'H':
@@ -152,7 +152,7 @@ main(int argc, char *argv[])
break;
case 'k':
kflag++;
- putenv("BLOCKSIZE=1024");
+ setenv("BLOCKSIZE", "1024", 1);
hflag = 0;
break;
case 'l':
@@ -162,7 +162,7 @@ main(int argc, char *argv[])
lflag = 1;
break;
case 'm':
- putenv("BLOCKSIZE=1m");
+ setenv("BLOCKSIZE", "1m", 1);
hflag = 0;
break;
case 'n':
diff --git a/bin/sh/var.c b/bin/sh/var.c
index 54a0a84..afb3c86 100644
--- a/bin/sh/var.c
+++ b/bin/sh/var.c
@@ -289,6 +289,7 @@ void
setvareq(char *s, int flags)
{
struct var *vp, **vpp;
+ char *p;
int len;
if (aflag)
@@ -319,7 +320,10 @@ setvareq(char *s, int flags)
if (vp == &vmpath || (vp == &vmail && ! mpathset()))
chkmail(1);
if ((vp->flags & VEXPORT) && localevar(s)) {
- putenv(s);
+ p = strchr(s, '=');
+ *p = '\0';
+ (void) setenv(s, p + 1, 1);
+ *p = '=';
(void) setlocale(LC_ALL, "");
}
INTON;
@@ -335,7 +339,10 @@ setvareq(char *s, int flags)
INTOFF;
*vpp = vp;
if ((vp->flags & VEXPORT) && localevar(s)) {
- putenv(s);
+ p = strchr(s, '=');
+ *p = '\0';
+ (void) setenv(s, p + 1, 1);
+ *p = '=';
(void) setlocale(LC_ALL, "");
}
INTON;
@@ -596,7 +603,10 @@ exportcmd(int argc, char **argv)
vp->flags |= flag;
if ((vp->flags & VEXPORT) && localevar(vp->text)) {
- putenv(vp->text);
+ p = strchr(vp->text, '=');
+ *p = '\0';
+ (void) setenv(vp->text, p + 1, 1);
+ *p = '=';
(void) setlocale(LC_ALL, "");
}
goto found;
diff --git a/include/stdlib.h b/include/stdlib.h
index 98fe8b7..98cb465 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -161,7 +161,7 @@ void _Exit(int) __dead2;
int posix_memalign(void **, size_t, size_t); /* (ADV) */
int rand_r(unsigned *); /* (TSF) */
int setenv(const char *, const char *, int);
-void unsetenv(const char *);
+int unsetenv(const char *);
#endif
/*
@@ -197,7 +197,7 @@ long mrand48(void);
long nrand48(unsigned short[3]);
int posix_openpt(int);
char *ptsname(int);
-int putenv(const char *);
+int putenv(char *);
long random(void);
char *realpath(const char *, char resolved_path[]);
unsigned short
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 99ea7fb..f9b8fec 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -8,10 +8,10 @@ MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
bsearch.c div.c exit.c getenv.c getopt.c getopt_long.c \
getsubopt.c grantpt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c \
- merge.c putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c \
- reallocf.c realpath.c remque.c setenv.c strfmon.c strtoimax.c \
- strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c strtoumax.c \
- strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
+ merge.c qsort.c qsort_r.c radixsort.c rand.c random.c \
+ reallocf.c realpath.c remque.c strfmon.c strtoimax.c \
+ strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \
+ strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
SYM_MAPS+= ${.CURDIR}/stdlib/Symbol.map
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
index 3d365f1..33d9c36 100644
--- a/lib/libc/stdlib/getenv.3
+++ b/lib/libc/stdlib/getenv.3
@@ -32,7 +32,7 @@
.\" @(#)getenv.3 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
-.Dd October 12, 2006
+.Dd June 20, 2007
.Dt GETENV 3
.Os
.Sh NAME
@@ -50,22 +50,13 @@
.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
.Em environment list .
-For compatibility with differing environment conventions,
-the given arguments
-.Fa name
-and
-.Fa value
-may be appended and prepended,
-respectively,
-with an equal sign
-.Dq Li \&= .
.Pp
The
.Fn getenv
@@ -97,11 +88,18 @@ to the given
.Pp
The
.Fn putenv
-function takes an argument of the form ``name=value'' and is
-equivalent to:
-.Bd -literal -offset indent
-setenv(name, value, 1);
-.Ed
+function takes an argument of the form ``name=value'' and
+puts it directly into the current environment,
+so altering the argument shall change the environment.
+If the variable
+.Fa name
+does not exist in the list,
+it is inserted with the given
+.Fa value .
+If the variable
+.Fa name
+does exist, it is reset to the given
+.Fa value .
.Pp
The
.Fn unsetenv
@@ -121,15 +119,55 @@ is not in the current environment,
.Dv NULL
is returned.
.Pp
-.Rv -std setenv putenv
+.Rv -std setenv putenv unsetenv
.Sh ERRORS
.Bl -tag -width Er
-.It Bq Er ENOMEM
+.It Bq Er EINVAL
The function
+.Fn getenv ,
.Fn setenv
or
+.Fn unsetenv
+failed because the
+.Fa name
+is a
+.Dv NULL
+pointer, points to an empty string, or points to a string containing an
+.Dq Li \&=
+character.
+.Pp
+The function
+.Fn putenv
+failed because
+.Fa string
+is a
+.Dv NULL
+pointer,
+.Fa string is without an
+.Dq Li \&=
+character or
+.Dq Li \&=
+is the first character in
+.Fa string .
+This does not follow the
+.Tn POSIX
+specification.
+.It Bq Er ENOMEM
+The function
+.Fn setenv ,
+.Fn unsetenv
+or
.Fn putenv
failed because they were unable to allocate memory for the environment.
+.It Bq Er EFAULT
+The functions
+.Fn setenv ,
+.Fn unsetenv
+or
+.Fn putenv
+failed to make a valid copy of the environment due to the environment being
+corrupt (i.e., a name without a value). A warning will be output to stderr with
+information about the issue.
.El
.Sh SEE ALSO
.Xr csh 1 ,
@@ -141,6 +179,13 @@ The
.Fn getenv
function conforms to
.St -isoC .
+The
+.Fn setenv ,
+.Fn putenv
+and
+.Fn unsetenv
+functions conforms to
+.St -p1003.1-2001 .
.Sh HISTORY
The functions
.Fn setenv
@@ -152,19 +197,30 @@ The
.Fn putenv
function appeared in
.Bx 4.3 Reno .
+.Pp
+Until
+.Fx 7.0 ,
+.Fn putenv
+would make a copy of
+.Fa string
+and insert it into the environment using
+.Fn setenv .
+This was changed to use
+.Fa string
+as the memory location of the ``name=value'' pair to follow the
+.Tn POSIX
+specification.
.Sh BUGS
Successive calls to
.Fn setenv
-or
-.Fn putenv
-assigning a differently sized
+that assign a larger-sized
.Fa value
-to the same
+than any previous value to the same
.Fa name
will result in a memory leak.
The
.Fx
-semantics for these functions
+semantics for this function
(namely, that the contents of
.Fa value
are copied and that old values remain accessible indefinitely) make this
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index 306b6a1..5f6f497 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -1,89 +1,568 @@
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org>
+ * 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.
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
* 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.
- * 4. 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-inline char *__findenv(const char *, int *);
+/*
+ * Standard environ. environ variable is exposed to entire process.
+ *
+ * origEnviron: Upon cleanup on unloading of library or failure, this
+ * allows environ to return to as it was before.
+ * environSize: Number of variables environ can hold. Can only
+ * increase.
+ */
+extern char **environ;
+static char **origEnviron;
+static int environSize = 0;
+
+/*
+ * Array of environment variables built from environ. Each element records:
+ * name: Pointer to name=value string
+ * name length: Length of name not counting '=' character
+ * value: Pointer to value within same string as name
+ * value size: Size (not length) of space for value not counting the
+ * nul character
+ * active state: true/false value to signify whether variable is active.
+ * Useful since multiple variables with the same name can
+ * co-exist. At most, one variable can be active at any
+ * one time.
+ * putenv: Created from putenv() call. This memory must not be
+ * reused.
+ */
+static struct envVars {
+ size_t nameLen;
+ size_t valueSize;
+ char *name;
+ char *value;
+ bool active;
+ bool putenv;
+} *envVars = NULL;
/*
- * __findenv --
- * Returns pointer to value associated with name, if any, else NULL.
- * Sets offset to be the offset of the name/value combination in the
- * environmental array, for use by setenv(3) and unsetenv(3).
- * Explicitly removes '=' in argument name.
+ * Environment array information.
*
- * This routine *should* be a static; don't use it.
+ * envActive: Number of active variables in array.
+ * envVarsSize: Size of array.
+ * envVarsTotal: Number of total variables in array (active or not).
+ */
+static int envActive = 0;
+static int envVarsSize = 0;
+static int envVarsTotal = 0;
+
+
+/* Deinitialization of new environment. */
+static void __attribute__ ((destructor)) __clean_env(void);
+
+
+/*
+ * Inline strlen() for performance. Also, perform check for an equals sign.
+ * Cheaper here than peforming a strchr() later.
+ */
+static inline size_t
+__strleneq(const char *str)
+{
+ const char *s;
+
+ for (s = str; *s != '\0'; ++s)
+ if (*s == '=')
+ return (0);
+
+ return (s - str);
+}
+
+
+/*
+ * Comparison of an environment name=value to a name.
+ */
+static inline bool
+strncmpeq(const char *nameValue, const char *name, size_t nameLen)
+{
+ if (strncmp(nameValue, name, nameLen) == 0 && nameValue[nameLen] == '=')
+ return (true);
+
+ return (false);
+}
+
+
+/*
+ * Using environment, returns pointer to value associated with name, if any,
+ * else NULL. If the onlyActive flag is set to true, only variables that are
+ * active are returned else all are.
+ */
+static inline char *
+__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive)
+{
+ int ndx;
+
+ /*
+ * Find environment variable from end of array (more likely to be
+ * active). A variable created by putenv is always active or it is not
+ * tracked in the array.
+ */
+ for (ndx = *envNdx; ndx >= 0; ndx--)
+ if (envVars[ndx].putenv) {
+ if (strncmpeq(envVars[ndx].name, name, nameLen)) {
+ *envNdx = ndx;
+ return (envVars[ndx].name + nameLen +
+ sizeof ("=") - 1);
+ }
+ } else if ((!onlyActive || envVars[ndx].active) &&
+ (envVars[ndx].nameLen == nameLen &&
+ strncmpeq(envVars[ndx].name, name, nameLen))) {
+ *envNdx = ndx;
+ return (envVars[ndx].value);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * Using environ, returns pointer to value associated with name, if any, else
+ * NULL. Used on the original environ passed into the program.
*/
-inline char *
-__findenv(name, offset)
- const char *name;
- int *offset;
+static char *
+__findenv_environ(const char *name, size_t nameLen)
{
- extern char **environ;
- int len, i;
- const char *np;
- char **p, *cp;
+ int envNdx;
- if (name == NULL || environ == NULL)
+ /* Check for non-existant environment. */
+ if (environ == NULL)
return (NULL);
- for (np = name; *np && *np != '='; ++np)
- continue;
- len = np - name;
- for (p = environ; (cp = *p) != NULL; ++p) {
- for (np = name, i = len; i && *cp; i--)
- if (*cp++ != *np++)
- break;
- if (i == 0 && *cp++ == '=') {
- *offset = p - environ;
- return (cp);
+
+ /* Find variable within environ. */
+ for (envNdx = 0; environ[envNdx] != NULL; envNdx++)
+ if (strncmpeq(environ[envNdx], name, nameLen))
+ return (&(environ[envNdx][nameLen + sizeof("=") - 1]));
+
+ return (NULL);
+}
+
+
+/*
+ * Using the environment, rebuild the environ array for use by other C library
+ * calls that depend upon it.
+ */
+static int
+__rebuild_environ(int newEnvironSize)
+{
+ char **tmpEnviron;
+ int envNdx;
+ int environNdx;
+ int tmpEnvironSize;
+
+ /* Resize environ. */
+ if (newEnvironSize > environSize) {
+ tmpEnvironSize = newEnvironSize * 2;
+ tmpEnviron = realloc(environ, sizeof (*environ) *
+ (tmpEnvironSize + 1));
+ if (tmpEnviron == NULL)
+ return (-1);
+ environSize = tmpEnvironSize;
+ environ = tmpEnviron;
+ }
+ envActive = newEnvironSize;
+
+ /* Assign active variables to environ. */
+ for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--)
+ if (envVars[envNdx].active)
+ environ[environNdx++] = envVars[envNdx].name;
+ environ[environNdx] = NULL;
+
+ return (0);
+}
+
+
+/*
+ * Enlarge new environment.
+ */
+static inline bool
+__enlarge_env(void)
+{
+ int newEnvVarsSize;
+ struct envVars *tmpEnvVars;
+
+ envVarsTotal++;
+ if (envVarsTotal > envVarsSize) {
+ newEnvVarsSize = envVarsTotal * 2;
+ tmpEnvVars = realloc(envVars, sizeof (*envVars) *
+ newEnvVarsSize);
+ if (tmpEnvVars == NULL) {
+ envVarsTotal--;
+ return (false);
}
+ envVarsSize = newEnvVarsSize;
+ envVars = tmpEnvVars;
}
- return (NULL);
+
+ return (true);
+}
+
+
+/*
+ * Using environ, build an environment for use by standard C library calls.
+ */
+static int
+__build_env(void)
+{
+ char **env;
+ int activeNdx;
+ int envNdx;
+ int rtrnVal;
+ int savedErrno;
+ size_t nameLen;
+
+ /* Check for non-existant environment. */
+ if (environ == NULL)
+ return (0);
+ if (environ[0] == NULL)
+ goto SaveEnviron;
+
+ /* Count environment variables. */
+ for (env = environ, envVarsTotal = 0; *env != NULL; env++)
+ envVarsTotal++;
+ envVarsSize = envVarsTotal * 2;
+
+ /* Create new environment. */
+ envVars = calloc(1, sizeof (*envVars) * envVarsSize);
+ if (envVars == NULL)
+ goto Failure;
+
+ /* Copy environ values and keep track of them. */
+ for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) {
+ envVars[envNdx].putenv = false;
+ envVars[envNdx].name =
+ strdup(environ[envVarsTotal - envNdx - 1]);
+ if (envVars[envNdx].name == NULL)
+ goto Failure;
+ envVars[envNdx].value = strchr(envVars[envNdx].name, '=');
+ if (envVars[envNdx].value != NULL) {
+ envVars[envNdx].value++;
+ envVars[envNdx].valueSize =
+ strlen(envVars[envNdx].value);
+ } else {
+ warnx("environment corrupt; missing value for %s",
+ envVars[envNdx].name);
+ errno = EFAULT;
+ goto Failure;
+ }
+
+ /*
+ * Find most current version of variable to make active. This
+ * will prevent multiple active variables from being created
+ * during this initialization phase.
+ */
+ nameLen = envVars[envNdx].value - envVars[envNdx].name - 1;
+ envVars[envNdx].nameLen = nameLen;
+ activeNdx = envVarsTotal - 1;
+ if (__findenv(envVars[envNdx].name, nameLen, &activeNdx,
+ false) == NULL) {
+ warnx("environment corrupt; unable to find %.*s",
+ nameLen, envVars[envNdx].name);
+ errno = EFAULT;
+ goto Failure;
+ }
+ envVars[activeNdx].active = true;
+ }
+
+ /* Create a new environ. */
+SaveEnviron:
+ origEnviron = environ;
+ environ = NULL;
+ if (envVarsTotal > 0) {
+ rtrnVal = __rebuild_environ(envVarsTotal);
+ if (rtrnVal == -1) {
+ savedErrno = errno;
+ __clean_env();
+ errno = savedErrno;
+ }
+ } else
+ rtrnVal = 0;
+
+ return (rtrnVal);
+
+Failure:
+ savedErrno = errno;
+ __clean_env();
+ errno = savedErrno;
+
+ return (-1);
+}
+
+
+/*
+ * Remove variable added by putenv() from variable tracking array.
+ */
+static void
+__remove_putenv(int envNdx)
+{
+ memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]),
+ (envVarsTotal - envNdx) * sizeof (*envVars));
+ envVarsTotal--;
+
+ return;
+}
+
+
+/*
+ * Deallocate the environment built from environ as well as environ then set
+ * both to NULL. Eases debugging of memory leaks.
+ */
+static void
+__clean_env(void)
+{
+ int envNdx;
+
+ /* Deallocate environment and environ if created by *env(). */
+ if (envVars != NULL) {
+ for (envNdx = 0; envNdx < envVarsTotal; envNdx++)
+ if (!envVars[envNdx].putenv)
+ free(envVars[envNdx].name);
+ free(envVars);
+ envVars = NULL;
+
+ /* Restore original environ. */
+ if (origEnviron != NULL) {
+ free(environ);
+ environ = origEnviron;
+ }
+ }
+
+ return;
}
+
/*
- * getenv --
- * Returns ptr to value associated with name, if any, else NULL.
+ * Returns the value of a variable or NULL if none are found.
*/
char *
-getenv(name)
- const char *name;
+getenv(const char *name)
+{
+ int envNdx;
+ size_t nameLen;
+
+ /* Check for malformed name. */
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Find environment variable via environ or rebuilt environment. */
+ if (envVars == NULL)
+ return (__findenv_environ(name, nameLen));
+ else {
+ envNdx = envVarsTotal - 1;
+ return (__findenv(name, nameLen, &envNdx, true));
+ }
+}
+
+
+/*
+ * Set the value of a variable. Older settings are labeled as inactive. If an
+ * older setting has enough room to store the new value, it will be reused. No
+ * previous variables are ever freed here to avoid causing a segmentation fault
+ * in a user's code.
+ */
+int
+setenv(const char *name, const char *value, int overwrite)
+{
+ bool reuse;
+ char *env;
+ int envNdx;
+ int newEnvActive;
+ size_t nameLen;
+ size_t valueLen;
+
+ /* Check for malformed name. */
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Initialize environment. */
+ if (envVars == NULL && __build_env() == -1)
+ return (-1);
+
+ /* Find existing environment variable large enough to use. */
+ envNdx = envVarsTotal - 1;
+ newEnvActive = envActive;
+ valueLen = strlen(value);
+ reuse = false;
+ if (__findenv(name, nameLen, &envNdx, false) != NULL) {
+ /* Deactivate entry if overwrite is allowed. */
+ if (envVars[envNdx].active) {
+ if (overwrite == 0)
+ return (0);
+ envVars[envNdx].active = false;
+ newEnvActive--;
+ }
+
+ /* putenv() created variable cannot be reused. */
+ if (envVars[envNdx].putenv)
+ __remove_putenv(envNdx);
+
+ /* Entry is large enough to reuse. */
+ else if (envVars[envNdx].valueSize >= valueLen)
+ reuse = true;
+
+ }
+
+ /* Create new variable if none was found of sufficient size. */
+ if (! reuse) {
+ /* Enlarge environment. */
+ envNdx = envVarsTotal;
+ if (!__enlarge_env())
+ return (-1);
+
+ /* Create environment entry. */
+ envVars[envNdx].name = malloc(nameLen + sizeof ("=") +
+ valueLen);
+ if (envVars[envNdx].name == NULL) {
+ envVarsTotal--;
+ return (-1);
+ }
+ envVars[envNdx].nameLen = nameLen;
+ envVars[envNdx].valueSize = valueLen;
+
+ /* Save name of name/value pair. */
+ env = stpcpy(envVars[envNdx].name, name);
+ if ((envVars[envNdx].name)[nameLen] != '=')
+ env = stpcpy(env, "=");
+ }
+ else
+ env = envVars[envNdx].value;
+
+ /* Save value of name/value pair. */
+ strcpy(env, value);
+ envVars[envNdx].value = env;
+ envVars[envNdx].active = true;
+ newEnvActive++;
+
+ /* No need to rebuild environ if the variable was reused. */
+ if (reuse)
+ return (0);
+ else
+ return (__rebuild_environ(newEnvActive));
+}
+
+
+/*
+ * Insert a "name=value" string into then environment. Special settings must be
+ * made to keep setenv() from reusing this memory block and unsetenv() from
+ * allowing it to be tracked.
+ */
+int
+putenv(char *string)
{
- int offset;
+ char *equals;
+ int envNdx;
+ int newEnvActive;
+ size_t nameLen;
+
+ /* Check for malformed argument. */
+ if (string == NULL || (equals = strchr(string, '=')) == NULL ||
+ (nameLen = equals - string) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Initialize environment. */
+ if (envVars == NULL && __build_env() == -1)
+ return (-1);
+
+ /* Deactivate previous environment variable. */
+ envNdx = envVarsTotal - 1;
+ newEnvActive = envActive;
+ if (__findenv(string, nameLen, &envNdx, true) != NULL) {
+ /* Reuse previous putenv slot. */
+ if (envVars[envNdx].putenv) {
+ envVars[envNdx].name = string;
+ return (__rebuild_environ(envActive));
+ } else {
+ newEnvActive--;
+ envVars[envNdx].active = false;
+ }
+ }
+
+ /* Enlarge environment. */
+ envNdx = envVarsTotal;
+ if (!__enlarge_env())
+ return (-1);
+
+ /* Create environment entry. */
+ envVars[envNdx].name = string;
+ envVars[envNdx].nameLen = -1;
+ envVars[envNdx].value = NULL;
+ envVars[envNdx].valueSize = -1;
+ envVars[envNdx].putenv = true;
+ envVars[envNdx].active = true;
+ newEnvActive++;
+
+ return (__rebuild_environ(newEnvActive));
+}
+
+
+/*
+ * Unset variable with the same name by flagging it as inactive. No variable is
+ * ever freed.
+ */
+int
+unsetenv(const char *name)
+{
+ int envNdx;
+ size_t nameLen;
+
+ /* Check for malformed name. */
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Initialize environment. */
+ if (envVars == NULL && __build_env() == -1)
+ return (-1);
+
+ /* Deactivate specified variable. */
+ envNdx = envVarsTotal - 1;
+ if (__findenv(name, nameLen, &envNdx, true) != NULL) {
+ envVars[envNdx].active = false;
+ if (envVars[envNdx].putenv)
+ __remove_putenv(envNdx);
+ __rebuild_environ(envActive - 1);
+ }
- return (__findenv(name, &offset));
+ return (0);
}
diff --git a/lib/libc/stdlib/putenv.c b/lib/libc/stdlib/putenv.c
deleted file mode 100644
index a5eea5d..0000000
--- a/lib/libc/stdlib/putenv.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-
- * 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.
- * 4. 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)putenv.c 8.2 (Berkeley) 3/27/94";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <stdlib.h>
-#include <string.h>
-
-int
-putenv(str)
- const char *str;
-{
- char *p, *equal;
- int rval;
-
- if ((p = strdup(str)) == NULL)
- return (-1);
- if ((equal = index(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
deleted file mode 100644
index 202c022..0000000
--- a/lib/libc/stdlib/setenv.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 1987, 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.
- * 4. 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-char *__findenv(const char *, int *);
-
-/*
- * setenv --
- * Set the value of the environmental variable "name" to be
- * "value". If rewrite is set, replace any current value.
- */
-int
-setenv(name, value, rewrite)
- const char *name;
- const char *value;
- int rewrite;
-{
- extern char **environ;
- static char **alloced; /* if allocated space before */
- char *c;
- int l_value, offset;
-
- if (*value == '=') /* no `=' in value */
- ++value;
- l_value = strlen(value);
- if ((c = __findenv(name, &offset))) { /* find if already exists */
- if (!rewrite)
- return (0);
- if (strlen(c) >= l_value) { /* old larger; copy over */
- while ( (*c++ = *value++) );
- return (0);
- }
- } else { /* create new slot */
- int cnt;
- char **p;
-
- for (p = environ, cnt = 0; *p; ++p, ++cnt);
- if (alloced == environ) { /* just increase size */
- p = (char **)realloc((char *)environ,
- (size_t)(sizeof(char *) * (cnt + 2)));
- if (!p)
- return (-1);
- alloced = environ = p;
- }
- else { /* get new space */
- /* copy old entries into it */
- p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
- if (!p)
- return (-1);
- bcopy(environ, p, cnt * sizeof(char *));
- alloced = environ = p;
- }
- environ[cnt + 1] = NULL;
- offset = cnt;
- }
- for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
- if (!(environ[offset] = /* name + `=' + value */
- malloc((size_t)((int)(c - name) + l_value + 2))))
- return (-1);
- for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
- for (*c++ = '='; (*c++ = *value++); );
- return (0);
-}
-
-/*
- * unsetenv(name) --
- * Delete environmental variable "name".
- */
-void
-unsetenv(name)
- const char *name;
-{
- extern char **environ;
- char **p;
- int offset;
-
- while (__findenv(name, &offset)) /* if set multiple times */
- for (p = &environ[offset];; ++p)
- if (!(*p = *(p + 1)))
- break;
-}
diff --git a/libexec/pppoed/pppoed.c b/libexec/pppoed/pppoed.c
index 8dfebb7..f07dd8c 100644
--- a/libexec/pppoed/pppoed.c
+++ b/libexec/pppoed/pppoed.c
@@ -258,7 +258,7 @@ Spawn(const char *prog, const char *acname, const char *provider,
struct ng_mesg *rep = (struct ng_mesg *)msgbuf;
struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep);
struct ngpppoe_init_data *data;
- char env[sizeof(HISMACADDR)+18], unknown[14], sessionid[5], *path;
+ char env[18], unknown[14], sessionid[5], *path;
unsigned char *macaddr;
const char *msg;
int ret, slen;
@@ -352,11 +352,11 @@ Spawn(const char *prog, const char *acname, const char *provider,
/* Put the peer's MAC address in the environment */
if (sz >= sizeof(struct ether_header)) {
macaddr = ((struct ether_header *)request)->ether_shost;
- snprintf(env, sizeof(env), "%s=%x:%x:%x:%x:%x:%x", HISMACADDR,
+ snprintf(env, sizeof(env), "%x:%x:%x:%x:%x:%x",
macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4],
macaddr[5]);
- if (putenv(env) != 0)
- syslog(LOG_INFO, "putenv: cannot set %s: %m", env);
+ if (setenv(HISMACADDR, env, 1) != 0)
+ syslog(LOG_INFO, "setenv: cannot set %s: %m", HISMACADDR);
}
/* And send our request data to the waiting node */
diff --git a/sys/sys/param.h b/sys/sys/param.h
index d77fa03..5857317 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -57,7 +57,7 @@
* is created, otherwise 1.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 700049 /* Master, propagated to newvers */
+#define __FreeBSD_version 700050 /* Master, propagated to newvers */
#ifndef LOCORE
#include <sys/types.h>
diff --git a/tools/regression/environ/Makefile b/tools/regression/environ/Makefile
new file mode 100644
index 0000000..62720d2
--- /dev/null
+++ b/tools/regression/environ/Makefile
@@ -0,0 +1,14 @@
+#
+# $FreeBSD$
+#
+PROGS= envctl retention timings
+
+all clean test:
+.for target in ${.TARGET}
+.for prog in ${PROGS}
+ @${MAKE} -f Makefile.${prog} ${target}
+.endfor
+.if make(clean)
+ rm -f *~
+.endif
+.endfor
diff --git a/tools/regression/environ/Makefile.envctl b/tools/regression/environ/Makefile.envctl
new file mode 100644
index 0000000..6298a20
--- /dev/null
+++ b/tools/regression/environ/Makefile.envctl
@@ -0,0 +1,16 @@
+#
+# $FreeBSD$
+#
+SRCS= envctl.c
+PROG= envctl
+
+CFLAGS+=-Wall -I../../../include
+
+CLEANFILES= ${PROG}.core
+
+NO_MAN= yes
+
+.include <bsd.prog.mk>
+
+test: ${PROG}
+ @sh envtest.t
diff --git a/tools/regression/environ/Makefile.retention b/tools/regression/environ/Makefile.retention
new file mode 100644
index 0000000..9e0687f
--- /dev/null
+++ b/tools/regression/environ/Makefile.retention
@@ -0,0 +1,16 @@
+#
+# $FreeBSD$
+#
+SRCS= retention.c
+PROG= retention
+
+CFLAGS+=-Wall -I../../../include
+
+CLEANFILES= *~ ${PROG}.core
+
+NO_MAN= yes
+
+.include <bsd.prog.mk>
+
+test: ${PROG}
+ @./${PROG}
diff --git a/tools/regression/environ/Makefile.timings b/tools/regression/environ/Makefile.timings
new file mode 100644
index 0000000..88c4f7c
--- /dev/null
+++ b/tools/regression/environ/Makefile.timings
@@ -0,0 +1,16 @@
+#
+# $FreeBSD$
+#
+SRCS= timings.c
+PROG= timings
+
+CFLAGS+=-Wall -I../../../include
+
+CLEANFILES= ${PROG}.core
+
+NO_MAN= yes
+
+.include <bsd.prog.mk>
+
+test: ${PROG}
+ @./timings
diff --git a/tools/regression/environ/envctl.c b/tools/regression/environ/envctl.c
new file mode 100644
index 0000000..2681741
--- /dev/null
+++ b/tools/regression/environ/envctl.c
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <errno.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+extern char **environ;
+
+
+static void
+dump_environ(void)
+{
+ char **environPtr;
+
+ for (environPtr = environ; *environPtr != NULL; *environPtr++)
+ printf("%s\n", *environPtr);
+
+ return;
+}
+
+
+static void
+usage(const char *program)
+{
+ fprintf(stderr, "Usage: %s [-DGUcht] [-gu name] [-p name=value] "
+ "[(-S|-s name) value overwrite]\n\n"
+ "Options:\n"
+ " -D\t\t\t\tDump environ\n"
+ " -G name\t\t\tgetenv(NULL)\n"
+ " -S value overwrite\t\tsetenv(NULL, value, overwrite)\n"
+ " -U\t\t\t\tunsetenv(NULL)\n"
+ " -c\t\t\t\tClear environ variable\n"
+ " -g name\t\t\tgetenv(name)\n"
+ " -h\t\t\t\tHelp\n"
+ " -p name=value\t\t\tputenv(name=value)\n"
+ " -s name value overwrite\tsetenv(name, value, overwrite)\n"
+ " -t\t\t\t\tOutput is suitable for testing (no newlines)\n"
+ " -u name\t\t\tunsetenv(name)\n",
+ basename(program));
+
+ return;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ char *cleanEnv[] = { NULL };
+ char arg;
+ const char *eol = "\n";
+ const char *value;
+
+ if (argc == 1) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ while ((arg = getopt(argc, argv, "DGS:Ucg:hp:s:tu:")) != -1) {
+ switch (arg) {
+ case 'D':
+ errno = 0;
+ dump_environ();
+ break;
+
+ case 'c':
+ environ = cleanEnv;
+ break;
+
+ case 'G':
+ value = getenv(NULL);
+ printf("%s%s", value == NULL ? "" : value, eol);
+ break;
+
+ case 'g':
+ value = getenv(optarg);
+ printf("%s%s", value == NULL ? "" : value, eol);
+ break;
+
+ case 'p':
+ errno = 0;
+ printf("%d %d%s", putenv(optarg), errno, eol);
+ break;
+
+ case 'S':
+ errno = 0;
+ printf("%d %d%s", setenv(NULL, optarg,
+ atoi(argv[optind])), errno, eol);
+ optind += 1;
+ break;
+
+ case 's':
+ errno = 0;
+ printf("%d %d%s", setenv(optarg, argv[optind],
+ atoi(argv[optind + 1])), errno, eol);
+ optind += 2;
+ break;
+
+ case 't':
+ eol = " ";
+ break;
+
+ case 'U':
+ printf("%d %d%s", unsetenv(NULL), errno, eol);
+ break;
+
+ case 'u':
+ printf("%d %d%s", unsetenv(optarg), errno, eol);
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ // Output a closing newline in test mode.
+ if (eol[0] == ' ')
+ printf("\n");
+
+ return (EXIT_SUCCESS);
+}
diff --git a/tools/regression/environ/envtest.t b/tools/regression/environ/envtest.t
new file mode 100644
index 0000000..e3aca95
--- /dev/null
+++ b/tools/regression/environ/envtest.t
@@ -0,0 +1,182 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org>
+# 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,
+# without modification, immediately at the beginning of the file.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+#
+# $FreeBSD$
+
+
+# Initialization.
+testndx=0
+
+
+# Testing function.
+run_test()
+{
+ lasttest="${@}"
+ result=`./envctl -t "${@}"`
+
+ if [ ${?} -ne 0 ]
+ then
+ echo "Test program failed" >&2
+ exit 1
+ fi
+
+ return
+}
+
+
+# Perform test on results.
+check_result()
+{
+ testndx=$((testndx + 1))
+
+ echo "${result}" | sed 's/[ \t]*$//' | grep -q "^${@}$"
+ if [ ${?} -eq 0 ]
+ then
+ echo "ok ${testndx}"
+ else
+ echo "not ok ${testndx} - '${lasttest}'"
+ fi
+
+ return
+}
+
+
+#
+# Regression tests
+#
+
+# Setup environment for tests.
+readonly BAR="bar"
+readonly NEWBAR="newbar"
+export FOO=${BAR}
+
+
+# Gets from environ.
+run_test -g FOO
+check_result "${FOO}"
+
+run_test -c -g FOO
+check_result ""
+
+run_test -g FOOBAR
+check_result ""
+
+run_test -c -g FOOBAR
+check_result ""
+
+run_test -G
+check_result ""
+
+
+# Sets.
+run_test -s FOO ${NEWBAR} 0 -g FOO
+check_result "0 0 ${BAR}"
+
+run_test -s FOO ${NEWBAR} 1 -g FOO
+check_result "0 0 ${NEWBAR}"
+
+run_test -c -s FOO ${NEWBAR} 0 -g FOO
+check_result "0 0 ${NEWBAR}"
+
+run_test -c -s FOO ${NEWBAR} 1 -g FOO
+check_result "0 0 ${NEWBAR}"
+
+run_test -s "FOO=" ${NEWBAR} 1 -g FOO
+check_result "-1 22 ${BAR}"
+
+run_test -s "=FOO" ${NEWBAR} 1
+check_result "-1 22"
+
+run_test -s "=" ${NEWBAR} 1
+check_result "-1 22"
+
+run_test -s "" ${NEWBAR} 1
+check_result "-1 22"
+
+run_test -S ${NEWBAR} 1
+check_result "-1 22"
+
+run_test -s FOO ${NEWBAR} 1 -s FOO ${BAR} 1 -g FOO
+check_result "0 0 0 0 ${BAR}"
+
+run_test -c -s FOO ${NEWBAR} 1 -s FOO ${BAR} 1 -g FOO
+check_result "0 0 0 0 ${BAR}"
+
+run_test -s FOO ${NEWBAR} 1 -s FOO ${BAR} 1 -s FOO ${NEWBAR} 1 -g FOO
+check_result "0 0 0 0 0 0 ${NEWBAR}"
+
+run_test -s FOO ${NEWBAR} 1 -s FOO ${BAR} 1 -s FOO ${NEWBAR} 1 -s FOO ${BAR} 1\
+ -g FOO
+check_result "0 0 0 0 0 0 0 0 ${BAR}"
+
+
+# Unsets.
+run_test -u FOO -g FOO
+check_result "0 0"
+
+run_test -c -u FOO -g FOO
+check_result "0 0"
+
+run_test -U
+check_result "-1 22"
+
+run_test -u ""
+check_result "-1 22"
+
+run_test -u "=${BAR}"
+check_result "-1 22"
+
+run_test -c -s FOO ${NEWBAR} 1 -g FOO -u FOO -g FOO
+check_result "0 0 ${NEWBAR} 0 0"
+
+
+# Puts.
+run_test -p FOO=${NEWBAR} -g FOO
+check_result "0 0 ${NEWBAR}"
+
+run_test -c -p FOO=${NEWBAR} -g FOO
+check_result "0 0 ${NEWBAR}"
+
+run_test -p FOO -g FOO
+check_result "-1 22 ${BAR}"
+
+run_test -p FOO=${BAR} -p FOO=${NEWBAR} -g FOO
+check_result "0 0 0 0 ${NEWBAR}"
+
+run_test -p FOO=${BAR} -s FOO ${NEWBAR} 1 -g FOO
+check_result "0 0 0 0 ${NEWBAR}"
+
+run_test -s FOO ${NEWBAR} 1 -p FOO=${BAR} -g FOO
+check_result "0 0 0 0 ${BAR}"
+
+run_test -p FOO=${BAR} -u FOO
+check_result "0 0 0 0"
+
+run_test -p FOO=${BAR} -s FOO ${NEWBAR} 1 -u FOO
+check_result "0 0 0 0 0 0"
+
+run_test -s FOO ${NEWBAR} 1 -p FOO=${BAR} -u FOO
+check_result "0 0 0 0 0 0"
diff --git a/tools/regression/environ/retention.c b/tools/regression/environ/retention.c
new file mode 100644
index 0000000..7f75cd1
--- /dev/null
+++ b/tools/regression/environ/retention.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+extern char **environ;
+const char *envName = "FOOBAR";
+const char *envValSmall = "Hi";
+const char *envValLarge = "Hi, again";
+const char *envValAny = "Any value";
+
+
+int
+main(int argc, char **argv)
+{
+ const char *env1 = NULL;
+ const char *env2 = NULL;
+ const char *env3 = NULL;
+ const char *env4 = NULL;
+ const char *env5 = NULL;
+ int testNdx;
+
+ /* Clean slate. */
+ environ = NULL;
+ testNdx = 0;
+
+ /* Initial value of variable. */
+ if (getenv(envName) != NULL)
+ printf("not ");
+ printf("ok %d - getenv(\"%s\")\n", ++testNdx, envName);
+
+ /* Set value of variable to smaller value and get value. */
+ if ((setenv(envName, envValSmall, 1) != 0) ||
+ ((env1 = getenv(envName)) == NULL) ||
+ (strcmp(env1, envValSmall) != 0))
+ printf("not ");
+ printf("ok %d - setenv(\"%s\", \"%s\", 1)\n", ++testNdx, envName,
+ envValSmall);
+
+ /* Unset variable. */
+ if ((unsetenv(envName) == -1) || ((env2 = getenv(envName)) != NULL))
+ printf("not ");
+ printf("ok %d - unsetenv(\"%s\")\n", ++testNdx, envName);
+
+ /* Set variable to bigger value and get value. */
+ if ((setenv(envName, envValLarge, 1) != 0) ||
+ ((env3 = getenv(envName)) == NULL) ||
+ (strcmp(env3, envValLarge) != 0))
+ printf("not ");
+ printf("ok %d - setenv(\"%s\", \"%s\", 1)\n", ++testNdx, envName,
+ envValLarge);
+
+ /* Set variable to smaller value and get value. */
+ if ((setenv(envName, envValSmall, 1) != 0) ||
+ ((env4 = getenv(envName)) == NULL) ||
+ (strcmp(env4, envValSmall) != 0))
+ printf("not ");
+ printf("ok %d - setenv(\"%s\", \"%s\", 1)\n", ++testNdx, envName,
+ envValSmall);
+
+ /* Set variable to any value without overwrite and get value. */
+ if ((setenv(envName, envValAny, 0) != 0) ||
+ ((env5 = getenv(envName)) == NULL) ||
+ (strcmp(env5, envValAny) == 0))
+ printf("not ");
+ printf("ok %d - setenv(\"%s\", \"%s\", 0)\n", ++testNdx, envName,
+ envValAny);
+
+ /*
+ * Verify FreeBSD-ism about allowing a program to keep old pointers without
+ * risk of segfaulting.
+ */
+ if ((strcmp(env1, envValSmall) != 0) ||
+ (strcmp(env3, envValSmall) != 0) ||
+ (strcmp(env4, envValSmall) != 0))
+ printf("not ");
+ printf("ok %d - old variables point to valid memory\n", ++testNdx);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tools/regression/environ/timings.c b/tools/regression/environ/timings.c
new file mode 100644
index 0000000..1bf3c91
--- /dev/null
+++ b/tools/regression/environ/timings.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/time.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+const char value1[] = "Large ------------------ value";
+const char value2[] = "Small -- value";
+char nameValuePair[] = "less=more";
+const char name[] = "PATH";
+const char name2[] = "SHELL";
+const int MaxIterations = 1000000;
+const char Tabs[] = "\t\t\t";
+
+
+static int
+report_time(const char *action, struct timeval *startTime,
+ struct timeval *endTime)
+{
+ int actionLen;
+ int numTabs;
+
+ actionLen = strlen(action);
+ numTabs = 3 - actionLen / 8;
+
+ return (printf("Time spent executing %s:%.*s%f\n", action, numTabs, Tabs,
+ (endTime->tv_sec - startTime->tv_sec) +
+ (double)(endTime->tv_usec - startTime->tv_usec) / 1000000));
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int iterations;
+ struct timeval endTime;
+ struct timeval startTime;
+
+ /*
+ * getenv() on the existing environment.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ if (getenv(name) == NULL)
+ err(EXIT_FAILURE, "getenv(name)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("getenv(name)", &startTime, &endTime);
+
+
+ /*
+ * setenv() a variable with a large value.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ if (setenv(name, value1, 1) == -1)
+ err(EXIT_FAILURE, "setenv(name, value1, 1)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("setenv(name, value1, 1)", &startTime, &endTime);
+
+
+ /*
+ * getenv() the new variable on the new environment.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ /* Set large value to variable. */
+ if (getenv(name) == NULL)
+ err(EXIT_FAILURE, "getenv(name)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("getenv(name)", &startTime, &endTime);
+
+
+ /*
+ * getenv() a different variable on the new environment.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ /* Set large value to variable. */
+ if (getenv(name2) == NULL)
+ err(EXIT_FAILURE, "getenv(name2)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("getenv(name2)", &startTime, &endTime);
+
+
+ /*
+ * setenv() a variable with a small value.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ if (setenv(name, value2, 1) == -1)
+ err(EXIT_FAILURE, "setenv(name, value2, 1)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("setenv(name, value2, 1)", &startTime, &endTime);
+
+
+ /*
+ * getenv() a different variable on the new environment.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ /* Set large value to variable. */
+ if (getenv(name2) == NULL)
+ err(EXIT_FAILURE, "getenv(name)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("getenv(name)", &startTime, &endTime);
+
+
+ /*
+ * getenv() a different variable on the new environment.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ /* Set large value to variable. */
+ if (getenv(name2) == NULL)
+ err(EXIT_FAILURE, "getenv(name2)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("getenv(name2)", &startTime, &endTime);
+
+
+ /*
+ * putenv() a variable with a small value.
+ */
+ gettimeofday(&startTime, NULL);
+
+ /* Iterate over setting variable. */
+ for (iterations = 0; iterations < MaxIterations; iterations++)
+ if (putenv(nameValuePair) == -1)
+ err(EXIT_FAILURE, "putenv(nameValuePair)");
+
+ gettimeofday(&endTime, NULL);
+
+ report_time("putenv(nameValuePair)", &startTime, &endTime);
+
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/usr.bin/du/du.c b/usr.bin/du/du.c
index 00c1f5e..73583e3 100644
--- a/usr.bin/du/du.c
+++ b/usr.bin/du/du.c
@@ -140,16 +140,16 @@ main(int argc, char *argv[])
cflag = 1;
break;
case 'h':
- putenv("BLOCKSIZE=512");
+ setenv("BLOCKSIZE", "512", 1);
hflag = 1;
break;
case 'k':
hflag = 0;
- putenv("BLOCKSIZE=1024");
+ setenv("BLOCKSIZE", "1024", 1);
break;
case 'm':
hflag = 0;
- putenv("BLOCKSIZE=1048576");
+ setenv("BLOCKSIZE", "1048576", 1);
break;
case 'n':
nodumpflag = 1;
diff --git a/usr.bin/env/env.c b/usr.bin/env/env.c
index 815976f..b11a0b7 100644
--- a/usr.bin/env/env.c
+++ b/usr.bin/env/env.c
@@ -67,6 +67,7 @@ main(int argc, char **argv)
char *altpath, **ep, *p, **parg;
char *cleanenv[1];
int ch, want_clear;
+ int rtrn;
altpath = NULL;
want_clear = 0;
@@ -105,7 +106,11 @@ main(int argc, char **argv)
for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) {
if (env_verbosity)
fprintf(stderr, "#env setenv:\t%s\n", *argv);
- (void)setenv(*argv, ++p, 1);
+ *p = '\0';
+ rtrn = setenv(*argv, p + 1, 1);
+ *p = '=';
+ if (rtrn == -1)
+ err(EXIT_FAILURE, "setenv %s", *argv);
}
if (*argv) {
if (altpath)
diff --git a/usr.bin/limits/limits.c b/usr.bin/limits/limits.c
index e976f36..0383ac2 100644
--- a/usr.bin/limits/limits.c
+++ b/usr.bin/limits/limits.c
@@ -244,6 +244,7 @@ main(int argc, char *argv[])
int rcswhich, shelltype;
int i, num_limits = 0;
int ch, doeval = 0, doall = 0;
+ int rtrn;
login_cap_t * lc = NULL;
enum { ANY=0, SOFT=1, HARD=2, BOTH=3, DISPLAYONLY=4 } type = ANY;
enum { RCSUNKNOWN=0, RCSSET=1, RCSSEL=2 } todo = RCSUNKNOWN;
@@ -399,8 +400,13 @@ main(int argc, char *argv[])
login_close(lc);
/* set leading environment variables, like eval(1) */
- while (*argv && (p = strchr(*argv, '=')))
- (void)setenv(*argv++, ++p, 1);
+ while (*argv && (p = strchr(*argv, '='))) {
+ *p = '\0';
+ rtrn = setenv(*argv++, p + 1, 1);
+ *p = '=';
+ if (rtrn == -1)
+ err(EXIT_FAILURE, "setenv %s", *argv);
+ }
/* Set limits */
for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) {
diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c
index 7827ea1..549e015 100644
--- a/usr.bin/login/login.c
+++ b/usr.bin/login/login.c
@@ -766,10 +766,11 @@ export(const char *s)
"SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
"IFS", "PATH", NULL
};
+ char *p;
const char **pp;
size_t n;
- if (strlen(s) > 1024 || strchr(s, '=') == NULL)
+ if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
return (0);
if (strncmp(s, "LD_", 3) == 0)
return (0);
@@ -778,7 +779,9 @@ export(const char *s)
if (s[n] == '=' && strncmp(s, *pp, n) == 0)
return (0);
}
- (void)putenv(s);
+ *p = '\0';
+ (void)setenv(s, p + 1, 1);
+ *p = '=';
return (1);
}
diff --git a/usr.bin/su/su.c b/usr.bin/su/su.c
index 76f76b6..8bc5472 100644
--- a/usr.bin/su/su.c
+++ b/usr.bin/su/su.c
@@ -564,10 +564,14 @@ static void
export_pam_environment(void)
{
char **pp;
+ char *p;
for (pp = environ_pam; *pp != NULL; pp++) {
- if (ok_to_export(*pp))
- putenv(*pp);
+ if (ok_to_export(*pp)) {
+ p = strchr(*pp, '=');
+ *p = '\0';
+ setenv(*pp, p + 1, 1);
+ }
free(*pp);
}
}
diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c
index 95f782c..1516365 100644
--- a/usr.sbin/pstat/pstat.c
+++ b/usr.sbin/pstat/pstat.c
@@ -135,16 +135,16 @@ main(int argc, char *argv[])
fileflag = 1;
break;
case 'g':
- putenv("BLOCKSIZE=1G");
+ setenv("BLOCKSIZE", "1G", 1);
break;
case 'h':
humanflag = 1;
break;
case 'k':
- putenv("BLOCKSIZE=1K");
+ setenv("BLOCKSIZE", "1K", 1);
break;
case 'm':
- putenv("BLOCKSIZE=1M");
+ setenv("BLOCKSIZE", "1M", 1);
break;
case 'M':
memf = optarg;
diff --git a/usr.sbin/sade/main.c b/usr.sbin/sade/main.c
index 45ed1bb..5496e13 100644
--- a/usr.sbin/sade/main.c
+++ b/usr.sbin/sade/main.c
@@ -56,7 +56,7 @@ main(int argc, char **argv)
/* XXX */
char *p = getenv("TERM");
if (p && strcmp(p, "cons25") == 0)
- putenv("TERM=cons25w");
+ setenv("TERM", "cons25w", 1);
}
#endif
diff --git a/usr.sbin/sade/variable.c b/usr.sbin/sade/variable.c
index bbbc2d2..7809deb 100644
--- a/usr.sbin/sade/variable.c
+++ b/usr.sbin/sade/variable.c
@@ -296,6 +296,7 @@ free_variables(void)
void
pvariable_set(char *var)
{
+ char *p;
char tmp[1024];
if (!var)
@@ -307,7 +308,9 @@ pvariable_set(char *var)
if (index(var, '=') == NULL)
msgFatal("Invalid variable format: %s", var);
strlcat(tmp, var, 1024);
- putenv(tmp);
+ p = strchr(tmp, '=');
+ *p = '\0';
+ setenv(tmp, p + 1, 1);
}
char *
diff --git a/usr.sbin/sysinstall/main.c b/usr.sbin/sysinstall/main.c
index 7af8d44..149a0dc 100644
--- a/usr.sbin/sysinstall/main.c
+++ b/usr.sbin/sysinstall/main.c
@@ -74,7 +74,7 @@ main(int argc, char **argv)
/* XXX */
char *p = getenv("TERM");
if (p && strcmp(p, "cons25") == 0)
- putenv("TERM=cons25w");
+ setenv("TERM", "cons25w", 1);
}
#endif
diff --git a/usr.sbin/sysinstall/variable.c b/usr.sbin/sysinstall/variable.c
index e86104f..694b8be 100644
--- a/usr.sbin/sysinstall/variable.c
+++ b/usr.sbin/sysinstall/variable.c
@@ -301,6 +301,7 @@ free_variables(void)
void
pvariable_set(char *var)
{
+ char *p;
char tmp[1024];
if (!var)
@@ -312,7 +313,9 @@ pvariable_set(char *var)
if (index(var, '=') == NULL)
msgFatal("Invalid variable format: %s", var);
strlcat(tmp, var, 1024);
- putenv(tmp);
+ p = strchr(tmp, '=');
+ *p = '\0';
+ setenv(tmp, p + 1, 1);
}
char *
OpenPOWER on IntegriCloud