1*342d3579Sdsl /* $NetBSD: main.c,v 1.17 2006/10/04 20:34:48 dsl 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 555ecc953bSthorpej COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\ 565ecc953bSthorpej The Regents of the University of California. All rights reserved.\n"); 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> 65*342d3579Sdsl #include <err.h> 665ecc953bSthorpej #include <errno.h> 675ecc953bSthorpej #include <fcntl.h> 685ecc953bSthorpej #include <stdio.h> 695ecc953bSthorpej #include <stdlib.h> 705ecc953bSthorpej #include <string.h> 715ecc953bSthorpej #include <unistd.h> 72d0fb8901Schristos #include <vis.h> 73d0fb8901Schristos #include <util.h> 74d0fb8901Schristos 755ecc953bSthorpej #include "defs.h" 765ecc953bSthorpej #include "sem.h" 775ecc953bSthorpej 785ecc953bSthorpej #ifndef LINE_MAX 795ecc953bSthorpej #define LINE_MAX 1024 805ecc953bSthorpej #endif 815ecc953bSthorpej 825ecc953bSthorpej int vflag; /* verbose output */ 835ecc953bSthorpej int Pflag; /* pack locators */ 845ecc953bSthorpej 855ecc953bSthorpej int yyparse(void); 865ecc953bSthorpej 875ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 885ecc953bSthorpej extern int yydebug; 895ecc953bSthorpej #endif 905ecc953bSthorpej 91ac24e161Scube static struct hashtab *obsopttab; 925ecc953bSthorpej static struct hashtab *mkopttab; 935ecc953bSthorpej static struct nvlist **nextopt; 945ecc953bSthorpej static struct nvlist **nextmkopt; 955ecc953bSthorpej static struct nvlist **nextappmkopt; 965ecc953bSthorpej static struct nvlist **nextfsopt; 975ecc953bSthorpej 985ecc953bSthorpej static void usage(void); 995ecc953bSthorpej static void dependopts(void); 1005ecc953bSthorpej static void do_depend(struct nvlist *); 1015ecc953bSthorpej static void stop(void); 1025ecc953bSthorpej static int do_option(struct hashtab *, struct nvlist ***, 1035ecc953bSthorpej const char *, const char *, const char *); 1045ecc953bSthorpej static int undo_option(struct hashtab *, struct nvlist **, 1055ecc953bSthorpej struct nvlist ***, const char *, const char *); 1065ecc953bSthorpej static int crosscheck(void); 1075ecc953bSthorpej static int badstar(void); 1085ecc953bSthorpej int main(int, char **); 1095ecc953bSthorpej static int mksymlinks(void); 1105ecc953bSthorpej static int mkident(void); 1117aa6070dScube static int devbase_has_dead_instances(const char *, void *, void *); 112a31ff6b4Scube static int devbase_has_any_instance(struct devbase *, int, int, int); 1137aa6070dScube static int check_dead_devi(const char *, void *, void *); 114c130d400Scube static void kill_orphans(void); 1157aa6070dScube static void do_kill_orphans(struct devbase *, struct attr *, 1167aa6070dScube struct devbase *, int); 117c130d400Scube static int kill_orphans_cb(const char *, void *, void *); 1185ecc953bSthorpej static int cfcrosscheck(struct config *, const char *, struct nvlist *); 1195ecc953bSthorpej static const char *strtolower(const char *); 1205ecc953bSthorpej void defopt(struct hashtab *ht, const char *fname, 121ac24e161Scube struct nvlist *opts, struct nvlist *deps, int obs); 1225ecc953bSthorpej 1235ecc953bSthorpej #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" 1245ecc953bSthorpej #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" 1255ecc953bSthorpej 1265ecc953bSthorpej static void logconfig_start(void); 1275ecc953bSthorpej static void logconfig_end(void); 1285ecc953bSthorpej static FILE *cfg; 1295ecc953bSthorpej static time_t cfgtime; 1305ecc953bSthorpej 1315ecc953bSthorpej static int is_elf(const char *); 1325ecc953bSthorpej static int extract_config(const char *, const char *, int); 1335ecc953bSthorpej 1345ecc953bSthorpej int badfilename(const char *fname); 1355ecc953bSthorpej 1365ecc953bSthorpej const char *progname; 1375ecc953bSthorpej 1385ecc953bSthorpej int 1395ecc953bSthorpej main(int argc, char **argv) 1405ecc953bSthorpej { 1415ecc953bSthorpej char *p, cname[20]; 1425ecc953bSthorpej const char *last_component; 1435ecc953bSthorpej int pflag, xflag, ch, removeit; 1445ecc953bSthorpej 1455ecc953bSthorpej setprogname(argv[0]); 1465ecc953bSthorpej 1475ecc953bSthorpej pflag = 0; 1485ecc953bSthorpej xflag = 0; 1495ecc953bSthorpej while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) { 1505ecc953bSthorpej switch (ch) { 1515ecc953bSthorpej 1525ecc953bSthorpej #ifndef MAKE_BOOTSTRAP 1535ecc953bSthorpej case 'D': 1545ecc953bSthorpej yydebug = 1; 1555ecc953bSthorpej break; 1565ecc953bSthorpej #endif 1575ecc953bSthorpej 1585ecc953bSthorpej case 'P': 1595ecc953bSthorpej Pflag = 1; 1605ecc953bSthorpej break; 1615ecc953bSthorpej 1625ecc953bSthorpej case 'g': 1635ecc953bSthorpej /* 1645ecc953bSthorpej * In addition to DEBUG, you probably wanted to 1655ecc953bSthorpej * set "options KGDB" and maybe others. We could 1665ecc953bSthorpej * do that for you, but you really should just 1675ecc953bSthorpej * put them in the config file. 1685ecc953bSthorpej */ 1695ecc953bSthorpej (void)fprintf(stderr, 1705ecc953bSthorpej "config: -g is obsolete (use makeoptions DEBUG=\"-g\")\n"); 1715ecc953bSthorpej usage(); 1725ecc953bSthorpej 1735ecc953bSthorpej case 'p': 1745ecc953bSthorpej /* 1755ecc953bSthorpej * Essentially the same as makeoptions PROF="-pg", 1765ecc953bSthorpej * but also changes the path from ../../compile/FOO 1775ecc953bSthorpej * to ../../compile/FOO.PROF; i.e., compile a 1785ecc953bSthorpej * profiling kernel based on a typical "regular" 1795ecc953bSthorpej * kernel. 1805ecc953bSthorpej * 1815ecc953bSthorpej * Note that if you always want profiling, you 1825ecc953bSthorpej * can (and should) use a "makeoptions" line. 1835ecc953bSthorpej */ 1845ecc953bSthorpej pflag = 1; 1855ecc953bSthorpej break; 1865ecc953bSthorpej 1875ecc953bSthorpej case 'v': 1885ecc953bSthorpej vflag = 1; 1895ecc953bSthorpej break; 1905ecc953bSthorpej 1915ecc953bSthorpej case 'b': 1925ecc953bSthorpej builddir = optarg; 1935ecc953bSthorpej break; 1945ecc953bSthorpej 1955ecc953bSthorpej case 's': 1965ecc953bSthorpej srcdir = optarg; 1975ecc953bSthorpej break; 1985ecc953bSthorpej 1995ecc953bSthorpej case 'x': 2005ecc953bSthorpej xflag = 1; 2015ecc953bSthorpej break; 2025ecc953bSthorpej 2035ecc953bSthorpej case '?': 2045ecc953bSthorpej default: 2055ecc953bSthorpej usage(); 2065ecc953bSthorpej } 2075ecc953bSthorpej } 2085ecc953bSthorpej 2095ecc953bSthorpej argc -= optind; 2105ecc953bSthorpej argv += optind; 2115ecc953bSthorpej if (argc > 1) { 2125ecc953bSthorpej usage(); 2135ecc953bSthorpej } 2145ecc953bSthorpej 2155ecc953bSthorpej if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag || 2165ecc953bSthorpej vflag)) { 2175ecc953bSthorpej (void)fprintf(stderr, "config: -x must be used alone\n"); 2185ecc953bSthorpej exit(1); 2195ecc953bSthorpej } 2205ecc953bSthorpej 2215ecc953bSthorpej if (xflag) { 2225ecc953bSthorpej #ifdef __NetBSD__ 2235ecc953bSthorpej conffile = (argc == 1) ? argv[0] : _PATH_UNIX; 2245ecc953bSthorpej #else 2255ecc953bSthorpej if (argc == 0) { 2265ecc953bSthorpej (void)fprintf(stderr, "config: no kernel supplied\n"); 2275ecc953bSthorpej exit(1); 2285ecc953bSthorpej } 2295ecc953bSthorpej #endif 2305ecc953bSthorpej if (!is_elf(conffile)) { 2315ecc953bSthorpej (void)fprintf(stderr, 2325ecc953bSthorpej "config: %s: not a binary kernel\n", 2335ecc953bSthorpej conffile); 2345ecc953bSthorpej exit(1); 2355ecc953bSthorpej } 2365ecc953bSthorpej if (!extract_config(conffile, "stdout", STDOUT_FILENO)) { 2375ecc953bSthorpej (void)fprintf(stderr, 2385ecc953bSthorpej "config: %s does not contain embedded " 2395ecc953bSthorpej "configuration data\n", conffile); 2405ecc953bSthorpej exit(2); 2415ecc953bSthorpej } 2425ecc953bSthorpej exit(0); 2435ecc953bSthorpej } 2445ecc953bSthorpej 2455ecc953bSthorpej conffile = (argc == 1) ? argv[0] : "CONFIG"; 2465ecc953bSthorpej if (firstfile(conffile)) { 2475ecc953bSthorpej (void)fprintf(stderr, "config: cannot read %s: %s\n", 2485ecc953bSthorpej conffile, strerror(errno)); 2495ecc953bSthorpej exit(2); 2505ecc953bSthorpej } 2515ecc953bSthorpej 2525ecc953bSthorpej /* 2535ecc953bSthorpej * Init variables. 2545ecc953bSthorpej */ 2555ecc953bSthorpej minmaxusers = 1; 2565ecc953bSthorpej maxmaxusers = 10000; 2575ecc953bSthorpej initintern(); 2585ecc953bSthorpej initfiles(); 2595ecc953bSthorpej initsem(); 2605ecc953bSthorpej ident = NULL; 2615ecc953bSthorpej devbasetab = ht_new(); 262c130d400Scube devroottab = ht_new(); 2635ecc953bSthorpej devatab = ht_new(); 2645ecc953bSthorpej devitab = ht_new(); 2657aa6070dScube deaddevitab = ht_new(); 2665ecc953bSthorpej selecttab = ht_new(); 2675ecc953bSthorpej needcnttab = ht_new(); 2685ecc953bSthorpej opttab = ht_new(); 2695ecc953bSthorpej mkopttab = ht_new(); 2705ecc953bSthorpej condmkopttab = ht_new(); 2715ecc953bSthorpej fsopttab = ht_new(); 2725ecc953bSthorpej deffstab = ht_new(); 2735ecc953bSthorpej defopttab = ht_new(); 2745ecc953bSthorpej defparamtab = ht_new(); 2755ecc953bSthorpej defflagtab = ht_new(); 2765ecc953bSthorpej optfiletab = ht_new(); 277ac24e161Scube obsopttab = ht_new(); 2785ecc953bSthorpej bdevmtab = ht_new(); 2795ecc953bSthorpej maxbdevm = 0; 2805ecc953bSthorpej cdevmtab = ht_new(); 2815ecc953bSthorpej maxcdevm = 0; 2825ecc953bSthorpej nextopt = &options; 2835ecc953bSthorpej nextmkopt = &mkoptions; 2845ecc953bSthorpej nextappmkopt = &appmkoptions; 2855ecc953bSthorpej nextfsopt = &fsoptions; 2865ecc953bSthorpej 2875ecc953bSthorpej /* 2885ecc953bSthorpej * Handle profiling (must do this before we try to create any 2895ecc953bSthorpej * files). 2905ecc953bSthorpej */ 2915ecc953bSthorpej last_component = strrchr(conffile, '/'); 2925ecc953bSthorpej last_component = (last_component) ? last_component + 1 : conffile; 2935ecc953bSthorpej if (pflag) { 2945ecc953bSthorpej p = emalloc(strlen(last_component) + 17); 2955ecc953bSthorpej (void)sprintf(p, "../compile/%s.PROF", last_component); 2965ecc953bSthorpej (void)addmkoption(intern("PROF"), "-pg"); 2975ecc953bSthorpej (void)addoption(intern("GPROF"), NULL); 2985ecc953bSthorpej } else { 2995ecc953bSthorpej p = emalloc(strlen(last_component) + 13); 3005ecc953bSthorpej (void)sprintf(p, "../compile/%s", last_component); 3015ecc953bSthorpej } 3025ecc953bSthorpej defbuilddir = (argc == 0) ? "." : p; 3035ecc953bSthorpej 3045ecc953bSthorpej removeit = 0; 3055ecc953bSthorpej if (is_elf(conffile)) { 3065ecc953bSthorpej const char *tmpdir; 3075ecc953bSthorpej int cfd; 3085ecc953bSthorpej 3095ecc953bSthorpej if (builddir == NULL) { 3105ecc953bSthorpej (void)fprintf(stderr, 3115ecc953bSthorpej "config: build directory must be specified with " 3125ecc953bSthorpej "binary kernels\n"); 3135ecc953bSthorpej exit(1); 3145ecc953bSthorpej } 3155ecc953bSthorpej 3165ecc953bSthorpej /* Open temporary configuration file */ 3175ecc953bSthorpej tmpdir = getenv("TMPDIR"); 3185ecc953bSthorpej if (tmpdir == NULL) 3195ecc953bSthorpej tmpdir = "/tmp"; 3205ecc953bSthorpej snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir); 3215ecc953bSthorpej cfd = mkstemp(cname); 3225ecc953bSthorpej if (cfd == -1) { 3235ecc953bSthorpej fprintf(stderr, "config: cannot create %s: %s", cname, 3245ecc953bSthorpej strerror(errno)); 3255ecc953bSthorpej exit(2); 3265ecc953bSthorpej } 3275ecc953bSthorpej 3285ecc953bSthorpej printf("Using configuration data embedded in kernel...\n"); 3295ecc953bSthorpej if (!extract_config(conffile, cname, cfd)) { 3305ecc953bSthorpej (void)fprintf(stderr, 3315ecc953bSthorpej "config: %s does not contain embedded " 3325ecc953bSthorpej "configuration data\n", conffile); 3335ecc953bSthorpej exit(2); 3345ecc953bSthorpej } 3355ecc953bSthorpej 3365ecc953bSthorpej removeit = 1; 3375ecc953bSthorpej close(cfd); 3385ecc953bSthorpej firstfile(cname); 3395ecc953bSthorpej } 3405ecc953bSthorpej 3415ecc953bSthorpej /* 3425ecc953bSthorpej * Parse config file (including machine definitions). 3435ecc953bSthorpej */ 3445ecc953bSthorpej logconfig_start(); 3455ecc953bSthorpej if (yyparse()) 3465ecc953bSthorpej stop(); 3475ecc953bSthorpej logconfig_end(); 3485ecc953bSthorpej 3495ecc953bSthorpej if (removeit) 3505ecc953bSthorpej unlink(cname); 3515ecc953bSthorpej 3525ecc953bSthorpej /* 353c130d400Scube * Detect and properly ignore orphaned devices 354c130d400Scube */ 355c130d400Scube kill_orphans(); 356c130d400Scube 357c130d400Scube /* 3585ecc953bSthorpej * Select devices and pseudo devices and their attributes 3595ecc953bSthorpej */ 3607aa6070dScube if (fixdevis()) 3617aa6070dScube stop(); 3625ecc953bSthorpej 3635ecc953bSthorpej /* 3645ecc953bSthorpej * Deal with option dependencies. 3655ecc953bSthorpej */ 3665ecc953bSthorpej dependopts(); 3675ecc953bSthorpej 3685ecc953bSthorpej /* 3695ecc953bSthorpej * Fix (as in `set firmly in place') files. 3705ecc953bSthorpej */ 3715ecc953bSthorpej if (fixfiles()) 3725ecc953bSthorpej stop(); 3735ecc953bSthorpej 3745ecc953bSthorpej /* 3755ecc953bSthorpej * Fix objects and libraries. 3765ecc953bSthorpej */ 3775ecc953bSthorpej if (fixobjects()) 3785ecc953bSthorpej stop(); 3795ecc953bSthorpej 3805ecc953bSthorpej /* 3815ecc953bSthorpej * Fix device-majors. 3825ecc953bSthorpej */ 3835ecc953bSthorpej if (fixdevsw()) 3845ecc953bSthorpej stop(); 3855ecc953bSthorpej 3865ecc953bSthorpej /* 3875ecc953bSthorpej * Perform cross-checking. 3885ecc953bSthorpej */ 3895ecc953bSthorpej if (maxusers == 0) { 3905ecc953bSthorpej if (defmaxusers) { 3915ecc953bSthorpej (void)printf("maxusers not specified; %d assumed\n", 3925ecc953bSthorpej defmaxusers); 3935ecc953bSthorpej maxusers = defmaxusers; 3945ecc953bSthorpej } else { 3955ecc953bSthorpej (void)fprintf(stderr, 3965ecc953bSthorpej "config: need \"maxusers\" line\n"); 3975ecc953bSthorpej errors++; 3985ecc953bSthorpej } 3995ecc953bSthorpej } 4005ecc953bSthorpej if (fsoptions == NULL) { 4015ecc953bSthorpej (void)fprintf(stderr, 4025ecc953bSthorpej "config: need at least one \"file-system\" line\n"); 4035ecc953bSthorpej errors++; 4045ecc953bSthorpej } 4055ecc953bSthorpej if (crosscheck() || errors) 4065ecc953bSthorpej stop(); 4075ecc953bSthorpej 4085ecc953bSthorpej /* 4095ecc953bSthorpej * Squeeze things down and finish cross-checks (STAR checks must 4105ecc953bSthorpej * run after packing). 4115ecc953bSthorpej */ 4125ecc953bSthorpej pack(); 4135ecc953bSthorpej if (badstar()) 4145ecc953bSthorpej stop(); 4155ecc953bSthorpej 4165ecc953bSthorpej /* 4175ecc953bSthorpej * Ready to go. Build all the various files. 4185ecc953bSthorpej */ 4195ecc953bSthorpej if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || 4205ecc953bSthorpej mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident()) 4215ecc953bSthorpej stop(); 4225ecc953bSthorpej (void)printf("Build directory is %s\n", builddir); 4235ecc953bSthorpej (void)printf("Don't forget to run \"make depend\"\n"); 4245ecc953bSthorpej exit(0); 4255ecc953bSthorpej } 4265ecc953bSthorpej 4275ecc953bSthorpej static void 4285ecc953bSthorpej usage(void) 4295ecc953bSthorpej { 4305ecc953bSthorpej (void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] " 4315ecc953bSthorpej "[sysname]\n", stderr); 4325ecc953bSthorpej (void)fputs(" config -x [kernel-file]\n", stderr); 4335ecc953bSthorpej exit(1); 4345ecc953bSthorpej } 4355ecc953bSthorpej 4365ecc953bSthorpej /* 4375ecc953bSthorpej * Set any options that are implied by other options. 4385ecc953bSthorpej */ 4395ecc953bSthorpej static void 4405ecc953bSthorpej dependopts(void) 4415ecc953bSthorpej { 4425ecc953bSthorpej struct nvlist *nv, *opt; 4435ecc953bSthorpej 4445ecc953bSthorpej for (nv = options; nv != NULL; nv = nv->nv_next) { 4455ecc953bSthorpej if ((opt = find_declared_option(nv->nv_name)) != NULL) { 4465ecc953bSthorpej for (opt = opt->nv_ptr; opt != NULL; 4475ecc953bSthorpej opt = opt->nv_next) { 4485ecc953bSthorpej do_depend(opt); 4495ecc953bSthorpej } 4505ecc953bSthorpej } 4515ecc953bSthorpej } 4524a82747aSmatt 4534a82747aSmatt for (nv = fsoptions; nv != NULL; nv = nv->nv_next) { 4544a82747aSmatt if ((opt = find_declared_option(nv->nv_name)) != NULL) { 4554a82747aSmatt for (opt = opt->nv_ptr; opt != NULL; 4564a82747aSmatt opt = opt->nv_next) { 4574a82747aSmatt do_depend(opt); 4584a82747aSmatt } 4594a82747aSmatt } 4604a82747aSmatt } 4615ecc953bSthorpej } 4625ecc953bSthorpej 4635ecc953bSthorpej static void 4645ecc953bSthorpej do_depend(struct nvlist *nv) 4655ecc953bSthorpej { 4665ecc953bSthorpej struct nvlist *nextnv; 4675ecc953bSthorpej struct attr *a; 4685ecc953bSthorpej 4695ecc953bSthorpej if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) { 4705ecc953bSthorpej nv->nv_flags |= NV_DEPENDED; 4715ecc953bSthorpej /* 4725ecc953bSthorpej * If the dependency is an attribute, then just add 4735ecc953bSthorpej * it to the selecttab. 4745ecc953bSthorpej */ 4755ecc953bSthorpej if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) { 4765ecc953bSthorpej if (a->a_iattr) 4775ecc953bSthorpej panic("do_depend(%s): dep `%s' is an iattr", 4785ecc953bSthorpej nv->nv_name, a->a_name); 4795ecc953bSthorpej expandattr(a, selectattr); 4805ecc953bSthorpej } else { 4815ecc953bSthorpej if (ht_lookup(opttab, nv->nv_name) == NULL) 4825ecc953bSthorpej addoption(nv->nv_name, NULL); 4835ecc953bSthorpej if ((nextnv = 4845ecc953bSthorpej find_declared_option(nv->nv_name)) != NULL) 4855ecc953bSthorpej do_depend(nextnv->nv_ptr); 4865ecc953bSthorpej } 4875ecc953bSthorpej } 4885ecc953bSthorpej } 4895ecc953bSthorpej 4905ecc953bSthorpej /* 4915ecc953bSthorpej * Make a symlink for "machine" so that "#include <machine/foo.h>" works, 4925ecc953bSthorpej * and for the machine's CPU architecture, so that works as well. 4935ecc953bSthorpej */ 4945ecc953bSthorpej static int 4955ecc953bSthorpej mksymlinks(void) 4965ecc953bSthorpej { 4975ecc953bSthorpej int ret; 4985ecc953bSthorpej char *p, buf[MAXPATHLEN]; 4995ecc953bSthorpej const char *q; 5005ecc953bSthorpej struct nvlist *nv; 5015ecc953bSthorpej 5025ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", machine); 5035ecc953bSthorpej p = sourcepath(buf); 5045ecc953bSthorpej ret = unlink("machine"); 5055ecc953bSthorpej if (ret && errno != ENOENT) 5065ecc953bSthorpej (void)fprintf(stderr, "config: unlink(machine): %s\n", 5075ecc953bSthorpej strerror(errno)); 5085ecc953bSthorpej ret = symlink(p, "machine"); 5095ecc953bSthorpej if (ret) 5105ecc953bSthorpej (void)fprintf(stderr, "config: symlink(machine -> %s): %s\n", 5115ecc953bSthorpej p, strerror(errno)); 5125ecc953bSthorpej free(p); 5135ecc953bSthorpej 5145ecc953bSthorpej if (machinearch != NULL) { 5155ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", machinearch); 5165ecc953bSthorpej p = sourcepath(buf); 5175ecc953bSthorpej q = machinearch; 5185ecc953bSthorpej } else { 5195ecc953bSthorpej p = estrdup("machine"); 5205ecc953bSthorpej q = machine; 5215ecc953bSthorpej } 5225ecc953bSthorpej ret = unlink(q); 5235ecc953bSthorpej if (ret && errno != ENOENT) 5245ecc953bSthorpej (void)fprintf(stderr, "config: unlink(%s): %s\n", 5255ecc953bSthorpej q, strerror(errno)); 5265ecc953bSthorpej ret = symlink(p, q); 5275ecc953bSthorpej if (ret) 5285ecc953bSthorpej (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n", 5295ecc953bSthorpej q, p, strerror(errno)); 5305ecc953bSthorpej free(p); 5315ecc953bSthorpej 5325ecc953bSthorpej for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { 5335ecc953bSthorpej q = nv->nv_name; 5345ecc953bSthorpej snprintf(buf, sizeof(buf), "arch/%s/include", q); 5355ecc953bSthorpej p = sourcepath(buf); 5365ecc953bSthorpej ret = unlink(q); 5375ecc953bSthorpej if (ret && errno != ENOENT) 5385ecc953bSthorpej (void)fprintf(stderr, "config: unlink(%s): %s\n", 5395ecc953bSthorpej q, strerror(errno)); 5405ecc953bSthorpej ret = symlink(p, q); 5415ecc953bSthorpej if (ret) 5425ecc953bSthorpej (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n", 5435ecc953bSthorpej q, p, strerror(errno)); 5445ecc953bSthorpej free(p); 5455ecc953bSthorpej } 5465ecc953bSthorpej 5475ecc953bSthorpej return (ret); 5485ecc953bSthorpej } 5495ecc953bSthorpej 5505ecc953bSthorpej static __dead void 5515ecc953bSthorpej stop(void) 5525ecc953bSthorpej { 5535ecc953bSthorpej (void)fprintf(stderr, "*** Stop.\n"); 5545ecc953bSthorpej exit(1); 5555ecc953bSthorpej } 5565ecc953bSthorpej 5574a82747aSmatt static void 5584a82747aSmatt add_dependencies(struct nvlist *nv, struct nvlist *deps) 5594a82747aSmatt { 5604a82747aSmatt struct nvlist *dep; 5614a82747aSmatt struct attr *a; 5624a82747aSmatt 5634a82747aSmatt /* Use nv_ptr to link any other options that are implied. */ 5644a82747aSmatt nv->nv_ptr = deps; 5654a82747aSmatt for (dep = deps; dep != NULL; dep = dep->nv_next) { 5664a82747aSmatt /* 5674a82747aSmatt * If the dependency is an attribute, it must not 5684a82747aSmatt * be an interface attribute. Otherwise, it must 5694a82747aSmatt * be a previously declared option. 5704a82747aSmatt */ 5714a82747aSmatt if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) { 5724a82747aSmatt if (a->a_iattr) 5734a82747aSmatt error("option `%s' dependency `%s' " 5744a82747aSmatt "is an interface attribute", 5754a82747aSmatt nv->nv_name, a->a_name); 5764a82747aSmatt } else if (OPT_OBSOLETE(dep->nv_name)) { 5774a82747aSmatt error("option `%s' dependency `%s' " 5784a82747aSmatt "is obsolete", nv->nv_name, dep->nv_name); 5794a82747aSmatt } else if (find_declared_option(dep->nv_name) == NULL) { 5804a82747aSmatt error("option `%s' dependency `%s' " 5814a82747aSmatt "is an unknown option", 5824a82747aSmatt nv->nv_name, dep->nv_name); 5834a82747aSmatt } 5844a82747aSmatt } 5854a82747aSmatt } 5864a82747aSmatt 5875ecc953bSthorpej /* 5885ecc953bSthorpej * Define one or more file systems. If file system options file name is 5895ecc953bSthorpej * specified, a preprocessor #define for that file system will be placed 5905ecc953bSthorpej * in that file. In this case, only one file system may be specified. 5915ecc953bSthorpej * Otherwise, no preprocessor #defines will be generated. 5925ecc953bSthorpej */ 5935ecc953bSthorpej void 5944a82747aSmatt deffilesystem(const char *fname, struct nvlist *fses, struct nvlist *deps) 5955ecc953bSthorpej { 5965ecc953bSthorpej struct nvlist *nv; 5975ecc953bSthorpej 5985ecc953bSthorpej /* 5995ecc953bSthorpej * Mark these options as ones to skip when creating the Makefile. 6005ecc953bSthorpej */ 6015ecc953bSthorpej for (nv = fses; nv != NULL; nv = nv->nv_next) { 6025ecc953bSthorpej if (ht_insert(defopttab, nv->nv_name, nv)) { 6035ecc953bSthorpej error("file system or option `%s' already defined", 6045ecc953bSthorpej nv->nv_name); 6055ecc953bSthorpej return; 6065ecc953bSthorpej } 6075ecc953bSthorpej 6085ecc953bSthorpej /* 6095ecc953bSthorpej * Also mark it as a valid file system, which may be 6105ecc953bSthorpej * used in "file-system" directives in the config 6115ecc953bSthorpej * file. 6125ecc953bSthorpej */ 6135ecc953bSthorpej if (ht_insert(deffstab, nv->nv_name, nv)) 6145ecc953bSthorpej panic("file system `%s' already in table?!", 6155ecc953bSthorpej nv->nv_name); 6165ecc953bSthorpej 6175ecc953bSthorpej if (fname != NULL) { 6185ecc953bSthorpej /* 6195ecc953bSthorpej * Only one file system allowed in this case. 6205ecc953bSthorpej */ 6215ecc953bSthorpej if (nv->nv_next != NULL) { 6225ecc953bSthorpej error("only one file system per option " 6235ecc953bSthorpej "file may be specified"); 6245ecc953bSthorpej return; 6255ecc953bSthorpej } 6265ecc953bSthorpej 6275ecc953bSthorpej if (ht_insert(optfiletab, fname, nv)) { 6285ecc953bSthorpej error("option file `%s' already exists", 6295ecc953bSthorpej fname); 6305ecc953bSthorpej return; 6315ecc953bSthorpej } 6325ecc953bSthorpej } 6334a82747aSmatt 6344a82747aSmatt add_dependencies(nv, deps); 6355ecc953bSthorpej } 6365ecc953bSthorpej } 6375ecc953bSthorpej 6385ecc953bSthorpej /* 6395ecc953bSthorpej * Sanity check a file name. 6405ecc953bSthorpej */ 6415ecc953bSthorpej int 6425ecc953bSthorpej badfilename(const char *fname) 6435ecc953bSthorpej { 6445ecc953bSthorpej const char *n; 6455ecc953bSthorpej 6465ecc953bSthorpej /* 6475ecc953bSthorpej * We're putting multiple options into one file. Sanity 6485ecc953bSthorpej * check the file name. 6495ecc953bSthorpej */ 6505ecc953bSthorpej if (strchr(fname, '/') != NULL) { 6515ecc953bSthorpej error("option file name contains a `/'"); 6525ecc953bSthorpej return 1; 6535ecc953bSthorpej } 6545ecc953bSthorpej if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) { 6555ecc953bSthorpej error("option file name does not end in `.h'"); 6565ecc953bSthorpej return 1; 6575ecc953bSthorpej } 6585ecc953bSthorpej return 0; 6595ecc953bSthorpej } 6605ecc953bSthorpej 6615ecc953bSthorpej 6625ecc953bSthorpej /* 6635ecc953bSthorpej * Search for a defined option (defopt, filesystem, etc), and if found, 6645ecc953bSthorpej * return the option's struct nvlist. 6655ecc953bSthorpej */ 6665ecc953bSthorpej struct nvlist * 6675ecc953bSthorpej find_declared_option(const char *name) 6685ecc953bSthorpej { 6695ecc953bSthorpej struct nvlist *option = NULL; 6705ecc953bSthorpej 6715ecc953bSthorpej if ((option = ht_lookup(defopttab, name)) != NULL || 6725ecc953bSthorpej (option = ht_lookup(defparamtab, name)) != NULL || 6735ecc953bSthorpej (option = ht_lookup(defflagtab, name)) != NULL || 6745ecc953bSthorpej (option = ht_lookup(fsopttab, name)) != NULL) { 6755ecc953bSthorpej return (option); 6765ecc953bSthorpej } 6775ecc953bSthorpej 6785ecc953bSthorpej return (NULL); 6795ecc953bSthorpej } 6805ecc953bSthorpej 6815ecc953bSthorpej 6825ecc953bSthorpej /* 6835ecc953bSthorpej * Define one or more standard options. If an option file name is specified, 6845ecc953bSthorpej * place all options in one file with the specified name. Otherwise, create 6855ecc953bSthorpej * an option file for each option. 6865ecc953bSthorpej * record the option information in the specified table. 6875ecc953bSthorpej */ 6885ecc953bSthorpej void 6895ecc953bSthorpej defopt(struct hashtab *ht, const char *fname, struct nvlist *opts, 690ac24e161Scube struct nvlist *deps, int obs) 6915ecc953bSthorpej { 6924a82747aSmatt struct nvlist *nv, *nextnv, *oldnv; 6935ecc953bSthorpej const char *name; 6945ecc953bSthorpej char buf[500]; 6955ecc953bSthorpej 6965ecc953bSthorpej if (fname != NULL && badfilename(fname)) { 6975ecc953bSthorpej return; 6985ecc953bSthorpej } 6995ecc953bSthorpej 7005ecc953bSthorpej /* 7015ecc953bSthorpej * Mark these options as ones to skip when creating the Makefile. 7025ecc953bSthorpej */ 7035ecc953bSthorpej for (nv = opts; nv != NULL; nv = nextnv) { 7045ecc953bSthorpej nextnv = nv->nv_next; 7055ecc953bSthorpej 7065ecc953bSthorpej /* An option name can be declared at most once. */ 7075ecc953bSthorpej if (DEFINED_OPTION(nv->nv_name)) { 7085ecc953bSthorpej error("file system or option `%s' already defined", 7095ecc953bSthorpej nv->nv_name); 7105ecc953bSthorpej return; 7115ecc953bSthorpej } 7125ecc953bSthorpej 7135ecc953bSthorpej if (ht_insert(ht, nv->nv_name, nv)) { 7145ecc953bSthorpej error("file system or option `%s' already defined", 7155ecc953bSthorpej nv->nv_name); 7165ecc953bSthorpej return; 7175ecc953bSthorpej } 7185ecc953bSthorpej 7195ecc953bSthorpej if (fname == NULL) { 7205ecc953bSthorpej /* 7215ecc953bSthorpej * Each option will be going into its own file. 7225ecc953bSthorpej * Convert the option name to lower case. This 7235ecc953bSthorpej * lower case name will be used as the option 7245ecc953bSthorpej * file name. 7255ecc953bSthorpej */ 7265ecc953bSthorpej (void) snprintf(buf, sizeof(buf), "opt_%s.h", 7275ecc953bSthorpej strtolower(nv->nv_name)); 7285ecc953bSthorpej name = intern(buf); 7295ecc953bSthorpej } else { 7305ecc953bSthorpej name = fname; 7315ecc953bSthorpej } 7325ecc953bSthorpej 7334a82747aSmatt add_dependencies(nv, deps); 7345ecc953bSthorpej 7355ecc953bSthorpej /* 7365ecc953bSthorpej * Remove this option from the parameter list before adding 7375ecc953bSthorpej * it to the list associated with this option file. 7385ecc953bSthorpej */ 7395ecc953bSthorpej nv->nv_next = NULL; 7405ecc953bSthorpej 7415ecc953bSthorpej /* 742ac24e161Scube * Flag as obsolete, if requested. 743ac24e161Scube */ 744ac24e161Scube if (obs) { 745ac24e161Scube nv->nv_flags |= NV_OBSOLETE; 746ac24e161Scube (void)ht_insert(obsopttab, nv->nv_name, nv); 747ac24e161Scube } 748ac24e161Scube 749ac24e161Scube /* 7505ecc953bSthorpej * Add this option file if we haven't seen it yet. 7515ecc953bSthorpej * Otherwise, append to the list of options already 7525ecc953bSthorpej * associated with this file. 7535ecc953bSthorpej */ 7545ecc953bSthorpej if ((oldnv = ht_lookup(optfiletab, name)) == NULL) { 7555ecc953bSthorpej (void)ht_insert(optfiletab, name, nv); 7565ecc953bSthorpej } else { 7575ecc953bSthorpej while (oldnv->nv_next != NULL) 7585ecc953bSthorpej oldnv = oldnv->nv_next; 7595ecc953bSthorpej oldnv->nv_next = nv; 7605ecc953bSthorpej } 7615ecc953bSthorpej } 7625ecc953bSthorpej } 7635ecc953bSthorpej 7645ecc953bSthorpej /* 7655ecc953bSthorpej * Define one or more standard options. If an option file name is specified, 7665ecc953bSthorpej * place all options in one file with the specified name. Otherwise, create 7675ecc953bSthorpej * an option file for each option. 7685ecc953bSthorpej */ 7695ecc953bSthorpej void 7705ecc953bSthorpej defoption(const char *fname, struct nvlist *opts, struct nvlist *deps) 7715ecc953bSthorpej { 7725ecc953bSthorpej 7735ecc953bSthorpej warn("The use of `defopt' is deprecated"); 774ac24e161Scube defopt(defopttab, fname, opts, deps, 0); 7755ecc953bSthorpej } 7765ecc953bSthorpej 7775ecc953bSthorpej 7785ecc953bSthorpej /* 7795ecc953bSthorpej * Define an option for which a value is required. 7805ecc953bSthorpej */ 7815ecc953bSthorpej void 782ac24e161Scube defparam(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs) 7835ecc953bSthorpej { 7845ecc953bSthorpej 785ac24e161Scube defopt(defparamtab, fname, opts, deps, obs); 7865ecc953bSthorpej } 7875ecc953bSthorpej 7885ecc953bSthorpej /* 78972303951Scube * Define an option which must not have a value, and which 7905ecc953bSthorpej * emits a "needs-flag" style output. 7915ecc953bSthorpej */ 7925ecc953bSthorpej void 793ac24e161Scube defflag(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs) 7945ecc953bSthorpej { 7955ecc953bSthorpej 796ac24e161Scube defopt(defflagtab, fname, opts, deps, obs); 7975ecc953bSthorpej } 7985ecc953bSthorpej 7995ecc953bSthorpej 8005ecc953bSthorpej /* 8015ecc953bSthorpej * Add an option from "options FOO". Note that this selects things that 8025ecc953bSthorpej * are "optional foo". 8035ecc953bSthorpej */ 8045ecc953bSthorpej void 8055ecc953bSthorpej addoption(const char *name, const char *value) 8065ecc953bSthorpej { 8075ecc953bSthorpej const char *n; 808ac24e161Scube int is_fs, is_param, is_flag, is_opt, is_undecl, is_obs; 8095ecc953bSthorpej 8105ecc953bSthorpej /* 8115ecc953bSthorpej * Figure out how this option was declared (if at all.) 8125ecc953bSthorpej * XXX should use "params" and "flags" in config. 8135ecc953bSthorpej * XXX crying out for a type field in a unified hashtab. 8145ecc953bSthorpej */ 8155ecc953bSthorpej is_fs = OPT_FSOPT(name); 8165ecc953bSthorpej is_param = OPT_DEFPARAM(name); 8175ecc953bSthorpej is_opt = OPT_DEFOPT(name); 8185ecc953bSthorpej is_flag = OPT_DEFFLAG(name); 819ac24e161Scube is_obs = OPT_OBSOLETE(name); 8205ecc953bSthorpej is_undecl = !DEFINED_OPTION(name); 8215ecc953bSthorpej 822ac24e161Scube /* Warn and pretend the user had not selected the option */ 823ac24e161Scube if (is_obs) { 824ac24e161Scube warn("obsolete option `%s' will be ignored", name); 825ac24e161Scube return; 826ac24e161Scube } 827ac24e161Scube 8285ecc953bSthorpej /* Make sure this is not a defined file system. */ 8295ecc953bSthorpej if (is_fs) { 8305ecc953bSthorpej error("`%s' is a defined file system", name); 8315ecc953bSthorpej return; 8325ecc953bSthorpej } 8335ecc953bSthorpej /* A defparam must have a value */ 8345ecc953bSthorpej if (is_param && value == NULL) { 8355ecc953bSthorpej error("option `%s' must have a value", name); 8365ecc953bSthorpej return; 8375ecc953bSthorpej } 8385ecc953bSthorpej /* A defflag must not have a value */ 8395ecc953bSthorpej if (is_flag && value != NULL) { 8405ecc953bSthorpej error("option `%s' must not have a value", name); 8415ecc953bSthorpej return; 8425ecc953bSthorpej } 8435ecc953bSthorpej 8445ecc953bSthorpej if (is_undecl && vflag) { 8455ecc953bSthorpej warn("undeclared option `%s' added to IDENT", name); 8465ecc953bSthorpej } 8475ecc953bSthorpej 8485ecc953bSthorpej if (do_option(opttab, &nextopt, name, value, "options")) 8495ecc953bSthorpej return; 8505ecc953bSthorpej 8515ecc953bSthorpej /* make lowercase, then add to select table */ 8525ecc953bSthorpej n = strtolower(name); 8535ecc953bSthorpej (void)ht_insert(selecttab, n, (void *)n); 8545ecc953bSthorpej } 8555ecc953bSthorpej 8565ecc953bSthorpej void 8575ecc953bSthorpej deloption(const char *name) 8585ecc953bSthorpej { 8595ecc953bSthorpej 8605ecc953bSthorpej if (undo_option(opttab, &options, &nextopt, name, "options")) 8615ecc953bSthorpej return; 8625ecc953bSthorpej if (undo_option(selecttab, NULL, NULL, strtolower(name), "options")) 8635ecc953bSthorpej return; 8645ecc953bSthorpej } 8655ecc953bSthorpej 8665ecc953bSthorpej /* 8675ecc953bSthorpej * Add a file system option. This routine simply inserts the name into 8685ecc953bSthorpej * a list of valid file systems, which is used to validate the root 8695ecc953bSthorpej * file system type. The name is then treated like a standard option. 8705ecc953bSthorpej */ 8715ecc953bSthorpej void 8725ecc953bSthorpej addfsoption(const char *name) 8735ecc953bSthorpej { 8745ecc953bSthorpej const char *n; 8755ecc953bSthorpej 8765ecc953bSthorpej /* Make sure this is a defined file system. */ 8775ecc953bSthorpej if (!OPT_FSOPT(name)) { 8785ecc953bSthorpej error("`%s' is not a defined file system", name); 8795ecc953bSthorpej return; 8805ecc953bSthorpej } 8815ecc953bSthorpej 8825ecc953bSthorpej /* 8835ecc953bSthorpej * Convert to lower case. This will be used in the select 8845ecc953bSthorpej * table, to verify root file systems, and when the initial 8855ecc953bSthorpej * VFS list is created. 8865ecc953bSthorpej */ 8875ecc953bSthorpej n = strtolower(name); 8885ecc953bSthorpej 8895ecc953bSthorpej if (do_option(fsopttab, &nextfsopt, name, n, "file-system")) 8905ecc953bSthorpej return; 8915ecc953bSthorpej 8925ecc953bSthorpej /* 8935ecc953bSthorpej * Add a lower-case version to the table for root file system 8945ecc953bSthorpej * verification. 8955ecc953bSthorpej */ 8965ecc953bSthorpej if (ht_insert(fsopttab, n, (void *)n)) 8975ecc953bSthorpej panic("addfsoption: already in table"); 8985ecc953bSthorpej 8995ecc953bSthorpej /* Add to select table. */ 9005ecc953bSthorpej (void)ht_insert(selecttab, n, (void *)n); 9015ecc953bSthorpej } 9025ecc953bSthorpej 9035ecc953bSthorpej void 9045ecc953bSthorpej delfsoption(const char *name) 9055ecc953bSthorpej { 9065ecc953bSthorpej const char *n; 9075ecc953bSthorpej 9085ecc953bSthorpej n = strtolower(name); 9095ecc953bSthorpej if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system")) 9105ecc953bSthorpej return; 9115ecc953bSthorpej if (undo_option(fsopttab, NULL, NULL, n, "file-system")) 9125ecc953bSthorpej return; 9135ecc953bSthorpej if (undo_option(selecttab, NULL, NULL, n, "file-system")) 9145ecc953bSthorpej return; 9155ecc953bSthorpej } 9165ecc953bSthorpej 9175ecc953bSthorpej /* 9185ecc953bSthorpej * Add a "make" option. 9195ecc953bSthorpej */ 9205ecc953bSthorpej void 9215ecc953bSthorpej addmkoption(const char *name, const char *value) 9225ecc953bSthorpej { 9235ecc953bSthorpej 9245ecc953bSthorpej (void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions"); 9255ecc953bSthorpej } 9265ecc953bSthorpej 9275ecc953bSthorpej void 9285ecc953bSthorpej delmkoption(const char *name) 9295ecc953bSthorpej { 9305ecc953bSthorpej 9315ecc953bSthorpej (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name, 9325ecc953bSthorpej "makeoptions"); 9335ecc953bSthorpej } 9345ecc953bSthorpej 9355ecc953bSthorpej /* 9365ecc953bSthorpej * Add an appending "make" option. 9375ecc953bSthorpej */ 9385ecc953bSthorpej void 9395ecc953bSthorpej appendmkoption(const char *name, const char *value) 9405ecc953bSthorpej { 9415ecc953bSthorpej struct nvlist *nv; 9425ecc953bSthorpej 9435ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 9445ecc953bSthorpej *nextappmkopt = nv; 9455ecc953bSthorpej nextappmkopt = &nv->nv_next; 9465ecc953bSthorpej } 9475ecc953bSthorpej 9485ecc953bSthorpej /* 9495ecc953bSthorpej * Add a conditional appending "make" option. 9505ecc953bSthorpej */ 9515ecc953bSthorpej void 9525ecc953bSthorpej appendcondmkoption(const char *selname, const char *name, const char *value) 9535ecc953bSthorpej { 9545ecc953bSthorpej struct nvlist *nv, *lnv; 9555ecc953bSthorpej const char *n; 9565ecc953bSthorpej 9575ecc953bSthorpej n = strtolower(selname); 9585ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 9595ecc953bSthorpej if (ht_insert(condmkopttab, n, nv) == 0) 9605ecc953bSthorpej return; 9615ecc953bSthorpej 9625ecc953bSthorpej if ((lnv = ht_lookup(condmkopttab, n)) == NULL) 9635ecc953bSthorpej panic("appendcondmkoption"); 9645ecc953bSthorpej for (; lnv->nv_next != NULL; lnv = lnv->nv_next) 9655ecc953bSthorpej /* search for the last list element */; 9665ecc953bSthorpej lnv->nv_next = nv; 9675ecc953bSthorpej } 9685ecc953bSthorpej 9695ecc953bSthorpej /* 9705ecc953bSthorpej * Add a name=value pair to an option list. The value may be NULL. 9715ecc953bSthorpej */ 9725ecc953bSthorpej static int 9735ecc953bSthorpej do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 9745ecc953bSthorpej const char *value, const char *type) 9755ecc953bSthorpej { 9765ecc953bSthorpej struct nvlist *nv; 9775ecc953bSthorpej 9785ecc953bSthorpej /* 9795ecc953bSthorpej * If a defopt'ed or defflag'ed option was enabled but without 9805ecc953bSthorpej * an explicit value (always the case for defflag), supply a 9815ecc953bSthorpej * default value of 1, as for non-defopt options (where cc 9825ecc953bSthorpej * treats -DBAR as -DBAR=1.) 9835ecc953bSthorpej */ 9845ecc953bSthorpej if ((OPT_DEFOPT(name) || OPT_DEFFLAG(name)) && value == NULL) 9855ecc953bSthorpej value = "1"; 9865ecc953bSthorpej 9875ecc953bSthorpej /* assume it will work */ 9885ecc953bSthorpej nv = newnv(name, value, NULL, 0, NULL); 9895ecc953bSthorpej if (ht_insert(ht, name, nv) == 0) { 9905ecc953bSthorpej **nppp = nv; 9915ecc953bSthorpej *nppp = &nv->nv_next; 9925ecc953bSthorpej return (0); 9935ecc953bSthorpej } 9945ecc953bSthorpej 9955ecc953bSthorpej /* oops, already got that option */ 9965ecc953bSthorpej nvfree(nv); 9975ecc953bSthorpej if ((nv = ht_lookup(ht, name)) == NULL) 9985ecc953bSthorpej panic("do_option"); 9995ecc953bSthorpej if (nv->nv_str != NULL && !OPT_FSOPT(name)) 10005ecc953bSthorpej error("already have %s `%s=%s'", type, name, nv->nv_str); 10015ecc953bSthorpej else 10025ecc953bSthorpej error("already have %s `%s'", type, name); 10035ecc953bSthorpej return (1); 10045ecc953bSthorpej } 10055ecc953bSthorpej 10065ecc953bSthorpej /* 10075ecc953bSthorpej * Remove a name from a hash table, 10085ecc953bSthorpej * and optionally, a name=value pair from an option list. 10095ecc953bSthorpej */ 10105ecc953bSthorpej static int 10115ecc953bSthorpej undo_option(struct hashtab *ht, struct nvlist **npp, 10125ecc953bSthorpej struct nvlist ***next, const char *name, const char *type) 10135ecc953bSthorpej { 10145ecc953bSthorpej struct nvlist *nv; 10155ecc953bSthorpej 10165ecc953bSthorpej if (ht_remove(ht, name)) { 10175ecc953bSthorpej error("%s `%s' is not defined", type, name); 10185ecc953bSthorpej return (1); 10195ecc953bSthorpej } 10205ecc953bSthorpej if (npp == NULL) 10215ecc953bSthorpej return (0); 10225ecc953bSthorpej 10235ecc953bSthorpej for ( ; *npp != NULL; npp = &(*npp)->nv_next) { 10245ecc953bSthorpej if ((*npp)->nv_name != name) 10255ecc953bSthorpej continue; 10265ecc953bSthorpej if (next != NULL && *next == &(*npp)->nv_next) 10275ecc953bSthorpej *next = npp; 10285ecc953bSthorpej nv = (*npp)->nv_next; 10295ecc953bSthorpej nvfree(*npp); 10305ecc953bSthorpej *npp = nv; 10315ecc953bSthorpej return (0); 10325ecc953bSthorpej } 10335ecc953bSthorpej panic("%s `%s' is not defined in nvlist", type, name); 10345ecc953bSthorpej return (1); 10355ecc953bSthorpej } 10365ecc953bSthorpej 10375ecc953bSthorpej /* 10385ecc953bSthorpej * Return true if there is at least one instance of the given unit 10395ecc953bSthorpej * on the given device attachment (or any units, if unit == WILD). 10405ecc953bSthorpej */ 10415ecc953bSthorpej int 10425ecc953bSthorpej deva_has_instances(struct deva *deva, int unit) 10435ecc953bSthorpej { 10445ecc953bSthorpej struct devi *i; 10455ecc953bSthorpej 10465ecc953bSthorpej for (i = deva->d_ihead; i != NULL; i = i->i_asame) 10477aa6070dScube if (i->i_active == DEVI_ACTIVE && 1048c130d400Scube (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) 10495ecc953bSthorpej return (1); 10505ecc953bSthorpej return (0); 10515ecc953bSthorpej } 10525ecc953bSthorpej 10535ecc953bSthorpej /* 10545ecc953bSthorpej * Return true if there is at least one instance of the given unit 10555ecc953bSthorpej * on the given base (or any units, if unit == WILD). 10565ecc953bSthorpej */ 10575ecc953bSthorpej int 10585ecc953bSthorpej devbase_has_instances(struct devbase *dev, int unit) 10595ecc953bSthorpej { 10605ecc953bSthorpej struct deva *da; 10615ecc953bSthorpej 10625ecc953bSthorpej /* 10635ecc953bSthorpej * Pseudo-devices are a little special. We consider them 10645ecc953bSthorpej * to have instances only if they are both: 10655ecc953bSthorpej * 10665ecc953bSthorpej * 1. Included in this kernel configuration. 10675ecc953bSthorpej * 10685ecc953bSthorpej * 2. Have one or more interface attributes. 10695ecc953bSthorpej */ 10705ecc953bSthorpej if (dev->d_ispseudo) { 10715ecc953bSthorpej struct nvlist *nv; 10725ecc953bSthorpej struct attr *a; 10735ecc953bSthorpej 10745ecc953bSthorpej if (ht_lookup(devitab, dev->d_name) == NULL) 10755ecc953bSthorpej return (0); 10765ecc953bSthorpej 10775ecc953bSthorpej for (nv = dev->d_attrs; nv != NULL; nv = nv->nv_next) { 10785ecc953bSthorpej a = nv->nv_ptr; 10795ecc953bSthorpej if (a->a_iattr) 10805ecc953bSthorpej return (1); 10815ecc953bSthorpej } 10825ecc953bSthorpej return (0); 10835ecc953bSthorpej } 10845ecc953bSthorpej 10855ecc953bSthorpej for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 10865ecc953bSthorpej if (deva_has_instances(da, unit)) 10875ecc953bSthorpej return (1); 10885ecc953bSthorpej return (0); 10895ecc953bSthorpej } 10905ecc953bSthorpej 10915ecc953bSthorpej static int 10925ecc953bSthorpej cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 10935ecc953bSthorpej { 10945ecc953bSthorpej struct devbase *dev; 10955ecc953bSthorpej struct devi *pd; 10965ecc953bSthorpej int errs, devunit; 10975ecc953bSthorpej 10985ecc953bSthorpej if (maxpartitions <= 0) 10995ecc953bSthorpej panic("cfcrosscheck"); 11005ecc953bSthorpej 11015ecc953bSthorpej for (errs = 0; nv != NULL; nv = nv->nv_next) { 11025ecc953bSthorpej if (nv->nv_name == NULL) 11035ecc953bSthorpej continue; 11045ecc953bSthorpej dev = ht_lookup(devbasetab, nv->nv_name); 11055ecc953bSthorpej if (dev == NULL) 11065ecc953bSthorpej panic("cfcrosscheck(%s)", nv->nv_name); 11075ecc953bSthorpej if (has_attr(dev->d_attrs, s_ifnet)) 11085ecc953bSthorpej devunit = nv->nv_ifunit; /* XXX XXX XXX */ 11095ecc953bSthorpej else 11105ecc953bSthorpej devunit = minor(nv->nv_int) / maxpartitions; 11115ecc953bSthorpej if (devbase_has_instances(dev, devunit)) 11125ecc953bSthorpej continue; 11135ecc953bSthorpej if (devbase_has_instances(dev, STAR) && 11145ecc953bSthorpej devunit >= dev->d_umax) 11155ecc953bSthorpej continue; 11165ecc953bSthorpej TAILQ_FOREACH(pd, &allpseudo, i_next) { 11175ecc953bSthorpej if (pd->i_base == dev && devunit < dev->d_umax && 11185ecc953bSthorpej devunit >= 0) 11195ecc953bSthorpej goto loop; 11205ecc953bSthorpej } 11215ecc953bSthorpej (void)fprintf(stderr, 11225ecc953bSthorpej "%s:%d: %s says %s on %s, but there's no %s\n", 11235ecc953bSthorpej conffile, cf->cf_lineno, 11245ecc953bSthorpej cf->cf_name, what, nv->nv_str, nv->nv_str); 11255ecc953bSthorpej errs++; 11265ecc953bSthorpej loop: 11275ecc953bSthorpej ; 11285ecc953bSthorpej } 11295ecc953bSthorpej return (errs); 11305ecc953bSthorpej } 11315ecc953bSthorpej 11325ecc953bSthorpej /* 11335ecc953bSthorpej * Cross-check the configuration: make sure that each target device 11345ecc953bSthorpej * or attribute (`at foo[0*?]') names at least one real device. Also 11355ecc953bSthorpej * see that the root and dump devices for all configurations are there. 11365ecc953bSthorpej */ 11375ecc953bSthorpej int 11385ecc953bSthorpej crosscheck(void) 11395ecc953bSthorpej { 11405ecc953bSthorpej struct config *cf; 11415ecc953bSthorpej int errs; 11425ecc953bSthorpej 11435ecc953bSthorpej errs = 0; 11445ecc953bSthorpej if (TAILQ_EMPTY(&allcf)) { 11455ecc953bSthorpej (void)fprintf(stderr, "%s has no configurations!\n", 11465ecc953bSthorpej conffile); 11475ecc953bSthorpej errs++; 11485ecc953bSthorpej } 11495ecc953bSthorpej TAILQ_FOREACH(cf, &allcf, cf_next) { 11505ecc953bSthorpej if (cf->cf_root != NULL) { /* i.e., not root on ? */ 11515ecc953bSthorpej errs += cfcrosscheck(cf, "root", cf->cf_root); 11525ecc953bSthorpej errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 11535ecc953bSthorpej } 11545ecc953bSthorpej } 11555ecc953bSthorpej return (errs); 11565ecc953bSthorpej } 11575ecc953bSthorpej 11585ecc953bSthorpej /* 11595ecc953bSthorpej * Check to see if there is a *'d unit with a needs-count file. 11605ecc953bSthorpej */ 11615ecc953bSthorpej int 11625ecc953bSthorpej badstar(void) 11635ecc953bSthorpej { 11645ecc953bSthorpej struct devbase *d; 11655ecc953bSthorpej struct deva *da; 11665ecc953bSthorpej struct devi *i; 11675ecc953bSthorpej int errs, n; 11685ecc953bSthorpej 11695ecc953bSthorpej errs = 0; 11705ecc953bSthorpej TAILQ_FOREACH(d, &allbases, d_next) { 11715ecc953bSthorpej for (da = d->d_ahead; da != NULL; da = da->d_bsame) 11725ecc953bSthorpej for (i = da->d_ihead; i != NULL; i = i->i_asame) { 11735ecc953bSthorpej if (i->i_unit == STAR) 11745ecc953bSthorpej goto aybabtu; 11755ecc953bSthorpej } 11765ecc953bSthorpej continue; 11775ecc953bSthorpej aybabtu: 11785ecc953bSthorpej if (ht_lookup(needcnttab, d->d_name)) { 11795ecc953bSthorpej (void)fprintf(stderr, 11805ecc953bSthorpej "config: %s's cannot be *'d until its driver is fixed\n", 11815ecc953bSthorpej d->d_name); 11825ecc953bSthorpej errs++; 11835ecc953bSthorpej continue; 11845ecc953bSthorpej } 11855ecc953bSthorpej for (n = 0; i != NULL; i = i->i_alias) 11865ecc953bSthorpej if (!i->i_collapsed) 11875ecc953bSthorpej n++; 11885ecc953bSthorpej if (n < 1) 11895ecc953bSthorpej panic("badstar() n<1"); 11905ecc953bSthorpej } 11915ecc953bSthorpej return (errs); 11925ecc953bSthorpej } 11935ecc953bSthorpej 11945ecc953bSthorpej /* 11955ecc953bSthorpej * Verify/create builddir if necessary, change to it, and verify srcdir. 11965ecc953bSthorpej * This will be called when we see the first include. 11975ecc953bSthorpej */ 11985ecc953bSthorpej void 11995ecc953bSthorpej setupdirs(void) 12005ecc953bSthorpej { 12015ecc953bSthorpej struct stat st; 12025ecc953bSthorpej 12035ecc953bSthorpej /* srcdir must be specified if builddir is not specified or if 12045ecc953bSthorpej * no configuration filename was specified. */ 12055ecc953bSthorpej if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 12065ecc953bSthorpej error("source directory must be specified"); 12075ecc953bSthorpej exit(1); 12085ecc953bSthorpej } 12095ecc953bSthorpej 12105ecc953bSthorpej if (srcdir == NULL) 12115ecc953bSthorpej srcdir = "../../../.."; 12125ecc953bSthorpej if (builddir == NULL) 12135ecc953bSthorpej builddir = defbuilddir; 12145ecc953bSthorpej 12155ecc953bSthorpej if (stat(builddir, &st) != 0) { 12165ecc953bSthorpej if (mkdir(builddir, 0777)) { 12175ecc953bSthorpej (void)fprintf(stderr, "config: cannot create %s: %s\n", 12185ecc953bSthorpej builddir, strerror(errno)); 12195ecc953bSthorpej exit(2); 12205ecc953bSthorpej } 12215ecc953bSthorpej } else if (!S_ISDIR(st.st_mode)) { 12225ecc953bSthorpej (void)fprintf(stderr, "config: %s is not a directory\n", 12235ecc953bSthorpej builddir); 12245ecc953bSthorpej exit(2); 12255ecc953bSthorpej } 12265ecc953bSthorpej if (chdir(builddir) != 0) { 12275ecc953bSthorpej (void)fprintf(stderr, "config: cannot change to %s\n", 12285ecc953bSthorpej builddir); 12295ecc953bSthorpej exit(2); 12305ecc953bSthorpej } 12315ecc953bSthorpej if (stat(srcdir, &st) != 0 || !S_ISDIR(st.st_mode)) { 12325ecc953bSthorpej (void)fprintf(stderr, "config: %s is not a directory\n", 12335ecc953bSthorpej srcdir); 12345ecc953bSthorpej exit(2); 12355ecc953bSthorpej } 12365ecc953bSthorpej } 12375ecc953bSthorpej 12385ecc953bSthorpej /* 12395ecc953bSthorpej * Write identifier from "ident" directive into file, for 12405ecc953bSthorpej * newvers.sh to pick it up. 12415ecc953bSthorpej */ 12425ecc953bSthorpej int 12435ecc953bSthorpej mkident(void) 12445ecc953bSthorpej { 12455ecc953bSthorpej FILE *fp; 124611820066Scube int error = 0; 12475ecc953bSthorpej 12485ecc953bSthorpej (void)unlink("ident"); 12495ecc953bSthorpej 12505ecc953bSthorpej if (ident == NULL) 12515ecc953bSthorpej return (0); 12525ecc953bSthorpej 12535ecc953bSthorpej if ((fp = fopen("ident", "w")) == NULL) { 12545ecc953bSthorpej (void)fprintf(stderr, "config: cannot write ident: %s\n", 12555ecc953bSthorpej strerror(errno)); 12565ecc953bSthorpej return (1); 12575ecc953bSthorpej } 12585ecc953bSthorpej if (vflag) 12595ecc953bSthorpej (void)printf("using ident '%s'\n", ident); 1260*342d3579Sdsl fprintf(fp, "%s\n", ident); 1261*342d3579Sdsl fflush(fp); 1262*342d3579Sdsl if (ferror(fp)) 126311820066Scube error = 1; 12645ecc953bSthorpej (void)fclose(fp); 12655ecc953bSthorpej 126611820066Scube return error; 12675ecc953bSthorpej } 12685ecc953bSthorpej 12695ecc953bSthorpej void 12705ecc953bSthorpej logconfig_start(void) 12715ecc953bSthorpej { 12725ecc953bSthorpej extern FILE *yyin; 12735ecc953bSthorpej char line[1024]; 12745ecc953bSthorpej const char *tmpdir; 12755ecc953bSthorpej struct stat st; 12765ecc953bSthorpej int fd; 12775ecc953bSthorpej 12785ecc953bSthorpej if (yyin == NULL || fstat(fileno(yyin), &st) == -1) 12795ecc953bSthorpej return; 12805ecc953bSthorpej cfgtime = st.st_mtime; 12815ecc953bSthorpej 12825ecc953bSthorpej tmpdir = getenv("TMPDIR"); 12835ecc953bSthorpej if (tmpdir == NULL) 12845ecc953bSthorpej tmpdir = "/tmp"; 12855ecc953bSthorpej snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); 12865ecc953bSthorpej if ((fd = mkstemp(line)) == -1 || 12875ecc953bSthorpej (cfg = fdopen(fd, "r+")) == NULL) { 12885ecc953bSthorpej if (fd != -1) { 12895ecc953bSthorpej unlink(line); 12905ecc953bSthorpej close(fd); 12915ecc953bSthorpej } 12925ecc953bSthorpej cfg = NULL; 12935ecc953bSthorpej return; 12945ecc953bSthorpej } 12955ecc953bSthorpej unlink(line); 12965ecc953bSthorpej 12975ecc953bSthorpej (void)fprintf(cfg, "#include \"opt_config.h\"\n"); 12985ecc953bSthorpej (void)fprintf(cfg, "\n"); 12995ecc953bSthorpej (void)fprintf(cfg, "/*\n"); 13005ecc953bSthorpej (void)fprintf(cfg, " * Add either (or both) of\n"); 13015ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13025ecc953bSthorpej (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); 13035ecc953bSthorpej (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); 13045ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13055ecc953bSthorpej (void)fprintf(cfg, 13065ecc953bSthorpej " * to your kernel config file to embed it in the resulting\n"); 13075ecc953bSthorpej (void)fprintf(cfg, 13085ecc953bSthorpej " * kernel. The latter option does not include files that are\n"); 13095ecc953bSthorpej (void)fprintf(cfg, 13105ecc953bSthorpej " * included (recursively) by your config file. The embedded\n"); 13115ecc953bSthorpej (void)fprintf(cfg, 13125ecc953bSthorpej " * data be extracted by using the command:\n"); 13135ecc953bSthorpej (void)fprintf(cfg, " *\n"); 13145ecc953bSthorpej (void)fprintf(cfg, 13155ecc953bSthorpej " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); 13165ecc953bSthorpej (void)fprintf(cfg, " */\n"); 13175ecc953bSthorpej (void)fprintf(cfg, "\n"); 13185ecc953bSthorpej (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); 13195ecc953bSthorpej (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", 13205ecc953bSthorpej LOGCONFIG_LARGE, LOGCONFIG_SMALL); 13215ecc953bSthorpej (void)fprintf(cfg, 1322fc19b961Schristos "static const char config[]\n#ifdef __vax__\n" 1323f8156140Schristos "\t__attribute__((__unused__))\n#else\n" 1324f8156140Schristos "\t__attribute__((__used__))\n#endif\n\t=\n\n"); 13255ecc953bSthorpej 13265ecc953bSthorpej (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 13275ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", 13285ecc953bSthorpej conffile); 13295ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); 13305ecc953bSthorpej 13315ecc953bSthorpej logconfig_include(yyin, NULL); 13325ecc953bSthorpej 13335ecc953bSthorpej (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); 13345ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", 13355ecc953bSthorpej conffile); 13365ecc953bSthorpej 13375ecc953bSthorpej rewind(yyin); 13385ecc953bSthorpej } 13395ecc953bSthorpej 13405ecc953bSthorpej void 13415ecc953bSthorpej logconfig_include(FILE *cf, const char *filename) 13425ecc953bSthorpej { 13435ecc953bSthorpej char line[1024], in[2048], *out; 13445ecc953bSthorpej struct stat st; 13455ecc953bSthorpej int missingeol; 13465ecc953bSthorpej 13475ecc953bSthorpej if (!cfg) 13485ecc953bSthorpej return; 13495ecc953bSthorpej 13505ecc953bSthorpej missingeol = 0; 13515ecc953bSthorpej if (fstat(fileno(cf), &st) == -1) 13525ecc953bSthorpej return; 13535ecc953bSthorpej if (cfgtime < st.st_mtime) 13545ecc953bSthorpej cfgtime = st.st_mtime; 13555ecc953bSthorpej 13565ecc953bSthorpej if (filename) 13575ecc953bSthorpej (void)fprintf(cfg, 13585ecc953bSthorpej "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", 13595ecc953bSthorpej filename); 13605ecc953bSthorpej while (fgets(line, sizeof(line), cf) != NULL) { 13615ecc953bSthorpej missingeol = 1; 13625ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_"); 13635ecc953bSthorpej if (filename) 13645ecc953bSthorpej (void)fprintf(cfg, "###> "); 13655ecc953bSthorpej strvis(in, line, VIS_TAB); 13665ecc953bSthorpej for (out = in; *out; out++) 13675ecc953bSthorpej switch (*out) { 13685ecc953bSthorpej case '\n': 13695ecc953bSthorpej (void)fprintf(cfg, "\\n\"\n"); 13705ecc953bSthorpej missingeol = 0; 13715ecc953bSthorpej break; 13725ecc953bSthorpej case '"': case '\\': 13735ecc953bSthorpej (void)fputc('\\', cfg); 13745ecc953bSthorpej /* FALLTHROUGH */ 13755ecc953bSthorpej default: 13765ecc953bSthorpej (void)fputc(*out, cfg); 13775ecc953bSthorpej break; 13785ecc953bSthorpej } 13795ecc953bSthorpej } 13805ecc953bSthorpej if (missingeol) { 13815ecc953bSthorpej (void)fprintf(cfg, "\\n\"\n"); 13825ecc953bSthorpej (void)fprintf(stderr, 13835ecc953bSthorpej "config: %s: newline missing at EOF\n", 13845ecc953bSthorpej filename != NULL ? filename : conffile); 13855ecc953bSthorpej } 13865ecc953bSthorpej if (filename) 13875ecc953bSthorpej (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", 13885ecc953bSthorpej filename); 13895ecc953bSthorpej 13905ecc953bSthorpej rewind(cf); 13915ecc953bSthorpej } 13925ecc953bSthorpej 13935ecc953bSthorpej void 13945ecc953bSthorpej logconfig_end(void) 13955ecc953bSthorpej { 13965ecc953bSthorpej char line[1024]; 13975ecc953bSthorpej FILE *fp; 13985ecc953bSthorpej struct stat st; 13995ecc953bSthorpej 14005ecc953bSthorpej if (!cfg) 14015ecc953bSthorpej return; 14025ecc953bSthorpej 14035ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); 14045ecc953bSthorpej (void)fprintf(cfg, ";\n"); 14055ecc953bSthorpej (void)fprintf(cfg, "#endif /* %s || %s */\n", 14065ecc953bSthorpej LOGCONFIG_LARGE, LOGCONFIG_SMALL); 14075ecc953bSthorpej (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); 1408*342d3579Sdsl fflush(cfg); 1409*342d3579Sdsl if (ferror(cfg)) 1410*342d3579Sdsl err(EXIT_FAILURE, "write to temporary file for config.h failed"); 14115ecc953bSthorpej rewind(cfg); 14125ecc953bSthorpej 14135ecc953bSthorpej if (stat("config_file.h", &st) != -1) { 14145ecc953bSthorpej if (cfgtime < st.st_mtime) { 14155ecc953bSthorpej fclose(cfg); 14165ecc953bSthorpej return; 14175ecc953bSthorpej } 14185ecc953bSthorpej } 14195ecc953bSthorpej 14205ecc953bSthorpej fp = fopen("config_file.h", "w"); 1421*342d3579Sdsl if (!fp) 1422*342d3579Sdsl err(EXIT_FAILURE, "cannot open \"config.h\""); 14235ecc953bSthorpej 14245ecc953bSthorpej while (fgets(line, sizeof(line), cfg) != NULL) 14255ecc953bSthorpej fputs(line, fp); 1426*342d3579Sdsl fflush(fp); 1427*342d3579Sdsl if (ferror(fp)) 1428*342d3579Sdsl err(EXIT_FAILURE, "write to \"config.h\" failed"); 14295ecc953bSthorpej fclose(fp); 14305ecc953bSthorpej fclose(cfg); 14315ecc953bSthorpej } 14325ecc953bSthorpej 14335ecc953bSthorpej static const char * 14345ecc953bSthorpej strtolower(const char *name) 14355ecc953bSthorpej { 14365ecc953bSthorpej const char *n; 14375ecc953bSthorpej char *p, low[500]; 14385ecc953bSthorpej unsigned char c; 14395ecc953bSthorpej 14405ecc953bSthorpej for (n = name, p = low; (c = *n) != '\0'; n++) 14415ecc953bSthorpej *p++ = isupper(c) ? tolower(c) : c; 14425ecc953bSthorpej *p = 0; 14435ecc953bSthorpej return (intern(low)); 14445ecc953bSthorpej } 14455ecc953bSthorpej 14465ecc953bSthorpej static int 14475ecc953bSthorpej is_elf(const char *file) 14485ecc953bSthorpej { 14495ecc953bSthorpej int kernel; 14505ecc953bSthorpej char hdr[4]; 14515ecc953bSthorpej 14525ecc953bSthorpej kernel = open(file, O_RDONLY); 14535ecc953bSthorpej if (kernel == -1) { 14545ecc953bSthorpej fprintf(stderr, "config: cannot open %s: %s\n", file, 14555ecc953bSthorpej strerror(errno)); 14565ecc953bSthorpej exit(2); 14575ecc953bSthorpej } 14585ecc953bSthorpej if (read(kernel, hdr, 4) == -1) { 14595ecc953bSthorpej fprintf(stderr, "config: cannot read from %s: %s\n", file, 14605ecc953bSthorpej strerror(errno)); 14615ecc953bSthorpej exit(2); 14625ecc953bSthorpej } 14635ecc953bSthorpej close(kernel); 14645ecc953bSthorpej 14655ecc953bSthorpej return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; 14665ecc953bSthorpej } 14675ecc953bSthorpej 14685ecc953bSthorpej static int 14695ecc953bSthorpej extract_config(const char *kname, const char *cname, int cfd) 14705ecc953bSthorpej { 14715ecc953bSthorpej char *ptr; 14725ecc953bSthorpej int found, kfd, i; 14735ecc953bSthorpej struct stat st; 14745ecc953bSthorpej 14755ecc953bSthorpej found = 0; 14765ecc953bSthorpej 14775ecc953bSthorpej /* mmap(2) binary kernel */ 14785ecc953bSthorpej kfd = open(conffile, O_RDONLY); 14795ecc953bSthorpej if (kfd == -1) { 14805ecc953bSthorpej fprintf(stderr, "config: cannot open %s: %s\n", kname, 14815ecc953bSthorpej strerror(errno)); 14825ecc953bSthorpej exit(2); 14835ecc953bSthorpej } 14845ecc953bSthorpej if ((fstat(kfd, &st) == -1)) { 14855ecc953bSthorpej fprintf(stderr, "config: cannot stat %s: %s\n", kname, 14865ecc953bSthorpej strerror(errno)); 14875ecc953bSthorpej exit(2); 14885ecc953bSthorpej } 14895ecc953bSthorpej ptr = (char *)mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, 14905ecc953bSthorpej kfd, 0); 14915ecc953bSthorpej if (ptr == MAP_FAILED) { 14925ecc953bSthorpej fprintf(stderr, "config: cannot mmap %s: %s\n", kname, 14935ecc953bSthorpej strerror(errno)); 14945ecc953bSthorpej exit(2); 14955ecc953bSthorpej } 14965ecc953bSthorpej 14975ecc953bSthorpej /* Scan mmap(2)'ed region, extracting kernel configuration */ 14985ecc953bSthorpej for (i = 0; i < st.st_size; i++) { 14995ecc953bSthorpej if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, 15005ecc953bSthorpej "_CFG_", 5) == 0) { 15015ecc953bSthorpej /* Line found */ 15025ecc953bSthorpej char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; 15035ecc953bSthorpej int j; 15045ecc953bSthorpej 15055ecc953bSthorpej found = 1; 15065ecc953bSthorpej 15075ecc953bSthorpej oldptr = (ptr += 5); 15085ecc953bSthorpej while (*ptr != '\n' && *ptr != '\0') ptr++; 15095ecc953bSthorpej if (ptr - oldptr > LINE_MAX) { 15105ecc953bSthorpej fprintf(stderr, "config: line too long\n"); 15115ecc953bSthorpej exit(2); 15125ecc953bSthorpej } 15135ecc953bSthorpej i += ptr - oldptr + 5; 15145ecc953bSthorpej memcpy(line, oldptr, (ptr - oldptr)); 15155ecc953bSthorpej line[ptr - oldptr] = '\0'; 15165ecc953bSthorpej j = strunvis(uline, line); 15175ecc953bSthorpej if (j == -1) { 15185ecc953bSthorpej fprintf(stderr, "config: unvis: invalid " 15195ecc953bSthorpej "encoded sequence\n"); 15205ecc953bSthorpej exit(2); 15215ecc953bSthorpej } 15225ecc953bSthorpej uline[j] = '\n'; 15235ecc953bSthorpej if (write(cfd, uline, j + 1) == -1) { 15245ecc953bSthorpej fprintf(stderr, "config: cannot write to %s: " 15255ecc953bSthorpej "%s\n", cname, strerror(errno)); 15265ecc953bSthorpej exit(2); 15275ecc953bSthorpej } 15285ecc953bSthorpej } else ptr++; 15295ecc953bSthorpej } 15305ecc953bSthorpej 15315ecc953bSthorpej close(kfd); 15325ecc953bSthorpej 15335ecc953bSthorpej return found; 15345ecc953bSthorpej } 1535c130d400Scube 15367aa6070dScube struct dhdi_params { 15377aa6070dScube struct devbase *d; 15387aa6070dScube int unit; 1539a31ff6b4Scube int level; 15407aa6070dScube }; 15417aa6070dScube 15427aa6070dScube static int 15437aa6070dScube devbase_has_dead_instances(const char *key, void *value, void *aux) 15447aa6070dScube { 1545a31ff6b4Scube struct devi *i; 15467aa6070dScube struct dhdi_params *dhdi = aux; 15477aa6070dScube 1548a31ff6b4Scube for (i = value; i != NULL; i = i->i_alias) 15497aa6070dScube if (i->i_base == dhdi->d && 15507aa6070dScube (dhdi->unit == WILD || dhdi->unit == i->i_unit || 1551a31ff6b4Scube i->i_unit == STAR) && 1552a31ff6b4Scube i->i_level >= dhdi->level) 15537aa6070dScube return 1; 15547aa6070dScube return 0; 15557aa6070dScube } 15567aa6070dScube 15577aa6070dScube /* 15587aa6070dScube * This is almost the same as devbase_has_instances, except it 15597aa6070dScube * may have special considerations regarding ignored instances. 15607aa6070dScube */ 15617aa6070dScube 15627aa6070dScube static int 1563a31ff6b4Scube devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) 15647aa6070dScube { 15657aa6070dScube struct deva *da; 15667aa6070dScube struct devi *i; 15677aa6070dScube 15687aa6070dScube if (dev->d_ispseudo) { 15697aa6070dScube if (dev->d_ihead != NULL) 15707aa6070dScube return 1; 1571a31ff6b4Scube else if (state != DEVI_IGNORED) 15727aa6070dScube return 0; 1573a31ff6b4Scube if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) 1574a31ff6b4Scube return 0; 1575a31ff6b4Scube return (i->i_level >= level); 15767aa6070dScube } 15777aa6070dScube 15787aa6070dScube for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 15797aa6070dScube for (i = da->d_ihead; i != NULL; i = i->i_asame) 15807aa6070dScube if ((i->i_active == DEVI_ACTIVE || 15817aa6070dScube i->i_active == state) && 15827aa6070dScube (unit == WILD || unit == i->i_unit || 15837aa6070dScube i->i_unit == STAR)) 15847aa6070dScube return 1; 15857aa6070dScube 15867aa6070dScube if (state == DEVI_IGNORED) { 1587a31ff6b4Scube struct dhdi_params dhdi = { dev, unit, level }; 15887aa6070dScube /* also check dead devices */ 15897aa6070dScube return ht_enumerate(deaddevitab, devbase_has_dead_instances, 15907aa6070dScube &dhdi); 15917aa6070dScube } 15927aa6070dScube 15937aa6070dScube return 0; 15947aa6070dScube } 15957aa6070dScube 15967aa6070dScube /* 15977aa6070dScube * check_dead_devi(), used with ht_enumerate, checks if any of the removed 15987aa6070dScube * device instances would have been a valid instance considering the devbase, 15997aa6070dScube * the parent device and the interface attribute. 16007aa6070dScube * 16017aa6070dScube * In other words, for a non-active device, it checks if children would be 16027aa6070dScube * actual orphans or the result of a negative statement in the config file. 16037aa6070dScube */ 16047aa6070dScube 16057aa6070dScube struct cdd_params { 16067aa6070dScube struct devbase *d; 16077aa6070dScube struct attr *at; 16087aa6070dScube struct devbase *parent; 16097aa6070dScube }; 16107aa6070dScube 16117aa6070dScube static int 16127aa6070dScube check_dead_devi(const char *key, void *value, void *aux) 16137aa6070dScube { 16147aa6070dScube struct cdd_params *cdd = aux; 16157aa6070dScube struct devi *i = value; 1616a31ff6b4Scube struct pspec *p; 16177aa6070dScube 16187aa6070dScube if (i->i_base != cdd->d) 16197aa6070dScube return 0; 16207aa6070dScube 1621a31ff6b4Scube for (; i != NULL; i = i->i_alias) { 1622a31ff6b4Scube p = i->i_pspec; 16237aa6070dScube if ((p == NULL && cdd->at == NULL) || 16247aa6070dScube (p != NULL && p->p_iattr == cdd->at && 16257aa6070dScube (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { 16267aa6070dScube if (p != NULL && 16277aa6070dScube !devbase_has_any_instance(cdd->parent, p->p_atunit, 1628a31ff6b4Scube DEVI_IGNORED, i->i_level)) 16297aa6070dScube return 0; 16307aa6070dScube else 16317aa6070dScube return 1; 16327aa6070dScube } 1633a31ff6b4Scube } 16347aa6070dScube return 0; 16357aa6070dScube } 16367aa6070dScube 1637c130d400Scube static void 16387aa6070dScube do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, 16397aa6070dScube int state) 1640c130d400Scube { 1641c130d400Scube struct nvlist *nv, *nv1; 1642c130d400Scube struct attr *a; 1643c130d400Scube struct devi *i, *j = NULL; 1644c130d400Scube struct pspec *p; 16457aa6070dScube int active = 0; 1646c130d400Scube 1647c130d400Scube /* 1648c130d400Scube * A pseudo-device will always attach at root, and if it has an 1649c130d400Scube * instance (it cannot have more than one), it is enough to consider 1650c130d400Scube * it active, as there is no real attachment. 16517aa6070dScube * 16527aa6070dScube * A pseudo device can never be marked DEVI_IGNORED. 1653c130d400Scube */ 1654c130d400Scube if (d->d_ispseudo) { 16557aa6070dScube if (d->d_ihead != NULL) 16567aa6070dScube d->d_ihead->i_active = active = DEVI_ACTIVE; 16577aa6070dScube else { 16587aa6070dScube if (ht_lookup(deaddevitab, d->d_name) != NULL) 16597aa6070dScube active = DEVI_IGNORED; 16607aa6070dScube else 1661c130d400Scube return; 16627aa6070dScube } 1663c130d400Scube } else { 16642fb411a1Scube int seen = 0; 16652fb411a1Scube 1666c130d400Scube for (i = d->d_ihead; i != NULL; i = i->i_bsame) { 1667c130d400Scube for (j = i; j != NULL; j = j->i_alias) { 1668c130d400Scube p = j->i_pspec; 1669c130d400Scube if ((p == NULL && at == NULL) || 1670c130d400Scube (p != NULL && p->p_iattr == at && 1671c130d400Scube (p->p_atdev == NULL || 1672c130d400Scube p->p_atdev == parent))) { 1673c130d400Scube if (p != NULL && 16747aa6070dScube !devbase_has_any_instance(parent, 1675a31ff6b4Scube p->p_atunit, state, j->i_level)) 1676c130d400Scube continue; 1677c130d400Scube /* 1678c130d400Scube * There are Fry-like devices which can 1679c130d400Scube * be their own grand-parent (or even 1680c130d400Scube * parent, like uhub). We don't want 1681c130d400Scube * to loop, so if we've already reached 1682c130d400Scube * an instance for one reason or 1683c130d400Scube * another, stop there. 1684c130d400Scube */ 16857aa6070dScube if (j->i_active == DEVI_ACTIVE || 16862fb411a1Scube j->i_active == state) { 1687c130d400Scube /* 1688c130d400Scube * Device has already been 16892fb411a1Scube * seen. However it might 16902fb411a1Scube * have siblings who still 16912fb411a1Scube * have to be activated or 16922fb411a1Scube * orphaned. 1693c130d400Scube */ 16942fb411a1Scube seen = 1; 16952fb411a1Scube continue; 16962fb411a1Scube } 16977aa6070dScube j->i_active = active = state; 1698c130d400Scube if (p != NULL) 16997aa6070dScube p->p_active = state; 1700c130d400Scube } 1701c130d400Scube } 1702c130d400Scube } 1703b7505c15Scube /* 1704b7505c15Scube * If we've been there but have made no change, stop. 1705b7505c15Scube */ 1706b7505c15Scube if (seen && !active) 17072fb411a1Scube return; 17087aa6070dScube if (!active) { 17097aa6070dScube struct cdd_params cdd = { d, at, parent }; 17107aa6070dScube /* Look for a matching dead devi */ 171142256315Scube if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) && 171242256315Scube d != parent) 17137aa6070dScube /* 17147aa6070dScube * That device had its instances removed. 17157aa6070dScube * Continue the loop marking descendants 17167aa6070dScube * with DEVI_IGNORED instead of DEVI_ACTIVE. 171742256315Scube * 171842256315Scube * There is one special case for devices that 171942256315Scube * are their own parent: if that instance is 172042256315Scube * removed (e.g., no uhub* at uhub?), we don't 172142256315Scube * have to continue looping. 17227aa6070dScube */ 17237aa6070dScube active = DEVI_IGNORED; 17247aa6070dScube else 1725c130d400Scube return; 1726c130d400Scube } 17277aa6070dScube } 1728c130d400Scube 1729c130d400Scube for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { 1730c130d400Scube a = nv->nv_ptr; 1731c130d400Scube for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) 17327aa6070dScube do_kill_orphans(nv1->nv_ptr, a, d, active); 1733c130d400Scube } 1734c130d400Scube } 1735c130d400Scube 1736c130d400Scube static int 1737c130d400Scube kill_orphans_cb(const char *key, void *value, void *aux) 1738c130d400Scube { 17397aa6070dScube do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); 1740c130d400Scube return 0; 1741c130d400Scube } 1742c130d400Scube 1743c130d400Scube static void 1744c130d400Scube kill_orphans() 1745c130d400Scube { 1746c130d400Scube ht_enumerate(devroottab, kill_orphans_cb, NULL); 1747c130d400Scube } 1748