files.c revision 1.1 1 /* $NetBSD: files.c,v 1.1 2005/06/05 18:19:53 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: @(#)files.c 8.1 (Berkeley) 6/6/93
41 */
42
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
46
47 #include <sys/param.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include "defs.h"
53
54 extern const char *yyfile;
55
56 /*
57 * We check that each full path name is unique. File base names
58 * should generally also be unique, e.g., having both a net/xx.c and
59 * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
60 * wrong, but is permitted under some conditions.
61 */
62 static struct hashtab *basetab; /* file base names */
63 static struct hashtab *pathtab; /* full path names */
64
65 static struct files **unchecked;
66
67 static int checkaux(const char *, void *);
68 static int fixcount(const char *, void *);
69 static int fixfsel(const char *, void *);
70 static int fixsel(const char *, void *);
71 static int expr_eval(struct nvlist *,
72 int (*)(const char *, void *), void *);
73 static void expr_free(struct nvlist *);
74
75 void
76 initfiles(void)
77 {
78
79 basetab = ht_new();
80 pathtab = ht_new();
81 TAILQ_INIT(&allfiles);
82 unchecked = &TAILQ_FIRST(&allfiles);
83 TAILQ_INIT(&allobjects);
84 }
85
86 void
87 addfile(const char *path, struct nvlist *optx, int flags, const char *rule)
88 {
89 struct files *fi;
90 const char *dotp, *tail;
91 size_t baselen;
92 int needc, needf;
93 char base[200];
94
95 /* check various errors */
96 needc = flags & FI_NEEDSCOUNT;
97 needf = flags & FI_NEEDSFLAG;
98 if (needc && needf) {
99 error("cannot mix needs-count and needs-flag");
100 goto bad;
101 }
102 if (optx == NULL && (needc || needf)) {
103 error("nothing to %s for %s", needc ? "count" : "flag", path);
104 goto bad;
105 }
106
107 /* find last part of pathname, and same without trailing suffix */
108 tail = strrchr(path, '/');
109 if (tail == NULL)
110 tail = path;
111 else
112 tail++;
113 dotp = strrchr(tail, '.');
114 if (dotp == NULL || dotp[1] == 0 ||
115 (baselen = dotp - tail) >= sizeof(base)) {
116 error("invalid pathname `%s'", path);
117 goto bad;
118 }
119
120 /*
121 * Commit this file to memory. We will decide later whether it
122 * will be used after all.
123 */
124 fi = ecalloc(1, sizeof *fi);
125 if (ht_insert(pathtab, path, fi)) {
126 free(fi);
127 if ((fi = ht_lookup(pathtab, path)) == NULL)
128 panic("addfile: ht_lookup(%s)", path);
129
130 /*
131 * If it's a duplicate entry, it is must specify a make
132 * rule, and only a make rule, and must come from
133 * a different source file than the original entry.
134 * If it does otherwise, it is disallowed. This allows
135 * machine-dependent files to override the compilation
136 * options for specific files.
137 */
138 if (rule != NULL && optx == NULL && flags == 0 &&
139 yyfile != fi->fi_srcfile) {
140 fi->fi_mkrule = rule;
141 return;
142 }
143 error("duplicate file %s", path);
144 xerror(fi->fi_srcfile, fi->fi_srcline,
145 "here is the original definition");
146 goto bad;
147 }
148 memcpy(base, tail, baselen);
149 base[baselen] = 0;
150 fi->fi_srcfile = yyfile;
151 fi->fi_srcline = currentline();
152 fi->fi_flags = flags;
153 fi->fi_path = path;
154 fi->fi_tail = tail;
155 fi->fi_base = intern(base);
156 fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
157 SLIST_FIRST(&prefixes)->pf_prefix;
158 fi->fi_optx = optx;
159 fi->fi_optf = NULL;
160 fi->fi_mkrule = rule;
161 TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
162 return;
163 bad:
164 expr_free(optx);
165 }
166
167 void
168 addobject(const char *path, struct nvlist *optx, int flags)
169 {
170 struct objects *oi;
171
172 /*
173 * Commit this object to memory. We will decide later whether it
174 * will be used after all.
175 */
176 oi = ecalloc(1, sizeof *oi);
177 if (ht_insert(pathtab, path, oi)) {
178 free(oi);
179 if ((oi = ht_lookup(pathtab, path)) == NULL)
180 panic("addfile: ht_lookup(%s)", path);
181 error("duplicate file %s", path);
182 xerror(oi->oi_srcfile, oi->oi_srcline,
183 "here is the original definition");
184 }
185 oi->oi_srcfile = yyfile;
186 oi->oi_srcline = currentline();
187 oi->oi_flags = flags;
188 oi->oi_path = path;
189 oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
190 SLIST_FIRST(&prefixes)->pf_prefix;
191 oi->oi_optx = optx;
192 oi->oi_optf = NULL;
193 TAILQ_INSERT_TAIL(&allobjects, oi, oi_next);
194 return;
195 }
196
197 /*
198 * We have finished reading some "files" file, either ../../conf/files
199 * or ./files.$machine. Make sure that everything that is flagged as
200 * needing a count is reasonable. (This prevents ../../conf/files from
201 * depending on some machine-specific device.)
202 */
203 void
204 checkfiles(void)
205 {
206 struct files *fi, *last;
207
208 last = NULL;
209 for (fi = *unchecked; fi != NULL;
210 last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
211 if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
212 (void)expr_eval(fi->fi_optx, checkaux, fi);
213 }
214 if (last != NULL)
215 unchecked = &TAILQ_NEXT(last, fi_next);
216 }
217
218 /*
219 * Auxiliary function for checkfiles, called from expr_eval.
220 * We are not actually interested in the expression's value.
221 */
222 static int
223 checkaux(const char *name, void *context)
224 {
225 struct files *fi = context;
226
227 if (ht_lookup(devbasetab, name) == NULL) {
228 xerror(fi->fi_srcfile, fi->fi_srcline,
229 "`%s' is not a countable device",
230 name);
231 /* keep fixfiles() from complaining again */
232 fi->fi_flags |= FI_HIDDEN;
233 }
234 return (0);
235 }
236
237 /*
238 * We have finished reading everything. Tack the files down: calculate
239 * selection and counts as needed. Check that the object files built
240 * from the selected sources do not collide.
241 */
242 int
243 fixfiles(void)
244 {
245 struct files *fi, *ofi;
246 struct nvlist *flathead, **flatp;
247 int err, sel;
248
249 err = 0;
250 TAILQ_FOREACH(fi, &allfiles, fi_next) {
251 /* Skip files that generated counted-device complaints. */
252 if (fi->fi_flags & FI_HIDDEN)
253 continue;
254
255 /* Optional: see if it is to be included. */
256 if (fi->fi_optx != NULL) {
257 flathead = NULL;
258 flatp = &flathead;
259 sel = expr_eval(fi->fi_optx,
260 fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
261 fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
262 fixsel,
263 &flatp);
264 fi->fi_optf = flathead;
265 if (!sel)
266 continue;
267 }
268
269 /* We like this file. Make sure it generates a unique .o. */
270 if (ht_insert(basetab, fi->fi_base, fi)) {
271 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
272 panic("fixfiles ht_lookup(%s)", fi->fi_base);
273 /*
274 * If the new file comes from a different source,
275 * allow the new one to override the old one.
276 */
277 if (fi->fi_path != ofi->fi_path) {
278 if (ht_replace(basetab, fi->fi_base, fi) != 1)
279 panic("fixfiles ht_replace(%s)",
280 fi->fi_base);
281 ofi->fi_flags &= ~FI_SEL;
282 ofi->fi_flags |= FI_HIDDEN;
283 } else {
284 xerror(fi->fi_srcfile, fi->fi_srcline,
285 "object file collision on %s.o, from %s",
286 fi->fi_base, fi->fi_path);
287 xerror(ofi->fi_srcfile, ofi->fi_srcline,
288 "here is the previous file: %s",
289 ofi->fi_path);
290 err = 1;
291 }
292 }
293 fi->fi_flags |= FI_SEL;
294 }
295 return (err);
296 }
297
298 /*
299 * We have finished reading everything. Tack the objects down: calculate
300 * selection.
301 */
302 int
303 fixobjects(void)
304 {
305 struct objects *oi;
306 struct nvlist *flathead, **flatp;
307 int err, sel;
308
309 err = 0;
310 TAILQ_FOREACH(oi, &allobjects, oi_next) {
311 /* Optional: see if it is to be included. */
312 if (oi->oi_optx != NULL) {
313 flathead = NULL;
314 flatp = &flathead;
315 sel = expr_eval(oi->oi_optx,
316 oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
317 fixsel,
318 &flatp);
319 oi->oi_optf = flathead;
320 if (!sel)
321 continue;
322 }
323
324 oi->oi_flags |= OI_SEL;
325 }
326 return (err);
327 }
328
329 /*
330 * We have finished reading everything. Tack the devsws down: calculate
331 * selection.
332 */
333 int
334 fixdevsw(void)
335 {
336 struct devm *dm, *res;
337 struct hashtab *fixdevmtab;
338 char mstr[16];
339
340 fixdevmtab = ht_new();
341
342 TAILQ_FOREACH(dm, &alldevms, dm_next) {
343 res = ht_lookup(fixdevmtab, intern(dm->dm_name));
344 if (res != NULL) {
345 if (res->dm_cmajor != dm->dm_cmajor ||
346 res->dm_bmajor != dm->dm_bmajor) {
347 xerror(res->dm_srcfile, res->dm_srcline,
348 "device-major '%s' is inconsistent: "
349 "block %d, char %d", res->dm_name,
350 res->dm_bmajor, res->dm_cmajor);
351 xerror(dm->dm_srcfile, dm->dm_srcline,
352 "device-major '%s' is inconsistent: "
353 "block %d, char %d", dm->dm_name,
354 dm->dm_bmajor, dm->dm_cmajor);
355 return (1);
356 } else {
357 xerror(dm->dm_srcfile, dm->dm_srcline,
358 "device-major '%s' is duplicated: "
359 "block %d, char %d",
360 dm->dm_name, dm->dm_bmajor,
361 dm->dm_cmajor);
362 return (1);
363 }
364 }
365 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
366 panic("fixdevsw: %s char %d block %d",
367 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
368 }
369
370 if (dm->dm_opts != NULL &&
371 !expr_eval(dm->dm_opts, fixsel, NULL))
372 continue;
373
374 if (dm->dm_cmajor != -1) {
375 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
376 xerror(dm->dm_srcfile, dm->dm_srcline,
377 "device-major of character device '%s' "
378 "is already defined", dm->dm_name);
379 return (1);
380 }
381 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
382 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
383 xerror(dm->dm_srcfile, dm->dm_srcline,
384 "device-major of character major '%d' "
385 "is already defined", dm->dm_cmajor);
386 return (1);
387 }
388 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
389 ht_insert(cdevmtab, intern(mstr), dm)) {
390 panic("fixdevsw: %s character major %d",
391 dm->dm_name, dm->dm_cmajor);
392 }
393 }
394 if (dm->dm_bmajor != -1) {
395 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
396 xerror(dm->dm_srcfile, dm->dm_srcline,
397 "device-major of block device '%s' "
398 "is already defined", dm->dm_name);
399 return (1);
400 }
401 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
402 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
403 xerror(dm->dm_srcfile, dm->dm_srcline,
404 "device-major of block major '%d' "
405 "is already defined", dm->dm_bmajor);
406 return (1);
407 }
408 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
409 ht_insert(bdevmtab, intern(mstr), dm)) {
410 panic("fixdevsw: %s block major %d",
411 dm->dm_name, dm->dm_bmajor);
412 }
413 }
414 }
415
416 return (0);
417 }
418
419 /*
420 * Called when evaluating a needs-count expression. Make sure the
421 * atom is a countable device. The expression succeeds iff there
422 * is at least one of them (note that while `xx*' will not always
423 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The
424 * mkheaders() routine wants a flattened, in-order list of the
425 * atoms for `#define name value' lines, so we build that as we
426 * are called to eval each atom.
427 */
428 static int
429 fixcount(const char *name, void *context)
430 {
431 struct nvlist ***p = context;
432 struct devbase *dev;
433 struct nvlist *nv;
434
435 dev = ht_lookup(devbasetab, name);
436 if (dev == NULL) /* cannot occur here; we checked earlier */
437 panic("fixcount(%s)", name);
438 nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
439 **p = nv;
440 *p = &nv->nv_next;
441 (void)ht_insert(needcnttab, name, nv);
442 return (dev->d_umax != 0);
443 }
444
445 /*
446 * Called from fixfiles when eval'ing a selection expression for a
447 * file that will generate a .h with flags. We will need the flat list.
448 */
449 static int
450 fixfsel(const char *name, void *context)
451 {
452 struct nvlist ***p = context;
453 struct nvlist *nv;
454 int sel;
455
456 sel = ht_lookup(selecttab, name) != NULL;
457 nv = newnv(name, NULL, NULL, sel, NULL);
458 **p = nv;
459 *p = &nv->nv_next;
460 return (sel);
461 }
462
463 /*
464 * As for fixfsel above, but we do not need the flat list.
465 */
466 static int
467 fixsel(const char *name, void *context)
468 {
469
470 return (ht_lookup(selecttab, name) != NULL);
471 }
472
473 /*
474 * Eval an expression tree. Calls the given function on each node,
475 * passing it the given context & the name; return value is &/|/! of
476 * results of evaluating atoms.
477 *
478 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise
479 * our mixing of C's bitwise & boolean here may give surprises).
480 */
481 static int
482 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
483 {
484 int lhs, rhs;
485
486 switch (expr->nv_int) {
487
488 case FX_ATOM:
489 return ((*fn)(expr->nv_name, context));
490
491 case FX_NOT:
492 return (!expr_eval(expr->nv_next, fn, context));
493
494 case FX_AND:
495 lhs = expr_eval(expr->nv_ptr, fn, context);
496 rhs = expr_eval(expr->nv_next, fn, context);
497 return (lhs & rhs);
498
499 case FX_OR:
500 lhs = expr_eval(expr->nv_ptr, fn, context);
501 rhs = expr_eval(expr->nv_next, fn, context);
502 return (lhs | rhs);
503 }
504 panic("expr_eval %d", expr->nv_int);
505 /* NOTREACHED */
506 return (0);
507 }
508
509 /*
510 * Free an expression tree.
511 */
512 static void
513 expr_free(struct nvlist *expr)
514 {
515 struct nvlist *rhs;
516
517 /* This loop traverses down the RHS of each subexpression. */
518 for (; expr != NULL; expr = rhs) {
519 switch (expr->nv_int) {
520
521 /* Atoms and !-exprs have no left hand side. */
522 case FX_ATOM:
523 case FX_NOT:
524 break;
525
526 /* For AND and OR nodes, free the LHS. */
527 case FX_AND:
528 case FX_OR:
529 expr_free(expr->nv_ptr);
530 break;
531
532 default:
533 panic("expr_free %d", expr->nv_int);
534 }
535 rhs = expr->nv_next;
536 nvfree(expr);
537 }
538 }
539
540 #ifdef DEBUG
541 /*
542 * Print expression tree.
543 */
544 void
545 prexpr(struct nvlist *expr)
546 {
547 static void pr0();
548
549 printf("expr =");
550 pr0(expr);
551 printf("\n");
552 (void)fflush(stdout);
553 }
554
555 static void
556 pr0(struct nvlist *e)
557 {
558
559 switch (e->nv_int) {
560 case FX_ATOM:
561 printf(" %s", e->nv_name);
562 return;
563 case FX_NOT:
564 printf(" (!");
565 break;
566 case FX_AND:
567 printf(" (&");
568 break;
569 case FX_OR:
570 printf(" (|");
571 break;
572 default:
573 printf(" (?%d?", e->nv_int);
574 break;
575 }
576 if (e->nv_ptr)
577 pr0(e->nv_ptr);
578 pr0(e->nv_next);
579 printf(")");
580 }
581 #endif
582