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