xref: /netbsd-src/usr.bin/config/main.c (revision c0179c282a5968435315a82f4128c61372c68fc3)
1 /*	$NetBSD: main.c,v 1.18 2006/10/29 23:00:44 uwe Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratories.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	from: @(#)main.c	8.1 (Berkeley) 6/6/93
41  */
42 
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
46 
47 #ifndef MAKE_BOOTSTRAP
48 #include <sys/cdefs.h>
49 #define	COPYRIGHT(x)	__COPYRIGHT(x)
50 #else
51 #define	COPYRIGHT(x)	static const char copyright[] = x
52 #endif
53 
54 #ifndef lint
55 COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
56 	The Regents of the University of California.  All rights reserved.\n");
57 #endif /* not lint */
58 
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/param.h>
62 #include <sys/mman.h>
63 #include <paths.h>
64 #include <ctype.h>
65 #include <err.h>
66 #include <errno.h>
67 #include <fcntl.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include <vis.h>
73 #include <util.h>
74 
75 #include "defs.h"
76 #include "sem.h"
77 
78 #ifndef LINE_MAX
79 #define LINE_MAX 1024
80 #endif
81 
82 int	vflag;				/* verbose output */
83 int	Pflag;				/* pack locators */
84 
85 int	yyparse(void);
86 
87 #ifndef MAKE_BOOTSTRAP
88 extern int yydebug;
89 #endif
90 
91 static struct hashtab *obsopttab;
92 static struct hashtab *mkopttab;
93 static struct nvlist **nextopt;
94 static struct nvlist **nextmkopt;
95 static struct nvlist **nextappmkopt;
96 static struct nvlist **nextfsopt;
97 
98 static	void	usage(void);
99 static	void	dependopts(void);
100 static	void	do_depend(struct nvlist *);
101 static	void	stop(void);
102 static	int	do_option(struct hashtab *, struct nvlist ***,
103 		    const char *, const char *, const char *);
104 static	int	undo_option(struct hashtab *, struct nvlist **,
105 		    struct nvlist ***, const char *, const char *);
106 static	int	crosscheck(void);
107 static	int	badstar(void);
108 	int	main(int, char **);
109 static	int	mksymlinks(void);
110 static	int	mkident(void);
111 static	int	devbase_has_dead_instances(const char *, void *, void *);
112 static	int	devbase_has_any_instance(struct devbase *, int, int, int);
113 static	int	check_dead_devi(const char *, void *, void *);
114 static	void	kill_orphans(void);
115 static	void	do_kill_orphans(struct devbase *, struct attr *,
116     struct devbase *, int);
117 static	int	kill_orphans_cb(const char *, void *, void *);
118 static	int	cfcrosscheck(struct config *, const char *, struct nvlist *);
119 static	const char *strtolower(const char *);
120 void	defopt(struct hashtab *ht, const char *fname,
121 	     struct nvlist *opts, struct nvlist *deps, int obs);
122 
123 #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE"
124 #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG"
125 
126 static	void	logconfig_start(void);
127 static	void	logconfig_end(void);
128 static	FILE	*cfg;
129 static	time_t	cfgtime;
130 
131 static	int	is_elf(const char *);
132 static	int	extract_config(const char *, const char *, int);
133 
134 int badfilename(const char *fname);
135 
136 const char *progname;
137 
138 int
139 main(int argc, char **argv)
140 {
141 	char *p, cname[20];
142 	const char *last_component;
143 	int pflag, xflag, ch, removeit;
144 
145 	setprogname(argv[0]);
146 
147 	pflag = 0;
148 	xflag = 0;
149 	while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) {
150 		switch (ch) {
151 
152 #ifndef MAKE_BOOTSTRAP
153 		case 'D':
154 			yydebug = 1;
155 			break;
156 #endif
157 
158 		case 'P':
159 			Pflag = 1;
160 			break;
161 
162 		case 'g':
163 			/*
164 			 * In addition to DEBUG, you probably wanted to
165 			 * set "options KGDB" and maybe others.  We could
166 			 * do that for you, but you really should just
167 			 * put them in the config file.
168 			 */
169 			(void)fprintf(stderr,
170 		    "config: -g is obsolete (use makeoptions DEBUG=\"-g\")\n");
171 			usage();
172 
173 		case 'p':
174 			/*
175 			 * Essentially the same as makeoptions PROF="-pg",
176 			 * but also changes the path from ../../compile/FOO
177 			 * to ../../compile/FOO.PROF; i.e., compile a
178 			 * profiling kernel based on a typical "regular"
179 			 * kernel.
180 			 *
181 			 * Note that if you always want profiling, you
182 			 * can (and should) use a "makeoptions" line.
183 			 */
184 			pflag = 1;
185 			break;
186 
187 		case 'v':
188 			vflag = 1;
189 			break;
190 
191 		case 'b':
192 			builddir = optarg;
193 			break;
194 
195 		case 's':
196 			srcdir = optarg;
197 			break;
198 
199 		case 'x':
200 			xflag = 1;
201 			break;
202 
203 		case '?':
204 		default:
205 			usage();
206 		}
207 	}
208 
209 	argc -= optind;
210 	argv += optind;
211 	if (argc > 1) {
212 		usage();
213 	}
214 
215 	if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag ||
216 	    vflag)) {
217 		(void)fprintf(stderr, "config: -x must be used alone\n");
218 		exit(1);
219 	}
220 
221 	if (xflag) {
222 #ifdef __NetBSD__
223 		conffile = (argc == 1) ? argv[0] : _PATH_UNIX;
224 #else
225 		if (argc == 0) {
226 			(void)fprintf(stderr, "config: no kernel supplied\n");
227 			exit(1);
228 		}
229 #endif
230 		if (!is_elf(conffile)) {
231 			(void)fprintf(stderr,
232 			    "config: %s: not a binary kernel\n",
233 			    conffile);
234 			exit(1);
235 		}
236 		if (!extract_config(conffile, "stdout", STDOUT_FILENO)) {
237 			(void)fprintf(stderr,
238 			    "config: %s does not contain embedded "
239 			    "configuration data\n", conffile);
240 			exit(2);
241 		}
242 		exit(0);
243 	}
244 
245 	conffile = (argc == 1) ? argv[0] : "CONFIG";
246 	if (firstfile(conffile)) {
247 		(void)fprintf(stderr, "config: cannot read %s: %s\n",
248 		    conffile, strerror(errno));
249 		exit(2);
250 	}
251 
252 	/*
253 	 * Init variables.
254 	 */
255 	minmaxusers = 1;
256 	maxmaxusers = 10000;
257 	initintern();
258 	initfiles();
259 	initsem();
260 	ident = NULL;
261 	devbasetab = ht_new();
262 	devroottab = ht_new();
263 	devatab = ht_new();
264 	devitab = ht_new();
265 	deaddevitab = ht_new();
266 	selecttab = ht_new();
267 	needcnttab = ht_new();
268 	opttab = ht_new();
269 	mkopttab = ht_new();
270 	condmkopttab = ht_new();
271 	fsopttab = ht_new();
272 	deffstab = ht_new();
273 	defopttab = ht_new();
274 	defparamtab = ht_new();
275 	defflagtab = ht_new();
276 	optfiletab = ht_new();
277 	obsopttab = ht_new();
278 	bdevmtab = ht_new();
279 	maxbdevm = 0;
280 	cdevmtab = ht_new();
281 	maxcdevm = 0;
282 	nextopt = &options;
283 	nextmkopt = &mkoptions;
284 	nextappmkopt = &appmkoptions;
285 	nextfsopt = &fsoptions;
286 
287 	/*
288 	 * Handle profiling (must do this before we try to create any
289 	 * files).
290 	 */
291 	last_component = strrchr(conffile, '/');
292 	last_component = (last_component) ? last_component + 1 : conffile;
293 	if (pflag) {
294 		p = emalloc(strlen(last_component) + 17);
295 		(void)sprintf(p, "../compile/%s.PROF", last_component);
296 		(void)addmkoption(intern("PROF"), "-pg");
297 		(void)addoption(intern("GPROF"), NULL);
298 	} else {
299 		p = emalloc(strlen(last_component) + 13);
300 		(void)sprintf(p, "../compile/%s", last_component);
301 	}
302 	defbuilddir = (argc == 0) ? "." : p;
303 
304 	removeit = 0;
305 	if (is_elf(conffile)) {
306 		const char *tmpdir;
307 		int cfd;
308 
309 		if (builddir == NULL) {
310 			(void)fprintf(stderr,
311 			    "config: build directory must be specified with "
312 			    "binary kernels\n");
313 			exit(1);
314 		}
315 
316 		/* Open temporary configuration file */
317 		tmpdir = getenv("TMPDIR");
318 		if (tmpdir == NULL)
319 			tmpdir = "/tmp";
320 		snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir);
321 		cfd = mkstemp(cname);
322 		if (cfd == -1) {
323 			fprintf(stderr, "config: cannot create %s: %s", cname,
324 			    strerror(errno));
325 			exit(2);
326 		}
327 
328 		printf("Using configuration data embedded in kernel...\n");
329 		if (!extract_config(conffile, cname, cfd)) {
330 			(void)fprintf(stderr,
331 			    "config: %s does not contain embedded "
332 			    "configuration data\n", conffile);
333 			exit(2);
334 		}
335 
336 		removeit = 1;
337 		close(cfd);
338 		firstfile(cname);
339 	}
340 
341 	/*
342 	 * Parse config file (including machine definitions).
343 	 */
344 	logconfig_start();
345 	if (yyparse())
346 		stop();
347 	logconfig_end();
348 
349 	if (removeit)
350 		unlink(cname);
351 
352 	/*
353 	 * Detect and properly ignore orphaned devices
354 	 */
355 	kill_orphans();
356 
357 	/*
358 	 * Select devices and pseudo devices and their attributes
359 	 */
360 	if (fixdevis())
361 		stop();
362 
363 	/*
364 	 * Deal with option dependencies.
365 	 */
366 	dependopts();
367 
368 	/*
369 	 * Fix (as in `set firmly in place') files.
370 	 */
371 	if (fixfiles())
372 		stop();
373 
374 	/*
375 	 * Fix objects and libraries.
376 	 */
377 	if (fixobjects())
378 		stop();
379 
380 	/*
381 	 * Fix device-majors.
382 	 */
383 	if (fixdevsw())
384 		stop();
385 
386 	/*
387 	 * Perform cross-checking.
388 	 */
389 	if (maxusers == 0) {
390 		if (defmaxusers) {
391 			(void)printf("maxusers not specified; %d assumed\n",
392 			    defmaxusers);
393 			maxusers = defmaxusers;
394 		} else {
395 			(void)fprintf(stderr,
396 			    "config: need \"maxusers\" line\n");
397 			errors++;
398 		}
399 	}
400 	if (fsoptions == NULL) {
401 		(void)fprintf(stderr,
402 		    "config: need at least one \"file-system\" line\n");
403 		errors++;
404 	}
405 	if (crosscheck() || errors)
406 		stop();
407 
408 	/*
409 	 * Squeeze things down and finish cross-checks (STAR checks must
410 	 * run after packing).
411 	 */
412 	pack();
413 	if (badstar())
414 		stop();
415 
416 	/*
417 	 * Ready to go.  Build all the various files.
418 	 */
419 	if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
420 	    mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident())
421 		stop();
422 	(void)printf("Build directory is %s\n", builddir);
423 	(void)printf("Don't forget to run \"make depend\"\n");
424 	exit(0);
425 }
426 
427 static void
428 usage(void)
429 {
430 	(void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] "
431 		"[sysname]\n", stderr);
432 	(void)fputs("       config -x [kernel-file]\n", stderr);
433 	exit(1);
434 }
435 
436 /*
437  * Set any options that are implied by other options.
438  */
439 static void
440 dependopts(void)
441 {
442 	struct nvlist *nv, *opt;
443 
444 	for (nv = options; nv != NULL; nv = nv->nv_next) {
445 		if ((opt = find_declared_option(nv->nv_name)) != NULL) {
446 			for (opt = opt->nv_ptr; opt != NULL;
447 			    opt = opt->nv_next) {
448 				do_depend(opt);
449 			}
450 		}
451 	}
452 
453 	for (nv = fsoptions; nv != NULL; nv = nv->nv_next) {
454 		if ((opt = find_declared_option(nv->nv_name)) != NULL) {
455 			for (opt = opt->nv_ptr; opt != NULL;
456 			    opt = opt->nv_next) {
457 				do_depend(opt);
458 			}
459 		}
460 	}
461 }
462 
463 static void
464 do_depend(struct nvlist *nv)
465 {
466 	struct nvlist *nextnv;
467 	struct attr *a;
468 
469 	if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) {
470 		nv->nv_flags |= NV_DEPENDED;
471 		/*
472 		 * If the dependency is an attribute, then just add
473 		 * it to the selecttab.
474 		 */
475 		if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) {
476 			if (a->a_iattr)
477 				panic("do_depend(%s): dep `%s' is an iattr",
478 				    nv->nv_name, a->a_name);
479 			expandattr(a, selectattr);
480 		} else {
481 			if (ht_lookup(opttab, nv->nv_name) == NULL)
482 				addoption(nv->nv_name, NULL);
483 			if ((nextnv =
484 			     find_declared_option(nv->nv_name)) != NULL)
485 				do_depend(nextnv->nv_ptr);
486 		}
487 	}
488 }
489 
490 /*
491  * Make a symlink for "machine" so that "#include <machine/foo.h>" works,
492  * and for the machine's CPU architecture, so that works as well.
493  */
494 static int
495 mksymlinks(void)
496 {
497 	int ret;
498 	char *p, buf[MAXPATHLEN];
499 	const char *q;
500 	struct nvlist *nv;
501 
502 	snprintf(buf, sizeof(buf), "arch/%s/include", machine);
503 	p = sourcepath(buf);
504 	ret = unlink("machine");
505 	if (ret && errno != ENOENT)
506 		(void)fprintf(stderr, "config: unlink(machine): %s\n",
507 		    strerror(errno));
508 	ret = symlink(p, "machine");
509 	if (ret)
510 		(void)fprintf(stderr, "config: symlink(machine -> %s): %s\n",
511 		    p, strerror(errno));
512 	free(p);
513 
514 	if (machinearch != NULL) {
515 		snprintf(buf, sizeof(buf), "arch/%s/include", machinearch);
516 		p = sourcepath(buf);
517 		q = machinearch;
518 	} else {
519 		p = estrdup("machine");
520 		q = machine;
521 	}
522 	ret = unlink(q);
523 	if (ret && errno != ENOENT)
524 		(void)fprintf(stderr, "config: unlink(%s): %s\n",
525 		    q, strerror(errno));
526 	ret = symlink(p, q);
527 	if (ret)
528 		(void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
529 		    q, p, strerror(errno));
530 	free(p);
531 
532 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
533 		q = nv->nv_name;
534 		snprintf(buf, sizeof(buf), "arch/%s/include", q);
535 		p = sourcepath(buf);
536 		ret = unlink(q);
537 		if (ret && errno != ENOENT)
538 			(void)fprintf(stderr, "config: unlink(%s): %s\n",
539 			    q, strerror(errno));
540 		ret = symlink(p, q);
541 		if (ret)
542 			(void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
543 		    	q, p, strerror(errno));
544 		free(p);
545 	}
546 
547 	return (ret);
548 }
549 
550 static __dead void
551 stop(void)
552 {
553 	(void)fprintf(stderr, "*** Stop.\n");
554 	exit(1);
555 }
556 
557 static void
558 add_dependencies(struct nvlist *nv, struct nvlist *deps)
559 {
560 	struct nvlist *dep;
561 	struct attr *a;
562 
563 	/* Use nv_ptr to link any other options that are implied. */
564 	nv->nv_ptr = deps;
565 	for (dep = deps; dep != NULL; dep = dep->nv_next) {
566 		/*
567 		 * If the dependency is an attribute, it must not
568 		 * be an interface attribute.  Otherwise, it must
569 		 * be a previously declared option.
570 		 */
571 		if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) {
572 			if (a->a_iattr)
573 				error("option `%s' dependency `%s' "
574 				    "is an interface attribute",
575 				    nv->nv_name, a->a_name);
576 		} else if (OPT_OBSOLETE(dep->nv_name)) {
577 			error("option `%s' dependency `%s' "
578 			    "is obsolete", nv->nv_name, dep->nv_name);
579 		} else if (find_declared_option(dep->nv_name) == NULL) {
580 			error("option `%s' dependency `%s' "
581 			    "is an unknown option",
582 			    nv->nv_name, dep->nv_name);
583 		}
584 	}
585 }
586 
587 /*
588  * Define one or more file systems.  If file system options file name is
589  * specified, a preprocessor #define for that file system will be placed
590  * in that file.  In this case, only one file system may be specified.
591  * Otherwise, no preprocessor #defines will be generated.
592  */
593 void
594 deffilesystem(const char *fname, struct nvlist *fses, struct nvlist *deps)
595 {
596 	struct nvlist *nv;
597 
598 	/*
599 	 * Mark these options as ones to skip when creating the Makefile.
600 	 */
601 	for (nv = fses; nv != NULL; nv = nv->nv_next) {
602 		if (ht_insert(defopttab, nv->nv_name, nv)) {
603 			error("file system or option `%s' already defined",
604 			    nv->nv_name);
605 			return;
606 		}
607 
608 		/*
609 		 * Also mark it as a valid file system, which may be
610 		 * used in "file-system" directives in the config
611 		 * file.
612 		 */
613 		if (ht_insert(deffstab, nv->nv_name, nv))
614 			panic("file system `%s' already in table?!",
615 			    nv->nv_name);
616 
617 		if (fname != NULL) {
618 			/*
619 			 * Only one file system allowed in this case.
620 			 */
621 			if (nv->nv_next != NULL) {
622 				error("only one file system per option "
623 				    "file may be specified");
624 				return;
625 			}
626 
627 			if (ht_insert(optfiletab, fname, nv)) {
628 				error("option file `%s' already exists",
629 				    fname);
630 				return;
631 			}
632 		}
633 
634 		add_dependencies(nv, deps);
635 	}
636 }
637 
638 /*
639  * Sanity check a file name.
640  */
641 int
642 badfilename(const char *fname)
643 {
644 	const char *n;
645 
646 	/*
647 	 * We're putting multiple options into one file.  Sanity
648 	 * check the file name.
649 	 */
650 	if (strchr(fname, '/') != NULL) {
651 		error("option file name contains a `/'");
652 		return 1;
653 	}
654 	if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) {
655 		error("option file name does not end in `.h'");
656 		return 1;
657 	}
658 	return 0;
659 }
660 
661 
662 /*
663  * Search for a defined option (defopt, filesystem, etc), and if found,
664  * return the option's struct nvlist.
665  */
666 struct nvlist *
667 find_declared_option(const char *name)
668 {
669 	struct nvlist *option = NULL;
670 
671 	if ((option = ht_lookup(defopttab, name)) != NULL ||
672 	    (option = ht_lookup(defparamtab, name)) != NULL ||
673 	    (option = ht_lookup(defflagtab, name)) != NULL ||
674 	    (option = ht_lookup(fsopttab, name)) != NULL) {
675 		return (option);
676 	}
677 
678 	return (NULL);
679 }
680 
681 
682 /*
683  * Define one or more standard options.  If an option file name is specified,
684  * place all options in one file with the specified name.  Otherwise, create
685  * an option file for each option.
686  * record the option information in the specified table.
687  */
688 void
689 defopt(struct hashtab *ht, const char *fname, struct nvlist *opts,
690        struct nvlist *deps, int obs)
691 {
692 	struct nvlist *nv, *nextnv, *oldnv;
693 	const char *name;
694 	char buf[500];
695 
696 	if (fname != NULL && badfilename(fname)) {
697 		return;
698 	}
699 
700 	/*
701 	 * Mark these options as ones to skip when creating the Makefile.
702 	 */
703 	for (nv = opts; nv != NULL; nv = nextnv) {
704 		nextnv = nv->nv_next;
705 
706 		/* An option name can be declared at most once. */
707 		if (DEFINED_OPTION(nv->nv_name)) {
708 			error("file system or option `%s' already defined",
709 			    nv->nv_name);
710 			return;
711 		}
712 
713 		if (ht_insert(ht, nv->nv_name, nv)) {
714 			error("file system or option `%s' already defined",
715 			    nv->nv_name);
716 			return;
717 		}
718 
719 		if (fname == NULL) {
720 			/*
721 			 * Each option will be going into its own file.
722 			 * Convert the option name to lower case.  This
723 			 * lower case name will be used as the option
724 			 * file name.
725 			 */
726 			(void) snprintf(buf, sizeof(buf), "opt_%s.h",
727 			    strtolower(nv->nv_name));
728 			name = intern(buf);
729 		} else {
730 			name = fname;
731 		}
732 
733 		add_dependencies(nv, deps);
734 
735 		/*
736 		 * Remove this option from the parameter list before adding
737 		 * it to the list associated with this option file.
738 		 */
739 		nv->nv_next = NULL;
740 
741 		/*
742 		 * Flag as obsolete, if requested.
743 		 */
744 		if (obs) {
745 			nv->nv_flags |= NV_OBSOLETE;
746 			(void)ht_insert(obsopttab, nv->nv_name, nv);
747 		}
748 
749 		/*
750 		 * Add this option file if we haven't seen it yet.
751 		 * Otherwise, append to the list of options already
752 		 * associated with this file.
753 		 */
754 		if ((oldnv = ht_lookup(optfiletab, name)) == NULL) {
755 			(void)ht_insert(optfiletab, name, nv);
756 		} else {
757 			while (oldnv->nv_next != NULL)
758 				oldnv = oldnv->nv_next;
759 			oldnv->nv_next = nv;
760 		}
761 	}
762 }
763 
764 /*
765  * Define one or more standard options.  If an option file name is specified,
766  * place all options in one file with the specified name.  Otherwise, create
767  * an option file for each option.
768  */
769 void
770 defoption(const char *fname, struct nvlist *opts, struct nvlist *deps)
771 {
772 
773 	warn("The use of `defopt' is deprecated");
774 	defopt(defopttab, fname, opts, deps, 0);
775 }
776 
777 
778 /*
779  * Define an option for which a value is required.
780  */
781 void
782 defparam(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs)
783 {
784 
785 	defopt(defparamtab, fname, opts, deps, obs);
786 }
787 
788 /*
789  * Define an option which must not have a value, and which
790  * emits a "needs-flag" style output.
791  */
792 void
793 defflag(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs)
794 {
795 
796 	defopt(defflagtab, fname, opts, deps, obs);
797 }
798 
799 
800 /*
801  * Add an option from "options FOO".  Note that this selects things that
802  * are "optional foo".
803  */
804 void
805 addoption(const char *name, const char *value)
806 {
807 	const char *n;
808 	int is_fs, is_param, is_flag, is_opt, is_undecl, is_obs;
809 
810 	/*
811 	 * Figure out how this option was declared (if at all.)
812 	 * XXX should use "params" and "flags" in config.
813 	 * XXX crying out for a type field in a unified hashtab.
814 	 */
815 	is_fs = OPT_FSOPT(name);
816 	is_param = OPT_DEFPARAM(name);
817 	is_opt = OPT_DEFOPT(name);
818 	is_flag =  OPT_DEFFLAG(name);
819 	is_obs = OPT_OBSOLETE(name);
820 	is_undecl = !DEFINED_OPTION(name);
821 
822 	/* Warn and pretend the user had not selected the option  */
823 	if (is_obs) {
824 		warn("obsolete option `%s' will be ignored", name);
825 		return;
826 	}
827 
828 	/* Make sure this is not a defined file system. */
829 	if (is_fs) {
830 		error("`%s' is a defined file system", name);
831 		return;
832 	}
833 	/* A defparam must have a value */
834 	if (is_param && value == NULL) {
835 		error("option `%s' must have a value", name);
836 		return;
837 	}
838 	/* A defflag must not have a value */
839 	if (is_flag && value != NULL) {
840 		error("option `%s' must not have a value", name);
841 		return;
842 	}
843 
844 	if (is_undecl && vflag) {
845 		warn("undeclared option `%s' added to IDENT", name);
846 	}
847 
848 	if (do_option(opttab, &nextopt, name, value, "options"))
849 		return;
850 
851 	/* make lowercase, then add to select table */
852 	n = strtolower(name);
853 	(void)ht_insert(selecttab, n, (void *)n);
854 }
855 
856 void
857 deloption(const char *name)
858 {
859 
860 	if (undo_option(opttab, &options, &nextopt, name, "options"))
861 		return;
862 	if (undo_option(selecttab, NULL, NULL, strtolower(name), "options"))
863 		return;
864 }
865 
866 /*
867  * Add a file system option.  This routine simply inserts the name into
868  * a list of valid file systems, which is used to validate the root
869  * file system type.  The name is then treated like a standard option.
870  */
871 void
872 addfsoption(const char *name)
873 {
874 	const char *n;
875 
876 	/* Make sure this is a defined file system. */
877 	if (!OPT_FSOPT(name)) {
878 		error("`%s' is not a defined file system", name);
879 		return;
880 	}
881 
882 	/*
883 	 * Convert to lower case.  This will be used in the select
884 	 * table, to verify root file systems, and when the initial
885 	 * VFS list is created.
886 	 */
887 	n = strtolower(name);
888 
889 	if (do_option(fsopttab, &nextfsopt, name, n, "file-system"))
890 		return;
891 
892 	/*
893 	 * Add a lower-case version to the table for root file system
894 	 * verification.
895 	 */
896 	if (ht_insert(fsopttab, n, (void *)n))
897 		panic("addfsoption: already in table");
898 
899 	/* Add to select table. */
900 	(void)ht_insert(selecttab, n, (void *)n);
901 }
902 
903 void
904 delfsoption(const char *name)
905 {
906 	const char *n;
907 
908 	n = strtolower(name);
909 	if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system"))
910 		return;
911 	if (undo_option(fsopttab, NULL, NULL, n, "file-system"))
912 		return;
913 	if (undo_option(selecttab, NULL, NULL, n, "file-system"))
914 		return;
915 }
916 
917 /*
918  * Add a "make" option.
919  */
920 void
921 addmkoption(const char *name, const char *value)
922 {
923 
924 	(void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions");
925 }
926 
927 void
928 delmkoption(const char *name)
929 {
930 
931 	(void)undo_option(mkopttab, &mkoptions, &nextmkopt, name,
932 	    "makeoptions");
933 }
934 
935 /*
936  * Add an appending "make" option.
937  */
938 void
939 appendmkoption(const char *name, const char *value)
940 {
941 	struct nvlist *nv;
942 
943 	nv = newnv(name, value, NULL, 0, NULL);
944 	*nextappmkopt = nv;
945 	nextappmkopt = &nv->nv_next;
946 }
947 
948 /*
949  * Add a conditional appending "make" option.
950  */
951 void
952 appendcondmkoption(const char *selname, const char *name, const char *value)
953 {
954 	struct nvlist *nv, *lnv;
955 	const char *n;
956 
957 	n = strtolower(selname);
958 	nv = newnv(name, value, NULL, 0, NULL);
959 	if (ht_insert(condmkopttab, n, nv) == 0)
960 		return;
961 
962 	if ((lnv = ht_lookup(condmkopttab, n)) == NULL)
963 		panic("appendcondmkoption");
964 	for (; lnv->nv_next != NULL; lnv = lnv->nv_next)
965 		/* search for the last list element */;
966 	lnv->nv_next = nv;
967 }
968 
969 /*
970  * Add a name=value pair to an option list.  The value may be NULL.
971  */
972 static int
973 do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name,
974 	  const char *value, const char *type)
975 {
976 	struct nvlist *nv;
977 
978 	/*
979 	 * If a defopt'ed or defflag'ed option was enabled but without
980 	 * an explicit value (always the case for defflag), supply a
981 	 * default value of 1, as for non-defopt options (where cc
982 	 * treats -DBAR as -DBAR=1.)
983 	 */
984 	if ((OPT_DEFOPT(name) || OPT_DEFFLAG(name)) && value == NULL)
985 		value = "1";
986 
987 	/* assume it will work */
988 	nv = newnv(name, value, NULL, 0, NULL);
989 	if (ht_insert(ht, name, nv) == 0) {
990 		**nppp = nv;
991 		*nppp = &nv->nv_next;
992 		return (0);
993 	}
994 
995 	/* oops, already got that option */
996 	nvfree(nv);
997 	if ((nv = ht_lookup(ht, name)) == NULL)
998 		panic("do_option");
999 	if (nv->nv_str != NULL && !OPT_FSOPT(name))
1000 		error("already have %s `%s=%s'", type, name, nv->nv_str);
1001 	else
1002 		error("already have %s `%s'", type, name);
1003 	return (1);
1004 }
1005 
1006 /*
1007  * Remove a name from a hash table,
1008  * and optionally, a name=value pair from an option list.
1009  */
1010 static int
1011 undo_option(struct hashtab *ht, struct nvlist **npp,
1012     struct nvlist ***next, const char *name, const char *type)
1013 {
1014 	struct nvlist *nv;
1015 
1016 	if (ht_remove(ht, name)) {
1017 		error("%s `%s' is not defined", type, name);
1018 		return (1);
1019 	}
1020 	if (npp == NULL)
1021 		return (0);
1022 
1023 	for ( ; *npp != NULL; npp = &(*npp)->nv_next) {
1024 		if ((*npp)->nv_name != name)
1025 			continue;
1026 		if (next != NULL && *next == &(*npp)->nv_next)
1027 			*next = npp;
1028 		nv = (*npp)->nv_next;
1029 		nvfree(*npp);
1030 		*npp = nv;
1031 		return (0);
1032 	}
1033 	panic("%s `%s' is not defined in nvlist", type, name);
1034 	return (1);
1035 }
1036 
1037 /*
1038  * Return true if there is at least one instance of the given unit
1039  * on the given device attachment (or any units, if unit == WILD).
1040  */
1041 int
1042 deva_has_instances(struct deva *deva, int unit)
1043 {
1044 	struct devi *i;
1045 
1046 	for (i = deva->d_ihead; i != NULL; i = i->i_asame)
1047 		if (i->i_active == DEVI_ACTIVE &&
1048 		    (unit == WILD || unit == i->i_unit || i->i_unit == STAR))
1049 			return (1);
1050 	return (0);
1051 }
1052 
1053 /*
1054  * Return true if there is at least one instance of the given unit
1055  * on the given base (or any units, if unit == WILD).
1056  */
1057 int
1058 devbase_has_instances(struct devbase *dev, int unit)
1059 {
1060 	struct deva *da;
1061 
1062 	/*
1063 	 * Pseudo-devices are a little special.  We consider them
1064 	 * to have instances only if they are both:
1065 	 *
1066 	 *	1. Included in this kernel configuration.
1067 	 *
1068 	 *	2. Have one or more interface attributes.
1069 	 */
1070 	if (dev->d_ispseudo) {
1071 		struct nvlist *nv;
1072 		struct attr *a;
1073 
1074 		if (ht_lookup(devitab, dev->d_name) == NULL)
1075 			return (0);
1076 
1077 		for (nv = dev->d_attrs; nv != NULL; nv = nv->nv_next) {
1078 			a = nv->nv_ptr;
1079 			if (a->a_iattr)
1080 				return (1);
1081 		}
1082 		return (0);
1083 	}
1084 
1085 	for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
1086 		if (deva_has_instances(da, unit))
1087 			return (1);
1088 	return (0);
1089 }
1090 
1091 static int
1092 cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv)
1093 {
1094 	struct devbase *dev;
1095 	struct devi *pd;
1096 	int errs, devunit;
1097 
1098 	if (maxpartitions <= 0)
1099 		panic("cfcrosscheck");
1100 
1101 	for (errs = 0; nv != NULL; nv = nv->nv_next) {
1102 		if (nv->nv_name == NULL)
1103 			continue;
1104 		dev = ht_lookup(devbasetab, nv->nv_name);
1105 		if (dev == NULL)
1106 			panic("cfcrosscheck(%s)", nv->nv_name);
1107 		if (has_attr(dev->d_attrs, s_ifnet))
1108 			devunit = nv->nv_ifunit;	/* XXX XXX XXX */
1109 		else
1110 			devunit = minor(nv->nv_int) / maxpartitions;
1111 		if (devbase_has_instances(dev, devunit))
1112 			continue;
1113 		if (devbase_has_instances(dev, STAR) &&
1114 		    devunit >= dev->d_umax)
1115 			continue;
1116 		TAILQ_FOREACH(pd, &allpseudo, i_next) {
1117 			if (pd->i_base == dev && devunit < dev->d_umax &&
1118 			    devunit >= 0)
1119 				goto loop;
1120 		}
1121 		(void)fprintf(stderr,
1122 		    "%s:%d: %s says %s on %s, but there's no %s\n",
1123 		    conffile, cf->cf_lineno,
1124 		    cf->cf_name, what, nv->nv_str, nv->nv_str);
1125 		errs++;
1126  loop:
1127 		;
1128 	}
1129 	return (errs);
1130 }
1131 
1132 /*
1133  * Cross-check the configuration: make sure that each target device
1134  * or attribute (`at foo[0*?]') names at least one real device.  Also
1135  * see that the root and dump devices for all configurations are there.
1136  */
1137 int
1138 crosscheck(void)
1139 {
1140 	struct config *cf;
1141 	int errs;
1142 
1143 	errs = 0;
1144 	if (TAILQ_EMPTY(&allcf)) {
1145 		(void)fprintf(stderr, "%s has no configurations!\n",
1146 		    conffile);
1147 		errs++;
1148 	}
1149 	TAILQ_FOREACH(cf, &allcf, cf_next) {
1150 		if (cf->cf_root != NULL) {	/* i.e., not root on ? */
1151 			errs += cfcrosscheck(cf, "root", cf->cf_root);
1152 			errs += cfcrosscheck(cf, "dumps", cf->cf_dump);
1153 		}
1154 	}
1155 	return (errs);
1156 }
1157 
1158 /*
1159  * Check to see if there is a *'d unit with a needs-count file.
1160  */
1161 int
1162 badstar(void)
1163 {
1164 	struct devbase *d;
1165 	struct deva *da;
1166 	struct devi *i;
1167 	int errs, n;
1168 
1169 	errs = 0;
1170 	TAILQ_FOREACH(d, &allbases, d_next) {
1171 		for (da = d->d_ahead; da != NULL; da = da->d_bsame)
1172 			for (i = da->d_ihead; i != NULL; i = i->i_asame) {
1173 				if (i->i_unit == STAR)
1174 					goto aybabtu;
1175 			}
1176 		continue;
1177  aybabtu:
1178 		if (ht_lookup(needcnttab, d->d_name)) {
1179 			(void)fprintf(stderr,
1180 		    "config: %s's cannot be *'d until its driver is fixed\n",
1181 			    d->d_name);
1182 			errs++;
1183 			continue;
1184 		}
1185 		for (n = 0; i != NULL; i = i->i_alias)
1186 			if (!i->i_collapsed)
1187 				n++;
1188 		if (n < 1)
1189 			panic("badstar() n<1");
1190 	}
1191 	return (errs);
1192 }
1193 
1194 /*
1195  * Verify/create builddir if necessary, change to it, and verify srcdir.
1196  * This will be called when we see the first include.
1197  */
1198 void
1199 setupdirs(void)
1200 {
1201 	struct stat st;
1202 
1203 	/* srcdir must be specified if builddir is not specified or if
1204 	 * no configuration filename was specified. */
1205 	if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) {
1206 		error("source directory must be specified");
1207 		exit(1);
1208 	}
1209 
1210 	if (srcdir == NULL)
1211 		srcdir = "../../../..";
1212 	if (builddir == NULL)
1213 		builddir = defbuilddir;
1214 
1215 	if (stat(builddir, &st) != 0) {
1216 		if (mkdir(builddir, 0777)) {
1217 			(void)fprintf(stderr, "config: cannot create %s: %s\n",
1218 			    builddir, strerror(errno));
1219 			exit(2);
1220 		}
1221 	} else if (!S_ISDIR(st.st_mode)) {
1222 		(void)fprintf(stderr, "config: %s is not a directory\n",
1223 			      builddir);
1224 		exit(2);
1225 	}
1226 	if (chdir(builddir) != 0) {
1227 		(void)fprintf(stderr, "config: cannot change to %s\n",
1228 			      builddir);
1229 		exit(2);
1230 	}
1231 	if (stat(srcdir, &st) != 0 || !S_ISDIR(st.st_mode)) {
1232 		(void)fprintf(stderr, "config: %s is not a directory\n",
1233 			      srcdir);
1234 		exit(2);
1235 	}
1236 }
1237 
1238 /*
1239  * Write identifier from "ident" directive into file, for
1240  * newvers.sh to pick it up.
1241  */
1242 int
1243 mkident(void)
1244 {
1245 	FILE *fp;
1246 	int error = 0;
1247 
1248 	(void)unlink("ident");
1249 
1250 	if (ident == NULL)
1251 		return (0);
1252 
1253 	if ((fp = fopen("ident", "w")) == NULL) {
1254 		(void)fprintf(stderr, "config: cannot write ident: %s\n",
1255 		    strerror(errno));
1256 		return (1);
1257 	}
1258 	if (vflag)
1259 		(void)printf("using ident '%s'\n", ident);
1260 	fprintf(fp, "%s\n", ident);
1261 	fflush(fp);
1262 	if (ferror(fp))
1263 		error = 1;
1264 	(void)fclose(fp);
1265 
1266 	return error;
1267 }
1268 
1269 void
1270 logconfig_start(void)
1271 {
1272 	extern FILE *yyin;
1273 	char line[1024];
1274 	const char *tmpdir;
1275 	struct stat st;
1276 	int fd;
1277 
1278 	if (yyin == NULL || fstat(fileno(yyin), &st) == -1)
1279 		return;
1280 	cfgtime = st.st_mtime;
1281 
1282 	tmpdir = getenv("TMPDIR");
1283 	if (tmpdir == NULL)
1284 		tmpdir = "/tmp";
1285 	snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir);
1286 	if ((fd = mkstemp(line)) == -1 ||
1287 	    (cfg = fdopen(fd, "r+")) == NULL) {
1288 		if (fd != -1) {
1289 			unlink(line);
1290 			close(fd);
1291 		}
1292 		cfg = NULL;
1293 		return;
1294 	}
1295 	unlink(line);
1296 
1297 	(void)fprintf(cfg, "#include <sys/cdefs.h>\n\n");
1298 	(void)fprintf(cfg, "#include \"opt_config.h\"\n");
1299 	(void)fprintf(cfg, "\n");
1300 	(void)fprintf(cfg, "/*\n");
1301 	(void)fprintf(cfg, " * Add either (or both) of\n");
1302 	(void)fprintf(cfg, " *\n");
1303 	(void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE);
1304 	(void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL);
1305 	(void)fprintf(cfg, " *\n");
1306 	(void)fprintf(cfg,
1307 	    " * to your kernel config file to embed it in the resulting\n");
1308 	(void)fprintf(cfg,
1309 	    " * kernel.  The latter option does not include files that are\n");
1310 	(void)fprintf(cfg,
1311 	    " * included (recursively) by your config file.  The embedded\n");
1312 	(void)fprintf(cfg,
1313 	    " * data be extracted by using the command:\n");
1314 	(void)fprintf(cfg, " *\n");
1315 	(void)fprintf(cfg,
1316 	    " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n");
1317 	(void)fprintf(cfg, " */\n");
1318 	(void)fprintf(cfg, "\n");
1319 	(void)fprintf(cfg, "#ifdef CONFIG_FILE\n");
1320 	(void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n",
1321 	    LOGCONFIG_LARGE, LOGCONFIG_SMALL);
1322 	(void)fprintf(cfg, "static const char config[] __used =\n\n");
1323 
1324 	(void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE);
1325 	(void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n",
1326 	    conffile);
1327 	(void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE);
1328 
1329 	logconfig_include(yyin, NULL);
1330 
1331 	(void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE);
1332 	(void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n",
1333 	    conffile);
1334 
1335 	rewind(yyin);
1336 }
1337 
1338 void
1339 logconfig_include(FILE *cf, const char *filename)
1340 {
1341 	char line[1024], in[2048], *out;
1342 	struct stat st;
1343 	int missingeol;
1344 
1345 	if (!cfg)
1346 		return;
1347 
1348 	missingeol = 0;
1349 	if (fstat(fileno(cf), &st) == -1)
1350 		return;
1351 	if (cfgtime < st.st_mtime)
1352 		cfgtime = st.st_mtime;
1353 
1354 	if (filename)
1355 		(void)fprintf(cfg,
1356 		    "\"_CFG_### (included from \\\"%s\\\")\\n\"\n",
1357 		    filename);
1358 	while (fgets(line, sizeof(line), cf) != NULL) {
1359 		missingeol = 1;
1360 		(void)fprintf(cfg, "\"_CFG_");
1361 		if (filename)
1362 			(void)fprintf(cfg, "###> ");
1363 		strvis(in, line, VIS_TAB);
1364 		for (out = in; *out; out++)
1365 			switch (*out) {
1366 			case '\n':
1367 				(void)fprintf(cfg, "\\n\"\n");
1368 				missingeol = 0;
1369 				break;
1370 			case '"': case '\\':
1371 				(void)fputc('\\', cfg);
1372 				/* FALLTHROUGH */
1373 			default:
1374 				(void)fputc(*out, cfg);
1375 				break;
1376 			}
1377 	}
1378 	if (missingeol) {
1379 		(void)fprintf(cfg, "\\n\"\n");
1380 		(void)fprintf(stderr,
1381 		    "config: %s: newline missing at EOF\n",
1382 		    filename != NULL ? filename : conffile);
1383 	}
1384 	if (filename)
1385 		(void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n",
1386 		    filename);
1387 
1388 	rewind(cf);
1389 }
1390 
1391 void
1392 logconfig_end(void)
1393 {
1394 	char line[1024];
1395 	FILE *fp;
1396 	struct stat st;
1397 
1398 	if (!cfg)
1399 		return;
1400 
1401 	(void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE);
1402 	(void)fprintf(cfg, ";\n");
1403 	(void)fprintf(cfg, "#endif /* %s || %s */\n",
1404 	    LOGCONFIG_LARGE, LOGCONFIG_SMALL);
1405 	(void)fprintf(cfg, "#endif /* CONFIG_FILE */\n");
1406 	fflush(cfg);
1407 	if (ferror(cfg))
1408 		err(EXIT_FAILURE, "write to temporary file for config.h failed");
1409 	rewind(cfg);
1410 
1411 	if (stat("config_file.h", &st) != -1) {
1412 		if (cfgtime < st.st_mtime) {
1413 			fclose(cfg);
1414 			return;
1415 		}
1416 	}
1417 
1418 	fp = fopen("config_file.h", "w");
1419 	if (!fp)
1420 		err(EXIT_FAILURE, "cannot open \"config.h\"");
1421 
1422 	while (fgets(line, sizeof(line), cfg) != NULL)
1423 		fputs(line, fp);
1424 	fflush(fp);
1425 	if (ferror(fp))
1426 		err(EXIT_FAILURE, "write to \"config.h\" failed");
1427 	fclose(fp);
1428 	fclose(cfg);
1429 }
1430 
1431 static const char *
1432 strtolower(const char *name)
1433 {
1434 	const char *n;
1435 	char *p, low[500];
1436 	unsigned char c;
1437 
1438 	for (n = name, p = low; (c = *n) != '\0'; n++)
1439 		*p++ = isupper(c) ? tolower(c) : c;
1440 	*p = 0;
1441 	return (intern(low));
1442 }
1443 
1444 static int
1445 is_elf(const char *file)
1446 {
1447 	int kernel;
1448 	char hdr[4];
1449 
1450 	kernel = open(file, O_RDONLY);
1451 	if (kernel == -1) {
1452 		fprintf(stderr, "config: cannot open %s: %s\n", file,
1453 		    strerror(errno));
1454 		exit(2);
1455 	}
1456 	if (read(kernel, hdr, 4) == -1) {
1457 		fprintf(stderr, "config: cannot read from %s: %s\n", file,
1458 		    strerror(errno));
1459 		exit(2);
1460 	}
1461 	close(kernel);
1462 
1463 	return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0;
1464 }
1465 
1466 static int
1467 extract_config(const char *kname, const char *cname, int cfd)
1468 {
1469 	char *ptr;
1470 	int found, kfd, i;
1471 	struct stat st;
1472 
1473 	found = 0;
1474 
1475 	/* mmap(2) binary kernel */
1476 	kfd = open(conffile, O_RDONLY);
1477 	if (kfd == -1) {
1478 		fprintf(stderr, "config: cannot open %s: %s\n", kname,
1479 		    strerror(errno));
1480 		exit(2);
1481 	}
1482 	if ((fstat(kfd, &st) == -1)) {
1483 		fprintf(stderr, "config: cannot stat %s: %s\n", kname,
1484 		    strerror(errno));
1485 		exit(2);
1486 	}
1487 	ptr = (char *)mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
1488 	    kfd, 0);
1489 	if (ptr == MAP_FAILED) {
1490 		fprintf(stderr, "config: cannot mmap %s: %s\n", kname,
1491 		    strerror(errno));
1492 		exit(2);
1493 	}
1494 
1495 	/* Scan mmap(2)'ed region, extracting kernel configuration */
1496 	for (i = 0; i < st.st_size; i++) {
1497 		if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr,
1498 		    "_CFG_", 5) == 0) {
1499 			/* Line found */
1500 			char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1];
1501 			int j;
1502 
1503 			found = 1;
1504 
1505 			oldptr = (ptr += 5);
1506 			while (*ptr != '\n' && *ptr != '\0') ptr++;
1507 			if (ptr - oldptr > LINE_MAX) {
1508 				fprintf(stderr, "config: line too long\n");
1509 				exit(2);
1510 			}
1511 			i += ptr - oldptr + 5;
1512 			memcpy(line, oldptr, (ptr - oldptr));
1513 			line[ptr - oldptr] = '\0';
1514 			j = strunvis(uline, line);
1515 			if (j == -1) {
1516 				fprintf(stderr, "config: unvis: invalid "
1517 				    "encoded sequence\n");
1518 				exit(2);
1519 			}
1520 			uline[j] = '\n';
1521 			if (write(cfd, uline, j + 1) == -1) {
1522 				fprintf(stderr, "config: cannot write to %s: "
1523 				    "%s\n", cname, strerror(errno));
1524 				exit(2);
1525 			}
1526 		} else ptr++;
1527 	}
1528 
1529 	close(kfd);
1530 
1531 	return found;
1532 }
1533 
1534 struct dhdi_params {
1535 	struct devbase *d;
1536 	int unit;
1537 	int level;
1538 };
1539 
1540 static int
1541 devbase_has_dead_instances(const char *key, void *value, void *aux)
1542 {
1543 	struct devi *i;
1544 	struct dhdi_params *dhdi = aux;
1545 
1546 	for (i = value; i != NULL; i = i->i_alias)
1547 		if (i->i_base == dhdi->d &&
1548 		    (dhdi->unit == WILD || dhdi->unit == i->i_unit ||
1549 		     i->i_unit == STAR) &&
1550 		    i->i_level >= dhdi->level)
1551 			return 1;
1552 	return 0;
1553 }
1554 
1555 /*
1556  * This is almost the same as devbase_has_instances, except it
1557  * may have special considerations regarding ignored instances.
1558  */
1559 
1560 static int
1561 devbase_has_any_instance(struct devbase *dev, int unit, int state, int level)
1562 {
1563 	struct deva *da;
1564 	struct devi *i;
1565 
1566 	if (dev->d_ispseudo) {
1567 		if (dev->d_ihead != NULL)
1568 			return 1;
1569 		else if (state != DEVI_IGNORED)
1570 			return 0;
1571 		if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL)
1572 			return 0;
1573 		return (i->i_level >= level);
1574 	}
1575 
1576 	for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
1577 		for (i = da->d_ihead; i != NULL; i = i->i_asame)
1578 			if ((i->i_active == DEVI_ACTIVE ||
1579 			     i->i_active == state) &&
1580 			    (unit == WILD || unit == i->i_unit ||
1581 			     i->i_unit == STAR))
1582 				return 1;
1583 
1584 	if (state == DEVI_IGNORED) {
1585 		struct dhdi_params dhdi = { dev, unit, level };
1586 		/* also check dead devices */
1587 		return ht_enumerate(deaddevitab, devbase_has_dead_instances,
1588 		    &dhdi);
1589 	}
1590 
1591 	return 0;
1592 }
1593 
1594 /*
1595  * check_dead_devi(), used with ht_enumerate, checks if any of the removed
1596  * device instances would have been a valid instance considering the devbase,
1597  * the parent device and the interface attribute.
1598  *
1599  * In other words, for a non-active device, it checks if children would be
1600  * actual orphans or the result of a negative statement in the config file.
1601  */
1602 
1603 struct cdd_params {
1604 	struct devbase *d;
1605 	struct attr *at;
1606 	struct devbase *parent;
1607 };
1608 
1609 static int
1610 check_dead_devi(const char *key, void *value, void *aux)
1611 {
1612 	struct cdd_params *cdd = aux;
1613 	struct devi *i = value;
1614 	struct pspec *p;
1615 
1616 	if (i->i_base != cdd->d)
1617 		return 0;
1618 
1619 	for (; i != NULL; i = i->i_alias) {
1620 		p = i->i_pspec;
1621 		if ((p == NULL && cdd->at == NULL) ||
1622 		    (p != NULL && p->p_iattr == cdd->at &&
1623 		     (p->p_atdev == NULL || p->p_atdev == cdd->parent))) {
1624 			if (p != NULL &&
1625 			    !devbase_has_any_instance(cdd->parent, p->p_atunit,
1626 			    DEVI_IGNORED, i->i_level))
1627 				return 0;
1628 			else
1629 				return 1;
1630 		}
1631 	}
1632 	return 0;
1633 }
1634 
1635 static void
1636 do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent,
1637     int state)
1638 {
1639 	struct nvlist *nv, *nv1;
1640 	struct attr *a;
1641 	struct devi *i, *j = NULL;
1642 	struct pspec *p;
1643 	int active = 0;
1644 
1645 	/*
1646 	 * A pseudo-device will always attach at root, and if it has an
1647 	 * instance (it cannot have more than one), it is enough to consider
1648 	 * it active, as there is no real attachment.
1649 	 *
1650 	 * A pseudo device can never be marked DEVI_IGNORED.
1651 	 */
1652 	if (d->d_ispseudo) {
1653 		if (d->d_ihead != NULL)
1654 			d->d_ihead->i_active = active = DEVI_ACTIVE;
1655 		else {
1656 			if (ht_lookup(deaddevitab, d->d_name) != NULL)
1657 				active = DEVI_IGNORED;
1658 			else
1659 				return;
1660 		}
1661 	} else {
1662 		int seen = 0;
1663 
1664 		for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
1665 			for (j = i; j != NULL; j = j->i_alias) {
1666 				p = j->i_pspec;
1667 				if ((p == NULL && at == NULL) ||
1668 				    (p != NULL && p->p_iattr == at &&
1669 				    (p->p_atdev == NULL ||
1670 				    p->p_atdev == parent))) {
1671 					if (p != NULL &&
1672 					    !devbase_has_any_instance(parent,
1673 					      p->p_atunit, state, j->i_level))
1674 						continue;
1675 					/*
1676 					 * There are Fry-like devices which can
1677 					 * be their own grand-parent (or even
1678 					 * parent, like uhub).  We don't want
1679 					 * to loop, so if we've already reached
1680 					 * an instance for one reason or
1681 					 * another, stop there.
1682 					 */
1683 					if (j->i_active == DEVI_ACTIVE ||
1684 					    j->i_active == state) {
1685 						/*
1686 						 * Device has already been
1687 						 * seen.  However it might
1688 						 * have siblings who still
1689 						 * have to be activated or
1690 						 * orphaned.
1691 						 */
1692 						seen = 1;
1693 						continue;
1694 					}
1695 					j->i_active = active = state;
1696 					if (p != NULL)
1697 						p->p_active = state;
1698 				}
1699 			}
1700 		}
1701 		/*
1702 		 * If we've been there but have made no change, stop.
1703 		 */
1704 		if (seen && !active)
1705 			return;
1706 		if (!active) {
1707 			struct cdd_params cdd = { d, at, parent };
1708 			/* Look for a matching dead devi */
1709 			if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) &&
1710 			    d != parent)
1711 				/*
1712 				 * That device had its instances removed.
1713 				 * Continue the loop marking descendants
1714 				 * with DEVI_IGNORED instead of DEVI_ACTIVE.
1715 				 *
1716 				 * There is one special case for devices that
1717 				 * are their own parent:  if that instance is
1718 				 * removed (e.g., no uhub* at uhub?), we don't
1719 				 * have to continue looping.
1720 				 */
1721 				active = DEVI_IGNORED;
1722 			else
1723 				return;
1724 		}
1725 	}
1726 
1727 	for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
1728 		a = nv->nv_ptr;
1729 		for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next)
1730 			do_kill_orphans(nv1->nv_ptr, a, d, active);
1731 	}
1732 }
1733 
1734 static int
1735 kill_orphans_cb(const char *key, void *value, void *aux)
1736 {
1737 	do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE);
1738 	return 0;
1739 }
1740 
1741 static void
1742 kill_orphans()
1743 {
1744 	ht_enumerate(devroottab, kill_orphans_cb, NULL);
1745 }
1746