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