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