1 /* $OpenBSD: setenv.c,v 1.13 2010/08/23 22:31:50 millert Exp $ */ 2 /* 3 * Copyright (c) 1987 Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* OPENBSD ORIGINAL: lib/libc/stdlib/setenv.c */ 32 33 #include "includes.h" 34 35 #if !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) 36 37 #include <errno.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 extern char **environ; 42 #ifndef HAVE_SETENV 43 static char **lastenv; /* last value of environ */ 44 #endif 45 46 /* OpenSSH Portable: __findenv is from getenv.c rev 1.8, made static */ 47 /* 48 * __findenv -- 49 * Returns pointer to value associated with name, if any, else NULL. 50 * Starts searching within the environmental array at offset. 51 * Sets offset to be the offset of the name/value combination in the 52 * environmental array, for use by putenv(3), setenv(3) and unsetenv(3). 53 * Explicitly removes '=' in argument name. 54 * 55 * This routine *should* be a static; don't use it. 56 */ 57 static char * 58 __findenv(const char *name, int len, int *offset) 59 { 60 extern char **environ; 61 int i; 62 const char *np; 63 char **p, *cp; 64 65 if (name == NULL || environ == NULL) 66 return (NULL); 67 for (p = environ + *offset; (cp = *p) != NULL; ++p) { 68 for (np = name, i = len; i && *cp; i--) 69 if (*cp++ != *np++) 70 break; 71 if (i == 0 && *cp++ == '=') { 72 *offset = p - environ; 73 return (cp); 74 } 75 } 76 return (NULL); 77 } 78 79 #if 0 /* nothing uses putenv */ 80 /* 81 * putenv -- 82 * Add a name=value string directly to the environmental, replacing 83 * any current value. 84 */ 85 int 86 putenv(char *str) 87 { 88 char **P, *cp; 89 size_t cnt; 90 int offset = 0; 91 92 for (cp = str; *cp && *cp != '='; ++cp) 93 ; 94 if (*cp != '=') { 95 errno = EINVAL; 96 return (-1); /* missing `=' in string */ 97 } 98 99 if (__findenv(str, (int)(cp - str), &offset) != NULL) { 100 environ[offset++] = str; 101 /* could be set multiple times */ 102 while (__findenv(str, (int)(cp - str), &offset)) { 103 for (P = &environ[offset];; ++P) 104 if (!(*P = *(P + 1))) 105 break; 106 } 107 return (0); 108 } 109 110 /* create new slot for string */ 111 for (P = environ; *P != NULL; P++) 112 ; 113 cnt = P - environ; 114 P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); 115 if (!P) 116 return (-1); 117 if (lastenv != environ) 118 memcpy(P, environ, cnt * sizeof(char *)); 119 lastenv = environ = P; 120 environ[cnt] = str; 121 environ[cnt + 1] = NULL; 122 return (0); 123 } 124 125 #endif 126 127 #ifndef HAVE_SETENV 128 /* 129 * setenv -- 130 * Set the value of the environmental variable "name" to be 131 * "value". If rewrite is set, replace any current value. 132 */ 133 int 134 setenv(const char *name, const char *value, int rewrite) 135 { 136 char *C, **P; 137 const char *np; 138 int l_value, offset = 0; 139 140 for (np = name; *np && *np != '='; ++np) 141 ; 142 #ifdef notyet 143 if (*np) { 144 errno = EINVAL; 145 return (-1); /* has `=' in name */ 146 } 147 #endif 148 149 l_value = strlen(value); 150 if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) { 151 int tmpoff = offset + 1; 152 if (!rewrite) 153 return (0); 154 #if 0 /* XXX - existing entry may not be writable */ 155 if (strlen(C) >= l_value) { /* old larger; copy over */ 156 while ((*C++ = *value++)) 157 ; 158 return (0); 159 } 160 #endif 161 /* could be set multiple times */ 162 while (__findenv(name, (int)(np - name), &tmpoff)) { 163 for (P = &environ[tmpoff];; ++P) 164 if (!(*P = *(P + 1))) 165 break; 166 } 167 } else { /* create new slot */ 168 size_t cnt; 169 170 for (P = environ; *P != NULL; P++) 171 ; 172 cnt = P - environ; 173 P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); 174 if (!P) 175 return (-1); 176 if (lastenv != environ) 177 memcpy(P, environ, cnt * sizeof(char *)); 178 lastenv = environ = P; 179 offset = cnt; 180 environ[cnt + 1] = NULL; 181 } 182 if (!(environ[offset] = /* name + `=' + value */ 183 malloc((size_t)((int)(np - name) + l_value + 2)))) 184 return (-1); 185 for (C = environ[offset]; (*C = *name++) && *C != '='; ++C) 186 ; 187 for (*C++ = '='; (*C++ = *value++); ) 188 ; 189 return (0); 190 } 191 192 #endif /* HAVE_SETENV */ 193 194 #ifndef HAVE_UNSETENV 195 /* 196 * unsetenv(name) -- 197 * Delete environmental variable "name". 198 */ 199 int 200 unsetenv(const char *name) 201 { 202 char **P; 203 const char *np; 204 int offset = 0; 205 206 if (!name || !*name) { 207 errno = EINVAL; 208 return (-1); 209 } 210 for (np = name; *np && *np != '='; ++np) 211 ; 212 if (*np) { 213 errno = EINVAL; 214 return (-1); /* has `=' in name */ 215 } 216 217 /* could be set multiple times */ 218 while (__findenv(name, (int)(np - name), &offset)) { 219 for (P = &environ[offset];; ++P) 220 if (!(*P = *(P + 1))) 221 break; 222 } 223 return (0); 224 } 225 #endif /* HAVE_UNSETENV */ 226 227 #endif /* !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) */ 228 229