Subject: Allow config extract embedded configuration files
To: None <tech-userlevel@netbsd.org>
From: Julio Merino <jmmv@menta.net>
List: tech-userlevel
Date: 04/14/2003 15:10:39
Hi,

as kernel files can contain embedded configuration files (with options
INCLUDE_CONFIG_FILE or INCLUDE_JUST_CONFIG), I think it could be good
if config(8) could automatically extract them and configure a new
kernel based on that information.

I've got a patch that does it (see below).  I feel it's not very polished
and several things can be improved, but I don't know which ones are they.

Is it there any interest in this?  Comments?

Index: config.8
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/config.8,v
retrieving revision 1.22
diff -u -u -r1.22 config.8
--- config.8	2003/02/25 10:36:06	1.22
+++ config.8	2003/04/14 12:55:50
@@ -33,7 +33,7 @@
 .\"
 .\"     from: @(#)config.8	8.2 (Berkeley) 4/19/94
 .\"
-.Dd April 19, 1994
+.Dd April 14, 2003
 .Dt CONFIG 8
 .Os
 .Sh NAME
@@ -106,6 +106,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
Index: main.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/main.c,v
retrieving revision 1.75
diff -u -u -r1.75 main.c
--- main.c	2003/01/27 05:00:54	1.75
+++ main.c	2003/04/14 12:55:56
@@ -62,6 +62,7 @@
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -110,6 +111,9 @@
 static	FILE	*cfg;
 static	time_t	cfgtime;
 
+static	int	is_elf(const char *);
+static	int	extract_config(const char *, char *, int);
+
 int badfilename(const char *fname);
 
 const char *progname;
@@ -242,14 +246,44 @@
 	}
 	defbuilddir = (argc == 0) ? "." : p;
 
-	/*
-	 * Parse config file (including machine definitions).
-	 */
-	logconfig_start();
-	if (yyparse())
-		stop();
-	logconfig_end();
+	if (is_elf(conffile)) {
+		char cname[20];
+
+		if (builddir == NULL) {
+			(void)fprintf(stderr,
+			    "config: build directory must be specified with "
+			    "binary kernels\n");
+			exit(1);
+		}
+
+		if (!extract_config(conffile, cname, sizeof(cname))) {
+			(void)fprintf(stderr,
+			    "config: %s does not contain configuration "
+			    "information\n", conffile);
+			exit(2);
+		}
+
+		firstfile(cname);
+
+		/*
+		 * Parse config file (including machine definitions).
+		 */
+		logconfig_start();
+		if (yyparse())
+			stop();
+		logconfig_end();
 
+		unlink(cname);
+	} else {
+		/*
+		 * Parse config file (including machine definitions).
+		 */
+		logconfig_start();
+		if (yyparse())
+			stop();
+		logconfig_end();
+	}
+
 	/*
 	 * Select devices and pseudo devices and their attributes
 	 */
@@ -1297,3 +1331,107 @@
 	return (intern(low));
 }
 
+static int
+is_elf(const char *file)
+{
+	int kernel;
+	char hdr[4];
+
+	kernel = open(file, O_RDONLY);
+	read(kernel, hdr, 4);
+	close(kernel);
+	return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0;
+}
+
+static int
+extract_config(const char *kname, char *cname, int cnamelen)
+{
+	char ibuf[LINE_MAX + 1], obuf[LINE_MAX + 1], *tmpdir;
+	int found, kfd, cfd;
+
+	found = 0;
+
+	/* Open binary kernel */
+	kfd = open(conffile, O_RDONLY);
+	if (kfd == -1) {
+		fprintf(stderr, "config: cannot open %s: %s", kname,
+		    strerror(errno));
+		exit(2);
+	}
+
+	/* Open temporary configuration file */
+	tmpdir = getenv("TMPDIR");
+	if (tmpdir == NULL)
+		tmpdir = "/tmp";
+	snprintf(cname, cnamelen, "%s/config.tmp.XXXXXX", tmpdir);
+	cfd = mkstemp(cname);
+	if (cfd == -1) {
+		fprintf(stderr, "config: cannot create %s: %s", cname,
+		    strerror(errno));
+		exit(2);
+	}
+
+	/* Extract configuration from kfd into cfd */
+	for (;;) {
+		int count;
+		char *ptr;
+
+		count = read(kfd, ibuf, LINE_MAX);
+		if (count == -1) {
+			(void)fprintf(stderr,
+			    "config: cannot read from %s: %s", kname,
+			    strerror(errno));
+			exit(2);
+		} else if (count == 0)
+			break;
+		ibuf[count] = '\0';
+
+		/* Convert \0's into anything else, so strstr(3) works */
+		for (ptr = ibuf; ptr < ibuf + count; ptr++)
+			if (*ptr == '\0')
+				*ptr = 1;
+
+		ptr = strstr(ibuf, "_CFG_");
+		if (ptr != NULL) {
+			int len;
+
+			if (!found) {
+				printf("Using configuration embedded in %s\n",
+				    kname);
+				found = 1;
+			}
+
+			lseek(kfd, -(count - (ptr - ibuf)), SEEK_CUR);
+			count = read(kfd, ibuf, LINE_MAX);
+			if (count == -1) {
+				(void)fprintf(stderr,
+				    "config: cannot read from %s: %s", kname,
+				    strerror(errno));
+				exit(2);
+			}
+			ibuf[count] = '\0';
+
+			ptr = ibuf;
+			while (*ptr != '\n' && *ptr != '\0') ptr++;
+			*ptr = '\0';
+
+			strunvis(obuf, ibuf + 5);
+			len = strlen(obuf);
+			obuf[len] = '\n';
+			if (write(cfd, obuf, len + 1) == -1) {
+				(void)fprintf(stderr,
+				    "config: cannot write to %s: %s", cname,
+				    strerror(errno));
+				exit(2);
+			}
+
+			lseek(kfd, -(count - (ptr - ibuf)), SEEK_CUR);
+		} else if (count > 5)
+			lseek(kfd, -5, SEEK_CUR);
+	}
+
+	close(kfd);
+	close(cfd);
+
+	return found;
+}

Thanks.

-- 
Julio M. Merino Vidal <jmmv@menta.net>
The NetBSD Project - http://www.NetBSD.org/