xref: /csrg-svn/usr.sbin/config.new/main.c (revision 61818)
157490Storek /*
2*61818Sbostic  * Copyright (c) 1992, 1993
3*61818Sbostic  *	The Regents of the University of California.  All rights reserved.
457490Storek  *
557490Storek  * This software was developed by the Computer Systems Engineering group
657490Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
757490Storek  * contributed to Berkeley.
857490Storek  *
957490Storek  * All advertising materials mentioning features or use of this software
1057490Storek  * must display the following acknowledgement:
1157490Storek  *	This product includes software developed by the University of
1257490Storek  *	California, Lawrence Berkeley Laboratories.
1357490Storek  *
1457490Storek  * %sccs.include.redist.c%
1557490Storek  *
16*61818Sbostic  *	@(#)main.c	8.1 (Berkeley) 06/06/93
1757490Storek  */
1857490Storek 
1957490Storek #ifndef lint
20*61818Sbostic static char copyright[] =
21*61818Sbostic "@(#) Copyright (c) 1992, 1993\n\
22*61818Sbostic 	The Regents of the University of California.  All rights reserved.\n";
2357490Storek #endif /* not lint */
2457490Storek 
2557490Storek #include <sys/types.h>
2657490Storek #include <sys/stat.h>
2757490Storek #include <ctype.h>
2857490Storek #include <errno.h>
2957490Storek #include <stdio.h>
3057490Storek #include <stdlib.h>
3157490Storek #include <string.h>
3257490Storek #include <unistd.h>
3357490Storek #include "config.h"
3457490Storek 
3557490Storek int	firstfile __P((const char *));
3657490Storek int	yyparse __P((void));
3757490Storek 
3857490Storek extern char *optarg;
3957490Storek extern int optind;
4057490Storek 
4157490Storek static struct hashtab *opttab;
4257490Storek static struct hashtab *mkopttab;
4357490Storek static struct nvlist **nextopt;
4457490Storek static struct nvlist **nextmkopt;
4557490Storek 
4657490Storek static __dead void stop __P((void));
4757490Storek static int do_option __P((struct hashtab *, struct nvlist ***,
4857490Storek 			const char *, const char *, const char *));
4957490Storek static int crosscheck __P((void));
5057490Storek static int badstar __P((void));
5157490Storek static int mksymlinks __P((void));
5257490Storek static int has_instances __P((struct devbase *, int));
5357490Storek static int hasparent __P((struct devi *));
5457490Storek static int cfcrosscheck __P((struct config *, const char *, struct nvlist *));
5557490Storek 
5657490Storek int
main(argc,argv)5757490Storek main(argc, argv)
5857490Storek 	int argc;
5957490Storek 	char **argv;
6057490Storek {
6157490Storek 	register char *p;
6257490Storek 	int pflag, ch;
6357490Storek 	struct stat st;
6457490Storek 
6557490Storek 	pflag = 0;
6657490Storek 	while ((ch = getopt(argc, argv, "gp")) != EOF) {
6757490Storek 		switch (ch) {
6857490Storek 
6957490Storek 		case 'g':
7057490Storek 			/*
7157490Storek 			 * In addition to DEBUG, you probably wanted to
7257490Storek 			 * set "options KGDB" and maybe others.  We could
7357490Storek 			 * do that for you, but you really should just
7457490Storek 			 * put them in the config file.
7557490Storek 			 */
7657490Storek 			(void)fputs(
7757490Storek 			    "-g is obsolete (use makeoptions DEBUG=\"-g\")\n",
7857490Storek 			    stderr);
7957490Storek 			goto usage;
8057490Storek 
8157490Storek 		case 'p':
8257490Storek 			/*
8357490Storek 			 * Essentially the same as makeoptions PROF="-pg",
8457490Storek 			 * but also changes the path from ../../compile/FOO
8557490Storek 			 * to ../../compile/FOO.prof; i.e., compile a
8657490Storek 			 * profiling kernel based on a typical "regular"
8757490Storek 			 * kernel.
8857490Storek 			 *
8957490Storek 			 * Note that if you always want profiling, you
9057490Storek 			 * can (and should) use a "makeoptions" line.
9157490Storek 			 */
9257490Storek 			pflag = 1;
9357490Storek 			break;
9457490Storek 
9557490Storek 		case '?':
9657490Storek 		default:
9757490Storek 			goto usage;
9857490Storek 		}
9957490Storek 	}
10057490Storek 
10157490Storek 	argc -= optind;
10257490Storek 	argv += optind;
10357490Storek 	if (argc != 1) {
10457490Storek usage:
10557490Storek 		(void)fputs("usage: config [-p] sysname\n", stderr);
10657490Storek 		exit(1);
10757490Storek 	}
10857490Storek 	conffile = argv[0];
10957490Storek 	if (firstfile(conffile)) {
11057490Storek 		(void)fprintf(stderr, "config: cannot read %s: %s\n",
11157490Storek 		    conffile, strerror(errno));
11257490Storek 		exit(2);
11357490Storek 	}
11457490Storek 
11557490Storek 	/*
11657490Storek 	 * Init variables.
11757490Storek 	 */
11857490Storek 	minmaxusers = 1;
11957490Storek 	maxmaxusers = 10000;
12057490Storek 	initintern();
12157490Storek 	initfiles();
12257490Storek 	initsem();
12357490Storek 	devbasetab = ht_new();
12457490Storek 	selecttab = ht_new();
12557490Storek 	needcnttab = ht_new();
12657490Storek 	opttab = ht_new();
12757490Storek 	mkopttab = ht_new();
12857490Storek 	nextopt = &options;
12957490Storek 	nextmkopt = &mkoptions;
13057490Storek 
13157490Storek 	/*
13257490Storek 	 * Handle profiling (must do this before we try to create any
13357490Storek 	 * files).
13457490Storek 	 */
13557490Storek 	if (pflag) {
13657490Storek 		char *s;
13757490Storek 
13857490Storek 		s = emalloc(strlen(conffile) + sizeof(".PROF"));
13957490Storek 		(void)sprintf(s, "%s.PROF", conffile);
14057490Storek 		confdirbase = s;
14157490Storek 		(void)addmkoption(intern("PROF"), "-pg");
14257490Storek 		(void)addoption(intern("GPROF"), NULL);
14357490Storek 	} else
14457490Storek 		confdirbase = conffile;
14557490Storek 
14657490Storek 	/*
14757490Storek 	 * Verify, creating if necessary, the compilation directory.
14857490Storek 	 */
14957490Storek 	p = path(NULL);
15057490Storek 	if (stat(p, &st)) {
15157490Storek 		if (mkdir(p, 0777)) {
15257490Storek 			(void)fprintf(stderr, "config: cannot create %s: %s\n",
15357490Storek 			    p, strerror(errno));
15457490Storek 			exit(2);
15557490Storek 		}
15657490Storek 	} else if (!S_ISDIR(st.st_mode)) {
15757490Storek 		(void)fprintf(stderr, "config: %s is not a directory\n", p);
15857490Storek 		exit(2);
15957490Storek 	}
16057490Storek 
16157490Storek 	/*
16257490Storek 	 * Parse config file (including machine definitions).
16357490Storek 	 */
16457490Storek 	if (yyparse())
16557490Storek 		stop();
16657490Storek 
16757490Storek 	/*
16857490Storek 	 * Fix (as in `set firmly in place') files.
16957490Storek 	 */
17057490Storek 	if (fixfiles())
17157490Storek 		stop();
17257490Storek 
17357490Storek 	/*
17457490Storek 	 * Perform cross-checking.
17557490Storek 	 */
17657490Storek 	if (maxusers == 0) {
17757490Storek 		if (defmaxusers) {
17857490Storek 			(void)printf("maxusers not specified; %d assumed\n",
17957490Storek 			    defmaxusers);
18057490Storek 			maxusers = defmaxusers;
18157490Storek 		} else {
18257490Storek 			(void)fprintf(stderr,
18357490Storek 			    "config: need \"maxusers\" line\n");
18457490Storek 			errors++;
18557490Storek 		}
18657490Storek 	}
18757490Storek 	if (crosscheck() || errors)
18857490Storek 		stop();
18957490Storek 
19057490Storek 	/*
19157490Storek 	 * Squeeze things down and finish cross-checks (STAR checks must
19257490Storek 	 * run after packing).
19357490Storek 	 */
19457490Storek 	pack();
19557490Storek 	if (badstar())
19657490Storek 		stop();
19757490Storek 
19857490Storek 	/*
19957490Storek 	 * Ready to go.  Build all the various files.
20057490Storek 	 */
20157490Storek 	if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
20257490Storek 	    mkioconf())
20357490Storek 		stop();
20457490Storek 	(void)printf("Don't forget to run \"make depend\"\n");
20557490Storek 	exit(0);
20657490Storek }
20757490Storek 
20857490Storek /*
20957490Storek  * Make a symlink for "machine" so that "#include <machine/foo.h>" works.
21057490Storek  */
21157490Storek static int
mksymlinks()21257490Storek mksymlinks()
21357490Storek {
21457490Storek 	int ret;
21557490Storek 	char *p, buf[200];
21657490Storek 
21757490Storek 	p = path("machine");
21857490Storek 	(void)sprintf(buf, "../../%s/include", machine);
21957490Storek 	(void)unlink(p);
22057490Storek 	ret = symlink(buf, p);
22157490Storek 	if (ret)
22257490Storek 		(void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
22357490Storek 		    p, buf, strerror(errno));
22457490Storek 	free(p);
22557490Storek 	return (ret);
22657490Storek }
22757490Storek 
22857490Storek static __dead void
stop()22957490Storek stop()
23057490Storek {
23157490Storek 	(void)fprintf(stderr, "*** Stop.\n");
23257490Storek 	exit(1);
23357490Storek }
23457490Storek 
23557490Storek /*
23657490Storek  * Add an option from "options FOO".  Note that this selects things that
23757490Storek  * are "optional foo".
23857490Storek  */
23957490Storek void
addoption(name,value)24057490Storek addoption(name, value)
24157490Storek 	const char *name, *value;
24257490Storek {
24357490Storek 	register const char *n;
24457490Storek 	register char *p, c;
24557490Storek 	char low[500];
24657490Storek 
24757490Storek 	if (do_option(opttab, &nextopt, name, value, "options"))
24857490Storek 		return;
24957490Storek 
25057490Storek 	/* make lowercase, then add to select table */
25157490Storek 	for (n = name, p = low; (c = *n) != '\0'; n++)
25257490Storek 		*p++ = isupper(c) ? tolower(c) : c;
25357490Storek 	*p = 0;
25457490Storek 	n = intern(low);
25557490Storek 	(void)ht_insert(selecttab, n, (void *)n);
25657490Storek }
25757490Storek 
25857490Storek /*
25957490Storek  * Add a "make" option.
26057490Storek  */
26157490Storek void
addmkoption(name,value)26257490Storek addmkoption(name, value)
26357490Storek 	const char *name, *value;
26457490Storek {
26557490Storek 
26657490Storek 	(void)do_option(mkopttab, &nextmkopt, name, value, "mkoptions");
26757490Storek }
26857490Storek 
26957490Storek /*
27057490Storek  * Add a name=value pair to an option list.  The value may be NULL.
27157490Storek  */
27257490Storek static int
do_option(ht,nppp,name,value,type)27357490Storek do_option(ht, nppp, name, value, type)
27457490Storek 	struct hashtab *ht;
27557490Storek 	struct nvlist ***nppp;
27657490Storek 	const char *name, *value, *type;
27757490Storek {
27857490Storek 	register struct nvlist *nv;
27957490Storek 
28057490Storek 	/* assume it will work */
28157490Storek 	nv = newnv(name, value, NULL, 0);
28257490Storek 	if (ht_insert(ht, name, nv) == 0) {
28357490Storek 		**nppp = nv;
28457490Storek 		*nppp = &nv->nv_next;
28557490Storek 		return (0);
28657490Storek 	}
28757490Storek 
28857490Storek 	/* oops, already got that option */
28957490Storek 	nvfree(nv);
29057490Storek 	if ((nv = ht_lookup(ht, name)) == NULL)
29157490Storek 		panic("do_option");
29257490Storek 	if (nv->nv_str != NULL)
29357490Storek 		error("already have %s `%s=%s'", type, name, nv->nv_str);
29457490Storek 	else
29557490Storek 		error("already have %s `%s'", type, name);
29657490Storek 	return (1);
29757490Storek }
29857490Storek 
29957490Storek /*
30057490Storek  * Return true if there is at least one instance of the given unit
30157490Storek  * on the given base (or any units, if unit == WILD).
30257490Storek  */
30357490Storek static int
has_instances(dev,unit)30457490Storek has_instances(dev, unit)
30557490Storek 	register struct devbase *dev;
30657490Storek 	int unit;
30757490Storek {
30857490Storek 	register struct devi *i;
30957490Storek 
31057490Storek 	if (unit == WILD)
31157490Storek 		return (dev->d_ihead != NULL);
31257490Storek 	for (i = dev->d_ihead; i != NULL; i = i->i_bsame)
31357490Storek 		if (unit == i->i_unit)
31457490Storek 			return (1);
31557490Storek 	return (0);
31657490Storek }
31757490Storek 
31857490Storek static int
hasparent(i)31957490Storek hasparent(i)
32057490Storek 	register struct devi *i;
32157490Storek {
32257490Storek 	register struct nvlist *nv;
32357490Storek 	int atunit = i->i_atunit;
32457490Storek 
32557490Storek 	if (i->i_atdev != NULL && has_instances(i->i_atdev, atunit))
32657490Storek 		return (1);
32757490Storek 	if (i->i_atattr != NULL)
32857490Storek 		for (nv = i->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
32957490Storek 			if (has_instances(nv->nv_ptr, atunit))
33057490Storek 				return (1);
33157490Storek 	return (0);
33257490Storek }
33357490Storek 
33457490Storek static int
cfcrosscheck(cf,what,nv)33557490Storek cfcrosscheck(cf, what, nv)
33657490Storek 	register struct config *cf;
33757490Storek 	const char *what;
33857490Storek 	register struct nvlist *nv;
33957490Storek {
34057490Storek 	register struct devbase *dev;
34157490Storek 	int errs;
34257490Storek 
34357490Storek 	for (errs = 0; nv != NULL; nv = nv->nv_next) {
34457490Storek 		if (nv->nv_name == NULL)
34557490Storek 			continue;
34657490Storek 		dev = ht_lookup(devbasetab, nv->nv_name);
34757490Storek 		if (dev == NULL)
34857490Storek 			panic("cfcrosscheck(%s)", nv->nv_name);
34957490Storek 		if (has_instances(dev, STAR) ||
35057490Storek 		    has_instances(dev, minor(nv->nv_int) >> 3))
35157490Storek 			continue;
35257490Storek 		(void)fprintf(stderr,
35357490Storek 		    "%s%d: %s says %s on %s, but there's no %s\n",
35457490Storek 		    conffile, cf->cf_lineno,
35557490Storek 		    cf->cf_name, what, nv->nv_str, nv->nv_str);
35657490Storek 		errs++;
35757490Storek 	}
35857490Storek 	return (errs);
35957490Storek }
36057490Storek 
36157490Storek /*
36257490Storek  * Cross-check the configuration: make sure that each target device
36357490Storek  * or attribute (`at foo[0*?]') names at least one real device.  Also
36457490Storek  * see that the root, swap, and dump devices for all configurations
36557490Storek  * are there.
36657490Storek  */
36757490Storek int
crosscheck()36857490Storek crosscheck()
36957490Storek {
37057490Storek 	register struct devi *i;
37157490Storek 	register struct config *cf;
37257490Storek 	int errs;
37357490Storek 
37457490Storek 	errs = 0;
37557490Storek 	for (i = alldevi; i != NULL; i = i->i_next) {
37657490Storek 		if (i->i_at == NULL || hasparent(i))
37757490Storek 			continue;
37857490Storek 		xerror(conffile, i->i_lineno,
37957490Storek 		    "%s at %s is orphaned", i->i_name, i->i_at);
38057490Storek 		if (i->i_atunit == WILD)
38157490Storek 			(void)fprintf(stderr, " (no %s's declared)\n",
38257490Storek 			    i->i_base->d_name);
38357490Storek 		else
38457490Storek 			(void)fprintf(stderr, " (no %s declared)\n", i->i_at);
38557490Storek 		errs++;
38657490Storek 	}
38757490Storek 	if (allcf == NULL) {
38857490Storek 		(void)fprintf(stderr, "%s has no configurations!\n",
38957490Storek 		    conffile);
39057490Storek 		errs++;
39157490Storek 	}
39257490Storek 	for (cf = allcf; cf != NULL; cf = cf->cf_next) {
39357490Storek 		if (cf->cf_root != NULL) {	/* i.e., not swap generic */
39457490Storek 			errs += cfcrosscheck(cf, "root", cf->cf_root);
39557490Storek 			errs += cfcrosscheck(cf, "swap", cf->cf_swap);
39657490Storek 			errs += cfcrosscheck(cf, "dumps", cf->cf_dump);
39757490Storek 		}
39857490Storek 	}
39957490Storek 	return (errs);
40057490Storek }
40157490Storek 
40257490Storek /*
40357490Storek  * Check to see if there is more than one *'d unit for any device,
40457490Storek  * or a *'d unit with a needs-count file.
40557490Storek  */
40657490Storek int
badstar()40757490Storek badstar()
40857490Storek {
40957490Storek 	register struct devbase *d;
41057490Storek 	register struct devi *i;
41157490Storek 	register int errs, n;
41257490Storek 
41357490Storek 	errs = 0;
41457490Storek 	for (d = allbases; d != NULL; d = d->d_next) {
41557490Storek 		for (i = d->d_ihead; i != NULL; i = i->i_bsame)
41657490Storek 			if (i->i_unit == STAR)
41757490Storek 				goto foundstar;
41857490Storek 		continue;
41957490Storek 	foundstar:
42057490Storek 		if (ht_lookup(needcnttab, d->d_name)) {
42157490Storek 			(void)fprintf(stderr,
42257490Storek 		    "config: %s's cannot be *'d until its driver is fixed\n",
42357490Storek 			    d->d_name);
42457490Storek 			errs++;
42557490Storek 			continue;
42657490Storek 		}
42757490Storek 		for (n = 0; i != NULL; i = i->i_alias)
42857490Storek 			if (!i->i_collapsed)
42957490Storek 				n++;
43057490Storek 		if (n < 1)
43157490Storek 			panic("badstar() n<1");
43257490Storek 		if (n == 1)
43357490Storek 			continue;
43457490Storek 		(void)fprintf(stderr,
43557490Storek 		    "config: %d %s*'s in configuration; can only have 1\n",
43657490Storek 		    n, d->d_name);
43757490Storek 		errs++;
43857490Storek 	}
43957490Storek 	return (errs);
44057490Storek }
441