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