131de2854Smrg/*	$OpenBSD: setenv.c,v 1.13 2010/08/23 22:31:50 millert Exp $ */
231de2854Smrg/*
331de2854Smrg * Copyright (c) 1987 Regents of the University of California.
431de2854Smrg * All rights reserved.
531de2854Smrg *
631de2854Smrg * Redistribution and use in source and binary forms, with or without
731de2854Smrg * modification, are permitted provided that the following conditions
831de2854Smrg * are met:
931de2854Smrg * 1. Redistributions of source code must retain the above copyright
1031de2854Smrg *    notice, this list of conditions and the following disclaimer.
1131de2854Smrg * 2. Redistributions in binary form must reproduce the above copyright
1231de2854Smrg *    notice, this list of conditions and the following disclaimer in the
1331de2854Smrg *    documentation and/or other materials provided with the distribution.
1431de2854Smrg * 3. Neither the name of the University nor the names of its contributors
1531de2854Smrg *    may be used to endorse or promote products derived from this software
1631de2854Smrg *    without specific prior written permission.
1731de2854Smrg *
1831de2854Smrg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1931de2854Smrg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2031de2854Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2131de2854Smrg * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2231de2854Smrg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2331de2854Smrg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2431de2854Smrg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2531de2854Smrg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2631de2854Smrg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2731de2854Smrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2831de2854Smrg * SUCH DAMAGE.
2931de2854Smrg */
3031de2854Smrg
3131de2854Smrg#include <errno.h>
3231de2854Smrg#include <stdlib.h>
3331de2854Smrg#include <string.h>
3431de2854Smrg
3531de2854Smrgchar *__findenv(const char *name, int len, int *offset);
3631de2854Smrg
3731de2854Smrgextern char **environ;
3831de2854Smrgstatic char **lastenv;				/* last value of environ */
3931de2854Smrg
4031de2854Smrg/*
4131de2854Smrg * putenv --
4231de2854Smrg *	Add a name=value string directly to the environmental, replacing
4331de2854Smrg *	any current value.
4431de2854Smrg */
4531de2854Smrgint
4631de2854Smrgputenv(char *str)
4731de2854Smrg{
4831de2854Smrg	char **P, *cp;
4931de2854Smrg	size_t cnt;
5031de2854Smrg	int offset = 0;
5131de2854Smrg
5231de2854Smrg	for (cp = str; *cp && *cp != '='; ++cp)
5331de2854Smrg		;
5431de2854Smrg	if (*cp != '=') {
5531de2854Smrg		errno = EINVAL;
5631de2854Smrg		return (-1);			/* missing `=' in string */
5731de2854Smrg	}
5831de2854Smrg
5931de2854Smrg	if (__findenv(str, (int)(cp - str), &offset) != NULL) {
6031de2854Smrg		environ[offset++] = str;
6131de2854Smrg		/* could be set multiple times */
6231de2854Smrg		while (__findenv(str, (int)(cp - str), &offset)) {
6331de2854Smrg			for (P = &environ[offset];; ++P)
6431de2854Smrg				if (!(*P = *(P + 1)))
6531de2854Smrg					break;
6631de2854Smrg		}
6731de2854Smrg		return (0);
6831de2854Smrg	}
6931de2854Smrg
7031de2854Smrg	/* create new slot for string */
7131de2854Smrg	for (P = environ; *P != NULL; P++)
7231de2854Smrg		;
7331de2854Smrg	cnt = P - environ;
7431de2854Smrg	P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
7531de2854Smrg	if (!P)
7631de2854Smrg		return (-1);
7731de2854Smrg	if (lastenv != environ)
7831de2854Smrg		memcpy(P, environ, cnt * sizeof(char *));
7931de2854Smrg	lastenv = environ = P;
8031de2854Smrg	environ[cnt] = str;
8131de2854Smrg	environ[cnt + 1] = NULL;
8231de2854Smrg	return (0);
8331de2854Smrg}
8431de2854Smrg
8531de2854Smrg/*
8631de2854Smrg * setenv --
8731de2854Smrg *	Set the value of the environmental variable "name" to be
8831de2854Smrg *	"value".  If rewrite is set, replace any current value.
8931de2854Smrg */
9031de2854Smrgint
9131de2854Smrgsetenv(const char *name, const char *value, int rewrite)
9231de2854Smrg{
9331de2854Smrg	char *C, **P;
9431de2854Smrg	const char *np;
9531de2854Smrg	int l_value, offset = 0;
9631de2854Smrg
9731de2854Smrg	for (np = name; *np && *np != '='; ++np)
9831de2854Smrg		;
9931de2854Smrg#ifdef notyet
10031de2854Smrg	if (*np) {
10131de2854Smrg		errno = EINVAL;
10231de2854Smrg		return (-1);			/* has `=' in name */
10331de2854Smrg	}
10431de2854Smrg#endif
10531de2854Smrg
10631de2854Smrg	l_value = strlen(value);
10731de2854Smrg	if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) {
10831de2854Smrg		int tmpoff = offset + 1;
10931de2854Smrg		if (!rewrite)
11031de2854Smrg			return (0);
11131de2854Smrg#if 0 /* XXX - existing entry may not be writable */
11231de2854Smrg		if (strlen(C) >= l_value) {	/* old larger; copy over */
11331de2854Smrg			while ((*C++ = *value++))
11431de2854Smrg				;
11531de2854Smrg			return (0);
11631de2854Smrg		}
11731de2854Smrg#endif
11831de2854Smrg		/* could be set multiple times */
11931de2854Smrg		while (__findenv(name, (int)(np - name), &tmpoff)) {
12031de2854Smrg			for (P = &environ[tmpoff];; ++P)
12131de2854Smrg				if (!(*P = *(P + 1)))
12231de2854Smrg					break;
12331de2854Smrg		}
12431de2854Smrg	} else {					/* create new slot */
12531de2854Smrg		size_t cnt;
12631de2854Smrg
12731de2854Smrg		for (P = environ; *P != NULL; P++)
12831de2854Smrg			;
12931de2854Smrg		cnt = P - environ;
13031de2854Smrg		P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
13131de2854Smrg		if (!P)
13231de2854Smrg			return (-1);
13331de2854Smrg		if (lastenv != environ)
13431de2854Smrg			memcpy(P, environ, cnt * sizeof(char *));
13531de2854Smrg		lastenv = environ = P;
13631de2854Smrg		offset = cnt;
13731de2854Smrg		environ[cnt + 1] = NULL;
13831de2854Smrg	}
13931de2854Smrg	if (!(environ[offset] =			/* name + `=' + value */
14031de2854Smrg	    malloc((size_t)((int)(np - name) + l_value + 2))))
14131de2854Smrg		return (-1);
14231de2854Smrg	for (C = environ[offset]; (*C = *name++) && *C != '='; ++C)
14331de2854Smrg		;
14431de2854Smrg	for (*C++ = '='; (*C++ = *value++); )
14531de2854Smrg		;
14631de2854Smrg	return (0);
14731de2854Smrg}
14831de2854Smrg
14931de2854Smrg/*
15031de2854Smrg * unsetenv(name) --
15131de2854Smrg *	Delete environmental variable "name".
15231de2854Smrg */
15331de2854Smrgint
15431de2854Smrgunsetenv(const char *name)
15531de2854Smrg{
15631de2854Smrg	char **P;
15731de2854Smrg	const char *np;
15831de2854Smrg	int offset = 0;
15931de2854Smrg
16031de2854Smrg	if (!name || !*name) {
16131de2854Smrg		errno = EINVAL;
16231de2854Smrg		return (-1);
16331de2854Smrg	}
16431de2854Smrg	for (np = name; *np && *np != '='; ++np)
16531de2854Smrg		;
16631de2854Smrg	if (*np) {
16731de2854Smrg		errno = EINVAL;
16831de2854Smrg		return (-1);			/* has `=' in name */
16931de2854Smrg	}
17031de2854Smrg
17131de2854Smrg	/* could be set multiple times */
17231de2854Smrg	while (__findenv(name, (int)(np - name), &offset)) {
17331de2854Smrg		for (P = &environ[offset];; ++P)
17431de2854Smrg			if (!(*P = *(P + 1)))
17531de2854Smrg				break;
17631de2854Smrg	}
17731de2854Smrg	return (0);
17831de2854Smrg}
179