1171195Sscf/*- 2200190Sscf * Copyright (c) 2007-2009 Sean C. Farley <scf@FreeBSD.org> 3171195Sscf * All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 9171195Sscf * notice, this list of conditions and the following disclaimer, 10171195Sscf * without modification, immediately at the beginning of the file. 111573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer in the 131573Srgrimes * documentation and/or other materials provided with the distribution. 141573Srgrimes * 15171195Sscf * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16171195Sscf * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17171195Sscf * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18171195Sscf * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19171195Sscf * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20171195Sscf * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21171195Sscf * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22171195Sscf * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23171195Sscf * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24171195Sscf * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251573Srgrimes */ 26176632Sscf 27176632Sscf#include <sys/cdefs.h> 28176632Sscf__FBSDID("$FreeBSD: stable/10/lib/libc/stdlib/getenv.c 315415 2017-03-16 15:10:04Z pfg $"); 29176632Sscf 30176632Sscf 31176632Sscf#include "namespace.h" 32171195Sscf#include <sys/types.h> 33171195Sscf#include <errno.h> 34171195Sscf#include <stdbool.h> 35171195Sscf#include <stddef.h> 36171195Sscf#include <stdlib.h> 37171195Sscf#include <string.h> 38176632Sscf#include <unistd.h> 39176632Sscf#include "un-namespace.h" 401573Srgrimes 41171195Sscf 42176632Sscfstatic const char CorruptEnvFindMsg[] = "environment corrupt; unable to find "; 43171525Sscfstatic const char CorruptEnvValueMsg[] = 44176632Sscf "environment corrupt; missing value for "; 45171525Sscf 46171525Sscf 47171195Sscf/* 48171195Sscf * Standard environ. environ variable is exposed to entire process. 49171195Sscf * 50171195Sscf * origEnviron: Upon cleanup on unloading of library or failure, this 51171195Sscf * allows environ to return to as it was before. 52171195Sscf * environSize: Number of variables environ can hold. Can only 53171195Sscf * increase. 54171525Sscf * intEnviron: Internally-built environ. Exposed via environ during 55171525Sscf * (re)builds of the environment. 56171195Sscf */ 57171195Sscfextern char **environ; 58171195Sscfstatic char **origEnviron; 59171525Sscfstatic char **intEnviron = NULL; 60171195Sscfstatic int environSize = 0; 611573Srgrimes 621573Srgrimes/* 63171195Sscf * Array of environment variables built from environ. Each element records: 64171195Sscf * name: Pointer to name=value string 65171195Sscf * name length: Length of name not counting '=' character 66171195Sscf * value: Pointer to value within same string as name 67171195Sscf * value size: Size (not length) of space for value not counting the 68171195Sscf * nul character 69171195Sscf * active state: true/false value to signify whether variable is active. 70171195Sscf * Useful since multiple variables with the same name can 71171195Sscf * co-exist. At most, one variable can be active at any 72171195Sscf * one time. 73171195Sscf * putenv: Created from putenv() call. This memory must not be 74171195Sscf * reused. 75171195Sscf */ 76171195Sscfstatic struct envVars { 77171195Sscf size_t nameLen; 78171195Sscf size_t valueSize; 79171195Sscf char *name; 80171195Sscf char *value; 81171195Sscf bool active; 82171195Sscf bool putenv; 83171195Sscf} *envVars = NULL; 84171195Sscf 85171195Sscf/* 86171195Sscf * Environment array information. 871573Srgrimes * 88171195Sscf * envActive: Number of active variables in array. 89171195Sscf * envVarsSize: Size of array. 90171195Sscf * envVarsTotal: Number of total variables in array (active or not). 911573Srgrimes */ 92171195Sscfstatic int envActive = 0; 93171195Sscfstatic int envVarsSize = 0; 94171195Sscfstatic int envVarsTotal = 0; 95171195Sscf 96171195Sscf 97171195Sscf/* Deinitialization of new environment. */ 98171525Sscfstatic void __attribute__ ((destructor)) __clean_env_destructor(void); 99171195Sscf 100171195Sscf 101171195Sscf/* 102176632Sscf * A simple version of warnx() to avoid the bloat of including stdio in static 103176632Sscf * binaries. 104176632Sscf */ 105176632Sscfstatic void 106176632Sscf__env_warnx(const char *msg, const char *name, size_t nameLen) 107176632Sscf{ 108176632Sscf static const char nl[] = "\n"; 109176632Sscf static const char progSep[] = ": "; 110176632Sscf 111176632Sscf _write(STDERR_FILENO, _getprogname(), strlen(_getprogname())); 112176632Sscf _write(STDERR_FILENO, progSep, sizeof(progSep) - 1); 113176632Sscf _write(STDERR_FILENO, msg, strlen(msg)); 114176632Sscf _write(STDERR_FILENO, name, nameLen); 115176632Sscf _write(STDERR_FILENO, nl, sizeof(nl) - 1); 116176632Sscf 117176632Sscf return; 118176632Sscf} 119176632Sscf 120176632Sscf 121176632Sscf/* 122171195Sscf * Inline strlen() for performance. Also, perform check for an equals sign. 123171195Sscf * Cheaper here than peforming a strchr() later. 124171195Sscf */ 125171195Sscfstatic inline size_t 126171195Sscf__strleneq(const char *str) 1271573Srgrimes{ 128171195Sscf const char *s; 1291573Srgrimes 130171195Sscf for (s = str; *s != '\0'; ++s) 131171195Sscf if (*s == '=') 132171195Sscf return (0); 133171195Sscf 134171195Sscf return (s - str); 135171195Sscf} 136171195Sscf 137171195Sscf 138171195Sscf/* 139171195Sscf * Comparison of an environment name=value to a name. 140171195Sscf */ 141171195Sscfstatic inline bool 142171195Sscfstrncmpeq(const char *nameValue, const char *name, size_t nameLen) 143171195Sscf{ 144171195Sscf if (strncmp(nameValue, name, nameLen) == 0 && nameValue[nameLen] == '=') 145171195Sscf return (true); 146171195Sscf 147171195Sscf return (false); 148171195Sscf} 149171195Sscf 150171195Sscf 151171195Sscf/* 152171195Sscf * Using environment, returns pointer to value associated with name, if any, 153171195Sscf * else NULL. If the onlyActive flag is set to true, only variables that are 154171195Sscf * active are returned else all are. 155171195Sscf */ 156171195Sscfstatic inline char * 157171195Sscf__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive) 158171195Sscf{ 159171195Sscf int ndx; 160171195Sscf 161171195Sscf /* 162171195Sscf * Find environment variable from end of array (more likely to be 163200190Sscf * active). A variable created by putenv is always active, or it is not 164171195Sscf * tracked in the array. 165171195Sscf */ 166171195Sscf for (ndx = *envNdx; ndx >= 0; ndx--) 167171195Sscf if (envVars[ndx].putenv) { 168171195Sscf if (strncmpeq(envVars[ndx].name, name, nameLen)) { 169171195Sscf *envNdx = ndx; 170171195Sscf return (envVars[ndx].name + nameLen + 171171195Sscf sizeof ("=") - 1); 172171195Sscf } 173171195Sscf } else if ((!onlyActive || envVars[ndx].active) && 174171195Sscf (envVars[ndx].nameLen == nameLen && 175171195Sscf strncmpeq(envVars[ndx].name, name, nameLen))) { 176171195Sscf *envNdx = ndx; 177171195Sscf return (envVars[ndx].value); 178171195Sscf } 179171195Sscf 180171195Sscf return (NULL); 181171195Sscf} 182171195Sscf 183171195Sscf 184171195Sscf/* 185171195Sscf * Using environ, returns pointer to value associated with name, if any, else 186171195Sscf * NULL. Used on the original environ passed into the program. 187171195Sscf */ 188171195Sscfstatic char * 189171195Sscf__findenv_environ(const char *name, size_t nameLen) 190171195Sscf{ 191171195Sscf int envNdx; 192171195Sscf 193171195Sscf /* Find variable within environ. */ 194171195Sscf for (envNdx = 0; environ[envNdx] != NULL; envNdx++) 195171195Sscf if (strncmpeq(environ[envNdx], name, nameLen)) 196171195Sscf return (&(environ[envNdx][nameLen + sizeof("=") - 1])); 197171195Sscf 198171195Sscf return (NULL); 199171195Sscf} 200171195Sscf 201171195Sscf 202171195Sscf/* 203171525Sscf * Remove variable added by putenv() from variable tracking array. 204171525Sscf */ 205171525Sscfstatic void 206171525Sscf__remove_putenv(int envNdx) 207171525Sscf{ 208171525Sscf envVarsTotal--; 209171525Sscf if (envVarsTotal > envNdx) 210171525Sscf memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]), 211171525Sscf (envVarsTotal - envNdx) * sizeof (*envVars)); 212171525Sscf memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars)); 213171525Sscf 214171525Sscf return; 215171525Sscf} 216171525Sscf 217171525Sscf 218171525Sscf/* 219171525Sscf * Deallocate the environment built from environ as well as environ then set 220171525Sscf * both to NULL. Eases debugging of memory leaks. 221171525Sscf */ 222171525Sscfstatic void 223171525Sscf__clean_env(bool freeVars) 224171525Sscf{ 225171525Sscf int envNdx; 226171525Sscf 227171525Sscf /* Deallocate environment and environ if created by *env(). */ 228171525Sscf if (envVars != NULL) { 229171525Sscf for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) 230171525Sscf /* Free variables or deactivate them. */ 231171525Sscf if (envVars[envNdx].putenv) { 232171525Sscf if (!freeVars) 233171525Sscf __remove_putenv(envNdx); 234171525Sscf } else { 235171525Sscf if (freeVars) 236171525Sscf free(envVars[envNdx].name); 237171525Sscf else 238171525Sscf envVars[envNdx].active = false; 239171525Sscf } 240171525Sscf if (freeVars) { 241171525Sscf free(envVars); 242171525Sscf envVars = NULL; 243171525Sscf } else 244171525Sscf envActive = 0; 245171525Sscf 246171525Sscf /* Restore original environ if it has not updated by program. */ 247171525Sscf if (origEnviron != NULL) { 248171525Sscf if (environ == intEnviron) 249171525Sscf environ = origEnviron; 250171525Sscf free(intEnviron); 251171525Sscf intEnviron = NULL; 252171525Sscf environSize = 0; 253171525Sscf } 254171525Sscf } 255171525Sscf 256171525Sscf return; 257171525Sscf} 258171525Sscf 259171525Sscf 260171525Sscf/* 261171195Sscf * Using the environment, rebuild the environ array for use by other C library 262171195Sscf * calls that depend upon it. 263171195Sscf */ 264171195Sscfstatic int 265171195Sscf__rebuild_environ(int newEnvironSize) 266171195Sscf{ 267171195Sscf char **tmpEnviron; 268171195Sscf int envNdx; 269171195Sscf int environNdx; 270171195Sscf int tmpEnvironSize; 271171195Sscf 272171195Sscf /* Resize environ. */ 273171195Sscf if (newEnvironSize > environSize) { 274171195Sscf tmpEnvironSize = newEnvironSize * 2; 275171525Sscf tmpEnviron = realloc(intEnviron, sizeof (*intEnviron) * 276171195Sscf (tmpEnvironSize + 1)); 277171195Sscf if (tmpEnviron == NULL) 278171195Sscf return (-1); 279171195Sscf environSize = tmpEnvironSize; 280171525Sscf intEnviron = tmpEnviron; 281171195Sscf } 282171195Sscf envActive = newEnvironSize; 283171195Sscf 284171195Sscf /* Assign active variables to environ. */ 285171195Sscf for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--) 286171195Sscf if (envVars[envNdx].active) 287171525Sscf intEnviron[environNdx++] = envVars[envNdx].name; 288171525Sscf intEnviron[environNdx] = NULL; 289171195Sscf 290171525Sscf /* Always set environ which may have been replaced by program. */ 291171525Sscf environ = intEnviron; 292171525Sscf 293171195Sscf return (0); 294171195Sscf} 295171195Sscf 296171195Sscf 297171195Sscf/* 298171195Sscf * Enlarge new environment. 299171195Sscf */ 300171195Sscfstatic inline bool 301171195Sscf__enlarge_env(void) 302171195Sscf{ 303171195Sscf int newEnvVarsSize; 304171195Sscf struct envVars *tmpEnvVars; 305171195Sscf 306171195Sscf envVarsTotal++; 307171195Sscf if (envVarsTotal > envVarsSize) { 308171195Sscf newEnvVarsSize = envVarsTotal * 2; 309171195Sscf tmpEnvVars = realloc(envVars, sizeof (*envVars) * 310171195Sscf newEnvVarsSize); 311171195Sscf if (tmpEnvVars == NULL) { 312171195Sscf envVarsTotal--; 313171195Sscf return (false); 3141573Srgrimes } 315171195Sscf envVarsSize = newEnvVarsSize; 316171195Sscf envVars = tmpEnvVars; 31711549Sdg } 318171195Sscf 319171195Sscf return (true); 3201573Srgrimes} 32111549Sdg 322171195Sscf 32311549Sdg/* 324171195Sscf * Using environ, build an environment for use by standard C library calls. 32511549Sdg */ 326171195Sscfstatic int 327171195Sscf__build_env(void) 328171195Sscf{ 329171195Sscf char **env; 330171195Sscf int activeNdx; 331171195Sscf int envNdx; 332171195Sscf int savedErrno; 333171195Sscf size_t nameLen; 334171195Sscf 335171195Sscf /* Check for non-existant environment. */ 336171525Sscf if (environ == NULL || environ[0] == NULL) 337171195Sscf return (0); 338171195Sscf 339171195Sscf /* Count environment variables. */ 340171195Sscf for (env = environ, envVarsTotal = 0; *env != NULL; env++) 341171195Sscf envVarsTotal++; 342171195Sscf envVarsSize = envVarsTotal * 2; 343171195Sscf 344171195Sscf /* Create new environment. */ 345315415Spfg envVars = calloc(envVarsSize, sizeof(*envVars)); 346171195Sscf if (envVars == NULL) 347171195Sscf goto Failure; 348171195Sscf 349171195Sscf /* Copy environ values and keep track of them. */ 350171195Sscf for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) { 351171195Sscf envVars[envNdx].putenv = false; 352171195Sscf envVars[envNdx].name = 353171195Sscf strdup(environ[envVarsTotal - envNdx - 1]); 354171195Sscf if (envVars[envNdx].name == NULL) 355171195Sscf goto Failure; 356199987Sgreen envVars[envNdx].value = strchr(envVars[envNdx].name, '='); 357199987Sgreen if (envVars[envNdx].value != NULL) { 358199987Sgreen envVars[envNdx].value++; 359199987Sgreen envVars[envNdx].valueSize = 360199987Sgreen strlen(envVars[envNdx].value); 361199987Sgreen } else { 362199987Sgreen __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, 363199987Sgreen strlen(envVars[envNdx].name)); 364200198Sscf errno = EFAULT; 365200198Sscf goto Failure; 366199987Sgreen } 367199987Sgreen 368171195Sscf /* 369171195Sscf * Find most current version of variable to make active. This 370171195Sscf * will prevent multiple active variables from being created 371171195Sscf * during this initialization phase. 372171195Sscf */ 373171195Sscf nameLen = envVars[envNdx].value - envVars[envNdx].name - 1; 374171195Sscf envVars[envNdx].nameLen = nameLen; 375171195Sscf activeNdx = envVarsTotal - 1; 376171195Sscf if (__findenv(envVars[envNdx].name, nameLen, &activeNdx, 377171195Sscf false) == NULL) { 378176632Sscf __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name, 379176632Sscf nameLen); 380200198Sscf errno = EFAULT; 381200198Sscf goto Failure; 382171195Sscf } 383171195Sscf envVars[activeNdx].active = true; 384171195Sscf } 385171195Sscf 386171195Sscf /* Create a new environ. */ 387171195Sscf origEnviron = environ; 388171195Sscf environ = NULL; 389171525Sscf if (__rebuild_environ(envVarsTotal) == 0) 390171525Sscf return (0); 391171195Sscf 392171195SscfFailure: 393171195Sscf savedErrno = errno; 394171525Sscf __clean_env(true); 395171195Sscf errno = savedErrno; 396171195Sscf 397171195Sscf return (-1); 398171195Sscf} 399171195Sscf 400171195Sscf 401171195Sscf/* 402171525Sscf * Destructor function with default argument to __clean_env(). 403171195Sscf */ 404171195Sscfstatic void 405171525Sscf__clean_env_destructor(void) 406171195Sscf{ 407171525Sscf __clean_env(true); 408171195Sscf 409171195Sscf return; 410171195Sscf} 411171195Sscf 412171195Sscf 413171195Sscf/* 414171195Sscf * Returns the value of a variable or NULL if none are found. 415171195Sscf */ 41611549Sdgchar * 417171195Sscfgetenv(const char *name) 41811549Sdg{ 419171195Sscf int envNdx; 420171195Sscf size_t nameLen; 42111549Sdg 422171195Sscf /* Check for malformed name. */ 423171195Sscf if (name == NULL || (nameLen = __strleneq(name)) == 0) { 424171195Sscf errno = EINVAL; 425171195Sscf return (NULL); 426171195Sscf } 427171195Sscf 428171525Sscf /* 429200190Sscf * Variable search order: 430200190Sscf * 1. Check for an empty environ. This allows an application to clear 431200190Sscf * the environment. 432200190Sscf * 2. Search the external environ array. 433200190Sscf * 3. Search the internal environment. 434199987Sgreen * 435200190Sscf * Since malloc() depends upon getenv(), getenv() must never cause the 436200190Sscf * internal environment storage to be generated. 437171525Sscf */ 438199987Sgreen if (environ == NULL || environ[0] == NULL) 439199987Sgreen return (NULL); 440199987Sgreen else if (envVars == NULL || environ != intEnviron) 441199983Sgreen return (__findenv_environ(name, nameLen)); 442199987Sgreen else { 443199987Sgreen envNdx = envVarsTotal - 1; 444199987Sgreen return (__findenv(name, nameLen, &envNdx, true)); 445199987Sgreen } 44611549Sdg} 447171195Sscf 448171195Sscf 449171195Sscf/* 450171195Sscf * Set the value of a variable. Older settings are labeled as inactive. If an 451171195Sscf * older setting has enough room to store the new value, it will be reused. No 452171195Sscf * previous variables are ever freed here to avoid causing a segmentation fault 453171195Sscf * in a user's code. 454171525Sscf * 455171525Sscf * The variables nameLen and valueLen are passed into here to allow the caller 456171525Sscf * to calculate the length by means besides just strlen(). 457171195Sscf */ 458171525Sscfstatic int 459171525Sscf__setenv(const char *name, size_t nameLen, const char *value, int overwrite) 460171195Sscf{ 461171195Sscf bool reuse; 462171195Sscf char *env; 463171195Sscf int envNdx; 464171195Sscf int newEnvActive; 465171195Sscf size_t valueLen; 466171195Sscf 467171195Sscf /* Find existing environment variable large enough to use. */ 468171195Sscf envNdx = envVarsTotal - 1; 469171195Sscf newEnvActive = envActive; 470171195Sscf valueLen = strlen(value); 471171195Sscf reuse = false; 472171195Sscf if (__findenv(name, nameLen, &envNdx, false) != NULL) { 473171195Sscf /* Deactivate entry if overwrite is allowed. */ 474171195Sscf if (envVars[envNdx].active) { 475171195Sscf if (overwrite == 0) 476171195Sscf return (0); 477171195Sscf envVars[envNdx].active = false; 478171195Sscf newEnvActive--; 479171195Sscf } 480171195Sscf 481171195Sscf /* putenv() created variable cannot be reused. */ 482171195Sscf if (envVars[envNdx].putenv) 483171195Sscf __remove_putenv(envNdx); 484171195Sscf 485171195Sscf /* Entry is large enough to reuse. */ 486171195Sscf else if (envVars[envNdx].valueSize >= valueLen) 487171195Sscf reuse = true; 488171195Sscf } 489171195Sscf 490171195Sscf /* Create new variable if none was found of sufficient size. */ 491171195Sscf if (! reuse) { 492171195Sscf /* Enlarge environment. */ 493171195Sscf envNdx = envVarsTotal; 494171195Sscf if (!__enlarge_env()) 495171195Sscf return (-1); 496171195Sscf 497171195Sscf /* Create environment entry. */ 498171195Sscf envVars[envNdx].name = malloc(nameLen + sizeof ("=") + 499171195Sscf valueLen); 500171195Sscf if (envVars[envNdx].name == NULL) { 501171195Sscf envVarsTotal--; 502171195Sscf return (-1); 503171195Sscf } 504171195Sscf envVars[envNdx].nameLen = nameLen; 505171195Sscf envVars[envNdx].valueSize = valueLen; 506171195Sscf 507171195Sscf /* Save name of name/value pair. */ 508253380Savg env = stpncpy(envVars[envNdx].name, name, nameLen); 509253413Savg *env++ = '='; 510171195Sscf } 511171195Sscf else 512171195Sscf env = envVars[envNdx].value; 513171195Sscf 514171195Sscf /* Save value of name/value pair. */ 515171195Sscf strcpy(env, value); 516171195Sscf envVars[envNdx].value = env; 517171195Sscf envVars[envNdx].active = true; 518171195Sscf newEnvActive++; 519171195Sscf 520172191Sscf /* No need to rebuild environ if an active variable was reused. */ 521172191Sscf if (reuse && newEnvActive == envActive) 522171195Sscf return (0); 523171195Sscf else 524171195Sscf return (__rebuild_environ(newEnvActive)); 525171195Sscf} 526171195Sscf 527171195Sscf 528171195Sscf/* 529171525Sscf * If the program attempts to replace the array of environment variables 530181150Sscf * (environ) environ or sets the first varible to NULL, then deactivate all 531181150Sscf * variables and merge in the new list from environ. 532171525Sscf */ 533171525Sscfstatic int 534171525Sscf__merge_environ(void) 535171525Sscf{ 536171525Sscf char **env; 537171525Sscf char *equals; 538171525Sscf 539181150Sscf /* 540181266Sscf * Internally-built environ has been replaced or cleared (detected by 541181266Sscf * using the count of active variables against a NULL as the first value 542181266Sscf * in environ). Clean up everything. 543181150Sscf */ 544181266Sscf if (intEnviron != NULL && (environ != intEnviron || (envActive > 0 && 545181266Sscf environ[0] == NULL))) { 546171525Sscf /* Deactivate all environment variables. */ 547171525Sscf if (envActive > 0) { 548171525Sscf origEnviron = NULL; 549171525Sscf __clean_env(false); 550171525Sscf } 551171525Sscf 552171525Sscf /* 553171525Sscf * Insert new environ into existing, yet deactivated, 554171525Sscf * environment array. 555171525Sscf */ 556171525Sscf origEnviron = environ; 557171525Sscf if (origEnviron != NULL) 558171525Sscf for (env = origEnviron; *env != NULL; env++) { 559171525Sscf if ((equals = strchr(*env, '=')) == NULL) { 560176632Sscf __env_warnx(CorruptEnvValueMsg, *env, 561176632Sscf strlen(*env)); 562200198Sscf errno = EFAULT; 563200198Sscf return (-1); 564171525Sscf } 565171525Sscf if (__setenv(*env, equals - *env, equals + 1, 566171525Sscf 1) == -1) 567171525Sscf return (-1); 568171525Sscf } 569171525Sscf } 570171525Sscf 571171525Sscf return (0); 572171525Sscf} 573171525Sscf 574171525Sscf 575171525Sscf/* 576171525Sscf * The exposed setenv() that peforms a few tests before calling the function 577171525Sscf * (__setenv()) that does the actual work of inserting a variable into the 578171525Sscf * environment. 579171525Sscf */ 580171525Sscfint 581171525Sscfsetenv(const char *name, const char *value, int overwrite) 582171525Sscf{ 583171525Sscf size_t nameLen; 584171525Sscf 585171525Sscf /* Check for malformed name. */ 586171525Sscf if (name == NULL || (nameLen = __strleneq(name)) == 0) { 587171525Sscf errno = EINVAL; 588171525Sscf return (-1); 589171525Sscf } 590171525Sscf 591171525Sscf /* Initialize environment. */ 592171525Sscf if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 593171525Sscf return (-1); 594171525Sscf 595171525Sscf return (__setenv(name, nameLen, value, overwrite)); 596171525Sscf} 597171525Sscf 598171525Sscf 599171525Sscf/* 600171525Sscf * Insert a "name=value" string into the environment. Special settings must be 601171195Sscf * made to keep setenv() from reusing this memory block and unsetenv() from 602171195Sscf * allowing it to be tracked. 603171195Sscf */ 604171195Sscfint 605171195Sscfputenv(char *string) 606171195Sscf{ 607171195Sscf char *equals; 608171195Sscf int envNdx; 609171195Sscf int newEnvActive; 610171195Sscf size_t nameLen; 611171195Sscf 612171195Sscf /* Check for malformed argument. */ 613171195Sscf if (string == NULL || (equals = strchr(string, '=')) == NULL || 614171195Sscf (nameLen = equals - string) == 0) { 615171195Sscf errno = EINVAL; 616171195Sscf return (-1); 617171195Sscf } 618171195Sscf 619171195Sscf /* Initialize environment. */ 620171525Sscf if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 621171195Sscf return (-1); 622171195Sscf 623171195Sscf /* Deactivate previous environment variable. */ 624171195Sscf envNdx = envVarsTotal - 1; 625171195Sscf newEnvActive = envActive; 626171195Sscf if (__findenv(string, nameLen, &envNdx, true) != NULL) { 627171195Sscf /* Reuse previous putenv slot. */ 628171195Sscf if (envVars[envNdx].putenv) { 629171195Sscf envVars[envNdx].name = string; 630171195Sscf return (__rebuild_environ(envActive)); 631171195Sscf } else { 632171195Sscf newEnvActive--; 633171195Sscf envVars[envNdx].active = false; 634171195Sscf } 635171195Sscf } 636171195Sscf 637171195Sscf /* Enlarge environment. */ 638171195Sscf envNdx = envVarsTotal; 639171195Sscf if (!__enlarge_env()) 640171195Sscf return (-1); 641171195Sscf 642171195Sscf /* Create environment entry. */ 643171195Sscf envVars[envNdx].name = string; 644171195Sscf envVars[envNdx].nameLen = -1; 645171195Sscf envVars[envNdx].value = NULL; 646171195Sscf envVars[envNdx].valueSize = -1; 647171195Sscf envVars[envNdx].putenv = true; 648171195Sscf envVars[envNdx].active = true; 649171195Sscf newEnvActive++; 650171195Sscf 651171195Sscf return (__rebuild_environ(newEnvActive)); 652171195Sscf} 653171195Sscf 654171195Sscf 655171195Sscf/* 656171195Sscf * Unset variable with the same name by flagging it as inactive. No variable is 657171195Sscf * ever freed. 658171195Sscf */ 659171195Sscfint 660171195Sscfunsetenv(const char *name) 661171195Sscf{ 662171195Sscf int envNdx; 663171195Sscf size_t nameLen; 664241154Sache int newEnvActive; 665171195Sscf 666171195Sscf /* Check for malformed name. */ 667171195Sscf if (name == NULL || (nameLen = __strleneq(name)) == 0) { 668171195Sscf errno = EINVAL; 669171195Sscf return (-1); 670171195Sscf } 671171195Sscf 672171195Sscf /* Initialize environment. */ 673171525Sscf if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 674171195Sscf return (-1); 675171195Sscf 676171195Sscf /* Deactivate specified variable. */ 677241154Sache /* Remove all occurrences. */ 678171195Sscf envNdx = envVarsTotal - 1; 679241154Sache newEnvActive = envActive; 680241137Sache while (__findenv(name, nameLen, &envNdx, true) != NULL) { 681171195Sscf envVars[envNdx].active = false; 682171195Sscf if (envVars[envNdx].putenv) 683171195Sscf __remove_putenv(envNdx); 684241154Sache envNdx--; 685241154Sache newEnvActive--; 686171195Sscf } 687241154Sache if (newEnvActive != envActive) 688241154Sache __rebuild_environ(newEnvActive); 689171195Sscf 690171195Sscf return (0); 691171195Sscf} 692