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