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