xref: /netbsd-src/usr.sbin/mtree/spec.c (revision ce63d6c20fc4ec8ddc95c84bb229e3c4ecf82b69)
1 /*-
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char sccsid[] = "@(#)spec.c	5.14 (Berkeley) 3/2/91";
36 #endif /* not lint */
37 
38 #include <sys/types.h>
39 #include <pwd.h>
40 #include <grp.h>
41 #include <stdio.h>
42 #include <errno.h>
43 #include <ctype.h>
44 #include "mtree.h"
45 
46 extern NODE *root;			/* root of the tree */
47 
48 static int lineno;			/* current spec line number */
49 
50 spec()
51 {
52 	register NODE *centry, *last;
53 	register char *p;
54 	NODE ginfo, *emalloc();
55 	char buf[2048];
56 
57 	bzero((void *)&ginfo, sizeof(ginfo));
58 	for (lineno = 1; fgets(buf, sizeof(buf), stdin); ++lineno) {
59 		if (!(p = index(buf, '\n'))) {
60 			(void)fprintf(stderr,
61 			    "mtree: line %d too long.\n", lineno);
62 			exit(1);
63 		}
64 		*p = '\0';
65 		for (p = buf; *p && isspace(*p); ++p);
66 		if (!*p || *p == '#')
67 			continue;
68 
69 		/* grab file name, "$", "set", or "unset" */
70 		if (!(p = strtok(p, "\n\t ")))
71 			specerr();
72 
73 		if (p[0] == '/')
74 			switch(p[1]) {
75 			case 's':
76 				if (strcmp(p + 1, "set"))
77 					break;
78 				set(&ginfo);
79 				continue;
80 			case 'u':
81 				if (strcmp(p + 1, "unset"))
82 					break;
83 				unset(&ginfo);
84 				continue;
85 			}
86 
87 		if (index(p, '/')) {
88 			(void)fprintf(stderr,
89 			    "mtree: file names may not contain slashes.\n");
90 			specerr();
91 		}
92 
93 		if (!strcmp(p, "..")) {
94 			/* don't go up, if haven't gone down */
95 			if (!root)
96 				noparent();
97 			if (last->type != F_DIR || last->flags & F_DONE) {
98 				if (last == root)
99 					noparent();
100 				last = last->parent;
101 			}
102 			last->flags |= F_DONE;
103 			continue;
104 		}
105 
106 		centry = emalloc(sizeof(NODE) + strlen(p));
107 		*centry = ginfo;
108 		(void)strcpy(centry->name, p);
109 #define	MAGIC	"?*["
110 		if (strpbrk(p, MAGIC))
111 			centry->flags |= F_MAGIC;
112 		set(centry);
113 
114 		if (!root) {
115 			last = root = centry;
116 			root->parent = root;
117 		} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
118 			centry->parent = last;
119 			last = last->child = centry;
120 		} else {
121 			centry->parent = last->parent;
122 			centry->prev = last;
123 			last = last->next = centry;
124 		}
125 	}
126 }
127 
128 set(ip)
129 	register NODE *ip;
130 {
131 	register int type;
132 	register char *kw, *val;
133 	gid_t getgroup();
134 	uid_t getowner();
135 	long atol(), strtol();
136 
137 	while (kw = strtok((char *)NULL, "= \t\n")) {
138 		ip->flags |= type = key(kw);
139 		val = strtok((char *)NULL, " \t\n");
140 		if (!val)
141 			specerr();
142 		switch(type) {
143 		case F_CKSUM:
144 			ip->cksum = atol(val);
145 			break;
146 		case F_GROUP:
147 			ip->st_gid = getgroup(val);
148 			break;
149 		case F_IGN:
150 			/* just set flag bit */
151 			break;
152 		case F_MODE: {
153 			mode_t *m, *setmode();
154 
155 			if (!(m = setmode(val))) {
156 				(void)fprintf(stderr,
157 				    "mtree: invalid file mode %s.\n", val);
158 				specerr();
159 			}
160 			ip->st_mode = getmode(m, 0);
161 			break;
162 		}
163 		case F_NLINK:
164 			ip->st_nlink = atoi(val);
165 			break;
166 		case F_OWNER:
167 			ip->st_uid = getowner(val);
168 			break;
169 		case F_SIZE:
170 			ip->st_size = atol(val);
171 			break;
172 		case F_SLINK:
173 			if (!(ip->slink = strdup(val)))
174 				nomem();
175 			break;
176 		case F_TIME:
177 			ip->st_mtime = atol(val);
178 			break;
179 		case F_TYPE:
180 			switch(*val) {
181 			case 'b':
182 				if (!strcmp(val, "block"))
183 					ip->type = F_BLOCK;
184 				break;
185 			case 'c':
186 				if (!strcmp(val, "char"))
187 					ip->type = F_CHAR;
188 				break;
189 			case 'd':
190 				if (!strcmp(val, "dir"))
191 					ip->type = F_DIR;
192 				break;
193 			case 'f':
194 				if (!strcmp(val, "file"))
195 					ip->type = F_FILE;
196 				if (!strcmp(val, "fifo"))
197 					ip->type = F_FIFO;
198 				break;
199 			case 'l':
200 				if (!strcmp(val, "link"))
201 					ip->type = F_LINK;
202 				break;
203 			case 's':
204 				if (!strcmp(val, "socket"))
205 					ip->type = F_SOCK;
206 				break;
207 			default:
208 				(void)fprintf(stderr,
209 				    "mtree: unknown file type %s.\n", val);
210 				specerr();
211 			}
212 			break;
213 		}
214 	}
215 }
216 
217 unset(ip)
218 	register NODE *ip;
219 {
220 	register char *p;
221 
222 	while (p = strtok((char *)NULL, "\n\t "))
223 		ip->flags &= ~key(p);
224 }
225 
226 key(p)
227 	char *p;
228 {
229 	switch(*p) {
230 	case 'c':
231 		if (!strcmp(p, "cksum"))
232 			return(F_CKSUM);
233 		break;
234 	case 'g':
235 		if (!strcmp(p, "group"))
236 			return(F_GROUP);
237 		break;
238 	case 'i':
239 		if (!strcmp(p, "ignore"))
240 			return(F_IGN);
241 		break;
242 	case 'l':
243 		if (!strcmp(p, "link"))
244 			return(F_SLINK);
245 		break;
246 	case 'm':
247 		if (!strcmp(p, "mode"))
248 			return(F_MODE);
249 		break;
250 	case 'n':
251 		if (!strcmp(p, "nlink"))
252 			return(F_NLINK);
253 		break;
254 	case 'o':
255 		if (!strcmp(p, "owner"))
256 			return(F_OWNER);
257 		break;
258 	case 's':
259 		if (!strcmp(p, "size"))
260 			return(F_SIZE);
261 		break;
262 	case 't':
263 		if (!strcmp(p, "type"))
264 			return(F_TYPE);
265 		if (!strcmp(p, "time"))
266 			return(F_TIME);
267 		break;
268 	}
269 	(void)fprintf(stderr, "mtree: unknown keyword %s.\n", p);
270 	specerr();
271 	/* NOTREACHED */
272 }
273 
274 
275 uid_t
276 getowner(p)
277 	register char *p;
278 {
279 	struct passwd *pw;
280 	int val;
281 
282 	if (isdigit(*p)) {
283 		if ((val = atoi(p)) >= 0)
284 			return((uid_t)val);
285 		(void)fprintf(stderr, "mtree: illegal uid value %s.\n", p);
286 	} else if (pw = getpwnam(p))
287 		return(pw->pw_uid);
288 	else
289 		(void)fprintf(stderr, "mtree: unknown user %s.\n", p);
290 	specerr();
291 	/* NOTREACHED */
292 }
293 
294 gid_t
295 getgroup(p)
296 	register char *p;
297 {
298 	struct group *gr;
299 	int val;
300 
301 	if (isdigit(*p)) {
302 		if ((val = atoi(p)) >= 0)
303 			return((gid_t)val);
304 		(void)fprintf(stderr, "mtree: illegal gid value %s.\n", p);
305 	} else if (gr = getgrnam(p))
306 		return(gr->gr_gid);
307 	else
308 		(void)fprintf(stderr, "mtree: unknown group %s.\n", p);
309 	specerr();
310 	/* NOTREACHED */
311 }
312 
313 noparent()
314 {
315 	(void)fprintf(stderr, "mtree: no parent node.\n");
316 	specerr();
317 }
318 
319 specerr()
320 {
321 	(void)fprintf(stderr,
322 	    "mtree: line %d of the specification is incorrect.\n", lineno);
323 	exit(1);
324 }
325 
326 NODE *
327 emalloc(size)
328 	int size;
329 {
330 	void *p;
331 
332 	/* NOSTRICT */
333 	if (!(p = malloc((u_int)size)))
334 		nomem();
335 	bzero(p, size);
336 	return((NODE *)p);
337 }
338 
339 nomem()
340 {
341 	(void)fprintf(stderr, "mtree: %s.\n", strerror(ENOMEM));
342 	exit(1);
343 }
344