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