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