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