getenv.c revision 253380
197785Spdeuskar/*- 297785Spdeuskar * Copyright (c) 2007-2009 Sean C. Farley <scf@FreeBSD.org> 397785Spdeuskar * All rights reserved. 497785Spdeuskar * 5146663Stackerman * Redistribution and use in source and binary forms, with or without 697785Spdeuskar * modification, are permitted provided that the following conditions 797785Spdeuskar * are met: 897785Spdeuskar * 1. Redistributions of source code must retain the above copyright 997785Spdeuskar * notice, this list of conditions and the following disclaimer, 1097785Spdeuskar * without modification, immediately at the beginning of the file. 11112472Spdeuskar * 2. Redistributions in binary form must reproduce the above copyright 12146663Stackerman * notice, this list of conditions and the following disclaimer in the 1397785Spdeuskar * documentation and/or other materials provided with the distribution. 1497785Spdeuskar * 1597785Spdeuskar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1697785Spdeuskar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1797785Spdeuskar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1897785Spdeuskar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1997785Spdeuskar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2097785Spdeuskar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21112472Spdeuskar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22112472Spdeuskar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2397785Spdeuskar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24146663Stackerman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25146663Stackerman */ 26146663Stackerman 2797785Spdeuskar#include <sys/cdefs.h> 28146663Stackerman__FBSDID("$FreeBSD: head/lib/libc/stdlib/getenv.c 253380 2013-07-16 07:26:46Z avg $"); 29146663Stackerman 3097785Spdeuskar 3197785Spdeuskar#include "namespace.h" 3297785Spdeuskar#include <sys/types.h> 33146663Stackerman#include <errno.h> 34146663Stackerman#include <stdbool.h> 3597785Spdeuskar#include <stddef.h> 36146663Stackerman#include <stdlib.h> 37146663Stackerman#include <string.h> 3897785Spdeuskar#include <unistd.h> 39146663Stackerman#include "un-namespace.h" 4097785Spdeuskar 4197785Spdeuskar 42146663Stackermanstatic const char CorruptEnvFindMsg[] = "environment corrupt; unable to find "; 4397785Spdeuskarstatic const char CorruptEnvValueMsg[] = 44146663Stackerman "environment corrupt; missing value for "; 4597785Spdeuskar 4697785Spdeuskar 47146663Stackerman/* 4897785Spdeuskar * Standard environ. environ variable is exposed to entire process. 49119509Spdeuskar * 5097785Spdeuskar * origEnviron: Upon cleanup on unloading of library or failure, this 5197785Spdeuskar * allows environ to return to as it was before. 5297785Spdeuskar * environSize: Number of variables environ can hold. Can only 53146663Stackerman * increase. 54146663Stackerman * intEnviron: Internally-built environ. Exposed via environ during 55112472Spdeuskar * (re)builds of the environment. 5697785Spdeuskar */ 57146663Stackermanextern char **environ; 58112472Spdeuskarstatic char **origEnviron; 5997785Spdeuskarstatic char **intEnviron = NULL; 60146663Stackermanstatic int environSize = 0; 6197785Spdeuskar 6297785Spdeuskar/* 6397785Spdeuskar * Array of environment variables built from environ. Each element records: 6497785Spdeuskar * name: Pointer to name=value string 65112472Spdeuskar * name length: Length of name not counting '=' character 6697785Spdeuskar * value: Pointer to value within same string as name 67112472Spdeuskar * value size: Size (not length) of space for value not counting the 6897785Spdeuskar * nul character 69146663Stackerman * active state: true/false value to signify whether variable is active. 70112472Spdeuskar * Useful since multiple variables with the same name can 7197785Spdeuskar * co-exist. At most, one variable can be active at any 72146663Stackerman * one time. 7397785Spdeuskar * putenv: Created from putenv() call. This memory must not be 74146663Stackerman * reused. 75146663Stackerman */ 7697785Spdeuskarstatic struct envVars { 77146663Stackerman size_t nameLen; 7897785Spdeuskar size_t valueSize; 79146663Stackerman char *name; 8097785Spdeuskar char *value; 81146663Stackerman bool active; 8297785Spdeuskar bool putenv; 83146663Stackerman} *envVars = NULL; 84146663Stackerman 85146663Stackerman/* 86146663Stackerman * Environment array information. 87112472Spdeuskar * 8897785Spdeuskar * envActive: Number of active variables in array. 89112472Spdeuskar * envVarsSize: Size of array. 9097785Spdeuskar * envVarsTotal: Number of total variables in array (active or not). 91112472Spdeuskar */ 9297785Spdeuskarstatic int envActive = 0; 93115878Spdeuskarstatic int envVarsSize = 0; 9497785Spdeuskarstatic int envVarsTotal = 0; 95146663Stackerman 96146663Stackerman 9797785Spdeuskar/* Deinitialization of new environment. */ 98112472Spdeuskarstatic void __attribute__ ((destructor)) __clean_env_destructor(void); 9997785Spdeuskar 100146663Stackerman 10197785Spdeuskar/* 102146663Stackerman * A simple version of warnx() to avoid the bloat of including stdio in static 103112472Spdeuskar * binaries. 10497785Spdeuskar */ 105112472Spdeuskarstatic void 106112472Spdeuskar__env_warnx(const char *msg, const char *name, size_t nameLen) 10797785Spdeuskar{ 108146663Stackerman static const char nl[] = "\n"; 109112472Spdeuskar static const char progSep[] = ": "; 11097785Spdeuskar 111112472Spdeuskar _write(STDERR_FILENO, _getprogname(), strlen(_getprogname())); 11297785Spdeuskar _write(STDERR_FILENO, progSep, sizeof(progSep) - 1); 113112472Spdeuskar _write(STDERR_FILENO, msg, strlen(msg)); 114146663Stackerman _write(STDERR_FILENO, name, nameLen); 115112472Spdeuskar _write(STDERR_FILENO, nl, sizeof(nl) - 1); 11697785Spdeuskar 117112472Spdeuskar return; 11897785Spdeuskar} 119112472Spdeuskar 12097785Spdeuskar 121112472Spdeuskar/* 122112472Spdeuskar * Inline strlen() for performance. Also, perform check for an equals sign. 123112472Spdeuskar * Cheaper here than peforming a strchr() later. 12497785Spdeuskar */ 125112472Spdeuskarstatic inline size_t 12697785Spdeuskar__strleneq(const char *str) 127146663Stackerman{ 128146663Stackerman const char *s; 12997785Spdeuskar 130112472Spdeuskar for (s = str; *s != '\0'; ++s) 131112472Spdeuskar if (*s == '=') 132112472Spdeuskar return (0); 133112472Spdeuskar 134112472Spdeuskar return (s - str); 135112472Spdeuskar} 136112472Spdeuskar 137112472Spdeuskar 138112472Spdeuskar/* 13997785Spdeuskar * Comparison of an environment name=value to a name. 14097785Spdeuskar */ 14197785Spdeuskarstatic inline bool 142146663Stackermanstrncmpeq(const char *nameValue, const char *name, size_t nameLen) 143146663Stackerman{ 14497785Spdeuskar if (strncmp(nameValue, name, nameLen) == 0 && nameValue[nameLen] == '=') 14597785Spdeuskar return (true); 146146663Stackerman 14797785Spdeuskar return (false); 14897785Spdeuskar} 149146663Stackerman 150146663Stackerman 15197785Spdeuskar/* 15297785Spdeuskar * Using environment, returns pointer to value associated with name, if any, 15397785Spdeuskar * else NULL. If the onlyActive flag is set to true, only variables that are 15497785Spdeuskar * active are returned else all are. 15597785Spdeuskar */ 15697785Spdeuskarstatic inline char * 15797785Spdeuskar__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive) 158146663Stackerman{ 15997785Spdeuskar int ndx; 16097785Spdeuskar 16197785Spdeuskar /* 16297785Spdeuskar * Find environment variable from end of array (more likely to be 16397785Spdeuskar * active). A variable created by putenv is always active, or it is not 16497785Spdeuskar * tracked in the array. 16597785Spdeuskar */ 16697785Spdeuskar for (ndx = *envNdx; ndx >= 0; ndx--) 16797785Spdeuskar if (envVars[ndx].putenv) { 16897785Spdeuskar if (strncmpeq(envVars[ndx].name, name, nameLen)) { 16997785Spdeuskar *envNdx = ndx; 17097785Spdeuskar return (envVars[ndx].name + nameLen + 17197785Spdeuskar sizeof ("=") - 1); 17297785Spdeuskar } 17397785Spdeuskar } else if ((!onlyActive || envVars[ndx].active) && 17497785Spdeuskar (envVars[ndx].nameLen == nameLen && 17597785Spdeuskar strncmpeq(envVars[ndx].name, name, nameLen))) { 176146663Stackerman *envNdx = ndx; 177146663Stackerman return (envVars[ndx].value); 178146663Stackerman } 179112472Spdeuskar 18097785Spdeuskar return (NULL); 18197785Spdeuskar} 182146663Stackerman 183146663Stackerman 18497785Spdeuskar/* 185146663Stackerman * Using environ, returns pointer to value associated with name, if any, else 186112472Spdeuskar * NULL. Used on the original environ passed into the program. 18797785Spdeuskar */ 188146663Stackermanstatic char * 189146663Stackerman__findenv_environ(const char *name, size_t nameLen) 190146663Stackerman{ 191146663Stackerman int envNdx; 192146663Stackerman 193146663Stackerman /* Find variable within environ. */ 194146663Stackerman for (envNdx = 0; environ[envNdx] != NULL; envNdx++) 195146663Stackerman if (strncmpeq(environ[envNdx], name, nameLen)) 196112472Spdeuskar return (&(environ[envNdx][nameLen + sizeof("=") - 1])); 19797785Spdeuskar 198112472Spdeuskar return (NULL); 19997785Spdeuskar} 200146663Stackerman 201112472Spdeuskar 202112472Spdeuskar/* 203112472Spdeuskar * Remove variable added by putenv() from variable tracking array. 20497785Spdeuskar */ 20597785Spdeuskarstatic void 206146663Stackerman__remove_putenv(int envNdx) 20797785Spdeuskar{ 208112472Spdeuskar envVarsTotal--; 20997785Spdeuskar if (envVarsTotal > envNdx) 210146663Stackerman memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]), 211112472Spdeuskar (envVarsTotal - envNdx) * sizeof (*envVars)); 21297785Spdeuskar memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars)); 213146663Stackerman 214112472Spdeuskar return; 21597785Spdeuskar} 216112472Spdeuskar 21797785Spdeuskar 218112472Spdeuskar/* 21997785Spdeuskar * Deallocate the environment built from environ as well as environ then set 220146663Stackerman * both to NULL. Eases debugging of memory leaks. 221112472Spdeuskar */ 22297785Spdeuskarstatic void 223146663Stackerman__clean_env(bool freeVars) 22497785Spdeuskar{ 225112472Spdeuskar int envNdx; 22697785Spdeuskar 227112472Spdeuskar /* Deallocate environment and environ if created by *env(). */ 228112472Spdeuskar if (envVars != NULL) { 229146663Stackerman for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) 230146663Stackerman /* Free variables or deactivate them. */ 231146663Stackerman if (envVars[envNdx].putenv) { 232146663Stackerman if (!freeVars) 233146663Stackerman __remove_putenv(envNdx); 234146663Stackerman } else { 235112472Spdeuskar if (freeVars) 23697785Spdeuskar free(envVars[envNdx].name); 237112472Spdeuskar else 238112472Spdeuskar envVars[envNdx].active = false; 239112472Spdeuskar } 240146663Stackerman if (freeVars) { 241146663Stackerman free(envVars); 242146663Stackerman envVars = NULL; 243146663Stackerman } else 244112472Spdeuskar envActive = 0; 245146663Stackerman 246146663Stackerman /* Restore original environ if it has not updated by program. */ 247146663Stackerman if (origEnviron != NULL) { 248112472Spdeuskar if (environ == intEnviron) 249146663Stackerman environ = origEnviron; 250146663Stackerman free(intEnviron); 251112472Spdeuskar intEnviron = NULL; 252146663Stackerman environSize = 0; 253146663Stackerman } 254146663Stackerman } 255112472Spdeuskar 256146663Stackerman return; 257112472Spdeuskar} 258146663Stackerman 259112472Spdeuskar 260146663Stackerman/* 261146663Stackerman * Using the environment, rebuild the environ array for use by other C library 262146663Stackerman * calls that depend upon it. 263146663Stackerman */ 264146663Stackermanstatic int 265146663Stackerman__rebuild_environ(int newEnvironSize) 266146663Stackerman{ 267146663Stackerman char **tmpEnviron; 268146663Stackerman int envNdx; 269146663Stackerman int environNdx; 270146663Stackerman int tmpEnvironSize; 271146663Stackerman 272146663Stackerman /* Resize environ. */ 273146663Stackerman if (newEnvironSize > environSize) { 27497785Spdeuskar tmpEnvironSize = newEnvironSize * 2; 27597785Spdeuskar tmpEnviron = realloc(intEnviron, sizeof (*intEnviron) * 276146663Stackerman (tmpEnvironSize + 1)); 277119509Spdeuskar if (tmpEnviron == NULL) 278146663Stackerman return (-1); 27997785Spdeuskar environSize = tmpEnvironSize; 280146663Stackerman intEnviron = tmpEnviron; 281146663Stackerman } 282146663Stackerman envActive = newEnvironSize; 283119509Spdeuskar 284119509Spdeuskar /* Assign active variables to environ. */ 285119509Spdeuskar for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--) 286146663Stackerman if (envVars[envNdx].active) 287119509Spdeuskar intEnviron[environNdx++] = envVars[envNdx].name; 288146663Stackerman intEnviron[environNdx] = NULL; 289146663Stackerman 290119509Spdeuskar /* Always set environ which may have been replaced by program. */ 291119509Spdeuskar environ = intEnviron; 292146663Stackerman 293146663Stackerman return (0); 294119509Spdeuskar} 295146663Stackerman 296119509Spdeuskar 297119509Spdeuskar/* 298119509Spdeuskar * Enlarge new environment. 299146663Stackerman */ 300119509Spdeuskarstatic inline bool 301146663Stackerman__enlarge_env(void) 302146663Stackerman{ 303146663Stackerman int newEnvVarsSize; 304146663Stackerman struct envVars *tmpEnvVars; 305146663Stackerman 306119509Spdeuskar envVarsTotal++; 307119509Spdeuskar if (envVarsTotal > envVarsSize) { 308146663Stackerman newEnvVarsSize = envVarsTotal * 2; 309119509Spdeuskar tmpEnvVars = realloc(envVars, sizeof (*envVars) * 310119509Spdeuskar newEnvVarsSize); 31197785Spdeuskar if (tmpEnvVars == NULL) { 31297785Spdeuskar envVarsTotal--; 31397785Spdeuskar return (false); 31497785Spdeuskar } 31597785Spdeuskar envVarsSize = newEnvVarsSize; 31697785Spdeuskar envVars = tmpEnvVars; 31797785Spdeuskar } 318146663Stackerman 319146663Stackerman return (true); 32097785Spdeuskar} 32197785Spdeuskar 32297785Spdeuskar 32397785Spdeuskar/* 324146663Stackerman * Using environ, build an environment for use by standard C library calls. 325146663Stackerman */ 326146663Stackermanstatic int 327146663Stackerman__build_env(void) 328146663Stackerman{ 329146663Stackerman char **env; 33097785Spdeuskar int activeNdx; 33197785Spdeuskar int envNdx; 33297785Spdeuskar int savedErrno; 333 size_t nameLen; 334 335 /* Check for non-existant environment. */ 336 if (environ == NULL || environ[0] == NULL) 337 return (0); 338 339 /* Count environment variables. */ 340 for (env = environ, envVarsTotal = 0; *env != NULL; env++) 341 envVarsTotal++; 342 envVarsSize = envVarsTotal * 2; 343 344 /* Create new environment. */ 345 envVars = calloc(1, sizeof (*envVars) * envVarsSize); 346 if (envVars == NULL) 347 goto Failure; 348 349 /* Copy environ values and keep track of them. */ 350 for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) { 351 envVars[envNdx].putenv = false; 352 envVars[envNdx].name = 353 strdup(environ[envVarsTotal - envNdx - 1]); 354 if (envVars[envNdx].name == NULL) 355 goto Failure; 356 envVars[envNdx].value = strchr(envVars[envNdx].name, '='); 357 if (envVars[envNdx].value != NULL) { 358 envVars[envNdx].value++; 359 envVars[envNdx].valueSize = 360 strlen(envVars[envNdx].value); 361 } else { 362 __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, 363 strlen(envVars[envNdx].name)); 364 errno = EFAULT; 365 goto Failure; 366 } 367 368 /* 369 * Find most current version of variable to make active. This 370 * will prevent multiple active variables from being created 371 * during this initialization phase. 372 */ 373 nameLen = envVars[envNdx].value - envVars[envNdx].name - 1; 374 envVars[envNdx].nameLen = nameLen; 375 activeNdx = envVarsTotal - 1; 376 if (__findenv(envVars[envNdx].name, nameLen, &activeNdx, 377 false) == NULL) { 378 __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name, 379 nameLen); 380 errno = EFAULT; 381 goto Failure; 382 } 383 envVars[activeNdx].active = true; 384 } 385 386 /* Create a new environ. */ 387 origEnviron = environ; 388 environ = NULL; 389 if (__rebuild_environ(envVarsTotal) == 0) 390 return (0); 391 392Failure: 393 savedErrno = errno; 394 __clean_env(true); 395 errno = savedErrno; 396 397 return (-1); 398} 399 400 401/* 402 * Destructor function with default argument to __clean_env(). 403 */ 404static void 405__clean_env_destructor(void) 406{ 407 __clean_env(true); 408 409 return; 410} 411 412 413/* 414 * Returns the value of a variable or NULL if none are found. 415 */ 416char * 417getenv(const char *name) 418{ 419 int envNdx; 420 size_t nameLen; 421 422 /* Check for malformed name. */ 423 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 424 errno = EINVAL; 425 return (NULL); 426 } 427 428 /* 429 * Variable search order: 430 * 1. Check for an empty environ. This allows an application to clear 431 * the environment. 432 * 2. Search the external environ array. 433 * 3. Search the internal environment. 434 * 435 * Since malloc() depends upon getenv(), getenv() must never cause the 436 * internal environment storage to be generated. 437 */ 438 if (environ == NULL || environ[0] == NULL) 439 return (NULL); 440 else if (envVars == NULL || environ != intEnviron) 441 return (__findenv_environ(name, nameLen)); 442 else { 443 envNdx = envVarsTotal - 1; 444 return (__findenv(name, nameLen, &envNdx, true)); 445 } 446} 447 448 449/* 450 * Set the value of a variable. Older settings are labeled as inactive. If an 451 * older setting has enough room to store the new value, it will be reused. No 452 * previous variables are ever freed here to avoid causing a segmentation fault 453 * in a user's code. 454 * 455 * The variables nameLen and valueLen are passed into here to allow the caller 456 * to calculate the length by means besides just strlen(). 457 */ 458static int 459__setenv(const char *name, size_t nameLen, const char *value, int overwrite) 460{ 461 bool reuse; 462 char *env; 463 int envNdx; 464 int newEnvActive; 465 size_t valueLen; 466 467 /* Find existing environment variable large enough to use. */ 468 envNdx = envVarsTotal - 1; 469 newEnvActive = envActive; 470 valueLen = strlen(value); 471 reuse = false; 472 if (__findenv(name, nameLen, &envNdx, false) != NULL) { 473 /* Deactivate entry if overwrite is allowed. */ 474 if (envVars[envNdx].active) { 475 if (overwrite == 0) 476 return (0); 477 envVars[envNdx].active = false; 478 newEnvActive--; 479 } 480 481 /* putenv() created variable cannot be reused. */ 482 if (envVars[envNdx].putenv) 483 __remove_putenv(envNdx); 484 485 /* Entry is large enough to reuse. */ 486 else if (envVars[envNdx].valueSize >= valueLen) 487 reuse = true; 488 } 489 490 /* Create new variable if none was found of sufficient size. */ 491 if (! reuse) { 492 /* Enlarge environment. */ 493 envNdx = envVarsTotal; 494 if (!__enlarge_env()) 495 return (-1); 496 497 /* Create environment entry. */ 498 envVars[envNdx].name = malloc(nameLen + sizeof ("=") + 499 valueLen); 500 if (envVars[envNdx].name == NULL) { 501 envVarsTotal--; 502 return (-1); 503 } 504 envVars[envNdx].nameLen = nameLen; 505 envVars[envNdx].valueSize = valueLen; 506 507 /* Save name of name/value pair. */ 508 env = stpncpy(envVars[envNdx].name, name, nameLen); 509 if ((envVars[envNdx].name)[nameLen] != '=') 510 env = stpcpy(env, "="); 511 } 512 else 513 env = envVars[envNdx].value; 514 515 /* Save value of name/value pair. */ 516 strcpy(env, value); 517 envVars[envNdx].value = env; 518 envVars[envNdx].active = true; 519 newEnvActive++; 520 521 /* No need to rebuild environ if an active variable was reused. */ 522 if (reuse && newEnvActive == envActive) 523 return (0); 524 else 525 return (__rebuild_environ(newEnvActive)); 526} 527 528 529/* 530 * If the program attempts to replace the array of environment variables 531 * (environ) environ or sets the first varible to NULL, then deactivate all 532 * variables and merge in the new list from environ. 533 */ 534static int 535__merge_environ(void) 536{ 537 char **env; 538 char *equals; 539 540 /* 541 * Internally-built environ has been replaced or cleared (detected by 542 * using the count of active variables against a NULL as the first value 543 * in environ). Clean up everything. 544 */ 545 if (intEnviron != NULL && (environ != intEnviron || (envActive > 0 && 546 environ[0] == NULL))) { 547 /* Deactivate all environment variables. */ 548 if (envActive > 0) { 549 origEnviron = NULL; 550 __clean_env(false); 551 } 552 553 /* 554 * Insert new environ into existing, yet deactivated, 555 * environment array. 556 */ 557 origEnviron = environ; 558 if (origEnviron != NULL) 559 for (env = origEnviron; *env != NULL; env++) { 560 if ((equals = strchr(*env, '=')) == NULL) { 561 __env_warnx(CorruptEnvValueMsg, *env, 562 strlen(*env)); 563 errno = EFAULT; 564 return (-1); 565 } 566 if (__setenv(*env, equals - *env, equals + 1, 567 1) == -1) 568 return (-1); 569 } 570 } 571 572 return (0); 573} 574 575 576/* 577 * The exposed setenv() that peforms a few tests before calling the function 578 * (__setenv()) that does the actual work of inserting a variable into the 579 * environment. 580 */ 581int 582setenv(const char *name, const char *value, int overwrite) 583{ 584 size_t nameLen; 585 586 /* Check for malformed name. */ 587 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 588 errno = EINVAL; 589 return (-1); 590 } 591 592 /* Initialize environment. */ 593 if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 594 return (-1); 595 596 return (__setenv(name, nameLen, value, overwrite)); 597} 598 599 600/* 601 * Insert a "name=value" string into the environment. Special settings must be 602 * made to keep setenv() from reusing this memory block and unsetenv() from 603 * allowing it to be tracked. 604 */ 605int 606putenv(char *string) 607{ 608 char *equals; 609 int envNdx; 610 int newEnvActive; 611 size_t nameLen; 612 613 /* Check for malformed argument. */ 614 if (string == NULL || (equals = strchr(string, '=')) == NULL || 615 (nameLen = equals - string) == 0) { 616 errno = EINVAL; 617 return (-1); 618 } 619 620 /* Initialize environment. */ 621 if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 622 return (-1); 623 624 /* Deactivate previous environment variable. */ 625 envNdx = envVarsTotal - 1; 626 newEnvActive = envActive; 627 if (__findenv(string, nameLen, &envNdx, true) != NULL) { 628 /* Reuse previous putenv slot. */ 629 if (envVars[envNdx].putenv) { 630 envVars[envNdx].name = string; 631 return (__rebuild_environ(envActive)); 632 } else { 633 newEnvActive--; 634 envVars[envNdx].active = false; 635 } 636 } 637 638 /* Enlarge environment. */ 639 envNdx = envVarsTotal; 640 if (!__enlarge_env()) 641 return (-1); 642 643 /* Create environment entry. */ 644 envVars[envNdx].name = string; 645 envVars[envNdx].nameLen = -1; 646 envVars[envNdx].value = NULL; 647 envVars[envNdx].valueSize = -1; 648 envVars[envNdx].putenv = true; 649 envVars[envNdx].active = true; 650 newEnvActive++; 651 652 return (__rebuild_environ(newEnvActive)); 653} 654 655 656/* 657 * Unset variable with the same name by flagging it as inactive. No variable is 658 * ever freed. 659 */ 660int 661unsetenv(const char *name) 662{ 663 int envNdx; 664 size_t nameLen; 665 int newEnvActive; 666 667 /* Check for malformed name. */ 668 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 669 errno = EINVAL; 670 return (-1); 671 } 672 673 /* Initialize environment. */ 674 if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 675 return (-1); 676 677 /* Deactivate specified variable. */ 678 /* Remove all occurrences. */ 679 envNdx = envVarsTotal - 1; 680 newEnvActive = envActive; 681 while (__findenv(name, nameLen, &envNdx, true) != NULL) { 682 envVars[envNdx].active = false; 683 if (envVars[envNdx].putenv) 684 __remove_putenv(envNdx); 685 envNdx--; 686 newEnvActive--; 687 } 688 if (newEnvActive != envActive) 689 __rebuild_environ(newEnvActive); 690 691 return (0); 692} 693