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