1 /* $NetBSD: files.c,v 1.10 2009/03/13 18:24:41 cube 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 nvlist *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 expr_free(optx); 164 } 165 166 void 167 addobject(const char *path, struct nvlist *optx, int flags) 168 { 169 struct objects *oi; 170 171 /* 172 * Commit this object to memory. We will decide later whether it 173 * will be used after all. 174 */ 175 oi = ecalloc(1, sizeof *oi); 176 if (ht_insert(pathtab, path, oi)) { 177 free(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"); 183 } 184 oi->oi_srcfile = yyfile; 185 oi->oi_srcline = currentline(); 186 oi->oi_flags = flags; 187 oi->oi_path = path; 188 oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL : 189 SLIST_FIRST(&prefixes)->pf_prefix; 190 oi->oi_optx = optx; 191 oi->oi_optf = NULL; 192 TAILQ_INSERT_TAIL(&allobjects, oi, oi_next); 193 return; 194 } 195 196 /* 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.) 201 */ 202 void 203 checkfiles(void) 204 { 205 struct files *fi, *last; 206 207 last = NULL; 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); 212 } 213 if (last != NULL) 214 unchecked = &TAILQ_NEXT(last, fi_next); 215 } 216 217 /* 218 * Auxiliary function for checkfiles, called from expr_eval. 219 * We are not actually interested in the expression's value. 220 */ 221 static int 222 checkaux(const char *name, void *context) 223 { 224 struct files *fi = context; 225 226 if (ht_lookup(devbasetab, name) == NULL) { 227 cfgxerror(fi->fi_srcfile, fi->fi_srcline, 228 "`%s' is not a countable device", 229 name); 230 /* keep fixfiles() from complaining again */ 231 fi->fi_flags |= FI_HIDDEN; 232 } 233 return (0); 234 } 235 236 /* 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. 240 */ 241 int 242 fixfiles(void) 243 { 244 struct files *fi, *ofi; 245 struct nvlist *flathead, **flatp; 246 int err, sel; 247 248 err = 0; 249 TAILQ_FOREACH(fi, &allfiles, fi_next) { 250 251 /* Skip files that generated counted-device complaints. */ 252 if (fi->fi_flags & FI_HIDDEN) 253 continue; 254 255 /* Optional: see if it is to be included. */ 256 if (fi->fi_flags & FIT_FORCESELECT) 257 { 258 /* include it */ ; 259 } 260 else if (fi->fi_optx != NULL) { 261 flathead = NULL; 262 flatp = &flathead; 263 sel = expr_eval(fi->fi_optx, 264 fi->fi_flags & FI_NEEDSCOUNT ? fixcount : 265 fi->fi_flags & FI_NEEDSFLAG ? fixfsel : 266 fixsel, 267 &flatp); 268 fi->fi_optf = flathead; 269 if (!sel) 270 continue; 271 } 272 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); 277 /* 278 * If the new file comes from a different source, 279 * allow the new one to override the old one. 280 */ 281 if (fi->fi_path != ofi->fi_path) { 282 if (ht_replace(basetab, fi->fi_base, fi) != 1) 283 panic("fixfiles ht_replace(%s)", 284 fi->fi_base); 285 ofi->fi_flags &= ~FI_SEL; 286 ofi->fi_flags |= FI_HIDDEN; 287 } else { 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", 293 ofi->fi_path); 294 err = 1; 295 } 296 } 297 fi->fi_flags |= FI_SEL; 298 } 299 return (err); 300 } 301 302 /* 303 * We have finished reading everything. Tack the objects down: calculate 304 * selection. 305 */ 306 int 307 fixobjects(void) 308 { 309 struct objects *oi; 310 struct nvlist *flathead, **flatp; 311 int err, sel; 312 313 err = 0; 314 TAILQ_FOREACH(oi, &allobjects, oi_next) { 315 /* Optional: see if it is to be included. */ 316 if (oi->oi_optx != NULL) { 317 flathead = NULL; 318 flatp = &flathead; 319 sel = expr_eval(oi->oi_optx, 320 oi->oi_flags & OI_NEEDSFLAG ? fixfsel : 321 fixsel, 322 &flatp); 323 oi->oi_optf = flathead; 324 if (!sel) 325 continue; 326 } 327 328 oi->oi_flags |= OI_SEL; 329 } 330 return (err); 331 } 332 333 /* 334 * We have finished reading everything. Tack the devsws down: calculate 335 * selection. 336 */ 337 int 338 fixdevsw(void) 339 { 340 int error; 341 struct devm *dm, *res; 342 struct hashtab *fixdevmtab; 343 char mstr[16]; 344 345 error = 0; 346 fixdevmtab = ht_new(); 347 348 TAILQ_FOREACH(dm, &alldevms, dm_next) { 349 res = ht_lookup(fixdevmtab, intern(dm->dm_name)); 350 if (res != NULL) { 351 if (res->dm_cmajor != dm->dm_cmajor || 352 res->dm_bmajor != dm->dm_bmajor) { 353 cfgxerror(res->dm_srcfile, res->dm_srcline, 354 "device-major '%s' " 355 "block %d, char %d redefined" 356 " at %s:%d as block %d, char %d", 357 res->dm_name, 358 res->dm_bmajor, res->dm_cmajor, 359 dm->dm_srcfile, dm->dm_srcline, 360 dm->dm_bmajor, dm->dm_cmajor); 361 } else { 362 cfgxerror(res->dm_srcfile, res->dm_srcline, 363 "device-major '%s' " 364 "(block %d, char %d) duplicated" 365 " at %s:%d", 366 dm->dm_name, dm->dm_bmajor, 367 dm->dm_cmajor, 368 dm->dm_srcfile, dm->dm_srcline); 369 } 370 error = 1; 371 goto out; 372 } 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); 376 } 377 378 if (dm->dm_opts != NULL && 379 !expr_eval(dm->dm_opts, fixsel, NULL)) 380 continue; 381 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); 387 error = 1; 388 goto out; 389 } 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); 395 error = 1; 396 goto out; 397 } 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); 402 } 403 } 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); 409 error = 1; 410 goto out; 411 } 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); 417 error = 1; 418 goto out; 419 } 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); 424 } 425 } 426 } 427 428 out: 429 ht_free(fixdevmtab); 430 return (error); 431 } 432 433 /* 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. 441 */ 442 static int 443 fixcount(const char *name, void *context) 444 { 445 struct nvlist ***p = context; 446 struct devbase *dev; 447 struct nvlist *nv; 448 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); 453 **p = nv; 454 *p = &nv->nv_next; 455 (void)ht_insert(needcnttab, name, nv); 456 return (dev->d_umax != 0); 457 } 458 459 /* 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. 462 */ 463 static int 464 fixfsel(const char *name, void *context) 465 { 466 struct nvlist ***p = context; 467 struct nvlist *nv; 468 int sel; 469 470 sel = ht_lookup(selecttab, name) != NULL; 471 nv = newnv(name, NULL, NULL, sel, NULL); 472 **p = nv; 473 *p = &nv->nv_next; 474 return (sel); 475 } 476 477 /* 478 * As for fixfsel above, but we do not need the flat list. 479 */ 480 static int 481 /*ARGSUSED*/ 482 fixsel(const char *name, void *context) 483 { 484 485 return (ht_lookup(selecttab, name) != NULL); 486 } 487 488 /* 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. 492 * 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). 495 */ 496 int 497 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context) 498 { 499 int lhs, rhs; 500 501 switch (expr->nv_num) { 502 503 case FX_ATOM: 504 return ((*fn)(expr->nv_name, context)); 505 506 case FX_NOT: 507 return (!expr_eval(expr->nv_next, fn, context)); 508 509 case FX_AND: 510 lhs = expr_eval(expr->nv_ptr, fn, context); 511 rhs = expr_eval(expr->nv_next, fn, context); 512 return (lhs & rhs); 513 514 case FX_OR: 515 lhs = expr_eval(expr->nv_ptr, fn, context); 516 rhs = expr_eval(expr->nv_next, fn, context); 517 return (lhs | rhs); 518 } 519 panic("expr_eval %lld", expr->nv_num); 520 /* NOTREACHED */ 521 return (0); 522 } 523 524 /* 525 * Free an expression tree. 526 */ 527 void 528 expr_free(struct nvlist *expr) 529 { 530 struct nvlist *rhs; 531 532 /* This loop traverses down the RHS of each subexpression. */ 533 for (; expr != NULL; expr = rhs) { 534 switch (expr->nv_num) { 535 536 /* Atoms and !-exprs have no left hand side. */ 537 case FX_ATOM: 538 case FX_NOT: 539 break; 540 541 /* For AND and OR nodes, free the LHS. */ 542 case FX_AND: 543 case FX_OR: 544 expr_free(expr->nv_ptr); 545 break; 546 547 default: 548 panic("expr_free %lld", expr->nv_num); 549 } 550 rhs = expr->nv_next; 551 nvfree(expr); 552 } 553 } 554 555 #ifdef DEBUG 556 /* 557 * Print expression tree. 558 */ 559 void 560 prexpr(struct nvlist *expr) 561 { 562 static void pr0(); 563 564 printf("expr ="); 565 pr0(expr); 566 printf("\n"); 567 (void)fflush(stdout); 568 } 569 570 static void 571 pr0(struct nvlist *e) 572 { 573 574 switch (e->nv_num) { 575 case FX_ATOM: 576 printf(" %s", e->nv_name); 577 return; 578 case FX_NOT: 579 printf(" (!"); 580 break; 581 case FX_AND: 582 printf(" (&"); 583 break; 584 case FX_OR: 585 printf(" (|"); 586 break; 587 default: 588 printf(" (?%lld?", e->nv_num); 589 break; 590 } 591 if (e->nv_ptr) 592 pr0(e->nv_ptr); 593 pr0(e->nv_next); 594 printf(")"); 595 } 596 #endif 597