12311Sjkh/* Copyright 1988,1990,1993,1994 by Paul Vixie
22311Sjkh * All rights reserved
32311Sjkh *
42311Sjkh * Distribute freely, except: don't remove my name from the source or
52311Sjkh * documentation (don't take credit for my work), mark your changes (don't
62311Sjkh * get me blamed for your possible bugs), don't alter or remove this
72311Sjkh * notice.  May be sold if buildable source is provided to buyer.  No
82311Sjkh * warrantee of any kind, express or implied, is included with this
92311Sjkh * software; use at your own risk, responsibility for damages (if any) to
102311Sjkh * anyone resulting from the use of this software rests entirely with the
112311Sjkh * user.
122311Sjkh *
132311Sjkh * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
142311Sjkh * I'll try to keep a version up to date.  I can be reached as follows:
152311Sjkh * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
162311Sjkh */
172311Sjkh
182311Sjkh#if !defined(lint) && !defined(LINT)
1929452Scharnierstatic const char rcsid[] =
2050479Speter  "$FreeBSD$";
212311Sjkh#endif
222311Sjkh
232311Sjkh
242311Sjkh#include "cron.h"
252311Sjkh
262311Sjkh
272311Sjkhchar **
282311Sjkhenv_init()
292311Sjkh{
3059785Sghelmer	register char	**p = (char **) malloc(sizeof(char *));
312311Sjkh
3220573Spst	if (p)
3320573Spst		p[0] = NULL;
342311Sjkh	return (p);
352311Sjkh}
362311Sjkh
372311Sjkh
382311Sjkhvoid
392311Sjkhenv_free(envp)
402311Sjkh	char	**envp;
412311Sjkh{
422311Sjkh	char	**p;
432311Sjkh
4480030Sdavidn	if ((p = envp))
4580030Sdavidn	    for (;  *p;  p++)
462311Sjkh		free(*p);
472311Sjkh	free(envp);
482311Sjkh}
492311Sjkh
502311Sjkh
512311Sjkhchar **
522311Sjkhenv_copy(envp)
532311Sjkh	register char	**envp;
542311Sjkh{
552311Sjkh	register int	count, i;
562311Sjkh	register char	**p;
572311Sjkh
582311Sjkh	for (count = 0;  envp[count] != NULL;  count++)
592311Sjkh		;
6059785Sghelmer	p = (char **) malloc((count+1) * sizeof(char *)); /* 1 for the NULL */
6120573Spst	if (p == NULL) {
6220573Spst		errno = ENOMEM;
6320573Spst		return NULL;
6420573Spst	}
652311Sjkh	for (i = 0;  i < count;  i++)
6620573Spst		if ((p[i] = strdup(envp[i])) == NULL) {
6720573Spst			while (--i >= 0)
6820573Spst				(void) free(p[i]);
6920573Spst			free(p);
7020573Spst			errno = ENOMEM;
7120573Spst			return NULL;
7220573Spst		}
732311Sjkh	p[count] = NULL;
742311Sjkh	return (p);
752311Sjkh}
762311Sjkh
772311Sjkh
782311Sjkhchar **
792311Sjkhenv_set(envp, envstr)
802311Sjkh	char	**envp;
812311Sjkh	char	*envstr;
822311Sjkh{
832311Sjkh	register int	count, found;
842311Sjkh	register char	**p;
8559727Sghelmer	char		*q;
862311Sjkh
872311Sjkh	/*
882311Sjkh	 * count the number of elements, including the null pointer;
892311Sjkh	 * also set 'found' to -1 or index of entry if already in here.
902311Sjkh	 */
912311Sjkh	found = -1;
922311Sjkh	for (count = 0;  envp[count] != NULL;  count++) {
932311Sjkh		if (!strcmp_until(envp[count], envstr, '='))
942311Sjkh			found = count;
952311Sjkh	}
962311Sjkh	count++;	/* for the NULL */
972311Sjkh
982311Sjkh	if (found != -1) {
992311Sjkh		/*
1002311Sjkh		 * it exists already, so just free the existing setting,
1012311Sjkh		 * save our new one there, and return the existing array.
1022311Sjkh		 */
10359727Sghelmer		q = envp[found];
10420573Spst		if ((envp[found] = strdup(envstr)) == NULL) {
10559727Sghelmer			envp[found] = q;
10659727Sghelmer			/* XXX env_free(envp); */
10720573Spst			errno = ENOMEM;
10820573Spst			return NULL;
10920573Spst		}
11059727Sghelmer		free(q);
1112311Sjkh		return (envp);
1122311Sjkh	}
1132311Sjkh
1142311Sjkh	/*
1152311Sjkh	 * it doesn't exist yet, so resize the array, move null pointer over
1162311Sjkh	 * one, save our string over the old null pointer, and return resized
1172311Sjkh	 * array.
1182311Sjkh	 */
1192311Sjkh	p = (char **) realloc((void *) envp,
12059785Sghelmer			      (unsigned) ((count+1) * sizeof(char *)));
12120573Spst	if (p == NULL) 	{
12259727Sghelmer		/* XXX env_free(envp); */
12320573Spst		errno = ENOMEM;
12420573Spst		return NULL;
12520573Spst	}
1262311Sjkh	p[count] = p[count-1];
12720573Spst	if ((p[count-1] = strdup(envstr)) == NULL) {
12859727Sghelmer		env_free(p);
12920573Spst		errno = ENOMEM;
13020573Spst		return NULL;
13120573Spst	}
1322311Sjkh	return (p);
1332311Sjkh}
1342311Sjkh
1352311Sjkh
1362311Sjkh/* return	ERR = end of file
1372311Sjkh *		FALSE = not an env setting (file was repositioned)
1382311Sjkh *		TRUE = was an env setting
1392311Sjkh */
1402311Sjkhint
1412311Sjkhload_env(envstr, f)
1422311Sjkh	char	*envstr;
1432311Sjkh	FILE	*f;
1442311Sjkh{
1452311Sjkh	long	filepos;
1462311Sjkh	int	fileline;
14720557Spst	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
14897165Sroberto	char	quotechar, *c, *str;
14997165Sroberto	int	state;
1502311Sjkh
15197165Sroberto	/* The following states are traversed in order: */
15297165Sroberto#define NAMEI	0	/* First char of NAME, may be quote */
15397165Sroberto#define NAME	1	/* Subsequent chars of NAME */
15497165Sroberto#define EQ1	2	/* After end of name, looking for '=' sign */
15597165Sroberto#define EQ2	3	/* After '=', skipping whitespace */
15697165Sroberto#define VALUEI	4	/* First char of VALUE, may be quote */
15797165Sroberto#define VALUE	5	/* Subsequent chars of VALUE */
15897165Sroberto#define FINI	6	/* All done, skipping trailing whitespace */
15997165Sroberto#define ERROR	7	/* Error */
16097165Sroberto
1612311Sjkh	filepos = ftell(f);
1622311Sjkh	fileline = LineNumber;
1632311Sjkh	skip_comments(f);
1642311Sjkh	if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
1652311Sjkh		return (ERR);
1662311Sjkh
16797165Sroberto	Debug(DPARS, ("load_env, read <%s>\n", envstr));
1682311Sjkh
16997165Sroberto	bzero (name, sizeof name);
17097165Sroberto	bzero (val, sizeof val);
17197165Sroberto	str = name;
17297165Sroberto	state = NAMEI;
17397165Sroberto	quotechar = '\0';
17497165Sroberto	c = envstr;
17597165Sroberto	while (state != ERROR && *c) {
17697165Sroberto		switch (state) {
17797165Sroberto		case NAMEI:
17897165Sroberto		case VALUEI:
17997165Sroberto			if (*c == '\'' || *c == '"')
18097165Sroberto				quotechar = *c++;
18197165Sroberto			++state;
18297165Sroberto			/* FALLTHROUGH */
18397165Sroberto		case NAME:
18497165Sroberto		case VALUE:
18597165Sroberto			if (quotechar) {
18697165Sroberto				if (*c == quotechar) {
18797165Sroberto					state++;
18897165Sroberto					c++;
18997165Sroberto					break;
19097165Sroberto				}
19197165Sroberto				if (state == NAME && *c == '=') {
19297165Sroberto					state = ERROR;
19397165Sroberto					break;
19497165Sroberto				}
19597165Sroberto			} else {
196110638Sthomas				if (state == NAME) {
197110638Sthomas					if (isspace (*c)) {
198110638Sthomas						c++;
199110638Sthomas						state++;
200110638Sthomas						break;
201110638Sthomas					}
202110638Sthomas					if (*c == '=') {
203110638Sthomas						state++;
204110638Sthomas						break;
205110638Sthomas					}
20697165Sroberto				}
20797165Sroberto			}
20897165Sroberto			*str++ = *c++;
20997165Sroberto			break;
21097165Sroberto
21197165Sroberto		case EQ1:
21297165Sroberto			if (*c == '=') {
21397165Sroberto				state++;
21497165Sroberto				str = val;
21597165Sroberto				quotechar = '\0';
21697165Sroberto			} else {
21797165Sroberto				if (!isspace (*c))
21897165Sroberto					state = ERROR;
21997165Sroberto			}
22097165Sroberto			c++;
22197165Sroberto			break;
22297165Sroberto		case EQ2:
22397165Sroberto		case FINI:
22497165Sroberto			if (isspace (*c))
22597165Sroberto				c++;
22697165Sroberto			else
22797165Sroberto				state++;
22897165Sroberto			break;
22997165Sroberto		}
23097165Sroberto	}
23197165Sroberto	if (state != FINI && !(state == VALUE && !quotechar)) {
23297165Sroberto		Debug(DPARS, ("load_env, parse error, state = %d\n", state))
2332311Sjkh		fseek(f, filepos, 0);
2342311Sjkh		Set_LineNum(fileline);
2352311Sjkh		return (FALSE);
2362311Sjkh	}
237110638Sthomas	if (state == VALUE) {
238110638Sthomas		/* End of unquoted value: trim trailing whitespace */
239110638Sthomas		c = val + strlen (val);
240110638Sthomas		while (c > val && isspace (*(c - 1)))
241110638Sthomas			*(--c) = '\0';
242110638Sthomas	}
2432311Sjkh
244110638Sthomas	/* 2 fields from parser; looks like an env setting */
2452311Sjkh
24620573Spst	if (strlen(name) + 1 + strlen(val) >= MAX_ENVSTR-1)
24720573Spst		return (FALSE);
2482311Sjkh	(void) sprintf(envstr, "%s=%s", name, val);
2492311Sjkh	Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
2502311Sjkh	return (TRUE);
2512311Sjkh}
2522311Sjkh
2532311Sjkh
2542311Sjkhchar *
2552311Sjkhenv_get(name, envp)
2562311Sjkh	register char	*name;
2572311Sjkh	register char	**envp;
2582311Sjkh{
2592311Sjkh	register int	len = strlen(name);
2602311Sjkh	register char	*p, *q;
2612311Sjkh
26229452Scharnier	while ((p = *envp++)) {
2632311Sjkh		if (!(q = strchr(p, '=')))
2642311Sjkh			continue;
2652311Sjkh		if ((q - p) == len && !strncmp(p, name, len))
2662311Sjkh			return (q+1);
2672311Sjkh	}
2682311Sjkh	return (NULL);
2692311Sjkh}
270