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