Let config extract embedded configuration data from kernels that were built

with either "options INCLUDE_CONFIG_FILE" or "options INCLUDE_JUST_CONFIG".

The program can now be invoked like:
- config -b objdir -s srcdir /netbsd
  This will use configuration data from /netbsd to automatically create the
  build directory of the new kernel.
- config -x /netbsd > CONFFILE
  This will store configuration data from /netbsd in the CONFFILE file for
  further editing.
This commit is contained in:
jmmv 2003-04-26 12:53:43 +00:00
parent 325b10be64
commit f37b7f38ab
2 changed files with 214 additions and 7 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: config.8,v 1.23 2003/04/24 13:23:55 jmmv Exp $ .\" $NetBSD: config.8,v 1.24 2003/04/26 12:53:43 jmmv Exp $
.\" .\"
.\" Copyright (c) 1980, 1991, 1993 .\" Copyright (c) 1980, 1991, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -33,7 +33,7 @@
.\" .\"
.\" from: @(#)config.8 8.2 (Berkeley) 4/19/94 .\" from: @(#)config.8 8.2 (Berkeley) 4/19/94
.\" .\"
.Dd April 19, 1994 .Dd April 26, 2003
.Dt CONFIG 8 .Dt CONFIG 8
.Os .Os
.Sh NAME .Sh NAME
@ -45,7 +45,11 @@
.Op Fl b Ar builddir .Op Fl b Ar builddir
.Op Fl s Ar srcdir .Op Fl s Ar srcdir
.Op Ar config-file .Op Ar config-file
.Nm
.Fl x
.Op Ar kernel-file
.Sh DESCRIPTION .Sh DESCRIPTION
In its first synopsis form,
.Nm .Nm
creates a kernel build directory from the machine description file creates a kernel build directory from the machine description file
.Ar config-file , .Ar config-file ,
@ -109,6 +113,21 @@ directive at the beginning of the machine description file.
You must specify the location of the top-level kernel source directory if you You must specify the location of the top-level kernel source directory if you
specify a build directory. specify a build directory.
.Pp .Pp
If
.Ar config-file
is a binary kernel,
.Nm
will try to extract the configuration file embedded into it, which will
be present if that kernel was built either with
.Va INCLUDE_CONFIG_FILE
or
.Va INCLUDE_JUST_CONFIG
options.
This work mode requires you to manually specify a build directory with
the
.Fl b
option, which implies the need to provide a source tree too.
.Pp
If the If the
.Fl p .Fl p
option is supplied, option is supplied,
@ -183,6 +202,26 @@ if there are configuration errors,
but this code is not well-tested, but this code is not well-tested,
and some problems (such as running out of disk space) and some problems (such as running out of disk space)
are unrecoverable. are unrecoverable.
.Pp
In its second synopsis form,
.Nm
takes the binary kernel
.Ar kernel-file
as its single argument (aside from the mandatory
.Fl x
flag), then extracts the embedded configuration file (if any) and
writes it to standard output.
If
.Ar kernel-file
is not given,
.Pa /netbsd
is used.
Configuration data will be available if the given kernel was compiled
with either
.Va INCLUDE_CONFIG_FILE
or
.Va INCLUDE_JUST_CONFIG
options.
.Sh SEE ALSO .Sh SEE ALSO
The SYNOPSIS portion of each device in section 4. The SYNOPSIS portion of each device in section 4.
.\".Rs .\".Rs

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.75 2003/01/27 05:00:54 thorpej Exp $ */ /* $NetBSD: main.c,v 1.76 2003/04/26 12:53:43 jmmv Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -59,9 +59,12 @@ COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/mman.h>
#include <paths.h>
#include <ctype.h> #include <ctype.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -70,6 +73,10 @@ COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
#include "sem.h" #include "sem.h"
#include <vis.h> #include <vis.h>
#ifndef LINE_MAX
#define LINE_MAX 1024
#endif
int vflag; /* verbose output */ int vflag; /* verbose output */
int Pflag; /* pack locators */ int Pflag; /* pack locators */
@ -110,6 +117,9 @@ static void logconfig_end(void);
static FILE *cfg; static FILE *cfg;
static time_t cfgtime; static time_t cfgtime;
static int is_elf(const char *);
static int extract_config(const char *, const char *, int);
int badfilename(const char *fname); int badfilename(const char *fname);
const char *progname; const char *progname;
@ -117,14 +127,15 @@ const char *progname;
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
char *p; char *p, cname[20];
const char *last_component; const char *last_component;
int pflag, ch; int pflag, xflag, ch, removeit;
setprogname(argv[0]); setprogname(argv[0]);
pflag = 0; pflag = 0;
while ((ch = getopt(argc, argv, "DPgpvb:s:")) != -1) { xflag = 0;
while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) {
switch (ch) { switch (ch) {
#ifndef MAKE_BOOTSTRAP #ifndef MAKE_BOOTSTRAP
@ -175,6 +186,10 @@ main(int argc, char **argv)
srcdir = optarg; srcdir = optarg;
break; break;
case 'x':
xflag = 1;
break;
case '?': case '?':
default: default:
goto usage; goto usage;
@ -185,9 +200,34 @@ main(int argc, char **argv)
argv += optind; argv += optind;
if (argc > 1) { if (argc > 1) {
usage: usage:
(void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] sysname\n", stderr); (void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] "
"[sysname]\n", stderr);
(void)fputs(" config -x [kernel-file]\n", stderr);
exit(1); exit(1);
} }
if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag ||
vflag)) {
(void)fprintf(stderr, "config: -x must be used alone\n");
exit(1);
}
if (xflag) {
conffile = (argc == 1) ? argv[0] : _PATH_UNIX;
if (!is_elf(conffile)) {
(void)fprintf(stderr, "%s: not a binary kernel\n",
conffile);
exit(1);
}
if (!extract_config(conffile, "stdout", STDOUT_FILENO)) {
(void)fprintf(stderr,
"config: %s does not contain embedded "
"configuration data\n", conffile);
exit(2);
}
exit(0);
}
conffile = (argc == 1) ? argv[0] : "CONFIG"; conffile = (argc == 1) ? argv[0] : "CONFIG";
if (firstfile(conffile)) { if (firstfile(conffile)) {
(void)fprintf(stderr, "config: cannot read %s: %s\n", (void)fprintf(stderr, "config: cannot read %s: %s\n",
@ -242,6 +282,43 @@ main(int argc, char **argv)
} }
defbuilddir = (argc == 0) ? "." : p; defbuilddir = (argc == 0) ? "." : p;
removeit = 0;
if (is_elf(conffile)) {
char *tmpdir;
int cfd;
if (builddir == NULL) {
(void)fprintf(stderr,
"config: build directory must be specified with "
"binary kernels\n");
exit(1);
}
/* Open temporary configuration file */
tmpdir = getenv("TMPDIR");
if (tmpdir == NULL)
tmpdir = "/tmp";
snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir);
cfd = mkstemp(cname);
if (cfd == -1) {
fprintf(stderr, "config: cannot create %s: %s", cname,
strerror(errno));
exit(2);
}
printf("Using configuration data embedded in kernel...\n");
if (!extract_config(conffile, cname, cfd)) {
(void)fprintf(stderr,
"config: %s does not contain embedded "
"configuration data\n", conffile);
exit(2);
}
removeit = 1;
close(cfd);
firstfile(cname);
}
/* /*
* Parse config file (including machine definitions). * Parse config file (including machine definitions).
*/ */
@ -250,6 +327,9 @@ main(int argc, char **argv)
stop(); stop();
logconfig_end(); logconfig_end();
if (removeit)
unlink(cname);
/* /*
* Select devices and pseudo devices and their attributes * Select devices and pseudo devices and their attributes
*/ */
@ -1297,3 +1377,91 @@ strtolower(const char *name)
return (intern(low)); return (intern(low));
} }
static int
is_elf(const char *file)
{
int kernel;
char hdr[4];
kernel = open(file, O_RDONLY);
if (kernel == -1) {
fprintf(stderr, "config: cannot open %s: %s\n", file,
strerror(errno));
exit(2);
}
if (read(kernel, hdr, 4) == -1) {
fprintf(stderr, "config: cannot read from %s: %s\n", file,
strerror(errno));
exit(2);
}
close(kernel);
return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0;
}
static int
extract_config(const char *kname, const char *cname, int cfd)
{
char *ptr;
int found, kfd, i;
struct stat st;
found = 0;
/* mmap(2) binary kernel */
kfd = open(conffile, O_RDONLY);
if (kfd == -1) {
fprintf(stderr, "config: cannot open %s: %s\n", kname,
strerror(errno));
exit(2);
}
if ((fstat(kfd, &st) == -1)) {
fprintf(stderr, "config: cannot stat %s: %s\n", kname,
strerror(errno));
exit(2);
}
ptr = (char *)mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
kfd, 0);
if (ptr == MAP_FAILED) {
fprintf(stderr, "config: cannot mmap %s: %s\n", kname,
strerror(errno));
exit(2);
}
/* Scan mmap(2)'ed region, extracting kernel configuration */
for (i = 0; i < st.st_size; i++) {
if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr,
"_CFG_", 5) == 0) {
/* Line found */
char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1];
int i;
found = 1;
oldptr = (ptr += 5);
while (*ptr != '\n' && *ptr != '\0') ptr++;
if (ptr - oldptr > LINE_MAX) {
fprintf(stderr, "config: line too long\n");
exit(2);
}
memcpy(line, oldptr, (ptr - oldptr));
line[ptr - oldptr] = '\0';
i = strunvis(uline, line);
if (i == -1) {
fprintf(stderr, "config: unvis: invalid "
"encoded sequence\n");
exit(2);
}
uline[i] = '\n';
if (write(cfd, uline, i + 1) == -1) {
fprintf(stderr, "config: cannot write to %s: "
"%s\n", cname, strerror(errno));
exit(2);
}
} else ptr++;
}
close(kfd);
return found;
}