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 static char sccsid[] = "@(#)spec.c 5.14 (Berkeley) 3/2/91"; 36 #endif /* not lint */ 37 38 #include <sys/types.h> 39 #include <pwd.h> 40 #include <grp.h> 41 #include <stdio.h> 42 #include <errno.h> 43 #include <ctype.h> 44 #include "mtree.h" 45 46 extern NODE *root; /* root of the tree */ 47 48 static int lineno; /* current spec line number */ 49 50 spec() 51 { 52 register NODE *centry, *last; 53 register char *p; 54 NODE ginfo, *emalloc(); 55 char buf[2048]; 56 57 bzero((void *)&ginfo, sizeof(ginfo)); 58 for (lineno = 1; fgets(buf, sizeof(buf), stdin); ++lineno) { 59 if (!(p = index(buf, '\n'))) { 60 (void)fprintf(stderr, 61 "mtree: line %d too long.\n", lineno); 62 exit(1); 63 } 64 *p = '\0'; 65 for (p = buf; *p && isspace(*p); ++p); 66 if (!*p || *p == '#') 67 continue; 68 69 /* grab file name, "$", "set", or "unset" */ 70 if (!(p = strtok(p, "\n\t "))) 71 specerr(); 72 73 if (p[0] == '/') 74 switch(p[1]) { 75 case 's': 76 if (strcmp(p + 1, "set")) 77 break; 78 set(&ginfo); 79 continue; 80 case 'u': 81 if (strcmp(p + 1, "unset")) 82 break; 83 unset(&ginfo); 84 continue; 85 } 86 87 if (index(p, '/')) { 88 (void)fprintf(stderr, 89 "mtree: file names may not contain slashes.\n"); 90 specerr(); 91 } 92 93 if (!strcmp(p, "..")) { 94 /* don't go up, if haven't gone down */ 95 if (!root) 96 noparent(); 97 if (last->type != F_DIR || last->flags & F_DONE) { 98 if (last == root) 99 noparent(); 100 last = last->parent; 101 } 102 last->flags |= F_DONE; 103 continue; 104 } 105 106 centry = emalloc(sizeof(NODE) + strlen(p)); 107 *centry = ginfo; 108 (void)strcpy(centry->name, p); 109 #define MAGIC "?*[" 110 if (strpbrk(p, MAGIC)) 111 centry->flags |= F_MAGIC; 112 set(centry); 113 114 if (!root) { 115 last = root = centry; 116 root->parent = root; 117 } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 118 centry->parent = last; 119 last = last->child = centry; 120 } else { 121 centry->parent = last->parent; 122 centry->prev = last; 123 last = last->next = centry; 124 } 125 } 126 } 127 128 set(ip) 129 register NODE *ip; 130 { 131 register int type; 132 register char *kw, *val; 133 gid_t getgroup(); 134 uid_t getowner(); 135 long atol(), strtol(); 136 137 while (kw = strtok((char *)NULL, "= \t\n")) { 138 ip->flags |= type = key(kw); 139 val = strtok((char *)NULL, " \t\n"); 140 if (!val) 141 specerr(); 142 switch(type) { 143 case F_CKSUM: 144 ip->cksum = atol(val); 145 break; 146 case F_GROUP: 147 ip->st_gid = getgroup(val); 148 break; 149 case F_IGN: 150 /* just set flag bit */ 151 break; 152 case F_MODE: { 153 mode_t *m, *setmode(); 154 155 if (!(m = setmode(val))) { 156 (void)fprintf(stderr, 157 "mtree: invalid file mode %s.\n", val); 158 specerr(); 159 } 160 ip->st_mode = getmode(m, 0); 161 break; 162 } 163 case F_NLINK: 164 ip->st_nlink = atoi(val); 165 break; 166 case F_OWNER: 167 ip->st_uid = getowner(val); 168 break; 169 case F_SIZE: 170 ip->st_size = atol(val); 171 break; 172 case F_SLINK: 173 if (!(ip->slink = strdup(val))) 174 nomem(); 175 break; 176 case F_TIME: 177 ip->st_mtime = atol(val); 178 break; 179 case F_TYPE: 180 switch(*val) { 181 case 'b': 182 if (!strcmp(val, "block")) 183 ip->type = F_BLOCK; 184 break; 185 case 'c': 186 if (!strcmp(val, "char")) 187 ip->type = F_CHAR; 188 break; 189 case 'd': 190 if (!strcmp(val, "dir")) 191 ip->type = F_DIR; 192 break; 193 case 'f': 194 if (!strcmp(val, "file")) 195 ip->type = F_FILE; 196 if (!strcmp(val, "fifo")) 197 ip->type = F_FIFO; 198 break; 199 case 'l': 200 if (!strcmp(val, "link")) 201 ip->type = F_LINK; 202 break; 203 case 's': 204 if (!strcmp(val, "socket")) 205 ip->type = F_SOCK; 206 break; 207 default: 208 (void)fprintf(stderr, 209 "mtree: unknown file type %s.\n", val); 210 specerr(); 211 } 212 break; 213 } 214 } 215 } 216 217 unset(ip) 218 register NODE *ip; 219 { 220 register char *p; 221 222 while (p = strtok((char *)NULL, "\n\t ")) 223 ip->flags &= ~key(p); 224 } 225 226 key(p) 227 char *p; 228 { 229 switch(*p) { 230 case 'c': 231 if (!strcmp(p, "cksum")) 232 return(F_CKSUM); 233 break; 234 case 'g': 235 if (!strcmp(p, "group")) 236 return(F_GROUP); 237 break; 238 case 'i': 239 if (!strcmp(p, "ignore")) 240 return(F_IGN); 241 break; 242 case 'l': 243 if (!strcmp(p, "link")) 244 return(F_SLINK); 245 break; 246 case 'm': 247 if (!strcmp(p, "mode")) 248 return(F_MODE); 249 break; 250 case 'n': 251 if (!strcmp(p, "nlink")) 252 return(F_NLINK); 253 break; 254 case 'o': 255 if (!strcmp(p, "owner")) 256 return(F_OWNER); 257 break; 258 case 's': 259 if (!strcmp(p, "size")) 260 return(F_SIZE); 261 break; 262 case 't': 263 if (!strcmp(p, "type")) 264 return(F_TYPE); 265 if (!strcmp(p, "time")) 266 return(F_TIME); 267 break; 268 } 269 (void)fprintf(stderr, "mtree: unknown keyword %s.\n", p); 270 specerr(); 271 /* NOTREACHED */ 272 } 273 274 275 uid_t 276 getowner(p) 277 register char *p; 278 { 279 struct passwd *pw; 280 int val; 281 282 if (isdigit(*p)) { 283 if ((val = atoi(p)) >= 0) 284 return((uid_t)val); 285 (void)fprintf(stderr, "mtree: illegal uid value %s.\n", p); 286 } else if (pw = getpwnam(p)) 287 return(pw->pw_uid); 288 else 289 (void)fprintf(stderr, "mtree: unknown user %s.\n", p); 290 specerr(); 291 /* NOTREACHED */ 292 } 293 294 gid_t 295 getgroup(p) 296 register char *p; 297 { 298 struct group *gr; 299 int val; 300 301 if (isdigit(*p)) { 302 if ((val = atoi(p)) >= 0) 303 return((gid_t)val); 304 (void)fprintf(stderr, "mtree: illegal gid value %s.\n", p); 305 } else if (gr = getgrnam(p)) 306 return(gr->gr_gid); 307 else 308 (void)fprintf(stderr, "mtree: unknown group %s.\n", p); 309 specerr(); 310 /* NOTREACHED */ 311 } 312 313 noparent() 314 { 315 (void)fprintf(stderr, "mtree: no parent node.\n"); 316 specerr(); 317 } 318 319 specerr() 320 { 321 (void)fprintf(stderr, 322 "mtree: line %d of the specification is incorrect.\n", lineno); 323 exit(1); 324 } 325 326 NODE * 327 emalloc(size) 328 int size; 329 { 330 void *p; 331 332 /* NOSTRICT */ 333 if (!(p = malloc((u_int)size))) 334 nomem(); 335 bzero(p, size); 336 return((NODE *)p); 337 } 338 339 nomem() 340 { 341 (void)fprintf(stderr, "mtree: %s.\n", strerror(ENOMEM)); 342 exit(1); 343 } 344