spec.c revision 54375
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 3530027Scharnier#if 0 361553Srgrimesstatic char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; 3730027Scharnier#endif 3830027Scharnierstatic const char rcsid[] = 3950479Speter "$FreeBSD: head/usr.sbin/mtree/spec.c 54375 1999-12-09 20:38:36Z joe $"; 401553Srgrimes#endif /* not lint */ 411553Srgrimes 421553Srgrimes#include <sys/types.h> 431553Srgrimes#include <sys/stat.h> 4430027Scharnier#include <ctype.h> 4530027Scharnier#include <err.h> 4630027Scharnier#include <errno.h> 471553Srgrimes#include <fts.h> 4830027Scharnier#include <grp.h> 491553Srgrimes#include <pwd.h> 5030027Scharnier#include <stdio.h> 511553Srgrimes#include <unistd.h> 5242561Sjkoshy#include <vis.h> 531553Srgrimes#include "mtree.h" 541553Srgrimes#include "extern.h" 551553Srgrimes 561553Srgrimesint lineno; /* Current spec line number. */ 571553Srgrimes 581553Srgrimesstatic void set __P((char *, NODE *)); 591553Srgrimesstatic void unset __P((char *, NODE *)); 601553Srgrimes 611553SrgrimesNODE * 621553Srgrimesspec() 631553Srgrimes{ 641553Srgrimes register NODE *centry, *last; 651553Srgrimes register char *p; 661553Srgrimes NODE ginfo, *root; 671553Srgrimes int c_cur, c_next; 681553Srgrimes char buf[2048]; 691553Srgrimes 702860Srgrimes centry = last = root = NULL; 711553Srgrimes bzero(&ginfo, sizeof(ginfo)); 721553Srgrimes c_cur = c_next = 0; 731553Srgrimes for (lineno = 1; fgets(buf, sizeof(buf), stdin); 741553Srgrimes ++lineno, c_cur = c_next, c_next = 0) { 751553Srgrimes /* Skip empty lines. */ 761553Srgrimes if (buf[0] == '\n') 771553Srgrimes continue; 781553Srgrimes 791553Srgrimes /* Find end of line. */ 801553Srgrimes if ((p = index(buf, '\n')) == NULL) 8130027Scharnier errx(1, "line %d too long", lineno); 821553Srgrimes 831553Srgrimes /* See if next line is continuation line. */ 841553Srgrimes if (p[-1] == '\\') { 851553Srgrimes --p; 861553Srgrimes c_next = 1; 871553Srgrimes } 881553Srgrimes 891553Srgrimes /* Null-terminate the line. */ 901553Srgrimes *p = '\0'; 911553Srgrimes 921553Srgrimes /* Skip leading whitespace. */ 931553Srgrimes for (p = buf; *p && isspace(*p); ++p); 941553Srgrimes 951553Srgrimes /* If nothing but whitespace or comment char, continue. */ 961553Srgrimes if (!*p || *p == '#') 971553Srgrimes continue; 981553Srgrimes 991553Srgrimes#ifdef DEBUG 1001553Srgrimes (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 1011553Srgrimes#endif 1021553Srgrimes if (c_cur) { 1031553Srgrimes set(p, centry); 1041553Srgrimes continue; 1051553Srgrimes } 1068857Srgrimes 1071553Srgrimes /* Grab file name, "$", "set", or "unset". */ 1081553Srgrimes if ((p = strtok(p, "\n\t ")) == NULL) 10930027Scharnier errx(1, "line %d: missing field", lineno); 1101553Srgrimes 1111553Srgrimes if (p[0] == '/') 1121553Srgrimes switch(p[1]) { 1131553Srgrimes case 's': 1141553Srgrimes if (strcmp(p + 1, "set")) 1151553Srgrimes break; 1161553Srgrimes set(NULL, &ginfo); 1171553Srgrimes continue; 1181553Srgrimes case 'u': 1191553Srgrimes if (strcmp(p + 1, "unset")) 1201553Srgrimes break; 1211553Srgrimes unset(NULL, &ginfo); 1221553Srgrimes continue; 1231553Srgrimes } 1241553Srgrimes 1251553Srgrimes if (index(p, '/')) 12630027Scharnier errx(1, "line %d: slash character in file name", 12730027Scharnier lineno); 1281553Srgrimes 1291553Srgrimes if (!strcmp(p, "..")) { 1301553Srgrimes /* Don't go up, if haven't gone down. */ 1311553Srgrimes if (!root) 1321553Srgrimes goto noparent; 1331553Srgrimes if (last->type != F_DIR || last->flags & F_DONE) { 1341553Srgrimes if (last == root) 1351553Srgrimes goto noparent; 1361553Srgrimes last = last->parent; 1371553Srgrimes } 1381553Srgrimes last->flags |= F_DONE; 1391553Srgrimes continue; 1401553Srgrimes 14130027Scharniernoparent: errx(1, "line %d: no parent node", lineno); 1421553Srgrimes } 1431553Srgrimes 1441553Srgrimes if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 14530027Scharnier errx(1, "calloc"); 1461553Srgrimes *centry = ginfo; 1471553Srgrimes#define MAGIC "?*[" 1481553Srgrimes if (strpbrk(p, MAGIC)) 1491553Srgrimes centry->flags |= F_MAGIC; 15042561Sjkoshy if (strunvis(centry->name, p) == -1) { 15142561Sjkoshy warnx("filename %s is ill-encoded and literally used", 15242561Sjkoshy p); 15342561Sjkoshy strcpy(centry->name, p); 15442561Sjkoshy } 1551553Srgrimes set(NULL, centry); 1561553Srgrimes 1571553Srgrimes if (!root) { 1581553Srgrimes last = root = centry; 1591553Srgrimes root->parent = root; 1601553Srgrimes } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 1611553Srgrimes centry->parent = last; 1621553Srgrimes last = last->child = centry; 1631553Srgrimes } else { 1641553Srgrimes centry->parent = last->parent; 1651553Srgrimes centry->prev = last; 1661553Srgrimes last = last->next = centry; 1671553Srgrimes } 1681553Srgrimes } 1691553Srgrimes return (root); 1701553Srgrimes} 1711553Srgrimes 1721553Srgrimesstatic void 1731553Srgrimesset(t, ip) 1741553Srgrimes char *t; 17554375Sjoe NODE *ip; 1761553Srgrimes{ 1771553Srgrimes register int type; 17854375Sjoe char *kw, *val = NULL; 1791553Srgrimes struct group *gr; 1801553Srgrimes struct passwd *pw; 1811553Srgrimes mode_t *m; 1821553Srgrimes int value; 1831553Srgrimes char *ep; 1841553Srgrimes 1852860Srgrimes for (; (kw = strtok(t, "= \t\n")); t = NULL) { 1861553Srgrimes ip->flags |= type = parsekey(kw, &value); 1871553Srgrimes if (value && (val = strtok(NULL, " \t\n")) == NULL) 18830027Scharnier errx(1, "line %d: missing value", lineno); 1891553Srgrimes switch(type) { 1901553Srgrimes case F_CKSUM: 1911553Srgrimes ip->cksum = strtoul(val, &ep, 10); 1921553Srgrimes if (*ep) 19330027Scharnier errx(1, "line %d: invalid checksum %s", 19430027Scharnier lineno, val); 1951553Srgrimes break; 1966286Swollman case F_MD5: 1976286Swollman ip->md5digest = strdup(val); 1986286Swollman if(!ip->md5digest) { 19930027Scharnier errx(1, "strdup"); 2006286Swollman } 2016286Swollman break; 20244303Swollman case F_SHA1: 20344303Swollman ip->sha1digest = strdup(val); 20444303Swollman if(!ip->sha1digest) { 20544303Swollman errx(1, "strdup"); 20644303Swollman } 20744303Swollman break; 20844303Swollman case F_RMD160: 20944303Swollman ip->rmd160digest = strdup(val); 21044303Swollman if(!ip->rmd160digest) { 21144303Swollman errx(1, "strdup"); 21244303Swollman } 21344303Swollman break; 21454375Sjoe case F_FLAGS: 21554375Sjoe if (strcmp("none", val) == 0) 21654375Sjoe ip->st_flags = 0; 21754375Sjoe else if (string_to_flags(&val, &ip->st_flags,NULL) != 0) 21854375Sjoe errx(1, "line %d: invalid flag %s",lineno, val); 21954375Sjoe break; 2201553Srgrimes case F_GID: 2211553Srgrimes ip->st_gid = strtoul(val, &ep, 10); 2221553Srgrimes if (*ep) 22330027Scharnier errx(1, "line %d: invalid gid %s", lineno, val); 2241553Srgrimes break; 2251553Srgrimes case F_GNAME: 2261553Srgrimes if ((gr = getgrnam(val)) == NULL) 22730027Scharnier errx(1, "line %d: unknown group %s", lineno, val); 2281553Srgrimes ip->st_gid = gr->gr_gid; 2291553Srgrimes break; 2301553Srgrimes case F_IGN: 2311553Srgrimes /* just set flag bit */ 2321553Srgrimes break; 2331553Srgrimes case F_MODE: 2341553Srgrimes if ((m = setmode(val)) == NULL) 23530027Scharnier errx(1, "line %d: invalid file mode %s", 23630027Scharnier lineno, val); 2371553Srgrimes ip->st_mode = getmode(m, 0); 23841848Simp free(m); 2391553Srgrimes break; 2401553Srgrimes case F_NLINK: 2411553Srgrimes ip->st_nlink = strtoul(val, &ep, 10); 2421553Srgrimes if (*ep) 24330027Scharnier errx(1, "line %d: invalid link count %s", 24430027Scharnier lineno, val); 2451553Srgrimes break; 2461553Srgrimes case F_SIZE: 24711282Storstenb ip->st_size = strtoq(val, &ep, 10); 2481553Srgrimes if (*ep) 24930027Scharnier errx(1, "line %d: invalid size %s", 25030027Scharnier lineno, val); 2511553Srgrimes break; 2521553Srgrimes case F_SLINK: 2531553Srgrimes if ((ip->slink = strdup(val)) == NULL) 25430027Scharnier errx(1, "strdup"); 2551553Srgrimes break; 2561553Srgrimes case F_TIME: 25718404Snate ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 2581553Srgrimes if (*ep != '.') 25930027Scharnier errx(1, "line %d: invalid time %s", 26030027Scharnier lineno, val); 2611553Srgrimes val = ep + 1; 26218404Snate ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); 2631553Srgrimes if (*ep) 26430027Scharnier errx(1, "line %d: invalid time %s", 26530027Scharnier lineno, val); 2661553Srgrimes break; 2671553Srgrimes case F_TYPE: 2681553Srgrimes switch(*val) { 2691553Srgrimes case 'b': 2701553Srgrimes if (!strcmp(val, "block")) 2711553Srgrimes ip->type = F_BLOCK; 2721553Srgrimes break; 2731553Srgrimes case 'c': 2741553Srgrimes if (!strcmp(val, "char")) 2751553Srgrimes ip->type = F_CHAR; 2761553Srgrimes break; 2771553Srgrimes case 'd': 2781553Srgrimes if (!strcmp(val, "dir")) 2791553Srgrimes ip->type = F_DIR; 2801553Srgrimes break; 2811553Srgrimes case 'f': 2821553Srgrimes if (!strcmp(val, "file")) 2831553Srgrimes ip->type = F_FILE; 2841553Srgrimes if (!strcmp(val, "fifo")) 2851553Srgrimes ip->type = F_FIFO; 2861553Srgrimes break; 2871553Srgrimes case 'l': 2881553Srgrimes if (!strcmp(val, "link")) 2891553Srgrimes ip->type = F_LINK; 2901553Srgrimes break; 2911553Srgrimes case 's': 2921553Srgrimes if (!strcmp(val, "socket")) 2931553Srgrimes ip->type = F_SOCK; 2941553Srgrimes break; 2951553Srgrimes default: 29630027Scharnier errx(1, "line %d: unknown file type %s", 29730027Scharnier lineno, val); 2981553Srgrimes } 2991553Srgrimes break; 3001553Srgrimes case F_UID: 3011553Srgrimes ip->st_uid = strtoul(val, &ep, 10); 3021553Srgrimes if (*ep) 30330027Scharnier errx(1, "line %d: invalid uid %s", lineno, val); 3041553Srgrimes break; 3051553Srgrimes case F_UNAME: 3061553Srgrimes if ((pw = getpwnam(val)) == NULL) 30730027Scharnier errx(1, "line %d: unknown user %s", lineno, val); 3081553Srgrimes ip->st_uid = pw->pw_uid; 3091553Srgrimes break; 3101553Srgrimes } 3111553Srgrimes } 3121553Srgrimes} 3131553Srgrimes 3141553Srgrimesstatic void 3151553Srgrimesunset(t, ip) 3161553Srgrimes char *t; 3171553Srgrimes register NODE *ip; 3181553Srgrimes{ 3191553Srgrimes register char *p; 3201553Srgrimes 3212860Srgrimes while ((p = strtok(t, "\n\t "))) 3221553Srgrimes ip->flags &= ~parsekey(p, NULL); 3231553Srgrimes} 324