spec.c revision 187910
1276789Sdim/*- 2276789Sdim * Copyright (c) 1989, 1993 3353358Sdim * The Regents of the University of California. All rights reserved. 4353358Sdim * 5353358Sdim * Redistribution and use in source and binary forms, with or without 6276789Sdim * modification, are permitted provided that the following conditions 7276789Sdim * are met: 8276789Sdim * 1. Redistributions of source code must retain the above copyright 9276789Sdim * notice, this list of conditions and the following disclaimer. 10276789Sdim * 2. Redistributions in binary form must reproduce the above copyright 11276789Sdim * notice, this list of conditions and the following disclaimer in the 12276789Sdim * documentation and/or other materials provided with the distribution. 13276789Sdim * 3. Neither the name of the University nor the names of its contributors 14276789Sdim * may be used to endorse or promote products derived from this software 15296417Sdim * without specific prior written permission. 16276789Sdim * 17276789Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18276789Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19276789Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20276789Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21276789Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22276789Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23276789Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24276789Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25276789Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26276789Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27276789Sdim * SUCH DAMAGE. 28276789Sdim */ 29276789Sdim 30276789Sdim#if 0 31276789Sdim#ifndef lint 32276789Sdimstatic char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; 33276789Sdim#endif /* not lint */ 34276789Sdim#endif 35276789Sdim#include <sys/cdefs.h> 36276789Sdim__FBSDID("$FreeBSD: head/usr.sbin/mtree/spec.c 187910 2009-01-30 05:49:27Z kientzle $"); 37276789Sdim 38276789Sdim#include <sys/types.h> 39276789Sdim#include <sys/stat.h> 40276789Sdim#include <ctype.h> 41276789Sdim#include <err.h> 42276789Sdim#include <errno.h> 43276789Sdim#include <fts.h> 44276789Sdim#include <grp.h> 45276789Sdim#include <pwd.h> 46276789Sdim#include <stdio.h> 47276789Sdim#include <unistd.h> 48276789Sdim#include <vis.h> 49276789Sdim#include "mtree.h" 50276789Sdim#include "extern.h" 51276789Sdim 52276789Sdimint lineno; /* Current spec line number. */ 53276789Sdim 54276789Sdimstatic void set(char *, NODE *); 55276789Sdimstatic void unset(char *, NODE *); 56276789Sdim 57276789SdimNODE * 58276789Sdimmtree_readspec(FILE *fi) 59276789Sdim{ 60276789Sdim NODE *centry, *last; 61276789Sdim char *p; 62276789Sdim NODE ginfo, *root; 63276789Sdim int c_cur, c_next; 64276789Sdim char buf[2048]; 65276789Sdim 66276789Sdim centry = last = root = NULL; 67276789Sdim bzero(&ginfo, sizeof(ginfo)); 68276789Sdim c_cur = c_next = 0; 69276789Sdim for (lineno = 1; fgets(buf, sizeof(buf), fi); 70276789Sdim ++lineno, c_cur = c_next, c_next = 0) { 71276789Sdim /* Skip empty lines. */ 72276789Sdim if (buf[0] == '\n') 73276789Sdim continue; 74276789Sdim 75276789Sdim /* Find end of line. */ 76276789Sdim if ((p = index(buf, '\n')) == NULL) 77276789Sdim errx(1, "line %d too long", lineno); 78276789Sdim 79276789Sdim /* See if next line is continuation line. */ 80276789Sdim if (p[-1] == '\\') { 81276789Sdim --p; 82276789Sdim c_next = 1; 83276789Sdim } 84276789Sdim 85276789Sdim /* Null-terminate the line. */ 86276789Sdim *p = '\0'; 87276789Sdim 88276789Sdim /* Skip leading whitespace. */ 89276789Sdim for (p = buf; *p && isspace(*p); ++p); 90276789Sdim 91276789Sdim /* If nothing but whitespace or comment char, continue. */ 92276789Sdim if (!*p || *p == '#') 93276789Sdim continue; 94276789Sdim 95276789Sdim#ifdef DEBUG 96276789Sdim (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 97276789Sdim#endif 98276789Sdim if (c_cur) { 99276789Sdim set(p, centry); 100276789Sdim continue; 101276789Sdim } 102276789Sdim 103276789Sdim /* Grab file name, "$", "set", or "unset". */ 104276789Sdim if ((p = strtok(p, "\n\t ")) == NULL) 105276789Sdim errx(1, "line %d: missing field", lineno); 106276789Sdim 107276789Sdim if (p[0] == '/') 108276789Sdim switch(p[1]) { 109276789Sdim case 's': 110276789Sdim if (strcmp(p + 1, "set")) 111276789Sdim break; 112276789Sdim set(NULL, &ginfo); 113276789Sdim continue; 114276789Sdim case 'u': 115276789Sdim if (strcmp(p + 1, "unset")) 116276789Sdim break; 117276789Sdim unset(NULL, &ginfo); 118276789Sdim continue; 119276789Sdim } 120276789Sdim 121276789Sdim if (index(p, '/')) 122276789Sdim errx(1, "line %d: slash character in file name", 123276789Sdim lineno); 124276789Sdim 125276789Sdim if (!strcmp(p, "..")) { 126276789Sdim /* Don't go up, if haven't gone down. */ 127276789Sdim if (!root) 128276789Sdim goto noparent; 129276789Sdim if (last->type != F_DIR || last->flags & F_DONE) { 130276789Sdim if (last == root) 131276789Sdim goto noparent; 132276789Sdim last = last->parent; 133276789Sdim } 134276789Sdim last->flags |= F_DONE; 135276789Sdim continue; 136276789Sdim 137276789Sdimnoparent: errx(1, "line %d: no parent node", lineno); 138276789Sdim } 139276789Sdim 140276789Sdim if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 141276789Sdim errx(1, "calloc"); 142276789Sdim *centry = ginfo; 143276789Sdim#define MAGIC "?*[" 144276789Sdim if (strpbrk(p, MAGIC)) 145276789Sdim centry->flags |= F_MAGIC; 146276789Sdim if (strunvis(centry->name, p) == -1) 147276789Sdim errx(1, "filename %s is ill-encoded", p); 148276789Sdim set(NULL, centry); 149276789Sdim 150276789Sdim if (!root) { 151276789Sdim last = root = centry; 152276789Sdim root->parent = root; 153276789Sdim } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 154276789Sdim centry->parent = last; 155276789Sdim last = last->child = centry; 156276789Sdim } else { 157276789Sdim centry->parent = last->parent; 158276789Sdim centry->prev = last; 159276789Sdim last = last->next = centry; 160276789Sdim } 161276789Sdim } 162276789Sdim return (root); 163276789Sdim} 164276789Sdim 165276789Sdimstatic void 166276789Sdimset(char *t, NODE *ip) 167276789Sdim{ 168276789Sdim int type; 169276789Sdim char *kw, *val = NULL; 170276789Sdim struct group *gr; 171276789Sdim struct passwd *pw; 172276789Sdim mode_t *m; 173276789Sdim int value; 174276789Sdim char *ep; 175276789Sdim 176276789Sdim for (; (kw = strtok(t, "= \t\n")); t = NULL) { 177276789Sdim ip->flags |= type = parsekey(kw, &value); 178276789Sdim if (value && (val = strtok(NULL, " \t\n")) == NULL) 179276789Sdim errx(1, "line %d: missing value", lineno); 180276789Sdim switch(type) { 181276789Sdim case F_CKSUM: 182276789Sdim ip->cksum = strtoul(val, &ep, 10); 183276789Sdim if (*ep) 184276789Sdim errx(1, "line %d: invalid checksum %s", 185276789Sdim lineno, val); 186276789Sdim break; 187276789Sdim case F_MD5: 188276789Sdim ip->md5digest = strdup(val); 189276789Sdim if(!ip->md5digest) 190276789Sdim errx(1, "strdup"); 191276789Sdim break; 192276789Sdim case F_SHA1: 193276789Sdim ip->sha1digest = strdup(val); 194296417Sdim if(!ip->sha1digest) 195276789Sdim errx(1, "strdup"); 196276789Sdim break; 197276789Sdim case F_SHA256: 198276789Sdim ip->sha256digest = strdup(val); 199276789Sdim if(!ip->sha256digest) 200276789Sdim errx(1, "strdup"); 201276789Sdim break; 202276789Sdim case F_RMD160: 203276789Sdim ip->rmd160digest = strdup(val); 204276789Sdim if(!ip->rmd160digest) 205276789Sdim errx(1, "strdup"); 206276789Sdim break; 207276789Sdim case F_FLAGS: 208276789Sdim if (strcmp("none", val) == 0) 209296417Sdim ip->st_flags = 0; 210276789Sdim else if (strtofflags(&val, &ip->st_flags, NULL) != 0) 211276789Sdim errx(1, "line %d: invalid flag %s",lineno, val); 212276789Sdim break; 213276789Sdim case F_GID: 214276789Sdim ip->st_gid = strtoul(val, &ep, 10); 215276789Sdim if (*ep) 216276789Sdim errx(1, "line %d: invalid gid %s", lineno, val); 217276789Sdim break; 218276789Sdim case F_GNAME: 219276789Sdim if ((gr = getgrnam(val)) == NULL) 220276789Sdim errx(1, "line %d: unknown group %s", lineno, val); 221276789Sdim ip->st_gid = gr->gr_gid; 222276789Sdim break; 223276789Sdim case F_IGN: 224276789Sdim /* just set flag bit */ 225276789Sdim break; 226276789Sdim case F_MODE: 227276789Sdim if ((m = setmode(val)) == NULL) 228276789Sdim errx(1, "line %d: invalid file mode %s", 229296417Sdim lineno, val); 230296417Sdim ip->st_mode = getmode(m, 0); 231276789Sdim free(m); 232276789Sdim break; 233276789Sdim case F_NLINK: 234276789Sdim ip->st_nlink = strtoul(val, &ep, 10); 235276789Sdim if (*ep) 236276789Sdim errx(1, "line %d: invalid link count %s", 237276789Sdim lineno, val); 238276789Sdim break; 239276789Sdim case F_OPT: 240276789Sdim /* just set flag bit */ 241276789Sdim break; 242276789Sdim case F_SIZE: 243276789Sdim ip->st_size = strtoq(val, &ep, 10); 244276789Sdim if (*ep) 245276789Sdim errx(1, "line %d: invalid size %s", 246276789Sdim lineno, val); 247276789Sdim break; 248276789Sdim case F_SLINK: 249276789Sdim ip->slink = malloc(strlen(val) + 1); 250276789Sdim if (ip->slink == NULL) 251276789Sdim errx(1, "malloc"); 252276789Sdim if (strunvis(ip->slink, val) == -1) 253276789Sdim errx(1, "symlink %s is ill-encoded", val); 254296417Sdim break; 255276789Sdim case F_TIME: 256276789Sdim ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 257276789Sdim if (*ep == '.') { 258276789Sdim val = ep + 1; 259276789Sdim ip->st_mtimespec.tv_nsec 260276789Sdim = strtoul(val, &ep, 10); 261276789Sdim } else 262276789Sdim ip->st_mtimespec.tv_nsec = 0; 263276789Sdim if (*ep) 264276789Sdim errx(1, "line %d: invalid time %s", 265276789Sdim lineno, val); 266276789Sdim break; 267276789Sdim case F_TYPE: 268276789Sdim switch(*val) { 269276789Sdim case 'b': 270276789Sdim if (!strcmp(val, "block")) 271276789Sdim ip->type = F_BLOCK; 272276789Sdim break; 273276789Sdim case 'c': 274276789Sdim if (!strcmp(val, "char")) 275276789Sdim ip->type = F_CHAR; 276276789Sdim break; 277276789Sdim case 'd': 278276789Sdim if (!strcmp(val, "dir")) 279276789Sdim ip->type = F_DIR; 280276789Sdim break; 281276789Sdim case 'f': 282276789Sdim if (!strcmp(val, "file")) 283276789Sdim ip->type = F_FILE; 284276789Sdim if (!strcmp(val, "fifo")) 285276789Sdim ip->type = F_FIFO; 286276789Sdim break; 287276789Sdim case 'l': 288276789Sdim if (!strcmp(val, "link")) 289276789Sdim ip->type = F_LINK; 290276789Sdim break; 291276789Sdim case 's': 292276789Sdim if (!strcmp(val, "socket")) 293276789Sdim ip->type = F_SOCK; 294276789Sdim break; 295276789Sdim default: 296276789Sdim errx(1, "line %d: unknown file type %s", 297276789Sdim lineno, val); 298276789Sdim } 299276789Sdim break; 300276789Sdim case F_UID: 301276789Sdim ip->st_uid = strtoul(val, &ep, 10); 302276789Sdim if (*ep) 303276789Sdim errx(1, "line %d: invalid uid %s", lineno, val); 304276789Sdim break; 305276789Sdim case F_UNAME: 306276789Sdim if ((pw = getpwnam(val)) == NULL) 307276789Sdim errx(1, "line %d: unknown user %s", lineno, val); 308276789Sdim ip->st_uid = pw->pw_uid; 309276789Sdim break; 310276789Sdim } 311276789Sdim } 312276789Sdim} 313276789Sdim 314276789Sdimstatic void 315276789Sdimunset(char *t, NODE *ip) 316276789Sdim{ 317276789Sdim char *p; 318276789Sdim 319276789Sdim while ((p = strtok(t, "\n\t "))) 320276789Sdim ip->flags &= ~parsekey(p, NULL); 321276789Sdim} 322276789Sdim