spec.c revision 121299
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 34114601Sobrien#if 0 351553Srgrimes#ifndef lint 361553Srgrimesstatic char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; 37114601Sobrien#endif /* not lint */ 3830027Scharnier#endif 39114601Sobrien#include <sys/cdefs.h> 40114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/mtree/spec.c 121299 2003-10-21 07:58:52Z phk $"); 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 5899800Salfredstatic void set(char *, NODE *); 5999800Salfredstatic void unset(char *, NODE *); 601553Srgrimes 611553SrgrimesNODE * 62121299Sphkspec(void) 631553Srgrimes{ 64121299Sphk NODE *centry, *last; 65121299Sphk 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 173121299Sphkset(char *t, NODE *ip) 1741553Srgrimes{ 175121299Sphk int type; 17654375Sjoe char *kw, *val = NULL; 1771553Srgrimes struct group *gr; 1781553Srgrimes struct passwd *pw; 1791553Srgrimes mode_t *m; 1801553Srgrimes int value; 1811553Srgrimes char *ep; 1821553Srgrimes 1832860Srgrimes for (; (kw = strtok(t, "= \t\n")); t = NULL) { 1841553Srgrimes ip->flags |= type = parsekey(kw, &value); 1851553Srgrimes if (value && (val = strtok(NULL, " \t\n")) == NULL) 18630027Scharnier errx(1, "line %d: missing value", lineno); 1871553Srgrimes switch(type) { 1881553Srgrimes case F_CKSUM: 1891553Srgrimes ip->cksum = strtoul(val, &ep, 10); 1901553Srgrimes if (*ep) 19130027Scharnier errx(1, "line %d: invalid checksum %s", 19230027Scharnier lineno, val); 1931553Srgrimes break; 1946286Swollman case F_MD5: 1956286Swollman ip->md5digest = strdup(val); 1966286Swollman if(!ip->md5digest) { 19730027Scharnier errx(1, "strdup"); 1986286Swollman } 1996286Swollman break; 20044303Swollman case F_SHA1: 20144303Swollman ip->sha1digest = strdup(val); 20244303Swollman if(!ip->sha1digest) { 20344303Swollman errx(1, "strdup"); 20444303Swollman } 20544303Swollman break; 20644303Swollman case F_RMD160: 20744303Swollman ip->rmd160digest = strdup(val); 20844303Swollman if(!ip->rmd160digest) { 20944303Swollman errx(1, "strdup"); 21044303Swollman } 21144303Swollman break; 21254375Sjoe case F_FLAGS: 21354375Sjoe if (strcmp("none", val) == 0) 21454375Sjoe ip->st_flags = 0; 21561749Sjoe else if (strtofflags(&val, &ip->st_flags, NULL) != 0) 21654375Sjoe errx(1, "line %d: invalid flag %s",lineno, val); 21754375Sjoe break; 2181553Srgrimes case F_GID: 2191553Srgrimes ip->st_gid = strtoul(val, &ep, 10); 2201553Srgrimes if (*ep) 22130027Scharnier errx(1, "line %d: invalid gid %s", lineno, val); 2221553Srgrimes break; 2231553Srgrimes case F_GNAME: 2241553Srgrimes if ((gr = getgrnam(val)) == NULL) 22530027Scharnier errx(1, "line %d: unknown group %s", lineno, val); 2261553Srgrimes ip->st_gid = gr->gr_gid; 2271553Srgrimes break; 2281553Srgrimes case F_IGN: 2291553Srgrimes /* just set flag bit */ 2301553Srgrimes break; 2311553Srgrimes case F_MODE: 2321553Srgrimes if ((m = setmode(val)) == NULL) 23330027Scharnier errx(1, "line %d: invalid file mode %s", 23430027Scharnier lineno, val); 2351553Srgrimes ip->st_mode = getmode(m, 0); 23641848Simp free(m); 2371553Srgrimes break; 2381553Srgrimes case F_NLINK: 2391553Srgrimes ip->st_nlink = strtoul(val, &ep, 10); 2401553Srgrimes if (*ep) 24130027Scharnier errx(1, "line %d: invalid link count %s", 24230027Scharnier lineno, val); 2431553Srgrimes break; 2441553Srgrimes case F_SIZE: 24511282Storstenb ip->st_size = strtoq(val, &ep, 10); 2461553Srgrimes if (*ep) 24730027Scharnier errx(1, "line %d: invalid size %s", 24830027Scharnier lineno, val); 2491553Srgrimes break; 2501553Srgrimes case F_SLINK: 2511553Srgrimes if ((ip->slink = strdup(val)) == NULL) 25230027Scharnier errx(1, "strdup"); 2531553Srgrimes break; 2541553Srgrimes case F_TIME: 25518404Snate ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 2561553Srgrimes if (*ep != '.') 25730027Scharnier errx(1, "line %d: invalid time %s", 25830027Scharnier lineno, val); 2591553Srgrimes val = ep + 1; 26018404Snate ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); 2611553Srgrimes if (*ep) 26230027Scharnier errx(1, "line %d: invalid time %s", 26330027Scharnier lineno, val); 2641553Srgrimes break; 2651553Srgrimes case F_TYPE: 2661553Srgrimes switch(*val) { 2671553Srgrimes case 'b': 2681553Srgrimes if (!strcmp(val, "block")) 2691553Srgrimes ip->type = F_BLOCK; 2701553Srgrimes break; 2711553Srgrimes case 'c': 2721553Srgrimes if (!strcmp(val, "char")) 2731553Srgrimes ip->type = F_CHAR; 2741553Srgrimes break; 2751553Srgrimes case 'd': 2761553Srgrimes if (!strcmp(val, "dir")) 2771553Srgrimes ip->type = F_DIR; 2781553Srgrimes break; 2791553Srgrimes case 'f': 2801553Srgrimes if (!strcmp(val, "file")) 2811553Srgrimes ip->type = F_FILE; 2821553Srgrimes if (!strcmp(val, "fifo")) 2831553Srgrimes ip->type = F_FIFO; 2841553Srgrimes break; 2851553Srgrimes case 'l': 2861553Srgrimes if (!strcmp(val, "link")) 2871553Srgrimes ip->type = F_LINK; 2881553Srgrimes break; 2891553Srgrimes case 's': 2901553Srgrimes if (!strcmp(val, "socket")) 2911553Srgrimes ip->type = F_SOCK; 2921553Srgrimes break; 2931553Srgrimes default: 29430027Scharnier errx(1, "line %d: unknown file type %s", 29530027Scharnier lineno, val); 2961553Srgrimes } 2971553Srgrimes break; 2981553Srgrimes case F_UID: 2991553Srgrimes ip->st_uid = strtoul(val, &ep, 10); 3001553Srgrimes if (*ep) 30130027Scharnier errx(1, "line %d: invalid uid %s", lineno, val); 3021553Srgrimes break; 3031553Srgrimes case F_UNAME: 3041553Srgrimes if ((pw = getpwnam(val)) == NULL) 30530027Scharnier errx(1, "line %d: unknown user %s", lineno, val); 3061553Srgrimes ip->st_uid = pw->pw_uid; 3071553Srgrimes break; 3081553Srgrimes } 3091553Srgrimes } 3101553Srgrimes} 3111553Srgrimes 3121553Srgrimesstatic void 313121299Sphkunset(char *t, NODE *ip) 3141553Srgrimes{ 315121299Sphk char *p; 3161553Srgrimes 3172860Srgrimes while ((p = strtok(t, "\n\t "))) 3181553Srgrimes ip->flags &= ~parsekey(p, NULL); 3191553Srgrimes} 320