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