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