spec.c revision 1.1 1 1.1 cgd /*-
2 1.1 cgd * Copyright (c) 1989 The Regents of the University of California.
3 1.1 cgd * All rights reserved.
4 1.1 cgd *
5 1.1 cgd * Redistribution and use in source and binary forms, with or without
6 1.1 cgd * modification, are permitted provided that the following conditions
7 1.1 cgd * are met:
8 1.1 cgd * 1. Redistributions of source code must retain the above copyright
9 1.1 cgd * notice, this list of conditions and the following disclaimer.
10 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer in the
12 1.1 cgd * documentation and/or other materials provided with the distribution.
13 1.1 cgd * 3. All advertising materials mentioning features or use of this software
14 1.1 cgd * must display the following acknowledgement:
15 1.1 cgd * This product includes software developed by the University of
16 1.1 cgd * California, Berkeley and its contributors.
17 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
18 1.1 cgd * may be used to endorse or promote products derived from this software
19 1.1 cgd * without specific prior written permission.
20 1.1 cgd *
21 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 1.1 cgd * SUCH DAMAGE.
32 1.1 cgd */
33 1.1 cgd
34 1.1 cgd #ifndef lint
35 1.1 cgd static char sccsid[] = "@(#)spec.c 5.14 (Berkeley) 3/2/91";
36 1.1 cgd #endif /* not lint */
37 1.1 cgd
38 1.1 cgd #include <sys/types.h>
39 1.1 cgd #include <pwd.h>
40 1.1 cgd #include <grp.h>
41 1.1 cgd #include <stdio.h>
42 1.1 cgd #include <errno.h>
43 1.1 cgd #include <ctype.h>
44 1.1 cgd #include "mtree.h"
45 1.1 cgd
46 1.1 cgd extern NODE *root; /* root of the tree */
47 1.1 cgd
48 1.1 cgd static int lineno; /* current spec line number */
49 1.1 cgd
50 1.1 cgd spec()
51 1.1 cgd {
52 1.1 cgd register NODE *centry, *last;
53 1.1 cgd register char *p;
54 1.1 cgd NODE ginfo, *emalloc();
55 1.1 cgd char buf[2048];
56 1.1 cgd
57 1.1 cgd bzero((void *)&ginfo, sizeof(ginfo));
58 1.1 cgd for (lineno = 1; fgets(buf, sizeof(buf), stdin); ++lineno) {
59 1.1 cgd if (!(p = index(buf, '\n'))) {
60 1.1 cgd (void)fprintf(stderr,
61 1.1 cgd "mtree: line %d too long.\n", lineno);
62 1.1 cgd exit(1);
63 1.1 cgd }
64 1.1 cgd *p = '\0';
65 1.1 cgd for (p = buf; *p && isspace(*p); ++p);
66 1.1 cgd if (!*p || *p == '#')
67 1.1 cgd continue;
68 1.1 cgd
69 1.1 cgd /* grab file name, "$", "set", or "unset" */
70 1.1 cgd if (!(p = strtok(p, "\n\t ")))
71 1.1 cgd specerr();
72 1.1 cgd
73 1.1 cgd if (p[0] == '/')
74 1.1 cgd switch(p[1]) {
75 1.1 cgd case 's':
76 1.1 cgd if (strcmp(p + 1, "set"))
77 1.1 cgd break;
78 1.1 cgd set(&ginfo);
79 1.1 cgd continue;
80 1.1 cgd case 'u':
81 1.1 cgd if (strcmp(p + 1, "unset"))
82 1.1 cgd break;
83 1.1 cgd unset(&ginfo);
84 1.1 cgd continue;
85 1.1 cgd }
86 1.1 cgd
87 1.1 cgd if (index(p, '/')) {
88 1.1 cgd (void)fprintf(stderr,
89 1.1 cgd "mtree: file names may not contain slashes.\n");
90 1.1 cgd specerr();
91 1.1 cgd }
92 1.1 cgd
93 1.1 cgd if (!strcmp(p, "..")) {
94 1.1 cgd /* don't go up, if haven't gone down */
95 1.1 cgd if (!root)
96 1.1 cgd noparent();
97 1.1 cgd if (last->type != F_DIR || last->flags & F_DONE) {
98 1.1 cgd if (last == root)
99 1.1 cgd noparent();
100 1.1 cgd last = last->parent;
101 1.1 cgd }
102 1.1 cgd last->flags |= F_DONE;
103 1.1 cgd continue;
104 1.1 cgd }
105 1.1 cgd
106 1.1 cgd centry = emalloc(sizeof(NODE) + strlen(p));
107 1.1 cgd *centry = ginfo;
108 1.1 cgd (void)strcpy(centry->name, p);
109 1.1 cgd #define MAGIC "?*["
110 1.1 cgd if (strpbrk(p, MAGIC))
111 1.1 cgd centry->flags |= F_MAGIC;
112 1.1 cgd set(centry);
113 1.1 cgd
114 1.1 cgd if (!root) {
115 1.1 cgd last = root = centry;
116 1.1 cgd root->parent = root;
117 1.1 cgd } else if (last->type == F_DIR && !(last->flags & F_DONE)) {
118 1.1 cgd centry->parent = last;
119 1.1 cgd last = last->child = centry;
120 1.1 cgd } else {
121 1.1 cgd centry->parent = last->parent;
122 1.1 cgd centry->prev = last;
123 1.1 cgd last = last->next = centry;
124 1.1 cgd }
125 1.1 cgd }
126 1.1 cgd }
127 1.1 cgd
128 1.1 cgd set(ip)
129 1.1 cgd register NODE *ip;
130 1.1 cgd {
131 1.1 cgd register int type;
132 1.1 cgd register char *kw, *val;
133 1.1 cgd gid_t getgroup();
134 1.1 cgd uid_t getowner();
135 1.1 cgd long atol(), strtol();
136 1.1 cgd
137 1.1 cgd while (kw = strtok((char *)NULL, "= \t\n")) {
138 1.1 cgd ip->flags |= type = key(kw);
139 1.1 cgd val = strtok((char *)NULL, " \t\n");
140 1.1 cgd if (!val)
141 1.1 cgd specerr();
142 1.1 cgd switch(type) {
143 1.1 cgd case F_CKSUM:
144 1.1 cgd ip->cksum = atol(val);
145 1.1 cgd break;
146 1.1 cgd case F_GROUP:
147 1.1 cgd ip->st_gid = getgroup(val);
148 1.1 cgd break;
149 1.1 cgd case F_IGN:
150 1.1 cgd /* just set flag bit */
151 1.1 cgd break;
152 1.1 cgd case F_MODE: {
153 1.1 cgd mode_t *m, *setmode();
154 1.1 cgd
155 1.1 cgd if (!(m = setmode(val))) {
156 1.1 cgd (void)fprintf(stderr,
157 1.1 cgd "mtree: invalid file mode %s.\n", val);
158 1.1 cgd specerr();
159 1.1 cgd }
160 1.1 cgd ip->st_mode = getmode(m, 0);
161 1.1 cgd break;
162 1.1 cgd }
163 1.1 cgd case F_NLINK:
164 1.1 cgd ip->st_nlink = atoi(val);
165 1.1 cgd break;
166 1.1 cgd case F_OWNER:
167 1.1 cgd ip->st_uid = getowner(val);
168 1.1 cgd break;
169 1.1 cgd case F_SIZE:
170 1.1 cgd ip->st_size = atol(val);
171 1.1 cgd break;
172 1.1 cgd case F_SLINK:
173 1.1 cgd if (!(ip->slink = strdup(val)))
174 1.1 cgd nomem();
175 1.1 cgd break;
176 1.1 cgd case F_TIME:
177 1.1 cgd ip->st_mtime = atol(val);
178 1.1 cgd break;
179 1.1 cgd case F_TYPE:
180 1.1 cgd switch(*val) {
181 1.1 cgd case 'b':
182 1.1 cgd if (!strcmp(val, "block"))
183 1.1 cgd ip->type = F_BLOCK;
184 1.1 cgd break;
185 1.1 cgd case 'c':
186 1.1 cgd if (!strcmp(val, "char"))
187 1.1 cgd ip->type = F_CHAR;
188 1.1 cgd break;
189 1.1 cgd case 'd':
190 1.1 cgd if (!strcmp(val, "dir"))
191 1.1 cgd ip->type = F_DIR;
192 1.1 cgd break;
193 1.1 cgd case 'f':
194 1.1 cgd if (!strcmp(val, "file"))
195 1.1 cgd ip->type = F_FILE;
196 1.1 cgd if (!strcmp(val, "fifo"))
197 1.1 cgd ip->type = F_FIFO;
198 1.1 cgd break;
199 1.1 cgd case 'l':
200 1.1 cgd if (!strcmp(val, "link"))
201 1.1 cgd ip->type = F_LINK;
202 1.1 cgd break;
203 1.1 cgd case 's':
204 1.1 cgd if (!strcmp(val, "socket"))
205 1.1 cgd ip->type = F_SOCK;
206 1.1 cgd break;
207 1.1 cgd default:
208 1.1 cgd (void)fprintf(stderr,
209 1.1 cgd "mtree: unknown file type %s.\n", val);
210 1.1 cgd specerr();
211 1.1 cgd }
212 1.1 cgd break;
213 1.1 cgd }
214 1.1 cgd }
215 1.1 cgd }
216 1.1 cgd
217 1.1 cgd unset(ip)
218 1.1 cgd register NODE *ip;
219 1.1 cgd {
220 1.1 cgd register char *p;
221 1.1 cgd
222 1.1 cgd while (p = strtok((char *)NULL, "\n\t "))
223 1.1 cgd ip->flags &= ~key(p);
224 1.1 cgd }
225 1.1 cgd
226 1.1 cgd key(p)
227 1.1 cgd char *p;
228 1.1 cgd {
229 1.1 cgd switch(*p) {
230 1.1 cgd case 'c':
231 1.1 cgd if (!strcmp(p, "cksum"))
232 1.1 cgd return(F_CKSUM);
233 1.1 cgd break;
234 1.1 cgd case 'g':
235 1.1 cgd if (!strcmp(p, "group"))
236 1.1 cgd return(F_GROUP);
237 1.1 cgd break;
238 1.1 cgd case 'i':
239 1.1 cgd if (!strcmp(p, "ignore"))
240 1.1 cgd return(F_IGN);
241 1.1 cgd break;
242 1.1 cgd case 'l':
243 1.1 cgd if (!strcmp(p, "link"))
244 1.1 cgd return(F_SLINK);
245 1.1 cgd break;
246 1.1 cgd case 'm':
247 1.1 cgd if (!strcmp(p, "mode"))
248 1.1 cgd return(F_MODE);
249 1.1 cgd break;
250 1.1 cgd case 'n':
251 1.1 cgd if (!strcmp(p, "nlink"))
252 1.1 cgd return(F_NLINK);
253 1.1 cgd break;
254 1.1 cgd case 'o':
255 1.1 cgd if (!strcmp(p, "owner"))
256 1.1 cgd return(F_OWNER);
257 1.1 cgd break;
258 1.1 cgd case 's':
259 1.1 cgd if (!strcmp(p, "size"))
260 1.1 cgd return(F_SIZE);
261 1.1 cgd break;
262 1.1 cgd case 't':
263 1.1 cgd if (!strcmp(p, "type"))
264 1.1 cgd return(F_TYPE);
265 1.1 cgd if (!strcmp(p, "time"))
266 1.1 cgd return(F_TIME);
267 1.1 cgd break;
268 1.1 cgd }
269 1.1 cgd (void)fprintf(stderr, "mtree: unknown keyword %s.\n", p);
270 1.1 cgd specerr();
271 1.1 cgd /* NOTREACHED */
272 1.1 cgd }
273 1.1 cgd
274 1.1 cgd
275 1.1 cgd uid_t
276 1.1 cgd getowner(p)
277 1.1 cgd register char *p;
278 1.1 cgd {
279 1.1 cgd struct passwd *pw;
280 1.1 cgd int val;
281 1.1 cgd
282 1.1 cgd if (isdigit(*p)) {
283 1.1 cgd if ((val = atoi(p)) >= 0)
284 1.1 cgd return((uid_t)val);
285 1.1 cgd (void)fprintf(stderr, "mtree: illegal uid value %s.\n", p);
286 1.1 cgd } else if (pw = getpwnam(p))
287 1.1 cgd return(pw->pw_uid);
288 1.1 cgd else
289 1.1 cgd (void)fprintf(stderr, "mtree: unknown user %s.\n", p);
290 1.1 cgd specerr();
291 1.1 cgd /* NOTREACHED */
292 1.1 cgd }
293 1.1 cgd
294 1.1 cgd gid_t
295 1.1 cgd getgroup(p)
296 1.1 cgd register char *p;
297 1.1 cgd {
298 1.1 cgd struct group *gr;
299 1.1 cgd int val;
300 1.1 cgd
301 1.1 cgd if (isdigit(*p)) {
302 1.1 cgd if ((val = atoi(p)) >= 0)
303 1.1 cgd return((gid_t)val);
304 1.1 cgd (void)fprintf(stderr, "mtree: illegal gid value %s.\n", p);
305 1.1 cgd } else if (gr = getgrnam(p))
306 1.1 cgd return(gr->gr_gid);
307 1.1 cgd else
308 1.1 cgd (void)fprintf(stderr, "mtree: unknown group %s.\n", p);
309 1.1 cgd specerr();
310 1.1 cgd /* NOTREACHED */
311 1.1 cgd }
312 1.1 cgd
313 1.1 cgd noparent()
314 1.1 cgd {
315 1.1 cgd (void)fprintf(stderr, "mtree: no parent node.\n");
316 1.1 cgd specerr();
317 1.1 cgd }
318 1.1 cgd
319 1.1 cgd specerr()
320 1.1 cgd {
321 1.1 cgd (void)fprintf(stderr,
322 1.1 cgd "mtree: line %d of the specification is incorrect.\n", lineno);
323 1.1 cgd exit(1);
324 1.1 cgd }
325 1.1 cgd
326 1.1 cgd NODE *
327 1.1 cgd emalloc(size)
328 1.1 cgd int size;
329 1.1 cgd {
330 1.1 cgd void *p;
331 1.1 cgd
332 1.1 cgd /* NOSTRICT */
333 1.1 cgd if (!(p = malloc((u_int)size)))
334 1.1 cgd nomem();
335 1.1 cgd bzero(p, size);
336 1.1 cgd return((NODE *)p);
337 1.1 cgd }
338 1.1 cgd
339 1.1 cgd nomem()
340 1.1 cgd {
341 1.1 cgd (void)fprintf(stderr, "mtree: %s.\n", strerror(ENOMEM));
342 1.1 cgd exit(1);
343 1.1 cgd }
344