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