Deleted Added
sdiff udiff text old ( 171195 ) new ( 171525 )
full compact
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 $");
37
38
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.
46 */
47extern char **environ;
48static char **origEnviron;
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. */
87static void __attribute__ ((destructor)) __clean_env(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/*
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;
190 tmpEnviron = realloc(environ, sizeof (*environ) *
191 (tmpEnvironSize + 1));
192 if (tmpEnviron == NULL)
193 return (-1);
194 environSize = tmpEnvironSize;
195 environ = 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)
202 environ[environNdx++] = envVars[envNdx].name;
203 environ[environNdx] = NULL;
204
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;
244 int rtrnVal;
245 int savedErrno;
246 size_t nameLen;
247
248 /* Check for non-existant environment. */
249 if (environ == NULL)
250 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 {
277 warnx("environment corrupt; missing value for %s",
278 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) {
293 warnx("environment corrupt; unable to find %.*s",
294 nameLen, envVars[envNdx].name);
295 errno = EFAULT;
296 goto Failure;
297 }
298 envVars[activeNdx].active = true;
299 }
300
301 /* Create a new environ. */
302SaveEnviron:
303 origEnviron = environ;
304 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;
314
315 return (rtrnVal);
316
317Failure:
318 savedErrno = errno;
319 __clean_env();
320 errno = savedErrno;
321
322 return (-1);
323}
324
325
326/*
327 * Remove variable added by putenv() from variable tracking array.
328 */
329static void
330__remove_putenv(int envNdx)
331{
332 memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]),
333 (envVarsTotal - envNdx) * sizeof (*envVars));
334 envVarsTotal--;
335
336 return;
337}
338
339
340/*
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
383 /* Find environment variable via environ or rebuilt environment. */
384 if (envVars == NULL)
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.
398 */
399int
400setenv(const char *name, const char *value, int overwrite)
401{
402 bool reuse;
403 char *env;
404 int envNdx;
405 int newEnvActive;
406 size_t nameLen;
407 size_t valueLen;
408
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
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/*
483 * Insert a "name=value" string into then 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. */
503 if (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. */
555 if (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}