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