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