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