getenv.c (171195) | getenv.c (171525) |
---|---|
1/*- 2 * Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 19 unchanged lines hidden (view full) --- 28#include <errno.h> 29#include <stdbool.h> 30#include <stddef.h> 31#include <stdlib.h> 32#include <string.h> 33 34 35#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2007 Sean C. Farley <scf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 19 unchanged lines hidden (view full) --- 28#include <errno.h> 29#include <stdbool.h> 30#include <stddef.h> 31#include <stdlib.h> 32#include <string.h> 33 34 35#include <sys/cdefs.h> |
36__FBSDID("$FreeBSD: head/lib/libc/stdlib/getenv.c 171195 2007-07-04 00:00:41Z scf $"); | 36__FBSDID("$FreeBSD: head/lib/libc/stdlib/getenv.c 171525 2007-07-20 23:30:13Z scf $"); |
37 38 | 37 38 |
39static const char CorruptEnvFindMsg[] = 40 "environment corrupt; unable to find %.*s"; 41static const char CorruptEnvValueMsg[] = 42 "environment corrupt; missing value for %s"; 43 44 |
|
39/* 40 * Standard environ. environ variable is exposed to entire process. 41 * 42 * origEnviron: Upon cleanup on unloading of library or failure, this 43 * allows environ to return to as it was before. 44 * environSize: Number of variables environ can hold. Can only 45 * increase. | 45/* 46 * Standard environ. environ variable is exposed to entire process. 47 * 48 * origEnviron: Upon cleanup on unloading of library or failure, this 49 * allows environ to return to as it was before. 50 * environSize: Number of variables environ can hold. Can only 51 * increase. |
52 * intEnviron: Internally-built environ. Exposed via environ during 53 * (re)builds of the environment. |
|
46 */ 47extern char **environ; 48static char **origEnviron; | 54 */ 55extern char **environ; 56static char **origEnviron; |
57static char **intEnviron = NULL; |
|
49static int environSize = 0; 50 51/* 52 * Array of environment variables built from environ. Each element records: 53 * name: Pointer to name=value string 54 * name length: Length of name not counting '=' character 55 * value: Pointer to value within same string as name 56 * value size: Size (not length) of space for value not counting the --- 22 unchanged lines hidden (view full) --- 79 * envVarsTotal: Number of total variables in array (active or not). 80 */ 81static int envActive = 0; 82static int envVarsSize = 0; 83static int envVarsTotal = 0; 84 85 86/* Deinitialization of new environment. */ | 58static int environSize = 0; 59 60/* 61 * Array of environment variables built from environ. Each element records: 62 * name: Pointer to name=value string 63 * name length: Length of name not counting '=' character 64 * value: Pointer to value within same string as name 65 * value size: Size (not length) of space for value not counting the --- 22 unchanged lines hidden (view full) --- 88 * envVarsTotal: Number of total variables in array (active or not). 89 */ 90static int envActive = 0; 91static int envVarsSize = 0; 92static int envVarsTotal = 0; 93 94 95/* Deinitialization of new environment. */ |
87static void __attribute__ ((destructor)) __clean_env(void); | 96static void __attribute__ ((destructor)) __clean_env_destructor(void); |
88 89 90/* 91 * Inline strlen() for performance. Also, perform check for an equals sign. 92 * Cheaper here than peforming a strchr() later. 93 */ 94static inline size_t 95__strleneq(const char *str) --- 72 unchanged lines hidden (view full) --- 168 if (strncmpeq(environ[envNdx], name, nameLen)) 169 return (&(environ[envNdx][nameLen + sizeof("=") - 1])); 170 171 return (NULL); 172} 173 174 175/* | 97 98 99/* 100 * Inline strlen() for performance. Also, perform check for an equals sign. 101 * Cheaper here than peforming a strchr() later. 102 */ 103static inline size_t 104__strleneq(const char *str) --- 72 unchanged lines hidden (view full) --- 177 if (strncmpeq(environ[envNdx], name, nameLen)) 178 return (&(environ[envNdx][nameLen + sizeof("=") - 1])); 179 180 return (NULL); 181} 182 183 184/* |
185 * Remove variable added by putenv() from variable tracking array. 186 */ 187static void 188__remove_putenv(int envNdx) 189{ 190 envVarsTotal--; 191 if (envVarsTotal > envNdx) 192 memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]), 193 (envVarsTotal - envNdx) * sizeof (*envVars)); 194 memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars)); 195 196 return; 197} 198 199 200/* 201 * Deallocate the environment built from environ as well as environ then set 202 * both to NULL. Eases debugging of memory leaks. 203 */ 204static void 205__clean_env(bool freeVars) 206{ 207 int envNdx; 208 209 /* Deallocate environment and environ if created by *env(). */ 210 if (envVars != NULL) { 211 for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) 212 /* Free variables or deactivate them. */ 213 if (envVars[envNdx].putenv) { 214 if (!freeVars) 215 __remove_putenv(envNdx); 216 } else { 217 if (freeVars) 218 free(envVars[envNdx].name); 219 else 220 envVars[envNdx].active = false; 221 } 222 if (freeVars) { 223 free(envVars); 224 envVars = NULL; 225 } else 226 envActive = 0; 227 228 /* Restore original environ if it has not updated by program. */ 229 if (origEnviron != NULL) { 230 if (environ == intEnviron) 231 environ = origEnviron; 232 free(intEnviron); 233 intEnviron = NULL; 234 environSize = 0; 235 } 236 } 237 238 return; 239} 240 241 242/* |
|
176 * Using the environment, rebuild the environ array for use by other C library 177 * calls that depend upon it. 178 */ 179static int 180__rebuild_environ(int newEnvironSize) 181{ 182 char **tmpEnviron; 183 int envNdx; 184 int environNdx; 185 int tmpEnvironSize; 186 187 /* Resize environ. */ 188 if (newEnvironSize > environSize) { 189 tmpEnvironSize = newEnvironSize * 2; | 243 * Using the environment, rebuild the environ array for use by other C library 244 * calls that depend upon it. 245 */ 246static int 247__rebuild_environ(int newEnvironSize) 248{ 249 char **tmpEnviron; 250 int envNdx; 251 int environNdx; 252 int tmpEnvironSize; 253 254 /* Resize environ. */ 255 if (newEnvironSize > environSize) { 256 tmpEnvironSize = newEnvironSize * 2; |
190 tmpEnviron = realloc(environ, sizeof (*environ) * | 257 tmpEnviron = realloc(intEnviron, sizeof (*intEnviron) * |
191 (tmpEnvironSize + 1)); 192 if (tmpEnviron == NULL) 193 return (-1); 194 environSize = tmpEnvironSize; | 258 (tmpEnvironSize + 1)); 259 if (tmpEnviron == NULL) 260 return (-1); 261 environSize = tmpEnvironSize; |
195 environ = tmpEnviron; | 262 intEnviron = tmpEnviron; |
196 } 197 envActive = newEnvironSize; 198 199 /* Assign active variables to environ. */ 200 for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--) 201 if (envVars[envNdx].active) | 263 } 264 envActive = newEnvironSize; 265 266 /* Assign active variables to environ. */ 267 for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--) 268 if (envVars[envNdx].active) |
202 environ[environNdx++] = envVars[envNdx].name; 203 environ[environNdx] = NULL; | 269 intEnviron[environNdx++] = envVars[envNdx].name; 270 intEnviron[environNdx] = NULL; |
204 | 271 |
272 /* Always set environ which may have been replaced by program. */ 273 environ = intEnviron; 274 |
|
205 return (0); 206} 207 208 209/* 210 * Enlarge new environment. 211 */ 212static inline bool --- 23 unchanged lines hidden (view full) --- 236 * Using environ, build an environment for use by standard C library calls. 237 */ 238static int 239__build_env(void) 240{ 241 char **env; 242 int activeNdx; 243 int envNdx; | 275 return (0); 276} 277 278 279/* 280 * Enlarge new environment. 281 */ 282static inline bool --- 23 unchanged lines hidden (view full) --- 306 * Using environ, build an environment for use by standard C library calls. 307 */ 308static int 309__build_env(void) 310{ 311 char **env; 312 int activeNdx; 313 int envNdx; |
244 int rtrnVal; | |
245 int savedErrno; 246 size_t nameLen; 247 248 /* Check for non-existant environment. */ | 314 int savedErrno; 315 size_t nameLen; 316 317 /* Check for non-existant environment. */ |
249 if (environ == NULL) | 318 if (environ == NULL || environ[0] == NULL) |
250 return (0); | 319 return (0); |
251 if (environ[0] == NULL) 252 goto SaveEnviron; | |
253 254 /* Count environment variables. */ 255 for (env = environ, envVarsTotal = 0; *env != NULL; env++) 256 envVarsTotal++; 257 envVarsSize = envVarsTotal * 2; 258 259 /* Create new environment. */ 260 envVars = calloc(1, sizeof (*envVars) * envVarsSize); --- 8 unchanged lines hidden (view full) --- 269 if (envVars[envNdx].name == NULL) 270 goto Failure; 271 envVars[envNdx].value = strchr(envVars[envNdx].name, '='); 272 if (envVars[envNdx].value != NULL) { 273 envVars[envNdx].value++; 274 envVars[envNdx].valueSize = 275 strlen(envVars[envNdx].value); 276 } else { | 320 321 /* Count environment variables. */ 322 for (env = environ, envVarsTotal = 0; *env != NULL; env++) 323 envVarsTotal++; 324 envVarsSize = envVarsTotal * 2; 325 326 /* Create new environment. */ 327 envVars = calloc(1, sizeof (*envVars) * envVarsSize); --- 8 unchanged lines hidden (view full) --- 336 if (envVars[envNdx].name == NULL) 337 goto Failure; 338 envVars[envNdx].value = strchr(envVars[envNdx].name, '='); 339 if (envVars[envNdx].value != NULL) { 340 envVars[envNdx].value++; 341 envVars[envNdx].valueSize = 342 strlen(envVars[envNdx].value); 343 } else { |
277 warnx("environment corrupt; missing value for %s", 278 envVars[envNdx].name); | 344 warnx(CorruptEnvValueMsg, envVars[envNdx].name); |
279 errno = EFAULT; 280 goto Failure; 281 } 282 283 /* 284 * Find most current version of variable to make active. This 285 * will prevent multiple active variables from being created 286 * during this initialization phase. 287 */ 288 nameLen = envVars[envNdx].value - envVars[envNdx].name - 1; 289 envVars[envNdx].nameLen = nameLen; 290 activeNdx = envVarsTotal - 1; 291 if (__findenv(envVars[envNdx].name, nameLen, &activeNdx, 292 false) == NULL) { | 345 errno = EFAULT; 346 goto Failure; 347 } 348 349 /* 350 * Find most current version of variable to make active. This 351 * will prevent multiple active variables from being created 352 * during this initialization phase. 353 */ 354 nameLen = envVars[envNdx].value - envVars[envNdx].name - 1; 355 envVars[envNdx].nameLen = nameLen; 356 activeNdx = envVarsTotal - 1; 357 if (__findenv(envVars[envNdx].name, nameLen, &activeNdx, 358 false) == NULL) { |
293 warnx("environment corrupt; unable to find %.*s", 294 nameLen, envVars[envNdx].name); | 359 warnx(CorruptEnvFindMsg, nameLen, envVars[envNdx].name); |
295 errno = EFAULT; 296 goto Failure; 297 } 298 envVars[activeNdx].active = true; 299 } 300 301 /* Create a new environ. */ | 360 errno = EFAULT; 361 goto Failure; 362 } 363 envVars[activeNdx].active = true; 364 } 365 366 /* Create a new environ. */ |
302SaveEnviron: | |
303 origEnviron = environ; 304 environ = NULL; | 367 origEnviron = environ; 368 environ = NULL; |
305 if (envVarsTotal > 0) { 306 rtrnVal = __rebuild_environ(envVarsTotal); 307 if (rtrnVal == -1) { 308 savedErrno = errno; 309 __clean_env(); 310 errno = savedErrno; 311 } 312 } else 313 rtrnVal = 0; | 369 if (__rebuild_environ(envVarsTotal) == 0) 370 return (0); |
314 | 371 |
315 return (rtrnVal); 316 | |
317Failure: 318 savedErrno = errno; | 372Failure: 373 savedErrno = errno; |
319 __clean_env(); | 374 __clean_env(true); |
320 errno = savedErrno; 321 322 return (-1); 323} 324 325 326/* | 375 errno = savedErrno; 376 377 return (-1); 378} 379 380 381/* |
327 * Remove variable added by putenv() from variable tracking array. | 382 * Destructor function with default argument to __clean_env(). |
328 */ 329static void | 383 */ 384static void |
330__remove_putenv(int envNdx) | 385__clean_env_destructor(void) |
331{ | 386{ |
332 memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]), 333 (envVarsTotal - envNdx) * sizeof (*envVars)); 334 envVarsTotal--; | 387 __clean_env(true); |
335 336 return; 337} 338 339 340/* | 388 389 return; 390} 391 392 393/* |
341 * Deallocate the environment built from environ as well as environ then set 342 * both to NULL. Eases debugging of memory leaks. 343 */ 344static void 345__clean_env(void) 346{ 347 int envNdx; 348 349 /* Deallocate environment and environ if created by *env(). */ 350 if (envVars != NULL) { 351 for (envNdx = 0; envNdx < envVarsTotal; envNdx++) 352 if (!envVars[envNdx].putenv) 353 free(envVars[envNdx].name); 354 free(envVars); 355 envVars = NULL; 356 357 /* Restore original environ. */ 358 if (origEnviron != NULL) { 359 free(environ); 360 environ = origEnviron; 361 } 362 } 363 364 return; 365} 366 367 368/* | |
369 * Returns the value of a variable or NULL if none are found. 370 */ 371char * 372getenv(const char *name) 373{ 374 int envNdx; 375 size_t nameLen; 376 377 /* Check for malformed name. */ 378 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 379 errno = EINVAL; 380 return (NULL); 381 } 382 | 394 * Returns the value of a variable or NULL if none are found. 395 */ 396char * 397getenv(const char *name) 398{ 399 int envNdx; 400 size_t nameLen; 401 402 /* Check for malformed name. */ 403 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 404 errno = EINVAL; 405 return (NULL); 406 } 407 |
383 /* Find environment variable via environ or rebuilt environment. */ 384 if (envVars == NULL) | 408 /* 409 * Find environment variable via environ if no changes have been made 410 * via a *env() call or environ has been replaced by a running program, 411 * otherwise, use the rebuilt environment. 412 */ 413 if (envVars == NULL || environ != intEnviron) |
385 return (__findenv_environ(name, nameLen)); 386 else { 387 envNdx = envVarsTotal - 1; 388 return (__findenv(name, nameLen, &envNdx, true)); 389 } 390} 391 392 393/* 394 * Set the value of a variable. Older settings are labeled as inactive. If an 395 * older setting has enough room to store the new value, it will be reused. No 396 * previous variables are ever freed here to avoid causing a segmentation fault 397 * in a user's code. | 414 return (__findenv_environ(name, nameLen)); 415 else { 416 envNdx = envVarsTotal - 1; 417 return (__findenv(name, nameLen, &envNdx, true)); 418 } 419} 420 421 422/* 423 * Set the value of a variable. Older settings are labeled as inactive. If an 424 * older setting has enough room to store the new value, it will be reused. No 425 * previous variables are ever freed here to avoid causing a segmentation fault 426 * in a user's code. |
427 * 428 * The variables nameLen and valueLen are passed into here to allow the caller 429 * to calculate the length by means besides just strlen(). |
|
398 */ | 430 */ |
399int 400setenv(const char *name, const char *value, int overwrite) | 431static int 432__setenv(const char *name, size_t nameLen, const char *value, int overwrite) |
401{ 402 bool reuse; 403 char *env; 404 int envNdx; 405 int newEnvActive; | 433{ 434 bool reuse; 435 char *env; 436 int envNdx; 437 int newEnvActive; |
406 size_t nameLen; | |
407 size_t valueLen; 408 | 438 size_t valueLen; 439 |
409 /* Check for malformed name. */ 410 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 411 errno = EINVAL; 412 return (-1); 413 } 414 415 /* Initialize environment. */ 416 if (envVars == NULL && __build_env() == -1) 417 return (-1); 418 | |
419 /* Find existing environment variable large enough to use. */ 420 envNdx = envVarsTotal - 1; 421 newEnvActive = envActive; 422 valueLen = strlen(value); 423 reuse = false; 424 if (__findenv(name, nameLen, &envNdx, false) != NULL) { 425 /* Deactivate entry if overwrite is allowed. */ 426 if (envVars[envNdx].active) { --- 5 unchanged lines hidden (view full) --- 432 433 /* putenv() created variable cannot be reused. */ 434 if (envVars[envNdx].putenv) 435 __remove_putenv(envNdx); 436 437 /* Entry is large enough to reuse. */ 438 else if (envVars[envNdx].valueSize >= valueLen) 439 reuse = true; | 440 /* Find existing environment variable large enough to use. */ 441 envNdx = envVarsTotal - 1; 442 newEnvActive = envActive; 443 valueLen = strlen(value); 444 reuse = false; 445 if (__findenv(name, nameLen, &envNdx, false) != NULL) { 446 /* Deactivate entry if overwrite is allowed. */ 447 if (envVars[envNdx].active) { --- 5 unchanged lines hidden (view full) --- 453 454 /* putenv() created variable cannot be reused. */ 455 if (envVars[envNdx].putenv) 456 __remove_putenv(envNdx); 457 458 /* Entry is large enough to reuse. */ 459 else if (envVars[envNdx].valueSize >= valueLen) 460 reuse = true; |
440 | |
441 } 442 443 /* Create new variable if none was found of sufficient size. */ 444 if (! reuse) { 445 /* Enlarge environment. */ 446 envNdx = envVarsTotal; 447 if (!__enlarge_env()) 448 return (-1); --- 26 unchanged lines hidden (view full) --- 475 if (reuse) 476 return (0); 477 else 478 return (__rebuild_environ(newEnvActive)); 479} 480 481 482/* | 461 } 462 463 /* Create new variable if none was found of sufficient size. */ 464 if (! reuse) { 465 /* Enlarge environment. */ 466 envNdx = envVarsTotal; 467 if (!__enlarge_env()) 468 return (-1); --- 26 unchanged lines hidden (view full) --- 495 if (reuse) 496 return (0); 497 else 498 return (__rebuild_environ(newEnvActive)); 499} 500 501 502/* |
483 * Insert a "name=value" string into then environment. Special settings must be | 503 * If the program attempts to replace the array of environment variables 504 * (environ) environ, then deactivate all variables and merge in the new list 505 * from environ. 506 */ 507static int 508__merge_environ(void) 509{ 510 char **env; 511 char *equals; 512 513 /* environ has been replaced. clean up everything. */ 514 if (envVarsTotal > 0 && environ != intEnviron) { 515 /* Deactivate all environment variables. */ 516 if (envActive > 0) { 517 origEnviron = NULL; 518 __clean_env(false); 519 } 520 521 /* 522 * Insert new environ into existing, yet deactivated, 523 * environment array. 524 */ 525 origEnviron = environ; 526 if (origEnviron != NULL) 527 for (env = origEnviron; *env != NULL; env++) { 528 if ((equals = strchr(*env, '=')) == NULL) { 529 warnx(CorruptEnvValueMsg, *env); 530 errno = EFAULT; 531 return (-1); 532 } 533 if (__setenv(*env, equals - *env, equals + 1, 534 1) == -1) 535 return (-1); 536 } 537 } 538 539 return (0); 540} 541 542 543/* 544 * The exposed setenv() that peforms a few tests before calling the function 545 * (__setenv()) that does the actual work of inserting a variable into the 546 * environment. 547 */ 548int 549setenv(const char *name, const char *value, int overwrite) 550{ 551 size_t nameLen; 552 553 /* Check for malformed name. */ 554 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 555 errno = EINVAL; 556 return (-1); 557 } 558 559 /* Initialize environment. */ 560 if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) 561 return (-1); 562 563 return (__setenv(name, nameLen, value, overwrite)); 564} 565 566 567/* 568 * Insert a "name=value" string into the environment. Special settings must be |
484 * made to keep setenv() from reusing this memory block and unsetenv() from 485 * allowing it to be tracked. 486 */ 487int 488putenv(char *string) 489{ 490 char *equals; 491 int envNdx; 492 int newEnvActive; 493 size_t nameLen; 494 495 /* Check for malformed argument. */ 496 if (string == NULL || (equals = strchr(string, '=')) == NULL || 497 (nameLen = equals - string) == 0) { 498 errno = EINVAL; 499 return (-1); 500 } 501 502 /* Initialize environment. */ | 569 * made to keep setenv() from reusing this memory block and unsetenv() from 570 * allowing it to be tracked. 571 */ 572int 573putenv(char *string) 574{ 575 char *equals; 576 int envNdx; 577 int newEnvActive; 578 size_t nameLen; 579 580 /* Check for malformed argument. */ 581 if (string == NULL || (equals = strchr(string, '=')) == NULL || 582 (nameLen = equals - string) == 0) { 583 errno = EINVAL; 584 return (-1); 585 } 586 587 /* Initialize environment. */ |
503 if (envVars == NULL && __build_env() == -1) | 588 if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) |
504 return (-1); 505 506 /* Deactivate previous environment variable. */ 507 envNdx = envVarsTotal - 1; 508 newEnvActive = envActive; 509 if (__findenv(string, nameLen, &envNdx, true) != NULL) { 510 /* Reuse previous putenv slot. */ 511 if (envVars[envNdx].putenv) { --- 35 unchanged lines hidden (view full) --- 547 548 /* Check for malformed name. */ 549 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 550 errno = EINVAL; 551 return (-1); 552 } 553 554 /* Initialize environment. */ | 589 return (-1); 590 591 /* Deactivate previous environment variable. */ 592 envNdx = envVarsTotal - 1; 593 newEnvActive = envActive; 594 if (__findenv(string, nameLen, &envNdx, true) != NULL) { 595 /* Reuse previous putenv slot. */ 596 if (envVars[envNdx].putenv) { --- 35 unchanged lines hidden (view full) --- 632 633 /* Check for malformed name. */ 634 if (name == NULL || (nameLen = __strleneq(name)) == 0) { 635 errno = EINVAL; 636 return (-1); 637 } 638 639 /* Initialize environment. */ |
555 if (envVars == NULL && __build_env() == -1) | 640 if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) |
556 return (-1); 557 558 /* Deactivate specified variable. */ 559 envNdx = envVarsTotal - 1; 560 if (__findenv(name, nameLen, &envNdx, true) != NULL) { 561 envVars[envNdx].active = false; 562 if (envVars[envNdx].putenv) 563 __remove_putenv(envNdx); 564 __rebuild_environ(envActive - 1); 565 } 566 567 return (0); 568} | 641 return (-1); 642 643 /* Deactivate specified variable. */ 644 envNdx = envVarsTotal - 1; 645 if (__findenv(name, nameLen, &envNdx, true) != NULL) { 646 envVars[envNdx].active = false; 647 if (envVars[envNdx].putenv) 648 __remove_putenv(envNdx); 649 __rebuild_environ(envActive - 1); 650 } 651 652 return (0); 653} |