Commit | Line | Data |
---|---|---|
cbe4b98c | 1 | /*- |
87b199a9 KB |
2 | * Copyright (c) 1989 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
cbe4b98c | 5 | * %sccs.include.redist.c% |
87b199a9 KB |
6 | */ |
7 | ||
8 | #ifndef lint | |
c2bd878c | 9 | static char sccsid[] = "@(#)spec.c 5.18 (Berkeley) %G%"; |
87b199a9 KB |
10 | #endif /* not lint */ |
11 | ||
12 | #include <sys/types.h> | |
275bb093 KB |
13 | #include <sys/stat.h> |
14 | #include <fts.h> | |
cbe4b98c KB |
15 | #include <pwd.h> |
16 | #include <grp.h> | |
f06151dd | 17 | #include <errno.h> |
275bb093 KB |
18 | #include <unistd.h> |
19 | #include <stdio.h> | |
f06151dd | 20 | #include <ctype.h> |
87b199a9 | 21 | #include "mtree.h" |
275bb093 | 22 | #include "extern.h" |
87b199a9 | 23 | |
275bb093 | 24 | int lineno; /* Current spec line number. */ |
87b199a9 | 25 | |
275bb093 KB |
26 | static void set __P((char *, NODE *)); |
27 | static void unset __P((char *, NODE *)); | |
cbe4b98c | 28 | |
275bb093 | 29 | NODE * |
87b199a9 KB |
30 | spec() |
31 | { | |
6e4c29b1 | 32 | register NODE *centry, *last; |
87b199a9 | 33 | register char *p; |
275bb093 KB |
34 | NODE ginfo, *root; |
35 | int c_cur, c_next; | |
f06151dd | 36 | char buf[2048]; |
87b199a9 | 37 | |
ad357b7a | 38 | root = NULL; |
275bb093 KB |
39 | bzero(&ginfo, sizeof(ginfo)); |
40 | c_cur = c_next = 0; | |
41 | for (lineno = 1; fgets(buf, sizeof(buf), stdin); | |
42 | ++lineno, c_cur = c_next, c_next = 0) { | |
43 | /* Skip empty lines. */ | |
44 | if (buf[0] == '\n') | |
45 | continue; | |
46 | ||
47 | /* Find end of line. */ | |
48 | if ((p = index(buf, '\n')) == NULL) | |
49 | err("line %d too long", lineno); | |
50 | ||
51 | /* See if next line is continuation line. */ | |
52 | if (p[-1] == '\\') { | |
53 | --p; | |
54 | c_next = 1; | |
87b199a9 | 55 | } |
275bb093 KB |
56 | |
57 | /* Null-terminate the line. */ | |
87b199a9 | 58 | *p = '\0'; |
275bb093 KB |
59 | |
60 | /* Skip leading whitespace. */ | |
87b199a9 | 61 | for (p = buf; *p && isspace(*p); ++p); |
275bb093 KB |
62 | |
63 | /* If nothing but whitespace or comment char, continue. */ | |
87b199a9 KB |
64 | if (!*p || *p == '#') |
65 | continue; | |
66 | ||
ad357b7a KB |
67 | #ifdef DEBUG |
68 | (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); | |
69 | #endif | |
275bb093 KB |
70 | if (c_cur) { |
71 | set(p, centry); | |
72 | continue; | |
73 | } | |
74 | ||
75 | /* Grab file name, "$", "set", or "unset". */ | |
76 | if ((p = strtok(p, "\n\t ")) == NULL) | |
77 | err("missing field"); | |
87b199a9 | 78 | |
87b199a9 KB |
79 | if (p[0] == '/') |
80 | switch(p[1]) { | |
87b199a9 KB |
81 | case 's': |
82 | if (strcmp(p + 1, "set")) | |
83 | break; | |
275bb093 | 84 | set(NULL, &ginfo); |
87b199a9 KB |
85 | continue; |
86 | case 'u': | |
4c7f2dd1 | 87 | if (strcmp(p + 1, "unset")) |
87b199a9 | 88 | break; |
275bb093 | 89 | unset(NULL, &ginfo); |
87b199a9 KB |
90 | continue; |
91 | } | |
92 | ||
275bb093 KB |
93 | if (index(p, '/')) |
94 | err("slash character in file name"); | |
87b199a9 | 95 | |
87b199a9 | 96 | if (!strcmp(p, "..")) { |
275bb093 | 97 | /* Don't go up, if haven't gone down. */ |
03f682fb | 98 | if (!root) |
275bb093 | 99 | goto noparent; |
6e4c29b1 | 100 | if (last->type != F_DIR || last->flags & F_DONE) { |
03f682fb | 101 | if (last == root) |
275bb093 | 102 | goto noparent; |
03f682fb | 103 | last = last->parent; |
87b199a9 | 104 | } |
03f682fb KB |
105 | last->flags |= F_DONE; |
106 | continue; | |
275bb093 KB |
107 | |
108 | noparent: err("no parent node"); | |
87b199a9 KB |
109 | } |
110 | ||
275bb093 KB |
111 | if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) |
112 | err("%s", strerror(errno)); | |
6e4c29b1 | 113 | *centry = ginfo; |
7e5e86d9 KB |
114 | (void)strcpy(centry->name, p); |
115 | #define MAGIC "?*[" | |
116 | if (strpbrk(p, MAGIC)) | |
117 | centry->flags |= F_MAGIC; | |
275bb093 | 118 | set(NULL, centry); |
87b199a9 KB |
119 | |
120 | if (!root) { | |
121 | last = root = centry; | |
122 | root->parent = root; | |
6e4c29b1 | 123 | } else if (last->type == F_DIR && !(last->flags & F_DONE)) { |
87b199a9 KB |
124 | centry->parent = last; |
125 | last = last->child = centry; | |
126 | } else { | |
127 | centry->parent = last->parent; | |
f06151dd | 128 | centry->prev = last; |
87b199a9 KB |
129 | last = last->next = centry; |
130 | } | |
131 | } | |
275bb093 | 132 | return (root); |
87b199a9 | 133 | } |
03f682fb | 134 | |
275bb093 KB |
135 | static void |
136 | set(t, ip) | |
137 | char *t; | |
6e4c29b1 | 138 | register NODE *ip; |
cbe4b98c | 139 | { |
6e4c29b1 KB |
140 | register int type; |
141 | register char *kw, *val; | |
275bb093 KB |
142 | struct group *gr; |
143 | struct passwd *pw; | |
144 | mode_t *m; | |
4e63770a | 145 | int value; |
275bb093 | 146 | char *ep; |
cbe4b98c | 147 | |
275bb093 | 148 | for (; kw = strtok(t, "= \t\n"); t = NULL) { |
4e63770a KB |
149 | ip->flags |= type = parsekey(kw, &value); |
150 | if (value && (val = strtok(NULL, " \t\n")) == NULL) | |
275bb093 | 151 | err("missing value"); |
f06151dd KB |
152 | switch(type) { |
153 | case F_CKSUM: | |
275bb093 KB |
154 | ip->cksum = strtoul(val, &ep, 10); |
155 | if (*ep) | |
156 | err("invalid checksum %s", val); | |
157 | break; | |
158 | case F_GID: | |
159 | ip->st_gid = strtoul(val, &ep, 10); | |
160 | if (*ep) | |
161 | err("invalid gid %s", val); | |
f06151dd | 162 | break; |
275bb093 KB |
163 | case F_GNAME: |
164 | if ((gr = getgrnam(val)) == NULL) | |
165 | err("unknown group %s", val); | |
166 | ip->st_gid = gr->gr_gid; | |
f06151dd KB |
167 | break; |
168 | case F_IGN: | |
169 | /* just set flag bit */ | |
170 | break; | |
275bb093 KB |
171 | case F_MODE: |
172 | if ((m = setmode(val)) == NULL) | |
173 | err("invalid file mode %s", val); | |
1978bf80 | 174 | ip->st_mode = getmode(m, 0); |
f06151dd KB |
175 | break; |
176 | case F_NLINK: | |
275bb093 KB |
177 | ip->st_nlink = strtoul(val, &ep, 10); |
178 | if (*ep) | |
179 | err("invalid link count %s", val); | |
f06151dd KB |
180 | break; |
181 | case F_SIZE: | |
275bb093 KB |
182 | ip->st_size = strtoul(val, &ep, 10); |
183 | if (*ep) | |
184 | err("invalid size %s", val); | |
f06151dd KB |
185 | break; |
186 | case F_SLINK: | |
275bb093 KB |
187 | if ((ip->slink = strdup(val)) == NULL) |
188 | err("%s", strerror(errno)); | |
f06151dd | 189 | break; |
0af6fb71 | 190 | case F_TIME: |
c2bd878c KB |
191 | ip->st_mtimespec.ts_sec = strtoul(val, &ep, 10); |
192 | if (*ep != '.') | |
193 | err("invalid time %s", val); | |
194 | val = ep + 1; | |
195 | ip->st_mtimespec.ts_nsec = strtoul(val, &ep, 10); | |
275bb093 KB |
196 | if (*ep) |
197 | err("invalid time %s", val); | |
0af6fb71 | 198 | break; |
f06151dd KB |
199 | case F_TYPE: |
200 | switch(*val) { | |
201 | case 'b': | |
202 | if (!strcmp(val, "block")) | |
203 | ip->type = F_BLOCK; | |
204 | break; | |
205 | case 'c': | |
206 | if (!strcmp(val, "char")) | |
207 | ip->type = F_CHAR; | |
208 | break; | |
209 | case 'd': | |
210 | if (!strcmp(val, "dir")) | |
211 | ip->type = F_DIR; | |
212 | break; | |
213 | case 'f': | |
214 | if (!strcmp(val, "file")) | |
215 | ip->type = F_FILE; | |
c85e0d87 KB |
216 | if (!strcmp(val, "fifo")) |
217 | ip->type = F_FIFO; | |
f06151dd KB |
218 | break; |
219 | case 'l': | |
220 | if (!strcmp(val, "link")) | |
221 | ip->type = F_LINK; | |
222 | break; | |
223 | case 's': | |
224 | if (!strcmp(val, "socket")) | |
225 | ip->type = F_SOCK; | |
226 | break; | |
227 | default: | |
275bb093 | 228 | err("unknown file type %s", val); |
f06151dd KB |
229 | } |
230 | break; | |
275bb093 KB |
231 | case F_UID: |
232 | ip->st_uid = strtoul(val, &ep, 10); | |
233 | if (*ep) | |
234 | err("invalid uid %s", val); | |
235 | break; | |
236 | case F_UNAME: | |
237 | if ((pw = getpwnam(val)) == NULL) | |
238 | err("unknown user %s", val); | |
239 | ip->st_uid = pw->pw_uid; | |
240 | break; | |
cbe4b98c | 241 | } |
cbe4b98c KB |
242 | } |
243 | } | |
244 | ||
275bb093 KB |
245 | static void |
246 | unset(t, ip) | |
247 | char *t; | |
6e4c29b1 | 248 | register NODE *ip; |
cbe4b98c | 249 | { |
f06151dd KB |
250 | register char *p; |
251 | ||
275bb093 | 252 | while (p = strtok(t, "\n\t ")) |
4e63770a | 253 | ip->flags &= ~parsekey(p, NULL); |
f06151dd | 254 | } |