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