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