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