1 /* $OpenBSD: main.c,v 1.57 2016/10/16 18:02:03 tb Exp $ */ 2 /* $NetBSD: main.c,v 1.22 1997/02/02 21:12:33 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by the University of 15 * California, Lawrence Berkeley Laboratories. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * from: @(#)main.c 8.1 (Berkeley) 6/6/93 42 */ 43 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 47 #include <ctype.h> 48 #include <err.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <limits.h> 55 56 #include "config.h" 57 58 int firstfile(const char *); 59 int yyparse(void); 60 61 static struct hashtab *mkopttab; 62 static struct nvlist **nextopt; 63 static struct nvlist **nextdefopt; 64 static struct nvlist **nextmkopt; 65 66 static __dead void stop(void); 67 static int do_option(struct hashtab *, struct nvlist ***, 68 const char *, const char *, const char *); 69 static int crosscheck(void); 70 static int badstar(void); 71 static int mksymlinks(void); 72 static int hasparent(struct devi *); 73 static int cfcrosscheck(struct config *, const char *, struct nvlist *); 74 static void optiondelta(void); 75 76 int verbose; 77 78 __dead void 79 usage(void) 80 { 81 extern char *__progname; 82 83 fprintf(stderr, 84 "usage: %s [-p] [-b builddir] [-s srcdir] [config-file]\n" 85 " %s [-u] [-f | -o outfile] -e infile\n", 86 __progname, __progname); 87 88 exit(1); 89 } 90 91 int pflag = 0; 92 char *sflag = NULL; 93 char *bflag = NULL; 94 char *startdir; 95 96 int 97 main(int argc, char *argv[]) 98 { 99 char *p; 100 const char *last_component; 101 char *outfile = NULL; 102 int ch, eflag, uflag, fflag; 103 char dirbuffer[PATH_MAX]; 104 105 if (pledge("stdio rpath wpath cpath flock proc exec", NULL) == -1) 106 err(1, "pledge"); 107 108 pflag = eflag = uflag = fflag = 0; 109 while ((ch = getopt(argc, argv, "epfb:s:o:u")) != -1) { 110 switch (ch) { 111 112 case 'o': 113 outfile = optarg; 114 break; 115 case 'u': 116 uflag = 1; 117 break; 118 case 'f': 119 fflag = 1; 120 break; 121 122 case 'e': 123 eflag = 1; 124 if (!isatty(STDIN_FILENO)) 125 verbose = 1; 126 break; 127 128 case 'p': 129 /* 130 * Essentially the same as makeoptions PROF="-pg", 131 * but also changes the path from ../../compile/FOO 132 * to ../../compile/FOO.PROF; i.e., compile a 133 * profiling kernel based on a typical "regular" 134 * kernel. 135 * 136 * Note that if you always want profiling, you 137 * can (and should) use a "makeoptions" line. 138 */ 139 pflag = 1; 140 break; 141 142 case 'b': 143 bflag = optarg; 144 builddir = optarg; 145 break; 146 147 case 's': 148 sflag = optarg; 149 srcdir = optarg; 150 break; 151 152 default: 153 usage(); 154 } 155 } 156 157 argc -= optind; 158 argv += optind; 159 if (argc > 1 || (eflag && argv[0] == NULL)) 160 161 usage(); 162 if (bflag) { 163 startdir = getcwd(dirbuffer, sizeof dirbuffer); 164 if (startdir == NULL) 165 warn("Use of -b and can't getcwd, no make config"); 166 } else { 167 startdir = "../../conf"; 168 } 169 170 if (eflag) { 171 #ifdef MAKE_BOOTSTRAP 172 errx(1, "UKC not available in this binary"); 173 #else 174 return (ukc(argv[0], outfile, uflag, fflag)); 175 #endif 176 } 177 178 conffile = (argc == 1) ? argv[0] : "CONFIG"; 179 if (firstfile(conffile)) 180 err(2, "cannot read %s", conffile); 181 182 /* 183 * Init variables. 184 */ 185 minmaxusers = 1; 186 maxmaxusers = 10000; 187 initintern(); 188 initfiles(); 189 initsem(); 190 devbasetab = ht_new(); 191 devatab = ht_new(); 192 selecttab = ht_new(); 193 needcnttab = ht_new(); 194 opttab = ht_new(); 195 mkopttab = ht_new(); 196 defopttab = ht_new(); 197 nextopt = &options; 198 nextmkopt = &mkoptions; 199 nextdefopt = &defoptions; 200 201 /* 202 * Handle profiling (must do this before we try to create any 203 * files). 204 */ 205 last_component = strrchr(conffile, '/'); 206 last_component = (last_component) ? last_component + 1 : conffile; 207 if (pflag) { 208 if (asprintf(&p, "../compile/%s.PROF", last_component) == -1) 209 err(1, NULL); 210 (void)addmkoption(intern("PROF"), "-pg"); 211 (void)addoption(intern("GPROF"), NULL); 212 } else { 213 if (asprintf(&p, "../compile/%s", last_component) == -1) 214 err(1, NULL); 215 } 216 defbuilddir = (argc == 0) ? "." : p; 217 218 /* 219 * Parse config file (including machine definitions). 220 */ 221 if (yyparse()) 222 stop(); 223 224 /* 225 * Fix (as in `set firmly in place') files. 226 */ 227 if (fixfiles()) 228 stop(); 229 230 /* 231 * Fix objects and libraries. 232 */ 233 if (fixobjects()) 234 stop(); 235 236 /* 237 * Perform cross-checking. 238 */ 239 if (maxusers == 0) { 240 if (defmaxusers) { 241 (void)printf("maxusers not specified; %d assumed\n", 242 defmaxusers); 243 maxusers = defmaxusers; 244 } else { 245 warnx("need \"maxusers\" line"); 246 errors++; 247 } 248 } 249 if (crosscheck() || errors) 250 stop(); 251 252 /* 253 * Squeeze things down and finish cross-checks (STAR checks must 254 * run after packing). 255 */ 256 pack(); 257 if (badstar()) 258 stop(); 259 260 /* 261 * Ready to go. Build all the various files. 262 */ 263 if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || 264 mkioconf()) 265 stop(); 266 optiondelta(); 267 return (0); 268 } 269 270 static int 271 mksymlink(const char *value, const char *path) 272 { 273 int ret = 0; 274 275 if (remove(path) && errno != ENOENT) { 276 warn("remove(%s)", path); 277 ret = 1; 278 } 279 if (symlink(value, path)) { 280 warn("symlink(%s -> %s)", path, value); 281 ret = 1; 282 } 283 return (ret); 284 } 285 286 287 /* 288 * Make a symlink for "machine" so that "#include <machine/foo.h>" works, 289 * and for the machine's CPU architecture, so that works as well. 290 */ 291 static int 292 mksymlinks(void) 293 { 294 int ret; 295 char *p, buf[PATH_MAX]; 296 const char *q; 297 298 snprintf(buf, sizeof buf, "arch/%s/include", machine); 299 p = sourcepath(buf); 300 ret = mksymlink(p, "machine"); 301 if (machinearch != NULL) { 302 snprintf(buf, sizeof buf, "arch/%s/include", machinearch); 303 p = sourcepath(buf); 304 q = machinearch; 305 } else { 306 p = strdup("machine"); 307 if (!p) 308 errx(1, "out of memory"); 309 q = machine; 310 } 311 ret |= mksymlink(p, q); 312 free(p); 313 314 return (ret); 315 } 316 317 static __dead void 318 stop(void) 319 { 320 (void)fprintf(stderr, "*** Stop.\n"); 321 exit(1); 322 } 323 324 /* 325 * Define a standard option, for which a header file will be generated. 326 */ 327 void 328 defoption(const char *name) 329 { 330 char *p, *low, c; 331 const char *n; 332 333 /* 334 * Convert to lower case. The header file name will be 335 * in lower case, so we store the lower case version in 336 * the hash table to detect option name collisions. The 337 * original string will be stored in the nvlist for use 338 * in the header file. 339 */ 340 low = emalloc(strlen(name) + 1); 341 for (n = name, p = low; (c = *n) != '\0'; n++) 342 *p++ = isupper((unsigned char)c) ? 343 tolower((unsigned char)c) : c; 344 *p = 0; 345 346 n = intern(low); 347 free(low); 348 (void)do_option(defopttab, &nextdefopt, n, name, "defopt"); 349 350 /* 351 * Insert a verbatim copy of the option name, as well, 352 * to speed lookups when creating the Makefile. 353 */ 354 (void)ht_insert(defopttab, name, (void *)name); 355 } 356 357 /* 358 * Remove an option. 359 */ 360 void 361 removeoption(const char *name) 362 { 363 struct nvlist *nv, *nvt; 364 char *p, *low, c; 365 const char *n; 366 367 if ((nv = ht_lookup(opttab, name)) != NULL) { 368 if (options == nv) { 369 options = nv->nv_next; 370 nvfree(nv); 371 } else { 372 nvt = options; 373 while (nvt->nv_next != NULL) { 374 if (nvt->nv_next == nv) { 375 nvt->nv_next = nvt->nv_next->nv_next; 376 nvfree(nv); 377 break; 378 } else 379 nvt = nvt->nv_next; 380 } 381 } 382 } 383 384 (void)ht_remove(opttab, name); 385 386 low = emalloc(strlen(name) + 1); 387 /* make lowercase, then remove from select table */ 388 for (n = name, p = low; (c = *n) != '\0'; n++) 389 *p++ = isupper((unsigned char)c) ? 390 tolower((unsigned char)c) : c; 391 *p = 0; 392 n = intern(low); 393 free(low); 394 (void)ht_remove(selecttab, n); 395 } 396 397 /* 398 * Add an option from "options FOO". Note that this selects things that 399 * are "optional foo". 400 */ 401 void 402 addoption(const char *name, const char *value) 403 { 404 char *p, *low, c; 405 const char *n; 406 407 if (do_option(opttab, &nextopt, name, value, "options")) 408 return; 409 410 low = emalloc(strlen(name) + 1); 411 /* make lowercase, then add to select table */ 412 for (n = name, p = low; (c = *n) != '\0'; n++) 413 *p++ = isupper((unsigned char)c) ? 414 tolower((unsigned char)c) : c; 415 *p = 0; 416 n = intern(low); 417 free(low); 418 (void)ht_insert(selecttab, n, (void *)n); 419 } 420 421 /* 422 * Add a "make" option. 423 */ 424 void 425 addmkoption(const char *name, const char *value) 426 { 427 428 (void)do_option(mkopttab, &nextmkopt, name, value, "mkoptions"); 429 } 430 431 /* 432 * Add a name=value pair to an option list. The value may be NULL. 433 */ 434 static int 435 do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, 436 const char *value, const char *type) 437 { 438 struct nvlist *nv; 439 440 /* assume it will work */ 441 nv = newnv(name, value, NULL, 0, NULL); 442 if (ht_insert(ht, name, nv) == 0) { 443 **nppp = nv; 444 *nppp = &nv->nv_next; 445 return (0); 446 } 447 448 /* oops, already got that option */ 449 nvfree(nv); 450 if ((nv = ht_lookup(ht, name)) == NULL) 451 panic("do_option"); 452 if (nv->nv_str != NULL) 453 error("already have %s `%s=%s'", type, name, nv->nv_str); 454 else 455 error("already have %s `%s'", type, name); 456 return (1); 457 } 458 459 /* 460 * Return true if there is at least one instance of the given unit 461 * on the given device attachment (or any units, if unit == WILD). 462 */ 463 int 464 deva_has_instances(struct deva *deva, int unit) 465 { 466 struct devi *i; 467 468 if (unit == WILD) 469 return (deva->d_ihead != NULL); 470 for (i = deva->d_ihead; i != NULL; i = i->i_asame) 471 if (unit == i->i_unit) 472 return (1); 473 return (0); 474 } 475 476 /* 477 * Return true if there is at least one instance of the given unit 478 * on the given base (or any units, if unit == WILD). 479 */ 480 int 481 devbase_has_instances(struct devbase *dev, int unit) 482 { 483 struct deva *da; 484 485 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 486 if (deva_has_instances(da, unit)) 487 return (1); 488 return (0); 489 } 490 491 static int 492 hasparent(struct devi *i) 493 { 494 struct nvlist *nv; 495 int atunit = i->i_atunit; 496 497 /* 498 * We determine whether or not a device has a parent in in one 499 * of two ways: 500 * (1) If a parent device was named in the config file, 501 * i.e. cases (2) and (3) in sem.c:adddev(), then 502 * we search its devbase for a matching unit number. 503 * (2) If the device was attach to an attribute, then we 504 * search all attributes the device can be attached to 505 * for parents (with appropriate unit numbers) that 506 * may be able to attach the device. 507 */ 508 509 /* 510 * Case (1): A parent was named. Either it's configured, or not. 511 */ 512 if (i->i_atdev != NULL) 513 return (devbase_has_instances(i->i_atdev, atunit)); 514 515 /* 516 * Case (2): No parent was named. Look for devs that provide the attr. 517 */ 518 if (i->i_atattr != NULL) 519 for (nv = i->i_atattr->a_refs; nv != NULL; nv = nv->nv_next) 520 if (devbase_has_instances(nv->nv_ptr, atunit)) 521 return (1); 522 return (0); 523 } 524 525 static int 526 cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) 527 { 528 struct devbase *dev; 529 struct devi *pd; 530 int errs, devminor; 531 532 if (maxpartitions <= 0) 533 panic("cfcrosscheck"); 534 535 for (errs = 0; nv != NULL; nv = nv->nv_next) { 536 if (nv->nv_name == NULL) 537 continue; 538 dev = ht_lookup(devbasetab, nv->nv_name); 539 if (dev == NULL) 540 panic("cfcrosscheck(%s)", nv->nv_name); 541 devminor = minor(nv->nv_int) / maxpartitions; 542 if (devbase_has_instances(dev, devminor)) 543 continue; 544 if (devbase_has_instances(dev, STAR) && 545 devminor >= dev->d_umax) 546 continue; 547 for (pd = allpseudo; pd != NULL; pd = pd->i_next) 548 if (pd->i_base == dev && devminor < dev->d_umax && 549 devminor >= 0) 550 goto loop; 551 (void)fprintf(stderr, 552 "%s:%d: %s says %s on %s, but there's no %s\n", 553 conffile, cf->cf_lineno, 554 cf->cf_name, what, nv->nv_str, nv->nv_str); 555 errs++; 556 loop: 557 ; 558 } 559 return (errs); 560 } 561 562 /* 563 * Cross-check the configuration: make sure that each target device 564 * or attribute (`at foo[0*?]') names at least one real device. Also 565 * see that the root, swap, and dump devices for all configurations 566 * are there. 567 */ 568 int 569 crosscheck(void) 570 { 571 struct devi *i; 572 struct config *cf; 573 int errs; 574 575 errs = 0; 576 for (i = alldevi; i != NULL; i = i->i_next) { 577 if (i->i_at == NULL || hasparent(i)) 578 continue; 579 xerror(conffile, i->i_lineno, 580 "%s at %s is orphaned", i->i_name, i->i_at); 581 (void)fprintf(stderr, " (%s %s declared)\n", 582 i->i_atunit == WILD ? "nothing matching" : "no", 583 i->i_at); 584 errs++; 585 } 586 if (allcf == NULL) { 587 (void)fprintf(stderr, "%s has no configurations!\n", 588 conffile); 589 errs++; 590 } 591 for (cf = allcf; cf != NULL; cf = cf->cf_next) { 592 if (cf->cf_root != NULL) { /* i.e., not swap generic */ 593 errs += cfcrosscheck(cf, "root", cf->cf_root); 594 errs += cfcrosscheck(cf, "swap", cf->cf_swap); 595 errs += cfcrosscheck(cf, "dumps", cf->cf_dump); 596 } 597 } 598 return (errs); 599 } 600 601 /* 602 * Check to see if there is a *'d unit with a needs-count file. 603 */ 604 int 605 badstar(void) 606 { 607 struct devbase *d; 608 struct deva *da; 609 struct devi *i; 610 int errs, n; 611 612 errs = 0; 613 for (d = allbases; d != NULL; d = d->d_next) { 614 for (da = d->d_ahead; da != NULL; da = da->d_bsame) 615 for (i = da->d_ihead; i != NULL; i = i->i_asame) { 616 if (i->i_unit == STAR) 617 goto foundstar; 618 } 619 continue; 620 foundstar: 621 if (ht_lookup(needcnttab, d->d_name)) { 622 warnx("%s's cannot be *'d until its driver is fixed", 623 d->d_name); 624 errs++; 625 continue; 626 } 627 for (n = 0; i != NULL; i = i->i_alias) 628 if (!i->i_collapsed) 629 n++; 630 if (n < 1) 631 panic("badstar() n<1"); 632 } 633 return (errs); 634 } 635 636 /* 637 * Verify/create builddir if necessary, change to it, and verify srcdir. 638 * This will be called when we see the first include. 639 */ 640 void 641 setupdirs(void) 642 { 643 struct stat st; 644 FILE *fp; 645 646 /* srcdir must be specified if builddir is not specified or if 647 * no configuration filename was specified. */ 648 if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { 649 error("source directory must be specified"); 650 exit(1); 651 } 652 653 if (srcdir == NULL) 654 srcdir = "../../../.."; 655 if (builddir == NULL) 656 builddir = defbuilddir; 657 658 if (stat(builddir, &st) != 0) { 659 if (mkdir(builddir, 0777)) 660 err(2, "cannot create %s", builddir); 661 } else if (!S_ISDIR(st.st_mode)) 662 errc(2, ENOTDIR, "%s", builddir); 663 if (chdir(builddir) != 0) 664 errx(2, "cannot change to %s", builddir); 665 if (stat(srcdir, &st) != 0 || !S_ISDIR(st.st_mode)) 666 errc(2, ENOTDIR, "%s", srcdir); 667 668 if (bflag) { 669 if (pledge("stdio rpath wpath cpath flock", NULL) == -1) 670 err(1, "pledge"); 671 return; 672 } 673 674 if (stat("obj", &st) == 0) 675 goto reconfig; 676 677 fp = fopen("Makefile", "w"); 678 if (!fp) 679 errx(2, "cannot create Makefile"); 680 if (fprintf(fp, ".include \"../Makefile.inc\"\n") < 0 || 681 fclose(fp) == EOF) 682 errx(2, "cannot write Makefile"); 683 684 reconfig: 685 if (system("make obj") != 0) 686 exit(2); 687 if (system("make config") != 0) 688 exit(2); 689 exit(0); 690 } 691 692 struct opt { 693 const char *name; 694 const char *val; 695 }; 696 697 int 698 optcmp(const void *v1, const void *v2) 699 { 700 const struct opt *sp1 = v1, *sp2 = v2; 701 int r; 702 703 r = strcmp(sp1->name, sp2->name); 704 if (r == 0) { 705 if (!sp1->val && !sp2->val) 706 r = 0; 707 else if (sp1->val && !sp2->val) 708 r = -1; 709 else if (sp2->val && !sp1->val) 710 r = 1; 711 else r = strcmp(sp1->val, sp2->val); 712 } 713 return (r); 714 } 715 716 void 717 optiondelta(void) 718 { 719 struct nvlist *nv; 720 char nbuf[BUFSIZ], obuf[BUFSIZ]; /* XXX size */ 721 int nnewopts, ret = 0, i; 722 struct opt *newopts; 723 FILE *fp; 724 725 for (nnewopts = 0, nv = options; nv != NULL; nv = nv->nv_next) 726 nnewopts++; 727 newopts = ereallocarray(NULL, nnewopts, sizeof(struct opt)); 728 if (newopts == NULL) 729 ret = 0; 730 for (i = 0, nv = options; nv != NULL; nv = nv->nv_next, i++) { 731 newopts[i].name = nv->nv_name; 732 newopts[i].val = nv->nv_str; 733 } 734 qsort(newopts, nnewopts, sizeof (struct opt), optcmp); 735 736 /* compare options against previous config */ 737 if ((fp = fopen("options", "r"))) { 738 for (i = 0; !feof(fp) && i < nnewopts && ret == 0; i++) { 739 if (newopts[i].val) 740 snprintf(nbuf, sizeof nbuf, "%s=%s\n", 741 newopts[i].name, newopts[i].val); 742 else 743 snprintf(nbuf, sizeof nbuf, "%s\n", 744 newopts[i].name); 745 if (fgets(obuf, sizeof obuf, fp) == NULL || 746 strcmp(nbuf, obuf)) 747 ret = 1; 748 } 749 fclose(fp); 750 fp = NULL; 751 } else if (access("options", F_OK) == 0) 752 ret = 1; 753 754 /* replace with the new list of options */ 755 if ((fp = fopen("options", "w+"))) { 756 rewind(fp); 757 for (i = 0; i < nnewopts; i++) { 758 if (newopts[i].val) 759 fprintf(fp, "%s=%s\n", newopts[i].name, 760 newopts[i].val); 761 else 762 fprintf(fp, "%s\n", newopts[i].name); 763 } 764 fclose(fp); 765 } 766 free(newopts); 767 if (ret == 0) 768 return; 769 (void)printf("Kernel options have changed -- you must run \"make clean\"\n"); 770 } 771