1df930be7Sderaadt /* $NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $ */ 2*94bb8e67Smillert /* $OpenBSD: spec.c,v 1.4 1996/12/20 18:13:44 millert Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /*- 5df930be7Sderaadt * Copyright (c) 1989, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 16df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 17df930be7Sderaadt * must display the following acknowledgement: 18df930be7Sderaadt * This product includes software developed by the University of 19df930be7Sderaadt * California, Berkeley and its contributors. 20df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 21df930be7Sderaadt * may be used to endorse or promote products derived from this software 22df930be7Sderaadt * without specific prior written permission. 23df930be7Sderaadt * 24df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df930be7Sderaadt * SUCH DAMAGE. 35df930be7Sderaadt */ 36df930be7Sderaadt 37df930be7Sderaadt #ifndef lint 38df930be7Sderaadt #if 0 39df930be7Sderaadt static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; 40df930be7Sderaadt #else 41df930be7Sderaadt static char rcsid[] = "$NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $"; 42df930be7Sderaadt #endif 43df930be7Sderaadt #endif /* not lint */ 44df930be7Sderaadt 45df930be7Sderaadt #include <sys/types.h> 46df930be7Sderaadt #include <sys/stat.h> 47df930be7Sderaadt #include <fts.h> 48df930be7Sderaadt #include <pwd.h> 49df930be7Sderaadt #include <grp.h> 50df930be7Sderaadt #include <errno.h> 51df930be7Sderaadt #include <unistd.h> 52df930be7Sderaadt #include <stdio.h> 53df930be7Sderaadt #include <ctype.h> 54df930be7Sderaadt #include "mtree.h" 55df930be7Sderaadt #include "extern.h" 56df930be7Sderaadt 57df930be7Sderaadt int lineno; /* Current spec line number. */ 58df930be7Sderaadt 59df930be7Sderaadt static void set __P((char *, NODE *)); 60df930be7Sderaadt static void unset __P((char *, NODE *)); 61df930be7Sderaadt 62df930be7Sderaadt NODE * 63df930be7Sderaadt spec() 64df930be7Sderaadt { 65df930be7Sderaadt register NODE *centry, *last; 66df930be7Sderaadt register char *p; 67df930be7Sderaadt NODE ginfo, *root; 68df930be7Sderaadt int c_cur, c_next; 69df930be7Sderaadt char buf[2048]; 70df930be7Sderaadt 7146360e3cSderaadt centry = last = root = NULL; 72df930be7Sderaadt bzero(&ginfo, sizeof(ginfo)); 73df930be7Sderaadt c_cur = c_next = 0; 74df930be7Sderaadt for (lineno = 1; fgets(buf, sizeof(buf), stdin); 75df930be7Sderaadt ++lineno, c_cur = c_next, c_next = 0) { 76df930be7Sderaadt /* Skip empty lines. */ 77df930be7Sderaadt if (buf[0] == '\n') 78df930be7Sderaadt continue; 79df930be7Sderaadt 80df930be7Sderaadt /* Find end of line. */ 81df930be7Sderaadt if ((p = index(buf, '\n')) == NULL) 82df930be7Sderaadt err("line %d too long", lineno); 83df930be7Sderaadt 84df930be7Sderaadt /* See if next line is continuation line. */ 85df930be7Sderaadt if (p[-1] == '\\') { 86df930be7Sderaadt --p; 87df930be7Sderaadt c_next = 1; 88df930be7Sderaadt } 89df930be7Sderaadt 90df930be7Sderaadt /* Null-terminate the line. */ 91df930be7Sderaadt *p = '\0'; 92df930be7Sderaadt 93df930be7Sderaadt /* Skip leading whitespace. */ 94df930be7Sderaadt for (p = buf; *p && isspace(*p); ++p); 95df930be7Sderaadt 96df930be7Sderaadt /* If nothing but whitespace or comment char, continue. */ 97df930be7Sderaadt if (!*p || *p == '#') 98df930be7Sderaadt continue; 99df930be7Sderaadt 100df930be7Sderaadt #ifdef DEBUG 101df930be7Sderaadt (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 102df930be7Sderaadt #endif 103df930be7Sderaadt if (c_cur) { 104df930be7Sderaadt set(p, centry); 105df930be7Sderaadt continue; 106df930be7Sderaadt } 107df930be7Sderaadt 108df930be7Sderaadt /* Grab file name, "$", "set", or "unset". */ 109df930be7Sderaadt if ((p = strtok(p, "\n\t ")) == NULL) 110df930be7Sderaadt err("missing field"); 111df930be7Sderaadt 112df930be7Sderaadt if (p[0] == '/') 113df930be7Sderaadt switch(p[1]) { 114df930be7Sderaadt case 's': 115df930be7Sderaadt if (strcmp(p + 1, "set")) 116df930be7Sderaadt break; 117df930be7Sderaadt set(NULL, &ginfo); 118df930be7Sderaadt continue; 119df930be7Sderaadt case 'u': 120df930be7Sderaadt if (strcmp(p + 1, "unset")) 121df930be7Sderaadt break; 122df930be7Sderaadt unset(NULL, &ginfo); 123df930be7Sderaadt continue; 124df930be7Sderaadt } 125df930be7Sderaadt 126df930be7Sderaadt if (index(p, '/')) 127df930be7Sderaadt err("slash character in file name"); 128df930be7Sderaadt 129df930be7Sderaadt if (!strcmp(p, "..")) { 130df930be7Sderaadt /* Don't go up, if haven't gone down. */ 131df930be7Sderaadt if (!root) 132df930be7Sderaadt goto noparent; 133df930be7Sderaadt if (last->type != F_DIR || last->flags & F_DONE) { 134df930be7Sderaadt if (last == root) 135df930be7Sderaadt goto noparent; 136df930be7Sderaadt last = last->parent; 137df930be7Sderaadt } 138df930be7Sderaadt last->flags |= F_DONE; 139df930be7Sderaadt continue; 140df930be7Sderaadt 141df930be7Sderaadt noparent: err("no parent node"); 142df930be7Sderaadt } 143df930be7Sderaadt 144df930be7Sderaadt if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 145df930be7Sderaadt err("%s", strerror(errno)); 146df930be7Sderaadt *centry = ginfo; 147df930be7Sderaadt (void)strcpy(centry->name, p); 148df930be7Sderaadt #define MAGIC "?*[" 149df930be7Sderaadt if (strpbrk(p, MAGIC)) 150df930be7Sderaadt centry->flags |= F_MAGIC; 151df930be7Sderaadt set(NULL, centry); 152df930be7Sderaadt 153df930be7Sderaadt if (!root) { 154df930be7Sderaadt last = root = centry; 155df930be7Sderaadt root->parent = root; 156df930be7Sderaadt } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 157df930be7Sderaadt centry->parent = last; 158df930be7Sderaadt last = last->child = centry; 159df930be7Sderaadt } else { 160df930be7Sderaadt centry->parent = last->parent; 161df930be7Sderaadt centry->prev = last; 162df930be7Sderaadt last = last->next = centry; 163df930be7Sderaadt } 164df930be7Sderaadt } 165df930be7Sderaadt return (root); 166df930be7Sderaadt } 167df930be7Sderaadt 168df930be7Sderaadt static void 169df930be7Sderaadt set(t, ip) 170df930be7Sderaadt char *t; 171df930be7Sderaadt register NODE *ip; 172df930be7Sderaadt { 173df930be7Sderaadt register int type; 17446360e3cSderaadt register char *kw, *val = NULL; 175df930be7Sderaadt struct group *gr; 176df930be7Sderaadt struct passwd *pw; 177df930be7Sderaadt mode_t *m; 178df930be7Sderaadt int value; 179df930be7Sderaadt char *ep; 180df930be7Sderaadt 18146360e3cSderaadt for (; (kw = strtok(t, "= \t\n")); t = NULL) { 182df930be7Sderaadt ip->flags |= type = parsekey(kw, &value); 183df930be7Sderaadt if (value && (val = strtok(NULL, " \t\n")) == NULL) 184df930be7Sderaadt err("missing value"); 185df930be7Sderaadt switch(type) { 186df930be7Sderaadt case F_CKSUM: 187df930be7Sderaadt ip->cksum = strtoul(val, &ep, 10); 188df930be7Sderaadt if (*ep) 189df930be7Sderaadt err("invalid checksum %s", val); 190df930be7Sderaadt break; 19146360e3cSderaadt case F_MD5: 19246360e3cSderaadt ip->md5digest = strdup(val); 19346360e3cSderaadt if (!ip->md5digest) { 19446360e3cSderaadt err("%s", strerror(errno)); 19546360e3cSderaadt } 19646360e3cSderaadt break; 197df930be7Sderaadt case F_GID: 198df930be7Sderaadt ip->st_gid = strtoul(val, &ep, 10); 199df930be7Sderaadt if (*ep) 200df930be7Sderaadt err("invalid gid %s", val); 201df930be7Sderaadt break; 202df930be7Sderaadt case F_GNAME: 203df930be7Sderaadt if ((gr = getgrnam(val)) == NULL) 204df930be7Sderaadt err("unknown group %s", val); 205df930be7Sderaadt ip->st_gid = gr->gr_gid; 206df930be7Sderaadt break; 207df930be7Sderaadt case F_IGN: 208df930be7Sderaadt /* just set flag bit */ 209df930be7Sderaadt break; 210df930be7Sderaadt case F_MODE: 211df930be7Sderaadt if ((m = setmode(val)) == NULL) 212df930be7Sderaadt err("invalid file mode %s", val); 213df930be7Sderaadt ip->st_mode = getmode(m, 0); 214df930be7Sderaadt break; 215df930be7Sderaadt case F_NLINK: 216df930be7Sderaadt ip->st_nlink = strtoul(val, &ep, 10); 217df930be7Sderaadt if (*ep) 218df930be7Sderaadt err("invalid link count %s", val); 219df930be7Sderaadt break; 220df930be7Sderaadt case F_SIZE: 221*94bb8e67Smillert ip->st_size = strtouq(val, &ep, 10); 222df930be7Sderaadt if (*ep) 223df930be7Sderaadt err("invalid size %s", val); 224df930be7Sderaadt break; 225df930be7Sderaadt case F_SLINK: 226df930be7Sderaadt if ((ip->slink = strdup(val)) == NULL) 227df930be7Sderaadt err("%s", strerror(errno)); 228df930be7Sderaadt break; 229df930be7Sderaadt case F_TIME: 230c9fd28a4Stholo ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 231df930be7Sderaadt if (*ep != '.') 232df930be7Sderaadt err("invalid time %s", val); 233df930be7Sderaadt val = ep + 1; 234c9fd28a4Stholo ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); 235df930be7Sderaadt if (*ep) 236df930be7Sderaadt err("invalid time %s", val); 237df930be7Sderaadt break; 238df930be7Sderaadt case F_TYPE: 239df930be7Sderaadt switch(*val) { 240df930be7Sderaadt case 'b': 241df930be7Sderaadt if (!strcmp(val, "block")) 242df930be7Sderaadt ip->type = F_BLOCK; 243df930be7Sderaadt break; 244df930be7Sderaadt case 'c': 245df930be7Sderaadt if (!strcmp(val, "char")) 246df930be7Sderaadt ip->type = F_CHAR; 247df930be7Sderaadt break; 248df930be7Sderaadt case 'd': 249df930be7Sderaadt if (!strcmp(val, "dir")) 250df930be7Sderaadt ip->type = F_DIR; 251df930be7Sderaadt break; 252df930be7Sderaadt case 'f': 253df930be7Sderaadt if (!strcmp(val, "file")) 254df930be7Sderaadt ip->type = F_FILE; 255df930be7Sderaadt if (!strcmp(val, "fifo")) 256df930be7Sderaadt ip->type = F_FIFO; 257df930be7Sderaadt break; 258df930be7Sderaadt case 'l': 259df930be7Sderaadt if (!strcmp(val, "link")) 260df930be7Sderaadt ip->type = F_LINK; 261df930be7Sderaadt break; 262df930be7Sderaadt case 's': 263df930be7Sderaadt if (!strcmp(val, "socket")) 264df930be7Sderaadt ip->type = F_SOCK; 265df930be7Sderaadt break; 266df930be7Sderaadt default: 267df930be7Sderaadt err("unknown file type %s", val); 268df930be7Sderaadt } 269df930be7Sderaadt break; 270df930be7Sderaadt case F_UID: 271df930be7Sderaadt ip->st_uid = strtoul(val, &ep, 10); 272df930be7Sderaadt if (*ep) 273df930be7Sderaadt err("invalid uid %s", val); 274df930be7Sderaadt break; 275df930be7Sderaadt case F_UNAME: 276df930be7Sderaadt if ((pw = getpwnam(val)) == NULL) 277df930be7Sderaadt err("unknown user %s", val); 278df930be7Sderaadt ip->st_uid = pw->pw_uid; 279df930be7Sderaadt break; 280df930be7Sderaadt } 281df930be7Sderaadt } 282df930be7Sderaadt } 283df930be7Sderaadt 284df930be7Sderaadt static void 285df930be7Sderaadt unset(t, ip) 286df930be7Sderaadt char *t; 287df930be7Sderaadt register NODE *ip; 288df930be7Sderaadt { 289df930be7Sderaadt register char *p; 290df930be7Sderaadt 29146360e3cSderaadt while ((p = strtok(t, "\n\t "))) 292df930be7Sderaadt ip->flags &= ~parsekey(p, NULL); 293df930be7Sderaadt } 294