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