1 /* $NetBSD: main.c,v 1.1 2005/06/05 18:19:53 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratories. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: @(#)main.c 8.1 (Berkeley) 6/6/93 41 */ 42 43 #if HAVE_NBTOOL_CONFIG_H 44 #include "nbtool_config.h" 45 #endif 46 47 #ifndef MAKE_BOOTSTRAP 48 #include <sys/cdefs.h> 49 #define COPYRIGHT(x) __COPYRIGHT(x) 50 #else 51 #define COPYRIGHT(x) static const char copyright[] = x 52 #endif 53 54 #ifndef lint 55 COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\ 56 The Regents of the University of California. All rights reserved.\n"); 57 #endif /* not lint */ 58 59 #include <sys/types.h> 60 #include <sys/stat.h> 61 #include <sys/param.h> 62 #include <sys/mman.h> 63 #include <paths.h> 64 #include <ctype.h> 65 #include <errno.h> 66 #include <fcntl.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <unistd.h> 71 #include "defs.h" 72 #include "sem.h" 73 #include <vis.h> 74 75 #ifndef LINE_MAX 76 #define LINE_MAX 1024 77 #endif 78 79 int vflag; /* verbose output */ 80 int Pflag; /* pack locators */ 81 82 int yyparse(void); 83 84 #ifndef MAKE_BOOTSTRAP 85 extern int yydebug; 86 #endif 87 88 static struct hashtab *mkopttab; 89 static struct nvlist **nextopt; 90 static struct nvlist **nextmkopt; 91 static struct nvlist **nextappmkopt; 92 static struct nvlist **nextfsopt; 93 94 static void usage(void); 95 static void dependopts(void); 96 static void do_depend(struct nvlist *); 97 static void stop(void); 98 static int do_option(struct hashtab *, struct nvlist ***, 99 const char *, const char *, const char *); 100 static int undo_option(struct hashtab *, struct nvlist **, 101 struct nvlist ***, const char *, const char *); 102 static int crosscheck(void); 103 static int badstar(void); 104 int main(int, char **); 105 static int mksymlinks(void); 106 static int mkident(void); 107 static int hasparent(struct devi *); 108 static int cfcrosscheck(struct config *, const char *, struct nvlist *); 109 static const char *strtolower(const char *); 110 void defopt(struct hashtab *ht, const char *fname, 111 struct nvlist *opts, struct nvlist *deps); 112 113 #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" 114 #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" 115 116 static void logconfig_start(void); 117 static void logconfig_end(void); 118 static FILE *cfg; 119 static time_t cfgtime; 120 121 static int is_elf(const char *); 122 static int extract_config(const char *, const char *, int); 123 124 int badfilename(const char *fname); 125 126 const char *progname; 127 128 int 129 main(int argc, char **argv) 130 { 131 char *p, cname[20]; 132 const char *last_component; 133 int pflag, xflag, ch, removeit; 134 135 setprogname(argv[0]); 136 137 pflag = 0; 138 xflag = 0; 139 while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) { 140 switch (ch) { 141 142 #ifndef MAKE_BOOTSTRAP 143 case 'D': 144 yydebug = 1; 145 break; 146 #endif 147 148 case 'P': 149 Pflag = 1; 150 break; 151 152 case 'g': 153 /* 154 * In addition to DEBUG, you probably wanted to 155 * set "options KGDB" and maybe others. We could 156 * do that for you, but you really should just 157 * put them in the config file. 158 */ 159 (void)fprintf(stderr, 160 "config: -g is obsolete (use makeoptions DEBUG=\"-g\")\n"); 161 usage(); 162 163 case 'p': 164 /* 165 * Essentially the same as makeoptions PROF="-pg", 166 * but also changes the path from ../../compile/FOO 167 * to ../../compile/FOO.PROF; i.e., compile a 168 * profiling kernel based on a typical "regular" 169 * kernel. 170 * 171 * Note that if you always want profiling, you 172 * can (and should) use a "makeoptions" line. 173 */ 174 pflag = 1; 175 break; 176 177 case 'v': 178 vflag = 1; 179 break; 180 181 case 'b': 182 builddir = optarg; 183 break; 184 185 case 's': 186 srcdir = optarg; 187 break; 188 189 case 'x': 190 xflag = 1; 191 break; 192 193 case '?': 194 default: 195 usage(); 196 } 197 } 198 199 argc -= optind; 200 argv += optind; 201 if (argc > 1) { 202 usage(); 203 } 204 205 if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag || 206 vflag)) { 207 (void)fprintf(stderr, "config: -x must be used alone\n"); 208 exit(1); 209 } 210 211 if (xflag) { 212 #ifdef __NetBSD__ 213 conffile = (argc == 1) ? argv[0] : _PATH_UNIX; 214 #else 215 if (argc == 0) { 216 (void)fprintf(stderr, "config: no kernel supplied\n"); 217 exit(1); 218 } 219 #endif 220 if (!is_elf(conffile)) { 221 (void)fprintf(stderr, 222 "config: %s: not a binary kernel\n", 223 conffile); 224 exit(1); 225 } 226 if (!extract_config(conffile, "stdout", STDOUT_FILENO)) { 227 (void)fprintf(stderr, 228 "config: %s does not contain embedded " 229 "configuration data\n", conffile); 230 exit(2); 231 } 232 exit(0); 233 } 234 235 conffile = (argc == 1) ? argv[0] : "CONFIG"; 236 if (firstfile(conffile)) { 237 (void)fprintf(stderr, "config: cannot read %s: %s\n", 238 conffile, strerror(errno)); 239 exit(2); 240 } 241 242 /* 243 * Init variables. 244 */ 245 minmaxusers = 1; 246 maxmaxusers = 10000; 247 initintern(); 248 initfiles(); 249 initsem(); 250 ident = NULL; 251 devbasetab = ht_new(); 252 devatab = ht_new(); 253 devitab = ht_new(); 254 selecttab = ht_new(); 255 needcnttab = ht_new(); 256 opttab = ht_new(); 257 mkopttab = ht_new(); 258 condmkopttab = ht_new(); 259 fsopttab = ht_new(); 260 deffstab = ht_new(); 261 defopttab = ht_new(); 262 defparamtab = ht_new(); 263 defflagtab = ht_new(); 264 optfiletab = ht_new(); 265 bdevmtab = ht_new(); 266 maxbdevm = 0; 267 cdevmtab = ht_new(); 268 maxcdevm = 0; 269 nextopt = &options; 270 nextmkopt = &mkoptions; 271 nextappmkopt = &appmkoptions; 272 nextfsopt = &fsoptions; 273 274 /* 275 * Handle profiling (must do this before we try to create any 276 * files). 277 */ 278 last_component = strrchr(conffile, '/'); 279 last_component = (last_component) ? last_component + 1 : conffile; 280 if (pflag) { 281 p = emalloc(strlen(last_component) + 17); 282 (void)sprintf(p, "../compile/%s.PROF", last_component); 283 (void)addmkoption(intern("PROF"), "-pg"); 284 (void)addoption(intern("GPROF"), NULL); 285 } else { 286 p = emalloc(strlen(last_component) + 13); 287 (void)sprintf(p, "../compile/%s", last_component); 288 } 289 defbuilddir = (argc == 0) ? "." : p; 290 291 removeit = 0; 292 if (is_elf(conffile)) { 293 const char *tmpdir; 294 int cfd; 295 296 if (builddir == NULL) { 297 (void)fprintf(stderr, 298 "config: build directory must be specified with " 299 "binary kernels\n"); 300 exit(1); 301 } 302 303 /* Open temporary configuration file */ 304 tmpdir = getenv("TMPDIR"); 305 if (tmpdir == NULL) 306 tmpdir = "/tmp"; 307 snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir); 308 cfd = mkstemp(cname); 309 if (cfd == -1) { 310 fprintf(stderr, "config: cannot create %s: %s", cname, 311 strerror(errno)); 312 exit(2); 313 } 314 315 printf("Using configuration data embedded in kernel...\n"); 316 if (!extract_config(conffile, cname, cfd)) { 317 (void)fprintf(stderr, 318 "config: %s does not contain embedded " 319 "configuration data\n", conffile); 320 exit(2); 321 } 322 323 removeit = 1; 324 close(cfd); 325 firstfile(cname); 326 } 327 328 /* 329 * Parse config file (including machine definitions). 330 */ 331 logconfig_start(); 332 if (yyparse()) 333 stop(); 334 logconfig_end(); 335 336 if (removeit) 337 unlink(cname); 338 339 /* 340 * Select devices and pseudo devices and their attributes 341 */ 342 fixdevis(); 343 344 /* 345 * Deal with option dependencies. 346 */ 347 dependopts(); 348 349 /* 350 * Fix (as in `set firmly in place') files. 351 */ 352 if (fixfiles()) 353 stop(); 354 355 /* 356 * Fix objects and libraries. 357 */ 358 if (fixobjects()) 359 stop(); 360 361 /* 362 * Fix device-majors. 363 */ 364 if (fixdevsw()) 365 stop(); 366 367 /* 368 * Perform cross-checking. 369 */ 370 if (maxusers == 0) { 371 if (defmaxusers) { 372 (void)printf("maxusers not specified; %d assumed\n", 373 defmaxusers); 374 maxusers = defmaxusers; 375 } else { 376 (void)fprintf(stderr, 377 "config: need \"maxusers\" line\n"); 378 errors++; 379 } 380 } 381 if (fsoptions == NULL) { 382 (void)fprintf(stderr, 383 "config: need at least one \"file-system\" line\n"); 384 errors++; 385 } 386 if (crosscheck() || errors) 387 stop(); 388 389 /* 390 * Squeeze things down and finish cross-checks (STAR checks must 391 * run after packing). 392 */ 393 pack(); 394 if (badstar()) 395 stop(); 396 397 /* 398 * Ready to go. Build all the various files. 399 */ 400 if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || 401 mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident()) 402 stop(); 403 (void)printf("Build directory is %s\n", builddir); 404 (void)printf("Don't forget to run \"make depend\"\n"); 405 exit(0); 406 } 407 408 static void 409 usage(void) 410 { 411 (void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] " 412 "[sysname]\n", stderr); 413 (void)fputs(" config -x [kernel-file]\n", stderr); 414 exit(1); 415 } 416 417 /* 418 * Set any options that are implied by other options. 419 */ 420 static void 421 dependopts(void) 422 { 423 struct nvlist *nv, *opt; 424 425 for (nv = options; nv != NULL; nv = nv->nv_next) { 426 if ((opt = find_declared_option(nv->nv_name)) != NULL) { 427 for (opt = opt->nv_ptr; opt != NULL; 428 opt = opt->nv_next) { 429 do_depend(opt); 430 } 431 } 432 } 433 } 434 435 static void 436 do_depend(struct nvlist *nv) 437 { 438 struct nvlist *nextnv; 439 struct attr *a; 440 441 if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) { 442 nv->nv_flags |= NV_DEPENDED; 443 /* 444 * If the dependency is an attribute, then just add 445 * it to the selecttab. 446 */ 447 if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) { 448 if (a->a_iattr) 449 panic("do_depend(%s): dep `%s' is an iattr", 450 nv->nv_name, a->a_name); 451 expandattr(a, selectattr); 452 } else { 453 if (ht_lookup(opttab, nv->nv_name) == NULL) 454 addoption(nv->nv_name, NULL); 455 if ((nextnv = 456 find_declared_option(nv->nv_name)) != NULL) 457 do_depend(nextnv->nv_ptr); 458 } 459 } 460 } 461 462 /* 463 * Make a symlink for "machine" so that "#include <machine/foo.h>" works, 464 * and for the machine's CPU architecture, so that works as well. 465 */ 466 static int 467 mksymlinks(void) 468 { 469 int ret; 470 char *p, buf[MAXPATHLEN]; 471 const char *q; 472 struct nvlist *nv; 473 474 snprintf(buf, sizeof(buf), "arch/%s/include", machine); 475 p = sourcepath(buf); 476 ret = unlink("machine"); 477 if (ret && errno != ENOENT) 478 (void)fprintf(stderr, "config: unlink(machine): %s\n", 479 strerror(errno)); 480 ret = symlink(p, "machine"); 481 if (ret) 482 (void)fprintf(stderr, "config: symlink(machine -> %s): %s\n", 483 p, strerror(errno)); 484 free(p); 485 486 if (machinearch != NULL) { 487 snprintf(buf, sizeof(buf), "arch/%s/include", machinearch); 488 p = sourcepath(buf); 489 q = machinearch; 490 } else { 491 p = estrdup("machine"); 492 q = machine; 493 } 494 ret = unlink(q); 495 if (ret && errno != ENOENT) 496 (void)fprintf(stderr, "config: unlink(%s): %s\n", 497 q, strerror(errno)); 498 ret = symlink(p, q); 499 if (ret) 500 (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n", 501 q, p, strerror(errno)); 502 free(p); 503 504 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { 505 q = nv->nv_name; 506 snprintf(buf, sizeof(buf), "arch/%s/include", q); 507 p = sourcepath(buf); 508 ret = unlink(q); 509 if (ret && errno != ENOENT) 510 (void)fprintf(stderr, "config: unlink(%s): %s\n", 511 q, strerror(errno)); 512 ret = symlink(p, q); 513 if (ret) 514 (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n", 515 q, p, strerror(errno)); 516 free(p); 517 } 518 519 return (ret); 520 } 521 522 static __dead void 523 stop(void) 524 { 525 (void)fprintf(stderr, "*** Stop.\n"); 526 exit(1); 527 } 528 529 /* 530 * Define one or more file systems. If file system options file name is 531 * specified, a preprocessor #define for that file system will be placed 532 * in that file. In this case, only one file system may be specified. 533 * Otherwise, no preprocessor #defines will be generated. 534 */ 535 void 536 deffilesystem(const char *fname, struct nvlist *fses) 537 { 538 struct nvlist *nv; 539 540 /* 541 * Mark these options as ones to skip when creating the Makefile. 542 */ 543 for (nv = fses; nv != NULL; nv = nv->nv_next) { 544 if (ht_insert(defopttab, nv->nv_name, nv)) { 545 error("file system or option `%s' already defined", 546 nv->nv_name); 547 return; 548 } 549 550 /* 551 * Also mark it as a valid file system, which may be 552 * used in "file-system" directives in the config 553 * file. 554 */ 555 if (ht_insert(deffstab, nv->nv_name, nv)) 556 panic("file system `%s' already in table?!", 557 nv->nv_name); 558 559 if (fname != NULL) { 560 /* 561 * Only one file system allowed in this case. 562 */ 563 if (nv->nv_next != NULL) { 564 error("only one file system per option " 565 "file may be specified"); 566 return; 567 } 568 569 if (ht_insert(optfiletab, fname, nv)) { 570 error("option file `%s' already exists", 571 fname); 572 return; 573 } 574 } 575 } 576 } 577 578 /* 579 * Sanity check a file name. 580 */ 581 int 582 badfilename(const char *fname) 583 { 584 const char *n; 585 586 /* 587 * We're putting multiple options into one file. Sanity 588 * check the file name. 589 */ 590 if (strchr(fname, '/') != NULL) { 591 error("option file name contains a `/'"); 592 return 1; 593 } 594 if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) { 595 error("option file name does not end in `.h'"); 596 return 1; 597 } 598 return 0; 599 } 600 601 602 /* 603 * Search for a defined option (defopt, filesystem, etc), and if found, 604 * return the option's struct nvlist. 605 */ 606 struct nvlist * 607 find_declared_option(const char *name) 608 { 609 struct nvlist *option = NULL; 610 611 if ((option = ht_lookup(defopttab, name)) != NULL || 612 (option = ht_lookup(defparamtab, name)) != NULL || 613 (option = ht_lookup(defflagtab, name)) != NULL || 614 (option = ht_lookup(fsopttab, name)) != NULL) { 615 return (option); 616 } 617 618 return (NULL); 619 } 620 621 622 /* 623 * Define one or more standard options. If an option file name is specified, 624 * place all options in one file with the specified name. Otherwise, create 625 * an option file for each option. 626 * record the option information in the specified table. 627 */ 628 void 629 defopt(struct hashtab *ht, const char *fname, struct nvlist *opts, 630 struct nvlist *deps) 631 { 632 struct nvlist *nv, *nextnv, *oldnv, *dep; 633 struct attr *a; 634 const char *name; 635 char buf[500]; 636 637 if (fname != NULL && badfilename(fname)) { 638 return; 639 } 640 641 /* 642 * Mark these options as ones to skip when creating the Makefile. 643 */ 644 for (nv = opts; nv != NULL; nv = nextnv) { 645 nextnv = nv->nv_next; 646 647 /* An option name can be declared at most once. */ 648 if (DEFINED_OPTION(nv->nv_name)) { 649 error("file system or option `%s' already defined", 650 nv->nv_name); 651 return; 652 } 653 654 if (ht_insert(ht, nv->nv_name, nv)) { 655 error("file system or option `%s' already defined", 656 nv->nv_name); 657 return; 658 } 659 660 if (fname == NULL) { 661 /* 662 * Each option will be going into its own file. 663 * Convert the option name to lower case. This 664 * lower case name will be used as the option 665 * file name. 666 */ 667 (void) snprintf(buf, sizeof(buf), "opt_%s.h", 668 strtolower(nv->nv_name)); 669 name = intern(buf); 670 } else { 671 name = fname; 672 } 673 674 /* Use nv_ptr to link any other options that are implied. */ 675 nv->nv_ptr = deps; 676 for (dep = deps; dep != NULL; dep = dep->nv_next) { 677 /* 678 * If the dependency is an attribute, it must not 679 * be an interface attribute. Otherwise, it must 680 * be a previously declared option. 681 */ 682 if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) { 683 if (a->a_iattr) 684 error("option `%s' dependency `%s' " 685 "is an interface attribute", 686 nv->nv_name, a->a_name); 687 } else if (find_declared_option(dep->nv_name) == NULL) { 688 error("option `%s' dependency `%s' " 689 "is an unknown option", 690 nv->nv_name, dep->nv_name); 691 } 692 } 693 694 /* 695 * Remove this option from the parameter list before adding 696 * it to the list associated with this option file. 697 */ 698 nv->nv_next = NULL; 699 700 /* 701 * Add this option file if we haven't seen it yet. 702 * Otherwise, append to the list of options already 703 * associated with this file. 704 */ 705 if ((oldnv = ht_lookup(optfiletab, name)) == NULL) { 706 (void)ht_insert(optfiletab, name, nv); 707 } else { 708 while (oldnv->nv_next != NULL) 709 oldnv = oldnv->nv_next; 710 oldnv->nv_next = nv; 711 } 712 } 713 } 714 715 /* 716 * Define one or more standard options. If an option file name is specified, 717 * place all options in one file with the specified name. Otherwise, create 718 * an option file for each option. 719 */ 720 void 721 defoption(const char *fname, struct nvlist *opts, struct nvlist *deps) 722 { 723 724 warn("The use of `defopt' is deprecated"); 725 defopt(defopttab, fname, opts, deps); 726 } 727 728 729 /* 730 * Define an option for which a value is required. 731 */ 732 void 733 defparam(const char *fname, struct nvlist *opts, struct nvlist *deps) 734 { 735 736 defopt(defparamtab, fname, opts, deps); 737 } 738 739 /* 740 * Define an option which must have a value, and which 741 * emits a "needs-flag" style output. 742 */ 743 void 744 defflag(const char *fname, struct nvlist *opts, struct nvlist *deps) 745 { 746 747 defopt(defflagtab, fname, opts, deps); 748 } 749 750 751 /* 752 * Add an option from "options FOO". Note that this selects things that 753 * are "optional foo". 754 */ 755 void 756 addoption(const char *name, const char *value) 757 { 758 const char *n; 759 int is_fs, is_param, is_flag, is_opt, is_undecl; 760 761 /* 762 * Figure out how this option was declared (if at all.) 763 * XXX should use "params" and "flags" in config. 764 * XXX crying out for a type field in a unified hashtab. 765 */ 766 is_fs = OPT_FSOPT(name); 767 is_param = OPT_DEFPARAM(name); 768 is_opt = OPT_DEFOPT(name); 769 is_flag = OPT_DEFFLAG(name); 770 is_undecl = !DEFINED_OPTION(name); 771 772 /* Make sure this is not a defined file system. */ 773 if (is_fs) { 774 error("`%s' is a defined file system", name); 775 return; 776 } 777 /* A defparam must have a value */ 778 if (is_param && value == NULL) { 779 error("option `%s' must have a value", name); 780 return; 781 } 782 /* A defflag must not have a value */ 783 if (is_flag && value != NULL) { 784 error("option `%s' must not have a value", name); 785 return; 786 } 787 788 if (is_undecl && vflag) { 789 warn("undeclared option `%s' added to IDENT", name); 790 } 791 792 if (do_option(opttab, &nextopt, name, value, "options")) 793 return; 794 795 /* make lowercase, then add to select table */ 796 n = strtolower(name); 797 (void)ht_insert(selecttab, n, (void *)n); 798 } 799 800 void 801 deloption(const char *name) 802 { 803 804 if (undo_option(opttab, &options, &nextopt, name, "options")) 805 return; 806 if (undo_option(selecttab, NULL, NULL, strtolower(name), "options")) 807 return; 808 } 809 810 /* 811 * Add a file system option. This routine simply inserts the name into 812 * a list of valid file systems, which is used to validate the root 813 * file system type. The name is then treated like a standard option. 814 */ 815 void 816 addfsoption(const char *name) 817 { 818 const char *n; 819 820 /* Make sure this is a defined file system. */ 821 if (!OPT_FSOPT(name)) { 822 error("`%s' is not a defined file system", name); 823 return; 824 } 825 826 /* 827 * Convert to lower case. This will be used in the select 828 * table, to verify root file systems, and when the initial 829 * VFS list is created. 830 */ 831 n = strtolower(name); 832 833 if (do_option(fsopttab, &nextfsopt, name, n, "file-system")) 834 return; 835 836 /* 837 * Add a lower-case version to the table for root file system 838 * verification. 839 */ 840 if (ht_insert(fsopttab, n, (void *)n)) 841 panic("addfsoption: already in table"); 842 843 /* Add to select table. */ 844 (void)ht_insert(selecttab, n, (void *)n); 845 } 846 847 void 848 delfsoption(const char *name) 849 { 850 const char *n; 851 852 n = strtolower(name); 853 if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system")) 854 return; 855 if (undo_option(fsopttab, NULL, NULL, n, "file-system")) 856 return; 857 if (undo_option(selecttab, NULL, NULL, n, "file-system")) 858 return; 859 } 860 861 /* 862 * Add a "make" option. 863 */ 864 void 865 addmkoption(const char *name, const char *value) 866 { 867 868 (void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions"); 869 } 870 871 void 872 delmkoption(const char *name) 873 { 874 875 (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name, 876 "makeoptions"); 877 } 878 879 /* 880 * Add an appending "make" option. 881 */ 882 void 883 appendmkoption(const char *name, const char *value) 884 { 885 struct nvlist *nv; 886 887 nv = newnv(name, value, NULL, 0, NULL); 888 *nextappmkopt = nv; 889 nextappmkopt = &nv->nv_next; 890 } 891 892 /* 893 * Add a conditional appending "make" option. 894 */ 895 void 896 appendcondmkoption(const char *selname, const char *name, const char *value) 897 { 898 struct nvlist *nv, *lnv; 899 const char *n; 900 901 n = strtolower(selname); 902 nv = newnv(name, value, NULL, 0, NULL); 903 if (ht_insert(condmkopttab, n, nv) == 0) 904 return; 905 906 if ((lnv = ht_lookup(condmkopttab, n)) == NULL) 907 panic("appendcondmkoption"); 908 for (; lnv->nv_next != NULL; lnv = lnv->nv_next) 909 /* search for the last list element */; 910 lnv->nv_next = nv; 911 } 912 913 /* 914 * Add a name=value pair to an option list. The value may be NULL. 915 */ 916 static int 917 do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 918 const char *value, const char *type) 919 { 920 struct nvlist *nv; 921 922 /* 923 * If a defopt'ed or defflag'ed option was enabled but without 924 * an explicit value (always the case for defflag), supply a 925 * default value of 1, as for non-defopt options (where cc 926 * treats -DBAR as -DBAR=1.) 927 */ 928 if ((OPT_DEFOPT(name) || OPT_DEFFLAG(name)) && value == NULL) 929 value = "1"; 930 931 /* assume it will work */ 932 nv = newnv(name, value, NULL, 0, NULL); 933 if (ht_insert(ht, name, nv) == 0) { 934 **nppp = nv; 935 *nppp = &nv->nv_next; 936 return (0); 937 } 938 939 /* oops, already got that option */ 940 nvfree(nv); 941 if ((nv = ht_lookup(ht, name)) == NULL) 942 panic("do_option"); 943 if (nv->nv_str != NULL && !OPT_FSOPT(name)) 944 error("already have %s `%s=%s'", type, name, nv->nv_str); 945 else 946 error("already have %s `%s'", type, name); 947 return (1); 948 } 949 950 /* 951 * Remove a name from a hash table, 952 * and optionally, a name=value pair from an option list. 953 */ 954 static int 955 undo_option(struct hashtab *ht, struct nvlist **npp, 956 struct nvlist ***next, const char *name, const char *type) 957 { 958 struct nvlist *nv; 959 960 if (ht_remove(ht, name)) { 961 error("%s `%s' is not defined", type, name); 962 return (1); 963 } 964 if (npp == NULL) 965 return (0); 966 967 for ( ; *npp != NULL; npp = &(*npp)->nv_next) { 968 if ((*npp)->nv_name != name) 969 continue; 970 if (next != NULL && *next == &(*npp)->nv_next) 971 *next = npp; 972 nv = (*npp)->nv_next; 973 nvfree(*npp); 974 *npp = nv; 975 return (0); 976 } 977 panic("%s `%s' is not defined in nvlist", type, name); 978 return (1); 979 } 980 981 /* 982 * Return true if there is at least one instance of the given unit 983 * on the given device attachment (or any units, if unit == WILD). 984 */ 985 int 986 deva_has_instances(struct deva *deva, int unit) 987 { 988 struct devi *i; 989 990 if (unit == WILD) 991 return (deva->d_ihead != NULL); 992 for (i = deva->d_ihead; i != NULL; i = i->i_asame) 993 if (unit == i->i_unit) 994 return (1); 995 return (0); 996 } 997 998 /* 999 * Return true if there is at least one instance of the given unit 1000 * on the given base (or any units, if unit == WILD). 1001 */ 1002 int 1003 devbase_has_instances(struct devbase *dev, int unit) 1004 { 1005 struct deva *da; 1006 1007 /* 1008 * Pseudo-devices are a little special. We consider them 1009 * to have instances only if they are both: 1010 * 1011 * 1. Included in this kernel configuration. 1012 * 1013 * 2. Have one or more interface attributes. 1014 */ 1015 if (dev->d_ispseudo) { 1016 struct nvlist *nv; 1017 struct attr *a; 1018 1019 if (ht_lookup(devitab, dev->d_name) == NULL) 1020 return (0); 1021 1022 for (nv = dev->d_attrs; nv != NULL; nv = nv->nv_next) { 1023 a = nv->nv_ptr; 1024 if (a->a_iattr) 1025 return (1); 1026 } 1027 return (0); 1028 } 1029 1030 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 1031 if (deva_has_instances(da, unit)) 1032 return (1); 1033 return (0); 1034 } 1035 1036 static int 1037 hasparent(struct devi *i) 1038 { 1039 struct pspec *p; 1040 struct nvlist *nv; 1041 1042 /* 1043 * We determine whether or not a device has a parent in in one 1044 * of two ways: 1045 * (1) If a parent device was named in the config file, 1046 * i.e. cases (2) and (3) in sem.c:adddev(), then 1047 * we search its devbase for a matching unit number. 1048 * (2) If the device was attach to an attribute, then we 1049 * search all attributes the device can be attached to 1050 * for parents (with appropriate unit numebrs) that 1051 * may be able to attach the device. 1052 */ 1053 1054 /* No pspec, no parent (root node). */ 1055 if ((p = i->i_pspec) == NULL) 1056 return (0); 1057 1058 /* 1059 * Case (1): A parent was named. Either it's configured, or not. 1060 */ 1061 if (p->p_atdev != NULL) 1062 return (devbase_has_instances(p->p_atdev, p->p_atunit)); 1063 1064 /* 1065 * Case (2): No parent was named. Look for devs that provide the attr. 1066 */ 1067 if (p->p_iattr != NULL) 1068 for (nv = p->p_iattr->a_refs; nv != NULL; nv = nv->nv_next) 1069 if (devbase_has_instances(nv->nv_ptr, p->p_atunit)) 1070 return (1); 1071 return (0); 1072 } 1073 1074 static int 1075 cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 1076 { 1077 struct devbase *dev; 1078 struct devi *pd; 1079 int errs, devunit; 1080 1081 if (maxpartitions <= 0) 1082 panic("cfcrosscheck"); 1083 1084 for (errs = 0; nv != NULL; nv = nv->nv_next) { 1085 if (nv->nv_name == NULL) 1086 continue; 1087 dev = ht_lookup(devbasetab, nv->nv_name); 1088 if (dev == NULL) 1089 panic("cfcrosscheck(%s)", nv->nv_name); 1090 if (has_attr(dev->d_attrs, s_ifnet)) 1091 devunit = nv->nv_ifunit; /* XXX XXX XXX */ 1092 else 1093 devunit = minor(nv->nv_int) / maxpartitions; 1094 if (devbase_has_instances(dev, devunit)) 1095 continue; 1096 if (devbase_has_instances(dev, STAR) && 1097 devunit >= dev->d_umax) 1098 continue; 1099 TAILQ_FOREACH(pd, &allpseudo, i_next) { 1100 if (pd->i_base == dev && devunit < dev->d_umax && 1101 devunit >= 0) 1102 goto loop; 1103 } 1104 (void)fprintf(stderr, 1105 "%s:%d: %s says %s on %s, but there's no %s\n", 1106 conffile, cf->cf_lineno, 1107 cf->cf_name, what, nv->nv_str, nv->nv_str); 1108 errs++; 1109 loop: 1110 ; 1111 } 1112 return (errs); 1113 } 1114 1115 /* 1116 * Cross-check the configuration: make sure that each target device 1117 * or attribute (`at foo[0*?]') names at least one real device. Also 1118 * see that the root and dump devices for all configurations are there. 1119 */ 1120 int 1121 crosscheck(void) 1122 { 1123 struct pspec *p; 1124 struct devi *i; 1125 struct config *cf; 1126 int errs; 1127 1128 errs = 0; 1129 TAILQ_FOREACH(i, &alldevi, i_next) { 1130 if ((p = i->i_pspec) == NULL || hasparent(i)) 1131 continue; 1132 (void)fprintf(stderr, 1133 "%s:%d: `%s at %s' is orphaned (%s `%s' declared)\n", 1134 conffile, i->i_lineno, i->i_name, i->i_at, 1135 p->p_atunit == WILD ? "nothing matching" : "no", 1136 i->i_at); 1137 } 1138 if (TAILQ_EMPTY(&allcf)) { 1139 (void)fprintf(stderr, "%s has no configurations!\n", 1140 conffile); 1141 errs++; 1142 } 1143 TAILQ_FOREACH(cf, &allcf, cf_next) { 1144 if (cf->cf_root != NULL) { /* i.e., not root on ? */ 1145 errs += cfcrosscheck(cf, "root", cf->cf_root); 1146 errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 1147 } 1148 } 1149 return (errs); 1150 } 1151 1152 /* 1153 * Check to see if there is a *'d unit with a needs-count file. 1154 */ 1155 int 1156 badstar(void) 1157 { 1158 struct devbase *d; 1159 struct deva *da; 1160 struct devi *i; 1161 int errs, n; 1162 1163 errs = 0; 1164 TAILQ_FOREACH(d, &allbases, d_next) { 1165 for (da = d->d_ahead; da != NULL; da = da->d_bsame) 1166 for (i = da->d_ihead; i != NULL; i = i->i_asame) { 1167 if (i->i_unit == STAR) 1168 goto aybabtu; 1169 } 1170 continue; 1171 aybabtu: 1172 if (ht_lookup(needcnttab, d->d_name)) { 1173 (void)fprintf(stderr, 1174 "config: %s's cannot be *'d until its driver is fixed\n", 1175 d->d_name); 1176 errs++; 1177 continue; 1178 } 1179 for (n = 0; i != NULL; i = i->i_alias) 1180 if (!i->i_collapsed) 1181 n++; 1182 if (n < 1) 1183 panic("badstar() n<1"); 1184 } 1185 return (errs); 1186 } 1187 1188 /* 1189 * Verify/create builddir if necessary, change to it, and verify srcdir. 1190 * This will be called when we see the first include. 1191 */ 1192 void 1193 setupdirs(void) 1194 { 1195 struct stat st; 1196 1197 /* srcdir must be specified if builddir is not specified or if 1198 * no configuration filename was specified. */ 1199 if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 1200 error("source directory must be specified"); 1201 exit(1); 1202 } 1203 1204 if (srcdir == NULL) 1205 srcdir = "../../../.."; 1206 if (builddir == NULL) 1207 builddir = defbuilddir; 1208 1209 if (stat(builddir, &st) != 0) { 1210 if (mkdir(builddir, 0777)) { 1211 (void)fprintf(stderr, "config: cannot create %s: %s\n", 1212 builddir, strerror(errno)); 1213 exit(2); 1214 } 1215 } else if (!S_ISDIR(st.st_mode)) { 1216 (void)fprintf(stderr, "config: %s is not a directory\n", 1217 builddir); 1218 exit(2); 1219 } 1220 if (chdir(builddir) != 0) { 1221 (void)fprintf(stderr, "config: cannot change to %s\n", 1222 builddir); 1223 exit(2); 1224 } 1225 if (stat(srcdir, &st) != 0 || !S_ISDIR(st.st_mode)) { 1226 (void)fprintf(stderr, "config: %s is not a directory\n", 1227 srcdir); 1228 exit(2); 1229 } 1230 } 1231 1232 /* 1233 * Write identifier from "ident" directive into file, for 1234 * newvers.sh to pick it up. 1235 */ 1236 int 1237 mkident(void) 1238 { 1239 FILE *fp; 1240 1241 (void)unlink("ident"); 1242 1243 if (ident == NULL) 1244 return (0); 1245 1246 if ((fp = fopen("ident", "w")) == NULL) { 1247 (void)fprintf(stderr, "config: cannot write ident: %s\n", 1248 strerror(errno)); 1249 return (1); 1250 } 1251 if (vflag) 1252 (void)printf("using ident '%s'\n", ident); 1253 if (fprintf(fp, "%s\n", ident) < 0) 1254 return (1); 1255 (void)fclose(fp); 1256 1257 return (0); 1258 } 1259 1260 void 1261 logconfig_start(void) 1262 { 1263 extern FILE *yyin; 1264 char line[1024]; 1265 const char *tmpdir; 1266 struct stat st; 1267 int fd; 1268 1269 if (yyin == NULL || fstat(fileno(yyin), &st) == -1) 1270 return; 1271 cfgtime = st.st_mtime; 1272 1273 tmpdir = getenv("TMPDIR"); 1274 if (tmpdir == NULL) 1275 tmpdir = "/tmp"; 1276 snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); 1277 if ((fd = mkstemp(line)) == -1 || 1278 (cfg = fdopen(fd, "r+")) == NULL) { 1279 if (fd != -1) { 1280 unlink(line); 1281 close(fd); 1282 } 1283 cfg = NULL; 1284 return; 1285 } 1286 unlink(line); 1287 1288 (void)fprintf(cfg, "#include \"opt_config.h\"\n"); 1289 (void)fprintf(cfg, "\n"); 1290 (void)fprintf(cfg, "/*\n"); 1291 (void)fprintf(cfg, " * Add either (or both) of\n"); 1292 (void)fprintf(cfg, " *\n"); 1293 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); 1294 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); 1295 (void)fprintf(cfg, " *\n"); 1296 (void)fprintf(cfg, 1297 " * to your kernel config file to embed it in the resulting\n"); 1298 (void)fprintf(cfg, 1299 " * kernel. The latter option does not include files that are\n"); 1300 (void)fprintf(cfg, 1301 " * included (recursively) by your config file. The embedded\n"); 1302 (void)fprintf(cfg, 1303 " * data be extracted by using the command:\n"); 1304 (void)fprintf(cfg, " *\n"); 1305 (void)fprintf(cfg, 1306 " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); 1307 (void)fprintf(cfg, " */\n"); 1308 (void)fprintf(cfg, "\n"); 1309 (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); 1310 (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", 1311 LOGCONFIG_LARGE, LOGCONFIG_SMALL); 1312 (void)fprintf(cfg, 1313 "static const char config[] __attribute__((__unused__)) =\n\n"); 1314 1315 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 1316 (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", 1317 conffile); 1318 (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); 1319 1320 logconfig_include(yyin, NULL); 1321 1322 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 1323 (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", 1324 conffile); 1325 1326 rewind(yyin); 1327 } 1328 1329 void 1330 logconfig_include(FILE *cf, const char *filename) 1331 { 1332 char line[1024], in[2048], *out; 1333 struct stat st; 1334 int missingeol; 1335 1336 if (!cfg) 1337 return; 1338 1339 missingeol = 0; 1340 if (fstat(fileno(cf), &st) == -1) 1341 return; 1342 if (cfgtime < st.st_mtime) 1343 cfgtime = st.st_mtime; 1344 1345 if (filename) 1346 (void)fprintf(cfg, 1347 "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", 1348 filename); 1349 while (fgets(line, sizeof(line), cf) != NULL) { 1350 missingeol = 1; 1351 (void)fprintf(cfg, "\"_CFG_"); 1352 if (filename) 1353 (void)fprintf(cfg, "###> "); 1354 strvis(in, line, VIS_TAB); 1355 for (out = in; *out; out++) 1356 switch (*out) { 1357 case '\n': 1358 (void)fprintf(cfg, "\\n\"\n"); 1359 missingeol = 0; 1360 break; 1361 case '"': case '\\': 1362 (void)fputc('\\', cfg); 1363 /* FALLTHROUGH */ 1364 default: 1365 (void)fputc(*out, cfg); 1366 break; 1367 } 1368 } 1369 if (missingeol) { 1370 (void)fprintf(cfg, "\\n\"\n"); 1371 (void)fprintf(stderr, 1372 "config: %s: newline missing at EOF\n", 1373 filename != NULL ? filename : conffile); 1374 } 1375 if (filename) 1376 (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", 1377 filename); 1378 1379 rewind(cf); 1380 } 1381 1382 void 1383 logconfig_end(void) 1384 { 1385 char line[1024]; 1386 FILE *fp; 1387 struct stat st; 1388 1389 if (!cfg) 1390 return; 1391 1392 (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); 1393 (void)fprintf(cfg, ";\n"); 1394 (void)fprintf(cfg, "#endif /* %s || %s */\n", 1395 LOGCONFIG_LARGE, LOGCONFIG_SMALL); 1396 (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); 1397 rewind(cfg); 1398 1399 if (stat("config_file.h", &st) != -1) { 1400 if (cfgtime < st.st_mtime) { 1401 fclose(cfg); 1402 return; 1403 } 1404 } 1405 1406 fp = fopen("config_file.h", "w"); 1407 if(!fp) { 1408 (void)fprintf(stderr, 1409 "config: cannot write to \"config_file.h\"\n"); 1410 exit(1); 1411 } 1412 1413 while (fgets(line, sizeof(line), cfg) != NULL) 1414 fputs(line, fp); 1415 fclose(fp); 1416 fclose(cfg); 1417 } 1418 1419 static const char * 1420 strtolower(const char *name) 1421 { 1422 const char *n; 1423 char *p, low[500]; 1424 unsigned char c; 1425 1426 for (n = name, p = low; (c = *n) != '\0'; n++) 1427 *p++ = isupper(c) ? tolower(c) : c; 1428 *p = 0; 1429 return (intern(low)); 1430 } 1431 1432 static int 1433 is_elf(const char *file) 1434 { 1435 int kernel; 1436 char hdr[4]; 1437 1438 kernel = open(file, O_RDONLY); 1439 if (kernel == -1) { 1440 fprintf(stderr, "config: cannot open %s: %s\n", file, 1441 strerror(errno)); 1442 exit(2); 1443 } 1444 if (read(kernel, hdr, 4) == -1) { 1445 fprintf(stderr, "config: cannot read from %s: %s\n", file, 1446 strerror(errno)); 1447 exit(2); 1448 } 1449 close(kernel); 1450 1451 return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; 1452 } 1453 1454 static int 1455 extract_config(const char *kname, const char *cname, int cfd) 1456 { 1457 char *ptr; 1458 int found, kfd, i; 1459 struct stat st; 1460 1461 found = 0; 1462 1463 /* mmap(2) binary kernel */ 1464 kfd = open(conffile, O_RDONLY); 1465 if (kfd == -1) { 1466 fprintf(stderr, "config: cannot open %s: %s\n", kname, 1467 strerror(errno)); 1468 exit(2); 1469 } 1470 if ((fstat(kfd, &st) == -1)) { 1471 fprintf(stderr, "config: cannot stat %s: %s\n", kname, 1472 strerror(errno)); 1473 exit(2); 1474 } 1475 ptr = (char *)mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, 1476 kfd, 0); 1477 if (ptr == MAP_FAILED) { 1478 fprintf(stderr, "config: cannot mmap %s: %s\n", kname, 1479 strerror(errno)); 1480 exit(2); 1481 } 1482 1483 /* Scan mmap(2)'ed region, extracting kernel configuration */ 1484 for (i = 0; i < st.st_size; i++) { 1485 if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, 1486 "_CFG_", 5) == 0) { 1487 /* Line found */ 1488 char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; 1489 int j; 1490 1491 found = 1; 1492 1493 oldptr = (ptr += 5); 1494 while (*ptr != '\n' && *ptr != '\0') ptr++; 1495 if (ptr - oldptr > LINE_MAX) { 1496 fprintf(stderr, "config: line too long\n"); 1497 exit(2); 1498 } 1499 i += ptr - oldptr + 5; 1500 memcpy(line, oldptr, (ptr - oldptr)); 1501 line[ptr - oldptr] = '\0'; 1502 j = strunvis(uline, line); 1503 if (j == -1) { 1504 fprintf(stderr, "config: unvis: invalid " 1505 "encoded sequence\n"); 1506 exit(2); 1507 } 1508 uline[j] = '\n'; 1509 if (write(cfd, uline, j + 1) == -1) { 1510 fprintf(stderr, "config: cannot write to %s: " 1511 "%s\n", cname, strerror(errno)); 1512 exit(2); 1513 } 1514 } else ptr++; 1515 } 1516 1517 close(kfd); 1518 1519 return found; 1520 } 1521