1*34e6631aSbad /* $NetBSD: main.c,v 1.54 2014/08/09 12:40:14 bad Exp $ */ 25ecc953bSthorpej 35ecc953bSthorpej /* 45ecc953bSthorpej * Copyright (c) 1992, 1993 55ecc953bSthorpej * The Regents of the University of California. All rights reserved. 65ecc953bSthorpej * 75ecc953bSthorpej * This software was developed by the Computer Systems Engineering group 85ecc953bSthorpej * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 95ecc953bSthorpej * contributed to Berkeley. 105ecc953bSthorpej * 115ecc953bSthorpej * All advertising materials mentioning features or use of this software 125ecc953bSthorpej * must display the following acknowledgement: 135ecc953bSthorpej * This product includes software developed by the University of 145ecc953bSthorpej * California, Lawrence Berkeley Laboratories. 155ecc953bSthorpej * 165ecc953bSthorpej * Redistribution and use in source and binary forms, with or without 175ecc953bSthorpej * modification, are permitted provided that the following conditions 185ecc953bSthorpej * are met: 195ecc953bSthorpej * 1. Redistributions of source code must retain the above copyright 205ecc953bSthorpej * notice, this list of conditions and the following disclaimer. 215ecc953bSthorpej * 2. Redistributions in binary form must reproduce the above copyright 225ecc953bSthorpej * notice, this list of conditions and the following disclaimer in the 235ecc953bSthorpej * documentation and/or other materials provided with the distribution. 245ecc953bSthorpej * 3. Neither the name of the University nor the names of its contributors 255ecc953bSthorpej * may be used to endorse or promote products derived from this software 265ecc953bSthorpej * without specific prior written permission. 275ecc953bSthorpej * 285ecc953bSthorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 295ecc953bSthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 305ecc953bSthorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 315ecc953bSthorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 325ecc953bSthorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 335ecc953bSthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 345ecc953bSthorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 355ecc953bSthorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 365ecc953bSthorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 375ecc953bSthorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 385ecc953bSthorpej * SUCH DAMAGE. 395ecc953bSthorpej * 405ecc953bSthorpej * from: @(#)main.c 8.1 (Berkeley) 6/6/93 415ecc953bSthorpej */ 425ecc953bSthorpej 435ecc953bSthorpej #if HAVE_NBTOOL_CONFIG_H 445ecc953bSthorpej #include "nbtool_config.h" 455ecc953bSthorpej #endif 465ecc953bSthorpej 475ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 485ecc953bSthorpej #include <sys/cdefs.h> 495ecc953bSthorpej #define COPYRIGHT(x) __COPYRIGHT(x) 505ecc953bSthorpej #else 515ecc953bSthorpej #define COPYRIGHT(x) static const char copyright[] = x 525ecc953bSthorpej #endif 535ecc953bSthorpej 545ecc953bSthorpej #ifndef lint 5598e5374cSlukem COPYRIGHT("@(#) Copyright (c) 1992, 1993\ 5698e5374cSlukem The Regents of the University of California. All rights reserved."); 575ecc953bSthorpej #endif /* not lint */ 585ecc953bSthorpej 595ecc953bSthorpej #include <sys/types.h> 605ecc953bSthorpej #include <sys/stat.h> 615ecc953bSthorpej #include <sys/param.h> 625ecc953bSthorpej #include <sys/mman.h> 6399d2b097Schristos #if !HAVE_NBTOOL_CONFIG_H 649de19619Schristos #include <sys/sysctl.h> 659de19619Schristos #endif 665ecc953bSthorpej #include <paths.h> 675ecc953bSthorpej #include <ctype.h> 68342d3579Sdsl #include <err.h> 695ecc953bSthorpej #include <errno.h> 705ecc953bSthorpej #include <fcntl.h> 7136c1b19bSdholland #include <limits.h> 725ecc953bSthorpej #include <stdio.h> 735ecc953bSthorpej #include <stdlib.h> 745ecc953bSthorpej #include <string.h> 755ecc953bSthorpej #include <unistd.h> 76d0fb8901Schristos #include <vis.h> 77d0fb8901Schristos #include <util.h> 78d0fb8901Schristos 795ecc953bSthorpej #include "defs.h" 805ecc953bSthorpej #include "sem.h" 815ecc953bSthorpej 825ecc953bSthorpej #ifndef LINE_MAX 835ecc953bSthorpej #define LINE_MAX 1024 845ecc953bSthorpej #endif 855ecc953bSthorpej 865ecc953bSthorpej int vflag; /* verbose output */ 875ecc953bSthorpej int Pflag; /* pack locators */ 8859c94545Scube int Lflag; /* lint config generation */ 89d2737476Smartin int handling_cmdlineopts; /* currently processing -D/-U options */ 905ecc953bSthorpej 915ecc953bSthorpej int yyparse(void); 925ecc953bSthorpej 935ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 945ecc953bSthorpej extern int yydebug; 955ecc953bSthorpej #endif 965ecc953bSthorpej 97d74eb995Sdholland static struct dlhash *obsopttab; 985ecc953bSthorpej static struct hashtab *mkopttab; 995ecc953bSthorpej static struct nvlist **nextopt; 1005ecc953bSthorpej static struct nvlist **nextmkopt; 1015ecc953bSthorpej static struct nvlist **nextappmkopt; 102a16a6365Scube static struct nvlist **nextcndmkopt; 1035ecc953bSthorpej static struct nvlist **nextfsopt; 104d2737476Smartin static struct nvlist *cmdlinedefs, *cmdlineundefs; 1055ecc953bSthorpej 1068b0f9554Sperry static void usage(void) __dead; 1075ecc953bSthorpej static void dependopts(void); 108d74eb995Sdholland static void dependopts_one(const char *); 109d74eb995Sdholland static void do_depends(struct nvlist *); 1105ecc953bSthorpej static void do_depend(struct nvlist *); 1115ecc953bSthorpej static void stop(void); 1125ecc953bSthorpej static int do_option(struct hashtab *, struct nvlist ***, 1135ecc953bSthorpej const char *, const char *, const char *); 1145ecc953bSthorpej static int undo_option(struct hashtab *, struct nvlist **, 1155ecc953bSthorpej struct nvlist ***, const char *, const char *); 1165ecc953bSthorpej static int crosscheck(void); 1175ecc953bSthorpej static int badstar(void); 1185ecc953bSthorpej int main(int, char **); 1195ecc953bSthorpej static int mksymlinks(void); 1205ecc953bSthorpej static int mkident(void); 1217aa6070dScube static int devbase_has_dead_instances(const char *, void *, void *); 122a31ff6b4Scube static int devbase_has_any_instance(struct devbase *, int, int, int); 1237aa6070dScube static int check_dead_devi(const char *, void *, void *); 124d2737476Smartin static void add_makeopt(const char *); 125d2737476Smartin static void remove_makeopt(const char *); 126d2737476Smartin static void handle_cmdline_makeoptions(void); 127c130d400Scube static void kill_orphans(void); 1287aa6070dScube static void do_kill_orphans(struct devbase *, struct attr *, 1297aa6070dScube struct devbase *, int); 130c130d400Scube static int kill_orphans_cb(const char *, void *, void *); 1315ecc953bSthorpej static int cfcrosscheck(struct config *, const char *, struct nvlist *); 132d74eb995Sdholland static void defopt(struct dlhash *ht, const char *fname, 133d74eb995Sdholland struct defoptlist *opts, struct nvlist *deps, int obs); 134d74eb995Sdholland static struct defoptlist *find_declared_option_option(const char *name); 135d74eb995Sdholland static struct nvlist *find_declared_fs_option(const char *name); 1365ecc953bSthorpej 1375ecc953bSthorpej #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" 1385ecc953bSthorpej #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" 1395ecc953bSthorpej 1405ecc953bSthorpej static void logconfig_start(void); 1415ecc953bSthorpej static void logconfig_end(void); 1425ecc953bSthorpej static FILE *cfg; 1435ecc953bSthorpej static time_t cfgtime; 1445ecc953bSthorpej 1455ecc953bSthorpej static int is_elf(const char *); 1465ecc953bSthorpej static int extract_config(const char *, const char *, int); 1475ecc953bSthorpej 1485ecc953bSthorpej int badfilename(const char *fname); 1495ecc953bSthorpej 1505ecc953bSthorpej const char *progname; 1515ecc953bSthorpej 1525ecc953bSthorpej int 1535ecc953bSthorpej main(int argc, char **argv) 1545ecc953bSthorpej { 15536c1b19bSdholland char *p, cname[PATH_MAX]; 1565ecc953bSthorpej const char *last_component; 1575ecc953bSthorpej int pflag, xflag, ch, removeit; 1585ecc953bSthorpej 1595ecc953bSthorpej setprogname(argv[0]); 1605ecc953bSthorpej 1615ecc953bSthorpej pflag = 0; 1625ecc953bSthorpej xflag = 0; 163d2737476Smartin while ((ch = getopt(argc, argv, "D:LPU:dgpvb:s:x")) != -1) { 1645ecc953bSthorpej switch (ch) { 1655ecc953bSthorpej 1665ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 167d2737476Smartin case 'd': 1685ecc953bSthorpej yydebug = 1; 1695ecc953bSthorpej break; 1705ecc953bSthorpej #endif 1715ecc953bSthorpej 17259c94545Scube case 'L': 17359c94545Scube Lflag = 1; 17459c94545Scube break; 17559c94545Scube 1765ecc953bSthorpej case 'P': 1775ecc953bSthorpej Pflag = 1; 1785ecc953bSthorpej break; 1795ecc953bSthorpej 1805ecc953bSthorpej case 'g': 1815ecc953bSthorpej /* 1825ecc953bSthorpej * In addition to DEBUG, you probably wanted to 1835ecc953bSthorpej * set "options KGDB" and maybe others. We could 1845ecc953bSthorpej * do that for you, but you really should just 1855ecc953bSthorpej * put them in the config file. 1865ecc953bSthorpej */ 187d2737476Smartin warnx("-g is obsolete (use -D DEBUG=\"-g\")"); 1885ecc953bSthorpej usage(); 189c7295a4cSchristos /*NOTREACHED*/ 1905ecc953bSthorpej 1915ecc953bSthorpej case 'p': 1925ecc953bSthorpej /* 1935ecc953bSthorpej * Essentially the same as makeoptions PROF="-pg", 1945ecc953bSthorpej * but also changes the path from ../../compile/FOO 1955ecc953bSthorpej * to ../../compile/FOO.PROF; i.e., compile a 1965ecc953bSthorpej * profiling kernel based on a typical "regular" 1975ecc953bSthorpej * kernel. 1985ecc953bSthorpej * 1995ecc953bSthorpej * Note that if you always want profiling, you 2005ecc953bSthorpej * can (and should) use a "makeoptions" line. 2015ecc953bSthorpej */ 2025ecc953bSthorpej pflag = 1; 2035ecc953bSthorpej break; 2045ecc953bSthorpej 2055ecc953bSthorpej case 'v': 2065ecc953bSthorpej vflag = 1; 2075ecc953bSthorpej break; 2085ecc953bSthorpej 2095ecc953bSthorpej case 'b': 2105ecc953bSthorpej builddir = optarg; 2115ecc953bSthorpej break; 2125ecc953bSthorpej 2135ecc953bSthorpej case 's': 2145ecc953bSthorpej srcdir = optarg; 2155ecc953bSthorpej break; 2165ecc953bSthorpej 2175ecc953bSthorpej case 'x': 2185ecc953bSthorpej xflag = 1; 2195ecc953bSthorpej break; 2205ecc953bSthorpej 221d2737476Smartin case 'D': 222d2737476Smartin add_makeopt(optarg); 223d2737476Smartin break; 224d2737476Smartin 225d2737476Smartin case 'U': 226d2737476Smartin remove_makeopt(optarg); 227d2737476Smartin break; 228d2737476Smartin 2295ecc953bSthorpej case '?': 2305ecc953bSthorpej default: 2315ecc953bSthorpej usage(); 2325ecc953bSthorpej } 2335ecc953bSthorpej } 2345ecc953bSthorpej 2357547791dSpooka if (xflag && optind != 2) { 236e239742fSpooka errx(EXIT_FAILURE, "-x must be used alone"); 237e239742fSpooka } 238e239742fSpooka 2395ecc953bSthorpej argc -= optind; 2405ecc953bSthorpej argv += optind; 2415ecc953bSthorpej if (argc > 1) { 2425ecc953bSthorpej usage(); 2435ecc953bSthorpej } 2445ecc953bSthorpej 245c7295a4cSchristos if (Lflag && (builddir != NULL || Pflag || pflag)) 246c7295a4cSchristos errx(EXIT_FAILURE, "-L can only be used with -s and -v"); 2475ecc953bSthorpej 2485ecc953bSthorpej if (xflag) { 2499de19619Schristos if (argc == 0) { 25099d2b097Schristos #if !HAVE_NBTOOL_CONFIG_H 2519de19619Schristos char path_unix[MAXPATHLEN]; 2529de19619Schristos size_t len = sizeof(path_unix) - 1; 2539de19619Schristos path_unix[0] = '/'; 2549de19619Schristos 2559de19619Schristos conffile = sysctlbyname("machdep.booted_kernel", 2569de19619Schristos &path_unix[1], &len, NULL, 0) == -1 ? _PATH_UNIX : 2579de19619Schristos path_unix; 2585ecc953bSthorpej #else 259c7295a4cSchristos errx(EXIT_FAILURE, "no kernel supplied"); 2605ecc953bSthorpej #endif 2619de19619Schristos } else 2629de19619Schristos conffile = argv[0]; 263c7295a4cSchristos if (!is_elf(conffile)) 264c7295a4cSchristos errx(EXIT_FAILURE, "%s: not a binary kernel", 2655ecc953bSthorpej conffile); 266c7295a4cSchristos if (!extract_config(conffile, "stdout", STDOUT_FILENO)) 267c7295a4cSchristos errx(EXIT_FAILURE, "%s does not contain embedded " 268c7295a4cSchristos "configuration data", conffile); 2695ecc953bSthorpej exit(0); 2705ecc953bSthorpej } 2715ecc953bSthorpej 2725ecc953bSthorpej conffile = (argc == 1) ? argv[0] : "CONFIG"; 2735ecc953bSthorpej if (firstfile(conffile)) { 274c7295a4cSchristos err(EXIT_FAILURE, "Cannot read `%s'", conffile); 2755ecc953bSthorpej exit(2); 2765ecc953bSthorpej } 2775ecc953bSthorpej 2785ecc953bSthorpej /* 2795ecc953bSthorpej * Init variables. 2805ecc953bSthorpej */ 2815ecc953bSthorpej minmaxusers = 1; 2825ecc953bSthorpej maxmaxusers = 10000; 2835ecc953bSthorpej initintern(); 2845ecc953bSthorpej initfiles(); 2855ecc953bSthorpej initsem(); 2865ecc953bSthorpej ident = NULL; 2875ecc953bSthorpej devbasetab = ht_new(); 288c130d400Scube devroottab = ht_new(); 2895ecc953bSthorpej devatab = ht_new(); 2905ecc953bSthorpej devitab = ht_new(); 2917aa6070dScube deaddevitab = ht_new(); 2925ecc953bSthorpej selecttab = ht_new(); 2935ecc953bSthorpej needcnttab = ht_new(); 2945ecc953bSthorpej opttab = ht_new(); 2955ecc953bSthorpej mkopttab = ht_new(); 2965ecc953bSthorpej fsopttab = ht_new(); 29702245173Sdholland deffstab = nvhash_create(); 298d74eb995Sdholland defopttab = dlhash_create(); 299d74eb995Sdholland defparamtab = dlhash_create(); 300d74eb995Sdholland defoptlint = dlhash_create(); 301d74eb995Sdholland defflagtab = dlhash_create(); 302d74eb995Sdholland optfiletab = dlhash_create(); 303d74eb995Sdholland obsopttab = dlhash_create(); 3045ecc953bSthorpej bdevmtab = ht_new(); 3055ecc953bSthorpej maxbdevm = 0; 3065ecc953bSthorpej cdevmtab = ht_new(); 3075ecc953bSthorpej maxcdevm = 0; 3085ecc953bSthorpej nextopt = &options; 3095ecc953bSthorpej nextmkopt = &mkoptions; 3105ecc953bSthorpej nextappmkopt = &appmkoptions; 3111894a7d2Scube nextcndmkopt = &condmkoptions; 3125ecc953bSthorpej nextfsopt = &fsoptions; 3135ecc953bSthorpej 3145ecc953bSthorpej /* 3155ecc953bSthorpej * Handle profiling (must do this before we try to create any 3165ecc953bSthorpej * files). 3175ecc953bSthorpej */ 3185ecc953bSthorpej last_component = strrchr(conffile, '/'); 3195ecc953bSthorpej last_component = (last_component) ? last_component + 1 : conffile; 3205ecc953bSthorpej if (pflag) { 3215ecc953bSthorpej p = emalloc(strlen(last_component) + 17); 3225ecc953bSthorpej (void)sprintf(p, "../compile/%s.PROF", last_component); 3235ecc953bSthorpej (void)addmkoption(intern("PROF"), "-pg"); 3245ecc953bSthorpej (void)addoption(intern("GPROF"), NULL); 3255ecc953bSthorpej } else { 3265ecc953bSthorpej p = emalloc(strlen(last_component) + 13); 3275ecc953bSthorpej (void)sprintf(p, "../compile/%s", last_component); 3285ecc953bSthorpej } 3295ecc953bSthorpej defbuilddir = (argc == 0) ? "." : p; 3305ecc953bSthorpej 33159c94545Scube if (Lflag) { 33259c94545Scube char resolvedname[MAXPATHLEN]; 33359c94545Scube 33459c94545Scube if (realpath(conffile, resolvedname) == NULL) 33559c94545Scube err(EXIT_FAILURE, "realpath(%s)", conffile); 33659c94545Scube 33759c94545Scube if (yyparse()) 33859c94545Scube stop(); 33959c94545Scube 340aa3d0249Scube printf("include \"%s\"\n", resolvedname); 34159c94545Scube 34259c94545Scube emit_params(); 34359c94545Scube emit_options(); 34459c94545Scube emit_instances(); 34559c94545Scube 34659c94545Scube exit(EXIT_SUCCESS); 34759c94545Scube } 34859c94545Scube 3495ecc953bSthorpej removeit = 0; 3505ecc953bSthorpej if (is_elf(conffile)) { 3515ecc953bSthorpej const char *tmpdir; 3525ecc953bSthorpej int cfd; 3535ecc953bSthorpej 354c7295a4cSchristos if (builddir == NULL) 355c7295a4cSchristos errx(EXIT_FAILURE, "Build directory must be specified " 356c7295a4cSchristos "with binary kernels"); 3575ecc953bSthorpej 3585ecc953bSthorpej /* Open temporary configuration file */ 3595ecc953bSthorpej tmpdir = getenv("TMPDIR"); 3605ecc953bSthorpej if (tmpdir == NULL) 36136c1b19bSdholland tmpdir = _PATH_TMP; 3625ecc953bSthorpej snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir); 3635ecc953bSthorpej cfd = mkstemp(cname); 364c7295a4cSchristos if (cfd == -1) 365c7295a4cSchristos err(EXIT_FAILURE, "Cannot create `%s'", cname); 3665ecc953bSthorpej 3675ecc953bSthorpej printf("Using configuration data embedded in kernel...\n"); 36836c1b19bSdholland if (!extract_config(conffile, cname, cfd)) { 36936c1b19bSdholland unlink(cname); 370c7295a4cSchristos errx(EXIT_FAILURE, "%s does not contain embedded " 371c7295a4cSchristos "configuration data", conffile); 37236c1b19bSdholland } 3735ecc953bSthorpej 3745ecc953bSthorpej removeit = 1; 3755ecc953bSthorpej close(cfd); 3765ecc953bSthorpej firstfile(cname); 3775ecc953bSthorpej } 3785ecc953bSthorpej 3795ecc953bSthorpej /* 380e239742fSpooka * Log config file. We don't know until yyparse() if we're 381e239742fSpooka * going to need config_file.h (i.e. if we're doing ioconf-only 382e239742fSpooka * or not). Just start creating the file, and when we know 383e239742fSpooka * later, we'll just keep or discard our work here. 3845ecc953bSthorpej */ 3855ecc953bSthorpej logconfig_start(); 386e239742fSpooka 387e239742fSpooka /* 388e239742fSpooka * Parse config file (including machine definitions). 389e239742fSpooka */ 3905ecc953bSthorpej if (yyparse()) 3915ecc953bSthorpej stop(); 392e239742fSpooka 393e239742fSpooka if (ioconfname && cfg) 394e239742fSpooka fclose(cfg); 395e239742fSpooka else 3965ecc953bSthorpej logconfig_end(); 3975ecc953bSthorpej 3985ecc953bSthorpej if (removeit) 3995ecc953bSthorpej unlink(cname); 4005ecc953bSthorpej 4015ecc953bSthorpej /* 402d2737476Smartin * Handle command line overrides 403d2737476Smartin */ 404d2737476Smartin handle_cmdline_makeoptions(); 405d2737476Smartin 406d2737476Smartin /* 407c130d400Scube * Detect and properly ignore orphaned devices 408c130d400Scube */ 409c130d400Scube kill_orphans(); 410c130d400Scube 411c130d400Scube /* 4125ecc953bSthorpej * Select devices and pseudo devices and their attributes 4135ecc953bSthorpej */ 4147aa6070dScube if (fixdevis()) 4157aa6070dScube stop(); 4165ecc953bSthorpej 4175ecc953bSthorpej /* 418e239742fSpooka * If working on an ioconf-only config, process here and exit 419e239742fSpooka */ 420e239742fSpooka if (ioconfname) { 421e239742fSpooka pack(); 422e239742fSpooka mkioconf(); 423e239742fSpooka emitlocs(); 424d0e5d937Spooka emitioconfh(); 425e239742fSpooka return 0; 426e239742fSpooka } 427e239742fSpooka 428e239742fSpooka /* 4295ecc953bSthorpej * Deal with option dependencies. 4305ecc953bSthorpej */ 4315ecc953bSthorpej dependopts(); 4325ecc953bSthorpej 4335ecc953bSthorpej /* 4345ecc953bSthorpej * Fix (as in `set firmly in place') files. 4355ecc953bSthorpej */ 4365ecc953bSthorpej if (fixfiles()) 4375ecc953bSthorpej stop(); 4385ecc953bSthorpej 4395ecc953bSthorpej /* 4405ecc953bSthorpej * Fix objects and libraries. 4415ecc953bSthorpej */ 4425ecc953bSthorpej if (fixobjects()) 4435ecc953bSthorpej stop(); 4445ecc953bSthorpej 4455ecc953bSthorpej /* 4465ecc953bSthorpej * Fix device-majors. 4475ecc953bSthorpej */ 4485ecc953bSthorpej if (fixdevsw()) 4495ecc953bSthorpej stop(); 4505ecc953bSthorpej 4515ecc953bSthorpej /* 4525ecc953bSthorpej * Perform cross-checking. 4535ecc953bSthorpej */ 4545ecc953bSthorpej if (maxusers == 0) { 4555ecc953bSthorpej if (defmaxusers) { 4565ecc953bSthorpej (void)printf("maxusers not specified; %d assumed\n", 4575ecc953bSthorpej defmaxusers); 4585ecc953bSthorpej maxusers = defmaxusers; 4595ecc953bSthorpej } else { 460c7295a4cSchristos warnx("need \"maxusers\" line"); 4615ecc953bSthorpej errors++; 4625ecc953bSthorpej } 4635ecc953bSthorpej } 4645ecc953bSthorpej if (crosscheck() || errors) 4655ecc953bSthorpej stop(); 4665ecc953bSthorpej 4675ecc953bSthorpej /* 4685ecc953bSthorpej * Squeeze things down and finish cross-checks (STAR checks must 4695ecc953bSthorpej * run after packing). 4705ecc953bSthorpej */ 4715ecc953bSthorpej pack(); 4725ecc953bSthorpej if (badstar()) 4735ecc953bSthorpej stop(); 4745ecc953bSthorpej 4755ecc953bSthorpej /* 4765ecc953bSthorpej * Ready to go. Build all the various files. 4775ecc953bSthorpej */ 4785ecc953bSthorpej if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || 4790367057bScube mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident() || errors) 4805ecc953bSthorpej stop(); 4815ecc953bSthorpej (void)printf("Build directory is %s\n", builddir); 4825ecc953bSthorpej (void)printf("Don't forget to run \"make depend\"\n"); 483c7295a4cSchristos return 0; 4845ecc953bSthorpej } 4855ecc953bSthorpej 4865ecc953bSthorpej static void 4875ecc953bSthorpej usage(void) 4885ecc953bSthorpej { 4898566a894Swiz (void)fprintf(stderr, "Usage: %s [-Ppv] [-b builddir] [-D var=value] " 4908566a894Swiz "[-s srcdir] [-U var] " 491c7295a4cSchristos "[config-file]\n\t%s -x [kernel-file]\n" 492c7295a4cSchristos "\t%s -L [-v] [-s srcdir] [config-file]\n", 493c7295a4cSchristos getprogname(), getprogname(), getprogname()); 4945ecc953bSthorpej exit(1); 4955ecc953bSthorpej } 4965ecc953bSthorpej 4975ecc953bSthorpej /* 4985ecc953bSthorpej * Set any options that are implied by other options. 4995ecc953bSthorpej */ 5005ecc953bSthorpej static void 5015ecc953bSthorpej dependopts(void) 5025ecc953bSthorpej { 503d74eb995Sdholland struct nvlist *nv; 5045ecc953bSthorpej 5055ecc953bSthorpej for (nv = options; nv != NULL; nv = nv->nv_next) { 506d74eb995Sdholland dependopts_one(nv->nv_name); 5075ecc953bSthorpej } 5084a82747aSmatt 5094a82747aSmatt for (nv = fsoptions; nv != NULL; nv = nv->nv_next) { 510d74eb995Sdholland dependopts_one(nv->nv_name); 511d74eb995Sdholland } 512d74eb995Sdholland } 513d74eb995Sdholland 514d74eb995Sdholland static void 515d74eb995Sdholland dependopts_one(const char *name) 516d74eb995Sdholland { 517d74eb995Sdholland struct defoptlist *dl; 518d74eb995Sdholland struct nvlist *fs; 519d74eb995Sdholland 520d74eb995Sdholland dl = find_declared_option_option(name); 521d74eb995Sdholland if (dl != NULL) { 522d74eb995Sdholland do_depends(dl->dl_depends); 523d74eb995Sdholland } 524d74eb995Sdholland fs = find_declared_fs_option(name); 525d74eb995Sdholland if (fs != NULL) { 526d74eb995Sdholland do_depends(fs->nv_ptr); 527d74eb995Sdholland } 528d74eb995Sdholland } 529d74eb995Sdholland 530d74eb995Sdholland static void 531d74eb995Sdholland do_depends(struct nvlist *nv) 532d74eb995Sdholland { 533d74eb995Sdholland struct nvlist *opt; 534d74eb995Sdholland 535d74eb995Sdholland for (opt = nv; opt != NULL; opt = opt->nv_next) { 5364a82747aSmatt do_depend(opt); 5374a82747aSmatt } 5384a82747aSmatt } 5395ecc953bSthorpej 5405ecc953bSthorpej static void 5415ecc953bSthorpej do_depend(struct nvlist *nv) 5425ecc953bSthorpej { 5435ecc953bSthorpej struct attr *a; 5445ecc953bSthorpej 5455ecc953bSthorpej if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) { 5465ecc953bSthorpej nv->nv_flags |= NV_DEPENDED; 5475ecc953bSthorpej /* 5485ecc953bSthorpej * If the dependency is an attribute, then just add 5495ecc953bSthorpej * it to the selecttab. 5505ecc953bSthorpej */ 5515ecc953bSthorpej if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) { 5525ecc953bSthorpej if (a->a_iattr) 5535ecc953bSthorpej panic("do_depend(%s): dep `%s' is an iattr", 5545ecc953bSthorpej nv->nv_name, a->a_name); 5555ecc953bSthorpej expandattr(a, selectattr); 5565ecc953bSthorpej } else { 5575ecc953bSthorpej if (ht_lookup(opttab, nv->nv_name) == NULL) 5585ecc953bSthorpej addoption(nv->nv_name, NULL); 559d74eb995Sdholland dependopts_one(nv->nv_name); 5605ecc953bSthorpej } 5615ecc953bSthorpej } 5625ecc953bSthorpej } 5635ecc953bSthorpej 564c7295a4cSchristos static int 565c7295a4cSchristos recreate(const char *p, const char *q) 566c7295a4cSchristos { 567c7295a4cSchristos int ret; 568c7295a4cSchristos 569c7295a4cSchristos if ((ret = unlink(q)) == -1 && errno != ENOENT) 570c7295a4cSchristos warn("unlink(%s)\n", q); 571c7295a4cSchristos if ((ret = symlink(p, q)) == -1) 572c7295a4cSchristos warn("symlink(%s -> %s)", q, p); 573c7295a4cSchristos return ret; 574c7295a4cSchristos } 575c7295a4cSchristos 5765ecc953bSthorpej /* 5775ecc953bSthorpej * Make a symlink for "machine" so that "#include <machine/foo.h>" works, 5785ecc953bSthorpej * and for the machine's CPU architecture, so that works as well. 5795ecc953bSthorpej */ 5805ecc953bSthorpej static int 5815ecc953bSthorpej mksymlinks(void) 5825ecc953bSthorpej { 5835ecc953bSthorpej int ret; 5845ecc953bSthorpej char *p, buf[MAXPATHLEN]; 5855ecc953bSthorpej const char *q; 5865ecc953bSthorpej struct nvlist *nv; 5875ecc953bSthorpej 5885ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", machine); 5895ecc953bSthorpej p = sourcepath(buf); 590c7295a4cSchristos ret = recreate(p, "machine"); 591cfbe3a4fSmatt ret = recreate(p, machine); 5925ecc953bSthorpej free(p); 5935ecc953bSthorpej 5945ecc953bSthorpej if (machinearch != NULL) { 5955ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", machinearch); 5965ecc953bSthorpej p = sourcepath(buf); 5975ecc953bSthorpej q = machinearch; 5985ecc953bSthorpej } else { 5995ecc953bSthorpej p = estrdup("machine"); 6005ecc953bSthorpej q = machine; 6015ecc953bSthorpej } 602c7295a4cSchristos 603c7295a4cSchristos ret = recreate(p, q); 6045ecc953bSthorpej free(p); 6055ecc953bSthorpej 6065ecc953bSthorpej for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { 6075ecc953bSthorpej q = nv->nv_name; 6085ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", q); 6095ecc953bSthorpej p = sourcepath(buf); 610c7295a4cSchristos ret = recreate(p, q); 6115ecc953bSthorpej free(p); 6125ecc953bSthorpej } 6135ecc953bSthorpej 6145ecc953bSthorpej return (ret); 6155ecc953bSthorpej } 6165ecc953bSthorpej 6175ecc953bSthorpej static __dead void 6185ecc953bSthorpej stop(void) 6195ecc953bSthorpej { 6205ecc953bSthorpej (void)fprintf(stderr, "*** Stop.\n"); 6215ecc953bSthorpej exit(1); 6225ecc953bSthorpej } 6235ecc953bSthorpej 6244a82747aSmatt static void 625d74eb995Sdholland check_dependencies(const char *thing, struct nvlist *deps) 6264a82747aSmatt { 6274a82747aSmatt struct nvlist *dep; 6284a82747aSmatt struct attr *a; 6294a82747aSmatt 6304a82747aSmatt for (dep = deps; dep != NULL; dep = dep->nv_next) { 6314a82747aSmatt /* 6324a82747aSmatt * If the dependency is an attribute, it must not 6334a82747aSmatt * be an interface attribute. Otherwise, it must 6344a82747aSmatt * be a previously declared option. 6354a82747aSmatt */ 6364a82747aSmatt if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) { 6374a82747aSmatt if (a->a_iattr) 638c7295a4cSchristos cfgerror("option `%s' dependency `%s' " 6394a82747aSmatt "is an interface attribute", 640d74eb995Sdholland thing, a->a_name); 6414a82747aSmatt } else if (OPT_OBSOLETE(dep->nv_name)) { 642c7295a4cSchristos cfgerror("option `%s' dependency `%s' " 643d74eb995Sdholland "is obsolete", thing, dep->nv_name); 644d74eb995Sdholland } else if (!is_declared_option(dep->nv_name)) { 645c7295a4cSchristos cfgerror("option `%s' dependency `%s' " 6464a82747aSmatt "is an unknown option", 647d74eb995Sdholland thing, dep->nv_name); 6484a82747aSmatt } 6494a82747aSmatt } 6504a82747aSmatt } 6514a82747aSmatt 652d74eb995Sdholland static void 653d74eb995Sdholland add_fs_dependencies(struct nvlist *nv, struct nvlist *deps) 654d74eb995Sdholland { 655d74eb995Sdholland /* Use nv_ptr to link any other options that are implied. */ 656d74eb995Sdholland nv->nv_ptr = deps; 657d74eb995Sdholland check_dependencies(nv->nv_name, deps); 658d74eb995Sdholland } 659d74eb995Sdholland 660d74eb995Sdholland static void 661d74eb995Sdholland add_opt_dependencies(struct defoptlist *dl, struct nvlist *deps) 662d74eb995Sdholland { 663d74eb995Sdholland dl->dl_depends = deps; 664d74eb995Sdholland check_dependencies(dl->dl_name, deps); 665d74eb995Sdholland } 666d74eb995Sdholland 6675ecc953bSthorpej /* 668e6e6744fSpooka * Define one or more file systems. 6695ecc953bSthorpej */ 6705ecc953bSthorpej void 671c9607065Spooka deffilesystem(struct nvlist *fses, struct nvlist *deps) 6725ecc953bSthorpej { 6735ecc953bSthorpej struct nvlist *nv; 6745ecc953bSthorpej 6755ecc953bSthorpej /* 6765ecc953bSthorpej * Mark these options as ones to skip when creating the Makefile. 6775ecc953bSthorpej */ 6785ecc953bSthorpej for (nv = fses; nv != NULL; nv = nv->nv_next) { 679c93963e6Scube if (DEFINED_OPTION(nv->nv_name)) { 680c7295a4cSchristos cfgerror("file system or option `%s' already defined", 6815ecc953bSthorpej nv->nv_name); 6825ecc953bSthorpej return; 6835ecc953bSthorpej } 6845ecc953bSthorpej 6855ecc953bSthorpej /* 6865ecc953bSthorpej * Also mark it as a valid file system, which may be 6875ecc953bSthorpej * used in "file-system" directives in the config 6885ecc953bSthorpej * file. 6895ecc953bSthorpej */ 69002245173Sdholland if (nvhash_insert(deffstab, nv->nv_name, nv)) 6915ecc953bSthorpej panic("file system `%s' already in table?!", 6925ecc953bSthorpej nv->nv_name); 6935ecc953bSthorpej 694d74eb995Sdholland add_fs_dependencies(nv, deps); 6955ecc953bSthorpej } 6965ecc953bSthorpej } 6975ecc953bSthorpej 6985ecc953bSthorpej /* 6995ecc953bSthorpej * Sanity check a file name. 7005ecc953bSthorpej */ 7015ecc953bSthorpej int 7025ecc953bSthorpej badfilename(const char *fname) 7035ecc953bSthorpej { 7045ecc953bSthorpej const char *n; 7055ecc953bSthorpej 7065ecc953bSthorpej /* 7075ecc953bSthorpej * We're putting multiple options into one file. Sanity 7085ecc953bSthorpej * check the file name. 7095ecc953bSthorpej */ 7105ecc953bSthorpej if (strchr(fname, '/') != NULL) { 711c7295a4cSchristos cfgerror("option file name contains a `/'"); 7125ecc953bSthorpej return 1; 7135ecc953bSthorpej } 7145ecc953bSthorpej if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) { 715c7295a4cSchristos cfgerror("option file name does not end in `.h'"); 7165ecc953bSthorpej return 1; 7175ecc953bSthorpej } 7185ecc953bSthorpej return 0; 7195ecc953bSthorpej } 7205ecc953bSthorpej 7215ecc953bSthorpej 7225ecc953bSthorpej /* 7235ecc953bSthorpej * Search for a defined option (defopt, filesystem, etc), and if found, 7245ecc953bSthorpej * return the option's struct nvlist. 725d74eb995Sdholland * 726d74eb995Sdholland * This used to be one function (find_declared_option) before options 727d74eb995Sdholland * and filesystems became different types. 7285ecc953bSthorpej */ 729d74eb995Sdholland static struct defoptlist * 730d74eb995Sdholland find_declared_option_option(const char *name) 7315ecc953bSthorpej { 732d74eb995Sdholland struct defoptlist *option; 7335ecc953bSthorpej 734d74eb995Sdholland if ((option = dlhash_lookup(defopttab, name)) != NULL || 735d74eb995Sdholland (option = dlhash_lookup(defparamtab, name)) != NULL || 736d74eb995Sdholland (option = dlhash_lookup(defflagtab, name)) != NULL) { 7375ecc953bSthorpej return (option); 7385ecc953bSthorpej } 7395ecc953bSthorpej 7405ecc953bSthorpej return (NULL); 7415ecc953bSthorpej } 7425ecc953bSthorpej 743d74eb995Sdholland static struct nvlist * 744d74eb995Sdholland find_declared_fs_option(const char *name) 745d74eb995Sdholland { 746d74eb995Sdholland struct nvlist *fs; 747d74eb995Sdholland 748d74eb995Sdholland if ((fs = nvhash_lookup(deffstab, name)) != NULL) { 749d74eb995Sdholland return fs; 750d74eb995Sdholland } 751d74eb995Sdholland 752d74eb995Sdholland return (NULL); 753d74eb995Sdholland } 754d74eb995Sdholland 755d74eb995Sdholland /* 756d74eb995Sdholland * Like find_declared_option but doesn't return what it finds, so it 757d74eb995Sdholland * can search both the various kinds of options and also filesystems. 758d74eb995Sdholland */ 759d74eb995Sdholland int 760d74eb995Sdholland is_declared_option(const char *name) 761d74eb995Sdholland { 762d74eb995Sdholland struct defoptlist *option = NULL; 763d74eb995Sdholland struct nvlist *fs; 764d74eb995Sdholland 765d74eb995Sdholland if ((option = dlhash_lookup(defopttab, name)) != NULL || 766d74eb995Sdholland (option = dlhash_lookup(defparamtab, name)) != NULL || 767d74eb995Sdholland (option = dlhash_lookup(defflagtab, name)) != NULL) { 768d74eb995Sdholland return 1; 769d74eb995Sdholland } 770d74eb995Sdholland if ((fs = nvhash_lookup(deffstab, name)) != NULL) { 771d74eb995Sdholland return 1; 772d74eb995Sdholland } 773d74eb995Sdholland 774d74eb995Sdholland return 0; 775d74eb995Sdholland } 7765ecc953bSthorpej 7775ecc953bSthorpej /* 7785ecc953bSthorpej * Define one or more standard options. If an option file name is specified, 7795ecc953bSthorpej * place all options in one file with the specified name. Otherwise, create 7805ecc953bSthorpej * an option file for each option. 7815ecc953bSthorpej * record the option information in the specified table. 7825ecc953bSthorpej */ 7835ecc953bSthorpej void 784d74eb995Sdholland defopt(struct dlhash *ht, const char *fname, struct defoptlist *opts, 785ac24e161Scube struct nvlist *deps, int obs) 7865ecc953bSthorpej { 787d74eb995Sdholland struct defoptlist *dl, *nextdl, *olddl; 7885ecc953bSthorpej const char *name; 7895ecc953bSthorpej char buf[500]; 7905ecc953bSthorpej 7915ecc953bSthorpej if (fname != NULL && badfilename(fname)) { 7925ecc953bSthorpej return; 7935ecc953bSthorpej } 7945ecc953bSthorpej 7955ecc953bSthorpej /* 7965ecc953bSthorpej * Mark these options as ones to skip when creating the Makefile. 7975ecc953bSthorpej */ 798d74eb995Sdholland for (dl = opts; dl != NULL; dl = nextdl) { 799d74eb995Sdholland nextdl = dl->dl_next; 8005ecc953bSthorpej 801d74eb995Sdholland if (dl->dl_lintvalue != NULL) { 80290426267Scube /* 80390426267Scube * If an entry already exists, then we are about to 80490426267Scube * complain, so no worry. 80590426267Scube */ 806d74eb995Sdholland (void) dlhash_insert(defoptlint, dl->dl_name, 807d74eb995Sdholland dl); 80890426267Scube } 80990426267Scube 8105ecc953bSthorpej /* An option name can be declared at most once. */ 811d74eb995Sdholland if (DEFINED_OPTION(dl->dl_name)) { 812c7295a4cSchristos cfgerror("file system or option `%s' already defined", 813d74eb995Sdholland dl->dl_name); 8145ecc953bSthorpej return; 8155ecc953bSthorpej } 8165ecc953bSthorpej 817d74eb995Sdholland if (dlhash_insert(ht, dl->dl_name, dl)) { 818c7295a4cSchristos cfgerror("file system or option `%s' already defined", 819d74eb995Sdholland dl->dl_name); 8205ecc953bSthorpej return; 8215ecc953bSthorpej } 8225ecc953bSthorpej 8235ecc953bSthorpej if (fname == NULL) { 8245ecc953bSthorpej /* 8255ecc953bSthorpej * Each option will be going into its own file. 8265ecc953bSthorpej * Convert the option name to lower case. This 8275ecc953bSthorpej * lower case name will be used as the option 8285ecc953bSthorpej * file name. 8295ecc953bSthorpej */ 8305ecc953bSthorpej (void) snprintf(buf, sizeof(buf), "opt_%s.h", 831d74eb995Sdholland strtolower(dl->dl_name)); 8325ecc953bSthorpej name = intern(buf); 8335ecc953bSthorpej } else { 8345ecc953bSthorpej name = fname; 8355ecc953bSthorpej } 8365ecc953bSthorpej 837d74eb995Sdholland add_opt_dependencies(dl, deps); 8385ecc953bSthorpej 8395ecc953bSthorpej /* 8405ecc953bSthorpej * Remove this option from the parameter list before adding 8415ecc953bSthorpej * it to the list associated with this option file. 8425ecc953bSthorpej */ 843d74eb995Sdholland dl->dl_next = NULL; 8445ecc953bSthorpej 8455ecc953bSthorpej /* 846ac24e161Scube * Flag as obsolete, if requested. 847ac24e161Scube */ 848ac24e161Scube if (obs) { 849d74eb995Sdholland dl->dl_obsolete = 1; 850d74eb995Sdholland (void)dlhash_insert(obsopttab, dl->dl_name, dl); 851ac24e161Scube } 852ac24e161Scube 853ac24e161Scube /* 8545ecc953bSthorpej * Add this option file if we haven't seen it yet. 8555ecc953bSthorpej * Otherwise, append to the list of options already 8565ecc953bSthorpej * associated with this file. 8575ecc953bSthorpej */ 858d74eb995Sdholland if ((olddl = dlhash_lookup(optfiletab, name)) == NULL) { 859d74eb995Sdholland (void)dlhash_insert(optfiletab, name, dl); 8605ecc953bSthorpej } else { 861d74eb995Sdholland while (olddl->dl_next != NULL) 862d74eb995Sdholland olddl = olddl->dl_next; 863d74eb995Sdholland olddl->dl_next = dl; 8645ecc953bSthorpej } 8655ecc953bSthorpej } 8665ecc953bSthorpej } 8675ecc953bSthorpej 8685ecc953bSthorpej /* 8695ecc953bSthorpej * Define one or more standard options. If an option file name is specified, 8705ecc953bSthorpej * place all options in one file with the specified name. Otherwise, create 8715ecc953bSthorpej * an option file for each option. 8725ecc953bSthorpej */ 8735ecc953bSthorpej void 874d74eb995Sdholland defoption(const char *fname, struct defoptlist *opts, struct nvlist *deps) 8755ecc953bSthorpej { 8765ecc953bSthorpej 877c7295a4cSchristos cfgwarn("The use of `defopt' is deprecated"); 878ac24e161Scube defopt(defopttab, fname, opts, deps, 0); 8795ecc953bSthorpej } 8805ecc953bSthorpej 8815ecc953bSthorpej 8825ecc953bSthorpej /* 8835ecc953bSthorpej * Define an option for which a value is required. 8845ecc953bSthorpej */ 8855ecc953bSthorpej void 886d74eb995Sdholland defparam(const char *fname, struct defoptlist *opts, struct nvlist *deps, int obs) 8875ecc953bSthorpej { 8885ecc953bSthorpej 889ac24e161Scube defopt(defparamtab, fname, opts, deps, obs); 8905ecc953bSthorpej } 8915ecc953bSthorpej 8925ecc953bSthorpej /* 89372303951Scube * Define an option which must not have a value, and which 8945ecc953bSthorpej * emits a "needs-flag" style output. 8955ecc953bSthorpej */ 8965ecc953bSthorpej void 897d74eb995Sdholland defflag(const char *fname, struct defoptlist *opts, struct nvlist *deps, int obs) 8985ecc953bSthorpej { 8995ecc953bSthorpej 900ac24e161Scube defopt(defflagtab, fname, opts, deps, obs); 9015ecc953bSthorpej } 9025ecc953bSthorpej 9035ecc953bSthorpej 9045ecc953bSthorpej /* 9055ecc953bSthorpej * Add an option from "options FOO". Note that this selects things that 9065ecc953bSthorpej * are "optional foo". 9075ecc953bSthorpej */ 9085ecc953bSthorpej void 9095ecc953bSthorpej addoption(const char *name, const char *value) 9105ecc953bSthorpej { 9115ecc953bSthorpej const char *n; 912c7295a4cSchristos int is_fs, is_param, is_flag, is_undecl, is_obs; 9135ecc953bSthorpej 9145ecc953bSthorpej /* 9155ecc953bSthorpej * Figure out how this option was declared (if at all.) 9165ecc953bSthorpej * XXX should use "params" and "flags" in config. 9175ecc953bSthorpej * XXX crying out for a type field in a unified hashtab. 9185ecc953bSthorpej */ 9195ecc953bSthorpej is_fs = OPT_FSOPT(name); 9205ecc953bSthorpej is_param = OPT_DEFPARAM(name); 9215ecc953bSthorpej is_flag = OPT_DEFFLAG(name); 922ac24e161Scube is_obs = OPT_OBSOLETE(name); 9235ecc953bSthorpej is_undecl = !DEFINED_OPTION(name); 9245ecc953bSthorpej 925ac24e161Scube /* Warn and pretend the user had not selected the option */ 926ac24e161Scube if (is_obs) { 927c7295a4cSchristos cfgwarn("obsolete option `%s' will be ignored", name); 928ac24e161Scube return; 929ac24e161Scube } 930ac24e161Scube 9315ecc953bSthorpej /* Make sure this is not a defined file system. */ 9325ecc953bSthorpej if (is_fs) { 933c7295a4cSchristos cfgerror("`%s' is a defined file system", name); 9345ecc953bSthorpej return; 9355ecc953bSthorpej } 9365ecc953bSthorpej /* A defparam must have a value */ 9375ecc953bSthorpej if (is_param && value == NULL) { 938c7295a4cSchristos cfgerror("option `%s' must have a value", name); 9395ecc953bSthorpej return; 9405ecc953bSthorpej } 9415ecc953bSthorpej /* A defflag must not have a value */ 9425ecc953bSthorpej if (is_flag && value != NULL) { 943c7295a4cSchristos cfgerror("option `%s' must not have a value", name); 9445ecc953bSthorpej return; 9455ecc953bSthorpej } 9465ecc953bSthorpej 9475ecc953bSthorpej if (is_undecl && vflag) { 948c7295a4cSchristos cfgwarn("undeclared option `%s' added to IDENT", name); 9495ecc953bSthorpej } 9505ecc953bSthorpej 9515ecc953bSthorpej if (do_option(opttab, &nextopt, name, value, "options")) 9525ecc953bSthorpej return; 9535ecc953bSthorpej 9545ecc953bSthorpej /* make lowercase, then add to select table */ 9555ecc953bSthorpej n = strtolower(name); 956c7295a4cSchristos (void)ht_insert(selecttab, n, (void *)__UNCONST(n)); 9575ecc953bSthorpej } 9585ecc953bSthorpej 9595ecc953bSthorpej void 9605ecc953bSthorpej deloption(const char *name) 9615ecc953bSthorpej { 9625ecc953bSthorpej 9635ecc953bSthorpej if (undo_option(opttab, &options, &nextopt, name, "options")) 9645ecc953bSthorpej return; 9655ecc953bSthorpej if (undo_option(selecttab, NULL, NULL, strtolower(name), "options")) 9665ecc953bSthorpej return; 9675ecc953bSthorpej } 9685ecc953bSthorpej 9695ecc953bSthorpej /* 9705ecc953bSthorpej * Add a file system option. This routine simply inserts the name into 9715ecc953bSthorpej * a list of valid file systems, which is used to validate the root 9725ecc953bSthorpej * file system type. The name is then treated like a standard option. 9735ecc953bSthorpej */ 9745ecc953bSthorpej void 9755ecc953bSthorpej addfsoption(const char *name) 9765ecc953bSthorpej { 9775ecc953bSthorpej const char *n; 9785ecc953bSthorpej 9795ecc953bSthorpej /* Make sure this is a defined file system. */ 9805ecc953bSthorpej if (!OPT_FSOPT(name)) { 981c7295a4cSchristos cfgerror("`%s' is not a defined file system", name); 9825ecc953bSthorpej return; 9835ecc953bSthorpej } 9845ecc953bSthorpej 9855ecc953bSthorpej /* 9865ecc953bSthorpej * Convert to lower case. This will be used in the select 987baec5c01Scube * table, to verify root file systems. 9885ecc953bSthorpej */ 9895ecc953bSthorpej n = strtolower(name); 9905ecc953bSthorpej 9915ecc953bSthorpej if (do_option(fsopttab, &nextfsopt, name, n, "file-system")) 9925ecc953bSthorpej return; 9935ecc953bSthorpej 9945ecc953bSthorpej /* Add to select table. */ 995c7295a4cSchristos (void)ht_insert(selecttab, n, __UNCONST(n)); 9965ecc953bSthorpej } 9975ecc953bSthorpej 9985ecc953bSthorpej void 9995ecc953bSthorpej delfsoption(const char *name) 10005ecc953bSthorpej { 10015ecc953bSthorpej const char *n; 10025ecc953bSthorpej 10035ecc953bSthorpej n = strtolower(name); 10045ecc953bSthorpej if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system")) 10055ecc953bSthorpej return; 10065ecc953bSthorpej if (undo_option(selecttab, NULL, NULL, n, "file-system")) 10075ecc953bSthorpej return; 10085ecc953bSthorpej } 10095ecc953bSthorpej 10105ecc953bSthorpej /* 10115ecc953bSthorpej * Add a "make" option. 10125ecc953bSthorpej */ 10135ecc953bSthorpej void 10145ecc953bSthorpej addmkoption(const char *name, const char *value) 10155ecc953bSthorpej { 10165ecc953bSthorpej 10175ecc953bSthorpej (void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions"); 10185ecc953bSthorpej } 10195ecc953bSthorpej 10205ecc953bSthorpej void 10215ecc953bSthorpej delmkoption(const char *name) 10225ecc953bSthorpej { 10235ecc953bSthorpej 10245ecc953bSthorpej (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name, 10255ecc953bSthorpej "makeoptions"); 10265ecc953bSthorpej } 10275ecc953bSthorpej 10285ecc953bSthorpej /* 10295ecc953bSthorpej * Add an appending "make" option. 10305ecc953bSthorpej */ 10315ecc953bSthorpej void 10325ecc953bSthorpej appendmkoption(const char *name, const char *value) 10335ecc953bSthorpej { 10345ecc953bSthorpej struct nvlist *nv; 10355ecc953bSthorpej 10365ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 10375ecc953bSthorpej *nextappmkopt = nv; 10385ecc953bSthorpej nextappmkopt = &nv->nv_next; 10395ecc953bSthorpej } 10405ecc953bSthorpej 10415ecc953bSthorpej /* 10425ecc953bSthorpej * Add a conditional appending "make" option. 10435ecc953bSthorpej */ 10445ecc953bSthorpej void 10459483bda7Sdholland appendcondmkoption(struct condexpr *cond, const char *name, const char *value) 10465ecc953bSthorpej { 1047a16a6365Scube struct nvlist *nv; 10485ecc953bSthorpej 10499483bda7Sdholland nv = newnv(name, value, cond, 0, NULL); 1050a16a6365Scube *nextcndmkopt = nv; 1051a16a6365Scube nextcndmkopt = &nv->nv_next; 10525ecc953bSthorpej } 10535ecc953bSthorpej 10545ecc953bSthorpej /* 10555ecc953bSthorpej * Add a name=value pair to an option list. The value may be NULL. 10565ecc953bSthorpej */ 10575ecc953bSthorpej static int 10585ecc953bSthorpej do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 10595ecc953bSthorpej const char *value, const char *type) 10605ecc953bSthorpej { 10615ecc953bSthorpej struct nvlist *nv; 10625ecc953bSthorpej 10635ecc953bSthorpej /* assume it will work */ 10645ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 10655ecc953bSthorpej if (ht_insert(ht, name, nv) == 0) { 10665ecc953bSthorpej **nppp = nv; 10675ecc953bSthorpej *nppp = &nv->nv_next; 10685ecc953bSthorpej return (0); 10695ecc953bSthorpej } 10705ecc953bSthorpej 10715ecc953bSthorpej /* oops, already got that option */ 10725ecc953bSthorpej nvfree(nv); 10735ecc953bSthorpej if ((nv = ht_lookup(ht, name)) == NULL) 10745ecc953bSthorpej panic("do_option"); 10755ecc953bSthorpej if (nv->nv_str != NULL && !OPT_FSOPT(name)) 1076c7295a4cSchristos cfgerror("already have %s `%s=%s'", type, name, nv->nv_str); 10775ecc953bSthorpej else 1078c7295a4cSchristos cfgerror("already have %s `%s'", type, name); 10795ecc953bSthorpej return (1); 10805ecc953bSthorpej } 10815ecc953bSthorpej 10825ecc953bSthorpej /* 10835ecc953bSthorpej * Remove a name from a hash table, 10845ecc953bSthorpej * and optionally, a name=value pair from an option list. 10855ecc953bSthorpej */ 10865ecc953bSthorpej static int 10875ecc953bSthorpej undo_option(struct hashtab *ht, struct nvlist **npp, 10885ecc953bSthorpej struct nvlist ***next, const char *name, const char *type) 10895ecc953bSthorpej { 10905ecc953bSthorpej struct nvlist *nv; 10915ecc953bSthorpej 10925ecc953bSthorpej if (ht_remove(ht, name)) { 1093d2737476Smartin /* 1094d2737476Smartin * -U command line option removals are always silent 1095d2737476Smartin */ 1096*34e6631aSbad if (!handling_cmdlineopts) 1097*34e6631aSbad cfgwarn("%s `%s' is not defined", type, name); 10985ecc953bSthorpej return (1); 10995ecc953bSthorpej } 11005ecc953bSthorpej if (npp == NULL) 11015ecc953bSthorpej return (0); 11025ecc953bSthorpej 11035ecc953bSthorpej for ( ; *npp != NULL; npp = &(*npp)->nv_next) { 11045ecc953bSthorpej if ((*npp)->nv_name != name) 11055ecc953bSthorpej continue; 11065ecc953bSthorpej if (next != NULL && *next == &(*npp)->nv_next) 11075ecc953bSthorpej *next = npp; 11085ecc953bSthorpej nv = (*npp)->nv_next; 11095ecc953bSthorpej nvfree(*npp); 11105ecc953bSthorpej *npp = nv; 11115ecc953bSthorpej return (0); 11125ecc953bSthorpej } 11135ecc953bSthorpej panic("%s `%s' is not defined in nvlist", type, name); 11145ecc953bSthorpej return (1); 11155ecc953bSthorpej } 11165ecc953bSthorpej 11175ecc953bSthorpej /* 11185ecc953bSthorpej * Return true if there is at least one instance of the given unit 11195ecc953bSthorpej * on the given device attachment (or any units, if unit == WILD). 11205ecc953bSthorpej */ 11215ecc953bSthorpej int 11225ecc953bSthorpej deva_has_instances(struct deva *deva, int unit) 11235ecc953bSthorpej { 11245ecc953bSthorpej struct devi *i; 11255ecc953bSthorpej 112690ac64deSpooka /* 112790ac64deSpooka * EHAMMERTOOBIG: we shouldn't check i_pseudoroot here. 112890ac64deSpooka * What we want by this check is them to appear non-present 112990ac64deSpooka * except for purposes of other devices being able to attach 113090ac64deSpooka * to them. 113190ac64deSpooka */ 11325ecc953bSthorpej for (i = deva->d_ihead; i != NULL; i = i->i_asame) 113390ac64deSpooka if (i->i_active == DEVI_ACTIVE && i->i_pseudoroot == 0 && 1134c130d400Scube (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) 11355ecc953bSthorpej return (1); 11365ecc953bSthorpej return (0); 11375ecc953bSthorpej } 11385ecc953bSthorpej 11395ecc953bSthorpej /* 11405ecc953bSthorpej * Return true if there is at least one instance of the given unit 11415ecc953bSthorpej * on the given base (or any units, if unit == WILD). 11425ecc953bSthorpej */ 11435ecc953bSthorpej int 11445ecc953bSthorpej devbase_has_instances(struct devbase *dev, int unit) 11455ecc953bSthorpej { 11465ecc953bSthorpej struct deva *da; 11475ecc953bSthorpej 11485ecc953bSthorpej /* 11495ecc953bSthorpej * Pseudo-devices are a little special. We consider them 11505ecc953bSthorpej * to have instances only if they are both: 11515ecc953bSthorpej * 11525ecc953bSthorpej * 1. Included in this kernel configuration. 11535ecc953bSthorpej * 1154b66156c7Sdrochner * 2. Be declared "defpseudodev". 11555ecc953bSthorpej */ 11565ecc953bSthorpej if (dev->d_ispseudo) { 1157b66156c7Sdrochner return ((ht_lookup(devitab, dev->d_name) != NULL) 1158b66156c7Sdrochner && (dev->d_ispseudo > 1)); 11595ecc953bSthorpej } 11605ecc953bSthorpej 11615ecc953bSthorpej for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 11625ecc953bSthorpej if (deva_has_instances(da, unit)) 11635ecc953bSthorpej return (1); 11645ecc953bSthorpej return (0); 11655ecc953bSthorpej } 11665ecc953bSthorpej 11675ecc953bSthorpej static int 11685ecc953bSthorpej cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 11695ecc953bSthorpej { 11705ecc953bSthorpej struct devbase *dev; 11715ecc953bSthorpej struct devi *pd; 11725ecc953bSthorpej int errs, devunit; 11735ecc953bSthorpej 11745ecc953bSthorpej if (maxpartitions <= 0) 11755ecc953bSthorpej panic("cfcrosscheck"); 11765ecc953bSthorpej 11775ecc953bSthorpej for (errs = 0; nv != NULL; nv = nv->nv_next) { 11785ecc953bSthorpej if (nv->nv_name == NULL) 11795ecc953bSthorpej continue; 11805ecc953bSthorpej dev = ht_lookup(devbasetab, nv->nv_name); 11815ecc953bSthorpej if (dev == NULL) 11825ecc953bSthorpej panic("cfcrosscheck(%s)", nv->nv_name); 11835ecc953bSthorpej if (has_attr(dev->d_attrs, s_ifnet)) 11845ecc953bSthorpej devunit = nv->nv_ifunit; /* XXX XXX XXX */ 11855ecc953bSthorpej else 11860001b928Schristos devunit = (int)(minor(nv->nv_num) / maxpartitions); 11875ecc953bSthorpej if (devbase_has_instances(dev, devunit)) 11885ecc953bSthorpej continue; 11895ecc953bSthorpej if (devbase_has_instances(dev, STAR) && 11905ecc953bSthorpej devunit >= dev->d_umax) 11915ecc953bSthorpej continue; 11925ecc953bSthorpej TAILQ_FOREACH(pd, &allpseudo, i_next) { 11935ecc953bSthorpej if (pd->i_base == dev && devunit < dev->d_umax && 11945ecc953bSthorpej devunit >= 0) 11955ecc953bSthorpej goto loop; 11965ecc953bSthorpej } 11975ecc953bSthorpej (void)fprintf(stderr, 1198fb65a080Schristos "%s:%d: %s says %s on %s, but there's no %s\n", 11995ecc953bSthorpej conffile, cf->cf_lineno, 12005ecc953bSthorpej cf->cf_name, what, nv->nv_str, nv->nv_str); 12015ecc953bSthorpej errs++; 12025ecc953bSthorpej loop: 12035ecc953bSthorpej ; 12045ecc953bSthorpej } 12055ecc953bSthorpej return (errs); 12065ecc953bSthorpej } 12075ecc953bSthorpej 12085ecc953bSthorpej /* 12095ecc953bSthorpej * Cross-check the configuration: make sure that each target device 12105ecc953bSthorpej * or attribute (`at foo[0*?]') names at least one real device. Also 12115ecc953bSthorpej * see that the root and dump devices for all configurations are there. 12125ecc953bSthorpej */ 12135ecc953bSthorpej int 12145ecc953bSthorpej crosscheck(void) 12155ecc953bSthorpej { 12165ecc953bSthorpej struct config *cf; 12175ecc953bSthorpej int errs; 12185ecc953bSthorpej 12195ecc953bSthorpej errs = 0; 12205ecc953bSthorpej if (TAILQ_EMPTY(&allcf)) { 1221c7295a4cSchristos warnx("%s has no configurations!", conffile); 12225ecc953bSthorpej errs++; 12235ecc953bSthorpej } 12245ecc953bSthorpej TAILQ_FOREACH(cf, &allcf, cf_next) { 12255ecc953bSthorpej if (cf->cf_root != NULL) { /* i.e., not root on ? */ 12265ecc953bSthorpej errs += cfcrosscheck(cf, "root", cf->cf_root); 12275ecc953bSthorpej errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 12285ecc953bSthorpej } 12295ecc953bSthorpej } 12305ecc953bSthorpej return (errs); 12315ecc953bSthorpej } 12325ecc953bSthorpej 12335ecc953bSthorpej /* 12345ecc953bSthorpej * Check to see if there is a *'d unit with a needs-count file. 12355ecc953bSthorpej */ 12365ecc953bSthorpej int 12375ecc953bSthorpej badstar(void) 12385ecc953bSthorpej { 12395ecc953bSthorpej struct devbase *d; 12405ecc953bSthorpej struct deva *da; 12415ecc953bSthorpej struct devi *i; 12425ecc953bSthorpej int errs, n; 12435ecc953bSthorpej 12445ecc953bSthorpej errs = 0; 12455ecc953bSthorpej TAILQ_FOREACH(d, &allbases, d_next) { 12465ecc953bSthorpej for (da = d->d_ahead; da != NULL; da = da->d_bsame) 12475ecc953bSthorpej for (i = da->d_ihead; i != NULL; i = i->i_asame) { 12485ecc953bSthorpej if (i->i_unit == STAR) 12495ecc953bSthorpej goto aybabtu; 12505ecc953bSthorpej } 12515ecc953bSthorpej continue; 12525ecc953bSthorpej aybabtu: 12535ecc953bSthorpej if (ht_lookup(needcnttab, d->d_name)) { 1254c7295a4cSchristos warnx("%s's cannot be *'d until its driver is fixed", 12555ecc953bSthorpej d->d_name); 12565ecc953bSthorpej errs++; 12575ecc953bSthorpej continue; 12585ecc953bSthorpej } 12595ecc953bSthorpej for (n = 0; i != NULL; i = i->i_alias) 12605ecc953bSthorpej if (!i->i_collapsed) 12615ecc953bSthorpej n++; 12625ecc953bSthorpej if (n < 1) 12635ecc953bSthorpej panic("badstar() n<1"); 12645ecc953bSthorpej } 12655ecc953bSthorpej return (errs); 12665ecc953bSthorpej } 12675ecc953bSthorpej 12685ecc953bSthorpej /* 12695ecc953bSthorpej * Verify/create builddir if necessary, change to it, and verify srcdir. 12705ecc953bSthorpej * This will be called when we see the first include. 12715ecc953bSthorpej */ 12725ecc953bSthorpej void 12735ecc953bSthorpej setupdirs(void) 12745ecc953bSthorpej { 12755ecc953bSthorpej struct stat st; 12765ecc953bSthorpej 12775ecc953bSthorpej /* srcdir must be specified if builddir is not specified or if 12785ecc953bSthorpej * no configuration filename was specified. */ 12795ecc953bSthorpej if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 1280c7295a4cSchristos cfgerror("source directory must be specified"); 12815ecc953bSthorpej exit(1); 12825ecc953bSthorpej } 12835ecc953bSthorpej 128459c94545Scube if (Lflag) { 128559c94545Scube if (srcdir == NULL) 128659c94545Scube srcdir = "../../.."; 128759c94545Scube return; 128859c94545Scube } 128959c94545Scube 12905ecc953bSthorpej if (srcdir == NULL) 12915ecc953bSthorpej srcdir = "../../../.."; 12925ecc953bSthorpej if (builddir == NULL) 12935ecc953bSthorpej builddir = defbuilddir; 12945ecc953bSthorpej 1295c7295a4cSchristos if (stat(builddir, &st) == -1) { 1296c7295a4cSchristos if (mkdir(builddir, 0777) == -1) 1297c7295a4cSchristos errx(EXIT_FAILURE, "cannot create %s", builddir); 1298c7295a4cSchristos } else if (!S_ISDIR(st.st_mode)) 1299c7295a4cSchristos errx(EXIT_FAILURE, "%s is not a directory", builddir); 1300c7295a4cSchristos if (chdir(builddir) == -1) 1301c7295a4cSchristos err(EXIT_FAILURE, "cannot change to %s", builddir); 1302c7295a4cSchristos if (stat(srcdir, &st) == -1) 1303c7295a4cSchristos err(EXIT_FAILURE, "cannot stat %s", srcdir); 1304c7295a4cSchristos if (!S_ISDIR(st.st_mode)) 1305c7295a4cSchristos errx(EXIT_FAILURE, "%s is not a directory", srcdir); 13065ecc953bSthorpej } 13075ecc953bSthorpej 13085ecc953bSthorpej /* 13095ecc953bSthorpej * Write identifier from "ident" directive into file, for 13105ecc953bSthorpej * newvers.sh to pick it up. 13115ecc953bSthorpej */ 13125ecc953bSthorpej int 13135ecc953bSthorpej mkident(void) 13145ecc953bSthorpej { 13155ecc953bSthorpej FILE *fp; 131611820066Scube int error = 0; 13175ecc953bSthorpej 13185ecc953bSthorpej (void)unlink("ident"); 13195ecc953bSthorpej 13205ecc953bSthorpej if (ident == NULL) 13215ecc953bSthorpej return (0); 13225ecc953bSthorpej 13235ecc953bSthorpej if ((fp = fopen("ident", "w")) == NULL) { 1324c7295a4cSchristos warn("cannot write ident"); 13255ecc953bSthorpej return (1); 13265ecc953bSthorpej } 13275ecc953bSthorpej if (vflag) 13285ecc953bSthorpej (void)printf("using ident '%s'\n", ident); 1329342d3579Sdsl fprintf(fp, "%s\n", ident); 1330342d3579Sdsl fflush(fp); 1331342d3579Sdsl if (ferror(fp)) 133211820066Scube error = 1; 13335ecc953bSthorpej (void)fclose(fp); 13345ecc953bSthorpej 133511820066Scube return error; 13365ecc953bSthorpej } 13375ecc953bSthorpej 13385ecc953bSthorpej void 13395ecc953bSthorpej logconfig_start(void) 13405ecc953bSthorpej { 13415ecc953bSthorpej extern FILE *yyin; 13425ecc953bSthorpej char line[1024]; 13435ecc953bSthorpej const char *tmpdir; 13445ecc953bSthorpej struct stat st; 13455ecc953bSthorpej int fd; 13465ecc953bSthorpej 13475ecc953bSthorpej if (yyin == NULL || fstat(fileno(yyin), &st) == -1) 13485ecc953bSthorpej return; 13495ecc953bSthorpej cfgtime = st.st_mtime; 13505ecc953bSthorpej 13515ecc953bSthorpej tmpdir = getenv("TMPDIR"); 13525ecc953bSthorpej if (tmpdir == NULL) 13533b398d5cSdholland tmpdir = _PATH_TMP; 1354c7295a4cSchristos (void)snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); 13555ecc953bSthorpej if ((fd = mkstemp(line)) == -1 || 13565ecc953bSthorpej (cfg = fdopen(fd, "r+")) == NULL) { 13575ecc953bSthorpej if (fd != -1) { 1358c7295a4cSchristos (void)unlink(line); 1359c7295a4cSchristos (void)close(fd); 13605ecc953bSthorpej } 13615ecc953bSthorpej cfg = NULL; 13625ecc953bSthorpej return; 13635ecc953bSthorpej } 1364c7295a4cSchristos (void)unlink(line); 13655ecc953bSthorpej 13664e4935bbSuwe (void)fprintf(cfg, "#include <sys/cdefs.h>\n\n"); 13675ecc953bSthorpej (void)fprintf(cfg, "#include \"opt_config.h\"\n"); 13685ecc953bSthorpej (void)fprintf(cfg, "\n"); 13695ecc953bSthorpej (void)fprintf(cfg, "/*\n"); 13705ecc953bSthorpej (void)fprintf(cfg, " * Add either (or both) of\n"); 13715ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13725ecc953bSthorpej (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); 13735ecc953bSthorpej (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); 13745ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13755ecc953bSthorpej (void)fprintf(cfg, 13765ecc953bSthorpej " * to your kernel config file to embed it in the resulting\n"); 13775ecc953bSthorpej (void)fprintf(cfg, 13785ecc953bSthorpej " * kernel. The latter option does not include files that are\n"); 13795ecc953bSthorpej (void)fprintf(cfg, 13805ecc953bSthorpej " * included (recursively) by your config file. The embedded\n"); 13815ecc953bSthorpej (void)fprintf(cfg, 13825ecc953bSthorpej " * data be extracted by using the command:\n"); 13835ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13845ecc953bSthorpej (void)fprintf(cfg, 13855ecc953bSthorpej " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); 13865ecc953bSthorpej (void)fprintf(cfg, " */\n"); 13875ecc953bSthorpej (void)fprintf(cfg, "\n"); 13885ecc953bSthorpej (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); 13895ecc953bSthorpej (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", 13905ecc953bSthorpej LOGCONFIG_LARGE, LOGCONFIG_SMALL); 13914e4935bbSuwe (void)fprintf(cfg, "static const char config[] __used =\n\n"); 13925ecc953bSthorpej 13935ecc953bSthorpej (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 13945ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", 13955ecc953bSthorpej conffile); 13965ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); 13975ecc953bSthorpej 13985ecc953bSthorpej logconfig_include(yyin, NULL); 13995ecc953bSthorpej 14005ecc953bSthorpej (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 14015ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", 14025ecc953bSthorpej conffile); 14035ecc953bSthorpej 14045ecc953bSthorpej rewind(yyin); 14055ecc953bSthorpej } 14065ecc953bSthorpej 14075ecc953bSthorpej void 14085ecc953bSthorpej logconfig_include(FILE *cf, const char *filename) 14095ecc953bSthorpej { 14105ecc953bSthorpej char line[1024], in[2048], *out; 14115ecc953bSthorpej struct stat st; 14125ecc953bSthorpej int missingeol; 14135ecc953bSthorpej 14145ecc953bSthorpej if (!cfg) 14155ecc953bSthorpej return; 14165ecc953bSthorpej 14175ecc953bSthorpej missingeol = 0; 14185ecc953bSthorpej if (fstat(fileno(cf), &st) == -1) 14195ecc953bSthorpej return; 14205ecc953bSthorpej if (cfgtime < st.st_mtime) 14215ecc953bSthorpej cfgtime = st.st_mtime; 14225ecc953bSthorpej 14235ecc953bSthorpej if (filename) 14245ecc953bSthorpej (void)fprintf(cfg, 14255ecc953bSthorpej "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", 14265ecc953bSthorpej filename); 14275ecc953bSthorpej while (fgets(line, sizeof(line), cf) != NULL) { 14285ecc953bSthorpej missingeol = 1; 14295ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_"); 14305ecc953bSthorpej if (filename) 14315ecc953bSthorpej (void)fprintf(cfg, "###> "); 14325ecc953bSthorpej strvis(in, line, VIS_TAB); 14335ecc953bSthorpej for (out = in; *out; out++) 14345ecc953bSthorpej switch (*out) { 14355ecc953bSthorpej case '\n': 14365ecc953bSthorpej (void)fprintf(cfg, "\\n\"\n"); 14375ecc953bSthorpej missingeol = 0; 14385ecc953bSthorpej break; 14395ecc953bSthorpej case '"': case '\\': 14405ecc953bSthorpej (void)fputc('\\', cfg); 14415ecc953bSthorpej /* FALLTHROUGH */ 14425ecc953bSthorpej default: 14435ecc953bSthorpej (void)fputc(*out, cfg); 14445ecc953bSthorpej break; 14455ecc953bSthorpej } 14465ecc953bSthorpej } 14475ecc953bSthorpej if (missingeol) { 14485ecc953bSthorpej (void)fprintf(cfg, "\\n\"\n"); 1449c7295a4cSchristos warnx("%s: newline missing at EOF", 14505ecc953bSthorpej filename != NULL ? filename : conffile); 14515ecc953bSthorpej } 14525ecc953bSthorpej if (filename) 14535ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", 14545ecc953bSthorpej filename); 14555ecc953bSthorpej 14565ecc953bSthorpej rewind(cf); 14575ecc953bSthorpej } 14585ecc953bSthorpej 14595ecc953bSthorpej void 14605ecc953bSthorpej logconfig_end(void) 14615ecc953bSthorpej { 14625ecc953bSthorpej char line[1024]; 14635ecc953bSthorpej FILE *fp; 14645ecc953bSthorpej struct stat st; 14655ecc953bSthorpej 14665ecc953bSthorpej if (!cfg) 14675ecc953bSthorpej return; 14685ecc953bSthorpej 14695ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); 14705ecc953bSthorpej (void)fprintf(cfg, ";\n"); 14715ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s || %s */\n", 14725ecc953bSthorpej LOGCONFIG_LARGE, LOGCONFIG_SMALL); 14735ecc953bSthorpej (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); 1474342d3579Sdsl fflush(cfg); 1475342d3579Sdsl if (ferror(cfg)) 1476342d3579Sdsl err(EXIT_FAILURE, "write to temporary file for config.h failed"); 14775ecc953bSthorpej rewind(cfg); 14785ecc953bSthorpej 14795ecc953bSthorpej if (stat("config_file.h", &st) != -1) { 14805ecc953bSthorpej if (cfgtime < st.st_mtime) { 14815ecc953bSthorpej fclose(cfg); 14825ecc953bSthorpej return; 14835ecc953bSthorpej } 14845ecc953bSthorpej } 14855ecc953bSthorpej 14865ecc953bSthorpej fp = fopen("config_file.h", "w"); 1487342d3579Sdsl if (!fp) 1488342d3579Sdsl err(EXIT_FAILURE, "cannot open \"config.h\""); 14895ecc953bSthorpej 14905ecc953bSthorpej while (fgets(line, sizeof(line), cfg) != NULL) 14915ecc953bSthorpej fputs(line, fp); 1492342d3579Sdsl fflush(fp); 1493342d3579Sdsl if (ferror(fp)) 1494342d3579Sdsl err(EXIT_FAILURE, "write to \"config.h\" failed"); 14955ecc953bSthorpej fclose(fp); 14965ecc953bSthorpej fclose(cfg); 14975ecc953bSthorpej } 14985ecc953bSthorpej 1499a16a6365Scube const char * 15005ecc953bSthorpej strtolower(const char *name) 15015ecc953bSthorpej { 15025ecc953bSthorpej const char *n; 15035ecc953bSthorpej char *p, low[500]; 15045ecc953bSthorpej unsigned char c; 15055ecc953bSthorpej 15065ecc953bSthorpej for (n = name, p = low; (c = *n) != '\0'; n++) 15075ecc953bSthorpej *p++ = isupper(c) ? tolower(c) : c; 15085ecc953bSthorpej *p = 0; 15095ecc953bSthorpej return (intern(low)); 15105ecc953bSthorpej } 15115ecc953bSthorpej 15125ecc953bSthorpej static int 15135ecc953bSthorpej is_elf(const char *file) 15145ecc953bSthorpej { 15155ecc953bSthorpej int kernel; 15165ecc953bSthorpej char hdr[4]; 15175ecc953bSthorpej 15185ecc953bSthorpej kernel = open(file, O_RDONLY); 1519c7295a4cSchristos if (kernel == -1) 1520c7295a4cSchristos err(EXIT_FAILURE, "cannot open %s", file); 1521c7295a4cSchristos if (read(kernel, hdr, 4) != 4) 1522c7295a4cSchristos err(EXIT_FAILURE, "Cannot read from %s", file); 1523c7295a4cSchristos (void)close(kernel); 15245ecc953bSthorpej 15255ecc953bSthorpej return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; 15265ecc953bSthorpej } 15275ecc953bSthorpej 15285ecc953bSthorpej static int 15295ecc953bSthorpej extract_config(const char *kname, const char *cname, int cfd) 15305ecc953bSthorpej { 15315ecc953bSthorpej char *ptr; 15325ecc953bSthorpej int found, kfd, i; 15335ecc953bSthorpej struct stat st; 15345ecc953bSthorpej 15355ecc953bSthorpej found = 0; 15365ecc953bSthorpej 15375ecc953bSthorpej /* mmap(2) binary kernel */ 15385ecc953bSthorpej kfd = open(conffile, O_RDONLY); 1539c7295a4cSchristos if (kfd == -1) 1540c7295a4cSchristos err(EXIT_FAILURE, "cannot open %s", kname); 1541c7295a4cSchristos if (fstat(kfd, &st) == -1) 1542c7295a4cSchristos err(EXIT_FAILURE, "cannot stat %s", kname); 1543c7295a4cSchristos ptr = mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, 15445ecc953bSthorpej kfd, 0); 1545c7295a4cSchristos if (ptr == MAP_FAILED) 1546c7295a4cSchristos err(EXIT_FAILURE, "cannot mmap %s", kname); 15475ecc953bSthorpej 15485ecc953bSthorpej /* Scan mmap(2)'ed region, extracting kernel configuration */ 15495ecc953bSthorpej for (i = 0; i < st.st_size; i++) { 15505ecc953bSthorpej if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, 15515ecc953bSthorpej "_CFG_", 5) == 0) { 15525ecc953bSthorpej /* Line found */ 15535ecc953bSthorpej char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; 15545ecc953bSthorpej int j; 15555ecc953bSthorpej 15565ecc953bSthorpej found = 1; 15575ecc953bSthorpej 15585ecc953bSthorpej oldptr = (ptr += 5); 1559c7295a4cSchristos while (*ptr != '\n' && *ptr != '\0') 1560c7295a4cSchristos ptr++; 1561c7295a4cSchristos if (ptr - oldptr > LINE_MAX) 1562c7295a4cSchristos errx(EXIT_FAILURE, "line too long"); 15635ecc953bSthorpej i += ptr - oldptr + 5; 1564c7295a4cSchristos (void)memcpy(line, oldptr, (size_t)(ptr - oldptr)); 15655ecc953bSthorpej line[ptr - oldptr] = '\0'; 15665ecc953bSthorpej j = strunvis(uline, line); 1567c7295a4cSchristos if (j == -1) 1568c7295a4cSchristos errx(EXIT_FAILURE, "unvis: invalid " 1569c7295a4cSchristos "encoded sequence"); 15705ecc953bSthorpej uline[j] = '\n'; 1571c7295a4cSchristos if (write(cfd, uline, (size_t)j + 1) == -1) 1572c7295a4cSchristos err(EXIT_FAILURE, "cannot write to %s", cname); 1573c7295a4cSchristos } else 1574c7295a4cSchristos ptr++; 15755ecc953bSthorpej } 15765ecc953bSthorpej 1577c7295a4cSchristos (void)close(kfd); 15785ecc953bSthorpej 15795ecc953bSthorpej return found; 15805ecc953bSthorpej } 1581c130d400Scube 15827aa6070dScube struct dhdi_params { 15837aa6070dScube struct devbase *d; 15847aa6070dScube int unit; 1585a31ff6b4Scube int level; 15867aa6070dScube }; 15877aa6070dScube 15887aa6070dScube static int 15897aa6070dScube devbase_has_dead_instances(const char *key, void *value, void *aux) 15907aa6070dScube { 1591a31ff6b4Scube struct devi *i; 15927aa6070dScube struct dhdi_params *dhdi = aux; 15937aa6070dScube 1594a31ff6b4Scube for (i = value; i != NULL; i = i->i_alias) 15957aa6070dScube if (i->i_base == dhdi->d && 15967aa6070dScube (dhdi->unit == WILD || dhdi->unit == i->i_unit || 1597a31ff6b4Scube i->i_unit == STAR) && 1598a31ff6b4Scube i->i_level >= dhdi->level) 15997aa6070dScube return 1; 16007aa6070dScube return 0; 16017aa6070dScube } 16027aa6070dScube 16037aa6070dScube /* 16047aa6070dScube * This is almost the same as devbase_has_instances, except it 16057aa6070dScube * may have special considerations regarding ignored instances. 16067aa6070dScube */ 16077aa6070dScube 16087aa6070dScube static int 1609a31ff6b4Scube devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) 16107aa6070dScube { 16117aa6070dScube struct deva *da; 16127aa6070dScube struct devi *i; 16137aa6070dScube 16147aa6070dScube if (dev->d_ispseudo) { 16157aa6070dScube if (dev->d_ihead != NULL) 16167aa6070dScube return 1; 1617a31ff6b4Scube else if (state != DEVI_IGNORED) 16187aa6070dScube return 0; 1619a31ff6b4Scube if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) 1620a31ff6b4Scube return 0; 1621a31ff6b4Scube return (i->i_level >= level); 16227aa6070dScube } 16237aa6070dScube 16247aa6070dScube for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 16257aa6070dScube for (i = da->d_ihead; i != NULL; i = i->i_asame) 16267aa6070dScube if ((i->i_active == DEVI_ACTIVE || 16277aa6070dScube i->i_active == state) && 16287aa6070dScube (unit == WILD || unit == i->i_unit || 16297aa6070dScube i->i_unit == STAR)) 16307aa6070dScube return 1; 16317aa6070dScube 16327aa6070dScube if (state == DEVI_IGNORED) { 1633a31ff6b4Scube struct dhdi_params dhdi = { dev, unit, level }; 16347aa6070dScube /* also check dead devices */ 16357aa6070dScube return ht_enumerate(deaddevitab, devbase_has_dead_instances, 16367aa6070dScube &dhdi); 16377aa6070dScube } 16387aa6070dScube 16397aa6070dScube return 0; 16407aa6070dScube } 16417aa6070dScube 16427aa6070dScube /* 16437aa6070dScube * check_dead_devi(), used with ht_enumerate, checks if any of the removed 16447aa6070dScube * device instances would have been a valid instance considering the devbase, 16457aa6070dScube * the parent device and the interface attribute. 16467aa6070dScube * 16477aa6070dScube * In other words, for a non-active device, it checks if children would be 16487aa6070dScube * actual orphans or the result of a negative statement in the config file. 16497aa6070dScube */ 16507aa6070dScube 16517aa6070dScube struct cdd_params { 16527aa6070dScube struct devbase *d; 16537aa6070dScube struct attr *at; 16547aa6070dScube struct devbase *parent; 16557aa6070dScube }; 16567aa6070dScube 16577aa6070dScube static int 16587aa6070dScube check_dead_devi(const char *key, void *value, void *aux) 16597aa6070dScube { 16607aa6070dScube struct cdd_params *cdd = aux; 16617aa6070dScube struct devi *i = value; 1662a31ff6b4Scube struct pspec *p; 16637aa6070dScube 16647aa6070dScube if (i->i_base != cdd->d) 16657aa6070dScube return 0; 16667aa6070dScube 1667a31ff6b4Scube for (; i != NULL; i = i->i_alias) { 1668a31ff6b4Scube p = i->i_pspec; 16697aa6070dScube if ((p == NULL && cdd->at == NULL) || 16707aa6070dScube (p != NULL && p->p_iattr == cdd->at && 16717aa6070dScube (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { 16727aa6070dScube if (p != NULL && 16737aa6070dScube !devbase_has_any_instance(cdd->parent, p->p_atunit, 1674a31ff6b4Scube DEVI_IGNORED, i->i_level)) 16757aa6070dScube return 0; 16767aa6070dScube else 16777aa6070dScube return 1; 16787aa6070dScube } 1679a31ff6b4Scube } 16807aa6070dScube return 0; 16817aa6070dScube } 16827aa6070dScube 1683c130d400Scube static void 16847aa6070dScube do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, 16857aa6070dScube int state) 1686c130d400Scube { 16874caf067bSdholland struct nvlist *nv1; 16884caf067bSdholland struct attrlist *al; 1689c130d400Scube struct attr *a; 1690c130d400Scube struct devi *i, *j = NULL; 1691c130d400Scube struct pspec *p; 16927aa6070dScube int active = 0; 1693c130d400Scube 1694c130d400Scube /* 1695c130d400Scube * A pseudo-device will always attach at root, and if it has an 1696c130d400Scube * instance (it cannot have more than one), it is enough to consider 1697c130d400Scube * it active, as there is no real attachment. 16987aa6070dScube * 16997aa6070dScube * A pseudo device can never be marked DEVI_IGNORED. 1700c130d400Scube */ 1701c130d400Scube if (d->d_ispseudo) { 17027aa6070dScube if (d->d_ihead != NULL) 17037aa6070dScube d->d_ihead->i_active = active = DEVI_ACTIVE; 17047aa6070dScube else { 17057aa6070dScube if (ht_lookup(deaddevitab, d->d_name) != NULL) 17067aa6070dScube active = DEVI_IGNORED; 17077aa6070dScube else 1708c130d400Scube return; 17097aa6070dScube } 1710c130d400Scube } else { 17112fb411a1Scube int seen = 0; 17122fb411a1Scube 1713c130d400Scube for (i = d->d_ihead; i != NULL; i = i->i_bsame) { 1714c130d400Scube for (j = i; j != NULL; j = j->i_alias) { 1715c130d400Scube p = j->i_pspec; 1716c130d400Scube if ((p == NULL && at == NULL) || 1717c130d400Scube (p != NULL && p->p_iattr == at && 1718c130d400Scube (p->p_atdev == NULL || 1719c130d400Scube p->p_atdev == parent))) { 1720c130d400Scube if (p != NULL && 17217aa6070dScube !devbase_has_any_instance(parent, 1722a31ff6b4Scube p->p_atunit, state, j->i_level)) 1723c130d400Scube continue; 1724c130d400Scube /* 1725c130d400Scube * There are Fry-like devices which can 1726c130d400Scube * be their own grand-parent (or even 1727c130d400Scube * parent, like uhub). We don't want 1728c130d400Scube * to loop, so if we've already reached 1729c130d400Scube * an instance for one reason or 1730c130d400Scube * another, stop there. 1731c130d400Scube */ 17327aa6070dScube if (j->i_active == DEVI_ACTIVE || 17332fb411a1Scube j->i_active == state) { 1734c130d400Scube /* 1735c130d400Scube * Device has already been 17362fb411a1Scube * seen. However it might 17372fb411a1Scube * have siblings who still 17382fb411a1Scube * have to be activated or 17392fb411a1Scube * orphaned. 1740c130d400Scube */ 17412fb411a1Scube seen = 1; 17422fb411a1Scube continue; 17432fb411a1Scube } 17447aa6070dScube j->i_active = active = state; 1745c130d400Scube if (p != NULL) 17467aa6070dScube p->p_active = state; 1747c130d400Scube } 1748c130d400Scube } 1749c130d400Scube } 1750b7505c15Scube /* 1751b7505c15Scube * If we've been there but have made no change, stop. 1752b7505c15Scube */ 1753b7505c15Scube if (seen && !active) 17542fb411a1Scube return; 17557aa6070dScube if (!active) { 17567aa6070dScube struct cdd_params cdd = { d, at, parent }; 17577aa6070dScube /* Look for a matching dead devi */ 175842256315Scube if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) && 175942256315Scube d != parent) 17607aa6070dScube /* 17617aa6070dScube * That device had its instances removed. 17627aa6070dScube * Continue the loop marking descendants 17637aa6070dScube * with DEVI_IGNORED instead of DEVI_ACTIVE. 176442256315Scube * 176542256315Scube * There is one special case for devices that 176642256315Scube * are their own parent: if that instance is 176742256315Scube * removed (e.g., no uhub* at uhub?), we don't 176842256315Scube * have to continue looping. 17697aa6070dScube */ 17707aa6070dScube active = DEVI_IGNORED; 17717aa6070dScube else 1772c130d400Scube return; 1773c130d400Scube } 17747aa6070dScube } 1775c130d400Scube 17764caf067bSdholland for (al = d->d_attrs; al != NULL; al = al->al_next) { 17774caf067bSdholland a = al->al_this; 1778c130d400Scube for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) 17797aa6070dScube do_kill_orphans(nv1->nv_ptr, a, d, active); 1780c130d400Scube } 1781c130d400Scube } 1782c130d400Scube 1783c130d400Scube static int 1784c7295a4cSchristos /*ARGSUSED*/ 1785c130d400Scube kill_orphans_cb(const char *key, void *value, void *aux) 1786c130d400Scube { 17877aa6070dScube do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); 1788c130d400Scube return 0; 1789c130d400Scube } 1790c130d400Scube 1791c130d400Scube static void 1792c7295a4cSchristos kill_orphans(void) 1793c130d400Scube { 1794c130d400Scube ht_enumerate(devroottab, kill_orphans_cb, NULL); 1795c130d400Scube } 1796d2737476Smartin 1797d2737476Smartin static void 1798d2737476Smartin add_makeopt(const char *opt) 1799d2737476Smartin { 1800d2737476Smartin struct nvlist *p; 1801d2737476Smartin char *buf = estrdup(opt); 1802d2737476Smartin char *eq = strchr(buf, '='); 1803d2737476Smartin 1804d2737476Smartin if (!eq) 1805d2737476Smartin errx(EXIT_FAILURE, "-D %s is not in var=value format", opt); 1806d2737476Smartin 1807d2737476Smartin *eq = 0; 1808d2737476Smartin p = newnv(estrdup(buf), estrdup(eq+1), NULL, 0, NULL); 1809d2737476Smartin free(buf); 1810d2737476Smartin p->nv_next = cmdlinedefs; 1811d2737476Smartin cmdlinedefs = p; 1812d2737476Smartin } 1813d2737476Smartin 1814d2737476Smartin static void 1815d2737476Smartin remove_makeopt(const char *opt) 1816d2737476Smartin { 1817d2737476Smartin struct nvlist *p; 1818d2737476Smartin 1819d2737476Smartin p = newnv(estrdup(opt), NULL, NULL, 0, NULL); 1820d2737476Smartin p->nv_next = cmdlineundefs; 1821d2737476Smartin cmdlineundefs = p; 1822d2737476Smartin } 1823d2737476Smartin 1824d2737476Smartin static void 1825d2737476Smartin handle_cmdline_makeoptions(void) 1826d2737476Smartin { 1827d2737476Smartin struct nvlist *p, *n; 1828d2737476Smartin 1829d2737476Smartin handling_cmdlineopts = 1; 1830d2737476Smartin for (p = cmdlineundefs; p; p = n) { 1831d2737476Smartin n = p->nv_next; 1832d2737476Smartin delmkoption(intern(p->nv_name)); 1833d2737476Smartin free(__UNCONST(p->nv_name)); 1834d2737476Smartin nvfree(p); 1835d2737476Smartin } 1836d2737476Smartin for (p = cmdlinedefs; p; p = n) { 1837d2737476Smartin const char *name = intern(p->nv_name); 1838d2737476Smartin 1839d2737476Smartin n = p->nv_next; 1840d2737476Smartin delmkoption(name); 1841d2737476Smartin addmkoption(name, intern(p->nv_str)); 1842d2737476Smartin free(__UNCONST(p->nv_name)); 1843d2737476Smartin free(__UNCONST(p->nv_str)); 1844d2737476Smartin 1845d2737476Smartin nvfree(p); 1846d2737476Smartin } 1847d2737476Smartin handling_cmdlineopts = 0; 1848d2737476Smartin } 1849