spec.c revision 229403
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. 13121300Sphk * 3. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 30114601Sobrien#if 0 311553Srgrimes#ifndef lint 321553Srgrimesstatic char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; 33114601Sobrien#endif /* not lint */ 3430027Scharnier#endif 35114601Sobrien#include <sys/cdefs.h> 36114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/mtree/spec.c 229403 2012-01-03 18:51:58Z ed $"); 371553Srgrimes 381553Srgrimes#include <sys/types.h> 391553Srgrimes#include <sys/stat.h> 4030027Scharnier#include <ctype.h> 4130027Scharnier#include <err.h> 4230027Scharnier#include <errno.h> 431553Srgrimes#include <fts.h> 4430027Scharnier#include <grp.h> 451553Srgrimes#include <pwd.h> 4630027Scharnier#include <stdio.h> 471553Srgrimes#include <unistd.h> 4842561Sjkoshy#include <vis.h> 491553Srgrimes#include "mtree.h" 501553Srgrimes#include "extern.h" 511553Srgrimes 521553Srgrimesint lineno; /* Current spec line number. */ 531553Srgrimes 5499800Salfredstatic void set(char *, NODE *); 5599800Salfredstatic void unset(char *, NODE *); 561553Srgrimes 571553SrgrimesNODE * 58122135Sphkmtree_readspec(FILE *fi) 591553Srgrimes{ 60121299Sphk NODE *centry, *last; 61121299Sphk char *p; 621553Srgrimes NODE ginfo, *root; 631553Srgrimes int c_cur, c_next; 641553Srgrimes char buf[2048]; 651553Srgrimes 662860Srgrimes centry = last = root = NULL; 671553Srgrimes bzero(&ginfo, sizeof(ginfo)); 681553Srgrimes c_cur = c_next = 0; 69122135Sphk for (lineno = 1; fgets(buf, sizeof(buf), fi); 701553Srgrimes ++lineno, c_cur = c_next, c_next = 0) { 711553Srgrimes /* Skip empty lines. */ 721553Srgrimes if (buf[0] == '\n') 731553Srgrimes continue; 741553Srgrimes 751553Srgrimes /* Find end of line. */ 76229403Sed if ((p = strchr(buf, '\n')) == NULL) 7730027Scharnier errx(1, "line %d too long", lineno); 781553Srgrimes 791553Srgrimes /* See if next line is continuation line. */ 801553Srgrimes if (p[-1] == '\\') { 811553Srgrimes --p; 821553Srgrimes c_next = 1; 831553Srgrimes } 841553Srgrimes 851553Srgrimes /* Null-terminate the line. */ 861553Srgrimes *p = '\0'; 871553Srgrimes 881553Srgrimes /* Skip leading whitespace. */ 891553Srgrimes for (p = buf; *p && isspace(*p); ++p); 901553Srgrimes 911553Srgrimes /* If nothing but whitespace or comment char, continue. */ 921553Srgrimes if (!*p || *p == '#') 931553Srgrimes continue; 941553Srgrimes 951553Srgrimes#ifdef DEBUG 961553Srgrimes (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 971553Srgrimes#endif 981553Srgrimes if (c_cur) { 991553Srgrimes set(p, centry); 1001553Srgrimes continue; 1011553Srgrimes } 1028857Srgrimes 1031553Srgrimes /* Grab file name, "$", "set", or "unset". */ 1041553Srgrimes if ((p = strtok(p, "\n\t ")) == NULL) 10530027Scharnier errx(1, "line %d: missing field", lineno); 1061553Srgrimes 1071553Srgrimes if (p[0] == '/') 1081553Srgrimes switch(p[1]) { 1091553Srgrimes case 's': 1101553Srgrimes if (strcmp(p + 1, "set")) 1111553Srgrimes break; 1121553Srgrimes set(NULL, &ginfo); 1131553Srgrimes continue; 1141553Srgrimes case 'u': 1151553Srgrimes if (strcmp(p + 1, "unset")) 1161553Srgrimes break; 1171553Srgrimes unset(NULL, &ginfo); 1181553Srgrimes continue; 1191553Srgrimes } 1201553Srgrimes 121229403Sed if (strchr(p, '/')) 12230027Scharnier errx(1, "line %d: slash character in file name", 12330027Scharnier lineno); 1241553Srgrimes 1251553Srgrimes if (!strcmp(p, "..")) { 1261553Srgrimes /* Don't go up, if haven't gone down. */ 1271553Srgrimes if (!root) 1281553Srgrimes goto noparent; 1291553Srgrimes if (last->type != F_DIR || last->flags & F_DONE) { 1301553Srgrimes if (last == root) 1311553Srgrimes goto noparent; 1321553Srgrimes last = last->parent; 1331553Srgrimes } 1341553Srgrimes last->flags |= F_DONE; 1351553Srgrimes continue; 1361553Srgrimes 13730027Scharniernoparent: errx(1, "line %d: no parent node", lineno); 1381553Srgrimes } 1391553Srgrimes 1401553Srgrimes if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 14130027Scharnier errx(1, "calloc"); 1421553Srgrimes *centry = ginfo; 1431553Srgrimes#define MAGIC "?*[" 1441553Srgrimes if (strpbrk(p, MAGIC)) 1451553Srgrimes centry->flags |= F_MAGIC; 146121734Sphk if (strunvis(centry->name, p) == -1) 147121734Sphk errx(1, "filename %s is ill-encoded", p); 1481553Srgrimes set(NULL, centry); 1491553Srgrimes 1501553Srgrimes if (!root) { 1511553Srgrimes last = root = centry; 1521553Srgrimes root->parent = root; 1531553Srgrimes } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 1541553Srgrimes centry->parent = last; 1551553Srgrimes last = last->child = centry; 1561553Srgrimes } else { 1571553Srgrimes centry->parent = last->parent; 1581553Srgrimes centry->prev = last; 1591553Srgrimes last = last->next = centry; 1601553Srgrimes } 1611553Srgrimes } 1621553Srgrimes return (root); 1631553Srgrimes} 1641553Srgrimes 1651553Srgrimesstatic void 166121299Sphkset(char *t, NODE *ip) 1671553Srgrimes{ 168121299Sphk int type; 16954375Sjoe char *kw, *val = NULL; 1701553Srgrimes struct group *gr; 1711553Srgrimes struct passwd *pw; 1721553Srgrimes mode_t *m; 1731553Srgrimes int value; 1741553Srgrimes char *ep; 1751553Srgrimes 1762860Srgrimes for (; (kw = strtok(t, "= \t\n")); t = NULL) { 1771553Srgrimes ip->flags |= type = parsekey(kw, &value); 1781553Srgrimes if (value && (val = strtok(NULL, " \t\n")) == NULL) 17930027Scharnier errx(1, "line %d: missing value", lineno); 1801553Srgrimes switch(type) { 1811553Srgrimes case F_CKSUM: 1821553Srgrimes ip->cksum = strtoul(val, &ep, 10); 1831553Srgrimes if (*ep) 18430027Scharnier errx(1, "line %d: invalid checksum %s", 18530027Scharnier lineno, val); 1861553Srgrimes break; 1876286Swollman case F_MD5: 1886286Swollman ip->md5digest = strdup(val); 189122135Sphk if(!ip->md5digest) 19030027Scharnier errx(1, "strdup"); 1916286Swollman break; 19244303Swollman case F_SHA1: 19344303Swollman ip->sha1digest = strdup(val); 194122135Sphk if(!ip->sha1digest) 19544303Swollman errx(1, "strdup"); 19644303Swollman break; 197144295Stobez case F_SHA256: 198144295Stobez ip->sha256digest = strdup(val); 199144295Stobez if(!ip->sha256digest) 200144295Stobez errx(1, "strdup"); 201144295Stobez break; 20244303Swollman case F_RMD160: 20344303Swollman ip->rmd160digest = strdup(val); 204122135Sphk if(!ip->rmd160digest) 20544303Swollman errx(1, "strdup"); 20644303Swollman break; 20754375Sjoe case F_FLAGS: 20854375Sjoe if (strcmp("none", val) == 0) 20954375Sjoe ip->st_flags = 0; 21061749Sjoe else if (strtofflags(&val, &ip->st_flags, NULL) != 0) 21154375Sjoe errx(1, "line %d: invalid flag %s",lineno, val); 21254375Sjoe break; 2131553Srgrimes case F_GID: 2141553Srgrimes ip->st_gid = strtoul(val, &ep, 10); 2151553Srgrimes if (*ep) 21630027Scharnier errx(1, "line %d: invalid gid %s", lineno, val); 2171553Srgrimes break; 2181553Srgrimes case F_GNAME: 2191553Srgrimes if ((gr = getgrnam(val)) == NULL) 22030027Scharnier errx(1, "line %d: unknown group %s", lineno, val); 2211553Srgrimes ip->st_gid = gr->gr_gid; 2221553Srgrimes break; 2231553Srgrimes case F_IGN: 2241553Srgrimes /* just set flag bit */ 2251553Srgrimes break; 2261553Srgrimes case F_MODE: 2271553Srgrimes if ((m = setmode(val)) == NULL) 22830027Scharnier errx(1, "line %d: invalid file mode %s", 22930027Scharnier lineno, val); 2301553Srgrimes ip->st_mode = getmode(m, 0); 23141848Simp free(m); 2321553Srgrimes break; 2331553Srgrimes case F_NLINK: 2341553Srgrimes ip->st_nlink = strtoul(val, &ep, 10); 2351553Srgrimes if (*ep) 23630027Scharnier errx(1, "line %d: invalid link count %s", 23730027Scharnier lineno, val); 2381553Srgrimes break; 239160083Smaxim case F_OPT: 240160083Smaxim /* just set flag bit */ 241160083Smaxim break; 2421553Srgrimes case F_SIZE: 24311282Storstenb ip->st_size = strtoq(val, &ep, 10); 2441553Srgrimes if (*ep) 24530027Scharnier errx(1, "line %d: invalid size %s", 24630027Scharnier lineno, val); 2471553Srgrimes break; 2481553Srgrimes case F_SLINK: 249122896Sphk ip->slink = malloc(strlen(val) + 1); 250121734Sphk if (ip->slink == NULL) 251121734Sphk errx(1, "malloc"); 252121734Sphk if (strunvis(ip->slink, val) == -1) 253121734Sphk errx(1, "symlink %s is ill-encoded", val); 2541553Srgrimes break; 2551553Srgrimes case F_TIME: 25618404Snate ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 257187910Skientzle if (*ep == '.') { 258187940Skientzle /* Note: we require exactly nine 259187940Skientzle * digits after the decimal point. */ 260187910Skientzle val = ep + 1; 261187910Skientzle ip->st_mtimespec.tv_nsec 262187910Skientzle = strtoul(val, &ep, 10); 263187910Skientzle } else 264187910Skientzle ip->st_mtimespec.tv_nsec = 0; 2651553Srgrimes if (*ep) 26630027Scharnier errx(1, "line %d: invalid time %s", 267187910Skientzle lineno, val); 2681553Srgrimes break; 2691553Srgrimes case F_TYPE: 2701553Srgrimes switch(*val) { 2711553Srgrimes case 'b': 2721553Srgrimes if (!strcmp(val, "block")) 2731553Srgrimes ip->type = F_BLOCK; 2741553Srgrimes break; 2751553Srgrimes case 'c': 2761553Srgrimes if (!strcmp(val, "char")) 2771553Srgrimes ip->type = F_CHAR; 2781553Srgrimes break; 2791553Srgrimes case 'd': 2801553Srgrimes if (!strcmp(val, "dir")) 2811553Srgrimes ip->type = F_DIR; 2821553Srgrimes break; 2831553Srgrimes case 'f': 2841553Srgrimes if (!strcmp(val, "file")) 2851553Srgrimes ip->type = F_FILE; 2861553Srgrimes if (!strcmp(val, "fifo")) 2871553Srgrimes ip->type = F_FIFO; 2881553Srgrimes break; 2891553Srgrimes case 'l': 2901553Srgrimes if (!strcmp(val, "link")) 2911553Srgrimes ip->type = F_LINK; 2921553Srgrimes break; 2931553Srgrimes case 's': 2941553Srgrimes if (!strcmp(val, "socket")) 2951553Srgrimes ip->type = F_SOCK; 2961553Srgrimes break; 2971553Srgrimes default: 29830027Scharnier errx(1, "line %d: unknown file type %s", 29930027Scharnier lineno, val); 3001553Srgrimes } 3011553Srgrimes break; 3021553Srgrimes case F_UID: 3031553Srgrimes ip->st_uid = strtoul(val, &ep, 10); 3041553Srgrimes if (*ep) 30530027Scharnier errx(1, "line %d: invalid uid %s", lineno, val); 3061553Srgrimes break; 3071553Srgrimes case F_UNAME: 3081553Srgrimes if ((pw = getpwnam(val)) == NULL) 30930027Scharnier errx(1, "line %d: unknown user %s", lineno, val); 3101553Srgrimes ip->st_uid = pw->pw_uid; 3111553Srgrimes break; 3121553Srgrimes } 3131553Srgrimes } 3141553Srgrimes} 3151553Srgrimes 3161553Srgrimesstatic void 317121299Sphkunset(char *t, NODE *ip) 3181553Srgrimes{ 319121299Sphk char *p; 3201553Srgrimes 3212860Srgrimes while ((p = strtok(t, "\n\t "))) 3221553Srgrimes ip->flags &= ~parsekey(p, NULL); 3231553Srgrimes} 324