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