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