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