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