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