xref: /freebsd/usr.sbin/cron/lib/env.c (revision d0b2dbfa)
1 /* Copyright 1988,1990,1993,1994 by Paul Vixie
2  * All rights reserved
3  */
4 
5 /*
6  * Copyright (c) 1997 by Internet Software Consortium
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
13  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
14  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
15  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
18  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
19  * SOFTWARE.
20  */
21 
22 #if !defined(lint) && !defined(LINT)
23 static const char rcsid[] = "$Id: env.c,v 1.3 1998/08/14 00:32:39 vixie Exp $";
24 #endif
25 
26 
27 #include "cron.h"
28 
29 
30 char **
31 env_init(void)
32 {
33 	char	**p = (char **) malloc(sizeof(char **));
34 
35 	if (p)
36 		p[0] = NULL;
37 	return (p);
38 }
39 
40 
41 void
42 env_free(char **envp)
43 {
44 	char	**p;
45 
46 	if ((p = envp))
47 	    for (;  *p;  p++)
48 		free(*p);
49 	free(envp);
50 }
51 
52 
53 char **
54 env_copy(char **envp)
55 {
56 	int	count, i;
57 	char	**p;
58 
59 	for (count = 0;  envp[count] != NULL;  count++)
60 		;
61 	p = (char **) malloc((count+1) * sizeof(char *)); /* 1 for the NULL */
62 	if (p == NULL) {
63 		errno = ENOMEM;
64 		return NULL;
65 	}
66 	for (i = 0;  i < count;  i++)
67 		if ((p[i] = strdup(envp[i])) == NULL) {
68 			while (--i >= 0)
69 				(void) free(p[i]);
70 			free(p);
71 			errno = ENOMEM;
72 			return NULL;
73 		}
74 	p[count] = NULL;
75 	return (p);
76 }
77 
78 
79 char **
80 env_set(char **envp, char *envstr)
81 {
82 	int	count, found;
83 	char	**p;
84 	char	*q;
85 
86 	/*
87 	 * count the number of elements, including the null pointer;
88 	 * also set 'found' to -1 or index of entry if already in here.
89 	 */
90 	found = -1;
91 	for (count = 0;  envp[count] != NULL;  count++) {
92 		if (!strcmp_until(envp[count], envstr, '='))
93 			found = count;
94 	}
95 	count++;	/* for the NULL */
96 
97 	if (found != -1) {
98 		/*
99 		 * it exists already, so just free the existing setting,
100 		 * save our new one there, and return the existing array.
101 		 */
102 		q = envp[found];
103 		if ((envp[found] = strdup(envstr)) == NULL) {
104 			envp[found] = q;
105 			/* XXX env_free(envp); */
106 			errno = ENOMEM;
107 			return NULL;
108 		}
109 		free(q);
110 		return (envp);
111 	}
112 
113 	/*
114 	 * it doesn't exist yet, so resize the array, move null pointer over
115 	 * one, save our string over the old null pointer, and return resized
116 	 * array.
117 	 */
118 	p = (char **) realloc((void *) envp,
119 			      (unsigned) ((count+1) * sizeof(char *)));
120 	if (p == NULL) 	{
121 		/* XXX env_free(envp); */
122 		errno = ENOMEM;
123 		return NULL;
124 	}
125 	p[count] = p[count-1];
126 	if ((p[count-1] = strdup(envstr)) == NULL) {
127 		env_free(p);
128 		errno = ENOMEM;
129 		return NULL;
130 	}
131 	return (p);
132 }
133 
134 
135 /* return	ERR = end of file
136  *		FALSE = not an env setting (file was repositioned)
137  *		TRUE = was an env setting
138  */
139 int
140 load_env(char *envstr, FILE *f)
141 {
142 	long	filepos;
143 	int	fileline;
144 	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
145 	char	quotechar, *c, *str;
146 	int	state;
147 
148 	/* The following states are traversed in order: */
149 #define NAMEI	0	/* First char of NAME, may be quote */
150 #define NAME	1	/* Subsequent chars of NAME */
151 #define EQ1	2	/* After end of name, looking for '=' sign */
152 #define EQ2	3	/* After '=', skipping whitespace */
153 #define VALUEI	4	/* First char of VALUE, may be quote */
154 #define VALUE	5	/* Subsequent chars of VALUE */
155 #define FINI	6	/* All done, skipping trailing whitespace */
156 #define ERROR	7	/* Error */
157 
158 	filepos = ftell(f);
159 	fileline = LineNumber;
160 	skip_comments(f);
161 	if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
162 		return (ERR);
163 
164 	Debug(DPARS, ("load_env, read <%s>\n", envstr));
165 
166 	bzero (name, sizeof name);
167 	bzero (val, sizeof val);
168 	str = name;
169 	state = NAMEI;
170 	quotechar = '\0';
171 	c = envstr;
172 	while (state != ERROR && *c) {
173 		switch (state) {
174 		case NAMEI:
175 		case VALUEI:
176 			if (*c == '\'' || *c == '"')
177 				quotechar = *c++;
178 			++state;
179 			/* FALLTHROUGH */
180 		case NAME:
181 		case VALUE:
182 			if (quotechar) {
183 				if (*c == quotechar) {
184 					state++;
185 					c++;
186 					break;
187 				}
188 				if (state == NAME && *c == '=') {
189 					state = ERROR;
190 					break;
191 				}
192 			} else {
193 				if (state == NAME) {
194 					if (isspace (*c)) {
195 						c++;
196 						state++;
197 						break;
198 					}
199 					if (*c == '=') {
200 						state++;
201 						break;
202 					}
203 				}
204 			}
205 			*str++ = *c++;
206 			break;
207 
208 		case EQ1:
209 			if (*c == '=') {
210 				state++;
211 				str = val;
212 				quotechar = '\0';
213 			} else {
214 				if (!isspace (*c))
215 					state = ERROR;
216 			}
217 			c++;
218 			break;
219 		case EQ2:
220 		case FINI:
221 			if (isspace (*c))
222 				c++;
223 			else
224 				state++;
225 			break;
226 		}
227 	}
228 	if (state != FINI && !(state == VALUE && !quotechar)) {
229 		Debug(DPARS, ("load_env, parse error, state = %d\n", state))
230 		fseek(f, filepos, 0);
231 		Set_LineNum(fileline);
232 		return (FALSE);
233 	}
234 	if (state == VALUE) {
235 		/* End of unquoted value: trim trailing whitespace */
236 		c = val + strlen (val);
237 		while (c > val && isspace (*(c - 1)))
238 			*(--c) = '\0';
239 	}
240 
241 	/* 2 fields from parser; looks like an env setting */
242 
243 	if (snprintf(envstr, MAX_ENVSTR, "%s=%s", name, val) >= MAX_ENVSTR)
244 		return (FALSE);
245 	Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
246 	return (TRUE);
247 }
248 
249 
250 char *
251 env_get(char *name, char **envp)
252 {
253 	int	len = strlen(name);
254 	char	*p, *q;
255 
256 	while ((p = *envp++) != NULL) {
257 		if (!(q = strchr(p, '=')))
258 			continue;
259 		if ((q - p) == len && !strncmp(p, name, len))
260 			return (q+1);
261 	}
262 	return (NULL);
263 }
264