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