GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/mtree/spec.c Lines: 77 152 50.7 %
Date: 2017-11-07 Branches: 58 133 43.6 %

Line Branch Exec Source
1
/*	$NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $	*/
2
/*	$OpenBSD: spec.c,v 1.28 2016/08/16 16:41:46 krw Exp $	*/
3
4
/*-
5
 * Copyright (c) 1989, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <sys/stat.h>
35
#include <pwd.h>
36
#include <grp.h>
37
#include <errno.h>
38
#include <unistd.h>
39
#include <stdio.h>
40
#include <ctype.h>
41
#include <vis.h>
42
#include "mtree.h"
43
#include "extern.h"
44
45
int lineno;				/* Current spec line number. */
46
47
static void	 set(char *, NODE *);
48
static void	 unset(char *, NODE *);
49
50
NODE *
51
spec(void)
52
{
53
	NODE *centry, *last;
54
	char *p;
55
20
	NODE ginfo, *root;
56
	int c_cur, c_next;
57
	char *buf, *tbuf = NULL;
58
10
	size_t len;
59
60
	last = root = NULL;
61
10
	bzero(&ginfo, sizeof(ginfo));
62
	centry = &ginfo;
63
	c_cur = c_next = 0;
64
3516
	for (lineno = 1; (buf = fgetln(stdin, &len));
65
1748
	    ++lineno, c_cur = c_next, c_next = 0) {
66
		/* Null-terminate the line. */
67
1748
		if (buf[len - 1] == '\n') {
68
1748
			buf[--len] = '\0';
69
1748
		} else {
70
			/* EOF with no newline. */
71
			tbuf = malloc(len + 1);
72
			memcpy(tbuf, buf, len);
73
			tbuf[len] = '\0';
74
			buf = tbuf;
75
		}
76
77
		/* Skip leading whitespace. */
78
31660
		for (p = buf; isspace((unsigned char)*p); p++)
79
			;
80
81
		/* If nothing but whitespace or comment char, continue. */
82

3377
		if (*p == '\0' || *p == '#')
83
			continue;
84
85
		/* See if next line is continuation line. */
86
1510
		if (buf[len - 1] == '\\') {
87
			c_next = 1;
88
7
			if (--len == 0)
89
				continue;
90
7
			buf[len] = '\0';
91
7
		}
92
93
#ifdef DEBUG
94
		(void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
95
#endif
96
1510
		if (c_cur) {
97
7
			set(p, centry);
98
7
			continue;
99
		}
100
101
		/* Grab file name, "$", "set", or "unset". */
102
1503
		if ((p = strtok(p, "\n\t ")) == NULL)
103
			error("missing field");
104
105
1503
		if (p[0] == '/')
106
1300
			switch(p[1]) {
107
			case 's':
108
16
				if (strcmp(p + 1, "set"))
109
					break;
110
16
				set(NULL, &ginfo);
111
16
				continue;
112
			case 'u':
113
				if (strcmp(p + 1, "unset"))
114
					break;
115
				unset(NULL, &ginfo);
116
				continue;
117
			}
118
119
1487
		if (strchr(p, '/'))
120
			error("slash character in file name");
121
122
1487
		if (!strcmp(p, "..")) {
123
			/* Don't go up, if haven't gone down. */
124
679
			if (!root)
125
				goto noparent;
126

1345
			if (last->type != F_DIR || last->flags & F_DONE) {
127
119
				if (last == root)
128
					goto noparent;
129
119
				last = last->parent;
130
119
			}
131
679
			last->flags |= F_DONE;
132
679
			continue;
133
134
noparent:		error("no parent node");
135
		}
136
137
808
		len = strlen(p) + 1;	/* NUL in struct _node */
138
808
		if ((centry = calloc(1, sizeof(NODE) + len - 1)) == NULL)
139
			error("%s", strerror(errno));
140
808
		*centry = ginfo;
141
#define	MAGIC	"?*["
142
808
		if (strpbrk(p, MAGIC))
143
			centry->flags |= F_MAGIC;
144
808
		if (strunvis(centry->name, p) == -1) {
145
			fprintf(stderr,
146
			    "mtree: filename (%s) encoded incorrectly\n", p);
147
			strlcpy(centry->name, p, len);
148
		}
149
808
		set(NULL, centry);
150
151
808
		if (!root) {
152
			last = root = centry;
153
10
			root->parent = root;
154

1508
		} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
155
130
			centry->parent = last;
156
130
			last = last->child = centry;
157
130
		} else {
158
668
			centry->parent = last->parent;
159
668
			centry->prev = last;
160
668
			last = last->next = centry;
161
		}
162
	}
163
10
	free(tbuf);
164
10
	return (root);
165
10
}
166
167
static void
168
set(char *t, NODE *ip)
169
{
170
	int type;
171
1662
	char *kw, *val = NULL;
172
	struct group *gr;
173
	struct passwd *pw;
174
	void *m;
175
831
	int value;
176
831
	u_int32_t fset, fclr;
177
831
	char *ep;
178
	size_t len;
179
180
4122
	for (; (kw = strtok(t, "= \t\n")); t = NULL) {
181
1230
		ip->flags |= type = parsekey(kw, &value);
182

2359
		if (value && (val = strtok(NULL, " \t\n")) == NULL)
183
			error("missing value");
184




2148
		switch(type) {
185
		case F_CKSUM:
186
			ip->cksum = strtoul(val, &ep, 10);
187
			if (*ep)
188
				error("invalid checksum %s", val);
189
			break;
190
		case F_MD5:
191
			ip->md5digest = strdup(val);
192
			if (!ip->md5digest)
193
				error("%s", strerror(errno));
194
			break;
195
		case F_FLAGS:
196
			if (!strcmp(val, "none")) {
197
				ip->file_flags = 0;
198
				break;
199
			}
200
			if (strtofflags(&val, &fset, &fclr))
201
				error("%s", strerror(errno));
202
			ip->file_flags = fset;
203
			break;
204
		case F_GID:
205
			ip->st_gid = strtoul(val, &ep, 10);
206
			if (*ep)
207
				error("invalid gid %s", val);
208
			break;
209
		case F_GNAME:
210
278
			if ((gr = getgrnam(val)) == NULL)
211
			    error("unknown group %s", val);
212
278
			ip->st_gid = gr->gr_gid;
213
278
			break;
214
		case F_IGN:
215
			/* just set flag bit */
216
			break;
217
		case F_MODE:
218
338
			if ((m = setmode(val)) == NULL)
219
				error("invalid file mode %s", val);
220
338
			ip->st_mode = getmode(m, 0);
221
338
			free(m);
222
338
			break;
223
		case F_NLINK:
224
			ip->st_nlink = strtoul(val, &ep, 10);
225
			if (*ep)
226
				error("invalid link count %s", val);
227
			break;
228
		case F_RMD160:
229
			ip->rmd160digest = strdup(val);
230
			if (!ip->rmd160digest)
231
				error("%s", strerror(errno));
232
			break;
233
		case F_SHA1:
234
			ip->sha1digest = strdup(val);
235
			if (!ip->sha1digest)
236
				error("%s", strerror(errno));
237
			break;
238
		case F_SHA256:
239
			ip->sha256digest = strdup(val);
240
			if (!ip->sha256digest)
241
				error("%s", strerror(errno));
242
			break;
243
		case F_SIZE:
244
			ip->st_size = strtoll(val, &ep, 10);
245
			if (*ep)
246
				error("invalid size %s", val);
247
			break;
248
		case F_SLINK:
249
			len = strlen(val) + 1;
250
			if ((ip->slink = malloc(len)) == NULL)
251
				error("%s", strerror(errno));
252
			if (strunvis(ip->slink, val) == -1) {
253
				fprintf(stderr,
254
				    "mtree: filename (%s) encoded incorrectly\n", val);
255
				strlcpy(ip->slink, val, len);
256
			}
257
			break;
258
		case F_TIME:
259
			ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
260
			if (*ep != '.')
261
				error("invalid time %s", val);
262
			val = ep + 1;
263
			ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
264
			if (*ep)
265
				error("invalid time %s", val);
266
			break;
267
		case F_TYPE:
268

211
			switch(*val) {
269
			case 'b':
270
				if (!strcmp(val, "block"))
271
					ip->type = F_BLOCK;
272
				break;
273
			case 'c':
274
2
				if (!strcmp(val, "char"))
275
2
					ip->type = F_CHAR;
276
				break;
277
			case 'd':
278
94
				if (!strcmp(val, "dir"))
279
94
					ip->type = F_DIR;
280
				break;
281
			case 'f':
282
115
				if (!strcmp(val, "file"))
283
115
					ip->type = F_FILE;
284
115
				if (!strcmp(val, "fifo"))
285
					ip->type = F_FIFO;
286
				break;
287
			case 'l':
288
				if (!strcmp(val, "link"))
289
					ip->type = F_LINK;
290
				break;
291
			case 's':
292
				if (!strcmp(val, "socket"))
293
					ip->type = F_SOCK;
294
				break;
295
			default:
296
				error("unknown file type %s", val);
297
			}
298
			break;
299
		case F_UID:
300
			ip->st_uid = strtoul(val, &ep, 10);
301
			if (*ep)
302
				error("invalid uid %s", val);
303
			break;
304
		case F_UNAME:
305
302
			if ((pw = getpwnam(val)) == NULL)
306
			    error("unknown user %s", val);
307
302
			ip->st_uid = pw->pw_uid;
308
302
			break;
309
		}
310
	}
311
831
}
312
313
static void
314
unset(char *t, NODE *ip)
315
{
316
	char *p;
317
318
	while ((p = strtok(t, "\n\t ")))
319
		ip->flags &= ~parsekey(p, NULL);
320
}