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