1 /* Copyright 1988,1990,1993,1994 by Paul Vixie
2 * All rights reserved
3 */
4
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include "config.h"
23
24 #include <ctype.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include "globals.h"
32 #include "funcs.h"
33
34 #if defined(BSD)
35 extern char **environ;
36 #endif
37
38 char **env_init(void) {
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
39 char **p = (char **) malloc(sizeof (char *));
40
41 if (p != NULL)
42 p[0] = NULL;
43 return (p);
44 }
45
46 void env_free(char **envp) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
47 char **p;
48
49 for (p = envp; *p != NULL; p++)
50 free(*p);
51 free(envp);
52 }
53
54 char **env_copy(char **envp) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
55 int save_errno;
56 size_t 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 for (i = 0; i < count; i++)
64 if ((p[i] = strdup(envp[i])) == NULL) {
65 save_errno = errno;
66 while (i-- > 0)
67 free(p[i]);
68 free(p);
69 errno = save_errno;
70 return (NULL);
71 }
72 p[count] = NULL;
73 }
74 return (p);
75 }
76
77 char **env_set(char **envp, const char *envstr) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
78 size_t count, found;
79 char **p, *envtmp;
80
81 /*
82 * count the number of elements, including the null pointer;
83 * also set 'found' to -1 or index of entry if already in here.
84 */
85 found = (size_t)-1;
86 for (count = 0; envp[count] != NULL; count++) {
87 if (!strcmp_until(envp[count], envstr, '='))
88 found = count;
89 }
90 count++; /* for the NULL */
91
92 if (found != (size_t)-1) {
93 /*
94 * it exists already, so just free the existing setting,
95 * save our new one there, and return the existing array.
96 */
97 if ((envtmp = strdup(envstr)) == NULL)
98 return (NULL);
99 free(envp[found]);
100 envp[found] = envtmp;
101 return (envp);
102 }
103
104 /*
105 * it doesn't exist yet, so resize the array, move null pointer over
106 * one, save our string over the old null pointer, and return resized
107 * array.
108 */
109 if ((envtmp = strdup(envstr)) == NULL)
110 return (NULL);
111 p = (char **) realloc((void *) envp,
112 (count + 1) * sizeof (char *));
113 if (p == NULL) {
114 free(envtmp);
115 return (NULL);
116 }
117 p[count] = p[count - 1];
118 p[count - 1] = envtmp;
119 return (p);
120 }
121
122 int env_set_from_environ(char ***envpp) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
123 static const char *names[] = {
124 "LANG",
125 "LC_CTYPE",
126 "LC_NUMERIC",
127 "LC_TIME",
128 "LC_COLLATE",
129 "LC_MONETARY",
130 "LC_MESSAGES",
131 "LC_PAPER",
132 "LC_NAME",
133 "LC_ADDRESS",
134 "LC_TELEPHONE",
135 "LC_MEASUREMENT",
136 "LC_IDENTIFICATION",
137 "LC_ALL",
138 "LANGUAGE",
139 "RANDOM_DELAY",
140 NULL
141 };
142 const char **name;
143 char **procenv;
144
145 for (procenv = environ; *procenv != NULL; ++procenv) {
146 for (name = names; *name != NULL; ++name) {
147 size_t namelen;
148
149 namelen = strlen(*name);
150 if (strncmp(*name, *procenv, namelen) == 0
151 && (*procenv)[namelen] == '=') {
152 char **tmpenv;
153
154 tmpenv = env_set(*envpp, *procenv);
155 if (tmpenv == NULL)
156 return FALSE;
157 *envpp = tmpenv;
158 }
159 }
160 }
161 return TRUE;
162 }
163
164 /* The following states are used by load_env(), traversed in order: */
165 enum env_state {
166 NAMEI, /* First char of NAME, may be quote */
167 NAME, /* Subsequent chars of NAME */
168 EQ1, /* After end of name, looking for '=' sign */
169 EQ2, /* After '=', skipping whitespace */
170 VALUEI, /* First char of VALUE, may be quote */
171 VALUE, /* Subsequent chars of VALUE */
172 FINI, /* All done, skipping trailing whitespace */
173 ERROR, /* Error */
174 };
175
176 /* return ERR = end of file
177 * FALSE = not an env setting (file was repositioned)
178 * TRUE = was an env setting
179 */
180 int load_env(char *envstr, FILE * f) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
181 long filepos;
182 int fileline;
183 enum env_state state;
184 char name[MAX_ENVSTR], val[MAX_ENVSTR];
185 char quotechar, *c, *str;
186
187 filepos = ftell(f);
188 fileline = LineNumber;
189 skip_comments(f);
190 if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
191 return (ERR);
192
193 Debug(DPARS, ("load_env, read <%s>\n", envstr));
194
195 memset(name, 0, sizeof name);
196 memset(val, 0, sizeof val);
197
198 str = name;
199 state = NAMEI;
200 quotechar = '\0';
201 c = envstr;
202 while (state != ERROR && *c) {
203 switch (state) {
204 case NAMEI:
205 case VALUEI:
206 if (*c == '\'' || *c == '"')
207 quotechar = *c++;
208 state++;
209 /* FALLTHROUGH */
210 case NAME:
211 case VALUE:
212 if (quotechar) {
213 if (*c == quotechar) {
214 state++;
215 c++;
216 break;
217 }
218 if (state == NAME && *c == '=') {
219 state = ERROR;
220 break;
221 }
222 }
223 else {
224 if (state == NAME) {
225 if (isspace((unsigned char) *c)) {
226 c++;
227 state++;
228 break;
229 }
230 if (*c == '=') {
231 state++;
232 break;
233 }
234 }
235 }
236 *str++ = *c++;
237 break;
238
239 case EQ1:
240 if (*c == '=') {
241 state++;
242 str = val;
243 quotechar = '\0';
244 }
245 else {
246 if (!isspace((unsigned char) *c))
247 state = ERROR;
248 }
249 c++;
250 break;
251
252 case EQ2:
253 case FINI:
254 if (isspace((unsigned char) *c))
255 c++;
256 else
257 state++;
258 break;
259
260 default:
261 abort();
262 }
263 }
264 if (state != FINI && state != EQ2 && !(state == VALUE && !quotechar)) {
265 Debug(DPARS, ("load_env, not an env var, state = %d\n", state));
266 if (fseek(f, filepos, 0)) {
267 return ERR;
268 }
269 Set_LineNum(fileline);
270 return (FALSE);
271 }
272 if (state == VALUE) {
273 /* End of unquoted value: trim trailing whitespace */
274 c = val + strlen(val);
275 while (c > val && isspace((unsigned char) c[-1]))
276 *(--c) = '\0';
277 }
278
279 /* 2 fields from parser; looks like an env setting */
280
281 /*
282 * This can't overflow because get_string() limited the size of the
283 * name and val fields. Still, it doesn't hurt to be careful...
284 */
285 if (!glue_strings(envstr, MAX_ENVSTR, name, val, '='))
286 return (FALSE);
287 Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr));
288 return (TRUE);
289 }
290
291 char *env_get(const char *name, char **envp) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
292 size_t len = strlen(name);
293 char *p, *q;
294
295 while ((p = *envp++) != NULL) {
296 if (!(q = strchr(p, '=')))
297 continue;
298 if ((q - p) == len && !strncmp(p, name, len))
299 return (q + 1);
300 }
301 return (NULL);
302 }
303
304 char **env_update_home(char **envp, const char *dir) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
305 char envstr[MAX_ENVSTR];
306
307 if (dir == NULL || *dir == '\0' || env_get("HOME", envp)) {
308 return envp;
309 }
310
311 if (glue_strings(envstr, sizeof envstr, "HOME", dir, '=')) {
312 envp = env_set(envp, envstr);
313 }
314 else
315 log_it("CRON", getpid(), "ERROR", "can't set HOME", 0);
316
317 return envp;
318 }