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