1 /* $NetBSD: files.c,v 1.9 2009/01/20 18:20:48 drochner Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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.
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
40 * from: @(#)files.c 8.1 (Berkeley) 6/6/93
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
47 #include <sys/param.h>
55 extern const char *yyfile
;
58 * We check that each full path name is unique. File base names
59 * should generally also be unique, e.g., having both a net/xx.c and
60 * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
61 * wrong, but is permitted under some conditions.
63 static struct hashtab
*basetab
; /* file base names */
64 static struct hashtab
*pathtab
; /* full path names */
66 static struct files
**unchecked
;
68 static int checkaux(const char *, void *);
69 static int fixcount(const char *, void *);
70 static int fixfsel(const char *, void *);
71 static int fixsel(const char *, void *);
79 TAILQ_INIT(&allfiles
);
80 unchecked
= &TAILQ_FIRST(&allfiles
);
81 TAILQ_INIT(&allobjects
);
85 addfile(const char *path
, struct nvlist
*optx
, int flags
, const char *rule
)
88 const char *dotp
, *tail
;
93 /* check various errors */
94 needc
= flags
& FI_NEEDSCOUNT
;
95 needf
= flags
& FI_NEEDSFLAG
;
97 cfgerror("cannot mix needs-count and needs-flag");
100 if (optx
== NULL
&& (needc
|| needf
)) {
101 cfgerror("nothing to %s for %s", needc
? "count" : "flag",
106 /* find last part of pathname, and same without trailing suffix */
107 tail
= strrchr(path
, '/');
112 dotp
= strrchr(tail
, '.');
113 if (dotp
== NULL
|| dotp
[1] == 0 ||
114 (baselen
= dotp
- tail
) >= sizeof(base
)) {
115 cfgerror("invalid pathname `%s'", path
);
120 * Commit this file to memory. We will decide later whether it
121 * will be used after all.
123 fi
= ecalloc(1, sizeof *fi
);
124 if (ht_insert(pathtab
, path
, fi
)) {
126 if ((fi
= ht_lookup(pathtab
, path
)) == NULL
)
127 panic("addfile: ht_lookup(%s)", path
);
130 * If it's a duplicate entry, it is must specify a make
131 * rule, and only a make rule, and must come from
132 * a different source file than the original entry.
133 * If it does otherwise, it is disallowed. This allows
134 * machine-dependent files to override the compilation
135 * options for specific files.
137 if (rule
!= NULL
&& optx
== NULL
&& flags
== 0 &&
138 yyfile
!= fi
->fi_srcfile
) {
139 fi
->fi_mkrule
= rule
;
142 cfgerror("duplicate file %s", path
);
143 cfgxerror(fi
->fi_srcfile
, fi
->fi_srcline
,
144 "here is the original definition");
147 memcpy(base
, tail
, baselen
);
149 fi
->fi_srcfile
= yyfile
;
150 fi
->fi_srcline
= currentline();
151 fi
->fi_flags
= flags
;
154 fi
->fi_base
= intern(base
);
155 fi
->fi_prefix
= SLIST_EMPTY(&prefixes
) ? NULL
:
156 SLIST_FIRST(&prefixes
)->pf_prefix
;
159 fi
->fi_mkrule
= rule
;
160 TAILQ_INSERT_TAIL(&allfiles
, fi
, fi_next
);
167 addobject(const char *path
, struct nvlist
*optx
, int flags
)
172 * Commit this object to memory. We will decide later whether it
173 * will be used after all.
175 oi
= ecalloc(1, sizeof *oi
);
176 if (ht_insert(pathtab
, path
, oi
)) {
178 if ((oi
= ht_lookup(pathtab
, path
)) == NULL
)
179 panic("addfile: ht_lookup(%s)", path
);
180 cfgerror("duplicate file %s", path
);
181 cfgxerror(oi
->oi_srcfile
, oi
->oi_srcline
,
182 "here is the original definition");
184 oi
->oi_srcfile
= yyfile
;
185 oi
->oi_srcline
= currentline();
186 oi
->oi_flags
= flags
;
188 oi
->oi_prefix
= SLIST_EMPTY(&prefixes
) ? NULL
:
189 SLIST_FIRST(&prefixes
)->pf_prefix
;
192 TAILQ_INSERT_TAIL(&allobjects
, oi
, oi_next
);
197 * We have finished reading some "files" file, either ../../conf/files
198 * or ./files.$machine. Make sure that everything that is flagged as
199 * needing a count is reasonable. (This prevents ../../conf/files from
200 * depending on some machine-specific device.)
205 struct files
*fi
, *last
;
208 for (fi
= *unchecked
; fi
!= NULL
;
209 last
= fi
, fi
= TAILQ_NEXT(fi
, fi_next
)) {
210 if ((fi
->fi_flags
& FI_NEEDSCOUNT
) != 0)
211 (void)expr_eval(fi
->fi_optx
, checkaux
, fi
);
214 unchecked
= &TAILQ_NEXT(last
, fi_next
);
218 * Auxiliary function for checkfiles, called from expr_eval.
219 * We are not actually interested in the expression's value.
222 checkaux(const char *name
, void *context
)
224 struct files
*fi
= context
;
226 if (ht_lookup(devbasetab
, name
) == NULL
) {
227 cfgxerror(fi
->fi_srcfile
, fi
->fi_srcline
,
228 "`%s' is not a countable device",
230 /* keep fixfiles() from complaining again */
231 fi
->fi_flags
|= FI_HIDDEN
;
237 * We have finished reading everything. Tack the files down: calculate
238 * selection and counts as needed. Check that the object files built
239 * from the selected sources do not collide.
244 struct files
*fi
, *ofi
;
245 struct nvlist
*flathead
, **flatp
;
249 TAILQ_FOREACH(fi
, &allfiles
, fi_next
) {
251 /* Skip files that generated counted-device complaints. */
252 if (fi
->fi_flags
& FI_HIDDEN
)
255 /* Optional: see if it is to be included. */
256 if (fi
->fi_flags
& FIT_FORCESELECT
)
260 else if (fi
->fi_optx
!= NULL
) {
263 sel
= expr_eval(fi
->fi_optx
,
264 fi
->fi_flags
& FI_NEEDSCOUNT
? fixcount
:
265 fi
->fi_flags
& FI_NEEDSFLAG
? fixfsel
:
268 fi
->fi_optf
= flathead
;
273 /* We like this file. Make sure it generates a unique .o. */
274 if (ht_insert(basetab
, fi
->fi_base
, fi
)) {
275 if ((ofi
= ht_lookup(basetab
, fi
->fi_base
)) == NULL
)
276 panic("fixfiles ht_lookup(%s)", fi
->fi_base
);
278 * If the new file comes from a different source,
279 * allow the new one to override the old one.
281 if (fi
->fi_path
!= ofi
->fi_path
) {
282 if (ht_replace(basetab
, fi
->fi_base
, fi
) != 1)
283 panic("fixfiles ht_replace(%s)",
285 ofi
->fi_flags
&= ~FI_SEL
;
286 ofi
->fi_flags
|= FI_HIDDEN
;
288 cfgxerror(fi
->fi_srcfile
, fi
->fi_srcline
,
289 "object file collision on %s.o, from %s",
290 fi
->fi_base
, fi
->fi_path
);
291 cfgxerror(ofi
->fi_srcfile
, ofi
->fi_srcline
,
292 "here is the previous file: %s",
297 fi
->fi_flags
|= FI_SEL
;
303 * We have finished reading everything. Tack the objects down: calculate
310 struct nvlist
*flathead
, **flatp
;
314 TAILQ_FOREACH(oi
, &allobjects
, oi_next
) {
315 /* Optional: see if it is to be included. */
316 if (oi
->oi_optx
!= NULL
) {
319 sel
= expr_eval(oi
->oi_optx
,
320 oi
->oi_flags
& OI_NEEDSFLAG
? fixfsel
:
323 oi
->oi_optf
= flathead
;
328 oi
->oi_flags
|= OI_SEL
;
334 * We have finished reading everything. Tack the devsws down: calculate
341 struct devm
*dm
, *res
;
342 struct hashtab
*fixdevmtab
;
346 fixdevmtab
= ht_new();
348 TAILQ_FOREACH(dm
, &alldevms
, dm_next
) {
349 res
= ht_lookup(fixdevmtab
, intern(dm
->dm_name
));
351 if (res
->dm_cmajor
!= dm
->dm_cmajor
||
352 res
->dm_bmajor
!= dm
->dm_bmajor
) {
353 cfgxerror(res
->dm_srcfile
, res
->dm_srcline
,
355 "block %d, char %d redefined"
356 " at %s:%d as block %d, char %d",
358 res
->dm_bmajor
, res
->dm_cmajor
,
359 dm
->dm_srcfile
, dm
->dm_srcline
,
360 dm
->dm_bmajor
, dm
->dm_cmajor
);
362 cfgxerror(res
->dm_srcfile
, res
->dm_srcline
,
364 "(block %d, char %d) duplicated"
366 dm
->dm_name
, dm
->dm_bmajor
,
368 dm
->dm_srcfile
, dm
->dm_srcline
);
373 if (ht_insert(fixdevmtab
, intern(dm
->dm_name
), dm
)) {
374 panic("fixdevsw: %s char %d block %d",
375 dm
->dm_name
, dm
->dm_cmajor
, dm
->dm_bmajor
);
378 if (dm
->dm_opts
!= NULL
&&
379 !expr_eval(dm
->dm_opts
, fixsel
, NULL
))
382 if (dm
->dm_cmajor
!= NODEVMAJOR
) {
383 if (ht_lookup(cdevmtab
, intern(dm
->dm_name
)) != NULL
) {
384 cfgxerror(dm
->dm_srcfile
, dm
->dm_srcline
,
385 "device-major of character device '%s' "
386 "is already defined", dm
->dm_name
);
390 (void)snprintf(mstr
, sizeof(mstr
), "%d", dm
->dm_cmajor
);
391 if (ht_lookup(cdevmtab
, intern(mstr
)) != NULL
) {
392 cfgxerror(dm
->dm_srcfile
, dm
->dm_srcline
,
393 "device-major of character major '%d' "
394 "is already defined", dm
->dm_cmajor
);
398 if (ht_insert(cdevmtab
, intern(dm
->dm_name
), dm
) ||
399 ht_insert(cdevmtab
, intern(mstr
), dm
)) {
400 panic("fixdevsw: %s character major %d",
401 dm
->dm_name
, dm
->dm_cmajor
);
404 if (dm
->dm_bmajor
!= NODEVMAJOR
) {
405 if (ht_lookup(bdevmtab
, intern(dm
->dm_name
)) != NULL
) {
406 cfgxerror(dm
->dm_srcfile
, dm
->dm_srcline
,
407 "device-major of block device '%s' "
408 "is already defined", dm
->dm_name
);
412 (void)snprintf(mstr
, sizeof(mstr
), "%d", dm
->dm_bmajor
);
413 if (ht_lookup(bdevmtab
, intern(mstr
)) != NULL
) {
414 cfgxerror(dm
->dm_srcfile
, dm
->dm_srcline
,
415 "device-major of block major '%d' "
416 "is already defined", dm
->dm_bmajor
);
420 if (ht_insert(bdevmtab
, intern(dm
->dm_name
), dm
) ||
421 ht_insert(bdevmtab
, intern(mstr
), dm
)) {
422 panic("fixdevsw: %s block major %d",
423 dm
->dm_name
, dm
->dm_bmajor
);
434 * Called when evaluating a needs-count expression. Make sure the
435 * atom is a countable device. The expression succeeds iff there
436 * is at least one of them (note that while `xx*' will not always
437 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The
438 * mkheaders() routine wants a flattened, in-order list of the
439 * atoms for `#define name value' lines, so we build that as we
440 * are called to eval each atom.
443 fixcount(const char *name
, void *context
)
445 struct nvlist
***p
= context
;
449 dev
= ht_lookup(devbasetab
, name
);
450 if (dev
== NULL
) /* cannot occur here; we checked earlier */
451 panic("fixcount(%s)", name
);
452 nv
= newnv(name
, NULL
, NULL
, dev
->d_umax
, NULL
);
455 (void)ht_insert(needcnttab
, name
, nv
);
456 return (dev
->d_umax
!= 0);
460 * Called from fixfiles when eval'ing a selection expression for a
461 * file that will generate a .h with flags. We will need the flat list.
464 fixfsel(const char *name
, void *context
)
466 struct nvlist
***p
= context
;
470 sel
= ht_lookup(selecttab
, name
) != NULL
;
471 nv
= newnv(name
, NULL
, NULL
, sel
, NULL
);
478 * As for fixfsel above, but we do not need the flat list.
482 fixsel(const char *name
, void *context
)
485 return (ht_lookup(selecttab
, name
) != NULL
);
489 * Eval an expression tree. Calls the given function on each node,
490 * passing it the given context & the name; return value is &/|/! of
491 * results of evaluating atoms.
493 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise
494 * our mixing of C's bitwise & boolean here may give surprises).
497 expr_eval(struct nvlist
*expr
, int (*fn
)(const char *, void *), void *context
)
501 switch (expr
->nv_num
) {
504 return ((*fn
)(expr
->nv_name
, context
));
507 return (!expr_eval(expr
->nv_next
, fn
, context
));
510 lhs
= expr_eval(expr
->nv_ptr
, fn
, context
);
511 rhs
= expr_eval(expr
->nv_next
, fn
, context
);
515 lhs
= expr_eval(expr
->nv_ptr
, fn
, context
);
516 rhs
= expr_eval(expr
->nv_next
, fn
, context
);
519 panic("expr_eval %lld", expr
->nv_num
);
525 * Free an expression tree.
528 expr_free(struct nvlist
*expr
)
532 /* This loop traverses down the RHS of each subexpression. */
533 for (; expr
!= NULL
; expr
= rhs
) {
534 switch (expr
->nv_num
) {
536 /* Atoms and !-exprs have no left hand side. */
541 /* For AND and OR nodes, free the LHS. */
544 expr_free(expr
->nv_ptr
);
548 panic("expr_free %lld", expr
->nv_num
);
557 * Print expression tree.
560 prexpr(struct nvlist
*expr
)
567 (void)fflush(stdout
);
571 pr0(struct nvlist
*e
)
576 printf(" %s", e
->nv_name
);
588 printf(" (?%lld?", e
->nv_num
);