Index: config.8 =================================================================== RCS file: /cvsroot/src/usr.sbin/config/config.8,v retrieving revision 1.23 diff -u -r1.23 config.8 --- config.8 2003/04/24 13:23:55 1.23 +++ config.8 2003/04/25 16:29:42 @@ -33,7 +33,7 @@ .\" .\" from: @(#)config.8 8.2 (Berkeley) 4/19/94 .\" -.Dd April 19, 1994 +.Dd April 25, 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 @@ 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 @@ 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 @@ -199,3 +238,7 @@ .Bx 4.1 . It was completely revised in .Bx 4.4 . +The +.Fl x +option appeared in +.Nx 2.0 . Index: main.c =================================================================== RCS file: /cvsroot/src/usr.sbin/config/main.c,v retrieving revision 1.75 diff -u -r1.75 main.c --- main.c 2003/01/27 05:00:54 1.75 +++ main.c 2003/04/25 16:29:43 @@ -59,9 +59,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -70,6 +72,10 @@ #include "sem.h" #include +#ifndef LINE_MAX +#define LINE_MAX 1024 +#endif + int vflag; /* verbose output */ int Pflag; /* pack locators */ @@ -110,6 +116,9 @@ 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 +126,15 @@ 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 +185,10 @@ srcdir = optarg; break; + case 'x': + xflag = 1; + break; + case '?': default: goto usage; @@ -185,9 +199,34 @@ 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] : "/netbsd"; + 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 +281,43 @@ } 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 +326,9 @@ stop(); logconfig_end(); + if (removeit) + unlink(cname); + /* * Select devices and pseudo devices and their attributes */ @@ -1297,3 +1376,91 @@ 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; +}