1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1980, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/file.h> 44 #include <sys/mman.h> 45 #include <sys/param.h> 46 47 #include <assert.h> 48 #include <ctype.h> 49 #include <dirent.h> 50 #include <err.h> 51 #include <iostream> 52 #include <sstream> 53 #include <stdio.h> 54 #include <string.h> 55 #include <sysexits.h> 56 #include <unistd.h> 57 58 #include "y.tab.h" 59 #include "config.h" 60 #include "configvers.h" 61 62 #ifndef TRUE 63 #define TRUE (1) 64 #endif 65 66 #ifndef FALSE 67 #define FALSE (0) 68 #endif 69 70 #define CDIR "../compile/" 71 72 char *machinename; 73 char *machinearch; 74 75 struct cfgfile_head cfgfiles; 76 struct cputype_head cputype; 77 struct opt_head opt, mkopt, rmopts; 78 struct opt_list_head otab; 79 struct envvar_head envvars; 80 struct hint_head hints; 81 struct includepath_head includepath; 82 83 char * PREFIX; 84 char destdir[MAXPATHLEN]; 85 char srcdir[MAXPATHLEN]; 86 87 int debugging; 88 int found_defaults; 89 int incignore; 90 91 /* 92 * Preserve old behaviour in INCLUDE_CONFIG_FILE handling (files are included 93 * literally). 94 */ 95 int filebased = 0; 96 int versreq; 97 98 static void configfile(void); 99 static void get_srcdir(void); 100 static void usage(void); 101 static void cleanheaders(char *); 102 static void kernconfdump(const char *); 103 static void badversion(void); 104 static void checkversion(void); 105 106 struct hdr_list { 107 const char *h_name; 108 struct hdr_list *h_next; 109 } *htab; 110 111 static std::stringstream line_buf; 112 113 /* 114 * Config builds a set of files for building a UNIX 115 * system given a description of the desired system. 116 */ 117 int 118 main(int argc, char **argv) 119 { 120 121 struct stat buf; 122 int ch, len; 123 char *p; 124 char *kernfile; 125 struct includepath* ipath; 126 int printmachine; 127 bool cust_dest = false; 128 129 printmachine = 0; 130 kernfile = NULL; 131 SLIST_INIT(&includepath); 132 SLIST_INIT(&cputype); 133 SLIST_INIT(&mkopt); 134 SLIST_INIT(&opt); 135 SLIST_INIT(&rmopts); 136 STAILQ_INIT(&cfgfiles); 137 STAILQ_INIT(&dtab); 138 STAILQ_INIT(&fntab); 139 STAILQ_INIT(&ftab); 140 STAILQ_INIT(&hints); 141 STAILQ_INIT(&envvars); 142 while ((ch = getopt(argc, argv, "Cd:gI:mps:Vx:")) != -1) 143 switch (ch) { 144 case 'C': 145 filebased = 1; 146 break; 147 case 'd': 148 if (*destdir == '\0') 149 strlcpy(destdir, optarg, sizeof(destdir)); 150 else 151 errx(EXIT_FAILURE, "directory already set"); 152 cust_dest = true; 153 break; 154 case 'g': 155 debugging++; 156 break; 157 case 'I': 158 ipath = (struct includepath *) \ 159 calloc(1, sizeof (struct includepath)); 160 if (ipath == NULL) 161 err(EXIT_FAILURE, "calloc"); 162 ipath->path = optarg; 163 SLIST_INSERT_HEAD(&includepath, ipath, path_next); 164 break; 165 case 'm': 166 printmachine = 1; 167 break; 168 case 's': 169 if (*srcdir == '\0') 170 strlcpy(srcdir, optarg, sizeof(srcdir)); 171 else 172 errx(EXIT_FAILURE, "src directory already set"); 173 break; 174 case 'V': 175 printf("%d\n", CONFIGVERS); 176 exit(0); 177 case 'x': 178 kernfile = optarg; 179 break; 180 case '?': 181 default: 182 usage(); 183 } 184 argc -= optind; 185 argv += optind; 186 187 if (kernfile != NULL) { 188 kernconfdump(kernfile); 189 exit(EXIT_SUCCESS); 190 } 191 192 if (argc != 1) 193 usage(); 194 195 PREFIX = *argv; 196 if (stat(PREFIX, &buf) != 0 || !S_ISREG(buf.st_mode)) 197 err(2, "%s", PREFIX); 198 if (freopen("DEFAULTS", "r", stdin) != NULL) { 199 found_defaults = 1; 200 yyfile = "DEFAULTS"; 201 } else { 202 if (freopen(PREFIX, "r", stdin) == NULL) 203 err(2, "%s", PREFIX); 204 yyfile = PREFIX; 205 } 206 if (*destdir != '\0') { 207 len = strlen(destdir); 208 while (len > 1 && destdir[len - 1] == '/') 209 destdir[--len] = '\0'; 210 if (*srcdir == '\0') 211 get_srcdir(); 212 } else { 213 strlcpy(destdir, CDIR, sizeof(destdir)); 214 strlcat(destdir, PREFIX, sizeof(destdir)); 215 } 216 217 if (yyparse()) 218 exit(3); 219 220 /* 221 * Ensure that required elements (machine, cpu, ident) are present. 222 */ 223 if (machinename == NULL) { 224 printf("Specify machine type, e.g. ``machine i386''\n"); 225 exit(1); 226 } 227 if (ident == NULL) { 228 printf("no ident line specified\n"); 229 exit(1); 230 } 231 if (SLIST_EMPTY(&cputype)) { 232 printf("cpu type must be specified\n"); 233 exit(1); 234 } 235 checkversion(); 236 237 if (printmachine) { 238 printf("%s\t%s\n",machinename,machinearch); 239 exit(0); 240 } 241 242 /* 243 * Make CDIR directory, if doing a default destination. Some version 244 * control systems delete empty directories and this seemlessly copes. 245 */ 246 if (!cust_dest && stat(CDIR, &buf)) 247 if (mkdir(CDIR, 0777)) 248 err(2, "%s", CDIR); 249 /* Create the compile directory */ 250 p = path((char *)NULL); 251 if (stat(p, &buf)) { 252 if (mkdir(p, 0777)) 253 err(2, "%s", p); 254 } else if (!S_ISDIR(buf.st_mode)) 255 errx(EXIT_FAILURE, "%s isn't a directory", p); 256 257 configfile(); /* put config file into kernel*/ 258 options(); /* make options .h files */ 259 makefile(); /* build Makefile */ 260 makeenv(); /* build env.c */ 261 makehints(); /* build hints.c */ 262 headers(); /* make a lot of .h files */ 263 cleanheaders(p); 264 printf("Kernel build directory is %s\n", p); 265 printf("Don't forget to do ``make cleandepend && make depend''\n"); 266 exit(0); 267 } 268 269 /* 270 * get_srcdir 271 * determine the root of the kernel source tree 272 * and save that in srcdir. 273 */ 274 static void 275 get_srcdir(void) 276 { 277 struct stat lg, phy; 278 char *p, *pwd; 279 int i; 280 281 if (realpath("../..", srcdir) == NULL) 282 err(EXIT_FAILURE, "Unable to find root of source tree"); 283 if ((pwd = getenv("PWD")) != NULL && *pwd == '/' && 284 (pwd = strdup(pwd)) != NULL) { 285 /* Remove the last two path components. */ 286 for (i = 0; i < 2; i++) { 287 if ((p = strrchr(pwd, '/')) == NULL) { 288 free(pwd); 289 return; 290 } 291 *p = '\0'; 292 } 293 if (stat(pwd, &lg) != -1 && stat(srcdir, &phy) != -1 && 294 lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino) 295 strlcpy(srcdir, pwd, MAXPATHLEN); 296 free(pwd); 297 } 298 } 299 300 static void 301 usage(void) 302 { 303 304 fprintf(stderr, 305 "usage: config [-CgmpV] [-d destdir] [-s srcdir] sysname\n"); 306 fprintf(stderr, " config -x kernel\n"); 307 exit(EX_USAGE); 308 } 309 310 static void 311 init_line_buf(void) 312 { 313 314 line_buf.str(""); 315 } 316 317 static std::string 318 get_line_buf(void) 319 { 320 321 line_buf.flush(); 322 if (!line_buf.good()) { 323 errx(EXIT_FAILURE, "failed to generate line buffer, " 324 "partial line = %s", line_buf.str().c_str()); 325 } 326 327 return line_buf.str(); 328 } 329 330 /* 331 * get_word 332 * returns EOF on end of file 333 * NULL on end of line 334 * pointer to the word otherwise 335 */ 336 configword 337 get_word(FILE *fp) 338 { 339 int ch; 340 int escaped_nl = 0; 341 342 init_line_buf(); 343 begin: 344 while ((ch = getc(fp)) != EOF) 345 if (ch != ' ' && ch != '\t') 346 break; 347 if (ch == EOF) 348 return (configword().eof(true)); 349 if (ch == '\\'){ 350 escaped_nl = 1; 351 goto begin; 352 } 353 if (ch == '\n') { 354 if (escaped_nl){ 355 escaped_nl = 0; 356 goto begin; 357 } 358 else 359 return (configword().eol(true)); 360 } 361 line_buf << (char)ch; 362 /* Negation operator is a word by itself. */ 363 if (ch == '!') { 364 return (configword(get_line_buf())); 365 } 366 while ((ch = getc(fp)) != EOF) { 367 if (isspace(ch)) 368 break; 369 line_buf << (char)ch; 370 } 371 if (ch == EOF) 372 return (configword().eof(true)); 373 (void) ungetc(ch, fp); 374 return (configword(get_line_buf())); 375 } 376 377 /* 378 * get_quoted_word 379 * like get_word but will accept something in double or single quotes 380 * (to allow embedded spaces). 381 */ 382 configword 383 get_quoted_word(FILE *fp) 384 { 385 int ch; 386 int escaped_nl = 0; 387 388 init_line_buf(); 389 begin: 390 while ((ch = getc(fp)) != EOF) 391 if (ch != ' ' && ch != '\t') 392 break; 393 if (ch == EOF) 394 return (configword().eof(true)); 395 if (ch == '\\'){ 396 escaped_nl = 1; 397 goto begin; 398 } 399 if (ch == '\n') { 400 if (escaped_nl){ 401 escaped_nl = 0; 402 goto begin; 403 } 404 else 405 return (configword().eol(true)); 406 } 407 if (ch == '"' || ch == '\'') { 408 int quote = ch; 409 410 escaped_nl = 0; 411 while ((ch = getc(fp)) != EOF) { 412 if (ch == quote && !escaped_nl) 413 break; 414 if (ch == '\n' && !escaped_nl) { 415 printf("config: missing quote reading `%s'\n", 416 get_line_buf().c_str()); 417 exit(2); 418 } 419 if (ch == '\\' && !escaped_nl) { 420 escaped_nl = 1; 421 continue; 422 } 423 if (ch != quote && escaped_nl) 424 line_buf << "\\"; 425 line_buf << (char)ch; 426 escaped_nl = 0; 427 } 428 } else { 429 line_buf << (char)ch; 430 while ((ch = getc(fp)) != EOF) { 431 if (isspace(ch)) 432 break; 433 line_buf << (char)ch; 434 } 435 if (ch != EOF) 436 (void) ungetc(ch, fp); 437 } 438 if (ch == EOF) 439 return (configword().eof(true)); 440 return (configword(get_line_buf())); 441 } 442 443 /* 444 * prepend the path to a filename 445 */ 446 char * 447 path(const char *file) 448 { 449 char *cp = NULL; 450 451 if (file) 452 asprintf(&cp, "%s/%s", destdir, file); 453 else 454 cp = strdup(destdir); 455 if (cp == NULL) 456 err(EXIT_FAILURE, "malloc"); 457 return (cp); 458 } 459 460 /* 461 * Generate configuration file based on actual settings. With this mode, user 462 * will be able to obtain and build conifguration file with one command. 463 */ 464 static void 465 configfile_dynamic(std::ostringstream &cfg) 466 { 467 struct cputype *cput; 468 struct device *d; 469 struct opt *ol; 470 char *lend; 471 unsigned int i; 472 473 asprintf(&lend, "\\n\\\n"); 474 assert(lend != NULL); 475 cfg << "options\t" << OPT_AUTOGEN << lend; 476 cfg << "ident\t" << ident << lend; 477 cfg << "machine\t" << machinename << lend; 478 SLIST_FOREACH(cput, &cputype, cpu_next) 479 cfg << "cpu\t" << cput->cpu_name << lend; 480 SLIST_FOREACH(ol, &mkopt, op_next) 481 cfg << "makeoptions\t" << ol->op_name << '=' << 482 ol->op_value << lend; 483 SLIST_FOREACH(ol, &opt, op_next) { 484 if (strncmp(ol->op_name, "DEV_", 4) == 0) 485 continue; 486 cfg << "options\t" << ol->op_name; 487 if (ol->op_value != NULL) { 488 cfg << '='; 489 for (i = 0; i < strlen(ol->op_value); i++) { 490 if (ol->op_value[i] == '"') 491 cfg << '\\' << ol->op_value[i]; 492 else 493 cfg << ol->op_value[i]; 494 } 495 } 496 497 cfg << lend; 498 } 499 /* 500 * Mark this file as containing everything we need. 501 */ 502 STAILQ_FOREACH(d, &dtab, d_next) 503 cfg << "device\t" << d->d_name << lend; 504 free(lend); 505 } 506 507 /* 508 * Generate file from the configuration files. 509 */ 510 static void 511 configfile_filebased(std::ostringstream &cfg) 512 { 513 FILE *cff; 514 struct cfgfile *cf; 515 int i; 516 517 /* 518 * Try to read all configuration files. Since those will be present as 519 * C string in the macro, we have to slash their ends then the line 520 * wraps. 521 */ 522 STAILQ_FOREACH(cf, &cfgfiles, cfg_next) { 523 cff = fopen(cf->cfg_path, "r"); 524 if (cff == NULL) { 525 warn("Couldn't open file %s", cf->cfg_path); 526 continue; 527 } 528 while ((i = getc(cff)) != EOF) { 529 if (i == '\n') 530 cfg << "\\n\\\n"; 531 else if (i == '"' || i == '\'') 532 cfg << '\\' << i; 533 else 534 cfg << i; 535 } 536 fclose(cff); 537 } 538 } 539 540 static void 541 configfile(void) 542 { 543 FILE *fo; 544 std::ostringstream cfg; 545 char *p; 546 547 /* Add main configuration file to the list of files to be included */ 548 cfgfile_add(PREFIX); 549 p = path("config.c.new"); 550 fo = fopen(p, "w"); 551 if (!fo) 552 err(2, "%s", p); 553 free(p); 554 555 if (filebased) { 556 /* Is needed, can be used for backward compatibility. */ 557 configfile_filebased(cfg); 558 } else { 559 configfile_dynamic(cfg); 560 } 561 562 cfg.flush(); 563 /* 564 * We print first part of the template, replace our tag with 565 * configuration files content and later continue writing our 566 * template. 567 */ 568 p = strstr(kernconfstr, KERNCONFTAG); 569 if (p == NULL) 570 errx(EXIT_FAILURE, "Something went terribly wrong!"); 571 *p = '\0'; 572 fprintf(fo, "%s", kernconfstr); 573 fprintf(fo, "%s", cfg.str().c_str()); 574 p += strlen(KERNCONFTAG); 575 fprintf(fo, "%s", p); 576 fclose(fo); 577 moveifchanged("config.c.new", "config.c"); 578 cfgfile_removeall(); 579 } 580 581 /* 582 * moveifchanged -- 583 * compare two files; rename if changed. 584 */ 585 void 586 moveifchanged(const char *from_name, const char *to_name) 587 { 588 char *p, *q; 589 char *from_path, *to_path; 590 int changed; 591 size_t tsize; 592 struct stat from_sb, to_sb; 593 int from_fd, to_fd; 594 595 changed = 0; 596 597 from_path = path(from_name); 598 to_path = path(to_name); 599 if ((from_fd = open(from_path, O_RDONLY)) < 0) 600 err(EX_OSERR, "moveifchanged open(%s)", from_name); 601 602 if ((to_fd = open(to_path, O_RDONLY)) < 0) 603 changed++; 604 605 if (!changed && fstat(from_fd, &from_sb) < 0) 606 err(EX_OSERR, "moveifchanged fstat(%s)", from_path); 607 608 if (!changed && fstat(to_fd, &to_sb) < 0) 609 err(EX_OSERR, "moveifchanged fstat(%s)", to_path); 610 611 if (!changed && from_sb.st_size != to_sb.st_size) 612 changed++; 613 614 if (!changed) { 615 tsize = (size_t)from_sb.st_size; 616 617 p = (char *)mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, 618 (off_t)0); 619 if (p == MAP_FAILED) 620 err(EX_OSERR, "mmap %s", from_path); 621 q = (char *)mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, 622 (off_t)0); 623 if (q == MAP_FAILED) 624 err(EX_OSERR, "mmap %s", to_path); 625 626 changed = memcmp(p, q, tsize); 627 munmap(p, tsize); 628 munmap(q, tsize); 629 } 630 631 if (changed) { 632 if (rename(from_path, to_path) < 0) 633 err(EX_OSERR, "rename(%s, %s)", from_path, to_path); 634 } else { 635 if (unlink(from_path) < 0) 636 err(EX_OSERR, "unlink(%s)", from_path); 637 } 638 639 close(from_fd); 640 if (to_fd >= 0) 641 close(to_fd); 642 643 free(from_path); 644 free(to_path); 645 } 646 647 static void 648 cleanheaders(char *p) 649 { 650 DIR *dirp; 651 struct dirent *dp; 652 struct file_list *fl; 653 struct hdr_list *hl; 654 size_t len; 655 656 remember("y.tab.h"); 657 remember("setdefs.h"); 658 STAILQ_FOREACH(fl, &ftab, f_next) 659 remember(fl->f_fn); 660 661 /* 662 * Scan the build directory and clean out stuff that looks like 663 * it might have been a leftover NFOO header, etc. 664 */ 665 if ((dirp = opendir(p)) == NULL) 666 err(EX_OSERR, "opendir %s", p); 667 while ((dp = readdir(dirp)) != NULL) { 668 len = strlen(dp->d_name); 669 /* Skip non-headers */ 670 if (len < 2 || dp->d_name[len - 2] != '.' || 671 dp->d_name[len - 1] != 'h') 672 continue; 673 /* Skip special stuff, eg: bus_if.h, but check opt_*.h */ 674 if (strchr(dp->d_name, '_') && 675 strncmp(dp->d_name, "opt_", 4) != 0) 676 continue; 677 /* Check if it is a target file */ 678 for (hl = htab; hl != NULL; hl = hl->h_next) { 679 if (eq(dp->d_name, hl->h_name)) { 680 break; 681 } 682 } 683 if (hl) 684 continue; 685 printf("Removing stale header: %s\n", dp->d_name); 686 p = path(dp->d_name); 687 if (unlink(p) == -1) 688 warn("unlink %s", dp->d_name); 689 free(p); 690 } 691 (void)closedir(dirp); 692 } 693 694 void 695 remember(const char *file) 696 { 697 const char *s; 698 struct hdr_list *hl; 699 700 if ((s = strrchr(file, '/')) != NULL) 701 s = ns(s + 1); 702 else 703 s = ns(file); 704 705 if (strchr(s, '_') && strncmp(s, "opt_", 4) != 0) { 706 free(__DECONST(char *, s)); 707 return; 708 } 709 for (hl = htab; hl != NULL; hl = hl->h_next) { 710 if (eq(s, hl->h_name)) { 711 free(__DECONST(char *, s)); 712 return; 713 } 714 } 715 hl = (struct hdr_list *)calloc(1, sizeof(*hl)); 716 if (hl == NULL) 717 err(EXIT_FAILURE, "calloc"); 718 hl->h_name = s; 719 hl->h_next = htab; 720 htab = hl; 721 } 722 723 /* 724 * This one is quick hack. Will be probably moved to elf(3) interface. 725 * It takes kernel configuration file name, passes it as an argument to 726 * elfdump -a, which output is parsed by some UNIX tools... 727 */ 728 static void 729 kernconfdump(const char *file) 730 { 731 struct stat st; 732 FILE *fp, *pp; 733 int error, osz, r; 734 size_t i, off, size, t1, t2, align; 735 char *cmd, *o; 736 737 r = open(file, O_RDONLY); 738 if (r == -1) 739 err(EXIT_FAILURE, "Couldn't open file '%s'", file); 740 error = fstat(r, &st); 741 if (error == -1) 742 err(EXIT_FAILURE, "fstat() failed"); 743 if (S_ISDIR(st.st_mode)) 744 errx(EXIT_FAILURE, "'%s' is a directory", file); 745 fp = fdopen(r, "r"); 746 if (fp == NULL) 747 err(EXIT_FAILURE, "fdopen() failed"); 748 osz = 1024; 749 o = (char *)calloc(1, osz); 750 if (o == NULL) 751 err(EXIT_FAILURE, "Couldn't allocate memory"); 752 /* ELF note section header. */ 753 asprintf(&cmd, "/usr/bin/elfdump -c %s | grep -A 8 kern_conf" 754 "| tail -5 | cut -d ' ' -f 2 | paste - - - - -", file); 755 if (cmd == NULL) 756 errx(EXIT_FAILURE, "asprintf() failed"); 757 pp = popen(cmd, "r"); 758 if (pp == NULL) 759 errx(EXIT_FAILURE, "popen() failed"); 760 free(cmd); 761 (void)fread(o, osz, 1, pp); 762 pclose(pp); 763 r = sscanf(o, "%zu%zu%zu%zu%zu", &off, &size, &t1, &t2, &align); 764 free(o); 765 if (size > SIZE_MAX - off || off + size > (size_t)st.st_size) 766 errx(EXIT_FAILURE, "%s: incoherent ELF headers", file); 767 if (r != 5) 768 errx(EXIT_FAILURE, "File %s doesn't contain configuration " 769 "file. Either unsupported, or not compiled with " 770 "INCLUDE_CONFIG_FILE", file); 771 r = fseek(fp, off, SEEK_CUR); 772 if (r != 0) 773 err(EXIT_FAILURE, "fseek() failed"); 774 for (i = 0; i < size; i++) { 775 r = fgetc(fp); 776 if (r == EOF) 777 break; 778 if (r == '\0') { 779 assert(i == size - 1 && 780 ("\\0 found in the middle of a file")); 781 break; 782 } 783 fputc(r, stdout); 784 } 785 fclose(fp); 786 } 787 788 static void 789 badversion(void) 790 { 791 fprintf(stderr, "ERROR: version of config(8) does not match kernel!\n"); 792 fprintf(stderr, "config version = %d, ", CONFIGVERS); 793 fprintf(stderr, "version required = %d\n\n", versreq); 794 fprintf(stderr, "Make sure that /usr/src/usr.sbin/config is in sync\n"); 795 fprintf(stderr, "with your /usr/src/sys and install a new config binary\n"); 796 fprintf(stderr, "before trying this again.\n\n"); 797 fprintf(stderr, "If running the new config fails check your config\n"); 798 fprintf(stderr, "file against the GENERIC or LINT config files for\n"); 799 fprintf(stderr, "changes in config syntax, or option/device naming\n"); 800 fprintf(stderr, "conventions\n\n"); 801 exit(1); 802 } 803 804 static void 805 checkversion(void) 806 { 807 FILE *ifp; 808 char line[BUFSIZ]; 809 810 ifp = open_makefile_template(); 811 while (fgets(line, BUFSIZ, ifp) != 0) { 812 if (*line != '%') 813 continue; 814 if (strncmp(line, "%VERSREQ=", 9) != 0) 815 continue; 816 versreq = atoi(line + 9); 817 if (MAJOR_VERS(versreq) == MAJOR_VERS(CONFIGVERS) && 818 versreq <= CONFIGVERS) 819 continue; 820 badversion(); 821 } 822 fclose(ifp); 823 } 824