138451Smsmith/*
238451Smsmith * Copyright (c) 1998 Michael Smith.
338451Smsmith * All rights reserved.
438451Smsmith *
538451Smsmith * Redistribution and use in source and binary forms, with or without
638451Smsmith * modification, are permitted provided that the following conditions
738451Smsmith * are met:
838451Smsmith * 1. Redistributions of source code must retain the above copyright
938451Smsmith *    notice, this list of conditions and the following disclaimer.
1038451Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138451Smsmith *    notice, this list of conditions and the following disclaimer in the
1238451Smsmith *    documentation and/or other materials provided with the distribution.
1338451Smsmith *
1438451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738451Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438451Smsmith * SUCH DAMAGE.
2538451Smsmith */
2638451Smsmith
2784221Sdillon#include <sys/cdefs.h>
2884221Sdillon__FBSDID("$FreeBSD$");
2984221Sdillon
3038451Smsmith/*
3138451Smsmith * Manage an environment-like space in which string variables may be stored.
3238451Smsmith * Provide support for some method-like operations for setting/retrieving
3338451Smsmith * variables in order to allow some type strength.
3438451Smsmith */
3538451Smsmith
3638451Smsmith#include "stand.h"
3738451Smsmith
3838451Smsmith#include <string.h>
3938451Smsmith
4038451Smsmithstatic void	env_discard(struct env_var *ev);
4138451Smsmith
4238451Smsmithstruct env_var	*environ = NULL;
4338451Smsmith
4438451Smsmith/*
4538451Smsmith * Look up (name) and return it's env_var structure.
4638451Smsmith */
4738451Smsmithstruct env_var	*
4838451Smsmithenv_getenv(const char *name)
4938451Smsmith{
5038451Smsmith    struct env_var	*ev;
5138451Smsmith
5238451Smsmith    for (ev = environ; ev != NULL; ev = ev->ev_next)
5338451Smsmith	if (!strcmp(ev->ev_name, name))
5438451Smsmith	    break;
5538451Smsmith    return(ev);
5638451Smsmith}
5738451Smsmith
5838451Smsmith/*
5938451Smsmith * Some notes:
6038451Smsmith *
6138451Smsmith * If the EV_VOLATILE flag is set, a copy of the variable is made.
62218909Sbrucec * If EV_DYNAMIC is set, the variable has been allocated with
6338451Smsmith * malloc and ownership transferred to the environment.
6438451Smsmith * If (value) is NULL, the variable is set but has no value.
6538451Smsmith */
6638451Smsmithint
6764185Sjhbenv_setenv(const char *name, int flags, const void *value,
6864185Sjhb	   ev_sethook_t sethook, ev_unsethook_t unsethook)
6938451Smsmith{
7038451Smsmith    struct env_var	*ev, *curr, *last;
7138451Smsmith
7238451Smsmith    if ((ev = env_getenv(name)) != NULL) {
7338451Smsmith	/*
7438451Smsmith	 * If there's a set hook, let it do the work (unless we are working
7538451Smsmith	 * for one already.
7638451Smsmith	 */
7738451Smsmith	if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
7838451Smsmith	    return(ev->ev_sethook(ev, flags, value));
7938451Smsmith    } else {
8039665Smsmith
8139665Smsmith	/*
8239665Smsmith	 * New variable; create and sort into list
8339665Smsmith	 */
8438451Smsmith	ev = malloc(sizeof(struct env_var));
8538451Smsmith	ev->ev_name = strdup(name);
8638451Smsmith	ev->ev_value = NULL;
8738451Smsmith	/* hooks can only be set when the variable is instantiated */
8838451Smsmith	ev->ev_sethook = sethook;
8938451Smsmith	ev->ev_unsethook = unsethook;
9039665Smsmith
9139665Smsmith	/* Sort into list */
9239665Smsmith	ev->ev_prev = NULL;
9339665Smsmith	ev->ev_next = NULL;
9439665Smsmith	/* Search for the record to insert before */
9539665Smsmith	for (last = NULL, curr = environ;
9639665Smsmith	     curr != NULL;
9739665Smsmith	     last = curr, curr = curr->ev_next) {
9839665Smsmith
9939665Smsmith	    if (strcmp(ev->ev_name, curr->ev_name) < 0) {
10039665Smsmith		if (curr->ev_prev) {
10139665Smsmith		    curr->ev_prev->ev_next = ev;
10239665Smsmith		} else {
10339665Smsmith		    environ = ev;
10439665Smsmith		}
10539665Smsmith		ev->ev_next = curr;
10639665Smsmith		ev->ev_prev = curr->ev_prev;
10739665Smsmith		curr->ev_prev = ev;
10839665Smsmith		break;
10939665Smsmith	    }
11039665Smsmith	}
11139665Smsmith	if (curr == NULL) {
11239665Smsmith	    if (last == NULL) {
11339665Smsmith		environ = ev;
11439665Smsmith	    } else {
11539665Smsmith		last->ev_next = ev;
11639665Smsmith		ev->ev_prev = last;
11739665Smsmith	    }
11839665Smsmith	}
11938451Smsmith    }
12038451Smsmith
12138451Smsmith    /* If there is data in the variable, discard it */
12238451Smsmith    if (ev->ev_value != NULL)
12338451Smsmith	free(ev->ev_value);
12438451Smsmith
12538451Smsmith    /* If we have a new value, use it */
12638451Smsmith    if (flags & EV_VOLATILE) {
12738451Smsmith	ev->ev_value = strdup(value);
12838451Smsmith    } else {
129168348Skan	ev->ev_value = (char *)value;
13038451Smsmith    }
13138451Smsmith
13238451Smsmith    /* Keep the flag components that are relevant */
13338451Smsmith    ev->ev_flags = flags & (EV_DYNAMIC);
13438451Smsmith
13538451Smsmith    return(0);
13638451Smsmith}
13738451Smsmith
13838451Smsmithchar *
13938451Smsmithgetenv(const char *name)
14038451Smsmith{
14138451Smsmith    struct env_var	*ev;
14238451Smsmith
14338451Smsmith    /* Set but no value gives empty string */
14438451Smsmith    if ((ev = env_getenv(name)) != NULL) {
14538451Smsmith	if (ev->ev_value != NULL)
14638451Smsmith	    return(ev->ev_value);
14738451Smsmith	return("");
14838451Smsmith    }
14938451Smsmith    return(NULL);
15038451Smsmith}
15138451Smsmith
15238451Smsmithint
15364185Sjhbsetenv(const char *name, const char *value, int overwrite)
15438451Smsmith{
15538451Smsmith    /* No guarantees about state, always assume volatile */
15638451Smsmith    if (overwrite || (env_getenv(name) == NULL))
15738451Smsmith	return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
15838451Smsmith    return(0);
15938451Smsmith}
16038451Smsmith
16138451Smsmithint
16238451Smsmithputenv(const char *string)
16338451Smsmith{
16439665Smsmith    char	*value, *copy;
16539665Smsmith    int		result;
16638451Smsmith
16739665Smsmith    copy = strdup(string);
16839665Smsmith    if ((value = strchr(copy, '=')) != NULL)
16938451Smsmith	*(value++) = 0;
17039665Smsmith    result = setenv(copy, value, 1);
17139665Smsmith    free(copy);
17239665Smsmith    return(result);
17338451Smsmith}
17438451Smsmith
17538451Smsmithint
17638451Smsmithunsetenv(const char *name)
17738451Smsmith{
17838451Smsmith    struct env_var	*ev;
17938451Smsmith    int			err;
18038451Smsmith
18138451Smsmith    err = 0;
18238451Smsmith    if ((ev = env_getenv(name)) == NULL) {
18338451Smsmith	err = ENOENT;
18438451Smsmith    } else {
18538451Smsmith	if (ev->ev_unsethook != NULL)
18638451Smsmith	    err = ev->ev_unsethook(ev);
18738451Smsmith	if (err == 0) {
18838451Smsmith	    env_discard(ev);
18938451Smsmith	}
19038451Smsmith    }
19138451Smsmith    return(err);
19238451Smsmith}
19338451Smsmith
19438451Smsmithstatic void
19538451Smsmithenv_discard(struct env_var *ev)
19638451Smsmith{
19738451Smsmith    if (ev->ev_prev)
19838451Smsmith	ev->ev_prev->ev_next = ev->ev_next;
19938451Smsmith    if (ev->ev_next)
20038451Smsmith	ev->ev_next->ev_prev = ev->ev_prev;
20138451Smsmith    if (environ == ev)
20238451Smsmith	environ = ev->ev_next;
20338451Smsmith    free(ev->ev_name);
20438451Smsmith    if (ev->ev_flags & EV_DYNAMIC)
20538451Smsmith	free(ev->ev_value);
20638451Smsmith    free(ev);
20738451Smsmith}
20838451Smsmith
20938451Smsmithint
210221358Srodrigcenv_noset(struct env_var *ev __unused, int flags __unused,
211221358Srodrigc    const void *value __unused)
21238451Smsmith{
21338451Smsmith    return(EPERM);
21438451Smsmith}
21538451Smsmith
21638451Smsmithint
217221358Srodrigcenv_nounset(struct env_var *ev __unused)
21838451Smsmith{
21938451Smsmith    return(EPERM);
22038451Smsmith}
221