1335c4bemsmith/*
2335c4bemsmith * Copyright (c) 1998 Michael Smith.
3335c4bemsmith * All rights reserved.
4335c4bemsmith *
5335c4bemsmith * Redistribution and use in source and binary forms, with or without
6335c4bemsmith * modification, are permitted provided that the following conditions
7335c4bemsmith * are met:
8335c4bemsmith * 1. Redistributions of source code must retain the above copyright
9335c4bemsmith *    notice, this list of conditions and the following disclaimer.
10335c4bemsmith * 2. Redistributions in binary form must reproduce the above copyright
11335c4bemsmith *    notice, this list of conditions and the following disclaimer in the
12335c4bemsmith *    documentation and/or other materials provided with the distribution.
13335c4bemsmith *
14335c4bemsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15335c4bemsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16335c4bemsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17335c4bemsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18335c4bemsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19335c4bemsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20335c4bemsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21335c4bemsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22335c4bemsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23335c4bemsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24335c4bemsmith * SUCH DAMAGE.
25335c4bemsmith */
26335c4bemsmith
27f6666a6dillon#include <sys/cdefs.h>
28f6666a6dillon__FBSDID("$FreeBSD$");
29f6666a6dillon
30335c4bemsmith/*
31335c4bemsmith * Manage an environment-like space in which string variables may be stored.
32335c4bemsmith * Provide support for some method-like operations for setting/retrieving
33335c4bemsmith * variables in order to allow some type strength.
34335c4bemsmith */
35335c4bemsmith
36335c4bemsmith#include "stand.h"
37335c4bemsmith
38335c4bemsmith#include <string.h>
39335c4bemsmith
40335c4bemsmithstatic void	env_discard(struct env_var *ev);
41335c4bemsmith
42335c4bemsmithstruct env_var	*environ = NULL;
43335c4bemsmith
44335c4bemsmith/*
45335c4bemsmith * Look up (name) and return it's env_var structure.
46335c4bemsmith */
47335c4bemsmithstruct env_var	*
48335c4bemsmithenv_getenv(const char *name)
49335c4bemsmith{
50335c4bemsmith    struct env_var	*ev;
51335c4bemsmith
52335c4bemsmith    for (ev = environ; ev != NULL; ev = ev->ev_next)
53335c4bemsmith	if (!strcmp(ev->ev_name, name))
54335c4bemsmith	    break;
55335c4bemsmith    return(ev);
56335c4bemsmith}
57335c4bemsmith
58335c4bemsmith/*
59335c4bemsmith * Some notes:
60335c4bemsmith *
61335c4bemsmith * If the EV_VOLATILE flag is set, a copy of the variable is made.
626d9b42bbrucec * If EV_DYNAMIC is set, the variable has been allocated with
63335c4bemsmith * malloc and ownership transferred to the environment.
64335c4bemsmith * If (value) is NULL, the variable is set but has no value.
65335c4bemsmith */
66335c4bemsmithint
6704f2dc8jhbenv_setenv(const char *name, int flags, const void *value,
6804f2dc8jhb	   ev_sethook_t sethook, ev_unsethook_t unsethook)
69335c4bemsmith{
70335c4bemsmith    struct env_var	*ev, *curr, *last;
71335c4bemsmith
72335c4bemsmith    if ((ev = env_getenv(name)) != NULL) {
73335c4bemsmith	/*
74335c4bemsmith	 * If there's a set hook, let it do the work (unless we are working
75335c4bemsmith	 * for one already.
76335c4bemsmith	 */
77335c4bemsmith	if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
78566238cmarcel	    return (ev->ev_sethook(ev, flags, value));
79566238cmarcel
80566238cmarcel	/* If there is data in the variable, discard it. */
81566238cmarcel	if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0)
82566238cmarcel	    free(ev->ev_value);
83566238cmarcel	ev->ev_value = NULL;
84566238cmarcel	ev->ev_flags &= ~EV_DYNAMIC;
85566238cmarcel
86335c4bemsmith    } else {
87ea78326msmith
88ea78326msmith	/*
89ea78326msmith	 * New variable; create and sort into list
90ea78326msmith	 */
91335c4bemsmith	ev = malloc(sizeof(struct env_var));
92335c4bemsmith	ev->ev_name = strdup(name);
93335c4bemsmith	ev->ev_value = NULL;
94566238cmarcel	ev->ev_flags = 0;
95335c4bemsmith	/* hooks can only be set when the variable is instantiated */
96335c4bemsmith	ev->ev_sethook = sethook;
97335c4bemsmith	ev->ev_unsethook = unsethook;
98ea78326msmith
99ea78326msmith	/* Sort into list */
100ea78326msmith	ev->ev_prev = NULL;
101ea78326msmith	ev->ev_next = NULL;
102ea78326msmith	/* Search for the record to insert before */
103ea78326msmith	for (last = NULL, curr = environ;
104ea78326msmith	     curr != NULL;
105ea78326msmith	     last = curr, curr = curr->ev_next) {
106ea78326msmith
107ea78326msmith	    if (strcmp(ev->ev_name, curr->ev_name) < 0) {
108ea78326msmith		if (curr->ev_prev) {
109ea78326msmith		    curr->ev_prev->ev_next = ev;
110ea78326msmith		} else {
111ea78326msmith		    environ = ev;
112ea78326msmith		}
113ea78326msmith		ev->ev_next = curr;
114ea78326msmith		ev->ev_prev = curr->ev_prev;
115ea78326msmith		curr->ev_prev = ev;
116ea78326msmith		break;
117ea78326msmith	    }
118ea78326msmith	}
119ea78326msmith	if (curr == NULL) {
120ea78326msmith	    if (last == NULL) {
121ea78326msmith		environ = ev;
122ea78326msmith	    } else {
123ea78326msmith		last->ev_next = ev;
124ea78326msmith		ev->ev_prev = last;
125ea78326msmith	    }
126ea78326msmith	}
127335c4bemsmith    }
128335c4bemsmith
129335c4bemsmith    /* If we have a new value, use it */
130335c4bemsmith    if (flags & EV_VOLATILE) {
131335c4bemsmith	ev->ev_value = strdup(value);
132566238cmarcel	ev->ev_flags |= EV_DYNAMIC;
133335c4bemsmith    } else {
13436e8f3fkan	ev->ev_value = (char *)value;
135566238cmarcel	ev->ev_flags |= flags & EV_DYNAMIC;
136335c4bemsmith    }
137335c4bemsmith
138335c4bemsmith    return(0);
139335c4bemsmith}
140335c4bemsmith
14126e7d23imp/* coverity[ -tainted_string_return_content ] */
142335c4bemsmithchar *
143335c4bemsmithgetenv(const char *name)
144335c4bemsmith{
145335c4bemsmith    struct env_var	*ev;
146335c4bemsmith
147335c4bemsmith    /* Set but no value gives empty string */
148335c4bemsmith    if ((ev = env_getenv(name)) != NULL) {
149335c4bemsmith	if (ev->ev_value != NULL)
150335c4bemsmith	    return(ev->ev_value);
151335c4bemsmith	return("");
152335c4bemsmith    }
153335c4bemsmith    return(NULL);
154335c4bemsmith}
155335c4bemsmith
156335c4bemsmithint
15704f2dc8jhbsetenv(const char *name, const char *value, int overwrite)
158335c4bemsmith{
159335c4bemsmith    /* No guarantees about state, always assume volatile */
160335c4bemsmith    if (overwrite || (env_getenv(name) == NULL))
161335c4bemsmith	return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
162335c4bemsmith    return(0);
163335c4bemsmith}
164335c4bemsmith
165335c4bemsmithint
1661f7bf6aimpputenv(char *string)
167335c4bemsmith{
168ea78326msmith    char	*value, *copy;
169ea78326msmith    int		result;
170335c4bemsmith
171ea78326msmith    copy = strdup(string);
172ea78326msmith    if ((value = strchr(copy, '=')) != NULL)
173335c4bemsmith	*(value++) = 0;
174ea78326msmith    result = setenv(copy, value, 1);
175ea78326msmith    free(copy);
176ea78326msmith    return(result);
177335c4bemsmith}
178335c4bemsmith
179335c4bemsmithint
180335c4bemsmithunsetenv(const char *name)
181335c4bemsmith{
182335c4bemsmith    struct env_var	*ev;
183335c4bemsmith    int			err;
184335c4bemsmith
185335c4bemsmith    err = 0;
186335c4bemsmith    if ((ev = env_getenv(name)) == NULL) {
187335c4bemsmith	err = ENOENT;
188335c4bemsmith    } else {
189335c4bemsmith	if (ev->ev_unsethook != NULL)
190335c4bemsmith	    err = ev->ev_unsethook(ev);
191335c4bemsmith	if (err == 0) {
192335c4bemsmith	    env_discard(ev);
193335c4bemsmith	}
194335c4bemsmith    }
195335c4bemsmith    return(err);
196335c4bemsmith}
197335c4bemsmith
198335c4bemsmithstatic void
199335c4bemsmithenv_discard(struct env_var *ev)
200335c4bemsmith{
201335c4bemsmith    if (ev->ev_prev)
202335c4bemsmith	ev->ev_prev->ev_next = ev->ev_next;
203335c4bemsmith    if (ev->ev_next)
204335c4bemsmith	ev->ev_next->ev_prev = ev->ev_prev;
205335c4bemsmith    if (environ == ev)
206335c4bemsmith	environ = ev->ev_next;
207335c4bemsmith    free(ev->ev_name);
208566238cmarcel    if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0)
209335c4bemsmith	free(ev->ev_value);
210335c4bemsmith    free(ev);
211335c4bemsmith}
212335c4bemsmith
213335c4bemsmithint
214a857fferodrigcenv_noset(struct env_var *ev __unused, int flags __unused,
215a857fferodrigc    const void *value __unused)
216335c4bemsmith{
217335c4bemsmith    return(EPERM);
218335c4bemsmith}
219335c4bemsmith
220335c4bemsmithint
221a857fferodrigcenv_nounset(struct env_var *ev __unused)
222335c4bemsmith{
223335c4bemsmith    return(EPERM);
224335c4bemsmith}
225