files.c revision 1.2 1 /* $NetBSD: files.c,v 1.2 2005/11/07 03:26:20 erh 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
252 /* Skip files that generated counted-device complaints. */
253 if (fi->fi_flags & FI_HIDDEN)
254 continue;
255
256 /* Optional: see if it is to be included. */
257 if (fi->fi_flags & FIT_FORCESELECT)
258 {
259 /* include it */ ;
260 }
261 else if (fi->fi_optx != NULL) {
262 flathead = NULL;
263 flatp = &flathead;
264 sel = expr_eval(fi->fi_optx,
265 fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
266 fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
267 fixsel,
268 &flatp);
269 fi->fi_optf = flathead;
270 if (!sel)
271 continue;
272 }
273
274 /* We like this file. Make sure it generates a unique .o. */
275 if (ht_insert(basetab, fi->fi_base, fi)) {
276 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
277 panic("fixfiles ht_lookup(%s)", fi->fi_base);
278 /*
279 * If the new file comes from a different source,
280 * allow the new one to override the old one.
281 */
282 if (fi->fi_path != ofi->fi_path) {
283 if (ht_replace(basetab, fi->fi_base, fi) != 1)
284 panic("fixfiles ht_replace(%s)",
285 fi->fi_base);
286 ofi->fi_flags &= ~FI_SEL;
287 ofi->fi_flags |= FI_HIDDEN;
288 } else {
289 xerror(fi->fi_srcfile, fi->fi_srcline,
290 "object file collision on %s.o, from %s",
291 fi->fi_base, fi->fi_path);
292 xerror(ofi->fi_srcfile, ofi->fi_srcline,
293 "here is the previous file: %s",
294 ofi->fi_path);
295 err = 1;
296 }
297 }
298 fi->fi_flags |= FI_SEL;
299 }
300 return (err);
301 }
302
303 /*
304 * We have finished reading everything. Tack the objects down: calculate
305 * selection.
306 */
307 int
308 fixobjects(void)
309 {
310 struct objects *oi;
311 struct nvlist *flathead, **flatp;
312 int err, sel;
313
314 err = 0;
315 TAILQ_FOREACH(oi, &allobjects, oi_next) {
316 /* Optional: see if it is to be included. */
317 if (oi->oi_optx != NULL) {
318 flathead = NULL;
319 flatp = &flathead;
320 sel = expr_eval(oi->oi_optx,
321 oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
322 fixsel,
323 &flatp);
324 oi->oi_optf = flathead;
325 if (!sel)
326 continue;
327 }
328
329 oi->oi_flags |= OI_SEL;
330 }
331 return (err);
332 }
333
334 /*
335 * We have finished reading everything. Tack the devsws down: calculate
336 * selection.
337 */
338 int
339 fixdevsw(void)
340 {
341 struct devm *dm, *res;
342 struct hashtab *fixdevmtab;
343 char mstr[16];
344
345 fixdevmtab = ht_new();
346
347 TAILQ_FOREACH(dm, &alldevms, dm_next) {
348 res = ht_lookup(fixdevmtab, intern(dm->dm_name));
349 if (res != NULL) {
350 if (res->dm_cmajor != dm->dm_cmajor ||
351 res->dm_bmajor != dm->dm_bmajor) {
352 xerror(res->dm_srcfile, res->dm_srcline,
353 "device-major '%s' is inconsistent: "
354 "block %d, char %d", res->dm_name,
355 res->dm_bmajor, res->dm_cmajor);
356 xerror(dm->dm_srcfile, dm->dm_srcline,
357 "device-major '%s' is inconsistent: "
358 "block %d, char %d", dm->dm_name,
359 dm->dm_bmajor, dm->dm_cmajor);
360 return (1);
361 } else {
362 xerror(dm->dm_srcfile, dm->dm_srcline,
363 "device-major '%s' is duplicated: "
364 "block %d, char %d",
365 dm->dm_name, dm->dm_bmajor,
366 dm->dm_cmajor);
367 return (1);
368 }
369 }
370 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
371 panic("fixdevsw: %s char %d block %d",
372 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
373 }
374
375 if (dm->dm_opts != NULL &&
376 !expr_eval(dm->dm_opts, fixsel, NULL))
377 continue;
378
379 if (dm->dm_cmajor != -1) {
380 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
381 xerror(dm->dm_srcfile, dm->dm_srcline,
382 "device-major of character device '%s' "
383 "is already defined", dm->dm_name);
384 return (1);
385 }
386 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
387 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
388 xerror(dm->dm_srcfile, dm->dm_srcline,
389 "device-major of character major '%d' "
390 "is already defined", dm->dm_cmajor);
391 return (1);
392 }
393 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
394 ht_insert(cdevmtab, intern(mstr), dm)) {
395 panic("fixdevsw: %s character major %d",
396 dm->dm_name, dm->dm_cmajor);
397 }
398 }
399 if (dm->dm_bmajor != -1) {
400 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
401 xerror(dm->dm_srcfile, dm->dm_srcline,
402 "device-major of block device '%s' "
403 "is already defined", dm->dm_name);
404 return (1);
405 }
406 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
407 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
408 xerror(dm->dm_srcfile, dm->dm_srcline,
409 "device-major of block major '%d' "
410 "is already defined", dm->dm_bmajor);
411 return (1);
412 }
413 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
414 ht_insert(bdevmtab, intern(mstr), dm)) {
415 panic("fixdevsw: %s block major %d",
416 dm->dm_name, dm->dm_bmajor);
417 }
418 }
419 }
420
421 return (0);
422 }
423
424 /*
425 * Called when evaluating a needs-count expression. Make sure the
426 * atom is a countable device. The expression succeeds iff there
427 * is at least one of them (note that while `xx*' will not always
428 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The
429 * mkheaders() routine wants a flattened, in-order list of the
430 * atoms for `#define name value' lines, so we build that as we
431 * are called to eval each atom.
432 */
433 static int
434 fixcount(const char *name, void *context)
435 {
436 struct nvlist ***p = context;
437 struct devbase *dev;
438 struct nvlist *nv;
439
440 dev = ht_lookup(devbasetab, name);
441 if (dev == NULL) /* cannot occur here; we checked earlier */
442 panic("fixcount(%s)", name);
443 nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
444 **p = nv;
445 *p = &nv->nv_next;
446 (void)ht_insert(needcnttab, name, nv);
447 return (dev->d_umax != 0);
448 }
449
450 /*
451 * Called from fixfiles when eval'ing a selection expression for a
452 * file that will generate a .h with flags. We will need the flat list.
453 */
454 static int
455 fixfsel(const char *name, void *context)
456 {
457 struct nvlist ***p = context;
458 struct nvlist *nv;
459 int sel;
460
461 sel = ht_lookup(selecttab, name) != NULL;
462 nv = newnv(name, NULL, NULL, sel, NULL);
463 **p = nv;
464 *p = &nv->nv_next;
465 return (sel);
466 }
467
468 /*
469 * As for fixfsel above, but we do not need the flat list.
470 */
471 static int
472 fixsel(const char *name, void *context)
473 {
474
475 return (ht_lookup(selecttab, name) != NULL);
476 }
477
478 /*
479 * Eval an expression tree. Calls the given function on each node,
480 * passing it the given context & the name; return value is &/|/! of
481 * results of evaluating atoms.
482 *
483 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise
484 * our mixing of C's bitwise & boolean here may give surprises).
485 */
486 static int
487 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
488 {
489 int lhs, rhs;
490
491 switch (expr->nv_int) {
492
493 case FX_ATOM:
494 return ((*fn)(expr->nv_name, context));
495
496 case FX_NOT:
497 return (!expr_eval(expr->nv_next, fn, context));
498
499 case FX_AND:
500 lhs = expr_eval(expr->nv_ptr, fn, context);
501 rhs = expr_eval(expr->nv_next, fn, context);
502 return (lhs & rhs);
503
504 case FX_OR:
505 lhs = expr_eval(expr->nv_ptr, fn, context);
506 rhs = expr_eval(expr->nv_next, fn, context);
507 return (lhs | rhs);
508 }
509 panic("expr_eval %d", expr->nv_int);
510 /* NOTREACHED */
511 return (0);
512 }
513
514 /*
515 * Free an expression tree.
516 */
517 static void
518 expr_free(struct nvlist *expr)
519 {
520 struct nvlist *rhs;
521
522 /* This loop traverses down the RHS of each subexpression. */
523 for (; expr != NULL; expr = rhs) {
524 switch (expr->nv_int) {
525
526 /* Atoms and !-exprs have no left hand side. */
527 case FX_ATOM:
528 case FX_NOT:
529 break;
530
531 /* For AND and OR nodes, free the LHS. */
532 case FX_AND:
533 case FX_OR:
534 expr_free(expr->nv_ptr);
535 break;
536
537 default:
538 panic("expr_free %d", expr->nv_int);
539 }
540 rhs = expr->nv_next;
541 nvfree(expr);
542 }
543 }
544
545 #ifdef DEBUG
546 /*
547 * Print expression tree.
548 */
549 void
550 prexpr(struct nvlist *expr)
551 {
552 static void pr0();
553
554 printf("expr =");
555 pr0(expr);
556 printf("\n");
557 (void)fflush(stdout);
558 }
559
560 static void
561 pr0(struct nvlist *e)
562 {
563
564 switch (e->nv_int) {
565 case FX_ATOM:
566 printf(" %s", e->nv_name);
567 return;
568 case FX_NOT:
569 printf(" (!");
570 break;
571 case FX_AND:
572 printf(" (&");
573 break;
574 case FX_OR:
575 printf(" (|");
576 break;
577 default:
578 printf(" (?%d?", e->nv_int);
579 break;
580 }
581 if (e->nv_ptr)
582 pr0(e->nv_ptr);
583 pr0(e->nv_next);
584 printf(")");
585 }
586 #endif
587