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 static char **lastenv; /* last value of environ */ 43 44 /* OpenSSH Portable: __findenv is from getenv.c rev 1.8, made static */ 45 /* 46 * __findenv -- 47 * Returns pointer to value associated with name, if any, else NULL. 48 * Starts searching within the environmental array at offset. 49 * Sets offset to be the offset of the name/value combination in the 50 * environmental array, for use by putenv(3), setenv(3) and unsetenv(3). 51 * Explicitly removes '=' in argument name. 52 * 53 * This routine *should* be a static; don't use it. 54 */ 55 static char * 56 __findenv(const char *name, int len, int *offset) 57 { 58 extern char **environ; 59 int i; 60 const char *np; 61 char **p, *cp; 62 63 if (name == NULL || environ == NULL) 64 return (NULL); 65 for (p = environ + *offset; (cp = *p) != NULL; ++p) { 66 for (np = name, i = len; i && *cp; i--) 67 if (*cp++ != *np++) 68 break; 69 if (i == 0 && *cp++ == '=') { 70 *offset = p - environ; 71 return (cp); 72 } 73 } 74 return (NULL); 75 } 76 77 #if 0 /* nothing uses putenv */ 78 /* 79 * putenv -- 80 * Add a name=value string directly to the environmental, replacing 81 * any current value. 82 */ 83 int 84 putenv(char *str) 85 { 86 char **P, *cp; 87 size_t cnt; 88 int offset = 0; 89 90 for (cp = str; *cp && *cp != '='; ++cp) 91 ; 92 if (*cp != '=') { 93 errno = EINVAL; 94 return (-1); /* missing `=' in string */ 95 } 96 97 if (__findenv(str, (int)(cp - str), &offset) != NULL) { 98 environ[offset++] = str; 99 /* could be set multiple times */ 100 while (__findenv(str, (int)(cp - str), &offset)) { 101 for (P = &environ[offset];; ++P) 102 if (!(*P = *(P + 1))) 103 break; 104 } 105 return (0); 106 } 107 108 /* create new slot for string */ 109 for (P = environ; *P != NULL; P++) 110 ; 111 cnt = P - environ; 112 P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); 113 if (!P) 114 return (-1); 115 if (lastenv != environ) 116 memcpy(P, environ, cnt * sizeof(char *)); 117 lastenv = environ = P; 118 environ[cnt] = str; 119 environ[cnt + 1] = NULL; 120 return (0); 121 } 122 123 #endif 124 125 #ifndef HAVE_SETENV 126 /* 127 * setenv -- 128 * Set the value of the environmental variable "name" to be 129 * "value". If rewrite is set, replace any current value. 130 */ 131 int 132 setenv(const char *name, const char *value, int rewrite) 133 { 134 char *C, **P; 135 const char *np; 136 int l_value, offset = 0; 137 138 for (np = name; *np && *np != '='; ++np) 139 ; 140 #ifdef notyet 141 if (*np) { 142 errno = EINVAL; 143 return (-1); /* has `=' in name */ 144 } 145 #endif 146 147 l_value = strlen(value); 148 if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) { 149 int tmpoff = offset + 1; 150 if (!rewrite) 151 return (0); 152 #if 0 /* XXX - existing entry may not be writable */ 153 if (strlen(C) >= l_value) { /* old larger; copy over */ 154 while ((*C++ = *value++)) 155 ; 156 return (0); 157 } 158 #endif 159 /* could be set multiple times */ 160 while (__findenv(name, (int)(np - name), &tmpoff)) { 161 for (P = &environ[tmpoff];; ++P) 162 if (!(*P = *(P + 1))) 163 break; 164 } 165 } else { /* create new slot */ 166 size_t cnt; 167 168 for (P = environ; *P != NULL; P++) 169 ; 170 cnt = P - environ; 171 P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); 172 if (!P) 173 return (-1); 174 if (lastenv != environ) 175 memcpy(P, environ, cnt * sizeof(char *)); 176 lastenv = environ = P; 177 offset = cnt; 178 environ[cnt + 1] = NULL; 179 } 180 if (!(environ[offset] = /* name + `=' + value */ 181 malloc((size_t)((int)(np - name) + l_value + 2)))) 182 return (-1); 183 for (C = environ[offset]; (*C = *name++) && *C != '='; ++C) 184 ; 185 for (*C++ = '='; (*C++ = *value++); ) 186 ; 187 return (0); 188 } 189 190 #endif /* HAVE_SETENV */ 191 192 #ifndef HAVE_UNSETENV 193 /* 194 * unsetenv(name) -- 195 * Delete environmental variable "name". 196 */ 197 int 198 unsetenv(const char *name) 199 { 200 char **P; 201 const char *np; 202 int offset = 0; 203 204 if (!name || !*name) { 205 errno = EINVAL; 206 return (-1); 207 } 208 for (np = name; *np && *np != '='; ++np) 209 ; 210 if (*np) { 211 errno = EINVAL; 212 return (-1); /* has `=' in name */ 213 } 214 215 /* could be set multiple times */ 216 while (__findenv(name, (int)(np - name), &offset)) { 217 for (P = &environ[offset];; ++P) 218 if (!(*P = *(P + 1))) 219 break; 220 } 221 return (0); 222 } 223 #endif /* HAVE_UNSETENV */ 224 225 #endif /* !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) */ 226 227