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