spec.c revision 8857
146283Sdfr/*-
246283Sdfr * Copyright (c) 1989, 1993
398944Sobrien *	The Regents of the University of California.  All rights reserved.
498944Sobrien *
546283Sdfr * Redistribution and use in source and binary forms, with or without
698944Sobrien * modification, are permitted provided that the following conditions
746283Sdfr * are met:
898944Sobrien * 1. Redistributions of source code must retain the above copyright
998944Sobrien *    notice, this list of conditions and the following disclaimer.
1098944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer in the
1246283Sdfr *    documentation and/or other materials provided with the distribution.
1398944Sobrien * 3. All advertising materials mentioning features or use of this software
1498944Sobrien *    must display the following acknowledgement:
1598944Sobrien *	This product includes software developed by the University of
1698944Sobrien *	California, Berkeley and its contributors.
1746283Sdfr * 4. Neither the name of the University nor the names of its contributors
1898944Sobrien *    may be used to endorse or promote products derived from this software
1998944Sobrien *    without specific prior written permission.
2098944Sobrien *
2198944Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2298944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2346283Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2446283Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2546283Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2646283Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2746283Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2846283Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2946283Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3046283Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3146283Sdfr * SUCH DAMAGE.
3246283Sdfr */
3346283Sdfr
3446283Sdfr#ifndef lint
3546283Sdfrstatic char sccsid[] = "@(#)spec.c	8.1 (Berkeley) 6/6/93";
3698944Sobrien#endif /* not lint */
3798944Sobrien
3898944Sobrien#include <sys/types.h>
3998944Sobrien#include <sys/stat.h>
4046283Sdfr#include <fts.h>
4146283Sdfr#include <pwd.h>
4246283Sdfr#include <grp.h>
4346283Sdfr#include <errno.h>
4446283Sdfr#include <unistd.h>
4546283Sdfr#include <stdio.h>
4646283Sdfr#include <ctype.h>
4746283Sdfr#include "mtree.h"
4846283Sdfr#include "extern.h"
4946283Sdfr
5046283Sdfrint lineno;				/* Current spec line number. */
5198944Sobrien
5246283Sdfrstatic void	 set __P((char *, NODE *));
5346283Sdfrstatic void	 unset __P((char *, NODE *));
5446283Sdfr
5598944SobrienNODE *
5646283Sdfrspec()
5798944Sobrien{
5898944Sobrien	register NODE *centry, *last;
5998944Sobrien	register char *p;
6098944Sobrien	NODE ginfo, *root;
6146283Sdfr	int c_cur, c_next;
6298944Sobrien	char buf[2048];
6346283Sdfr
6498944Sobrien	centry = last = root = NULL;
6546283Sdfr	bzero(&ginfo, sizeof(ginfo));
6698944Sobrien	c_cur = c_next = 0;
6798944Sobrien	for (lineno = 1; fgets(buf, sizeof(buf), stdin);
6846283Sdfr	    ++lineno, c_cur = c_next, c_next = 0) {
6998944Sobrien		/* Skip empty lines. */
7046283Sdfr		if (buf[0] == '\n')
7198944Sobrien			continue;
7246283Sdfr
7398944Sobrien		/* Find end of line. */
7446283Sdfr		if ((p = index(buf, '\n')) == NULL)
7598944Sobrien			err("line %d too long", lineno);
7646283Sdfr
7798944Sobrien		/* See if next line is continuation line. */
7846283Sdfr		if (p[-1] == '\\') {
7998944Sobrien			--p;
8046283Sdfr			c_next = 1;
8198944Sobrien		}
8246283Sdfr
8398944Sobrien		/* Null-terminate the line. */
8446283Sdfr		*p = '\0';
8598944Sobrien
8646283Sdfr		/* Skip leading whitespace. */
8798944Sobrien		for (p = buf; *p && isspace(*p); ++p);
8846283Sdfr
8998944Sobrien		/* If nothing but whitespace or comment char, continue. */
9046283Sdfr		if (!*p || *p == '#')
9146283Sdfr			continue;
9246283Sdfr
9346283Sdfr#ifdef DEBUG
9446283Sdfr		(void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
9546283Sdfr#endif
9646283Sdfr		if (c_cur) {
9746283Sdfr			set(p, centry);
9846283Sdfr			continue;
9946283Sdfr		}
10046283Sdfr
10146283Sdfr		/* Grab file name, "$", "set", or "unset". */
10246283Sdfr		if ((p = strtok(p, "\n\t ")) == NULL)
10398944Sobrien			err("missing field");
10498944Sobrien
10598944Sobrien		if (p[0] == '/')
10698944Sobrien			switch(p[1]) {
10798944Sobrien			case 's':
10898944Sobrien				if (strcmp(p + 1, "set"))
10998944Sobrien					break;
11098944Sobrien				set(NULL, &ginfo);
11198944Sobrien				continue;
11298944Sobrien			case 'u':
11398944Sobrien				if (strcmp(p + 1, "unset"))
11498944Sobrien					break;
11546283Sdfr				unset(NULL, &ginfo);
11646283Sdfr				continue;
11798944Sobrien			}
11898944Sobrien
11998944Sobrien		if (index(p, '/'))
12098944Sobrien			err("slash character in file name");
12198944Sobrien
12298944Sobrien		if (!strcmp(p, "..")) {
12398944Sobrien			/* Don't go up, if haven't gone down. */
12498944Sobrien			if (!root)
12546283Sdfr				goto noparent;
12646283Sdfr			if (last->type != F_DIR || last->flags & F_DONE) {
12746283Sdfr				if (last == root)
128130803Smarcel					goto noparent;
12998944Sobrien				last = last->parent;
13046283Sdfr			}
13146283Sdfr			last->flags |= F_DONE;
13246283Sdfr			continue;
13346283Sdfr
13446283Sdfrnoparent:		err("no parent node");
135130803Smarcel		}
13646283Sdfr
13746283Sdfr		if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
13846283Sdfr			err("%s", strerror(errno));
13946283Sdfr		*centry = ginfo;
14046283Sdfr		(void)strcpy(centry->name, p);
141130803Smarcel#define	MAGIC	"?*["
14246283Sdfr		if (strpbrk(p, MAGIC))
14346283Sdfr			centry->flags |= F_MAGIC;
14446283Sdfr		set(NULL, centry);
14546283Sdfr
14646283Sdfr		if (!root) {
14746283Sdfr			last = root = centry;
148130803Smarcel			root->parent = root;
14946283Sdfr		} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
15046283Sdfr			centry->parent = last;
15146283Sdfr			last = last->child = centry;
15246283Sdfr		} else {
15346283Sdfr			centry->parent = last->parent;
15446283Sdfr			centry->prev = last;
15598944Sobrien			last = last->next = centry;
15646283Sdfr		}
15798944Sobrien	}
15898944Sobrien	return (root);
15998944Sobrien}
16098944Sobrien
16198944Sobrienstatic void
16246283Sdfrset(t, ip)
16346283Sdfr	char *t;
16446283Sdfr	register NODE *ip;
16546283Sdfr{
16646283Sdfr	register int type;
167130803Smarcel	register char *kw, *val = NULL;
16846283Sdfr	struct group *gr;
16946283Sdfr	struct passwd *pw;
17046283Sdfr	mode_t *m;
17146283Sdfr	int value;
17246283Sdfr	char *ep;
17346283Sdfr
17446283Sdfr	for (; (kw = strtok(t, "= \t\n")); t = NULL) {
175130803Smarcel		ip->flags |= type = parsekey(kw, &value);
17698944Sobrien		if (value && (val = strtok(NULL, " \t\n")) == NULL)
17746283Sdfr			err("missing value");
17846283Sdfr		switch(type) {
17946283Sdfr		case F_CKSUM:
18046283Sdfr			ip->cksum = strtoul(val, &ep, 10);
181130803Smarcel			if (*ep)
18246283Sdfr				err("invalid checksum %s", val);
18398944Sobrien			break;
18446283Sdfr		case F_MD5:
18546283Sdfr			ip->md5digest = strdup(val);
18646283Sdfr			if(!ip->md5digest) {
18746283Sdfr				err("%s", strerror(errno));
18846283Sdfr			}
18946283Sdfr			break;
19046283Sdfr		case F_GID:
19146283Sdfr			ip->st_gid = strtoul(val, &ep, 10);
19246283Sdfr			if (*ep)
19398944Sobrien				err("invalid gid %s", val);
19446283Sdfr			break;
19546283Sdfr		case F_GNAME:
19646283Sdfr			if ((gr = getgrnam(val)) == NULL)
19798944Sobrien			    err("unknown group %s", val);
19898944Sobrien			ip->st_gid = gr->gr_gid;
19998944Sobrien			break;
20046283Sdfr		case F_IGN:
20146283Sdfr			/* just set flag bit */
20246283Sdfr			break;
20346283Sdfr		case F_MODE:
20446283Sdfr			if ((m = setmode(val)) == NULL)
20598944Sobrien				err("invalid file mode %s", val);
20698944Sobrien			ip->st_mode = getmode(m, 0);
20798944Sobrien			break;
20898944Sobrien		case F_NLINK:
20998944Sobrien			ip->st_nlink = strtoul(val, &ep, 10);
21098944Sobrien			if (*ep)
21198944Sobrien				err("invalid link count %s", val);
21298944Sobrien			break;
21398944Sobrien		case F_SIZE:
21498944Sobrien			ip->st_size = strtoul(val, &ep, 10);
21598944Sobrien			if (*ep)
21698944Sobrien				err("invalid size %s", val);
21798944Sobrien			break;
21898944Sobrien		case F_SLINK:
21998944Sobrien			if ((ip->slink = strdup(val)) == NULL)
22046283Sdfr				err("%s", strerror(errno));
22146283Sdfr			break;
22298944Sobrien		case F_TIME:
22398944Sobrien			ip->st_mtimespec.ts_sec = strtoul(val, &ep, 10);
22446283Sdfr			if (*ep != '.')
22546283Sdfr				err("invalid time %s", val);
22646283Sdfr			val = ep + 1;
22746283Sdfr			ip->st_mtimespec.ts_nsec = strtoul(val, &ep, 10);
22898944Sobrien			if (*ep)
22946283Sdfr				err("invalid time %s", val);
23046283Sdfr			break;
23146283Sdfr		case F_TYPE:
23246283Sdfr			switch(*val) {
23346283Sdfr			case 'b':
23446283Sdfr				if (!strcmp(val, "block"))
23546283Sdfr					ip->type = F_BLOCK;
23646283Sdfr				break;
23746283Sdfr			case 'c':
23846283Sdfr				if (!strcmp(val, "char"))
23946283Sdfr					ip->type = F_CHAR;
24046283Sdfr				break;
24146283Sdfr			case 'd':
24246283Sdfr				if (!strcmp(val, "dir"))
24346283Sdfr					ip->type = F_DIR;
24446283Sdfr				break;
24546283Sdfr			case 'f':
24698944Sobrien				if (!strcmp(val, "file"))
247130803Smarcel					ip->type = F_FILE;
24846283Sdfr				if (!strcmp(val, "fifo"))
24946283Sdfr					ip->type = F_FIFO;
25098944Sobrien				break;
25198944Sobrien			case 'l':
25246283Sdfr				if (!strcmp(val, "link"))
25346283Sdfr					ip->type = F_LINK;
25446283Sdfr				break;
255130803Smarcel			case 's':
25646283Sdfr				if (!strcmp(val, "socket"))
25746283Sdfr					ip->type = F_SOCK;
25846283Sdfr				break;
25946283Sdfr			default:
260130803Smarcel				err("unknown file type %s", val);
26146283Sdfr			}
26246283Sdfr			break;
26346283Sdfr		case F_UID:
26446283Sdfr			ip->st_uid = strtoul(val, &ep, 10);
265130803Smarcel			if (*ep)
26646283Sdfr				err("invalid uid %s", val);
26746283Sdfr			break;
26846283Sdfr		case F_UNAME:
26946283Sdfr			if ((pw = getpwnam(val)) == NULL)
270130803Smarcel			    err("unknown user %s", val);
27146283Sdfr			ip->st_uid = pw->pw_uid;
27246283Sdfr			break;
27346283Sdfr		}
27446283Sdfr	}
275130803Smarcel}
27646283Sdfr
27746283Sdfrstatic void
27846283Sdfrunset(t, ip)
27946283Sdfr	char *t;
28046283Sdfr	register NODE *ip;
281130803Smarcel{
28246283Sdfr	register char *p;
28346283Sdfr
28446283Sdfr	while ((p = strtok(t, "\n\t ")))
28546283Sdfr		ip->flags &= ~parsekey(p, NULL);
28646283Sdfr}
28746283Sdfr