1 /* 2 * From: TCP Wrapper. 3 * 4 * Many systems have putenv() but no setenv(). Other systems have setenv() but 5 * no putenv() (MIPS). Still other systems have neither (NeXT). This is a 6 * re-implementation that hopefully ends all problems. 7 * 8 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 9 */ 10#include "sys_defs.h" 11 12#ifdef MISSING_SETENV_PUTENV 13 14#include <stdio.h> 15#include <string.h> 16#include <stdlib.h> 17 18extern char **environ; 19 20static int addenv(char *); /* append entry to environment */ 21static int allocated = 0; /* environ is, or is not, allocated */ 22 23#define DO_CLOBBER 1 24 25/* namelength - determine length of name in "name=whatever" */ 26 27static ssize_t namelength(const char *name) 28{ 29 char *equal; 30 31 equal = strchr(name, '='); 32 return ((equal == 0) ? strlen(name) : (equal - name)); 33} 34 35/* findenv - given name, locate name=value */ 36 37static char **findenv(const char *name, ssize_t len) 38{ 39 char **envp; 40 41 for (envp = environ; envp && *envp; envp++) 42 if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=') 43 return (envp); 44 return (0); 45} 46 47#if 0 48 49/* getenv - given name, locate value */ 50 51char *getenv(const char *name) 52{ 53 ssize_t len = namelength(name); 54 char **envp = findenv(name, len); 55 56 return (envp ? *envp + len + 1 : 0); 57} 58 59/* putenv - update or append environment (name,value) pair */ 60 61int putenv(const char *nameval) 62{ 63 char *equal = strchr(nameval, '='); 64 char *value = (equal ? equal : ""); 65 66 return (setenv(nameval, value, DO_CLOBBER)); 67} 68 69/* unsetenv - remove variable from environment */ 70 71void unsetenv(const char *name) 72{ 73 char **envp; 74 75 while ((envp = findenv(name, namelength(name))) != 0) 76 while (envp[0] = envp[1]) 77 envp++; 78} 79 80#endif 81 82/* setenv - update or append environment (name,value) pair */ 83 84int setenv(const char *name, const char *value, int clobber) 85{ 86 char *destination; 87 char **envp; 88 ssize_t l_name; /* length of name part */ 89 unsigned int l_nameval; /* length of name=value */ 90 91 /* Permit name= and =value. */ 92 93 l_name = namelength(name); 94 envp = findenv(name, l_name); 95 if (envp != 0 && clobber == 0) 96 return (0); 97 if (*value == '=') 98 value++; 99 l_nameval = l_name + strlen(value) + 1; 100 101 /* 102 * Use available memory if the old value is long enough. Never free an 103 * old name=value entry because it may not be allocated. 104 */ 105 106 destination = (envp != 0 && strlen(*envp) >= l_nameval) ? 107 *envp : malloc(l_nameval + 1); 108 if (destination == 0) 109 return (-1); 110 strncpy(destination, name, l_name); 111 destination[l_name] = '='; 112 strlcpy(destination + l_name + 1, value, l_nameval - l_name); /* APPLE */ 113 return ((envp == 0) ? addenv(destination) : (*envp = destination, 0)); 114} 115 116/* cmalloc - malloc and copy block of memory */ 117 118static char *cmalloc(ssize_t new_len, char *old, ssize_t old_len) 119{ 120 char *new = malloc(new_len); 121 122 if (new != 0) 123 memcpy(new, old, old_len); 124 return (new); 125} 126 127/* addenv - append environment entry */ 128 129static int addenv(char *nameval) 130{ 131 char **envp; 132 ssize_t n_used; /* number of environment entries */ 133 ssize_t l_used; /* bytes used excl. terminator */ 134 ssize_t l_need; /* bytes needed incl. terminator */ 135 136 for (envp = environ; envp && *envp; envp++) 137 /* void */ ; 138 n_used = envp - environ; 139 l_used = n_used * sizeof(*envp); 140 l_need = l_used + 2 * sizeof(*envp); 141 142 envp = allocated ? 143 (char **) realloc((char *) environ, l_need) : 144 (char **) cmalloc(l_need, (char *) environ, l_used); 145 if (envp == 0) { 146 return (-1); 147 } else { 148 allocated = 1; 149 environ = envp; 150 environ[n_used++] = nameval; /* add new entry */ 151 environ[n_used] = 0; /* terminate list */ 152 return (0); 153 } 154} 155 156#endif 157