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