1 /*- 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)spec.c 5.16 (Berkeley) 02/19/92"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <fts.h> 15 #include <pwd.h> 16 #include <grp.h> 17 #include <errno.h> 18 #include <unistd.h> 19 #include <stdio.h> 20 #include <ctype.h> 21 #include "mtree.h" 22 #include "extern.h" 23 24 int lineno; /* Current spec line number. */ 25 26 static void set __P((char *, NODE *)); 27 static void unset __P((char *, NODE *)); 28 29 NODE * 30 spec() 31 { 32 register NODE *centry, *last; 33 register char *p; 34 NODE ginfo, *root; 35 int c_cur, c_next; 36 char buf[2048]; 37 38 root = NULL; 39 bzero(&ginfo, sizeof(ginfo)); 40 c_cur = c_next = 0; 41 for (lineno = 1; fgets(buf, sizeof(buf), stdin); 42 ++lineno, c_cur = c_next, c_next = 0) { 43 /* Skip empty lines. */ 44 if (buf[0] == '\n') 45 continue; 46 47 /* Find end of line. */ 48 if ((p = index(buf, '\n')) == NULL) 49 err("line %d too long", lineno); 50 51 /* See if next line is continuation line. */ 52 if (p[-1] == '\\') { 53 --p; 54 c_next = 1; 55 } 56 57 /* Null-terminate the line. */ 58 *p = '\0'; 59 60 /* Skip leading whitespace. */ 61 for (p = buf; *p && isspace(*p); ++p); 62 63 /* If nothing but whitespace or comment char, continue. */ 64 if (!*p || *p == '#') 65 continue; 66 67 #ifdef DEBUG 68 (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 69 #endif 70 if (c_cur) { 71 set(p, centry); 72 continue; 73 } 74 75 /* Grab file name, "$", "set", or "unset". */ 76 if ((p = strtok(p, "\n\t ")) == NULL) 77 err("missing field"); 78 79 if (p[0] == '/') 80 switch(p[1]) { 81 case 's': 82 if (strcmp(p + 1, "set")) 83 break; 84 set(NULL, &ginfo); 85 continue; 86 case 'u': 87 if (strcmp(p + 1, "unset")) 88 break; 89 unset(NULL, &ginfo); 90 continue; 91 } 92 93 if (index(p, '/')) 94 err("slash character in file name"); 95 96 if (!strcmp(p, "..")) { 97 /* Don't go up, if haven't gone down. */ 98 if (!root) 99 goto noparent; 100 if (last->type != F_DIR || last->flags & F_DONE) { 101 if (last == root) 102 goto noparent; 103 last = last->parent; 104 } 105 last->flags |= F_DONE; 106 continue; 107 108 noparent: err("no parent node"); 109 } 110 111 if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 112 err("%s", strerror(errno)); 113 *centry = ginfo; 114 (void)strcpy(centry->name, p); 115 #define MAGIC "?*[" 116 if (strpbrk(p, MAGIC)) 117 centry->flags |= F_MAGIC; 118 set(NULL, centry); 119 120 if (!root) { 121 last = root = centry; 122 root->parent = root; 123 } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 124 centry->parent = last; 125 last = last->child = centry; 126 } else { 127 centry->parent = last->parent; 128 centry->prev = last; 129 last = last->next = centry; 130 } 131 } 132 return (root); 133 } 134 135 static void 136 set(t, ip) 137 char *t; 138 register NODE *ip; 139 { 140 register int type; 141 register char *kw, *val; 142 struct group *gr; 143 struct passwd *pw; 144 mode_t *m; 145 char *ep; 146 147 for (; kw = strtok(t, "= \t\n"); t = NULL) { 148 ip->flags |= type = parsekey(kw); 149 if ((val = strtok(NULL, " \t\n")) == NULL) 150 err("missing value"); 151 switch(type) { 152 case F_CKSUM: 153 ip->cksum = strtoul(val, &ep, 10); 154 if (*ep) 155 err("invalid checksum %s", val); 156 break; 157 case F_GID: 158 ip->st_gid = strtoul(val, &ep, 10); 159 if (*ep) 160 err("invalid gid %s", val); 161 break; 162 case F_GNAME: 163 if ((gr = getgrnam(val)) == NULL) 164 err("unknown group %s", val); 165 ip->st_gid = gr->gr_gid; 166 break; 167 case F_IGN: 168 /* just set flag bit */ 169 break; 170 case F_MODE: 171 if ((m = setmode(val)) == NULL) 172 err("invalid file mode %s", val); 173 ip->st_mode = getmode(m, 0); 174 break; 175 case F_NLINK: 176 ip->st_nlink = strtoul(val, &ep, 10); 177 if (*ep) 178 err("invalid link count %s", val); 179 break; 180 case F_SIZE: 181 ip->st_size = strtoul(val, &ep, 10); 182 if (*ep) 183 err("invalid size %s", val); 184 break; 185 case F_SLINK: 186 if ((ip->slink = strdup(val)) == NULL) 187 err("%s", strerror(errno)); 188 break; 189 case F_TIME: 190 ip->st_mtime = strtoul(val, &ep, 10); 191 if (*ep) 192 err("invalid time %s", val); 193 break; 194 case F_TYPE: 195 switch(*val) { 196 case 'b': 197 if (!strcmp(val, "block")) 198 ip->type = F_BLOCK; 199 break; 200 case 'c': 201 if (!strcmp(val, "char")) 202 ip->type = F_CHAR; 203 break; 204 case 'd': 205 if (!strcmp(val, "dir")) 206 ip->type = F_DIR; 207 break; 208 case 'f': 209 if (!strcmp(val, "file")) 210 ip->type = F_FILE; 211 if (!strcmp(val, "fifo")) 212 ip->type = F_FIFO; 213 break; 214 case 'l': 215 if (!strcmp(val, "link")) 216 ip->type = F_LINK; 217 break; 218 case 's': 219 if (!strcmp(val, "socket")) 220 ip->type = F_SOCK; 221 break; 222 default: 223 err("unknown file type %s", val); 224 } 225 break; 226 case F_UID: 227 ip->st_uid = strtoul(val, &ep, 10); 228 if (*ep) 229 err("invalid uid %s", val); 230 break; 231 case F_UNAME: 232 if ((pw = getpwnam(val)) == NULL) 233 err("unknown user %s", val); 234 ip->st_uid = pw->pw_uid; 235 break; 236 } 237 } 238 } 239 240 static void 241 unset(t, ip) 242 char *t; 243 register NODE *ip; 244 { 245 register char *p; 246 247 while (p = strtok(t, "\n\t ")) 248 ip->flags &= ~parsekey(p); 249 } 250