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