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