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