spec.c revision 18404
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1989, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 351553Srgrimesstatic char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; 361553Srgrimes#endif /* not lint */ 371553Srgrimes 381553Srgrimes#include <sys/types.h> 391553Srgrimes#include <sys/stat.h> 401553Srgrimes#include <fts.h> 411553Srgrimes#include <pwd.h> 421553Srgrimes#include <grp.h> 431553Srgrimes#include <errno.h> 441553Srgrimes#include <unistd.h> 451553Srgrimes#include <stdio.h> 461553Srgrimes#include <ctype.h> 471553Srgrimes#include "mtree.h" 481553Srgrimes#include "extern.h" 491553Srgrimes 501553Srgrimesint lineno; /* Current spec line number. */ 511553Srgrimes 521553Srgrimesstatic void set __P((char *, NODE *)); 531553Srgrimesstatic void unset __P((char *, NODE *)); 541553Srgrimes 551553SrgrimesNODE * 561553Srgrimesspec() 571553Srgrimes{ 581553Srgrimes register NODE *centry, *last; 591553Srgrimes register char *p; 601553Srgrimes NODE ginfo, *root; 611553Srgrimes int c_cur, c_next; 621553Srgrimes char buf[2048]; 631553Srgrimes 642860Srgrimes centry = last = root = NULL; 651553Srgrimes bzero(&ginfo, sizeof(ginfo)); 661553Srgrimes c_cur = c_next = 0; 671553Srgrimes for (lineno = 1; fgets(buf, sizeof(buf), stdin); 681553Srgrimes ++lineno, c_cur = c_next, c_next = 0) { 691553Srgrimes /* Skip empty lines. */ 701553Srgrimes if (buf[0] == '\n') 711553Srgrimes continue; 721553Srgrimes 731553Srgrimes /* Find end of line. */ 741553Srgrimes if ((p = index(buf, '\n')) == NULL) 751553Srgrimes err("line %d too long", lineno); 761553Srgrimes 771553Srgrimes /* See if next line is continuation line. */ 781553Srgrimes if (p[-1] == '\\') { 791553Srgrimes --p; 801553Srgrimes c_next = 1; 811553Srgrimes } 821553Srgrimes 831553Srgrimes /* Null-terminate the line. */ 841553Srgrimes *p = '\0'; 851553Srgrimes 861553Srgrimes /* Skip leading whitespace. */ 871553Srgrimes for (p = buf; *p && isspace(*p); ++p); 881553Srgrimes 891553Srgrimes /* If nothing but whitespace or comment char, continue. */ 901553Srgrimes if (!*p || *p == '#') 911553Srgrimes continue; 921553Srgrimes 931553Srgrimes#ifdef DEBUG 941553Srgrimes (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 951553Srgrimes#endif 961553Srgrimes if (c_cur) { 971553Srgrimes set(p, centry); 981553Srgrimes continue; 991553Srgrimes } 1008857Srgrimes 1011553Srgrimes /* Grab file name, "$", "set", or "unset". */ 1021553Srgrimes if ((p = strtok(p, "\n\t ")) == NULL) 1031553Srgrimes err("missing field"); 1041553Srgrimes 1051553Srgrimes if (p[0] == '/') 1061553Srgrimes switch(p[1]) { 1071553Srgrimes case 's': 1081553Srgrimes if (strcmp(p + 1, "set")) 1091553Srgrimes break; 1101553Srgrimes set(NULL, &ginfo); 1111553Srgrimes continue; 1121553Srgrimes case 'u': 1131553Srgrimes if (strcmp(p + 1, "unset")) 1141553Srgrimes break; 1151553Srgrimes unset(NULL, &ginfo); 1161553Srgrimes continue; 1171553Srgrimes } 1181553Srgrimes 1191553Srgrimes if (index(p, '/')) 1201553Srgrimes err("slash character in file name"); 1211553Srgrimes 1221553Srgrimes if (!strcmp(p, "..")) { 1231553Srgrimes /* Don't go up, if haven't gone down. */ 1241553Srgrimes if (!root) 1251553Srgrimes goto noparent; 1261553Srgrimes if (last->type != F_DIR || last->flags & F_DONE) { 1271553Srgrimes if (last == root) 1281553Srgrimes goto noparent; 1291553Srgrimes last = last->parent; 1301553Srgrimes } 1311553Srgrimes last->flags |= F_DONE; 1321553Srgrimes continue; 1331553Srgrimes 1341553Srgrimesnoparent: err("no parent node"); 1351553Srgrimes } 1361553Srgrimes 1371553Srgrimes if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 1381553Srgrimes err("%s", strerror(errno)); 1391553Srgrimes *centry = ginfo; 1401553Srgrimes (void)strcpy(centry->name, p); 1411553Srgrimes#define MAGIC "?*[" 1421553Srgrimes if (strpbrk(p, MAGIC)) 1431553Srgrimes centry->flags |= F_MAGIC; 1441553Srgrimes set(NULL, centry); 1451553Srgrimes 1461553Srgrimes if (!root) { 1471553Srgrimes last = root = centry; 1481553Srgrimes root->parent = root; 1491553Srgrimes } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 1501553Srgrimes centry->parent = last; 1511553Srgrimes last = last->child = centry; 1521553Srgrimes } else { 1531553Srgrimes centry->parent = last->parent; 1541553Srgrimes centry->prev = last; 1551553Srgrimes last = last->next = centry; 1561553Srgrimes } 1571553Srgrimes } 1581553Srgrimes return (root); 1591553Srgrimes} 1601553Srgrimes 1611553Srgrimesstatic void 1621553Srgrimesset(t, ip) 1631553Srgrimes char *t; 1641553Srgrimes register NODE *ip; 1651553Srgrimes{ 1661553Srgrimes register int type; 1672860Srgrimes register char *kw, *val = NULL; 1681553Srgrimes struct group *gr; 1691553Srgrimes struct passwd *pw; 1701553Srgrimes mode_t *m; 1711553Srgrimes int value; 1721553Srgrimes char *ep; 1731553Srgrimes 1742860Srgrimes for (; (kw = strtok(t, "= \t\n")); t = NULL) { 1751553Srgrimes ip->flags |= type = parsekey(kw, &value); 1761553Srgrimes if (value && (val = strtok(NULL, " \t\n")) == NULL) 1771553Srgrimes err("missing value"); 1781553Srgrimes switch(type) { 1791553Srgrimes case F_CKSUM: 1801553Srgrimes ip->cksum = strtoul(val, &ep, 10); 1811553Srgrimes if (*ep) 1821553Srgrimes err("invalid checksum %s", val); 1831553Srgrimes break; 1846286Swollman case F_MD5: 1856286Swollman ip->md5digest = strdup(val); 1866286Swollman if(!ip->md5digest) { 1876286Swollman err("%s", strerror(errno)); 1886286Swollman } 1896286Swollman break; 1901553Srgrimes case F_GID: 1911553Srgrimes ip->st_gid = strtoul(val, &ep, 10); 1921553Srgrimes if (*ep) 1931553Srgrimes err("invalid gid %s", val); 1941553Srgrimes break; 1951553Srgrimes case F_GNAME: 1961553Srgrimes if ((gr = getgrnam(val)) == NULL) 1971553Srgrimes err("unknown group %s", val); 1981553Srgrimes ip->st_gid = gr->gr_gid; 1991553Srgrimes break; 2001553Srgrimes case F_IGN: 2011553Srgrimes /* just set flag bit */ 2021553Srgrimes break; 2031553Srgrimes case F_MODE: 2041553Srgrimes if ((m = setmode(val)) == NULL) 2051553Srgrimes err("invalid file mode %s", val); 2061553Srgrimes ip->st_mode = getmode(m, 0); 2071553Srgrimes break; 2081553Srgrimes case F_NLINK: 2091553Srgrimes ip->st_nlink = strtoul(val, &ep, 10); 2101553Srgrimes if (*ep) 2111553Srgrimes err("invalid link count %s", val); 2121553Srgrimes break; 2131553Srgrimes case F_SIZE: 21411282Storstenb ip->st_size = strtoq(val, &ep, 10); 2151553Srgrimes if (*ep) 2161553Srgrimes err("invalid size %s", val); 2171553Srgrimes break; 2181553Srgrimes case F_SLINK: 2191553Srgrimes if ((ip->slink = strdup(val)) == NULL) 2201553Srgrimes err("%s", strerror(errno)); 2211553Srgrimes break; 2221553Srgrimes case F_TIME: 22318404Snate ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 2241553Srgrimes if (*ep != '.') 2251553Srgrimes err("invalid time %s", val); 2261553Srgrimes val = ep + 1; 22718404Snate ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); 2281553Srgrimes if (*ep) 2291553Srgrimes err("invalid time %s", val); 2301553Srgrimes break; 2311553Srgrimes case F_TYPE: 2321553Srgrimes switch(*val) { 2331553Srgrimes case 'b': 2341553Srgrimes if (!strcmp(val, "block")) 2351553Srgrimes ip->type = F_BLOCK; 2361553Srgrimes break; 2371553Srgrimes case 'c': 2381553Srgrimes if (!strcmp(val, "char")) 2391553Srgrimes ip->type = F_CHAR; 2401553Srgrimes break; 2411553Srgrimes case 'd': 2421553Srgrimes if (!strcmp(val, "dir")) 2431553Srgrimes ip->type = F_DIR; 2441553Srgrimes break; 2451553Srgrimes case 'f': 2461553Srgrimes if (!strcmp(val, "file")) 2471553Srgrimes ip->type = F_FILE; 2481553Srgrimes if (!strcmp(val, "fifo")) 2491553Srgrimes ip->type = F_FIFO; 2501553Srgrimes break; 2511553Srgrimes case 'l': 2521553Srgrimes if (!strcmp(val, "link")) 2531553Srgrimes ip->type = F_LINK; 2541553Srgrimes break; 2551553Srgrimes case 's': 2561553Srgrimes if (!strcmp(val, "socket")) 2571553Srgrimes ip->type = F_SOCK; 2581553Srgrimes break; 2591553Srgrimes default: 2601553Srgrimes err("unknown file type %s", val); 2611553Srgrimes } 2621553Srgrimes break; 2631553Srgrimes case F_UID: 2641553Srgrimes ip->st_uid = strtoul(val, &ep, 10); 2651553Srgrimes if (*ep) 2661553Srgrimes err("invalid uid %s", val); 2671553Srgrimes break; 2681553Srgrimes case F_UNAME: 2691553Srgrimes if ((pw = getpwnam(val)) == NULL) 2701553Srgrimes err("unknown user %s", val); 2711553Srgrimes ip->st_uid = pw->pw_uid; 2721553Srgrimes break; 2731553Srgrimes } 2741553Srgrimes } 2751553Srgrimes} 2761553Srgrimes 2771553Srgrimesstatic void 2781553Srgrimesunset(t, ip) 2791553Srgrimes char *t; 2801553Srgrimes register NODE *ip; 2811553Srgrimes{ 2821553Srgrimes register char *p; 2831553Srgrimes 2842860Srgrimes while ((p = strtok(t, "\n\t "))) 2851553Srgrimes ip->flags &= ~parsekey(p, NULL); 2861553Srgrimes} 287