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