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