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