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