diff -ruN /usr/src/lib/libc/stdlib/Makefile.inc.orig /usr/src/lib/libc/stdlib/Makefile.inc --- /usr/src/lib/libc/stdlib/Makefile.inc.orig Tue May 9 11:17:22 2006 +++ /usr/src/lib/libc/stdlib/Makefile.inc Wed Apr 18 21:43:15 2007 @@ -5,13 +5,13 @@ .PATH: ${.CURDIR}/${MACHINE_ARCH}/stdlib ${.CURDIR}/stdlib MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ - bsearch.c calloc.c div.c exit.c getenv.c getopt.c getopt_long.c \ + bsearch.c calloc.c div.c exit.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 \ + sysenv.c system.c tdelete.c tfind.c tsearch.c twalk.c # machine-dependent stdlib sources .if exists(${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc) diff -ruN /usr/src/lib/libc/stdlib/sysenv.c.orig /usr/src/lib/libc/stdlib/sysenv.c --- /usr/src/lib/libc/stdlib/sysenv.c.orig Wed Dec 31 18:00:00 1969 +++ /usr/src/lib/libc/stdlib/sysenv.c Wed Apr 18 22:47:59 2007 @@ -0,0 +1,402 @@ +/*- + * Copyright (c) 2007 Sean Farley + * 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 +#include +#include +#include +#include +#include +#include +#if defined(DMALLOC_DEBUG) +#include +#endif + + +/* Standard environ that is exposed to all code. */ +extern char **environ; +static int environSize = 0; + +/* + * Array of environment variables built from environ. Each element records: + * name: Pointer to name=value string + * value: Pointer to value within same string as name + * value size: Size (not length) of space for value not counting 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. + */ +static struct envVars { + size_t valueSize; + char *name; + char *value; + bool active; +} *envVars = NULL; +static int envActive = 0; +static int envVarsSize = 0; + + +/* Deinitialization of new environment. */ +static void __attribute__ ((destructor)) __clean_env(void); + + +/* + * Using environment, returns pointer to value associated with name, if any, + * else NULL. Explicitly removes '=' in argument name in the search for the + * variable. If the onlyActive flag is set to true, only variables that are + * active are returned else all are. + */ +static char * +__findenv(const char *name, size_t *nameLen, int *envNdx, bool onlyActive) +{ + /* + * Remove '=' from end of name for compatibility with other environment + * conventions. See getenv(3). + */ + if (name[*nameLen - 1] == '=') + (*nameLen)--; + if (*nameLen == 0) + return (NULL); + + /* + * Find environment variable from end of array (more likely to be + * active). + */ + for (; *envNdx >= 0; (*envNdx)--) + if ((!onlyActive || envVars[*envNdx].active) && + envVars[*envNdx].name != NULL && + strncmp(envVars[*envNdx].name, name, *nameLen) == 0 && + (envVars[*envNdx].name)[*nameLen] == '=') + return (envVars[*envNdx].value); + + return (NULL); +} + + +/* + * Using environ, returns pointer to value associated with name, if any, else + * NULL. Explicitly removes '=' in argument name in the search for the + * variable. Used on the original environ passed into the program. + */ +static char * +__findenv_environ(const char *name) +{ + int envNdx; + size_t nameLen; + + if (name == NULL || environ == NULL) + return (NULL); + + /* Find variable within environ. */ + nameLen = strlen(name); + for (envNdx = 0; environ[envNdx] != NULL; envNdx++) + if (strncmp(environ[envNdx], name, nameLen) == 0 && + (environ[envNdx])[nameLen] == '=') { + return (&(environ[envNdx][nameLen + strlen("=")])); + } + + 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 newEnvSize) +{ + int envNdx; + int environNdx; + + /* Resize environ. */ + if (newEnvSize > environSize) { + environSize = newEnvSize; + environ = realloc(environ, sizeof (*environ) * (environSize + + 1)); + if (environ == NULL) + return (-1); + } + envActive = newEnvSize; + + /* Assign active variables to environ. */ + for (envNdx = envVarsSize - 1, environNdx = 0; envNdx >= 0; envNdx--) + if (envVars[envNdx].active) + environ[environNdx++] = envVars[envNdx].name; + environ[environNdx] = NULL; + + return (0); +} + + +/* + * Using environ, build an environment for use by standard C library calls. + */ +static int +__build_env(void) +{ + char **env; + int activeNdx; + int envNdx; + size_t nameLen; + + /* Check for non-existant environment. */ + if (environ == NULL) + return (0); + + /* Count environment variables. */ + for (env = environ, envVarsSize = 0; *env != NULL; env++) + envVarsSize++; + + /* Create new environment. */ + envVars = malloc(sizeof (*envVars) * envVarsSize); + if (envVars == NULL) + return (-1); + + /* Copy environ values and keep track of them. */ + for (envNdx = envVarsSize - 1; envNdx >= 0; envNdx--) { + envVars[envNdx].name = + strdup(environ[envVarsSize - envNdx - 1]); + if (envVars[envNdx].name == NULL) + return (-1); + envVars[envNdx].value = strstr(envVars[envNdx].name, "="); + if (envVars[envNdx].value != NULL) { + envVars[envNdx].value++; + envVars[envNdx].valueSize = + strlen(envVars[envNdx].value); + } + else + errx(EXIT_FAILURE, "environ corrupt"); + + /* + * 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; + activeNdx = envVarsSize - 1; + if (__findenv(envVars[envNdx].name, &nameLen, &activeNdx, + false) == NULL) + errx(EXIT_FAILURE, "environ corrupt"); + envVars[activeNdx].active = true; + } + + /* Create a new environ. */ + environ = NULL; + return (__rebuild_environ(envVarsSize)); +} + + +/* + * 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 (un)setenv(). */ + if (envVars != NULL) { + for (envNdx = 0; envNdx < envVarsSize; envNdx++) + free(envVars[envNdx].name); + free(envVars); + free(environ); + envVars = NULL; + environ = NULL; + } + + return; +} + + +/* + * Returns the value of a variable or NULL if none are found. Special handling + * is provided for a MALLOC_OPTIONS variable to prevent recursion since + * malloc(), during its initialization, calls getenv(). + */ +char * +getenv(const char *name) +{ + int envNdx; + size_t nameLen; + + if (name == NULL) + return (NULL); + + /* Find environment variable via environ or rebuilt environment. */ + if (envVars == NULL) + return (__findenv_environ(name)); + else { + nameLen = strlen(name); + envNdx = envVarsSize - 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 reused; + char *env; + int envNdx; + int newEnvSize; + size_t nameLen; + size_t valueLen; + + /* Initialize environment. */ + if (envVars == NULL && __build_env() == -1) + return (-1); + + /* Check for malformed name. */ + if (name == NULL || (nameLen = strlen(name)) == 0 || name[0] == '=') { + errno = EINVAL; + return (-1); + } + + /* + * Remove '=' from beginning of value for compatibility with other + * environment conventions. See setenv(3). + */ + if (value[0] == '=') + value++; + + /* Find existing environment variable large enough to use. */ + envNdx = envVarsSize - 1; + newEnvSize = envActive; + valueLen = strlen(value); + reused = 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; + newEnvSize--; + reused = true; + } + + /* Entry is not large enough to use. */ + if (envVars[envNdx].valueSize < valueLen) + envNdx = -1; + } + + /* Create new variable if none was found of sufficient size. */ + if (envNdx < 0) { + /* Enlarge environment. */ + envNdx = envVarsSize; + envVarsSize++; + envVars = realloc(envVars, sizeof (*envVars) * envVarsSize); + if (envVars == NULL) + return (-1); + + /* Create environment entry. */ + envVars[envNdx].name = malloc(nameLen + sizeof ("=") + + valueLen); + if (envVars[envNdx].name == NULL) + return (-1); + 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; + newEnvSize++; + + if (reused) + return (0); + else + return (__rebuild_environ(newEnvSize)); +} + + +/* + * putenv() API call using setenv(). + */ +int +putenv(const char *string) +{ + char *equal; + char *name; + int rval; + + if ((name = strdup(string)) == NULL) + return (-1); + if ((equal = strchr(name, '=')) == NULL) { + free(name); + return (-1); + } + *equal = '\0'; + rval = setenv(name, equal + 1, 1); + free(name); + + return (rval); +} + + +/* + * Unset all variables with the same name by flagging them as inactive. No + * variable is ever freed. + */ +void +unsetenv(const char *name) +{ + int envNdx; + size_t nameLen; + + if (name == NULL) + return; + + /* Initialize environment. */ + if (envVars == NULL && __build_env() == -1) + return; + + /* Deactivate specified variable. */ + envNdx = envVarsSize - 1; + nameLen = strlen(name); + if (__findenv(name, &nameLen, &envNdx, true) != NULL) { + envVars[envNdx].active = false; + __rebuild_environ(envActive - 1); + } + + return; +}