spec.c revision 1.1 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