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
.\" The Regents of the University of California. All rights reserved.
@ -33,7 +33,7 @@
.\"
.\" from: @(#)config.8 8.2 (Berkeley) 4/19/94
.\"
.Dd April 19, 1994
.Dd April 26, 2003
.Dt CONFIG 8
.Os
.Sh NAME
@ -45,7 +45,11 @@
.Op Fl b Ar builddir
.Op Fl s Ar srcdir
.Op Ar config-file
.Nm
.Fl x
.Op Ar kernel-file
.Sh DESCRIPTION
In its first synopsis form,
.Nm
creates a kernel build directory from the machine description 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
specify a build directory.
.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
.Fl p
option is supplied,
@ -183,6 +202,26 @@ if there are configuration errors,
but this code is not well-tested,
and some problems (such as running out of disk space)
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
The SYNOPSIS portion of each device in section 4.
.\".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
@ -59,9 +59,12 @@ COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <paths.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -70,6 +73,10 @@ COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
#include "sem.h"
#include <vis.h>
#ifndef LINE_MAX
#define LINE_MAX 1024
#endif
int vflag; /* verbose output */
int Pflag; /* pack locators */
@ -110,6 +117,9 @@ static void logconfig_end(void);
static FILE *cfg;
static time_t cfgtime;
static int is_elf(const char *);
static int extract_config(const char *, const char *, int);
int badfilename(const char *fname);
const char *progname;
@ -117,14 +127,15 @@ const char *progname;
int
main(int argc, char **argv)
{
char *p;
char *p, cname[20];
const char *last_component;
int pflag, ch;
int pflag, xflag, ch, removeit;
setprogname(argv[0]);
pflag = 0;
while ((ch = getopt(argc, argv, "DPgpvb:s:")) != -1) {
xflag = 0;
while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) {
switch (ch) {
#ifndef MAKE_BOOTSTRAP
@ -175,6 +186,10 @@ main(int argc, char **argv)
srcdir = optarg;
break;
case 'x':
xflag = 1;
break;
case '?':
default:
goto usage;
@ -185,9 +200,34 @@ main(int argc, char **argv)
argv += optind;
if (argc > 1) {
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);
}
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";
if (firstfile(conffile)) {
(void)fprintf(stderr, "config: cannot read %s: %s\n",
@ -242,6 +282,43 @@ main(int argc, char **argv)
}
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).
*/
@ -250,6 +327,9 @@ main(int argc, char **argv)
stop();
logconfig_end();
if (removeit)
unlink(cname);
/*
* Select devices and pseudo devices and their attributes
*/
@ -1297,3 +1377,91 @@ strtolower(const char *name)
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;
}