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