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