1240075Sdes/* $OpenBSD: setenv.c,v 1.13 2010/08/23 22:31:50 millert Exp $ */ 298937Sdes/* 398937Sdes * Copyright (c) 1987 Regents of the University of California. 498937Sdes * All rights reserved. 598937Sdes * 698937Sdes * Redistribution and use in source and binary forms, with or without 798937Sdes * modification, are permitted provided that the following conditions 898937Sdes * are met: 998937Sdes * 1. Redistributions of source code must retain the above copyright 1098937Sdes * notice, this list of conditions and the following disclaimer. 1198937Sdes * 2. Redistributions in binary form must reproduce the above copyright 1298937Sdes * notice, this list of conditions and the following disclaimer in the 1398937Sdes * documentation and/or other materials provided with the distribution. 14124208Sdes * 3. Neither the name of the University nor the names of its contributors 1598937Sdes * may be used to endorse or promote products derived from this software 1698937Sdes * without specific prior written permission. 1798937Sdes * 1898937Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1998937Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2098937Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2198937Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2298937Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2398937Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2498937Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2598937Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2698937Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2798937Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2898937Sdes * SUCH DAMAGE. 2998937Sdes */ 3098937Sdes 31157016Sdes/* OPENBSD ORIGINAL: lib/libc/stdlib/setenv.c */ 32157016Sdes 33106121Sdes#include "includes.h" 34240075Sdes 35128456Sdes#if !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) 3698937Sdes 37240075Sdes#include <errno.h> 3898937Sdes#include <stdlib.h> 3998937Sdes#include <string.h> 4098937Sdes 41157016Sdesextern char **environ; 42240075Sdesstatic char **lastenv; /* last value of environ */ 43113908Sdes 44157016Sdes/* OpenSSH Portable: __findenv is from getenv.c rev 1.8, made static */ 4598937Sdes/* 4698937Sdes * __findenv -- 4798937Sdes * Returns pointer to value associated with name, if any, else NULL. 48240075Sdes * Starts searching within the environmental array at offset. 4998937Sdes * Sets offset to be the offset of the name/value combination in the 50240075Sdes * environmental array, for use by putenv(3), setenv(3) and unsetenv(3). 5198937Sdes * Explicitly removes '=' in argument name. 52240075Sdes * 53240075Sdes * This routine *should* be a static; don't use it. 5498937Sdes */ 55157016Sdesstatic char * 56240075Sdes__findenv(const char *name, int len, int *offset) 5798937Sdes{ 5898937Sdes extern char **environ; 59240075Sdes int i; 60157016Sdes const char *np; 61157016Sdes char **p, *cp; 6298937Sdes 6398937Sdes if (name == NULL || environ == NULL) 6498937Sdes return (NULL); 65240075Sdes for (p = environ + *offset; (cp = *p) != NULL; ++p) { 6698937Sdes for (np = name, i = len; i && *cp; i--) 6798937Sdes if (*cp++ != *np++) 6898937Sdes break; 6998937Sdes if (i == 0 && *cp++ == '=') { 7098937Sdes *offset = p - environ; 7198937Sdes return (cp); 7298937Sdes } 7398937Sdes } 7498937Sdes return (NULL); 7598937Sdes} 7698937Sdes 77240075Sdes#if 0 /* nothing uses putenv */ 78240075Sdes/* 79240075Sdes * putenv -- 80240075Sdes * Add a name=value string directly to the environmental, replacing 81240075Sdes * any current value. 82240075Sdes */ 83240075Sdesint 84240075Sdesputenv(char *str) 85240075Sdes{ 86240075Sdes char **P, *cp; 87240075Sdes size_t cnt; 88240075Sdes int offset = 0; 89240075Sdes 90240075Sdes for (cp = str; *cp && *cp != '='; ++cp) 91240075Sdes ; 92240075Sdes if (*cp != '=') { 93240075Sdes errno = EINVAL; 94240075Sdes return (-1); /* missing `=' in string */ 95240075Sdes } 96240075Sdes 97240075Sdes if (__findenv(str, (int)(cp - str), &offset) != NULL) { 98240075Sdes environ[offset++] = str; 99240075Sdes /* could be set multiple times */ 100240075Sdes while (__findenv(str, (int)(cp - str), &offset)) { 101240075Sdes for (P = &environ[offset];; ++P) 102240075Sdes if (!(*P = *(P + 1))) 103240075Sdes break; 104240075Sdes } 105240075Sdes return (0); 106240075Sdes } 107240075Sdes 108240075Sdes /* create new slot for string */ 109240075Sdes for (P = environ; *P != NULL; P++) 110240075Sdes ; 111240075Sdes cnt = P - environ; 112240075Sdes P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); 113240075Sdes if (!P) 114240075Sdes return (-1); 115240075Sdes if (lastenv != environ) 116240075Sdes memcpy(P, environ, cnt * sizeof(char *)); 117240075Sdes lastenv = environ = P; 118240075Sdes environ[cnt] = str; 119240075Sdes environ[cnt + 1] = NULL; 120240075Sdes return (0); 121240075Sdes} 122240075Sdes 123240075Sdes#endif 124240075Sdes 125128456Sdes#ifndef HAVE_SETENV 12698937Sdes/* 12798937Sdes * setenv -- 12898937Sdes * Set the value of the environmental variable "name" to be 12998937Sdes * "value". If rewrite is set, replace any current value. 13098937Sdes */ 13198937Sdesint 132157016Sdessetenv(const char *name, const char *value, int rewrite) 13398937Sdes{ 134240075Sdes char *C, **P; 135240075Sdes const char *np; 136240075Sdes int l_value, offset = 0; 13798937Sdes 138240075Sdes for (np = name; *np && *np != '='; ++np) 139240075Sdes ; 140240075Sdes#ifdef notyet 141240075Sdes if (*np) { 142240075Sdes errno = EINVAL; 143240075Sdes return (-1); /* has `=' in name */ 144240075Sdes } 145240075Sdes#endif 146240075Sdes 14798937Sdes l_value = strlen(value); 148240075Sdes if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) { 149240075Sdes int tmpoff = offset + 1; 15098937Sdes if (!rewrite) 15198937Sdes return (0); 152240075Sdes#if 0 /* XXX - existing entry may not be writable */ 15398937Sdes if (strlen(C) >= l_value) { /* old larger; copy over */ 15498937Sdes while ((*C++ = *value++)) 15598937Sdes ; 15698937Sdes return (0); 15798937Sdes } 158240075Sdes#endif 159240075Sdes /* could be set multiple times */ 160240075Sdes while (__findenv(name, (int)(np - name), &tmpoff)) { 161240075Sdes for (P = &environ[tmpoff];; ++P) 162240075Sdes if (!(*P = *(P + 1))) 163240075Sdes break; 164240075Sdes } 16598937Sdes } else { /* create new slot */ 166157016Sdes size_t cnt; 16798937Sdes 168157016Sdes for (P = environ; *P != NULL; P++) 169157016Sdes ; 170157016Sdes cnt = P - environ; 171157016Sdes P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); 172157016Sdes if (!P) 173157016Sdes return (-1); 174157016Sdes if (lastenv != environ) 175157016Sdes memcpy(P, environ, cnt * sizeof(char *)); 176157016Sdes lastenv = environ = P; 177157016Sdes offset = cnt; 17898937Sdes environ[cnt + 1] = NULL; 17998937Sdes } 18098937Sdes if (!(environ[offset] = /* name + `=' + value */ 181240075Sdes malloc((size_t)((int)(np - name) + l_value + 2)))) 18298937Sdes return (-1); 18398937Sdes for (C = environ[offset]; (*C = *name++) && *C != '='; ++C) 18498937Sdes ; 18598937Sdes for (*C++ = '='; (*C++ = *value++); ) 18698937Sdes ; 18798937Sdes return (0); 18898937Sdes} 189240075Sdes 190128456Sdes#endif /* HAVE_SETENV */ 19198937Sdes 192128456Sdes#ifndef HAVE_UNSETENV 19398937Sdes/* 19498937Sdes * unsetenv(name) -- 19598937Sdes * Delete environmental variable "name". 19698937Sdes */ 197240075Sdesint 198157016Sdesunsetenv(const char *name) 19998937Sdes{ 200157016Sdes char **P; 201240075Sdes const char *np; 202240075Sdes int offset = 0; 20398937Sdes 204240075Sdes if (!name || !*name) { 205240075Sdes errno = EINVAL; 206240075Sdes return (-1); 207240075Sdes } 208240075Sdes for (np = name; *np && *np != '='; ++np) 209240075Sdes ; 210240075Sdes if (*np) { 211240075Sdes errno = EINVAL; 212240075Sdes return (-1); /* has `=' in name */ 213240075Sdes } 214240075Sdes 215240075Sdes /* could be set multiple times */ 216240075Sdes while (__findenv(name, (int)(np - name), &offset)) { 21798937Sdes for (P = &environ[offset];; ++P) 21898937Sdes if (!(*P = *(P + 1))) 21998937Sdes break; 220240075Sdes } 221240075Sdes return (0); 22298937Sdes} 223128456Sdes#endif /* HAVE_UNSETENV */ 22498937Sdes 225128456Sdes#endif /* !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) */ 226240075Sdes 227