1 /* $NetBSD: main.c,v 1.36 2009/03/13 20:44:59 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\ 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 **nextcndmkopt; 99 static struct nvlist **nextfsopt; 100 101 static void usage(void) __dead; 102 static void dependopts(void); 103 static void do_depend(struct nvlist *); 104 static void stop(void); 105 static int do_option(struct hashtab *, struct nvlist ***, 106 const char *, const char *, const char *); 107 static int undo_option(struct hashtab *, struct nvlist **, 108 struct nvlist ***, const char *, const char *); 109 static int crosscheck(void); 110 static int badstar(void); 111 int main(int, char **); 112 static int mksymlinks(void); 113 static int mkident(void); 114 static int devbase_has_dead_instances(const char *, void *, void *); 115 static int devbase_has_any_instance(struct devbase *, int, int, int); 116 static int check_dead_devi(const char *, void *, void *); 117 static void kill_orphans(void); 118 static void do_kill_orphans(struct devbase *, struct attr *, 119 struct devbase *, int); 120 static int kill_orphans_cb(const char *, void *, void *); 121 static int cfcrosscheck(struct config *, const char *, struct nvlist *); 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 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 nextcndmkopt = &condmkoptions; 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() || errors) 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(struct nvlist *cnd, const char *name, const char *value) 951 { 952 struct nvlist *nv; 953 954 nv = newnv(name, value, cnd, 0, NULL); 955 *nextcndmkopt = nv; 956 nextcndmkopt = &nv->nv_next; 957 } 958 959 /* 960 * Add a name=value pair to an option list. The value may be NULL. 961 */ 962 static int 963 do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 964 const char *value, const char *type) 965 { 966 struct nvlist *nv; 967 968 /* assume it will work */ 969 nv = newnv(name, value, NULL, 0, NULL); 970 if (ht_insert(ht, name, nv) == 0) { 971 **nppp = nv; 972 *nppp = &nv->nv_next; 973 return (0); 974 } 975 976 /* oops, already got that option */ 977 nvfree(nv); 978 if ((nv = ht_lookup(ht, name)) == NULL) 979 panic("do_option"); 980 if (nv->nv_str != NULL && !OPT_FSOPT(name)) 981 cfgerror("already have %s `%s=%s'", type, name, nv->nv_str); 982 else 983 cfgerror("already have %s `%s'", type, name); 984 return (1); 985 } 986 987 /* 988 * Remove a name from a hash table, 989 * and optionally, a name=value pair from an option list. 990 */ 991 static int 992 undo_option(struct hashtab *ht, struct nvlist **npp, 993 struct nvlist ***next, const char *name, const char *type) 994 { 995 struct nvlist *nv; 996 997 if (ht_remove(ht, name)) { 998 cfgerror("%s `%s' is not defined", type, name); 999 return (1); 1000 } 1001 if (npp == NULL) 1002 return (0); 1003 1004 for ( ; *npp != NULL; npp = &(*npp)->nv_next) { 1005 if ((*npp)->nv_name != name) 1006 continue; 1007 if (next != NULL && *next == &(*npp)->nv_next) 1008 *next = npp; 1009 nv = (*npp)->nv_next; 1010 nvfree(*npp); 1011 *npp = nv; 1012 return (0); 1013 } 1014 panic("%s `%s' is not defined in nvlist", type, name); 1015 return (1); 1016 } 1017 1018 /* 1019 * Return true if there is at least one instance of the given unit 1020 * on the given device attachment (or any units, if unit == WILD). 1021 */ 1022 int 1023 deva_has_instances(struct deva *deva, int unit) 1024 { 1025 struct devi *i; 1026 1027 for (i = deva->d_ihead; i != NULL; i = i->i_asame) 1028 if (i->i_active == DEVI_ACTIVE && 1029 (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) 1030 return (1); 1031 return (0); 1032 } 1033 1034 /* 1035 * Return true if there is at least one instance of the given unit 1036 * on the given base (or any units, if unit == WILD). 1037 */ 1038 int 1039 devbase_has_instances(struct devbase *dev, int unit) 1040 { 1041 struct deva *da; 1042 1043 /* 1044 * Pseudo-devices are a little special. We consider them 1045 * to have instances only if they are both: 1046 * 1047 * 1. Included in this kernel configuration. 1048 * 1049 * 2. Be declared "defpseudodev". 1050 */ 1051 if (dev->d_ispseudo) { 1052 return ((ht_lookup(devitab, dev->d_name) != NULL) 1053 && (dev->d_ispseudo > 1)); 1054 } 1055 1056 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 1057 if (deva_has_instances(da, unit)) 1058 return (1); 1059 return (0); 1060 } 1061 1062 static int 1063 cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 1064 { 1065 struct devbase *dev; 1066 struct devi *pd; 1067 int errs, devunit; 1068 1069 if (maxpartitions <= 0) 1070 panic("cfcrosscheck"); 1071 1072 for (errs = 0; nv != NULL; nv = nv->nv_next) { 1073 if (nv->nv_name == NULL) 1074 continue; 1075 dev = ht_lookup(devbasetab, nv->nv_name); 1076 if (dev == NULL) 1077 panic("cfcrosscheck(%s)", nv->nv_name); 1078 if (has_attr(dev->d_attrs, s_ifnet)) 1079 devunit = nv->nv_ifunit; /* XXX XXX XXX */ 1080 else 1081 devunit = (int)(minor(nv->nv_num) / maxpartitions); 1082 if (devbase_has_instances(dev, devunit)) 1083 continue; 1084 if (devbase_has_instances(dev, STAR) && 1085 devunit >= dev->d_umax) 1086 continue; 1087 TAILQ_FOREACH(pd, &allpseudo, i_next) { 1088 if (pd->i_base == dev && devunit < dev->d_umax && 1089 devunit >= 0) 1090 goto loop; 1091 } 1092 (void)fprintf(stderr, 1093 "%s:%d: %s says %s on %s, but there's no %s\n", 1094 conffile, cf->cf_lineno, 1095 cf->cf_name, what, nv->nv_str, nv->nv_str); 1096 errs++; 1097 loop: 1098 ; 1099 } 1100 return (errs); 1101 } 1102 1103 /* 1104 * Cross-check the configuration: make sure that each target device 1105 * or attribute (`at foo[0*?]') names at least one real device. Also 1106 * see that the root and dump devices for all configurations are there. 1107 */ 1108 int 1109 crosscheck(void) 1110 { 1111 struct config *cf; 1112 int errs; 1113 1114 errs = 0; 1115 if (TAILQ_EMPTY(&allcf)) { 1116 warnx("%s has no configurations!", conffile); 1117 errs++; 1118 } 1119 TAILQ_FOREACH(cf, &allcf, cf_next) { 1120 if (cf->cf_root != NULL) { /* i.e., not root on ? */ 1121 errs += cfcrosscheck(cf, "root", cf->cf_root); 1122 errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 1123 } 1124 } 1125 return (errs); 1126 } 1127 1128 /* 1129 * Check to see if there is a *'d unit with a needs-count file. 1130 */ 1131 int 1132 badstar(void) 1133 { 1134 struct devbase *d; 1135 struct deva *da; 1136 struct devi *i; 1137 int errs, n; 1138 1139 errs = 0; 1140 TAILQ_FOREACH(d, &allbases, d_next) { 1141 for (da = d->d_ahead; da != NULL; da = da->d_bsame) 1142 for (i = da->d_ihead; i != NULL; i = i->i_asame) { 1143 if (i->i_unit == STAR) 1144 goto aybabtu; 1145 } 1146 continue; 1147 aybabtu: 1148 if (ht_lookup(needcnttab, d->d_name)) { 1149 warnx("%s's cannot be *'d until its driver is fixed", 1150 d->d_name); 1151 errs++; 1152 continue; 1153 } 1154 for (n = 0; i != NULL; i = i->i_alias) 1155 if (!i->i_collapsed) 1156 n++; 1157 if (n < 1) 1158 panic("badstar() n<1"); 1159 } 1160 return (errs); 1161 } 1162 1163 /* 1164 * Verify/create builddir if necessary, change to it, and verify srcdir. 1165 * This will be called when we see the first include. 1166 */ 1167 void 1168 setupdirs(void) 1169 { 1170 struct stat st; 1171 1172 /* srcdir must be specified if builddir is not specified or if 1173 * no configuration filename was specified. */ 1174 if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 1175 cfgerror("source directory must be specified"); 1176 exit(1); 1177 } 1178 1179 if (Lflag) { 1180 if (srcdir == NULL) 1181 srcdir = "../../.."; 1182 return; 1183 } 1184 1185 if (srcdir == NULL) 1186 srcdir = "../../../.."; 1187 if (builddir == NULL) 1188 builddir = defbuilddir; 1189 1190 if (stat(builddir, &st) == -1) { 1191 if (mkdir(builddir, 0777) == -1) 1192 errx(EXIT_FAILURE, "cannot create %s", builddir); 1193 } else if (!S_ISDIR(st.st_mode)) 1194 errx(EXIT_FAILURE, "%s is not a directory", builddir); 1195 if (chdir(builddir) == -1) 1196 err(EXIT_FAILURE, "cannot change to %s", builddir); 1197 if (stat(srcdir, &st) == -1) 1198 err(EXIT_FAILURE, "cannot stat %s", srcdir); 1199 if (!S_ISDIR(st.st_mode)) 1200 errx(EXIT_FAILURE, "%s is not a directory", srcdir); 1201 } 1202 1203 /* 1204 * Write identifier from "ident" directive into file, for 1205 * newvers.sh to pick it up. 1206 */ 1207 int 1208 mkident(void) 1209 { 1210 FILE *fp; 1211 int error = 0; 1212 1213 (void)unlink("ident"); 1214 1215 if (ident == NULL) 1216 return (0); 1217 1218 if ((fp = fopen("ident", "w")) == NULL) { 1219 warn("cannot write ident"); 1220 return (1); 1221 } 1222 if (vflag) 1223 (void)printf("using ident '%s'\n", ident); 1224 fprintf(fp, "%s\n", ident); 1225 fflush(fp); 1226 if (ferror(fp)) 1227 error = 1; 1228 (void)fclose(fp); 1229 1230 return error; 1231 } 1232 1233 void 1234 logconfig_start(void) 1235 { 1236 extern FILE *yyin; 1237 char line[1024]; 1238 const char *tmpdir; 1239 struct stat st; 1240 int fd; 1241 1242 if (yyin == NULL || fstat(fileno(yyin), &st) == -1) 1243 return; 1244 cfgtime = st.st_mtime; 1245 1246 tmpdir = getenv("TMPDIR"); 1247 if (tmpdir == NULL) 1248 tmpdir = _PATH_TMP; 1249 (void)snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); 1250 if ((fd = mkstemp(line)) == -1 || 1251 (cfg = fdopen(fd, "r+")) == NULL) { 1252 if (fd != -1) { 1253 (void)unlink(line); 1254 (void)close(fd); 1255 } 1256 cfg = NULL; 1257 return; 1258 } 1259 (void)unlink(line); 1260 1261 (void)fprintf(cfg, "#include <sys/cdefs.h>\n\n"); 1262 (void)fprintf(cfg, "#include \"opt_config.h\"\n"); 1263 (void)fprintf(cfg, "\n"); 1264 (void)fprintf(cfg, "/*\n"); 1265 (void)fprintf(cfg, " * Add either (or both) of\n"); 1266 (void)fprintf(cfg, " *\n"); 1267 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); 1268 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); 1269 (void)fprintf(cfg, " *\n"); 1270 (void)fprintf(cfg, 1271 " * to your kernel config file to embed it in the resulting\n"); 1272 (void)fprintf(cfg, 1273 " * kernel. The latter option does not include files that are\n"); 1274 (void)fprintf(cfg, 1275 " * included (recursively) by your config file. The embedded\n"); 1276 (void)fprintf(cfg, 1277 " * data be extracted by using the command:\n"); 1278 (void)fprintf(cfg, " *\n"); 1279 (void)fprintf(cfg, 1280 " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); 1281 (void)fprintf(cfg, " */\n"); 1282 (void)fprintf(cfg, "\n"); 1283 (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); 1284 (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", 1285 LOGCONFIG_LARGE, LOGCONFIG_SMALL); 1286 (void)fprintf(cfg, "static const char config[] __used =\n\n"); 1287 1288 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 1289 (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", 1290 conffile); 1291 (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); 1292 1293 logconfig_include(yyin, NULL); 1294 1295 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 1296 (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", 1297 conffile); 1298 1299 rewind(yyin); 1300 } 1301 1302 void 1303 logconfig_include(FILE *cf, const char *filename) 1304 { 1305 char line[1024], in[2048], *out; 1306 struct stat st; 1307 int missingeol; 1308 1309 if (!cfg) 1310 return; 1311 1312 missingeol = 0; 1313 if (fstat(fileno(cf), &st) == -1) 1314 return; 1315 if (cfgtime < st.st_mtime) 1316 cfgtime = st.st_mtime; 1317 1318 if (filename) 1319 (void)fprintf(cfg, 1320 "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", 1321 filename); 1322 while (fgets(line, sizeof(line), cf) != NULL) { 1323 missingeol = 1; 1324 (void)fprintf(cfg, "\"_CFG_"); 1325 if (filename) 1326 (void)fprintf(cfg, "###> "); 1327 strvis(in, line, VIS_TAB); 1328 for (out = in; *out; out++) 1329 switch (*out) { 1330 case '\n': 1331 (void)fprintf(cfg, "\\n\"\n"); 1332 missingeol = 0; 1333 break; 1334 case '"': case '\\': 1335 (void)fputc('\\', cfg); 1336 /* FALLTHROUGH */ 1337 default: 1338 (void)fputc(*out, cfg); 1339 break; 1340 } 1341 } 1342 if (missingeol) { 1343 (void)fprintf(cfg, "\\n\"\n"); 1344 warnx("%s: newline missing at EOF", 1345 filename != NULL ? filename : conffile); 1346 } 1347 if (filename) 1348 (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", 1349 filename); 1350 1351 rewind(cf); 1352 } 1353 1354 void 1355 logconfig_end(void) 1356 { 1357 char line[1024]; 1358 FILE *fp; 1359 struct stat st; 1360 1361 if (!cfg) 1362 return; 1363 1364 (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); 1365 (void)fprintf(cfg, ";\n"); 1366 (void)fprintf(cfg, "#endif /* %s || %s */\n", 1367 LOGCONFIG_LARGE, LOGCONFIG_SMALL); 1368 (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); 1369 fflush(cfg); 1370 if (ferror(cfg)) 1371 err(EXIT_FAILURE, "write to temporary file for config.h failed"); 1372 rewind(cfg); 1373 1374 if (stat("config_file.h", &st) != -1) { 1375 if (cfgtime < st.st_mtime) { 1376 fclose(cfg); 1377 return; 1378 } 1379 } 1380 1381 fp = fopen("config_file.h", "w"); 1382 if (!fp) 1383 err(EXIT_FAILURE, "cannot open \"config.h\""); 1384 1385 while (fgets(line, sizeof(line), cfg) != NULL) 1386 fputs(line, fp); 1387 fflush(fp); 1388 if (ferror(fp)) 1389 err(EXIT_FAILURE, "write to \"config.h\" failed"); 1390 fclose(fp); 1391 fclose(cfg); 1392 } 1393 1394 const char * 1395 strtolower(const char *name) 1396 { 1397 const char *n; 1398 char *p, low[500]; 1399 unsigned char c; 1400 1401 for (n = name, p = low; (c = *n) != '\0'; n++) 1402 *p++ = isupper(c) ? tolower(c) : c; 1403 *p = 0; 1404 return (intern(low)); 1405 } 1406 1407 static int 1408 is_elf(const char *file) 1409 { 1410 int kernel; 1411 char hdr[4]; 1412 1413 kernel = open(file, O_RDONLY); 1414 if (kernel == -1) 1415 err(EXIT_FAILURE, "cannot open %s", file); 1416 if (read(kernel, hdr, 4) != 4) 1417 err(EXIT_FAILURE, "Cannot read from %s", file); 1418 (void)close(kernel); 1419 1420 return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; 1421 } 1422 1423 static int 1424 extract_config(const char *kname, const char *cname, int cfd) 1425 { 1426 char *ptr; 1427 int found, kfd, i; 1428 struct stat st; 1429 1430 found = 0; 1431 1432 /* mmap(2) binary kernel */ 1433 kfd = open(conffile, O_RDONLY); 1434 if (kfd == -1) 1435 err(EXIT_FAILURE, "cannot open %s", kname); 1436 if (fstat(kfd, &st) == -1) 1437 err(EXIT_FAILURE, "cannot stat %s", kname); 1438 ptr = mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, 1439 kfd, 0); 1440 if (ptr == MAP_FAILED) 1441 err(EXIT_FAILURE, "cannot mmap %s", kname); 1442 1443 /* Scan mmap(2)'ed region, extracting kernel configuration */ 1444 for (i = 0; i < st.st_size; i++) { 1445 if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, 1446 "_CFG_", 5) == 0) { 1447 /* Line found */ 1448 char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; 1449 int j; 1450 1451 found = 1; 1452 1453 oldptr = (ptr += 5); 1454 while (*ptr != '\n' && *ptr != '\0') 1455 ptr++; 1456 if (ptr - oldptr > LINE_MAX) 1457 errx(EXIT_FAILURE, "line too long"); 1458 i += ptr - oldptr + 5; 1459 (void)memcpy(line, oldptr, (size_t)(ptr - oldptr)); 1460 line[ptr - oldptr] = '\0'; 1461 j = strunvis(uline, line); 1462 if (j == -1) 1463 errx(EXIT_FAILURE, "unvis: invalid " 1464 "encoded sequence"); 1465 uline[j] = '\n'; 1466 if (write(cfd, uline, (size_t)j + 1) == -1) 1467 err(EXIT_FAILURE, "cannot write to %s", cname); 1468 } else 1469 ptr++; 1470 } 1471 1472 (void)close(kfd); 1473 1474 return found; 1475 } 1476 1477 struct dhdi_params { 1478 struct devbase *d; 1479 int unit; 1480 int level; 1481 }; 1482 1483 static int 1484 devbase_has_dead_instances(const char *key, void *value, void *aux) 1485 { 1486 struct devi *i; 1487 struct dhdi_params *dhdi = aux; 1488 1489 for (i = value; i != NULL; i = i->i_alias) 1490 if (i->i_base == dhdi->d && 1491 (dhdi->unit == WILD || dhdi->unit == i->i_unit || 1492 i->i_unit == STAR) && 1493 i->i_level >= dhdi->level) 1494 return 1; 1495 return 0; 1496 } 1497 1498 /* 1499 * This is almost the same as devbase_has_instances, except it 1500 * may have special considerations regarding ignored instances. 1501 */ 1502 1503 static int 1504 devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) 1505 { 1506 struct deva *da; 1507 struct devi *i; 1508 1509 if (dev->d_ispseudo) { 1510 if (dev->d_ihead != NULL) 1511 return 1; 1512 else if (state != DEVI_IGNORED) 1513 return 0; 1514 if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) 1515 return 0; 1516 return (i->i_level >= level); 1517 } 1518 1519 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 1520 for (i = da->d_ihead; i != NULL; i = i->i_asame) 1521 if ((i->i_active == DEVI_ACTIVE || 1522 i->i_active == state) && 1523 (unit == WILD || unit == i->i_unit || 1524 i->i_unit == STAR)) 1525 return 1; 1526 1527 if (state == DEVI_IGNORED) { 1528 struct dhdi_params dhdi = { dev, unit, level }; 1529 /* also check dead devices */ 1530 return ht_enumerate(deaddevitab, devbase_has_dead_instances, 1531 &dhdi); 1532 } 1533 1534 return 0; 1535 } 1536 1537 /* 1538 * check_dead_devi(), used with ht_enumerate, checks if any of the removed 1539 * device instances would have been a valid instance considering the devbase, 1540 * the parent device and the interface attribute. 1541 * 1542 * In other words, for a non-active device, it checks if children would be 1543 * actual orphans or the result of a negative statement in the config file. 1544 */ 1545 1546 struct cdd_params { 1547 struct devbase *d; 1548 struct attr *at; 1549 struct devbase *parent; 1550 }; 1551 1552 static int 1553 check_dead_devi(const char *key, void *value, void *aux) 1554 { 1555 struct cdd_params *cdd = aux; 1556 struct devi *i = value; 1557 struct pspec *p; 1558 1559 if (i->i_base != cdd->d) 1560 return 0; 1561 1562 for (; i != NULL; i = i->i_alias) { 1563 p = i->i_pspec; 1564 if ((p == NULL && cdd->at == NULL) || 1565 (p != NULL && p->p_iattr == cdd->at && 1566 (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { 1567 if (p != NULL && 1568 !devbase_has_any_instance(cdd->parent, p->p_atunit, 1569 DEVI_IGNORED, i->i_level)) 1570 return 0; 1571 else 1572 return 1; 1573 } 1574 } 1575 return 0; 1576 } 1577 1578 static void 1579 do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, 1580 int state) 1581 { 1582 struct nvlist *nv, *nv1; 1583 struct attr *a; 1584 struct devi *i, *j = NULL; 1585 struct pspec *p; 1586 int active = 0; 1587 1588 /* 1589 * A pseudo-device will always attach at root, and if it has an 1590 * instance (it cannot have more than one), it is enough to consider 1591 * it active, as there is no real attachment. 1592 * 1593 * A pseudo device can never be marked DEVI_IGNORED. 1594 */ 1595 if (d->d_ispseudo) { 1596 if (d->d_ihead != NULL) 1597 d->d_ihead->i_active = active = DEVI_ACTIVE; 1598 else { 1599 if (ht_lookup(deaddevitab, d->d_name) != NULL) 1600 active = DEVI_IGNORED; 1601 else 1602 return; 1603 } 1604 } else { 1605 int seen = 0; 1606 1607 for (i = d->d_ihead; i != NULL; i = i->i_bsame) { 1608 for (j = i; j != NULL; j = j->i_alias) { 1609 p = j->i_pspec; 1610 if ((p == NULL && at == NULL) || 1611 (p != NULL && p->p_iattr == at && 1612 (p->p_atdev == NULL || 1613 p->p_atdev == parent))) { 1614 if (p != NULL && 1615 !devbase_has_any_instance(parent, 1616 p->p_atunit, state, j->i_level)) 1617 continue; 1618 /* 1619 * There are Fry-like devices which can 1620 * be their own grand-parent (or even 1621 * parent, like uhub). We don't want 1622 * to loop, so if we've already reached 1623 * an instance for one reason or 1624 * another, stop there. 1625 */ 1626 if (j->i_active == DEVI_ACTIVE || 1627 j->i_active == state) { 1628 /* 1629 * Device has already been 1630 * seen. However it might 1631 * have siblings who still 1632 * have to be activated or 1633 * orphaned. 1634 */ 1635 seen = 1; 1636 continue; 1637 } 1638 j->i_active = active = state; 1639 if (p != NULL) 1640 p->p_active = state; 1641 } 1642 } 1643 } 1644 /* 1645 * If we've been there but have made no change, stop. 1646 */ 1647 if (seen && !active) 1648 return; 1649 if (!active) { 1650 struct cdd_params cdd = { d, at, parent }; 1651 /* Look for a matching dead devi */ 1652 if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) && 1653 d != parent) 1654 /* 1655 * That device had its instances removed. 1656 * Continue the loop marking descendants 1657 * with DEVI_IGNORED instead of DEVI_ACTIVE. 1658 * 1659 * There is one special case for devices that 1660 * are their own parent: if that instance is 1661 * removed (e.g., no uhub* at uhub?), we don't 1662 * have to continue looping. 1663 */ 1664 active = DEVI_IGNORED; 1665 else 1666 return; 1667 } 1668 } 1669 1670 for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { 1671 a = nv->nv_ptr; 1672 for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) 1673 do_kill_orphans(nv1->nv_ptr, a, d, active); 1674 } 1675 } 1676 1677 static int 1678 /*ARGSUSED*/ 1679 kill_orphans_cb(const char *key, void *value, void *aux) 1680 { 1681 do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); 1682 return 0; 1683 } 1684 1685 static void 1686 kill_orphans(void) 1687 { 1688 ht_enumerate(devroottab, kill_orphans_cb, NULL); 1689 } 1690