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