xref: /csrg-svn/usr.sbin/config.new/main.c (revision 57490)
1*57490Storek /*
2*57490Storek  * Copyright (c) 1992 The Regents of the University of California.
3*57490Storek  * All rights reserved.
4*57490Storek  *
5*57490Storek  * This software was developed by the Computer Systems Engineering group
6*57490Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7*57490Storek  * contributed to Berkeley.
8*57490Storek  *
9*57490Storek  * All advertising materials mentioning features or use of this software
10*57490Storek  * must display the following acknowledgement:
11*57490Storek  *	This product includes software developed by the University of
12*57490Storek  *	California, Lawrence Berkeley Laboratories.
13*57490Storek  *
14*57490Storek  * %sccs.include.redist.c%
15*57490Storek  *
16*57490Storek  *	@(#)main.c	5.1 (Berkeley) 01/12/93
17*57490Storek  *
18*57490Storek  * from: $Header: main.c,v 1.6 93/01/12 10:18:26 torek Exp $
19*57490Storek  */
20*57490Storek 
21*57490Storek #ifndef lint
22*57490Storek char copyright[] =
23*57490Storek "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
24*57490Storek  All rights reserved.\n";
25*57490Storek #endif /* not lint */
26*57490Storek 
27*57490Storek #include <sys/types.h>
28*57490Storek #include <sys/stat.h>
29*57490Storek #include <ctype.h>
30*57490Storek #include <errno.h>
31*57490Storek #include <stdio.h>
32*57490Storek #include <stdlib.h>
33*57490Storek #include <string.h>
34*57490Storek #include <unistd.h>
35*57490Storek #include "config.h"
36*57490Storek 
37*57490Storek int	firstfile __P((const char *));
38*57490Storek int	yyparse __P((void));
39*57490Storek 
40*57490Storek extern char *optarg;
41*57490Storek extern int optind;
42*57490Storek 
43*57490Storek static struct hashtab *opttab;
44*57490Storek static struct hashtab *mkopttab;
45*57490Storek static struct nvlist **nextopt;
46*57490Storek static struct nvlist **nextmkopt;
47*57490Storek 
48*57490Storek static __dead void stop __P((void));
49*57490Storek static int do_option __P((struct hashtab *, struct nvlist ***,
50*57490Storek 			const char *, const char *, const char *));
51*57490Storek static int crosscheck __P((void));
52*57490Storek static int badstar __P((void));
53*57490Storek static int mksymlinks __P((void));
54*57490Storek static int has_instances __P((struct devbase *, int));
55*57490Storek static int hasparent __P((struct devi *));
56*57490Storek static int cfcrosscheck __P((struct config *, const char *, struct nvlist *));
57*57490Storek 
58*57490Storek int
59*57490Storek main(argc, argv)
60*57490Storek 	int argc;
61*57490Storek 	char **argv;
62*57490Storek {
63*57490Storek 	register char *p;
64*57490Storek 	int pflag, ch;
65*57490Storek 	struct stat st;
66*57490Storek 
67*57490Storek 	pflag = 0;
68*57490Storek 	while ((ch = getopt(argc, argv, "gp")) != EOF) {
69*57490Storek 		switch (ch) {
70*57490Storek 
71*57490Storek 		case 'g':
72*57490Storek 			/*
73*57490Storek 			 * In addition to DEBUG, you probably wanted to
74*57490Storek 			 * set "options KGDB" and maybe others.  We could
75*57490Storek 			 * do that for you, but you really should just
76*57490Storek 			 * put them in the config file.
77*57490Storek 			 */
78*57490Storek 			(void)fputs(
79*57490Storek 			    "-g is obsolete (use makeoptions DEBUG=\"-g\")\n",
80*57490Storek 			    stderr);
81*57490Storek 			goto usage;
82*57490Storek 
83*57490Storek 		case 'p':
84*57490Storek 			/*
85*57490Storek 			 * Essentially the same as makeoptions PROF="-pg",
86*57490Storek 			 * but also changes the path from ../../compile/FOO
87*57490Storek 			 * to ../../compile/FOO.prof; i.e., compile a
88*57490Storek 			 * profiling kernel based on a typical "regular"
89*57490Storek 			 * kernel.
90*57490Storek 			 *
91*57490Storek 			 * Note that if you always want profiling, you
92*57490Storek 			 * can (and should) use a "makeoptions" line.
93*57490Storek 			 */
94*57490Storek 			pflag = 1;
95*57490Storek 			break;
96*57490Storek 
97*57490Storek 		case '?':
98*57490Storek 		default:
99*57490Storek 			goto usage;
100*57490Storek 		}
101*57490Storek 	}
102*57490Storek 
103*57490Storek 	argc -= optind;
104*57490Storek 	argv += optind;
105*57490Storek 	if (argc != 1) {
106*57490Storek usage:
107*57490Storek 		(void)fputs("usage: config [-p] sysname\n", stderr);
108*57490Storek 		exit(1);
109*57490Storek 	}
110*57490Storek 	conffile = argv[0];
111*57490Storek 	if (firstfile(conffile)) {
112*57490Storek 		(void)fprintf(stderr, "config: cannot read %s: %s\n",
113*57490Storek 		    conffile, strerror(errno));
114*57490Storek 		exit(2);
115*57490Storek 	}
116*57490Storek 
117*57490Storek 	/*
118*57490Storek 	 * Init variables.
119*57490Storek 	 */
120*57490Storek 	minmaxusers = 1;
121*57490Storek 	maxmaxusers = 10000;
122*57490Storek 	initintern();
123*57490Storek 	initfiles();
124*57490Storek 	initsem();
125*57490Storek 	devbasetab = ht_new();
126*57490Storek 	selecttab = ht_new();
127*57490Storek 	needcnttab = ht_new();
128*57490Storek 	opttab = ht_new();
129*57490Storek 	mkopttab = ht_new();
130*57490Storek 	nextopt = &options;
131*57490Storek 	nextmkopt = &mkoptions;
132*57490Storek 
133*57490Storek 	/*
134*57490Storek 	 * Handle profiling (must do this before we try to create any
135*57490Storek 	 * files).
136*57490Storek 	 */
137*57490Storek 	if (pflag) {
138*57490Storek 		char *s;
139*57490Storek 
140*57490Storek 		s = emalloc(strlen(conffile) + sizeof(".PROF"));
141*57490Storek 		(void)sprintf(s, "%s.PROF", conffile);
142*57490Storek 		confdirbase = s;
143*57490Storek 		(void)addmkoption(intern("PROF"), "-pg");
144*57490Storek 		(void)addoption(intern("GPROF"), NULL);
145*57490Storek 	} else
146*57490Storek 		confdirbase = conffile;
147*57490Storek 
148*57490Storek 	/*
149*57490Storek 	 * Verify, creating if necessary, the compilation directory.
150*57490Storek 	 */
151*57490Storek 	p = path(NULL);
152*57490Storek 	if (stat(p, &st)) {
153*57490Storek 		if (mkdir(p, 0777)) {
154*57490Storek 			(void)fprintf(stderr, "config: cannot create %s: %s\n",
155*57490Storek 			    p, strerror(errno));
156*57490Storek 			exit(2);
157*57490Storek 		}
158*57490Storek 	} else if (!S_ISDIR(st.st_mode)) {
159*57490Storek 		(void)fprintf(stderr, "config: %s is not a directory\n", p);
160*57490Storek 		exit(2);
161*57490Storek 	}
162*57490Storek 
163*57490Storek 	/*
164*57490Storek 	 * Parse config file (including machine definitions).
165*57490Storek 	 */
166*57490Storek 	if (yyparse())
167*57490Storek 		stop();
168*57490Storek 
169*57490Storek 	/*
170*57490Storek 	 * Fix (as in `set firmly in place') files.
171*57490Storek 	 */
172*57490Storek 	if (fixfiles())
173*57490Storek 		stop();
174*57490Storek 
175*57490Storek 	/*
176*57490Storek 	 * Perform cross-checking.
177*57490Storek 	 */
178*57490Storek 	if (maxusers == 0) {
179*57490Storek 		if (defmaxusers) {
180*57490Storek 			(void)printf("maxusers not specified; %d assumed\n",
181*57490Storek 			    defmaxusers);
182*57490Storek 			maxusers = defmaxusers;
183*57490Storek 		} else {
184*57490Storek 			(void)fprintf(stderr,
185*57490Storek 			    "config: need \"maxusers\" line\n");
186*57490Storek 			errors++;
187*57490Storek 		}
188*57490Storek 	}
189*57490Storek 	if (crosscheck() || errors)
190*57490Storek 		stop();
191*57490Storek 
192*57490Storek 	/*
193*57490Storek 	 * Squeeze things down and finish cross-checks (STAR checks must
194*57490Storek 	 * run after packing).
195*57490Storek 	 */
196*57490Storek 	pack();
197*57490Storek 	if (badstar())
198*57490Storek 		stop();
199*57490Storek 
200*57490Storek 	/*
201*57490Storek 	 * Ready to go.  Build all the various files.
202*57490Storek 	 */
203*57490Storek 	if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
204*57490Storek 	    mkioconf())
205*57490Storek 		stop();
206*57490Storek 	(void)printf("Don't forget to run \"make depend\"\n");
207*57490Storek 	exit(0);
208*57490Storek }
209*57490Storek 
210*57490Storek /*
211*57490Storek  * Make a symlink for "machine" so that "#include <machine/foo.h>" works.
212*57490Storek  */
213*57490Storek static int
214*57490Storek mksymlinks()
215*57490Storek {
216*57490Storek 	int ret;
217*57490Storek 	char *p, buf[200];
218*57490Storek 
219*57490Storek 	p = path("machine");
220*57490Storek 	(void)sprintf(buf, "../../%s/include", machine);
221*57490Storek 	(void)unlink(p);
222*57490Storek 	ret = symlink(buf, p);
223*57490Storek 	if (ret)
224*57490Storek 		(void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
225*57490Storek 		    p, buf, strerror(errno));
226*57490Storek 	free(p);
227*57490Storek 	return (ret);
228*57490Storek }
229*57490Storek 
230*57490Storek static __dead void
231*57490Storek stop()
232*57490Storek {
233*57490Storek 	(void)fprintf(stderr, "*** Stop.\n");
234*57490Storek 	exit(1);
235*57490Storek }
236*57490Storek 
237*57490Storek /*
238*57490Storek  * Add an option from "options FOO".  Note that this selects things that
239*57490Storek  * are "optional foo".
240*57490Storek  */
241*57490Storek void
242*57490Storek addoption(name, value)
243*57490Storek 	const char *name, *value;
244*57490Storek {
245*57490Storek 	register const char *n;
246*57490Storek 	register char *p, c;
247*57490Storek 	char low[500];
248*57490Storek 
249*57490Storek 	if (do_option(opttab, &nextopt, name, value, "options"))
250*57490Storek 		return;
251*57490Storek 
252*57490Storek 	/* make lowercase, then add to select table */
253*57490Storek 	for (n = name, p = low; (c = *n) != '\0'; n++)
254*57490Storek 		*p++ = isupper(c) ? tolower(c) : c;
255*57490Storek 	*p = 0;
256*57490Storek 	n = intern(low);
257*57490Storek 	(void)ht_insert(selecttab, n, (void *)n);
258*57490Storek }
259*57490Storek 
260*57490Storek /*
261*57490Storek  * Add a "make" option.
262*57490Storek  */
263*57490Storek void
264*57490Storek addmkoption(name, value)
265*57490Storek 	const char *name, *value;
266*57490Storek {
267*57490Storek 
268*57490Storek 	(void)do_option(mkopttab, &nextmkopt, name, value, "mkoptions");
269*57490Storek }
270*57490Storek 
271*57490Storek /*
272*57490Storek  * Add a name=value pair to an option list.  The value may be NULL.
273*57490Storek  */
274*57490Storek static int
275*57490Storek do_option(ht, nppp, name, value, type)
276*57490Storek 	struct hashtab *ht;
277*57490Storek 	struct nvlist ***nppp;
278*57490Storek 	const char *name, *value, *type;
279*57490Storek {
280*57490Storek 	register struct nvlist *nv;
281*57490Storek 
282*57490Storek 	/* assume it will work */
283*57490Storek 	nv = newnv(name, value, NULL, 0);
284*57490Storek 	if (ht_insert(ht, name, nv) == 0) {
285*57490Storek 		**nppp = nv;
286*57490Storek 		*nppp = &nv->nv_next;
287*57490Storek 		return (0);
288*57490Storek 	}
289*57490Storek 
290*57490Storek 	/* oops, already got that option */
291*57490Storek 	nvfree(nv);
292*57490Storek 	if ((nv = ht_lookup(ht, name)) == NULL)
293*57490Storek 		panic("do_option");
294*57490Storek 	if (nv->nv_str != NULL)
295*57490Storek 		error("already have %s `%s=%s'", type, name, nv->nv_str);
296*57490Storek 	else
297*57490Storek 		error("already have %s `%s'", type, name);
298*57490Storek 	return (1);
299*57490Storek }
300*57490Storek 
301*57490Storek /*
302*57490Storek  * Return true if there is at least one instance of the given unit
303*57490Storek  * on the given base (or any units, if unit == WILD).
304*57490Storek  */
305*57490Storek static int
306*57490Storek has_instances(dev, unit)
307*57490Storek 	register struct devbase *dev;
308*57490Storek 	int unit;
309*57490Storek {
310*57490Storek 	register struct devi *i;
311*57490Storek 
312*57490Storek 	if (unit == WILD)
313*57490Storek 		return (dev->d_ihead != NULL);
314*57490Storek 	for (i = dev->d_ihead; i != NULL; i = i->i_bsame)
315*57490Storek 		if (unit == i->i_unit)
316*57490Storek 			return (1);
317*57490Storek 	return (0);
318*57490Storek }
319*57490Storek 
320*57490Storek static int
321*57490Storek hasparent(i)
322*57490Storek 	register struct devi *i;
323*57490Storek {
324*57490Storek 	register struct nvlist *nv;
325*57490Storek 	int atunit = i->i_atunit;
326*57490Storek 
327*57490Storek 	if (i->i_atdev != NULL && has_instances(i->i_atdev, atunit))
328*57490Storek 		return (1);
329*57490Storek 	if (i->i_atattr != NULL)
330*57490Storek 		for (nv = i->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
331*57490Storek 			if (has_instances(nv->nv_ptr, atunit))
332*57490Storek 				return (1);
333*57490Storek 	return (0);
334*57490Storek }
335*57490Storek 
336*57490Storek static int
337*57490Storek cfcrosscheck(cf, what, nv)
338*57490Storek 	register struct config *cf;
339*57490Storek 	const char *what;
340*57490Storek 	register struct nvlist *nv;
341*57490Storek {
342*57490Storek 	register struct devbase *dev;
343*57490Storek 	int errs;
344*57490Storek 
345*57490Storek 	for (errs = 0; nv != NULL; nv = nv->nv_next) {
346*57490Storek 		if (nv->nv_name == NULL)
347*57490Storek 			continue;
348*57490Storek 		dev = ht_lookup(devbasetab, nv->nv_name);
349*57490Storek 		if (dev == NULL)
350*57490Storek 			panic("cfcrosscheck(%s)", nv->nv_name);
351*57490Storek 		if (has_instances(dev, STAR) ||
352*57490Storek 		    has_instances(dev, minor(nv->nv_int) >> 3))
353*57490Storek 			continue;
354*57490Storek 		(void)fprintf(stderr,
355*57490Storek 		    "%s%d: %s says %s on %s, but there's no %s\n",
356*57490Storek 		    conffile, cf->cf_lineno,
357*57490Storek 		    cf->cf_name, what, nv->nv_str, nv->nv_str);
358*57490Storek 		errs++;
359*57490Storek 	}
360*57490Storek 	return (errs);
361*57490Storek }
362*57490Storek 
363*57490Storek /*
364*57490Storek  * Cross-check the configuration: make sure that each target device
365*57490Storek  * or attribute (`at foo[0*?]') names at least one real device.  Also
366*57490Storek  * see that the root, swap, and dump devices for all configurations
367*57490Storek  * are there.
368*57490Storek  */
369*57490Storek int
370*57490Storek crosscheck()
371*57490Storek {
372*57490Storek 	register struct devi *i;
373*57490Storek 	register struct config *cf;
374*57490Storek 	int errs;
375*57490Storek 
376*57490Storek 	errs = 0;
377*57490Storek 	for (i = alldevi; i != NULL; i = i->i_next) {
378*57490Storek 		if (i->i_at == NULL || hasparent(i))
379*57490Storek 			continue;
380*57490Storek 		xerror(conffile, i->i_lineno,
381*57490Storek 		    "%s at %s is orphaned", i->i_name, i->i_at);
382*57490Storek 		if (i->i_atunit == WILD)
383*57490Storek 			(void)fprintf(stderr, " (no %s's declared)\n",
384*57490Storek 			    i->i_base->d_name);
385*57490Storek 		else
386*57490Storek 			(void)fprintf(stderr, " (no %s declared)\n", i->i_at);
387*57490Storek 		errs++;
388*57490Storek 	}
389*57490Storek 	if (allcf == NULL) {
390*57490Storek 		(void)fprintf(stderr, "%s has no configurations!\n",
391*57490Storek 		    conffile);
392*57490Storek 		errs++;
393*57490Storek 	}
394*57490Storek 	for (cf = allcf; cf != NULL; cf = cf->cf_next) {
395*57490Storek 		if (cf->cf_root != NULL) {	/* i.e., not swap generic */
396*57490Storek 			errs += cfcrosscheck(cf, "root", cf->cf_root);
397*57490Storek 			errs += cfcrosscheck(cf, "swap", cf->cf_swap);
398*57490Storek 			errs += cfcrosscheck(cf, "dumps", cf->cf_dump);
399*57490Storek 		}
400*57490Storek 	}
401*57490Storek 	return (errs);
402*57490Storek }
403*57490Storek 
404*57490Storek /*
405*57490Storek  * Check to see if there is more than one *'d unit for any device,
406*57490Storek  * or a *'d unit with a needs-count file.
407*57490Storek  */
408*57490Storek int
409*57490Storek badstar()
410*57490Storek {
411*57490Storek 	register struct devbase *d;
412*57490Storek 	register struct devi *i;
413*57490Storek 	register int errs, n;
414*57490Storek 
415*57490Storek 	errs = 0;
416*57490Storek 	for (d = allbases; d != NULL; d = d->d_next) {
417*57490Storek 		for (i = d->d_ihead; i != NULL; i = i->i_bsame)
418*57490Storek 			if (i->i_unit == STAR)
419*57490Storek 				goto foundstar;
420*57490Storek 		continue;
421*57490Storek 	foundstar:
422*57490Storek 		if (ht_lookup(needcnttab, d->d_name)) {
423*57490Storek 			(void)fprintf(stderr,
424*57490Storek 		    "config: %s's cannot be *'d until its driver is fixed\n",
425*57490Storek 			    d->d_name);
426*57490Storek 			errs++;
427*57490Storek 			continue;
428*57490Storek 		}
429*57490Storek 		for (n = 0; i != NULL; i = i->i_alias)
430*57490Storek 			if (!i->i_collapsed)
431*57490Storek 				n++;
432*57490Storek 		if (n < 1)
433*57490Storek 			panic("badstar() n<1");
434*57490Storek 		if (n == 1)
435*57490Storek 			continue;
436*57490Storek 		(void)fprintf(stderr,
437*57490Storek 		    "config: %d %s*'s in configuration; can only have 1\n",
438*57490Storek 		    n, d->d_name);
439*57490Storek 		errs++;
440*57490Storek 	}
441*57490Storek 	return (errs);
442*57490Storek }
443