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