GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/cron/env.c Lines: 0 95 0.0 %
Date: 2017-11-13 Branches: 0 82 0.0 %

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