diff options
Diffstat (limited to 'lib/libc/stdlib/getenv.c')
-rw-r--r-- | lib/libc/stdlib/getenv.c | 686 |
1 files changed, 0 insertions, 686 deletions
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c deleted file mode 100644 index b7826d7..0000000 --- a/lib/libc/stdlib/getenv.c +++ /dev/null @@ -1,686 +0,0 @@ -/*- - * Copyright (c) 2007-2009 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 <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - - -#include "namespace.h" -#include <sys/types.h> -#include <errno.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include "un-namespace.h" - - -static const char CorruptEnvFindMsg[] = "environment corrupt; unable to find "; -static const char CorruptEnvValueMsg[] = - "environment corrupt; missing value for "; - - -/* - * 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. - * intEnviron: Internally-built environ. Exposed via environ during - * (re)builds of the environment. - */ -extern char **environ; -static char **origEnviron; -static char **intEnviron = NULL; -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; - -/* - * Environment array information. - * - * 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_destructor(void); - - -/* - * A simple version of warnx() to avoid the bloat of including stdio in static - * binaries. - */ -static void -__env_warnx(const char *msg, const char *name, size_t nameLen) -{ - static const char nl[] = "\n"; - static const char progSep[] = ": "; - - _write(STDERR_FILENO, _getprogname(), strlen(_getprogname())); - _write(STDERR_FILENO, progSep, sizeof(progSep) - 1); - _write(STDERR_FILENO, msg, strlen(msg)); - _write(STDERR_FILENO, name, nameLen); - _write(STDERR_FILENO, nl, sizeof(nl) - 1); - - return; -} - - -/* - * 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. - */ -static char * -__findenv_environ(const char *name, size_t nameLen) -{ - int envNdx; - - /* 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); -} - - -/* - * Remove variable added by putenv() from variable tracking array. - */ -static void -__remove_putenv(int envNdx) -{ - envVarsTotal--; - if (envVarsTotal > envNdx) - memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]), - (envVarsTotal - envNdx) * sizeof (*envVars)); - memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars)); - - 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(bool freeVars) -{ - int envNdx; - - /* Deallocate environment and environ if created by *env(). */ - if (envVars != NULL) { - for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) - /* Free variables or deactivate them. */ - if (envVars[envNdx].putenv) { - if (!freeVars) - __remove_putenv(envNdx); - } else { - if (freeVars) - free(envVars[envNdx].name); - else - envVars[envNdx].active = false; - } - if (freeVars) { - free(envVars); - envVars = NULL; - } else - envActive = 0; - - /* Restore original environ if it has not updated by program. */ - if (origEnviron != NULL) { - if (environ == intEnviron) - environ = origEnviron; - free(intEnviron); - intEnviron = NULL; - environSize = 0; - } - } - - return; -} - - -/* - * 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(intEnviron, sizeof (*intEnviron) * - (tmpEnvironSize + 1)); - if (tmpEnviron == NULL) - return (-1); - environSize = tmpEnvironSize; - intEnviron = tmpEnviron; - } - envActive = newEnvironSize; - - /* Assign active variables to environ. */ - for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--) - if (envVars[envNdx].active) - intEnviron[environNdx++] = envVars[envNdx].name; - intEnviron[environNdx] = NULL; - - /* Always set environ which may have been replaced by program. */ - environ = intEnviron; - - 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 (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 savedErrno; - size_t nameLen; - - /* Check for non-existant environment. */ - if (environ == NULL || environ[0] == NULL) - return (0); - - /* 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 { - __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, - strlen(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) { - __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name, - nameLen); - errno = EFAULT; - goto Failure; - } - envVars[activeNdx].active = true; - } - - /* Create a new environ. */ - origEnviron = environ; - environ = NULL; - if (__rebuild_environ(envVarsTotal) == 0) - return (0); - -Failure: - savedErrno = errno; - __clean_env(true); - errno = savedErrno; - - return (-1); -} - - -/* - * Destructor function with default argument to __clean_env(). - */ -static void -__clean_env_destructor(void) -{ - __clean_env(true); - - return; -} - - -/* - * Returns the value of a variable or NULL if none are found. - */ -char * -getenv(const char *name) -{ - int envNdx; - size_t nameLen; - - /* Check for malformed name. */ - if (name == NULL || (nameLen = __strleneq(name)) == 0) { - errno = EINVAL; - return (NULL); - } - - /* - * Variable search order: - * 1. Check for an empty environ. This allows an application to clear - * the environment. - * 2. Search the external environ array. - * 3. Search the internal environment. - * - * Since malloc() depends upon getenv(), getenv() must never cause the - * internal environment storage to be generated. - */ - if (environ == NULL || environ[0] == NULL) - return (NULL); - else if (envVars == NULL || environ != intEnviron) - 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. - * - * The variables nameLen and valueLen are passed into here to allow the caller - * to calculate the length by means besides just strlen(). - */ -static int -__setenv(const char *name, size_t nameLen, const char *value, int overwrite) -{ - bool reuse; - char *env; - int envNdx; - int newEnvActive; - size_t valueLen; - - /* 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 an active variable was reused. */ - if (reuse && newEnvActive == envActive) - return (0); - else - return (__rebuild_environ(newEnvActive)); -} - - -/* - * If the program attempts to replace the array of environment variables - * (environ) environ or sets the first varible to NULL, then deactivate all - * variables and merge in the new list from environ. - */ -static int -__merge_environ(void) -{ - char **env; - char *equals; - - /* - * Internally-built environ has been replaced or cleared (detected by - * using the count of active variables against a NULL as the first value - * in environ). Clean up everything. - */ - if (intEnviron != NULL && (environ != intEnviron || (envActive > 0 && - environ[0] == NULL))) { - /* Deactivate all environment variables. */ - if (envActive > 0) { - origEnviron = NULL; - __clean_env(false); - } - - /* - * Insert new environ into existing, yet deactivated, - * environment array. - */ - origEnviron = environ; - if (origEnviron != NULL) - for (env = origEnviron; *env != NULL; env++) { - if ((equals = strchr(*env, '=')) == NULL) { - __env_warnx(CorruptEnvValueMsg, *env, - strlen(*env)); - errno = EFAULT; - return (-1); - } - if (__setenv(*env, equals - *env, equals + 1, - 1) == -1) - return (-1); - } - } - - return (0); -} - - -/* - * The exposed setenv() that peforms a few tests before calling the function - * (__setenv()) that does the actual work of inserting a variable into the - * environment. - */ -int -setenv(const char *name, const char *value, int overwrite) -{ - size_t nameLen; - - /* Check for malformed name. */ - if (name == NULL || (nameLen = __strleneq(name)) == 0) { - errno = EINVAL; - return (-1); - } - - /* Initialize environment. */ - if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) - return (-1); - - return (__setenv(name, nameLen, value, overwrite)); -} - - -/* - * Insert a "name=value" string into the 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) -{ - 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 (__merge_environ() == -1 || (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 (__merge_environ() == -1 || (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 (0); -} |