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