1 /* $NetBSD: main.c,v 1.25 2007/12/15 19:44:49 perry 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: @(#)main.c 8.1 (Berkeley) 6/6/93 41 */ 42 43 #if HAVE_NBTOOL_CONFIG_H 44 #include "nbtool_config.h" 45 #endif 46 47 #ifndef MAKE_BOOTSTRAP 48 #include <sys/cdefs.h> 49 #define COPYRIGHT(x) __COPYRIGHT(x) 50 #else 51 #define COPYRIGHT(x) static const char copyright[] = x 52 #endif 53 54 #ifndef lint 55 COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\ 56 The Regents of the University of California. All rights reserved.\n"); 57 #endif /* not lint */ 58 59 #include <sys/types.h> 60 #include <sys/stat.h> 61 #include <sys/param.h> 62 #include <sys/mman.h> 63 #include <paths.h> 64 #include <ctype.h> 65 #include <err.h> 66 #include <errno.h> 67 #include <fcntl.h> 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <string.h> 71 #include <unistd.h> 72 #include <vis.h> 73 #include <util.h> 74 75 #include "defs.h" 76 #include "sem.h" 77 78 #ifndef LINE_MAX 79 #define LINE_MAX 1024 80 #endif 81 82 int vflag; /* verbose output */ 83 int Pflag; /* pack locators */ 84 int Lflag; /* lint config generation */ 85 86 int yyparse(void); 87 88 #ifndef MAKE_BOOTSTRAP 89 extern int yydebug; 90 #endif 91 92 static struct hashtab *obsopttab; 93 static struct hashtab *mkopttab; 94 static struct nvlist **nextopt; 95 static struct nvlist **nextmkopt; 96 static struct nvlist **nextappmkopt; 97 static struct nvlist **nextfsopt; 98 99 static void usage(void) __dead; 100 static void dependopts(void); 101 static void do_depend(struct nvlist *); 102 static void stop(void); 103 static int do_option(struct hashtab *, struct nvlist ***, 104 const char *, const char *, const char *); 105 static int undo_option(struct hashtab *, struct nvlist **, 106 struct nvlist ***, const char *, const char *); 107 static int crosscheck(void); 108 static int badstar(void); 109 int main(int, char **); 110 static int mksymlinks(void); 111 static int mkident(void); 112 static int devbase_has_dead_instances(const char *, void *, void *); 113 static int devbase_has_any_instance(struct devbase *, int, int, int); 114 static int check_dead_devi(const char *, void *, void *); 115 static void kill_orphans(void); 116 static void do_kill_orphans(struct devbase *, struct attr *, 117 struct devbase *, int); 118 static int kill_orphans_cb(const char *, void *, void *); 119 static int cfcrosscheck(struct config *, const char *, struct nvlist *); 120 static const char *strtolower(const char *); 121 void defopt(struct hashtab *ht, const char *fname, 122 struct nvlist *opts, struct nvlist *deps, int obs); 123 124 #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" 125 #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" 126 127 static void logconfig_start(void); 128 static void logconfig_end(void); 129 static FILE *cfg; 130 static time_t cfgtime; 131 132 static int is_elf(const char *); 133 static int extract_config(const char *, const char *, int); 134 135 int badfilename(const char *fname); 136 137 const char *progname; 138 139 int 140 main(int argc, char **argv) 141 { 142 char *p, cname[20]; 143 const char *last_component; 144 int pflag, xflag, ch, removeit; 145 146 setprogname(argv[0]); 147 148 pflag = 0; 149 xflag = 0; 150 while ((ch = getopt(argc, argv, "DLPgpvb:s:x")) != -1) { 151 switch (ch) { 152 153 #ifndef MAKE_BOOTSTRAP 154 case 'D': 155 yydebug = 1; 156 break; 157 #endif 158 159 case 'L': 160 Lflag = 1; 161 break; 162 163 case 'P': 164 Pflag = 1; 165 break; 166 167 case 'g': 168 /* 169 * In addition to DEBUG, you probably wanted to 170 * set "options KGDB" and maybe others. We could 171 * do that for you, but you really should just 172 * put them in the config file. 173 */ 174 warnx("-g is obsolete (use makeoptions DEBUG=\"-g\")"); 175 usage(); 176 /*NOTREACHED*/ 177 178 case 'p': 179 /* 180 * Essentially the same as makeoptions PROF="-pg", 181 * but also changes the path from ../../compile/FOO 182 * to ../../compile/FOO.PROF; i.e., compile a 183 * profiling kernel based on a typical "regular" 184 * kernel. 185 * 186 * Note that if you always want profiling, you 187 * can (and should) use a "makeoptions" line. 188 */ 189 pflag = 1; 190 break; 191 192 case 'v': 193 vflag = 1; 194 break; 195 196 case 'b': 197 builddir = optarg; 198 break; 199 200 case 's': 201 srcdir = optarg; 202 break; 203 204 case 'x': 205 xflag = 1; 206 break; 207 208 case '?': 209 default: 210 usage(); 211 } 212 } 213 214 argc -= optind; 215 argv += optind; 216 if (argc > 1) { 217 usage(); 218 } 219 220 if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag || 221 vflag || Lflag)) 222 errx(EXIT_FAILURE, "-x must be used alone"); 223 if (Lflag && (builddir != NULL || Pflag || pflag)) 224 errx(EXIT_FAILURE, "-L can only be used with -s and -v"); 225 226 if (xflag) { 227 #ifdef __NetBSD__ 228 conffile = (argc == 1) ? argv[0] : _PATH_UNIX; 229 #else 230 if (argc == 0) 231 errx(EXIT_FAILURE, "no kernel supplied"); 232 #endif 233 if (!is_elf(conffile)) 234 errx(EXIT_FAILURE, "%s: not a binary kernel", 235 conffile); 236 if (!extract_config(conffile, "stdout", STDOUT_FILENO)) 237 errx(EXIT_FAILURE, "%s does not contain embedded " 238 "configuration data", conffile); 239 exit(0); 240 } 241 242 conffile = (argc == 1) ? argv[0] : "CONFIG"; 243 if (firstfile(conffile)) { 244 err(EXIT_FAILURE, "Cannot read `%s'", conffile); 245 exit(2); 246 } 247 248 /* 249 * Init variables. 250 */ 251 minmaxusers = 1; 252 maxmaxusers = 10000; 253 initintern(); 254 initfiles(); 255 initsem(); 256 ident = NULL; 257 devbasetab = ht_new(); 258 devroottab = ht_new(); 259 devatab = ht_new(); 260 devitab = ht_new(); 261 deaddevitab = ht_new(); 262 selecttab = ht_new(); 263 needcnttab = ht_new(); 264 opttab = ht_new(); 265 mkopttab = ht_new(); 266 condmkopttab = ht_new(); 267 fsopttab = ht_new(); 268 deffstab = ht_new(); 269 defopttab = ht_new(); 270 defparamtab = ht_new(); 271 defoptlint = ht_new(); 272 defflagtab = ht_new(); 273 optfiletab = ht_new(); 274 obsopttab = ht_new(); 275 bdevmtab = ht_new(); 276 maxbdevm = 0; 277 cdevmtab = ht_new(); 278 maxcdevm = 0; 279 nextopt = &options; 280 nextmkopt = &mkoptions; 281 nextappmkopt = &appmkoptions; 282 nextfsopt = &fsoptions; 283 284 /* 285 * Handle profiling (must do this before we try to create any 286 * files). 287 */ 288 last_component = strrchr(conffile, '/'); 289 last_component = (last_component) ? last_component + 1 : conffile; 290 if (pflag) { 291 p = emalloc(strlen(last_component) + 17); 292 (void)sprintf(p, "../compile/%s.PROF", last_component); 293 (void)addmkoption(intern("PROF"), "-pg"); 294 (void)addoption(intern("GPROF"), NULL); 295 } else { 296 p = emalloc(strlen(last_component) + 13); 297 (void)sprintf(p, "../compile/%s", last_component); 298 } 299 defbuilddir = (argc == 0) ? "." : p; 300 301 if (Lflag) { 302 char resolvedname[MAXPATHLEN]; 303 304 if (realpath(conffile, resolvedname) == NULL) 305 err(EXIT_FAILURE, "realpath(%s)", conffile); 306 307 if (yyparse()) 308 stop(); 309 310 printf("include \"%s\"\n", resolvedname); 311 312 emit_params(); 313 emit_options(); 314 emit_instances(); 315 316 exit(EXIT_SUCCESS); 317 } 318 319 removeit = 0; 320 if (is_elf(conffile)) { 321 const char *tmpdir; 322 int cfd; 323 324 if (builddir == NULL) 325 errx(EXIT_FAILURE, "Build directory must be specified " 326 "with binary kernels"); 327 328 /* Open temporary configuration file */ 329 tmpdir = getenv("TMPDIR"); 330 if (tmpdir == NULL) 331 tmpdir = "/tmp"; 332 snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir); 333 cfd = mkstemp(cname); 334 if (cfd == -1) 335 err(EXIT_FAILURE, "Cannot create `%s'", cname); 336 337 printf("Using configuration data embedded in kernel...\n"); 338 if (!extract_config(conffile, cname, cfd)) 339 errx(EXIT_FAILURE, "%s does not contain embedded " 340 "configuration data", conffile); 341 342 removeit = 1; 343 close(cfd); 344 firstfile(cname); 345 } 346 347 /* 348 * Parse config file (including machine definitions). 349 */ 350 logconfig_start(); 351 if (yyparse()) 352 stop(); 353 logconfig_end(); 354 355 if (removeit) 356 unlink(cname); 357 358 /* 359 * Detect and properly ignore orphaned devices 360 */ 361 kill_orphans(); 362 363 /* 364 * Select devices and pseudo devices and their attributes 365 */ 366 if (fixdevis()) 367 stop(); 368 369 /* 370 * Deal with option dependencies. 371 */ 372 dependopts(); 373 374 /* 375 * Fix (as in `set firmly in place') files. 376 */ 377 if (fixfiles()) 378 stop(); 379 380 /* 381 * Fix objects and libraries. 382 */ 383 if (fixobjects()) 384 stop(); 385 386 /* 387 * Fix device-majors. 388 */ 389 if (fixdevsw()) 390 stop(); 391 392 /* 393 * Perform cross-checking. 394 */ 395 if (maxusers == 0) { 396 if (defmaxusers) { 397 (void)printf("maxusers not specified; %d assumed\n", 398 defmaxusers); 399 maxusers = defmaxusers; 400 } else { 401 warnx("need \"maxusers\" line"); 402 errors++; 403 } 404 } 405 if (fsoptions == NULL) { 406 warnx( "need at least one \"file-system\" line"); 407 errors++; 408 } 409 if (crosscheck() || errors) 410 stop(); 411 412 /* 413 * Squeeze things down and finish cross-checks (STAR checks must 414 * run after packing). 415 */ 416 pack(); 417 if (badstar()) 418 stop(); 419 420 /* 421 * Ready to go. Build all the various files. 422 */ 423 if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || 424 mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident()) 425 stop(); 426 (void)printf("Build directory is %s\n", builddir); 427 (void)printf("Don't forget to run \"make depend\"\n"); 428 return 0; 429 } 430 431 static void 432 usage(void) 433 { 434 (void)fprintf(stderr, "Usage: %s [-Ppv] [-s srcdir] [-b builddir] " 435 "[config-file]\n\t%s -x [kernel-file]\n" 436 "\t%s -L [-v] [-s srcdir] [config-file]\n", 437 getprogname(), getprogname(), getprogname()); 438 exit(1); 439 } 440 441 /* 442 * Set any options that are implied by other options. 443 */ 444 static void 445 dependopts(void) 446 { 447 struct nvlist *nv, *opt; 448 449 for (nv = options; nv != NULL; nv = nv->nv_next) { 450 if ((opt = find_declared_option(nv->nv_name)) != NULL) { 451 for (opt = opt->nv_ptr; opt != NULL; 452 opt = opt->nv_next) { 453 do_depend(opt); 454 } 455 } 456 } 457 458 for (nv = fsoptions; nv != NULL; nv = nv->nv_next) { 459 if ((opt = find_declared_option(nv->nv_name)) != NULL) { 460 for (opt = opt->nv_ptr; opt != NULL; 461 opt = opt->nv_next) { 462 do_depend(opt); 463 } 464 } 465 } 466 } 467 468 static void 469 do_depend(struct nvlist *nv) 470 { 471 struct nvlist *nextnv; 472 struct attr *a; 473 474 if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) { 475 nv->nv_flags |= NV_DEPENDED; 476 /* 477 * If the dependency is an attribute, then just add 478 * it to the selecttab. 479 */ 480 if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) { 481 if (a->a_iattr) 482 panic("do_depend(%s): dep `%s' is an iattr", 483 nv->nv_name, a->a_name); 484 expandattr(a, selectattr); 485 } else { 486 if (ht_lookup(opttab, nv->nv_name) == NULL) 487 addoption(nv->nv_name, NULL); 488 if ((nextnv = 489 find_declared_option(nv->nv_name)) != NULL) 490 do_depend(nextnv->nv_ptr); 491 } 492 } 493 } 494 495 static int 496 recreate(const char *p, const char *q) 497 { 498 int ret; 499 500 if ((ret = unlink(q)) == -1 && errno != ENOENT) 501 warn("unlink(%s)\n", q); 502 if ((ret = symlink(p, q)) == -1) 503 warn("symlink(%s -> %s)", q, p); 504 return ret; 505 } 506 507 /* 508 * Make a symlink for "machine" so that "#include <machine/foo.h>" works, 509 * and for the machine's CPU architecture, so that works as well. 510 */ 511 static int 512 mksymlinks(void) 513 { 514 int ret; 515 char *p, buf[MAXPATHLEN]; 516 const char *q; 517 struct nvlist *nv; 518 519 snprintf(buf, sizeof(buf), "arch/%s/include", machine); 520 p = sourcepath(buf); 521 ret = recreate(p, "machine"); 522 free(p); 523 524 if (machinearch != NULL) { 525 snprintf(buf, sizeof(buf), "arch/%s/include", machinearch); 526 p = sourcepath(buf); 527 q = machinearch; 528 } else { 529 p = estrdup("machine"); 530 q = machine; 531 } 532 533 ret = recreate(p, q); 534 free(p); 535 536 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { 537 q = nv->nv_name; 538 snprintf(buf, sizeof(buf), "arch/%s/include", q); 539 p = sourcepath(buf); 540 ret = recreate(p, q); 541 free(p); 542 } 543 544 return (ret); 545 } 546 547 static __dead void 548 stop(void) 549 { 550 (void)fprintf(stderr, "*** Stop.\n"); 551 exit(1); 552 } 553 554 static void 555 add_dependencies(struct nvlist *nv, struct nvlist *deps) 556 { 557 struct nvlist *dep; 558 struct attr *a; 559 560 /* Use nv_ptr to link any other options that are implied. */ 561 nv->nv_ptr = deps; 562 for (dep = deps; dep != NULL; dep = dep->nv_next) { 563 /* 564 * If the dependency is an attribute, it must not 565 * be an interface attribute. Otherwise, it must 566 * be a previously declared option. 567 */ 568 if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) { 569 if (a->a_iattr) 570 cfgerror("option `%s' dependency `%s' " 571 "is an interface attribute", 572 nv->nv_name, a->a_name); 573 } else if (OPT_OBSOLETE(dep->nv_name)) { 574 cfgerror("option `%s' dependency `%s' " 575 "is obsolete", nv->nv_name, dep->nv_name); 576 } else if (find_declared_option(dep->nv_name) == NULL) { 577 cfgerror("option `%s' dependency `%s' " 578 "is an unknown option", 579 nv->nv_name, dep->nv_name); 580 } 581 } 582 } 583 584 /* 585 * Define one or more file systems. If file system options file name is 586 * specified, a preprocessor #define for that file system will be placed 587 * in that file. In this case, only one file system may be specified. 588 * Otherwise, no preprocessor #defines will be generated. 589 */ 590 void 591 deffilesystem(const char *fname, struct nvlist *fses, struct nvlist *deps) 592 { 593 struct nvlist *nv; 594 595 /* 596 * Mark these options as ones to skip when creating the Makefile. 597 */ 598 for (nv = fses; nv != NULL; nv = nv->nv_next) { 599 if (DEFINED_OPTION(nv->nv_name)) { 600 cfgerror("file system or option `%s' already defined", 601 nv->nv_name); 602 return; 603 } 604 605 /* 606 * Also mark it as a valid file system, which may be 607 * used in "file-system" directives in the config 608 * file. 609 */ 610 if (ht_insert(deffstab, nv->nv_name, nv)) 611 panic("file system `%s' already in table?!", 612 nv->nv_name); 613 614 if (fname != NULL) { 615 /* 616 * Only one file system allowed in this case. 617 */ 618 if (nv->nv_next != NULL) { 619 cfgerror("only one file system per option " 620 "file may be specified"); 621 return; 622 } 623 624 if (ht_insert(optfiletab, fname, nv)) { 625 cfgerror("option file `%s' already exists", 626 fname); 627 return; 628 } 629 } 630 631 add_dependencies(nv, deps); 632 } 633 } 634 635 /* 636 * Sanity check a file name. 637 */ 638 int 639 badfilename(const char *fname) 640 { 641 const char *n; 642 643 /* 644 * We're putting multiple options into one file. Sanity 645 * check the file name. 646 */ 647 if (strchr(fname, '/') != NULL) { 648 cfgerror("option file name contains a `/'"); 649 return 1; 650 } 651 if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) { 652 cfgerror("option file name does not end in `.h'"); 653 return 1; 654 } 655 return 0; 656 } 657 658 659 /* 660 * Search for a defined option (defopt, filesystem, etc), and if found, 661 * return the option's struct nvlist. 662 */ 663 struct nvlist * 664 find_declared_option(const char *name) 665 { 666 struct nvlist *option = NULL; 667 668 if ((option = ht_lookup(defopttab, name)) != NULL || 669 (option = ht_lookup(defparamtab, name)) != NULL || 670 (option = ht_lookup(defflagtab, name)) != NULL || 671 (option = ht_lookup(fsopttab, name)) != NULL) { 672 return (option); 673 } 674 675 return (NULL); 676 } 677 678 679 /* 680 * Define one or more standard options. If an option file name is specified, 681 * place all options in one file with the specified name. Otherwise, create 682 * an option file for each option. 683 * record the option information in the specified table. 684 */ 685 void 686 defopt(struct hashtab *ht, const char *fname, struct nvlist *opts, 687 struct nvlist *deps, int obs) 688 { 689 struct nvlist *nv, *nextnv, *oldnv; 690 const char *name; 691 char buf[500]; 692 693 if (fname != NULL && badfilename(fname)) { 694 return; 695 } 696 697 /* 698 * Mark these options as ones to skip when creating the Makefile. 699 */ 700 for (nv = opts; nv != NULL; nv = nextnv) { 701 nextnv = nv->nv_next; 702 703 if (*(nv->nv_name) == '\0') { 704 if (nextnv == NULL) 705 panic("invalid option chain"); 706 /* 707 * If an entry already exists, then we are about to 708 * complain, so no worry. 709 */ 710 (void) ht_insert(defoptlint, nextnv->nv_name, 711 nv); 712 nv = nextnv; 713 nextnv = nextnv->nv_next; 714 } 715 716 /* An option name can be declared at most once. */ 717 if (DEFINED_OPTION(nv->nv_name)) { 718 cfgerror("file system or option `%s' already defined", 719 nv->nv_name); 720 return; 721 } 722 723 if (ht_insert(ht, nv->nv_name, nv)) { 724 cfgerror("file system or option `%s' already defined", 725 nv->nv_name); 726 return; 727 } 728 729 if (fname == NULL) { 730 /* 731 * Each option will be going into its own file. 732 * Convert the option name to lower case. This 733 * lower case name will be used as the option 734 * file name. 735 */ 736 (void) snprintf(buf, sizeof(buf), "opt_%s.h", 737 strtolower(nv->nv_name)); 738 name = intern(buf); 739 } else { 740 name = fname; 741 } 742 743 add_dependencies(nv, deps); 744 745 /* 746 * Remove this option from the parameter list before adding 747 * it to the list associated with this option file. 748 */ 749 nv->nv_next = NULL; 750 751 /* 752 * Flag as obsolete, if requested. 753 */ 754 if (obs) { 755 nv->nv_flags |= NV_OBSOLETE; 756 (void)ht_insert(obsopttab, nv->nv_name, nv); 757 } 758 759 /* 760 * Add this option file if we haven't seen it yet. 761 * Otherwise, append to the list of options already 762 * associated with this file. 763 */ 764 if ((oldnv = ht_lookup(optfiletab, name)) == NULL) { 765 (void)ht_insert(optfiletab, name, nv); 766 } else { 767 while (oldnv->nv_next != NULL) 768 oldnv = oldnv->nv_next; 769 oldnv->nv_next = nv; 770 } 771 } 772 } 773 774 /* 775 * Define one or more standard options. If an option file name is specified, 776 * place all options in one file with the specified name. Otherwise, create 777 * an option file for each option. 778 */ 779 void 780 defoption(const char *fname, struct nvlist *opts, struct nvlist *deps) 781 { 782 783 cfgwarn("The use of `defopt' is deprecated"); 784 defopt(defopttab, fname, opts, deps, 0); 785 } 786 787 788 /* 789 * Define an option for which a value is required. 790 */ 791 void 792 defparam(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs) 793 { 794 795 defopt(defparamtab, fname, opts, deps, obs); 796 } 797 798 /* 799 * Define an option which must not have a value, and which 800 * emits a "needs-flag" style output. 801 */ 802 void 803 defflag(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs) 804 { 805 806 defopt(defflagtab, fname, opts, deps, obs); 807 } 808 809 810 /* 811 * Add an option from "options FOO". Note that this selects things that 812 * are "optional foo". 813 */ 814 void 815 addoption(const char *name, const char *value) 816 { 817 const char *n; 818 int is_fs, is_param, is_flag, is_undecl, is_obs; 819 820 /* 821 * Figure out how this option was declared (if at all.) 822 * XXX should use "params" and "flags" in config. 823 * XXX crying out for a type field in a unified hashtab. 824 */ 825 is_fs = OPT_FSOPT(name); 826 is_param = OPT_DEFPARAM(name); 827 is_flag = OPT_DEFFLAG(name); 828 is_obs = OPT_OBSOLETE(name); 829 is_undecl = !DEFINED_OPTION(name); 830 831 /* Warn and pretend the user had not selected the option */ 832 if (is_obs) { 833 cfgwarn("obsolete option `%s' will be ignored", name); 834 return; 835 } 836 837 /* Make sure this is not a defined file system. */ 838 if (is_fs) { 839 cfgerror("`%s' is a defined file system", name); 840 return; 841 } 842 /* A defparam must have a value */ 843 if (is_param && value == NULL) { 844 cfgerror("option `%s' must have a value", name); 845 return; 846 } 847 /* A defflag must not have a value */ 848 if (is_flag && value != NULL) { 849 cfgerror("option `%s' must not have a value", name); 850 return; 851 } 852 853 if (is_undecl && vflag) { 854 cfgwarn("undeclared option `%s' added to IDENT", name); 855 } 856 857 if (do_option(opttab, &nextopt, name, value, "options")) 858 return; 859 860 /* make lowercase, then add to select table */ 861 n = strtolower(name); 862 (void)ht_insert(selecttab, n, (void *)__UNCONST(n)); 863 } 864 865 void 866 deloption(const char *name) 867 { 868 869 if (undo_option(opttab, &options, &nextopt, name, "options")) 870 return; 871 if (undo_option(selecttab, NULL, NULL, strtolower(name), "options")) 872 return; 873 } 874 875 /* 876 * Add a file system option. This routine simply inserts the name into 877 * a list of valid file systems, which is used to validate the root 878 * file system type. The name is then treated like a standard option. 879 */ 880 void 881 addfsoption(const char *name) 882 { 883 const char *n; 884 885 /* Make sure this is a defined file system. */ 886 if (!OPT_FSOPT(name)) { 887 cfgerror("`%s' is not a defined file system", name); 888 return; 889 } 890 891 /* 892 * Convert to lower case. This will be used in the select 893 * table, to verify root file systems. 894 */ 895 n = strtolower(name); 896 897 if (do_option(fsopttab, &nextfsopt, name, n, "file-system")) 898 return; 899 900 /* Add to select table. */ 901 (void)ht_insert(selecttab, n, __UNCONST(n)); 902 } 903 904 void 905 delfsoption(const char *name) 906 { 907 const char *n; 908 909 n = strtolower(name); 910 if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system")) 911 return; 912 if (undo_option(selecttab, NULL, NULL, n, "file-system")) 913 return; 914 } 915 916 /* 917 * Add a "make" option. 918 */ 919 void 920 addmkoption(const char *name, const char *value) 921 { 922 923 (void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions"); 924 } 925 926 void 927 delmkoption(const char *name) 928 { 929 930 (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name, 931 "makeoptions"); 932 } 933 934 /* 935 * Add an appending "make" option. 936 */ 937 void 938 appendmkoption(const char *name, const char *value) 939 { 940 struct nvlist *nv; 941 942 nv = newnv(name, value, NULL, 0, NULL); 943 *nextappmkopt = nv; 944 nextappmkopt = &nv->nv_next; 945 } 946 947 /* 948 * Add a conditional appending "make" option. 949 */ 950 void 951 appendcondmkoption(const char *selname, const char *name, const char *value) 952 { 953 struct nvlist *nv, *lnv; 954 const char *n; 955 956 n = strtolower(selname); 957 nv = newnv(name, value, NULL, 0, NULL); 958 if (ht_insert(condmkopttab, n, nv) == 0) 959 return; 960 961 if ((lnv = ht_lookup(condmkopttab, n)) == NULL) 962 panic("appendcondmkoption"); 963 for (; lnv->nv_next != NULL; lnv = lnv->nv_next) 964 /* search for the last list element */; 965 lnv->nv_next = nv; 966 } 967 968 /* 969 * Add a name=value pair to an option list. The value may be NULL. 970 */ 971 static int 972 do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 973 const char *value, const char *type) 974 { 975 struct nvlist *nv; 976 977 /* assume it will work */ 978 nv = newnv(name, value, NULL, 0, NULL); 979 if (ht_insert(ht, name, nv) == 0) { 980 **nppp = nv; 981 *nppp = &nv->nv_next; 982 return (0); 983 } 984 985 /* oops, already got that option */ 986 nvfree(nv); 987 if ((nv = ht_lookup(ht, name)) == NULL) 988 panic("do_option"); 989 if (nv->nv_str != NULL && !OPT_FSOPT(name)) 990 cfgerror("already have %s `%s=%s'", type, name, nv->nv_str); 991 else 992 cfgerror("already have %s `%s'", type, name); 993 return (1); 994 } 995 996 /* 997 * Remove a name from a hash table, 998 * and optionally, a name=value pair from an option list. 999 */ 1000 static int 1001 undo_option(struct hashtab *ht, struct nvlist **npp, 1002 struct nvlist ***next, const char *name, const char *type) 1003 { 1004 struct nvlist *nv; 1005 1006 if (ht_remove(ht, name)) { 1007 cfgerror("%s `%s' is not defined", type, name); 1008 return (1); 1009 } 1010 if (npp == NULL) 1011 return (0); 1012 1013 for ( ; *npp != NULL; npp = &(*npp)->nv_next) { 1014 if ((*npp)->nv_name != name) 1015 continue; 1016 if (next != NULL && *next == &(*npp)->nv_next) 1017 *next = npp; 1018 nv = (*npp)->nv_next; 1019 nvfree(*npp); 1020 *npp = nv; 1021 return (0); 1022 } 1023 panic("%s `%s' is not defined in nvlist", type, name); 1024 return (1); 1025 } 1026 1027 /* 1028 * Return true if there is at least one instance of the given unit 1029 * on the given device attachment (or any units, if unit == WILD). 1030 */ 1031 int 1032 deva_has_instances(struct deva *deva, int unit) 1033 { 1034 struct devi *i; 1035 1036 for (i = deva->d_ihead; i != NULL; i = i->i_asame) 1037 if (i->i_active == DEVI_ACTIVE && 1038 (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) 1039 return (1); 1040 return (0); 1041 } 1042 1043 /* 1044 * Return true if there is at least one instance of the given unit 1045 * on the given base (or any units, if unit == WILD). 1046 */ 1047 int 1048 devbase_has_instances(struct devbase *dev, int unit) 1049 { 1050 struct deva *da; 1051 1052 /* 1053 * Pseudo-devices are a little special. We consider them 1054 * to have instances only if they are both: 1055 * 1056 * 1. Included in this kernel configuration. 1057 * 1058 * 2. Have one or more interface attributes. 1059 */ 1060 if (dev->d_ispseudo) { 1061 struct nvlist *nv; 1062 struct attr *a; 1063 1064 if (ht_lookup(devitab, dev->d_name) == NULL) 1065 return (0); 1066 1067 for (nv = dev->d_attrs; nv != NULL; nv = nv->nv_next) { 1068 a = nv->nv_ptr; 1069 if (a->a_iattr) 1070 return (1); 1071 } 1072 return (0); 1073 } 1074 1075 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 1076 if (deva_has_instances(da, unit)) 1077 return (1); 1078 return (0); 1079 } 1080 1081 static int 1082 cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 1083 { 1084 struct devbase *dev; 1085 struct devi *pd; 1086 int errs, devunit; 1087 1088 if (maxpartitions <= 0) 1089 panic("cfcrosscheck"); 1090 1091 for (errs = 0; nv != NULL; nv = nv->nv_next) { 1092 if (nv->nv_name == NULL) 1093 continue; 1094 dev = ht_lookup(devbasetab, nv->nv_name); 1095 if (dev == NULL) 1096 panic("cfcrosscheck(%s)", nv->nv_name); 1097 if (has_attr(dev->d_attrs, s_ifnet)) 1098 devunit = nv->nv_ifunit; /* XXX XXX XXX */ 1099 else 1100 devunit = minor((uint32_t)nv->nv_int) / maxpartitions; 1101 if (devbase_has_instances(dev, devunit)) 1102 continue; 1103 if (devbase_has_instances(dev, STAR) && 1104 devunit >= dev->d_umax) 1105 continue; 1106 TAILQ_FOREACH(pd, &allpseudo, i_next) { 1107 if (pd->i_base == dev && devunit < dev->d_umax && 1108 devunit >= 0) 1109 goto loop; 1110 } 1111 (void)fprintf(stderr, 1112 "%s:%d: %s says %s on %s, but there's no %s\n", 1113 conffile, cf->cf_lineno, 1114 cf->cf_name, what, nv->nv_str, nv->nv_str); 1115 errs++; 1116 loop: 1117 ; 1118 } 1119 return (errs); 1120 } 1121 1122 /* 1123 * Cross-check the configuration: make sure that each target device 1124 * or attribute (`at foo[0*?]') names at least one real device. Also 1125 * see that the root and dump devices for all configurations are there. 1126 */ 1127 int 1128 crosscheck(void) 1129 { 1130 struct config *cf; 1131 int errs; 1132 1133 errs = 0; 1134 if (TAILQ_EMPTY(&allcf)) { 1135 warnx("%s has no configurations!", conffile); 1136 errs++; 1137 } 1138 TAILQ_FOREACH(cf, &allcf, cf_next) { 1139 if (cf->cf_root != NULL) { /* i.e., not root on ? */ 1140 errs += cfcrosscheck(cf, "root", cf->cf_root); 1141 errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 1142 } 1143 } 1144 return (errs); 1145 } 1146 1147 /* 1148 * Check to see if there is a *'d unit with a needs-count file. 1149 */ 1150 int 1151 badstar(void) 1152 { 1153 struct devbase *d; 1154 struct deva *da; 1155 struct devi *i; 1156 int errs, n; 1157 1158 errs = 0; 1159 TAILQ_FOREACH(d, &allbases, d_next) { 1160 for (da = d->d_ahead; da != NULL; da = da->d_bsame) 1161 for (i = da->d_ihead; i != NULL; i = i->i_asame) { 1162 if (i->i_unit == STAR) 1163 goto aybabtu; 1164 } 1165 continue; 1166 aybabtu: 1167 if (ht_lookup(needcnttab, d->d_name)) { 1168 warnx("%s's cannot be *'d until its driver is fixed", 1169 d->d_name); 1170 errs++; 1171 continue; 1172 } 1173 for (n = 0; i != NULL; i = i->i_alias) 1174 if (!i->i_collapsed) 1175 n++; 1176 if (n < 1) 1177 panic("badstar() n<1"); 1178 } 1179 return (errs); 1180 } 1181 1182 /* 1183 * Verify/create builddir if necessary, change to it, and verify srcdir. 1184 * This will be called when we see the first include. 1185 */ 1186 void 1187 setupdirs(void) 1188 { 1189 struct stat st; 1190 1191 /* srcdir must be specified if builddir is not specified or if 1192 * no configuration filename was specified. */ 1193 if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 1194 cfgerror("source directory must be specified"); 1195 exit(1); 1196 } 1197 1198 if (Lflag) { 1199 if (srcdir == NULL) 1200 srcdir = "../../.."; 1201 return; 1202 } 1203 1204 if (srcdir == NULL) 1205 srcdir = "../../../.."; 1206 if (builddir == NULL) 1207 builddir = defbuilddir; 1208 1209 if (stat(builddir, &st) == -1) { 1210 if (mkdir(builddir, 0777) == -1) 1211 errx(EXIT_FAILURE, "cannot create %s", builddir); 1212 } else if (!S_ISDIR(st.st_mode)) 1213 errx(EXIT_FAILURE, "%s is not a directory", builddir); 1214 if (chdir(builddir) == -1) 1215 err(EXIT_FAILURE, "cannot change to %s", builddir); 1216 if (stat(srcdir, &st) == -1) 1217 err(EXIT_FAILURE, "cannot stat %s", srcdir); 1218 if (!S_ISDIR(st.st_mode)) 1219 errx(EXIT_FAILURE, "%s is not a directory", srcdir); 1220 } 1221 1222 /* 1223 * Write identifier from "ident" directive into file, for 1224 * newvers.sh to pick it up. 1225 */ 1226 int 1227 mkident(void) 1228 { 1229 FILE *fp; 1230 int error = 0; 1231 1232 (void)unlink("ident"); 1233 1234 if (ident == NULL) 1235 return (0); 1236 1237 if ((fp = fopen("ident", "w")) == NULL) { 1238 warn("cannot write ident"); 1239 return (1); 1240 } 1241 if (vflag) 1242 (void)printf("using ident '%s'\n", ident); 1243 fprintf(fp, "%s\n", ident); 1244 fflush(fp); 1245 if (ferror(fp)) 1246 error = 1; 1247 (void)fclose(fp); 1248 1249 return error; 1250 } 1251 1252 void 1253 logconfig_start(void) 1254 { 1255 extern FILE *yyin; 1256 char line[1024]; 1257 const char *tmpdir; 1258 struct stat st; 1259 int fd; 1260 1261 if (yyin == NULL || fstat(fileno(yyin), &st) == -1) 1262 return; 1263 cfgtime = st.st_mtime; 1264 1265 tmpdir = getenv("TMPDIR"); 1266 if (tmpdir == NULL) 1267 tmpdir = "/tmp"; 1268 (void)snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); 1269 if ((fd = mkstemp(line)) == -1 || 1270 (cfg = fdopen(fd, "r+")) == NULL) { 1271 if (fd != -1) { 1272 (void)unlink(line); 1273 (void)close(fd); 1274 } 1275 cfg = NULL; 1276 return; 1277 } 1278 (void)unlink(line); 1279 1280 (void)fprintf(cfg, "#include <sys/cdefs.h>\n\n"); 1281 (void)fprintf(cfg, "#include \"opt_config.h\"\n"); 1282 (void)fprintf(cfg, "\n"); 1283 (void)fprintf(cfg, "/*\n"); 1284 (void)fprintf(cfg, " * Add either (or both) of\n"); 1285 (void)fprintf(cfg, " *\n"); 1286 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); 1287 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); 1288 (void)fprintf(cfg, " *\n"); 1289 (void)fprintf(cfg, 1290 " * to your kernel config file to embed it in the resulting\n"); 1291 (void)fprintf(cfg, 1292 " * kernel. The latter option does not include files that are\n"); 1293 (void)fprintf(cfg, 1294 " * included (recursively) by your config file. The embedded\n"); 1295 (void)fprintf(cfg, 1296 " * data be extracted by using the command:\n"); 1297 (void)fprintf(cfg, " *\n"); 1298 (void)fprintf(cfg, 1299 " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); 1300 (void)fprintf(cfg, " */\n"); 1301 (void)fprintf(cfg, "\n"); 1302 (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); 1303 (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", 1304 LOGCONFIG_LARGE, LOGCONFIG_SMALL); 1305 (void)fprintf(cfg, "static const char config[] __used =\n\n"); 1306 1307 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 1308 (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", 1309 conffile); 1310 (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); 1311 1312 logconfig_include(yyin, NULL); 1313 1314 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 1315 (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", 1316 conffile); 1317 1318 rewind(yyin); 1319 } 1320 1321 void 1322 logconfig_include(FILE *cf, const char *filename) 1323 { 1324 char line[1024], in[2048], *out; 1325 struct stat st; 1326 int missingeol; 1327 1328 if (!cfg) 1329 return; 1330 1331 missingeol = 0; 1332 if (fstat(fileno(cf), &st) == -1) 1333 return; 1334 if (cfgtime < st.st_mtime) 1335 cfgtime = st.st_mtime; 1336 1337 if (filename) 1338 (void)fprintf(cfg, 1339 "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", 1340 filename); 1341 while (fgets(line, sizeof(line), cf) != NULL) { 1342 missingeol = 1; 1343 (void)fprintf(cfg, "\"_CFG_"); 1344 if (filename) 1345 (void)fprintf(cfg, "###> "); 1346 strvis(in, line, VIS_TAB); 1347 for (out = in; *out; out++) 1348 switch (*out) { 1349 case '\n': 1350 (void)fprintf(cfg, "\\n\"\n"); 1351 missingeol = 0; 1352 break; 1353 case '"': case '\\': 1354 (void)fputc('\\', cfg); 1355 /* FALLTHROUGH */ 1356 default: 1357 (void)fputc(*out, cfg); 1358 break; 1359 } 1360 } 1361 if (missingeol) { 1362 (void)fprintf(cfg, "\\n\"\n"); 1363 warnx("%s: newline missing at EOF", 1364 filename != NULL ? filename : conffile); 1365 } 1366 if (filename) 1367 (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", 1368 filename); 1369 1370 rewind(cf); 1371 } 1372 1373 void 1374 logconfig_end(void) 1375 { 1376 char line[1024]; 1377 FILE *fp; 1378 struct stat st; 1379 1380 if (!cfg) 1381 return; 1382 1383 (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); 1384 (void)fprintf(cfg, ";\n"); 1385 (void)fprintf(cfg, "#endif /* %s || %s */\n", 1386 LOGCONFIG_LARGE, LOGCONFIG_SMALL); 1387 (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); 1388 fflush(cfg); 1389 if (ferror(cfg)) 1390 err(EXIT_FAILURE, "write to temporary file for config.h failed"); 1391 rewind(cfg); 1392 1393 if (stat("config_file.h", &st) != -1) { 1394 if (cfgtime < st.st_mtime) { 1395 fclose(cfg); 1396 return; 1397 } 1398 } 1399 1400 fp = fopen("config_file.h", "w"); 1401 if (!fp) 1402 err(EXIT_FAILURE, "cannot open \"config.h\""); 1403 1404 while (fgets(line, sizeof(line), cfg) != NULL) 1405 fputs(line, fp); 1406 fflush(fp); 1407 if (ferror(fp)) 1408 err(EXIT_FAILURE, "write to \"config.h\" failed"); 1409 fclose(fp); 1410 fclose(cfg); 1411 } 1412 1413 static const char * 1414 strtolower(const char *name) 1415 { 1416 const char *n; 1417 char *p, low[500]; 1418 unsigned char c; 1419 1420 for (n = name, p = low; (c = *n) != '\0'; n++) 1421 *p++ = isupper(c) ? tolower(c) : c; 1422 *p = 0; 1423 return (intern(low)); 1424 } 1425 1426 static int 1427 is_elf(const char *file) 1428 { 1429 int kernel; 1430 char hdr[4]; 1431 1432 kernel = open(file, O_RDONLY); 1433 if (kernel == -1) 1434 err(EXIT_FAILURE, "cannot open %s", file); 1435 if (read(kernel, hdr, 4) != 4) 1436 err(EXIT_FAILURE, "Cannot read from %s", file); 1437 (void)close(kernel); 1438 1439 return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; 1440 } 1441 1442 static int 1443 extract_config(const char *kname, const char *cname, int cfd) 1444 { 1445 char *ptr; 1446 int found, kfd, i; 1447 struct stat st; 1448 1449 found = 0; 1450 1451 /* mmap(2) binary kernel */ 1452 kfd = open(conffile, O_RDONLY); 1453 if (kfd == -1) 1454 err(EXIT_FAILURE, "cannot open %s", kname); 1455 if (fstat(kfd, &st) == -1) 1456 err(EXIT_FAILURE, "cannot stat %s", kname); 1457 ptr = mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, 1458 kfd, 0); 1459 if (ptr == MAP_FAILED) 1460 err(EXIT_FAILURE, "cannot mmap %s", kname); 1461 1462 /* Scan mmap(2)'ed region, extracting kernel configuration */ 1463 for (i = 0; i < st.st_size; i++) { 1464 if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, 1465 "_CFG_", 5) == 0) { 1466 /* Line found */ 1467 char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; 1468 int j; 1469 1470 found = 1; 1471 1472 oldptr = (ptr += 5); 1473 while (*ptr != '\n' && *ptr != '\0') 1474 ptr++; 1475 if (ptr - oldptr > LINE_MAX) 1476 errx(EXIT_FAILURE, "line too long"); 1477 i += ptr - oldptr + 5; 1478 (void)memcpy(line, oldptr, (size_t)(ptr - oldptr)); 1479 line[ptr - oldptr] = '\0'; 1480 j = strunvis(uline, line); 1481 if (j == -1) 1482 errx(EXIT_FAILURE, "unvis: invalid " 1483 "encoded sequence"); 1484 uline[j] = '\n'; 1485 if (write(cfd, uline, (size_t)j + 1) == -1) 1486 err(EXIT_FAILURE, "cannot write to %s", cname); 1487 } else 1488 ptr++; 1489 } 1490 1491 (void)close(kfd); 1492 1493 return found; 1494 } 1495 1496 struct dhdi_params { 1497 struct devbase *d; 1498 int unit; 1499 int level; 1500 }; 1501 1502 static int 1503 devbase_has_dead_instances(const char *key, void *value, void *aux) 1504 { 1505 struct devi *i; 1506 struct dhdi_params *dhdi = aux; 1507 1508 for (i = value; i != NULL; i = i->i_alias) 1509 if (i->i_base == dhdi->d && 1510 (dhdi->unit == WILD || dhdi->unit == i->i_unit || 1511 i->i_unit == STAR) && 1512 i->i_level >= dhdi->level) 1513 return 1; 1514 return 0; 1515 } 1516 1517 /* 1518 * This is almost the same as devbase_has_instances, except it 1519 * may have special considerations regarding ignored instances. 1520 */ 1521 1522 static int 1523 devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) 1524 { 1525 struct deva *da; 1526 struct devi *i; 1527 1528 if (dev->d_ispseudo) { 1529 if (dev->d_ihead != NULL) 1530 return 1; 1531 else if (state != DEVI_IGNORED) 1532 return 0; 1533 if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) 1534 return 0; 1535 return (i->i_level >= level); 1536 } 1537 1538 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 1539 for (i = da->d_ihead; i != NULL; i = i->i_asame) 1540 if ((i->i_active == DEVI_ACTIVE || 1541 i->i_active == state) && 1542 (unit == WILD || unit == i->i_unit || 1543 i->i_unit == STAR)) 1544 return 1; 1545 1546 if (state == DEVI_IGNORED) { 1547 struct dhdi_params dhdi = { dev, unit, level }; 1548 /* also check dead devices */ 1549 return ht_enumerate(deaddevitab, devbase_has_dead_instances, 1550 &dhdi); 1551 } 1552 1553 return 0; 1554 } 1555 1556 /* 1557 * check_dead_devi(), used with ht_enumerate, checks if any of the removed 1558 * device instances would have been a valid instance considering the devbase, 1559 * the parent device and the interface attribute. 1560 * 1561 * In other words, for a non-active device, it checks if children would be 1562 * actual orphans or the result of a negative statement in the config file. 1563 */ 1564 1565 struct cdd_params { 1566 struct devbase *d; 1567 struct attr *at; 1568 struct devbase *parent; 1569 }; 1570 1571 static int 1572 check_dead_devi(const char *key, void *value, void *aux) 1573 { 1574 struct cdd_params *cdd = aux; 1575 struct devi *i = value; 1576 struct pspec *p; 1577 1578 if (i->i_base != cdd->d) 1579 return 0; 1580 1581 for (; i != NULL; i = i->i_alias) { 1582 p = i->i_pspec; 1583 if ((p == NULL && cdd->at == NULL) || 1584 (p != NULL && p->p_iattr == cdd->at && 1585 (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { 1586 if (p != NULL && 1587 !devbase_has_any_instance(cdd->parent, p->p_atunit, 1588 DEVI_IGNORED, i->i_level)) 1589 return 0; 1590 else 1591 return 1; 1592 } 1593 } 1594 return 0; 1595 } 1596 1597 static void 1598 do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, 1599 int state) 1600 { 1601 struct nvlist *nv, *nv1; 1602 struct attr *a; 1603 struct devi *i, *j = NULL; 1604 struct pspec *p; 1605 int active = 0; 1606 1607 /* 1608 * A pseudo-device will always attach at root, and if it has an 1609 * instance (it cannot have more than one), it is enough to consider 1610 * it active, as there is no real attachment. 1611 * 1612 * A pseudo device can never be marked DEVI_IGNORED. 1613 */ 1614 if (d->d_ispseudo) { 1615 if (d->d_ihead != NULL) 1616 d->d_ihead->i_active = active = DEVI_ACTIVE; 1617 else { 1618 if (ht_lookup(deaddevitab, d->d_name) != NULL) 1619 active = DEVI_IGNORED; 1620 else 1621 return; 1622 } 1623 } else { 1624 int seen = 0; 1625 1626 for (i = d->d_ihead; i != NULL; i = i->i_bsame) { 1627 for (j = i; j != NULL; j = j->i_alias) { 1628 p = j->i_pspec; 1629 if ((p == NULL && at == NULL) || 1630 (p != NULL && p->p_iattr == at && 1631 (p->p_atdev == NULL || 1632 p->p_atdev == parent))) { 1633 if (p != NULL && 1634 !devbase_has_any_instance(parent, 1635 p->p_atunit, state, j->i_level)) 1636 continue; 1637 /* 1638 * There are Fry-like devices which can 1639 * be their own grand-parent (or even 1640 * parent, like uhub). We don't want 1641 * to loop, so if we've already reached 1642 * an instance for one reason or 1643 * another, stop there. 1644 */ 1645 if (j->i_active == DEVI_ACTIVE || 1646 j->i_active == state) { 1647 /* 1648 * Device has already been 1649 * seen. However it might 1650 * have siblings who still 1651 * have to be activated or 1652 * orphaned. 1653 */ 1654 seen = 1; 1655 continue; 1656 } 1657 j->i_active = active = state; 1658 if (p != NULL) 1659 p->p_active = state; 1660 } 1661 } 1662 } 1663 /* 1664 * If we've been there but have made no change, stop. 1665 */ 1666 if (seen && !active) 1667 return; 1668 if (!active) { 1669 struct cdd_params cdd = { d, at, parent }; 1670 /* Look for a matching dead devi */ 1671 if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) && 1672 d != parent) 1673 /* 1674 * That device had its instances removed. 1675 * Continue the loop marking descendants 1676 * with DEVI_IGNORED instead of DEVI_ACTIVE. 1677 * 1678 * There is one special case for devices that 1679 * are their own parent: if that instance is 1680 * removed (e.g., no uhub* at uhub?), we don't 1681 * have to continue looping. 1682 */ 1683 active = DEVI_IGNORED; 1684 else 1685 return; 1686 } 1687 } 1688 1689 for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { 1690 a = nv->nv_ptr; 1691 for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) 1692 do_kill_orphans(nv1->nv_ptr, a, d, active); 1693 } 1694 } 1695 1696 static int 1697 /*ARGSUSED*/ 1698 kill_orphans_cb(const char *key, void *value, void *aux) 1699 { 1700 do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); 1701 return 0; 1702 } 1703 1704 static void 1705 kill_orphans(void) 1706 { 1707 ht_enumerate(devroottab, kill_orphans_cb, NULL); 1708 } 1709