xref: /freebsd-src/stand/libsa/environment.c (revision 3e15b01d6914c927e37d1699645783acf286655c)
1ca987d46SWarner Losh /*
2ca987d46SWarner Losh  * Copyright (c) 1998 Michael Smith.
3ca987d46SWarner Losh  * All rights reserved.
4ca987d46SWarner Losh  *
5ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
6ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
7ca987d46SWarner Losh  * are met:
8ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
9ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
10ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
11ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
12ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
13ca987d46SWarner Losh  *
14ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ca987d46SWarner Losh  * SUCH DAMAGE.
25ca987d46SWarner Losh  */
26ca987d46SWarner Losh 
27ca987d46SWarner Losh /*
28ca987d46SWarner Losh  * Manage an environment-like space in which string variables may be stored.
29ca987d46SWarner Losh  * Provide support for some method-like operations for setting/retrieving
30ca987d46SWarner Losh  * variables in order to allow some type strength.
31ca987d46SWarner Losh  */
32ca987d46SWarner Losh 
33ca987d46SWarner Losh #include "stand.h"
34ca987d46SWarner Losh 
35ca987d46SWarner Losh #include <string.h>
36ca987d46SWarner Losh 
37ca987d46SWarner Losh struct env_var	*environ = NULL;
38ca987d46SWarner Losh 
39ca987d46SWarner Losh /*
40ca987d46SWarner Losh  * Look up (name) and return it's env_var structure.
41ca987d46SWarner Losh  */
42ca987d46SWarner Losh struct env_var	*
env_getenv(const char * name)43ca987d46SWarner Losh env_getenv(const char *name)
44ca987d46SWarner Losh {
45ca987d46SWarner Losh 	struct env_var	*ev;
46ca987d46SWarner Losh 
47ca987d46SWarner Losh 	for (ev = environ; ev != NULL; ev = ev->ev_next)
48ca987d46SWarner Losh 		if (!strcmp(ev->ev_name, name))
49ca987d46SWarner Losh 			break;
50ca987d46SWarner Losh 	return (ev);
51ca987d46SWarner Losh }
52ca987d46SWarner Losh 
53ca987d46SWarner Losh /*
54ca987d46SWarner Losh  * Some notes:
55ca987d46SWarner Losh  *
56ca987d46SWarner Losh  * If the EV_VOLATILE flag is set, a copy of the variable is made.
57ca987d46SWarner Losh  * If EV_DYNAMIC is set, the variable has been allocated with
58ca987d46SWarner Losh  * malloc and ownership transferred to the environment.
59ca987d46SWarner Losh  * If (value) is NULL, the variable is set but has no value.
60ca987d46SWarner Losh  */
61ca987d46SWarner Losh int
env_setenv(const char * name,int flags,const void * value,ev_sethook_t sethook,ev_unsethook_t unsethook)62ca987d46SWarner Losh env_setenv(const char *name, int flags, const void *value,
63ca987d46SWarner Losh     ev_sethook_t sethook, ev_unsethook_t unsethook)
64ca987d46SWarner Losh {
65ca987d46SWarner Losh 	struct env_var	*ev, *curr, *last;
66ca987d46SWarner Losh 
67ca987d46SWarner Losh 	if ((ev = env_getenv(name)) != NULL) {
68ca987d46SWarner Losh 		/*
6916aabe28SToomas Soome 		 * If there's a set hook, let it do the work
7016aabe28SToomas Soome 		 * (unless we are working for one already).
71ca987d46SWarner Losh 		 */
72ca987d46SWarner Losh 		if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
73ca987d46SWarner Losh 			return (ev->ev_sethook(ev, flags, value));
74ca987d46SWarner Losh 
75ca987d46SWarner Losh 		/* If there is data in the variable, discard it. */
76ca987d46SWarner Losh 		if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0)
77ca987d46SWarner Losh 			free(ev->ev_value);
78ca987d46SWarner Losh 		ev->ev_value = NULL;
79ca987d46SWarner Losh 		ev->ev_flags &= ~EV_DYNAMIC;
80ca987d46SWarner Losh 
81ca987d46SWarner Losh 	} else {
82ca987d46SWarner Losh 
83ca987d46SWarner Losh 		/*
84ca987d46SWarner Losh 		 * New variable; create and sort into list
85ca987d46SWarner Losh 		 */
86ca987d46SWarner Losh 		ev = malloc(sizeof(struct env_var));
87ca987d46SWarner Losh 		ev->ev_name = strdup(name);
88ca987d46SWarner Losh 		ev->ev_value = NULL;
89ca987d46SWarner Losh 		ev->ev_flags = 0;
90ca987d46SWarner Losh 		/* hooks can only be set when the variable is instantiated */
91ca987d46SWarner Losh 		ev->ev_sethook = sethook;
92ca987d46SWarner Losh 		ev->ev_unsethook = unsethook;
93ca987d46SWarner Losh 
94ca987d46SWarner Losh 		/* Sort into list */
95ca987d46SWarner Losh 		ev->ev_prev = NULL;
96ca987d46SWarner Losh 		ev->ev_next = NULL;
97ca987d46SWarner Losh 		/* Search for the record to insert before */
9816aabe28SToomas Soome 		for (last = NULL, curr = environ; curr != NULL;
99ca987d46SWarner Losh 		    last = curr, curr = curr->ev_next) {
100ca987d46SWarner Losh 
101ca987d46SWarner Losh 			if (strcmp(ev->ev_name, curr->ev_name) < 0) {
102ca987d46SWarner Losh 				if (curr->ev_prev) {
103ca987d46SWarner Losh 					curr->ev_prev->ev_next = ev;
104ca987d46SWarner Losh 				} else {
105ca987d46SWarner Losh 					environ = ev;
106ca987d46SWarner Losh 				}
107ca987d46SWarner Losh 				ev->ev_next = curr;
108ca987d46SWarner Losh 				ev->ev_prev = curr->ev_prev;
109ca987d46SWarner Losh 				curr->ev_prev = ev;
110ca987d46SWarner Losh 				break;
111ca987d46SWarner Losh 			}
112ca987d46SWarner Losh 		}
113ca987d46SWarner Losh 		if (curr == NULL) {
114ca987d46SWarner Losh 			if (last == NULL) {
115ca987d46SWarner Losh 				environ = ev;
116ca987d46SWarner Losh 			} else {
117ca987d46SWarner Losh 				last->ev_next = ev;
118ca987d46SWarner Losh 				ev->ev_prev = last;
119ca987d46SWarner Losh 			}
120ca987d46SWarner Losh 		}
121ca987d46SWarner Losh 	}
122ca987d46SWarner Losh 
123ca987d46SWarner Losh 	/* If we have a new value, use it */
124ca987d46SWarner Losh 	if (flags & EV_VOLATILE) {
125ca987d46SWarner Losh 		ev->ev_value = strdup(value);
126ca987d46SWarner Losh 		ev->ev_flags |= EV_DYNAMIC;
127ca987d46SWarner Losh 	} else {
128ca987d46SWarner Losh 		ev->ev_value = (char *)value;
129ca987d46SWarner Losh 		ev->ev_flags |= flags & EV_DYNAMIC;
130ca987d46SWarner Losh 	}
131ca987d46SWarner Losh 
132ca987d46SWarner Losh 	return (0);
133ca987d46SWarner Losh }
134ca987d46SWarner Losh 
135e77c9f0cSWarner Losh /* coverity[ -tainted_string_return_content ] */
136ca987d46SWarner Losh char *
getenv(const char * name)137ca987d46SWarner Losh getenv(const char *name)
138ca987d46SWarner Losh {
139ca987d46SWarner Losh 	struct env_var	*ev;
140ca987d46SWarner Losh 
141ca987d46SWarner Losh 	/* Set but no value gives empty string */
142ca987d46SWarner Losh 	if ((ev = env_getenv(name)) != NULL) {
143ca987d46SWarner Losh 		if (ev->ev_value != NULL)
144ca987d46SWarner Losh 			return (ev->ev_value);
145ca987d46SWarner Losh 		return ("");
146ca987d46SWarner Losh 	}
147ca987d46SWarner Losh 	return (NULL);
148ca987d46SWarner Losh }
149ca987d46SWarner Losh 
150ca987d46SWarner Losh int
setenv(const char * name,const char * value,int overwrite)151ca987d46SWarner Losh setenv(const char *name, const char *value, int overwrite)
152ca987d46SWarner Losh {
153ca987d46SWarner Losh 	/* No guarantees about state, always assume volatile */
154ca987d46SWarner Losh 	if (overwrite || (env_getenv(name) == NULL))
155ca987d46SWarner Losh 		return (env_setenv(name, EV_VOLATILE, value, NULL, NULL));
156ca987d46SWarner Losh 	return (0);
157ca987d46SWarner Losh }
158ca987d46SWarner Losh 
159ca987d46SWarner Losh int
putenv(char * string)160e8e6a5f9SWarner Losh putenv(char *string)
161ca987d46SWarner Losh {
162ca987d46SWarner Losh 	char	*value, *copy;
163ca987d46SWarner Losh 	int	result;
164ca987d46SWarner Losh 
165ca987d46SWarner Losh 	copy = strdup(string);
166ca987d46SWarner Losh 	if ((value = strchr(copy, '=')) != NULL)
167ca987d46SWarner Losh 		*(value++) = 0;
168ca987d46SWarner Losh 	result = setenv(copy, value, 1);
169ca987d46SWarner Losh 	free(copy);
170ca987d46SWarner Losh 	return (result);
171ca987d46SWarner Losh }
172ca987d46SWarner Losh 
173ca987d46SWarner Losh int
unsetenv(const char * name)174ca987d46SWarner Losh unsetenv(const char *name)
175ca987d46SWarner Losh {
176ca987d46SWarner Losh 	struct env_var	*ev;
177ca987d46SWarner Losh 	int		err;
178ca987d46SWarner Losh 
179ca987d46SWarner Losh 	err = 0;
180ca987d46SWarner Losh 	if ((ev = env_getenv(name)) == NULL) {
181ca987d46SWarner Losh 		err = ENOENT;
182ca987d46SWarner Losh 	} else {
183ca987d46SWarner Losh 		if (ev->ev_unsethook != NULL)
184ca987d46SWarner Losh 			err = ev->ev_unsethook(ev);
185ca987d46SWarner Losh 		if (err == 0) {
186ca987d46SWarner Losh 			env_discard(ev);
187ca987d46SWarner Losh 		}
188ca987d46SWarner Losh 	}
189ca987d46SWarner Losh 	return (err);
190ca987d46SWarner Losh }
191ca987d46SWarner Losh 
192*588f0a1eSToomas Soome void
env_discard(struct env_var * ev)193ca987d46SWarner Losh env_discard(struct env_var *ev)
194ca987d46SWarner Losh {
195ca987d46SWarner Losh 	if (ev->ev_prev)
196ca987d46SWarner Losh 		ev->ev_prev->ev_next = ev->ev_next;
197ca987d46SWarner Losh 	if (ev->ev_next)
198ca987d46SWarner Losh 		ev->ev_next->ev_prev = ev->ev_prev;
199ca987d46SWarner Losh 	if (environ == ev)
200ca987d46SWarner Losh 		environ = ev->ev_next;
201ca987d46SWarner Losh 	free(ev->ev_name);
202ca987d46SWarner Losh 	if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0)
203ca987d46SWarner Losh 		free(ev->ev_value);
204ca987d46SWarner Losh 	free(ev);
205ca987d46SWarner Losh }
206ca987d46SWarner Losh 
207ca987d46SWarner Losh int
env_noset(struct env_var * ev __unused,int flags __unused,const void * value __unused)208ca987d46SWarner Losh env_noset(struct env_var *ev __unused, int flags __unused,
209ca987d46SWarner Losh     const void *value __unused)
210ca987d46SWarner Losh {
211ca987d46SWarner Losh 	return (EPERM);
212ca987d46SWarner Losh }
213ca987d46SWarner Losh 
214ca987d46SWarner Losh int
env_nounset(struct env_var * ev __unused)215ca987d46SWarner Losh env_nounset(struct env_var *ev __unused)
216ca987d46SWarner Losh {
217ca987d46SWarner Losh 	return (EPERM);
218ca987d46SWarner Losh }
219