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