1*7547791dSpooka /* $NetBSD: main.c,v 1.38 2010/02/13 22:57:03 pooka 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> 635ecc953bSthorpej #include <paths.h> 645ecc953bSthorpej #include <ctype.h> 65342d3579Sdsl #include <err.h> 665ecc953bSthorpej #include <errno.h> 675ecc953bSthorpej #include <fcntl.h> 6836c1b19bSdholland #include <limits.h> 695ecc953bSthorpej #include <stdio.h> 705ecc953bSthorpej #include <stdlib.h> 715ecc953bSthorpej #include <string.h> 725ecc953bSthorpej #include <unistd.h> 73d0fb8901Schristos #include <vis.h> 74d0fb8901Schristos #include <util.h> 75d0fb8901Schristos 765ecc953bSthorpej #include "defs.h" 775ecc953bSthorpej #include "sem.h" 785ecc953bSthorpej 795ecc953bSthorpej #ifndef LINE_MAX 805ecc953bSthorpej #define LINE_MAX 1024 815ecc953bSthorpej #endif 825ecc953bSthorpej 835ecc953bSthorpej int vflag; /* verbose output */ 845ecc953bSthorpej int Pflag; /* pack locators */ 8559c94545Scube int Lflag; /* lint config generation */ 865ecc953bSthorpej 875ecc953bSthorpej int yyparse(void); 885ecc953bSthorpej 895ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 905ecc953bSthorpej extern int yydebug; 915ecc953bSthorpej #endif 925ecc953bSthorpej 93ac24e161Scube static struct hashtab *obsopttab; 945ecc953bSthorpej static struct hashtab *mkopttab; 955ecc953bSthorpej static struct nvlist **nextopt; 965ecc953bSthorpej static struct nvlist **nextmkopt; 975ecc953bSthorpej static struct nvlist **nextappmkopt; 98a16a6365Scube static struct nvlist **nextcndmkopt; 995ecc953bSthorpej static struct nvlist **nextfsopt; 1005ecc953bSthorpej 1018b0f9554Sperry static void usage(void) __dead; 1025ecc953bSthorpej static void dependopts(void); 1035ecc953bSthorpej static void do_depend(struct nvlist *); 1045ecc953bSthorpej static void stop(void); 1055ecc953bSthorpej static int do_option(struct hashtab *, struct nvlist ***, 1065ecc953bSthorpej const char *, const char *, const char *); 1075ecc953bSthorpej static int undo_option(struct hashtab *, struct nvlist **, 1085ecc953bSthorpej struct nvlist ***, const char *, const char *); 1095ecc953bSthorpej static int crosscheck(void); 1105ecc953bSthorpej static int badstar(void); 1115ecc953bSthorpej int main(int, char **); 1125ecc953bSthorpej static int mksymlinks(void); 1135ecc953bSthorpej static int mkident(void); 1147aa6070dScube static int devbase_has_dead_instances(const char *, void *, void *); 115a31ff6b4Scube static int devbase_has_any_instance(struct devbase *, int, int, int); 1167aa6070dScube static int check_dead_devi(const char *, void *, void *); 117c130d400Scube static void kill_orphans(void); 1187aa6070dScube static void do_kill_orphans(struct devbase *, struct attr *, 1197aa6070dScube struct devbase *, int); 120c130d400Scube static int kill_orphans_cb(const char *, void *, void *); 1215ecc953bSthorpej static int cfcrosscheck(struct config *, const char *, struct nvlist *); 1225ecc953bSthorpej void defopt(struct hashtab *ht, const char *fname, 123ac24e161Scube struct nvlist *opts, struct nvlist *deps, int obs); 1245ecc953bSthorpej 1255ecc953bSthorpej #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" 1265ecc953bSthorpej #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" 1275ecc953bSthorpej 1285ecc953bSthorpej static void logconfig_start(void); 1295ecc953bSthorpej static void logconfig_end(void); 1305ecc953bSthorpej static FILE *cfg; 1315ecc953bSthorpej static time_t cfgtime; 1325ecc953bSthorpej 1335ecc953bSthorpej static int is_elf(const char *); 1345ecc953bSthorpej static int extract_config(const char *, const char *, int); 1355ecc953bSthorpej 1365ecc953bSthorpej int badfilename(const char *fname); 1375ecc953bSthorpej 1385ecc953bSthorpej const char *progname; 1395ecc953bSthorpej 1405ecc953bSthorpej int 1415ecc953bSthorpej main(int argc, char **argv) 1425ecc953bSthorpej { 14336c1b19bSdholland char *p, cname[PATH_MAX]; 1445ecc953bSthorpej const char *last_component; 1455ecc953bSthorpej int pflag, xflag, ch, removeit; 1465ecc953bSthorpej 1475ecc953bSthorpej setprogname(argv[0]); 1485ecc953bSthorpej 1495ecc953bSthorpej pflag = 0; 1505ecc953bSthorpej xflag = 0; 15159c94545Scube while ((ch = getopt(argc, argv, "DLPgpvb:s:x")) != -1) { 1525ecc953bSthorpej switch (ch) { 1535ecc953bSthorpej 1545ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 1555ecc953bSthorpej case 'D': 1565ecc953bSthorpej yydebug = 1; 1575ecc953bSthorpej break; 1585ecc953bSthorpej #endif 1595ecc953bSthorpej 16059c94545Scube case 'L': 16159c94545Scube Lflag = 1; 16259c94545Scube break; 16359c94545Scube 1645ecc953bSthorpej case 'P': 1655ecc953bSthorpej Pflag = 1; 1665ecc953bSthorpej break; 1675ecc953bSthorpej 1685ecc953bSthorpej case 'g': 1695ecc953bSthorpej /* 1705ecc953bSthorpej * In addition to DEBUG, you probably wanted to 1715ecc953bSthorpej * set "options KGDB" and maybe others. We could 1725ecc953bSthorpej * do that for you, but you really should just 1735ecc953bSthorpej * put them in the config file. 1745ecc953bSthorpej */ 175c7295a4cSchristos warnx("-g is obsolete (use makeoptions DEBUG=\"-g\")"); 1765ecc953bSthorpej usage(); 177c7295a4cSchristos /*NOTREACHED*/ 1785ecc953bSthorpej 1795ecc953bSthorpej case 'p': 1805ecc953bSthorpej /* 1815ecc953bSthorpej * Essentially the same as makeoptions PROF="-pg", 1825ecc953bSthorpej * but also changes the path from ../../compile/FOO 1835ecc953bSthorpej * to ../../compile/FOO.PROF; i.e., compile a 1845ecc953bSthorpej * profiling kernel based on a typical "regular" 1855ecc953bSthorpej * kernel. 1865ecc953bSthorpej * 1875ecc953bSthorpej * Note that if you always want profiling, you 1885ecc953bSthorpej * can (and should) use a "makeoptions" line. 1895ecc953bSthorpej */ 1905ecc953bSthorpej pflag = 1; 1915ecc953bSthorpej break; 1925ecc953bSthorpej 1935ecc953bSthorpej case 'v': 1945ecc953bSthorpej vflag = 1; 1955ecc953bSthorpej break; 1965ecc953bSthorpej 1975ecc953bSthorpej case 'b': 1985ecc953bSthorpej builddir = optarg; 1995ecc953bSthorpej break; 2005ecc953bSthorpej 2015ecc953bSthorpej case 's': 2025ecc953bSthorpej srcdir = optarg; 2035ecc953bSthorpej break; 2045ecc953bSthorpej 2055ecc953bSthorpej case 'x': 2065ecc953bSthorpej xflag = 1; 2075ecc953bSthorpej break; 2085ecc953bSthorpej 2095ecc953bSthorpej case '?': 2105ecc953bSthorpej default: 2115ecc953bSthorpej usage(); 2125ecc953bSthorpej } 2135ecc953bSthorpej } 2145ecc953bSthorpej 215*7547791dSpooka if (xflag && optind != 2) { 216e239742fSpooka errx(EXIT_FAILURE, "-x must be used alone"); 217e239742fSpooka } 218e239742fSpooka 2195ecc953bSthorpej argc -= optind; 2205ecc953bSthorpej argv += optind; 2215ecc953bSthorpej if (argc > 1) { 2225ecc953bSthorpej usage(); 2235ecc953bSthorpej } 2245ecc953bSthorpej 225c7295a4cSchristos if (Lflag && (builddir != NULL || Pflag || pflag)) 226c7295a4cSchristos errx(EXIT_FAILURE, "-L can only be used with -s and -v"); 2275ecc953bSthorpej 2285ecc953bSthorpej if (xflag) { 2295ecc953bSthorpej #ifdef __NetBSD__ 2305ecc953bSthorpej conffile = (argc == 1) ? argv[0] : _PATH_UNIX; 2315ecc953bSthorpej #else 232c7295a4cSchristos if (argc == 0) 233c7295a4cSchristos errx(EXIT_FAILURE, "no kernel supplied"); 2345ecc953bSthorpej #endif 235c7295a4cSchristos if (!is_elf(conffile)) 236c7295a4cSchristos errx(EXIT_FAILURE, "%s: not a binary kernel", 2375ecc953bSthorpej conffile); 238c7295a4cSchristos if (!extract_config(conffile, "stdout", STDOUT_FILENO)) 239c7295a4cSchristos errx(EXIT_FAILURE, "%s does not contain embedded " 240c7295a4cSchristos "configuration data", conffile); 2415ecc953bSthorpej exit(0); 2425ecc953bSthorpej } 2435ecc953bSthorpej 2445ecc953bSthorpej conffile = (argc == 1) ? argv[0] : "CONFIG"; 2455ecc953bSthorpej if (firstfile(conffile)) { 246c7295a4cSchristos err(EXIT_FAILURE, "Cannot read `%s'", conffile); 2475ecc953bSthorpej exit(2); 2485ecc953bSthorpej } 2495ecc953bSthorpej 2505ecc953bSthorpej /* 2515ecc953bSthorpej * Init variables. 2525ecc953bSthorpej */ 2535ecc953bSthorpej minmaxusers = 1; 2545ecc953bSthorpej maxmaxusers = 10000; 2555ecc953bSthorpej initintern(); 2565ecc953bSthorpej initfiles(); 2575ecc953bSthorpej initsem(); 2585ecc953bSthorpej ident = NULL; 2595ecc953bSthorpej devbasetab = ht_new(); 260c130d400Scube devroottab = ht_new(); 2615ecc953bSthorpej devatab = ht_new(); 2625ecc953bSthorpej devitab = ht_new(); 2637aa6070dScube deaddevitab = ht_new(); 2645ecc953bSthorpej selecttab = ht_new(); 2655ecc953bSthorpej needcnttab = ht_new(); 2665ecc953bSthorpej opttab = ht_new(); 2675ecc953bSthorpej mkopttab = ht_new(); 2685ecc953bSthorpej fsopttab = ht_new(); 2695ecc953bSthorpej deffstab = ht_new(); 2705ecc953bSthorpej defopttab = ht_new(); 2715ecc953bSthorpej defparamtab = ht_new(); 27290426267Scube defoptlint = ht_new(); 2735ecc953bSthorpej defflagtab = ht_new(); 2745ecc953bSthorpej optfiletab = ht_new(); 275ac24e161Scube obsopttab = ht_new(); 2765ecc953bSthorpej bdevmtab = ht_new(); 2775ecc953bSthorpej maxbdevm = 0; 2785ecc953bSthorpej cdevmtab = ht_new(); 2795ecc953bSthorpej maxcdevm = 0; 2805ecc953bSthorpej nextopt = &options; 2815ecc953bSthorpej nextmkopt = &mkoptions; 2825ecc953bSthorpej nextappmkopt = &appmkoptions; 2831894a7d2Scube nextcndmkopt = &condmkoptions; 2845ecc953bSthorpej nextfsopt = &fsoptions; 2855ecc953bSthorpej 2865ecc953bSthorpej /* 2875ecc953bSthorpej * Handle profiling (must do this before we try to create any 2885ecc953bSthorpej * files). 2895ecc953bSthorpej */ 2905ecc953bSthorpej last_component = strrchr(conffile, '/'); 2915ecc953bSthorpej last_component = (last_component) ? last_component + 1 : conffile; 2925ecc953bSthorpej if (pflag) { 2935ecc953bSthorpej p = emalloc(strlen(last_component) + 17); 2945ecc953bSthorpej (void)sprintf(p, "../compile/%s.PROF", last_component); 2955ecc953bSthorpej (void)addmkoption(intern("PROF"), "-pg"); 2965ecc953bSthorpej (void)addoption(intern("GPROF"), NULL); 2975ecc953bSthorpej } else { 2985ecc953bSthorpej p = emalloc(strlen(last_component) + 13); 2995ecc953bSthorpej (void)sprintf(p, "../compile/%s", last_component); 3005ecc953bSthorpej } 3015ecc953bSthorpej defbuilddir = (argc == 0) ? "." : p; 3025ecc953bSthorpej 30359c94545Scube if (Lflag) { 30459c94545Scube char resolvedname[MAXPATHLEN]; 30559c94545Scube 30659c94545Scube if (realpath(conffile, resolvedname) == NULL) 30759c94545Scube err(EXIT_FAILURE, "realpath(%s)", conffile); 30859c94545Scube 30959c94545Scube if (yyparse()) 31059c94545Scube stop(); 31159c94545Scube 312aa3d0249Scube printf("include \"%s\"\n", resolvedname); 31359c94545Scube 31459c94545Scube emit_params(); 31559c94545Scube emit_options(); 31659c94545Scube emit_instances(); 31759c94545Scube 31859c94545Scube exit(EXIT_SUCCESS); 31959c94545Scube } 32059c94545Scube 3215ecc953bSthorpej removeit = 0; 3225ecc953bSthorpej if (is_elf(conffile)) { 3235ecc953bSthorpej const char *tmpdir; 3245ecc953bSthorpej int cfd; 3255ecc953bSthorpej 326c7295a4cSchristos if (builddir == NULL) 327c7295a4cSchristos errx(EXIT_FAILURE, "Build directory must be specified " 328c7295a4cSchristos "with binary kernels"); 3295ecc953bSthorpej 3305ecc953bSthorpej /* Open temporary configuration file */ 3315ecc953bSthorpej tmpdir = getenv("TMPDIR"); 3325ecc953bSthorpej if (tmpdir == NULL) 33336c1b19bSdholland tmpdir = _PATH_TMP; 3345ecc953bSthorpej snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir); 3355ecc953bSthorpej cfd = mkstemp(cname); 336c7295a4cSchristos if (cfd == -1) 337c7295a4cSchristos err(EXIT_FAILURE, "Cannot create `%s'", cname); 3385ecc953bSthorpej 3395ecc953bSthorpej printf("Using configuration data embedded in kernel...\n"); 34036c1b19bSdholland if (!extract_config(conffile, cname, cfd)) { 34136c1b19bSdholland unlink(cname); 342c7295a4cSchristos errx(EXIT_FAILURE, "%s does not contain embedded " 343c7295a4cSchristos "configuration data", conffile); 34436c1b19bSdholland } 3455ecc953bSthorpej 3465ecc953bSthorpej removeit = 1; 3475ecc953bSthorpej close(cfd); 3485ecc953bSthorpej firstfile(cname); 3495ecc953bSthorpej } 3505ecc953bSthorpej 3515ecc953bSthorpej /* 352e239742fSpooka * Log config file. We don't know until yyparse() if we're 353e239742fSpooka * going to need config_file.h (i.e. if we're doing ioconf-only 354e239742fSpooka * or not). Just start creating the file, and when we know 355e239742fSpooka * later, we'll just keep or discard our work here. 3565ecc953bSthorpej */ 3575ecc953bSthorpej logconfig_start(); 358e239742fSpooka 359e239742fSpooka /* 360e239742fSpooka * Parse config file (including machine definitions). 361e239742fSpooka */ 3625ecc953bSthorpej if (yyparse()) 3635ecc953bSthorpej stop(); 364e239742fSpooka 365e239742fSpooka if (ioconfname && cfg) 366e239742fSpooka fclose(cfg); 367e239742fSpooka else 3685ecc953bSthorpej logconfig_end(); 3695ecc953bSthorpej 3705ecc953bSthorpej if (removeit) 3715ecc953bSthorpej unlink(cname); 3725ecc953bSthorpej 3735ecc953bSthorpej /* 374c130d400Scube * Detect and properly ignore orphaned devices 375c130d400Scube */ 376c130d400Scube kill_orphans(); 377c130d400Scube 378c130d400Scube /* 3795ecc953bSthorpej * Select devices and pseudo devices and their attributes 3805ecc953bSthorpej */ 3817aa6070dScube if (fixdevis()) 3827aa6070dScube stop(); 3835ecc953bSthorpej 3845ecc953bSthorpej /* 385e239742fSpooka * If working on an ioconf-only config, process here and exit 386e239742fSpooka */ 387e239742fSpooka if (ioconfname) { 388e239742fSpooka pack(); 389e239742fSpooka mkioconf(); 390e239742fSpooka emitlocs(); 391e239742fSpooka return 0; 392e239742fSpooka } 393e239742fSpooka 394e239742fSpooka /* 3955ecc953bSthorpej * Deal with option dependencies. 3965ecc953bSthorpej */ 3975ecc953bSthorpej dependopts(); 3985ecc953bSthorpej 3995ecc953bSthorpej /* 4005ecc953bSthorpej * Fix (as in `set firmly in place') files. 4015ecc953bSthorpej */ 4025ecc953bSthorpej if (fixfiles()) 4035ecc953bSthorpej stop(); 4045ecc953bSthorpej 4055ecc953bSthorpej /* 4065ecc953bSthorpej * Fix objects and libraries. 4075ecc953bSthorpej */ 4085ecc953bSthorpej if (fixobjects()) 4095ecc953bSthorpej stop(); 4105ecc953bSthorpej 4115ecc953bSthorpej /* 4125ecc953bSthorpej * Fix device-majors. 4135ecc953bSthorpej */ 4145ecc953bSthorpej if (fixdevsw()) 4155ecc953bSthorpej stop(); 4165ecc953bSthorpej 4175ecc953bSthorpej /* 4185ecc953bSthorpej * Perform cross-checking. 4195ecc953bSthorpej */ 4205ecc953bSthorpej if (maxusers == 0) { 4215ecc953bSthorpej if (defmaxusers) { 4225ecc953bSthorpej (void)printf("maxusers not specified; %d assumed\n", 4235ecc953bSthorpej defmaxusers); 4245ecc953bSthorpej maxusers = defmaxusers; 4255ecc953bSthorpej } else { 426c7295a4cSchristos warnx("need \"maxusers\" line"); 4275ecc953bSthorpej errors++; 4285ecc953bSthorpej } 4295ecc953bSthorpej } 4305ecc953bSthorpej if (crosscheck() || errors) 4315ecc953bSthorpej stop(); 4325ecc953bSthorpej 4335ecc953bSthorpej /* 4345ecc953bSthorpej * Squeeze things down and finish cross-checks (STAR checks must 4355ecc953bSthorpej * run after packing). 4365ecc953bSthorpej */ 4375ecc953bSthorpej pack(); 4385ecc953bSthorpej if (badstar()) 4395ecc953bSthorpej stop(); 4405ecc953bSthorpej 4415ecc953bSthorpej /* 4425ecc953bSthorpej * Ready to go. Build all the various files. 4435ecc953bSthorpej */ 4445ecc953bSthorpej if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || 4450367057bScube mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident() || errors) 4465ecc953bSthorpej stop(); 4475ecc953bSthorpej (void)printf("Build directory is %s\n", builddir); 4485ecc953bSthorpej (void)printf("Don't forget to run \"make depend\"\n"); 449c7295a4cSchristos return 0; 4505ecc953bSthorpej } 4515ecc953bSthorpej 4525ecc953bSthorpej static void 4535ecc953bSthorpej usage(void) 4545ecc953bSthorpej { 455c7295a4cSchristos (void)fprintf(stderr, "Usage: %s [-Ppv] [-s srcdir] [-b builddir] " 456c7295a4cSchristos "[config-file]\n\t%s -x [kernel-file]\n" 457c7295a4cSchristos "\t%s -L [-v] [-s srcdir] [config-file]\n", 458c7295a4cSchristos getprogname(), getprogname(), getprogname()); 4595ecc953bSthorpej exit(1); 4605ecc953bSthorpej } 4615ecc953bSthorpej 4625ecc953bSthorpej /* 4635ecc953bSthorpej * Set any options that are implied by other options. 4645ecc953bSthorpej */ 4655ecc953bSthorpej static void 4665ecc953bSthorpej dependopts(void) 4675ecc953bSthorpej { 4685ecc953bSthorpej struct nvlist *nv, *opt; 4695ecc953bSthorpej 4705ecc953bSthorpej for (nv = options; nv != NULL; nv = nv->nv_next) { 4715ecc953bSthorpej if ((opt = find_declared_option(nv->nv_name)) != NULL) { 4725ecc953bSthorpej for (opt = opt->nv_ptr; opt != NULL; 4735ecc953bSthorpej opt = opt->nv_next) { 4745ecc953bSthorpej do_depend(opt); 4755ecc953bSthorpej } 4765ecc953bSthorpej } 4775ecc953bSthorpej } 4784a82747aSmatt 4794a82747aSmatt for (nv = fsoptions; nv != NULL; nv = nv->nv_next) { 4804a82747aSmatt if ((opt = find_declared_option(nv->nv_name)) != NULL) { 4814a82747aSmatt for (opt = opt->nv_ptr; opt != NULL; 4824a82747aSmatt opt = opt->nv_next) { 4834a82747aSmatt do_depend(opt); 4844a82747aSmatt } 4854a82747aSmatt } 4864a82747aSmatt } 4875ecc953bSthorpej } 4885ecc953bSthorpej 4895ecc953bSthorpej static void 4905ecc953bSthorpej do_depend(struct nvlist *nv) 4915ecc953bSthorpej { 4925ecc953bSthorpej struct nvlist *nextnv; 4935ecc953bSthorpej struct attr *a; 4945ecc953bSthorpej 4955ecc953bSthorpej if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) { 4965ecc953bSthorpej nv->nv_flags |= NV_DEPENDED; 4975ecc953bSthorpej /* 4985ecc953bSthorpej * If the dependency is an attribute, then just add 4995ecc953bSthorpej * it to the selecttab. 5005ecc953bSthorpej */ 5015ecc953bSthorpej if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) { 5025ecc953bSthorpej if (a->a_iattr) 5035ecc953bSthorpej panic("do_depend(%s): dep `%s' is an iattr", 5045ecc953bSthorpej nv->nv_name, a->a_name); 5055ecc953bSthorpej expandattr(a, selectattr); 5065ecc953bSthorpej } else { 5075ecc953bSthorpej if (ht_lookup(opttab, nv->nv_name) == NULL) 5085ecc953bSthorpej addoption(nv->nv_name, NULL); 5095ecc953bSthorpej if ((nextnv = 5105ecc953bSthorpej find_declared_option(nv->nv_name)) != NULL) 5115ecc953bSthorpej do_depend(nextnv->nv_ptr); 5125ecc953bSthorpej } 5135ecc953bSthorpej } 5145ecc953bSthorpej } 5155ecc953bSthorpej 516c7295a4cSchristos static int 517c7295a4cSchristos recreate(const char *p, const char *q) 518c7295a4cSchristos { 519c7295a4cSchristos int ret; 520c7295a4cSchristos 521c7295a4cSchristos if ((ret = unlink(q)) == -1 && errno != ENOENT) 522c7295a4cSchristos warn("unlink(%s)\n", q); 523c7295a4cSchristos if ((ret = symlink(p, q)) == -1) 524c7295a4cSchristos warn("symlink(%s -> %s)", q, p); 525c7295a4cSchristos return ret; 526c7295a4cSchristos } 527c7295a4cSchristos 5285ecc953bSthorpej /* 5295ecc953bSthorpej * Make a symlink for "machine" so that "#include <machine/foo.h>" works, 5305ecc953bSthorpej * and for the machine's CPU architecture, so that works as well. 5315ecc953bSthorpej */ 5325ecc953bSthorpej static int 5335ecc953bSthorpej mksymlinks(void) 5345ecc953bSthorpej { 5355ecc953bSthorpej int ret; 5365ecc953bSthorpej char *p, buf[MAXPATHLEN]; 5375ecc953bSthorpej const char *q; 5385ecc953bSthorpej struct nvlist *nv; 5395ecc953bSthorpej 5405ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", machine); 5415ecc953bSthorpej p = sourcepath(buf); 542c7295a4cSchristos ret = recreate(p, "machine"); 5435ecc953bSthorpej free(p); 5445ecc953bSthorpej 5455ecc953bSthorpej if (machinearch != NULL) { 5465ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", machinearch); 5475ecc953bSthorpej p = sourcepath(buf); 5485ecc953bSthorpej q = machinearch; 5495ecc953bSthorpej } else { 5505ecc953bSthorpej p = estrdup("machine"); 5515ecc953bSthorpej q = machine; 5525ecc953bSthorpej } 553c7295a4cSchristos 554c7295a4cSchristos ret = recreate(p, q); 5555ecc953bSthorpej free(p); 5565ecc953bSthorpej 5575ecc953bSthorpej for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { 5585ecc953bSthorpej q = nv->nv_name; 5595ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", q); 5605ecc953bSthorpej p = sourcepath(buf); 561c7295a4cSchristos ret = recreate(p, q); 5625ecc953bSthorpej free(p); 5635ecc953bSthorpej } 5645ecc953bSthorpej 5655ecc953bSthorpej return (ret); 5665ecc953bSthorpej } 5675ecc953bSthorpej 5685ecc953bSthorpej static __dead void 5695ecc953bSthorpej stop(void) 5705ecc953bSthorpej { 5715ecc953bSthorpej (void)fprintf(stderr, "*** Stop.\n"); 5725ecc953bSthorpej exit(1); 5735ecc953bSthorpej } 5745ecc953bSthorpej 5754a82747aSmatt static void 5764a82747aSmatt add_dependencies(struct nvlist *nv, struct nvlist *deps) 5774a82747aSmatt { 5784a82747aSmatt struct nvlist *dep; 5794a82747aSmatt struct attr *a; 5804a82747aSmatt 5814a82747aSmatt /* Use nv_ptr to link any other options that are implied. */ 5824a82747aSmatt nv->nv_ptr = deps; 5834a82747aSmatt for (dep = deps; dep != NULL; dep = dep->nv_next) { 5844a82747aSmatt /* 5854a82747aSmatt * If the dependency is an attribute, it must not 5864a82747aSmatt * be an interface attribute. Otherwise, it must 5874a82747aSmatt * be a previously declared option. 5884a82747aSmatt */ 5894a82747aSmatt if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) { 5904a82747aSmatt if (a->a_iattr) 591c7295a4cSchristos cfgerror("option `%s' dependency `%s' " 5924a82747aSmatt "is an interface attribute", 5934a82747aSmatt nv->nv_name, a->a_name); 5944a82747aSmatt } else if (OPT_OBSOLETE(dep->nv_name)) { 595c7295a4cSchristos cfgerror("option `%s' dependency `%s' " 5964a82747aSmatt "is obsolete", nv->nv_name, dep->nv_name); 5974a82747aSmatt } else if (find_declared_option(dep->nv_name) == NULL) { 598c7295a4cSchristos cfgerror("option `%s' dependency `%s' " 5994a82747aSmatt "is an unknown option", 6004a82747aSmatt nv->nv_name, dep->nv_name); 6014a82747aSmatt } 6024a82747aSmatt } 6034a82747aSmatt } 6044a82747aSmatt 6055ecc953bSthorpej /* 6065ecc953bSthorpej * Define one or more file systems. If file system options file name is 6075ecc953bSthorpej * specified, a preprocessor #define for that file system will be placed 6085ecc953bSthorpej * in that file. In this case, only one file system may be specified. 6095ecc953bSthorpej * Otherwise, no preprocessor #defines will be generated. 6105ecc953bSthorpej */ 6115ecc953bSthorpej void 6124a82747aSmatt deffilesystem(const char *fname, struct nvlist *fses, struct nvlist *deps) 6135ecc953bSthorpej { 6145ecc953bSthorpej struct nvlist *nv; 6155ecc953bSthorpej 6165ecc953bSthorpej /* 6175ecc953bSthorpej * Mark these options as ones to skip when creating the Makefile. 6185ecc953bSthorpej */ 6195ecc953bSthorpej for (nv = fses; nv != NULL; nv = nv->nv_next) { 620c93963e6Scube if (DEFINED_OPTION(nv->nv_name)) { 621c7295a4cSchristos cfgerror("file system or option `%s' already defined", 6225ecc953bSthorpej nv->nv_name); 6235ecc953bSthorpej return; 6245ecc953bSthorpej } 6255ecc953bSthorpej 6265ecc953bSthorpej /* 6275ecc953bSthorpej * Also mark it as a valid file system, which may be 6285ecc953bSthorpej * used in "file-system" directives in the config 6295ecc953bSthorpej * file. 6305ecc953bSthorpej */ 6315ecc953bSthorpej if (ht_insert(deffstab, nv->nv_name, nv)) 6325ecc953bSthorpej panic("file system `%s' already in table?!", 6335ecc953bSthorpej nv->nv_name); 6345ecc953bSthorpej 6355ecc953bSthorpej if (fname != NULL) { 6365ecc953bSthorpej /* 6375ecc953bSthorpej * Only one file system allowed in this case. 6385ecc953bSthorpej */ 6395ecc953bSthorpej if (nv->nv_next != NULL) { 640c7295a4cSchristos cfgerror("only one file system per option " 6415ecc953bSthorpej "file may be specified"); 6425ecc953bSthorpej return; 6435ecc953bSthorpej } 6445ecc953bSthorpej 6455ecc953bSthorpej if (ht_insert(optfiletab, fname, nv)) { 646c7295a4cSchristos cfgerror("option file `%s' already exists", 6475ecc953bSthorpej fname); 6485ecc953bSthorpej return; 6495ecc953bSthorpej } 6505ecc953bSthorpej } 6514a82747aSmatt 6524a82747aSmatt add_dependencies(nv, deps); 6535ecc953bSthorpej } 6545ecc953bSthorpej } 6555ecc953bSthorpej 6565ecc953bSthorpej /* 6575ecc953bSthorpej * Sanity check a file name. 6585ecc953bSthorpej */ 6595ecc953bSthorpej int 6605ecc953bSthorpej badfilename(const char *fname) 6615ecc953bSthorpej { 6625ecc953bSthorpej const char *n; 6635ecc953bSthorpej 6645ecc953bSthorpej /* 6655ecc953bSthorpej * We're putting multiple options into one file. Sanity 6665ecc953bSthorpej * check the file name. 6675ecc953bSthorpej */ 6685ecc953bSthorpej if (strchr(fname, '/') != NULL) { 669c7295a4cSchristos cfgerror("option file name contains a `/'"); 6705ecc953bSthorpej return 1; 6715ecc953bSthorpej } 6725ecc953bSthorpej if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) { 673c7295a4cSchristos cfgerror("option file name does not end in `.h'"); 6745ecc953bSthorpej return 1; 6755ecc953bSthorpej } 6765ecc953bSthorpej return 0; 6775ecc953bSthorpej } 6785ecc953bSthorpej 6795ecc953bSthorpej 6805ecc953bSthorpej /* 6815ecc953bSthorpej * Search for a defined option (defopt, filesystem, etc), and if found, 6825ecc953bSthorpej * return the option's struct nvlist. 6835ecc953bSthorpej */ 6845ecc953bSthorpej struct nvlist * 6855ecc953bSthorpej find_declared_option(const char *name) 6865ecc953bSthorpej { 6875ecc953bSthorpej struct nvlist *option = NULL; 6885ecc953bSthorpej 6895ecc953bSthorpej if ((option = ht_lookup(defopttab, name)) != NULL || 6905ecc953bSthorpej (option = ht_lookup(defparamtab, name)) != NULL || 6915ecc953bSthorpej (option = ht_lookup(defflagtab, name)) != NULL || 6928e3d8732Scube (option = ht_lookup(deffstab, name)) != NULL) { 6935ecc953bSthorpej return (option); 6945ecc953bSthorpej } 6955ecc953bSthorpej 6965ecc953bSthorpej return (NULL); 6975ecc953bSthorpej } 6985ecc953bSthorpej 6995ecc953bSthorpej 7005ecc953bSthorpej /* 7015ecc953bSthorpej * Define one or more standard options. If an option file name is specified, 7025ecc953bSthorpej * place all options in one file with the specified name. Otherwise, create 7035ecc953bSthorpej * an option file for each option. 7045ecc953bSthorpej * record the option information in the specified table. 7055ecc953bSthorpej */ 7065ecc953bSthorpej void 7075ecc953bSthorpej defopt(struct hashtab *ht, const char *fname, struct nvlist *opts, 708ac24e161Scube struct nvlist *deps, int obs) 7095ecc953bSthorpej { 7104a82747aSmatt struct nvlist *nv, *nextnv, *oldnv; 7115ecc953bSthorpej const char *name; 7125ecc953bSthorpej char buf[500]; 7135ecc953bSthorpej 7145ecc953bSthorpej if (fname != NULL && badfilename(fname)) { 7155ecc953bSthorpej return; 7165ecc953bSthorpej } 7175ecc953bSthorpej 7185ecc953bSthorpej /* 7195ecc953bSthorpej * Mark these options as ones to skip when creating the Makefile. 7205ecc953bSthorpej */ 7215ecc953bSthorpej for (nv = opts; nv != NULL; nv = nextnv) { 7225ecc953bSthorpej nextnv = nv->nv_next; 7235ecc953bSthorpej 72490426267Scube if (*(nv->nv_name) == '\0') { 72590426267Scube if (nextnv == NULL) 72690426267Scube panic("invalid option chain"); 72790426267Scube /* 72890426267Scube * If an entry already exists, then we are about to 72990426267Scube * complain, so no worry. 73090426267Scube */ 73190426267Scube (void) ht_insert(defoptlint, nextnv->nv_name, 73290426267Scube nv); 73390426267Scube nv = nextnv; 73490426267Scube nextnv = nextnv->nv_next; 73590426267Scube } 73690426267Scube 7375ecc953bSthorpej /* An option name can be declared at most once. */ 7385ecc953bSthorpej if (DEFINED_OPTION(nv->nv_name)) { 739c7295a4cSchristos cfgerror("file system or option `%s' already defined", 7405ecc953bSthorpej nv->nv_name); 7415ecc953bSthorpej return; 7425ecc953bSthorpej } 7435ecc953bSthorpej 7445ecc953bSthorpej if (ht_insert(ht, nv->nv_name, nv)) { 745c7295a4cSchristos cfgerror("file system or option `%s' already defined", 7465ecc953bSthorpej nv->nv_name); 7475ecc953bSthorpej return; 7485ecc953bSthorpej } 7495ecc953bSthorpej 7505ecc953bSthorpej if (fname == NULL) { 7515ecc953bSthorpej /* 7525ecc953bSthorpej * Each option will be going into its own file. 7535ecc953bSthorpej * Convert the option name to lower case. This 7545ecc953bSthorpej * lower case name will be used as the option 7555ecc953bSthorpej * file name. 7565ecc953bSthorpej */ 7575ecc953bSthorpej (void) snprintf(buf, sizeof(buf), "opt_%s.h", 7585ecc953bSthorpej strtolower(nv->nv_name)); 7595ecc953bSthorpej name = intern(buf); 7605ecc953bSthorpej } else { 7615ecc953bSthorpej name = fname; 7625ecc953bSthorpej } 7635ecc953bSthorpej 7644a82747aSmatt add_dependencies(nv, deps); 7655ecc953bSthorpej 7665ecc953bSthorpej /* 7675ecc953bSthorpej * Remove this option from the parameter list before adding 7685ecc953bSthorpej * it to the list associated with this option file. 7695ecc953bSthorpej */ 7705ecc953bSthorpej nv->nv_next = NULL; 7715ecc953bSthorpej 7725ecc953bSthorpej /* 773ac24e161Scube * Flag as obsolete, if requested. 774ac24e161Scube */ 775ac24e161Scube if (obs) { 776ac24e161Scube nv->nv_flags |= NV_OBSOLETE; 777ac24e161Scube (void)ht_insert(obsopttab, nv->nv_name, nv); 778ac24e161Scube } 779ac24e161Scube 780ac24e161Scube /* 7815ecc953bSthorpej * Add this option file if we haven't seen it yet. 7825ecc953bSthorpej * Otherwise, append to the list of options already 7835ecc953bSthorpej * associated with this file. 7845ecc953bSthorpej */ 7855ecc953bSthorpej if ((oldnv = ht_lookup(optfiletab, name)) == NULL) { 7865ecc953bSthorpej (void)ht_insert(optfiletab, name, nv); 7875ecc953bSthorpej } else { 7885ecc953bSthorpej while (oldnv->nv_next != NULL) 7895ecc953bSthorpej oldnv = oldnv->nv_next; 7905ecc953bSthorpej oldnv->nv_next = nv; 7915ecc953bSthorpej } 7925ecc953bSthorpej } 7935ecc953bSthorpej } 7945ecc953bSthorpej 7955ecc953bSthorpej /* 7965ecc953bSthorpej * Define one or more standard options. If an option file name is specified, 7975ecc953bSthorpej * place all options in one file with the specified name. Otherwise, create 7985ecc953bSthorpej * an option file for each option. 7995ecc953bSthorpej */ 8005ecc953bSthorpej void 8015ecc953bSthorpej defoption(const char *fname, struct nvlist *opts, struct nvlist *deps) 8025ecc953bSthorpej { 8035ecc953bSthorpej 804c7295a4cSchristos cfgwarn("The use of `defopt' is deprecated"); 805ac24e161Scube defopt(defopttab, fname, opts, deps, 0); 8065ecc953bSthorpej } 8075ecc953bSthorpej 8085ecc953bSthorpej 8095ecc953bSthorpej /* 8105ecc953bSthorpej * Define an option for which a value is required. 8115ecc953bSthorpej */ 8125ecc953bSthorpej void 813ac24e161Scube defparam(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs) 8145ecc953bSthorpej { 8155ecc953bSthorpej 816ac24e161Scube defopt(defparamtab, fname, opts, deps, obs); 8175ecc953bSthorpej } 8185ecc953bSthorpej 8195ecc953bSthorpej /* 82072303951Scube * Define an option which must not have a value, and which 8215ecc953bSthorpej * emits a "needs-flag" style output. 8225ecc953bSthorpej */ 8235ecc953bSthorpej void 824ac24e161Scube defflag(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs) 8255ecc953bSthorpej { 8265ecc953bSthorpej 827ac24e161Scube defopt(defflagtab, fname, opts, deps, obs); 8285ecc953bSthorpej } 8295ecc953bSthorpej 8305ecc953bSthorpej 8315ecc953bSthorpej /* 8325ecc953bSthorpej * Add an option from "options FOO". Note that this selects things that 8335ecc953bSthorpej * are "optional foo". 8345ecc953bSthorpej */ 8355ecc953bSthorpej void 8365ecc953bSthorpej addoption(const char *name, const char *value) 8375ecc953bSthorpej { 8385ecc953bSthorpej const char *n; 839c7295a4cSchristos int is_fs, is_param, is_flag, is_undecl, is_obs; 8405ecc953bSthorpej 8415ecc953bSthorpej /* 8425ecc953bSthorpej * Figure out how this option was declared (if at all.) 8435ecc953bSthorpej * XXX should use "params" and "flags" in config. 8445ecc953bSthorpej * XXX crying out for a type field in a unified hashtab. 8455ecc953bSthorpej */ 8465ecc953bSthorpej is_fs = OPT_FSOPT(name); 8475ecc953bSthorpej is_param = OPT_DEFPARAM(name); 8485ecc953bSthorpej is_flag = OPT_DEFFLAG(name); 849ac24e161Scube is_obs = OPT_OBSOLETE(name); 8505ecc953bSthorpej is_undecl = !DEFINED_OPTION(name); 8515ecc953bSthorpej 852ac24e161Scube /* Warn and pretend the user had not selected the option */ 853ac24e161Scube if (is_obs) { 854c7295a4cSchristos cfgwarn("obsolete option `%s' will be ignored", name); 855ac24e161Scube return; 856ac24e161Scube } 857ac24e161Scube 8585ecc953bSthorpej /* Make sure this is not a defined file system. */ 8595ecc953bSthorpej if (is_fs) { 860c7295a4cSchristos cfgerror("`%s' is a defined file system", name); 8615ecc953bSthorpej return; 8625ecc953bSthorpej } 8635ecc953bSthorpej /* A defparam must have a value */ 8645ecc953bSthorpej if (is_param && value == NULL) { 865c7295a4cSchristos cfgerror("option `%s' must have a value", name); 8665ecc953bSthorpej return; 8675ecc953bSthorpej } 8685ecc953bSthorpej /* A defflag must not have a value */ 8695ecc953bSthorpej if (is_flag && value != NULL) { 870c7295a4cSchristos cfgerror("option `%s' must not have a value", name); 8715ecc953bSthorpej return; 8725ecc953bSthorpej } 8735ecc953bSthorpej 8745ecc953bSthorpej if (is_undecl && vflag) { 875c7295a4cSchristos cfgwarn("undeclared option `%s' added to IDENT", name); 8765ecc953bSthorpej } 8775ecc953bSthorpej 8785ecc953bSthorpej if (do_option(opttab, &nextopt, name, value, "options")) 8795ecc953bSthorpej return; 8805ecc953bSthorpej 8815ecc953bSthorpej /* make lowercase, then add to select table */ 8825ecc953bSthorpej n = strtolower(name); 883c7295a4cSchristos (void)ht_insert(selecttab, n, (void *)__UNCONST(n)); 8845ecc953bSthorpej } 8855ecc953bSthorpej 8865ecc953bSthorpej void 8875ecc953bSthorpej deloption(const char *name) 8885ecc953bSthorpej { 8895ecc953bSthorpej 8905ecc953bSthorpej if (undo_option(opttab, &options, &nextopt, name, "options")) 8915ecc953bSthorpej return; 8925ecc953bSthorpej if (undo_option(selecttab, NULL, NULL, strtolower(name), "options")) 8935ecc953bSthorpej return; 8945ecc953bSthorpej } 8955ecc953bSthorpej 8965ecc953bSthorpej /* 8975ecc953bSthorpej * Add a file system option. This routine simply inserts the name into 8985ecc953bSthorpej * a list of valid file systems, which is used to validate the root 8995ecc953bSthorpej * file system type. The name is then treated like a standard option. 9005ecc953bSthorpej */ 9015ecc953bSthorpej void 9025ecc953bSthorpej addfsoption(const char *name) 9035ecc953bSthorpej { 9045ecc953bSthorpej const char *n; 9055ecc953bSthorpej 9065ecc953bSthorpej /* Make sure this is a defined file system. */ 9075ecc953bSthorpej if (!OPT_FSOPT(name)) { 908c7295a4cSchristos cfgerror("`%s' is not a defined file system", name); 9095ecc953bSthorpej return; 9105ecc953bSthorpej } 9115ecc953bSthorpej 9125ecc953bSthorpej /* 9135ecc953bSthorpej * Convert to lower case. This will be used in the select 914baec5c01Scube * table, to verify root file systems. 9155ecc953bSthorpej */ 9165ecc953bSthorpej n = strtolower(name); 9175ecc953bSthorpej 9185ecc953bSthorpej if (do_option(fsopttab, &nextfsopt, name, n, "file-system")) 9195ecc953bSthorpej return; 9205ecc953bSthorpej 9215ecc953bSthorpej /* Add to select table. */ 922c7295a4cSchristos (void)ht_insert(selecttab, n, __UNCONST(n)); 9235ecc953bSthorpej } 9245ecc953bSthorpej 9255ecc953bSthorpej void 9265ecc953bSthorpej delfsoption(const char *name) 9275ecc953bSthorpej { 9285ecc953bSthorpej const char *n; 9295ecc953bSthorpej 9305ecc953bSthorpej n = strtolower(name); 9315ecc953bSthorpej if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system")) 9325ecc953bSthorpej return; 9335ecc953bSthorpej if (undo_option(selecttab, NULL, NULL, n, "file-system")) 9345ecc953bSthorpej return; 9355ecc953bSthorpej } 9365ecc953bSthorpej 9375ecc953bSthorpej /* 9385ecc953bSthorpej * Add a "make" option. 9395ecc953bSthorpej */ 9405ecc953bSthorpej void 9415ecc953bSthorpej addmkoption(const char *name, const char *value) 9425ecc953bSthorpej { 9435ecc953bSthorpej 9445ecc953bSthorpej (void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions"); 9455ecc953bSthorpej } 9465ecc953bSthorpej 9475ecc953bSthorpej void 9485ecc953bSthorpej delmkoption(const char *name) 9495ecc953bSthorpej { 9505ecc953bSthorpej 9515ecc953bSthorpej (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name, 9525ecc953bSthorpej "makeoptions"); 9535ecc953bSthorpej } 9545ecc953bSthorpej 9555ecc953bSthorpej /* 9565ecc953bSthorpej * Add an appending "make" option. 9575ecc953bSthorpej */ 9585ecc953bSthorpej void 9595ecc953bSthorpej appendmkoption(const char *name, const char *value) 9605ecc953bSthorpej { 9615ecc953bSthorpej struct nvlist *nv; 9625ecc953bSthorpej 9635ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 9645ecc953bSthorpej *nextappmkopt = nv; 9655ecc953bSthorpej nextappmkopt = &nv->nv_next; 9665ecc953bSthorpej } 9675ecc953bSthorpej 9685ecc953bSthorpej /* 9695ecc953bSthorpej * Add a conditional appending "make" option. 9705ecc953bSthorpej */ 9715ecc953bSthorpej void 972a16a6365Scube appendcondmkoption(struct nvlist *cnd, const char *name, const char *value) 9735ecc953bSthorpej { 974a16a6365Scube struct nvlist *nv; 9755ecc953bSthorpej 976a16a6365Scube nv = newnv(name, value, cnd, 0, NULL); 977a16a6365Scube *nextcndmkopt = nv; 978a16a6365Scube nextcndmkopt = &nv->nv_next; 9795ecc953bSthorpej } 9805ecc953bSthorpej 9815ecc953bSthorpej /* 9825ecc953bSthorpej * Add a name=value pair to an option list. The value may be NULL. 9835ecc953bSthorpej */ 9845ecc953bSthorpej static int 9855ecc953bSthorpej do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 9865ecc953bSthorpej const char *value, const char *type) 9875ecc953bSthorpej { 9885ecc953bSthorpej struct nvlist *nv; 9895ecc953bSthorpej 9905ecc953bSthorpej /* assume it will work */ 9915ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 9925ecc953bSthorpej if (ht_insert(ht, name, nv) == 0) { 9935ecc953bSthorpej **nppp = nv; 9945ecc953bSthorpej *nppp = &nv->nv_next; 9955ecc953bSthorpej return (0); 9965ecc953bSthorpej } 9975ecc953bSthorpej 9985ecc953bSthorpej /* oops, already got that option */ 9995ecc953bSthorpej nvfree(nv); 10005ecc953bSthorpej if ((nv = ht_lookup(ht, name)) == NULL) 10015ecc953bSthorpej panic("do_option"); 10025ecc953bSthorpej if (nv->nv_str != NULL && !OPT_FSOPT(name)) 1003c7295a4cSchristos cfgerror("already have %s `%s=%s'", type, name, nv->nv_str); 10045ecc953bSthorpej else 1005c7295a4cSchristos cfgerror("already have %s `%s'", type, name); 10065ecc953bSthorpej return (1); 10075ecc953bSthorpej } 10085ecc953bSthorpej 10095ecc953bSthorpej /* 10105ecc953bSthorpej * Remove a name from a hash table, 10115ecc953bSthorpej * and optionally, a name=value pair from an option list. 10125ecc953bSthorpej */ 10135ecc953bSthorpej static int 10145ecc953bSthorpej undo_option(struct hashtab *ht, struct nvlist **npp, 10155ecc953bSthorpej struct nvlist ***next, const char *name, const char *type) 10165ecc953bSthorpej { 10175ecc953bSthorpej struct nvlist *nv; 10185ecc953bSthorpej 10195ecc953bSthorpej if (ht_remove(ht, name)) { 1020c7295a4cSchristos cfgerror("%s `%s' is not defined", type, name); 10215ecc953bSthorpej return (1); 10225ecc953bSthorpej } 10235ecc953bSthorpej if (npp == NULL) 10245ecc953bSthorpej return (0); 10255ecc953bSthorpej 10265ecc953bSthorpej for ( ; *npp != NULL; npp = &(*npp)->nv_next) { 10275ecc953bSthorpej if ((*npp)->nv_name != name) 10285ecc953bSthorpej continue; 10295ecc953bSthorpej if (next != NULL && *next == &(*npp)->nv_next) 10305ecc953bSthorpej *next = npp; 10315ecc953bSthorpej nv = (*npp)->nv_next; 10325ecc953bSthorpej nvfree(*npp); 10335ecc953bSthorpej *npp = nv; 10345ecc953bSthorpej return (0); 10355ecc953bSthorpej } 10365ecc953bSthorpej panic("%s `%s' is not defined in nvlist", type, name); 10375ecc953bSthorpej return (1); 10385ecc953bSthorpej } 10395ecc953bSthorpej 10405ecc953bSthorpej /* 10415ecc953bSthorpej * Return true if there is at least one instance of the given unit 10425ecc953bSthorpej * on the given device attachment (or any units, if unit == WILD). 10435ecc953bSthorpej */ 10445ecc953bSthorpej int 10455ecc953bSthorpej deva_has_instances(struct deva *deva, int unit) 10465ecc953bSthorpej { 10475ecc953bSthorpej struct devi *i; 10485ecc953bSthorpej 10495ecc953bSthorpej for (i = deva->d_ihead; i != NULL; i = i->i_asame) 10507aa6070dScube if (i->i_active == DEVI_ACTIVE && 1051c130d400Scube (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) 10525ecc953bSthorpej return (1); 10535ecc953bSthorpej return (0); 10545ecc953bSthorpej } 10555ecc953bSthorpej 10565ecc953bSthorpej /* 10575ecc953bSthorpej * Return true if there is at least one instance of the given unit 10585ecc953bSthorpej * on the given base (or any units, if unit == WILD). 10595ecc953bSthorpej */ 10605ecc953bSthorpej int 10615ecc953bSthorpej devbase_has_instances(struct devbase *dev, int unit) 10625ecc953bSthorpej { 10635ecc953bSthorpej struct deva *da; 10645ecc953bSthorpej 10655ecc953bSthorpej /* 10665ecc953bSthorpej * Pseudo-devices are a little special. We consider them 10675ecc953bSthorpej * to have instances only if they are both: 10685ecc953bSthorpej * 10695ecc953bSthorpej * 1. Included in this kernel configuration. 10705ecc953bSthorpej * 1071b66156c7Sdrochner * 2. Be declared "defpseudodev". 10725ecc953bSthorpej */ 10735ecc953bSthorpej if (dev->d_ispseudo) { 1074b66156c7Sdrochner return ((ht_lookup(devitab, dev->d_name) != NULL) 1075b66156c7Sdrochner && (dev->d_ispseudo > 1)); 10765ecc953bSthorpej } 10775ecc953bSthorpej 10785ecc953bSthorpej for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 10795ecc953bSthorpej if (deva_has_instances(da, unit)) 10805ecc953bSthorpej return (1); 10815ecc953bSthorpej return (0); 10825ecc953bSthorpej } 10835ecc953bSthorpej 10845ecc953bSthorpej static int 10855ecc953bSthorpej cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 10865ecc953bSthorpej { 10875ecc953bSthorpej struct devbase *dev; 10885ecc953bSthorpej struct devi *pd; 10895ecc953bSthorpej int errs, devunit; 10905ecc953bSthorpej 10915ecc953bSthorpej if (maxpartitions <= 0) 10925ecc953bSthorpej panic("cfcrosscheck"); 10935ecc953bSthorpej 10945ecc953bSthorpej for (errs = 0; nv != NULL; nv = nv->nv_next) { 10955ecc953bSthorpej if (nv->nv_name == NULL) 10965ecc953bSthorpej continue; 10975ecc953bSthorpej dev = ht_lookup(devbasetab, nv->nv_name); 10985ecc953bSthorpej if (dev == NULL) 10995ecc953bSthorpej panic("cfcrosscheck(%s)", nv->nv_name); 11005ecc953bSthorpej if (has_attr(dev->d_attrs, s_ifnet)) 11015ecc953bSthorpej devunit = nv->nv_ifunit; /* XXX XXX XXX */ 11025ecc953bSthorpej else 11030001b928Schristos devunit = (int)(minor(nv->nv_num) / maxpartitions); 11045ecc953bSthorpej if (devbase_has_instances(dev, devunit)) 11055ecc953bSthorpej continue; 11065ecc953bSthorpej if (devbase_has_instances(dev, STAR) && 11075ecc953bSthorpej devunit >= dev->d_umax) 11085ecc953bSthorpej continue; 11095ecc953bSthorpej TAILQ_FOREACH(pd, &allpseudo, i_next) { 11105ecc953bSthorpej if (pd->i_base == dev && devunit < dev->d_umax && 11115ecc953bSthorpej devunit >= 0) 11125ecc953bSthorpej goto loop; 11135ecc953bSthorpej } 11145ecc953bSthorpej (void)fprintf(stderr, 11155ecc953bSthorpej "%s:%d: %s says %s on %s, but there's no %s\n", 11165ecc953bSthorpej conffile, cf->cf_lineno, 11175ecc953bSthorpej cf->cf_name, what, nv->nv_str, nv->nv_str); 11185ecc953bSthorpej errs++; 11195ecc953bSthorpej loop: 11205ecc953bSthorpej ; 11215ecc953bSthorpej } 11225ecc953bSthorpej return (errs); 11235ecc953bSthorpej } 11245ecc953bSthorpej 11255ecc953bSthorpej /* 11265ecc953bSthorpej * Cross-check the configuration: make sure that each target device 11275ecc953bSthorpej * or attribute (`at foo[0*?]') names at least one real device. Also 11285ecc953bSthorpej * see that the root and dump devices for all configurations are there. 11295ecc953bSthorpej */ 11305ecc953bSthorpej int 11315ecc953bSthorpej crosscheck(void) 11325ecc953bSthorpej { 11335ecc953bSthorpej struct config *cf; 11345ecc953bSthorpej int errs; 11355ecc953bSthorpej 11365ecc953bSthorpej errs = 0; 11375ecc953bSthorpej if (TAILQ_EMPTY(&allcf)) { 1138c7295a4cSchristos warnx("%s has no configurations!", conffile); 11395ecc953bSthorpej errs++; 11405ecc953bSthorpej } 11415ecc953bSthorpej TAILQ_FOREACH(cf, &allcf, cf_next) { 11425ecc953bSthorpej if (cf->cf_root != NULL) { /* i.e., not root on ? */ 11435ecc953bSthorpej errs += cfcrosscheck(cf, "root", cf->cf_root); 11445ecc953bSthorpej errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 11455ecc953bSthorpej } 11465ecc953bSthorpej } 11475ecc953bSthorpej return (errs); 11485ecc953bSthorpej } 11495ecc953bSthorpej 11505ecc953bSthorpej /* 11515ecc953bSthorpej * Check to see if there is a *'d unit with a needs-count file. 11525ecc953bSthorpej */ 11535ecc953bSthorpej int 11545ecc953bSthorpej badstar(void) 11555ecc953bSthorpej { 11565ecc953bSthorpej struct devbase *d; 11575ecc953bSthorpej struct deva *da; 11585ecc953bSthorpej struct devi *i; 11595ecc953bSthorpej int errs, n; 11605ecc953bSthorpej 11615ecc953bSthorpej errs = 0; 11625ecc953bSthorpej TAILQ_FOREACH(d, &allbases, d_next) { 11635ecc953bSthorpej for (da = d->d_ahead; da != NULL; da = da->d_bsame) 11645ecc953bSthorpej for (i = da->d_ihead; i != NULL; i = i->i_asame) { 11655ecc953bSthorpej if (i->i_unit == STAR) 11665ecc953bSthorpej goto aybabtu; 11675ecc953bSthorpej } 11685ecc953bSthorpej continue; 11695ecc953bSthorpej aybabtu: 11705ecc953bSthorpej if (ht_lookup(needcnttab, d->d_name)) { 1171c7295a4cSchristos warnx("%s's cannot be *'d until its driver is fixed", 11725ecc953bSthorpej d->d_name); 11735ecc953bSthorpej errs++; 11745ecc953bSthorpej continue; 11755ecc953bSthorpej } 11765ecc953bSthorpej for (n = 0; i != NULL; i = i->i_alias) 11775ecc953bSthorpej if (!i->i_collapsed) 11785ecc953bSthorpej n++; 11795ecc953bSthorpej if (n < 1) 11805ecc953bSthorpej panic("badstar() n<1"); 11815ecc953bSthorpej } 11825ecc953bSthorpej return (errs); 11835ecc953bSthorpej } 11845ecc953bSthorpej 11855ecc953bSthorpej /* 11865ecc953bSthorpej * Verify/create builddir if necessary, change to it, and verify srcdir. 11875ecc953bSthorpej * This will be called when we see the first include. 11885ecc953bSthorpej */ 11895ecc953bSthorpej void 11905ecc953bSthorpej setupdirs(void) 11915ecc953bSthorpej { 11925ecc953bSthorpej struct stat st; 11935ecc953bSthorpej 11945ecc953bSthorpej /* srcdir must be specified if builddir is not specified or if 11955ecc953bSthorpej * no configuration filename was specified. */ 11965ecc953bSthorpej if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 1197c7295a4cSchristos cfgerror("source directory must be specified"); 11985ecc953bSthorpej exit(1); 11995ecc953bSthorpej } 12005ecc953bSthorpej 120159c94545Scube if (Lflag) { 120259c94545Scube if (srcdir == NULL) 120359c94545Scube srcdir = "../../.."; 120459c94545Scube return; 120559c94545Scube } 120659c94545Scube 12075ecc953bSthorpej if (srcdir == NULL) 12085ecc953bSthorpej srcdir = "../../../.."; 12095ecc953bSthorpej if (builddir == NULL) 12105ecc953bSthorpej builddir = defbuilddir; 12115ecc953bSthorpej 1212c7295a4cSchristos if (stat(builddir, &st) == -1) { 1213c7295a4cSchristos if (mkdir(builddir, 0777) == -1) 1214c7295a4cSchristos errx(EXIT_FAILURE, "cannot create %s", builddir); 1215c7295a4cSchristos } else if (!S_ISDIR(st.st_mode)) 1216c7295a4cSchristos errx(EXIT_FAILURE, "%s is not a directory", builddir); 1217c7295a4cSchristos if (chdir(builddir) == -1) 1218c7295a4cSchristos err(EXIT_FAILURE, "cannot change to %s", builddir); 1219c7295a4cSchristos if (stat(srcdir, &st) == -1) 1220c7295a4cSchristos err(EXIT_FAILURE, "cannot stat %s", srcdir); 1221c7295a4cSchristos if (!S_ISDIR(st.st_mode)) 1222c7295a4cSchristos errx(EXIT_FAILURE, "%s is not a directory", srcdir); 12235ecc953bSthorpej } 12245ecc953bSthorpej 12255ecc953bSthorpej /* 12265ecc953bSthorpej * Write identifier from "ident" directive into file, for 12275ecc953bSthorpej * newvers.sh to pick it up. 12285ecc953bSthorpej */ 12295ecc953bSthorpej int 12305ecc953bSthorpej mkident(void) 12315ecc953bSthorpej { 12325ecc953bSthorpej FILE *fp; 123311820066Scube int error = 0; 12345ecc953bSthorpej 12355ecc953bSthorpej (void)unlink("ident"); 12365ecc953bSthorpej 12375ecc953bSthorpej if (ident == NULL) 12385ecc953bSthorpej return (0); 12395ecc953bSthorpej 12405ecc953bSthorpej if ((fp = fopen("ident", "w")) == NULL) { 1241c7295a4cSchristos warn("cannot write ident"); 12425ecc953bSthorpej return (1); 12435ecc953bSthorpej } 12445ecc953bSthorpej if (vflag) 12455ecc953bSthorpej (void)printf("using ident '%s'\n", ident); 1246342d3579Sdsl fprintf(fp, "%s\n", ident); 1247342d3579Sdsl fflush(fp); 1248342d3579Sdsl if (ferror(fp)) 124911820066Scube error = 1; 12505ecc953bSthorpej (void)fclose(fp); 12515ecc953bSthorpej 125211820066Scube return error; 12535ecc953bSthorpej } 12545ecc953bSthorpej 12555ecc953bSthorpej void 12565ecc953bSthorpej logconfig_start(void) 12575ecc953bSthorpej { 12585ecc953bSthorpej extern FILE *yyin; 12595ecc953bSthorpej char line[1024]; 12605ecc953bSthorpej const char *tmpdir; 12615ecc953bSthorpej struct stat st; 12625ecc953bSthorpej int fd; 12635ecc953bSthorpej 12645ecc953bSthorpej if (yyin == NULL || fstat(fileno(yyin), &st) == -1) 12655ecc953bSthorpej return; 12665ecc953bSthorpej cfgtime = st.st_mtime; 12675ecc953bSthorpej 12685ecc953bSthorpej tmpdir = getenv("TMPDIR"); 12695ecc953bSthorpej if (tmpdir == NULL) 12703b398d5cSdholland tmpdir = _PATH_TMP; 1271c7295a4cSchristos (void)snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); 12725ecc953bSthorpej if ((fd = mkstemp(line)) == -1 || 12735ecc953bSthorpej (cfg = fdopen(fd, "r+")) == NULL) { 12745ecc953bSthorpej if (fd != -1) { 1275c7295a4cSchristos (void)unlink(line); 1276c7295a4cSchristos (void)close(fd); 12775ecc953bSthorpej } 12785ecc953bSthorpej cfg = NULL; 12795ecc953bSthorpej return; 12805ecc953bSthorpej } 1281c7295a4cSchristos (void)unlink(line); 12825ecc953bSthorpej 12834e4935bbSuwe (void)fprintf(cfg, "#include <sys/cdefs.h>\n\n"); 12845ecc953bSthorpej (void)fprintf(cfg, "#include \"opt_config.h\"\n"); 12855ecc953bSthorpej (void)fprintf(cfg, "\n"); 12865ecc953bSthorpej (void)fprintf(cfg, "/*\n"); 12875ecc953bSthorpej (void)fprintf(cfg, " * Add either (or both) of\n"); 12885ecc953bSthorpej (void)fprintf(cfg, " *\n"); 12895ecc953bSthorpej (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); 12905ecc953bSthorpej (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); 12915ecc953bSthorpej (void)fprintf(cfg, " *\n"); 12925ecc953bSthorpej (void)fprintf(cfg, 12935ecc953bSthorpej " * to your kernel config file to embed it in the resulting\n"); 12945ecc953bSthorpej (void)fprintf(cfg, 12955ecc953bSthorpej " * kernel. The latter option does not include files that are\n"); 12965ecc953bSthorpej (void)fprintf(cfg, 12975ecc953bSthorpej " * included (recursively) by your config file. The embedded\n"); 12985ecc953bSthorpej (void)fprintf(cfg, 12995ecc953bSthorpej " * data be extracted by using the command:\n"); 13005ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13015ecc953bSthorpej (void)fprintf(cfg, 13025ecc953bSthorpej " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); 13035ecc953bSthorpej (void)fprintf(cfg, " */\n"); 13045ecc953bSthorpej (void)fprintf(cfg, "\n"); 13055ecc953bSthorpej (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); 13065ecc953bSthorpej (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", 13075ecc953bSthorpej LOGCONFIG_LARGE, LOGCONFIG_SMALL); 13084e4935bbSuwe (void)fprintf(cfg, "static const char config[] __used =\n\n"); 13095ecc953bSthorpej 13105ecc953bSthorpej (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 13115ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", 13125ecc953bSthorpej conffile); 13135ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); 13145ecc953bSthorpej 13155ecc953bSthorpej logconfig_include(yyin, NULL); 13165ecc953bSthorpej 13175ecc953bSthorpej (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 13185ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", 13195ecc953bSthorpej conffile); 13205ecc953bSthorpej 13215ecc953bSthorpej rewind(yyin); 13225ecc953bSthorpej } 13235ecc953bSthorpej 13245ecc953bSthorpej void 13255ecc953bSthorpej logconfig_include(FILE *cf, const char *filename) 13265ecc953bSthorpej { 13275ecc953bSthorpej char line[1024], in[2048], *out; 13285ecc953bSthorpej struct stat st; 13295ecc953bSthorpej int missingeol; 13305ecc953bSthorpej 13315ecc953bSthorpej if (!cfg) 13325ecc953bSthorpej return; 13335ecc953bSthorpej 13345ecc953bSthorpej missingeol = 0; 13355ecc953bSthorpej if (fstat(fileno(cf), &st) == -1) 13365ecc953bSthorpej return; 13375ecc953bSthorpej if (cfgtime < st.st_mtime) 13385ecc953bSthorpej cfgtime = st.st_mtime; 13395ecc953bSthorpej 13405ecc953bSthorpej if (filename) 13415ecc953bSthorpej (void)fprintf(cfg, 13425ecc953bSthorpej "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", 13435ecc953bSthorpej filename); 13445ecc953bSthorpej while (fgets(line, sizeof(line), cf) != NULL) { 13455ecc953bSthorpej missingeol = 1; 13465ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_"); 13475ecc953bSthorpej if (filename) 13485ecc953bSthorpej (void)fprintf(cfg, "###> "); 13495ecc953bSthorpej strvis(in, line, VIS_TAB); 13505ecc953bSthorpej for (out = in; *out; out++) 13515ecc953bSthorpej switch (*out) { 13525ecc953bSthorpej case '\n': 13535ecc953bSthorpej (void)fprintf(cfg, "\\n\"\n"); 13545ecc953bSthorpej missingeol = 0; 13555ecc953bSthorpej break; 13565ecc953bSthorpej case '"': case '\\': 13575ecc953bSthorpej (void)fputc('\\', cfg); 13585ecc953bSthorpej /* FALLTHROUGH */ 13595ecc953bSthorpej default: 13605ecc953bSthorpej (void)fputc(*out, cfg); 13615ecc953bSthorpej break; 13625ecc953bSthorpej } 13635ecc953bSthorpej } 13645ecc953bSthorpej if (missingeol) { 13655ecc953bSthorpej (void)fprintf(cfg, "\\n\"\n"); 1366c7295a4cSchristos warnx("%s: newline missing at EOF", 13675ecc953bSthorpej filename != NULL ? filename : conffile); 13685ecc953bSthorpej } 13695ecc953bSthorpej if (filename) 13705ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", 13715ecc953bSthorpej filename); 13725ecc953bSthorpej 13735ecc953bSthorpej rewind(cf); 13745ecc953bSthorpej } 13755ecc953bSthorpej 13765ecc953bSthorpej void 13775ecc953bSthorpej logconfig_end(void) 13785ecc953bSthorpej { 13795ecc953bSthorpej char line[1024]; 13805ecc953bSthorpej FILE *fp; 13815ecc953bSthorpej struct stat st; 13825ecc953bSthorpej 13835ecc953bSthorpej if (!cfg) 13845ecc953bSthorpej return; 13855ecc953bSthorpej 13865ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); 13875ecc953bSthorpej (void)fprintf(cfg, ";\n"); 13885ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s || %s */\n", 13895ecc953bSthorpej LOGCONFIG_LARGE, LOGCONFIG_SMALL); 13905ecc953bSthorpej (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); 1391342d3579Sdsl fflush(cfg); 1392342d3579Sdsl if (ferror(cfg)) 1393342d3579Sdsl err(EXIT_FAILURE, "write to temporary file for config.h failed"); 13945ecc953bSthorpej rewind(cfg); 13955ecc953bSthorpej 13965ecc953bSthorpej if (stat("config_file.h", &st) != -1) { 13975ecc953bSthorpej if (cfgtime < st.st_mtime) { 13985ecc953bSthorpej fclose(cfg); 13995ecc953bSthorpej return; 14005ecc953bSthorpej } 14015ecc953bSthorpej } 14025ecc953bSthorpej 14035ecc953bSthorpej fp = fopen("config_file.h", "w"); 1404342d3579Sdsl if (!fp) 1405342d3579Sdsl err(EXIT_FAILURE, "cannot open \"config.h\""); 14065ecc953bSthorpej 14075ecc953bSthorpej while (fgets(line, sizeof(line), cfg) != NULL) 14085ecc953bSthorpej fputs(line, fp); 1409342d3579Sdsl fflush(fp); 1410342d3579Sdsl if (ferror(fp)) 1411342d3579Sdsl err(EXIT_FAILURE, "write to \"config.h\" failed"); 14125ecc953bSthorpej fclose(fp); 14135ecc953bSthorpej fclose(cfg); 14145ecc953bSthorpej } 14155ecc953bSthorpej 1416a16a6365Scube const char * 14175ecc953bSthorpej strtolower(const char *name) 14185ecc953bSthorpej { 14195ecc953bSthorpej const char *n; 14205ecc953bSthorpej char *p, low[500]; 14215ecc953bSthorpej unsigned char c; 14225ecc953bSthorpej 14235ecc953bSthorpej for (n = name, p = low; (c = *n) != '\0'; n++) 14245ecc953bSthorpej *p++ = isupper(c) ? tolower(c) : c; 14255ecc953bSthorpej *p = 0; 14265ecc953bSthorpej return (intern(low)); 14275ecc953bSthorpej } 14285ecc953bSthorpej 14295ecc953bSthorpej static int 14305ecc953bSthorpej is_elf(const char *file) 14315ecc953bSthorpej { 14325ecc953bSthorpej int kernel; 14335ecc953bSthorpej char hdr[4]; 14345ecc953bSthorpej 14355ecc953bSthorpej kernel = open(file, O_RDONLY); 1436c7295a4cSchristos if (kernel == -1) 1437c7295a4cSchristos err(EXIT_FAILURE, "cannot open %s", file); 1438c7295a4cSchristos if (read(kernel, hdr, 4) != 4) 1439c7295a4cSchristos err(EXIT_FAILURE, "Cannot read from %s", file); 1440c7295a4cSchristos (void)close(kernel); 14415ecc953bSthorpej 14425ecc953bSthorpej return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; 14435ecc953bSthorpej } 14445ecc953bSthorpej 14455ecc953bSthorpej static int 14465ecc953bSthorpej extract_config(const char *kname, const char *cname, int cfd) 14475ecc953bSthorpej { 14485ecc953bSthorpej char *ptr; 14495ecc953bSthorpej int found, kfd, i; 14505ecc953bSthorpej struct stat st; 14515ecc953bSthorpej 14525ecc953bSthorpej found = 0; 14535ecc953bSthorpej 14545ecc953bSthorpej /* mmap(2) binary kernel */ 14555ecc953bSthorpej kfd = open(conffile, O_RDONLY); 1456c7295a4cSchristos if (kfd == -1) 1457c7295a4cSchristos err(EXIT_FAILURE, "cannot open %s", kname); 1458c7295a4cSchristos if (fstat(kfd, &st) == -1) 1459c7295a4cSchristos err(EXIT_FAILURE, "cannot stat %s", kname); 1460c7295a4cSchristos ptr = mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, 14615ecc953bSthorpej kfd, 0); 1462c7295a4cSchristos if (ptr == MAP_FAILED) 1463c7295a4cSchristos err(EXIT_FAILURE, "cannot mmap %s", kname); 14645ecc953bSthorpej 14655ecc953bSthorpej /* Scan mmap(2)'ed region, extracting kernel configuration */ 14665ecc953bSthorpej for (i = 0; i < st.st_size; i++) { 14675ecc953bSthorpej if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, 14685ecc953bSthorpej "_CFG_", 5) == 0) { 14695ecc953bSthorpej /* Line found */ 14705ecc953bSthorpej char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; 14715ecc953bSthorpej int j; 14725ecc953bSthorpej 14735ecc953bSthorpej found = 1; 14745ecc953bSthorpej 14755ecc953bSthorpej oldptr = (ptr += 5); 1476c7295a4cSchristos while (*ptr != '\n' && *ptr != '\0') 1477c7295a4cSchristos ptr++; 1478c7295a4cSchristos if (ptr - oldptr > LINE_MAX) 1479c7295a4cSchristos errx(EXIT_FAILURE, "line too long"); 14805ecc953bSthorpej i += ptr - oldptr + 5; 1481c7295a4cSchristos (void)memcpy(line, oldptr, (size_t)(ptr - oldptr)); 14825ecc953bSthorpej line[ptr - oldptr] = '\0'; 14835ecc953bSthorpej j = strunvis(uline, line); 1484c7295a4cSchristos if (j == -1) 1485c7295a4cSchristos errx(EXIT_FAILURE, "unvis: invalid " 1486c7295a4cSchristos "encoded sequence"); 14875ecc953bSthorpej uline[j] = '\n'; 1488c7295a4cSchristos if (write(cfd, uline, (size_t)j + 1) == -1) 1489c7295a4cSchristos err(EXIT_FAILURE, "cannot write to %s", cname); 1490c7295a4cSchristos } else 1491c7295a4cSchristos ptr++; 14925ecc953bSthorpej } 14935ecc953bSthorpej 1494c7295a4cSchristos (void)close(kfd); 14955ecc953bSthorpej 14965ecc953bSthorpej return found; 14975ecc953bSthorpej } 1498c130d400Scube 14997aa6070dScube struct dhdi_params { 15007aa6070dScube struct devbase *d; 15017aa6070dScube int unit; 1502a31ff6b4Scube int level; 15037aa6070dScube }; 15047aa6070dScube 15057aa6070dScube static int 15067aa6070dScube devbase_has_dead_instances(const char *key, void *value, void *aux) 15077aa6070dScube { 1508a31ff6b4Scube struct devi *i; 15097aa6070dScube struct dhdi_params *dhdi = aux; 15107aa6070dScube 1511a31ff6b4Scube for (i = value; i != NULL; i = i->i_alias) 15127aa6070dScube if (i->i_base == dhdi->d && 15137aa6070dScube (dhdi->unit == WILD || dhdi->unit == i->i_unit || 1514a31ff6b4Scube i->i_unit == STAR) && 1515a31ff6b4Scube i->i_level >= dhdi->level) 15167aa6070dScube return 1; 15177aa6070dScube return 0; 15187aa6070dScube } 15197aa6070dScube 15207aa6070dScube /* 15217aa6070dScube * This is almost the same as devbase_has_instances, except it 15227aa6070dScube * may have special considerations regarding ignored instances. 15237aa6070dScube */ 15247aa6070dScube 15257aa6070dScube static int 1526a31ff6b4Scube devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) 15277aa6070dScube { 15287aa6070dScube struct deva *da; 15297aa6070dScube struct devi *i; 15307aa6070dScube 15317aa6070dScube if (dev->d_ispseudo) { 15327aa6070dScube if (dev->d_ihead != NULL) 15337aa6070dScube return 1; 1534a31ff6b4Scube else if (state != DEVI_IGNORED) 15357aa6070dScube return 0; 1536a31ff6b4Scube if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) 1537a31ff6b4Scube return 0; 1538a31ff6b4Scube return (i->i_level >= level); 15397aa6070dScube } 15407aa6070dScube 15417aa6070dScube for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 15427aa6070dScube for (i = da->d_ihead; i != NULL; i = i->i_asame) 15437aa6070dScube if ((i->i_active == DEVI_ACTIVE || 15447aa6070dScube i->i_active == state) && 15457aa6070dScube (unit == WILD || unit == i->i_unit || 15467aa6070dScube i->i_unit == STAR)) 15477aa6070dScube return 1; 15487aa6070dScube 15497aa6070dScube if (state == DEVI_IGNORED) { 1550a31ff6b4Scube struct dhdi_params dhdi = { dev, unit, level }; 15517aa6070dScube /* also check dead devices */ 15527aa6070dScube return ht_enumerate(deaddevitab, devbase_has_dead_instances, 15537aa6070dScube &dhdi); 15547aa6070dScube } 15557aa6070dScube 15567aa6070dScube return 0; 15577aa6070dScube } 15587aa6070dScube 15597aa6070dScube /* 15607aa6070dScube * check_dead_devi(), used with ht_enumerate, checks if any of the removed 15617aa6070dScube * device instances would have been a valid instance considering the devbase, 15627aa6070dScube * the parent device and the interface attribute. 15637aa6070dScube * 15647aa6070dScube * In other words, for a non-active device, it checks if children would be 15657aa6070dScube * actual orphans or the result of a negative statement in the config file. 15667aa6070dScube */ 15677aa6070dScube 15687aa6070dScube struct cdd_params { 15697aa6070dScube struct devbase *d; 15707aa6070dScube struct attr *at; 15717aa6070dScube struct devbase *parent; 15727aa6070dScube }; 15737aa6070dScube 15747aa6070dScube static int 15757aa6070dScube check_dead_devi(const char *key, void *value, void *aux) 15767aa6070dScube { 15777aa6070dScube struct cdd_params *cdd = aux; 15787aa6070dScube struct devi *i = value; 1579a31ff6b4Scube struct pspec *p; 15807aa6070dScube 15817aa6070dScube if (i->i_base != cdd->d) 15827aa6070dScube return 0; 15837aa6070dScube 1584a31ff6b4Scube for (; i != NULL; i = i->i_alias) { 1585a31ff6b4Scube p = i->i_pspec; 15867aa6070dScube if ((p == NULL && cdd->at == NULL) || 15877aa6070dScube (p != NULL && p->p_iattr == cdd->at && 15887aa6070dScube (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { 15897aa6070dScube if (p != NULL && 15907aa6070dScube !devbase_has_any_instance(cdd->parent, p->p_atunit, 1591a31ff6b4Scube DEVI_IGNORED, i->i_level)) 15927aa6070dScube return 0; 15937aa6070dScube else 15947aa6070dScube return 1; 15957aa6070dScube } 1596a31ff6b4Scube } 15977aa6070dScube return 0; 15987aa6070dScube } 15997aa6070dScube 1600c130d400Scube static void 16017aa6070dScube do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, 16027aa6070dScube int state) 1603c130d400Scube { 1604c130d400Scube struct nvlist *nv, *nv1; 1605c130d400Scube struct attr *a; 1606c130d400Scube struct devi *i, *j = NULL; 1607c130d400Scube struct pspec *p; 16087aa6070dScube int active = 0; 1609c130d400Scube 1610c130d400Scube /* 1611c130d400Scube * A pseudo-device will always attach at root, and if it has an 1612c130d400Scube * instance (it cannot have more than one), it is enough to consider 1613c130d400Scube * it active, as there is no real attachment. 16147aa6070dScube * 16157aa6070dScube * A pseudo device can never be marked DEVI_IGNORED. 1616c130d400Scube */ 1617c130d400Scube if (d->d_ispseudo) { 16187aa6070dScube if (d->d_ihead != NULL) 16197aa6070dScube d->d_ihead->i_active = active = DEVI_ACTIVE; 16207aa6070dScube else { 16217aa6070dScube if (ht_lookup(deaddevitab, d->d_name) != NULL) 16227aa6070dScube active = DEVI_IGNORED; 16237aa6070dScube else 1624c130d400Scube return; 16257aa6070dScube } 1626c130d400Scube } else { 16272fb411a1Scube int seen = 0; 16282fb411a1Scube 1629c130d400Scube for (i = d->d_ihead; i != NULL; i = i->i_bsame) { 1630c130d400Scube for (j = i; j != NULL; j = j->i_alias) { 1631c130d400Scube p = j->i_pspec; 1632c130d400Scube if ((p == NULL && at == NULL) || 1633c130d400Scube (p != NULL && p->p_iattr == at && 1634c130d400Scube (p->p_atdev == NULL || 1635c130d400Scube p->p_atdev == parent))) { 1636c130d400Scube if (p != NULL && 16377aa6070dScube !devbase_has_any_instance(parent, 1638a31ff6b4Scube p->p_atunit, state, j->i_level)) 1639c130d400Scube continue; 1640c130d400Scube /* 1641c130d400Scube * There are Fry-like devices which can 1642c130d400Scube * be their own grand-parent (or even 1643c130d400Scube * parent, like uhub). We don't want 1644c130d400Scube * to loop, so if we've already reached 1645c130d400Scube * an instance for one reason or 1646c130d400Scube * another, stop there. 1647c130d400Scube */ 16487aa6070dScube if (j->i_active == DEVI_ACTIVE || 16492fb411a1Scube j->i_active == state) { 1650c130d400Scube /* 1651c130d400Scube * Device has already been 16522fb411a1Scube * seen. However it might 16532fb411a1Scube * have siblings who still 16542fb411a1Scube * have to be activated or 16552fb411a1Scube * orphaned. 1656c130d400Scube */ 16572fb411a1Scube seen = 1; 16582fb411a1Scube continue; 16592fb411a1Scube } 16607aa6070dScube j->i_active = active = state; 1661c130d400Scube if (p != NULL) 16627aa6070dScube p->p_active = state; 1663c130d400Scube } 1664c130d400Scube } 1665c130d400Scube } 1666b7505c15Scube /* 1667b7505c15Scube * If we've been there but have made no change, stop. 1668b7505c15Scube */ 1669b7505c15Scube if (seen && !active) 16702fb411a1Scube return; 16717aa6070dScube if (!active) { 16727aa6070dScube struct cdd_params cdd = { d, at, parent }; 16737aa6070dScube /* Look for a matching dead devi */ 167442256315Scube if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) && 167542256315Scube d != parent) 16767aa6070dScube /* 16777aa6070dScube * That device had its instances removed. 16787aa6070dScube * Continue the loop marking descendants 16797aa6070dScube * with DEVI_IGNORED instead of DEVI_ACTIVE. 168042256315Scube * 168142256315Scube * There is one special case for devices that 168242256315Scube * are their own parent: if that instance is 168342256315Scube * removed (e.g., no uhub* at uhub?), we don't 168442256315Scube * have to continue looping. 16857aa6070dScube */ 16867aa6070dScube active = DEVI_IGNORED; 16877aa6070dScube else 1688c130d400Scube return; 1689c130d400Scube } 16907aa6070dScube } 1691c130d400Scube 1692c130d400Scube for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { 1693c130d400Scube a = nv->nv_ptr; 1694c130d400Scube for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) 16957aa6070dScube do_kill_orphans(nv1->nv_ptr, a, d, active); 1696c130d400Scube } 1697c130d400Scube } 1698c130d400Scube 1699c130d400Scube static int 1700c7295a4cSchristos /*ARGSUSED*/ 1701c130d400Scube kill_orphans_cb(const char *key, void *value, void *aux) 1702c130d400Scube { 17037aa6070dScube do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); 1704c130d400Scube return 0; 1705c130d400Scube } 1706c130d400Scube 1707c130d400Scube static void 1708c7295a4cSchristos kill_orphans(void) 1709c130d400Scube { 1710c130d400Scube ht_enumerate(devroottab, kill_orphans_cb, NULL); 1711c130d400Scube } 1712