kernel - Revert part of the contig allocation work
[dragonfly.git] / usr.sbin / mtree / spec.c
blob40634c27f856858a1a9b349de7420df1ddd409f8
1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * @(#)spec.c 8.1 (Berkeley) 6/6/93
30 * $FreeBSD: src/usr.sbin/mtree/spec.c,v 1.13.2.1 2000/06/28 02:33:17 joe Exp $
31 * $DragonFly: src/usr.sbin/mtree/spec.c,v 1.6 2004/08/30 19:27:22 eirikn Exp $
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fts.h>
40 #include <grp.h>
41 #include <pwd.h>
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <vis.h>
45 #include "mtree.h"
46 #include "extern.h"
48 int lineno; /* Current spec line number. */
50 static void set(char *, NODE *);
51 static void unset(char *, NODE *);
53 NODE *
54 spec(void)
56 NODE *centry, *last;
57 char *p;
58 NODE ginfo, *root;
59 int c_cur, c_next;
60 char buf[2048];
62 centry = last = root = NULL;
63 bzero(&ginfo, sizeof(ginfo));
64 c_cur = c_next = 0;
65 for (lineno = 1; fgets(buf, sizeof(buf), stdin);
66 ++lineno, c_cur = c_next, c_next = 0) {
67 /* Skip empty lines. */
68 if (buf[0] == '\n')
69 continue;
71 /* Find end of line. */
72 if ((p = strchr(buf, '\n')) == NULL)
73 errx(1, "line %d too long", lineno);
75 /* See if next line is continuation line. */
76 if (p[-1] == '\\') {
77 --p;
78 c_next = 1;
81 /* Null-terminate the line. */
82 *p = '\0';
84 /* Skip leading whitespace. */
85 for (p = buf; *p && isspace(*p); ++p);
87 /* If nothing but whitespace or comment char, continue. */
88 if (!*p || *p == '#')
89 continue;
91 #ifdef DEBUG
92 fprintf(stderr, "line %d: {%s}\n", lineno, p);
93 #endif
94 if (c_cur) {
95 set(p, centry);
96 continue;
99 /* Grab file name, "$", "set", or "unset". */
100 if ((p = strtok(p, "\n\t ")) == NULL)
101 errx(1, "line %d: missing field", lineno);
103 if (p[0] == '/')
104 switch(p[1]) {
105 case 's':
106 if (strcmp(p + 1, "set"))
107 break;
108 set(NULL, &ginfo);
109 continue;
110 case 'u':
111 if (strcmp(p + 1, "unset"))
112 break;
113 unset(NULL, &ginfo);
114 continue;
117 if (strchr(p, '/'))
118 errx(1, "line %d: slash character in file name",
119 lineno);
121 if (!strcmp(p, "..")) {
122 /* Don't go up, if haven't gone down. */
123 if (!root)
124 goto noparent;
125 if (last->type != F_DIR || last->flags & F_DONE) {
126 if (last == root)
127 goto noparent;
128 last = last->parent;
130 last->flags |= F_DONE;
131 continue;
133 noparent: errx(1, "line %d: no parent node", lineno);
136 if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
137 errx(1, "calloc");
138 *centry = ginfo;
139 #define MAGIC "?*["
140 if (strpbrk(p, MAGIC))
141 centry->flags |= F_MAGIC;
142 if (strunvis(centry->name, p) == -1) {
143 warnx("filename %s is ill-encoded and literally used",
145 strcpy(centry->name, p);
147 set(NULL, centry);
149 if (!root) {
150 last = root = centry;
151 root->parent = root;
152 } else if (last->type == F_DIR && !(last->flags & F_DONE)) {
153 centry->parent = last;
154 last = last->child = centry;
155 } else {
156 centry->parent = last->parent;
157 centry->prev = last;
158 last = last->next = centry;
161 return (root);
164 static void
165 set(char *t, NODE *ip)
167 int type;
168 char *kw, *val = NULL;
169 struct group *gr;
170 struct passwd *pw;
171 mode_t *m;
172 int value;
173 char *ep;
175 for (; (kw = strtok(t, "= \t\n")); t = NULL) {
176 ip->flags |= type = parsekey(kw, &value);
177 if (value && (val = strtok(NULL, " \t\n")) == NULL)
178 errx(1, "line %d: missing value", lineno);
179 switch(type) {
180 case F_CKSUM:
181 ip->cksum = strtoul(val, &ep, 10);
182 if (*ep)
183 errx(1, "line %d: invalid checksum %s",
184 lineno, val);
185 break;
186 case F_MD5:
187 ip->md5digest = strdup(val);
188 if(!ip->md5digest) {
189 errx(1, "strdup");
191 break;
192 case F_SHA1:
193 ip->sha1digest = strdup(val);
194 if(!ip->sha1digest) {
195 errx(1, "strdup");
197 break;
198 case F_RMD160:
199 ip->rmd160digest = strdup(val);
200 if(!ip->rmd160digest) {
201 errx(1, "strdup");
203 break;
204 case F_FLAGS:
205 if (strcmp("none", val) == 0)
206 ip->st_flags = 0;
207 else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
208 errx(1, "line %d: invalid flag %s",lineno, val);
209 break;
210 case F_GID:
211 ip->st_gid = strtoul(val, &ep, 10);
212 if (*ep)
213 errx(1, "line %d: invalid gid %s", lineno, val);
214 break;
215 case F_GNAME:
216 if ((gr = getgrnam(val)) == NULL)
217 errx(1, "line %d: unknown group %s", lineno, val);
218 ip->st_gid = gr->gr_gid;
219 break;
220 case F_IGN:
221 /* just set flag bit */
222 break;
223 case F_MODE:
224 if ((m = setmode(val)) == NULL)
225 errx(1, "line %d: invalid file mode %s",
226 lineno, val);
227 ip->st_mode = getmode(m, 0);
228 free(m);
229 break;
230 case F_NLINK:
231 ip->st_nlink = strtoul(val, &ep, 10);
232 if (*ep)
233 errx(1, "line %d: invalid link count %s",
234 lineno, val);
235 break;
236 case F_SIZE:
237 ip->st_size = strtoq(val, &ep, 10);
238 if (*ep)
239 errx(1, "line %d: invalid size %s",
240 lineno, val);
241 break;
242 case F_SLINK:
243 if ((ip->slink = strdup(val)) == NULL)
244 errx(1, "strdup");
245 break;
246 case F_TIME:
247 ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
248 if (*ep != '.')
249 errx(1, "line %d: invalid time %s",
250 lineno, val);
251 val = ep + 1;
252 ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
253 if (*ep)
254 errx(1, "line %d: invalid time %s",
255 lineno, val);
256 break;
257 case F_TYPE:
258 switch(*val) {
259 case 'b':
260 if (!strcmp(val, "block"))
261 ip->type = F_BLOCK;
262 break;
263 case 'c':
264 if (!strcmp(val, "char"))
265 ip->type = F_CHAR;
266 break;
267 case 'd':
268 if (!strcmp(val, "dir"))
269 ip->type = F_DIR;
270 break;
271 case 'f':
272 if (!strcmp(val, "file"))
273 ip->type = F_FILE;
274 if (!strcmp(val, "fifo"))
275 ip->type = F_FIFO;
276 break;
277 case 'l':
278 if (!strcmp(val, "link"))
279 ip->type = F_LINK;
280 break;
281 case 's':
282 if (!strcmp(val, "socket"))
283 ip->type = F_SOCK;
284 break;
285 default:
286 errx(1, "line %d: unknown file type %s",
287 lineno, val);
289 break;
290 case F_UID:
291 ip->st_uid = strtoul(val, &ep, 10);
292 if (*ep)
293 errx(1, "line %d: invalid uid %s", lineno, val);
294 break;
295 case F_UNAME:
296 if ((pw = getpwnam(val)) == NULL)
297 errx(1, "line %d: unknown user %s", lineno, val);
298 ip->st_uid = pw->pw_uid;
299 break;
304 static void
305 unset(char *t, NODE *ip)
307 char *p;
309 while ((p = strtok(t, "\n\t ")))
310 ip->flags &= ~parsekey(p, NULL);