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