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