From 744b947ef84848227ce1a826167ada052973c82a Mon Sep 17 00:00:00 2001 From: "Wojciech A. Koszek" Date: Sat, 12 May 2007 19:38:18 +0000 Subject: [PATCH] Improve INCLUDE_CONFIG_FILE support. This change will let us to have full configuration of a running kernel available in sysctl: sysctl -b kern.conftxt The same configuration is also contained within the kernel image. It can be obtained with: config -x Current functionality lets you to quickly recover kernel configuration, by simply redirecting output from commands presented above and starting kernel build procedure. "include" statements are also honored, which means options and devices from included files are also included. Please note that comments from configuration files are not preserved by default. In order to preserve them, you can use -C flag for config(8). This will bring configuration file and included files literally; however, redirection to a file no longer works directly. This commit was followed by discussion, that took place on freebsd-current@. For more details, look here: http://lists.freebsd.org/pipermail/freebsd-current/2007-March/069994.html http://lists.freebsd.org/pipermail/freebsd-current/2007-May/071844.html Development of this patch took place in Perforce, hierarchy: //depot/user/wkoszek/wkoszek_kconftxt/ Support from: freebsd-current@ (links above) Reviewed by: imp@ Approved by: imp@ --- sys/kern/kern_mib.c | 33 +++++ usr.sbin/config/Makefile | 9 +- usr.sbin/config/config.8 | 42 ++++-- usr.sbin/config/config.h | 27 +++- usr.sbin/config/config.y | 109 +++++++++++---- usr.sbin/config/kernconf.tmpl | 17 +++ usr.sbin/config/lang.l | 26 ++++ usr.sbin/config/main.c | 249 +++++++++++++++++++++++++++------- 8 files changed, 422 insertions(+), 90 deletions(-) create mode 100644 usr.sbin/config/kernconf.tmpl diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index 0a5220df3535..2ccb207c5933 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -295,6 +296,38 @@ SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_kern_securelvl, "I", "Current secure level"); +/* Actual kernel configuration options. */ +extern char kernconfstring[]; + +static int +sysctl_kern_config(SYSCTL_HANDLER_ARGS) +{ + struct sbuf *sb; + int error; + char *p; + + sb = sbuf_new(NULL, NULL, 2048, SBUF_AUTOEXTEND); + if (sb == NULL) + return (ENOMEM); + sbuf_clear(sb); + p = kernconfstring; + if (p == NULL || *p == '\0') { + sbuf_printf(sb, "No kernel configuration\n"); + } else { + sbuf_printf(sb, "%s", p); + } + sbuf_trim(sb); + sbuf_putc(sb, '\n'); + sbuf_finish(sb); + error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); + if (error) + return (error); + sbuf_delete(sb); + return (error); +} +SYSCTL_PROC(_kern, OID_AUTO, conftxt, CTLTYPE_STRING|CTLFLAG_RW, + 0, 0, sysctl_kern_config, "", "Kernel configuration file"); + char domainname[MAXHOSTNAMELEN]; SYSCTL_STRING(_kern, KERN_NISDOMAINNAME, domainname, CTLFLAG_RW, &domainname, sizeof(domainname), "Name of the current YP/NIS domain"); diff --git a/usr.sbin/config/Makefile b/usr.sbin/config/Makefile index 8861b3cda326..bd318aeb53b0 100644 --- a/usr.sbin/config/Makefile +++ b/usr.sbin/config/Makefile @@ -4,13 +4,18 @@ PROG= config MAN= config.5 config.8 SRCS= config.y main.c lang.l mkmakefile.c mkheaders.c \ - mkoptions.c y.tab.h + mkoptions.c y.tab.h kernconf.c + +kernconf.c: kernconf.tmpl + file2c 'char kernconfstr[] = {' ',0};' < kernconf.tmpl > kernconf.c WARNS?= 6 CFLAGS+= -I. -I${.CURDIR} DPADD= ${LIBL} -LDADD= -ll +LDADD= -ll -lsbuf + +CLEANFILES+= kernconf.c mkmakefile.o: configvers.h diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8 index adffa122819f..01abc9499113 100644 --- a/usr.sbin/config/config.8 +++ b/usr.sbin/config/config.8 @@ -28,7 +28,7 @@ .\" @(#)config.8 8.2 (Berkeley) 4/19/94 .\" $FreeBSD$ .\" -.Dd December 16, 2004 +.Dd May 8, 2007 .Dt CONFIG 8 .Os .Sh NAME @@ -36,9 +36,11 @@ .Nd build system configuration files .Sh SYNOPSIS .Nm -.Op Fl Vgp +.Op Fl CVgp .Op Fl d Ar destdir .Ar SYSTEM_NAME +.Nm +.Op Fl x Ar kernel .Sh DESCRIPTION .\" This is the old version of the .\" .Nm @@ -76,6 +78,11 @@ Available options and operands: Print the .Nm version number. +.It Fl C +If the INCLUDE_CONFIG_FILE is present in a configuration file, +kernel image will contain full configuration files included +literally (preserving comments). +This flag is kept for backward compatibility. .It Fl d Ar destdir Use .Ar destdir @@ -87,6 +94,12 @@ does not append to the directory given. .It Fl g Configure a system for debugging. +.It Fl x Ar kernel +Print kernel configuration file embedded into a kernel +file. +This option makes sense only if +.Cd "options INCLUDE_CONFIG_FILE" +entry was present in your configuration file. .It Fl p Configure a system for profiling; for example, .Xr kgmon 8 @@ -151,17 +164,6 @@ the problems in the configuration file should be corrected and should be run again. Attempts to compile a system that had configuration errors are likely to fail. -.Pp -If the -.Cd "options INCLUDE_CONFIG_FILE" -is used in the configuration file the -entire input file is embedded in the new kernel. -This means that -.Xr strings 1 -can be used to extract it from a kernel: -to extract the configuration information, use the command -.Pp -.Dl "strings -n 3 kernel | sed -n 's/^___//p'" .Sh DEBUG KERNELS Traditional .Bx @@ -254,5 +256,19 @@ The .Nm utility appeared in .Bx 4.1 . +.Pp +Before support for +.Fl x +was introduced, +.Cd "options INCLUDE_CONFIG_FILE" +included entire configuration file that used to be embedded in +the new kernel. +This meant that +.Xr strings 1 +could be used to extract it from a kernel: +to extract the configuration information, you had to use +the command: +.Pp +.Dl "strings -n 3 kernel | sed -n 's/^___//p'" .Sh BUGS The line numbers reported in error messages are usually off by one. diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h index 08ac7969e228..3a3252009a4f 100644 --- a/usr.sbin/config/config.h +++ b/usr.sbin/config/config.h @@ -38,6 +38,12 @@ #include #include +struct cfgfile { + STAILQ_ENTRY(cfgfile) cfg_next; + char *cfg_path; +}; +STAILQ_HEAD(, cfgfile) cfgfiles; + struct file_list { STAILQ_ENTRY(file_list) f_next; char *f_fn; /* the name */ @@ -117,7 +123,7 @@ struct opt { SLIST_ENTRY(opt) op_next; }; -SLIST_HEAD(opt_head, opt) opt, mkopt; +SLIST_HEAD(opt_head, opt) opt, mkopt, rmopts; struct opt_list { char *o_name; @@ -134,11 +140,26 @@ struct hint { STAILQ_HEAD(hint_head, hint) hints; +/* + * Tag present in the kernelconf.tmlp template file. It's mandatory for those + * two strings to be the same. Otherwise you'll get into trouble. + */ +#define KERNCONFTAG "%%KERNCONFFILE%%" + +/* + * Faked option to note, that the configuration file has been taken from the + * kernel file and inclusion of DEFAULTS etc.. isn't nessesery, because we + * already have a list of all required devices. + */ +#define OPT_AUTOGEN "CONFIG_AUTOGENERATED" + extern char *ident; extern char *env; +extern char kernconfstr[]; extern int do_trace; extern int envmode; extern int hintmode; +extern int incignore; char *get_word(FILE *); char *get_quoted_word(FILE *); @@ -153,8 +174,10 @@ void makefile(void); void makeenv(void); void makehints(void); void headers(void); +void cfgfile_add(const char *); +void cfgfile_removeall(void); -extern STAILQ_HEAD(device_head, device) dtab; +extern STAILQ_HEAD(device_head, device) dtab, rmdtab; extern char errbuf[80]; extern int yyline; diff --git a/usr.sbin/config/config.y b/usr.sbin/config/config.y index 40ee93d584e7..9c8ba39eb639 100644 --- a/usr.sbin/config/config.y +++ b/usr.sbin/config/config.y @@ -70,6 +70,7 @@ * $FreeBSD$ */ +#include #include #include #include @@ -77,7 +78,7 @@ #include "config.h" -struct device_head dtab; +struct device_head dtab, rmdtab; char *ident; char *env; int envmode; @@ -104,6 +105,9 @@ devopt(char *dev) return ret; } +static void rmoptall(struct opt_head *list, struct opt_head *torem); +static void rmdevall(struct device_head *dh, struct device_head *torem); + %} %% Configuration: @@ -122,7 +126,10 @@ Spec: Config_spec SEMICOLON | INCLUDE ID SEMICOLON - = { include($2, 0); }; + = { + if (incignore == 0) + include($2, 0); + }; | FILES ID SEMICOLON = { newfile($2); }; @@ -170,11 +177,11 @@ Config_spec: OPTIONS Opt_list | NOOPTION Save_id - = { rmopt(&opt, $2); } | + = { rmopt_schedule(&rmopts, $2); } | MAKEOPTIONS Mkopt_list | NOMAKEOPTION Save_id - = { rmopt(&mkopt, $2); } | + = { rmopt_schedule(&mkopt, $2); } | IDENT ID = { ident = $2; } | System_spec @@ -298,10 +305,10 @@ NoDevice: = { char *s = devopt($1); - rmopt(&opt, s); + rmopt_schedule(&rmopts, s); free(s); /* and the device part */ - rmdev($1); + rmdev_schedule(&rmdtab, $1); } ; %% @@ -317,14 +324,16 @@ int yywrap(void) { - if (found_defaults) { - if (freopen(PREFIX, "r", stdin) == NULL) - err(2, "%s", PREFIX); - yyfile = PREFIX; + if (found_defaults == 0 && incignore == 0) { + if (freopen("DEFAULTS", "r", stdin) == NULL) + return 1; + yyfile = "DEFAULTS"; yyline = 0; - found_defaults = 0; + found_defaults = 1; return 0; } + rmoptall(&opt, &rmopts); + rmdevall(&dtab, &rmdtab); return 1; } @@ -345,11 +354,11 @@ newfile(char *name) * Find a device in the list of devices. */ static struct device * -finddev(char *name) +finddev(struct device_head *dlist, char *name) { struct device *dp; - STAILQ_FOREACH(dp, &dtab, d_next) + STAILQ_FOREACH(dp, dlist, d_next) if (eq(dp->d_name, name)) return (dp); @@ -364,7 +373,7 @@ newdev(char *name) { struct device *np; - if (finddev(name)) { + if (finddev(&dtab, name)) { printf("WARNING: duplicate device `%s' encountered.\n", name); return; } @@ -375,17 +384,36 @@ newdev(char *name) } /* - * Remove a device from the list of devices. + * Schedule a device to removal. */ static void -rmdev(char *name) +rmdev_schedule(struct device_head *dh, char *name) { struct device *dp; - dp = finddev(name); - if (dp != NULL) { - STAILQ_REMOVE(&dtab, dp, device, d_next); - free(dp->d_name); + dp = calloc(1, sizeof(struct device)); + dp->d_name = strdup(name); + assert(dp->d_name != NULL); + STAILQ_INSERT_HEAD(dh, dp, d_next); +} + +/* + * Take care a devices previously scheduled for removal. + */ +static void +rmdevall(struct device_head *dh, struct device_head *torem) +{ + struct device *dp, *rdp; + + while (!STAILQ_EMPTY(torem)) { + dp = STAILQ_FIRST(torem); + STAILQ_REMOVE_HEAD(torem, d_next); + rdp = finddev(dh, dp->d_name); + if (rdp != NULL) { + STAILQ_REMOVE(dh, rdp, device, d_next); + free(rdp->d_name); + free(rdp); + } free(dp); } } @@ -413,6 +441,14 @@ newopt(struct opt_head *list, char *name, char *value) { struct opt *op; + /* + * Ignore inclusions listed explicitly for configuration files. + */ + if (eq(name, OPT_AUTOGEN)) { + incignore = 1; + return; + } + if (findopt(list, name)) { printf("WARNING: duplicate option `%s' encountered.\n", name); return; @@ -429,16 +465,35 @@ newopt(struct opt_head *list, char *name, char *value) * Remove an option from the list of options. */ static void -rmopt(struct opt_head *list, char *name) +rmopt_schedule(struct opt_head *list, char *name) { struct opt *op; - op = findopt(list, name); - if (op != NULL) { - SLIST_REMOVE(list, op, opt, op_next); - free(op->op_name); - if (op->op_value != NULL) - free(op->op_value); + op = calloc(1, sizeof(*op)); + op->op_name = ns(name); + SLIST_INSERT_HEAD(list, op, op_next); +} + +/* + * Remove all options that were scheduled for removal. + */ +static void +rmoptall(struct opt_head *list, struct opt_head *torem) +{ + struct opt *op, *rop; + + op = rop = NULL; + while (!SLIST_EMPTY(torem)) { + op = SLIST_FIRST(torem); + SLIST_REMOVE_HEAD(torem, op_next); + rop = findopt(list, op->op_name); + if (rop != NULL) { + SLIST_REMOVE(list, rop, opt, op_next); + free(rop->op_name); + if (rop->op_value != NULL) + free(rop->op_value); + free(rop); + } free(op); } } diff --git a/usr.sbin/config/kernconf.tmpl b/usr.sbin/config/kernconf.tmpl new file mode 100644 index 000000000000..981efb7581a8 --- /dev/null +++ b/usr.sbin/config/kernconf.tmpl @@ -0,0 +1,17 @@ +/* + * This file acts as a template for config.c that will be generated in the + * kernel build directory after config(8) has been successfully run. + * + * $FreeBSD$ + */ +#include "opt_config.h" +#ifdef INCLUDE_CONFIG_FILE + +const char kernconfstring[] __attribute__ ((section("kern_conf"))) = +"%%KERNCONFFILE%%"; + +#else + +const char kernconfstring[] = "\0"; + +#endif /* INCLUDE_CONFIG_FILE */ diff --git a/usr.sbin/config/lang.l b/usr.sbin/config/lang.l index 4eb0de73be07..2f2886e28448 100644 --- a/usr.sbin/config/lang.l +++ b/usr.sbin/config/lang.l @@ -207,6 +207,30 @@ hex(const char *str) return num; } +void +cfgfile_add(const char *fname) +{ + struct cfgfile *cf; + + cf = calloc(1, sizeof(*cf)); + assert(cf != NULL); + asprintf(&cf->cfg_path, "%s", fname); + STAILQ_INSERT_TAIL(&cfgfiles, cf, cfg_next); +} + +void +cfgfile_removeall(void) +{ + struct cfgfile *cf; + + while (!STAILQ_EMPTY(&cfgfiles)) { + cf = STAILQ_FIRST(&cfgfiles); + STAILQ_REMOVE_HEAD(&cfgfiles, cfg_next); + if (cf->cfg_path != NULL) + free(cf->cfg_path); + free(cf); + } +} /* * Open the named file for inclusion at the current point. Returns 0 on @@ -222,6 +246,7 @@ include(const char *fname, int ateof) struct incl *in; char *fnamebuf; + fnamebuf = NULL; fp = fopen(fname, "r"); if (fp == NULL && fname[0] != '.' && fname[0] != '/') { asprintf(&fnamebuf, "../../conf/%s", fname); @@ -234,6 +259,7 @@ include(const char *fname, int ateof) yyerror("cannot open included file"); return (-1); } + cfgfile_add(fnamebuf == NULL ? fname : fnamebuf); in = malloc(sizeof(*in)); assert(in != NULL); in->in_prev = inclp; diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c index f9d2322fcc04..aede132ec852 100644 --- a/usr.sbin/config/main.c +++ b/usr.sbin/config/main.c @@ -43,9 +43,12 @@ static const char rcsid[] = #include #include +#include #include #include #include + +#include #include #include #include @@ -73,11 +76,19 @@ char srcdir[MAXPATHLEN]; int debugging; int profiling; int found_defaults; +int incignore; + +/* + * Preserve old behaviour in INCLUDE_CONFIG_FILE handling (files are included + * literally). + */ +int filebased = 0; static void configfile(void); static void get_srcdir(void); static void usage(void); static void cleanheaders(char *); +static void kernconfdump(const char *); struct hdr_list { char *h_name; @@ -96,13 +107,14 @@ main(int argc, char **argv) int ch, len; char *p; char xxx[MAXPATHLEN]; - FILE *fp; + char *kernfile; - while ((ch = getopt(argc, argv, "d:gpV")) != -1) + kernfile = NULL; + while ((ch = getopt(argc, argv, "Cd:gpVx:")) != -1) switch (ch) { - case 'V': - printf("%d\n", CONFIGVERS); - exit(0); + case 'C': + filebased = 1; + break; case 'd': if (*destdir == '\0') strlcpy(destdir, optarg, sizeof(destdir)); @@ -115,6 +127,12 @@ main(int argc, char **argv) case 'p': profiling++; break; + case 'V': + printf("%d\n", CONFIGVERS); + exit(0); + case 'x': + kernfile = optarg; + break; case '?': default: usage(); @@ -122,23 +140,23 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (kernfile != NULL) { + kernconfdump(kernfile); + exit(EXIT_SUCCESS); + } + if (argc != 1) usage(); PREFIX = *argv; - fp = fopen(PREFIX, "r"); - if (fp == NULL) + /* + * We mark lack of DEFAULTS here. Once we hit EOF in PREFIX, yywrap() + * will try to bring DEFAULTS to the playground, if this exists. + */ + found_defaults = 0; + if (freopen(PREFIX, "r", stdin) == NULL) err(2, "%s", PREFIX); - fclose(fp); - if (freopen("DEFAULTS", "r", stdin) != NULL) { - found_defaults = 1; - yyfile = "DEFAULTS"; - } else { - if (freopen(PREFIX, "r", stdin) == NULL) - err(2, "%s", PREFIX); - yyfile = PREFIX; - } - + yyfile = PREFIX; if (*destdir != '\0') { len = strlen(destdir); while (len > 1 && destdir[len - 1] == '/') @@ -156,11 +174,16 @@ main(int argc, char **argv) } else if (!S_ISDIR(buf.st_mode)) errx(2, "%s isn't a directory", p); + SLIST_INIT(&cputype); + SLIST_INIT(&mkopt); + SLIST_INIT(&opt); + SLIST_INIT(&rmopts); + STAILQ_INIT(&cfgfiles); STAILQ_INIT(&dtab); STAILQ_INIT(&fntab); - SLIST_INIT(&cputype); STAILQ_INIT(&ftab); STAILQ_INIT(&hints); + STAILQ_INIT(&rmdtab); if (yyparse()) exit(3); @@ -206,12 +229,12 @@ main(int argc, char **argv) (void) unlink(path(machinearch)); (void) symlink(xxx, path(machinearch)); } + configfile(); /* put config file into kernel*/ options(); /* make options .h files */ makefile(); /* build Makefile */ makeenv(); /* build env.c */ makehints(); /* build hints.c */ headers(); /* make a lot of .h files */ - configfile(); /* put config file into kernel*/ cleanheaders(p); printf("Kernel build directory is %s\n", p); printf("Don't forget to do ``make cleandepend && make depend''\n"); @@ -235,8 +258,9 @@ static void usage(void) { - fprintf(stderr, "usage: config [-Vgp] [-d destdir] sysname\n"); - exit(1); + fprintf(stderr, "usage: config [-CgpV] [-d destdir] sysname\n"); + fprintf(stderr, " config -x kernel\n"); + exit(EX_USAGE); } /* @@ -362,40 +386,119 @@ path(const char *file) return (cp); } +/* + * Generate configuration file based on actual settings. With this mode, user + * will be able to obtain and build conifguration file with one command. + */ +static void +configfile_dynamic(struct sbuf *sb) +{ + struct cputype *cput; + struct device *d; + struct opt *ol; + char *lend; + + asprintf(&lend, "\\n\\\n"); + assert(lend != NULL); + sbuf_printf(sb, "options\t%s%s", OPT_AUTOGEN, lend); + sbuf_printf(sb, "ident\t%s%s", ident, lend); + sbuf_printf(sb, "machine\t%s%s", machinename, lend); + SLIST_FOREACH(cput, &cputype, cpu_next) + sbuf_printf(sb, "cpu\t%s%s", cput->cpu_name, lend); + SLIST_FOREACH(ol, &mkopt, op_next) + sbuf_printf(sb, "makeoptions\t%s=%s%s", ol->op_name, + ol->op_value, lend); + SLIST_FOREACH(ol, &opt, op_next) { + if (strncmp(ol->op_name, "DEV_", 4) == 0) + continue; + sbuf_printf(sb, "options\t%s", ol->op_name); + if (ol->op_value != NULL) { + sbuf_printf(sb, "=%s%s", ol->op_value, lend); + } else { + sbuf_printf(sb, "%s", lend); + } + } + /* + * Mark this file as containing everything we need. + */ + STAILQ_FOREACH(d, &dtab, d_next) + sbuf_printf(sb, "device\t%s%s", d->d_name, lend); + free(lend); +} + +/* + * Generate file from the configuration files. + */ +static void +configfile_filebased(struct sbuf *sb) +{ + FILE *cff; + struct cfgfile *cf; + int i; + + STAILQ_FOREACH(cf, &cfgfiles, cfg_next) { + cff = fopen(cf->cfg_path, "r"); + if (cff == NULL) { + warn("Couldn't open file %s", cf->cfg_path); + continue; + } + while ((i = getc(cff)) != EOF) { + if (i == '\n') + sbuf_printf(sb, "\\n\\\n"); + else if (i == '"' || i == '\'') + sbuf_printf(sb, "\\%c", i); + else + sbuf_putc(sb, i); + } + fclose(cff); + } +} + static void configfile(void) { - FILE *fi, *fo; + FILE *fo; + struct sbuf *sb; char *p; - int i; - - fi = fopen(PREFIX, "r"); - if (!fi) - err(2, "%s", PREFIX); - fo = fopen(p=path("config.c.new"), "w"); + + /* Add main configuration file to the list of files to be included */ + cfgfile_add(PREFIX); + p = path("config.c.new"); + fo = fopen(p, "w"); if (!fo) err(2, "%s", p); - fprintf(fo, "#include \"opt_config.h\"\n"); - fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n"); - fprintf(fo, "const char config[] = \"\\\n"); - fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX); - while (EOF != (i=getc(fi))) { - if (i == '\n') { - fprintf(fo, "\\n\\\n___"); - } else if (i == '\"') { - fprintf(fo, "\\\""); - } else if (i == '\\') { - fprintf(fo, "\\\\"); - } else { - putc(i, fo); - } + sb = sbuf_new(NULL, NULL, 2048, SBUF_AUTOEXTEND); + assert(sb != NULL); + sbuf_clear(sb); + /* + * Try to read all configuration files. Since those will be present as + * C string in the macro, we have to slash their ends then the line + * wraps. + */ + if (filebased) { + /* Is needed, can be used for backward compatibility. */ + configfile_filebased(sb); + } else { + configfile_dynamic(sb); } - fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX); - fprintf(fo, "\";\n"); - fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n"); - fclose(fi); + sbuf_finish(sb); + /* + * We print first part of the tamplate, replace our tag with + * configuration files content and later continue writing our + * template. + */ + p = strstr(kernconfstr, KERNCONFTAG); + if (p == NULL) + errx(EXIT_FAILURE, "Something went terribly wrong!"); + *p = '\0'; + fprintf(fo, "%s", kernconfstr); + fprintf(fo, "%s", sbuf_data(sb)); + p += strlen(KERNCONFTAG); + fprintf(fo, "%s", p); + sbuf_delete(sb); fclose(fo); moveifchanged(path("config.c.new"), path("config.c")); + cfgfile_removeall(); } /* @@ -524,3 +627,57 @@ remember(const char *file) hl->h_next = htab; htab = hl; } + +/* + * This one is quick hack. Will be probably moved to elf(3) interface. + * It takes kernel configuration file name, passes it as an argument to + * elfdump -a, which output is parsed by some UNIX tools... + */ +static void +kernconfdump(const char *file) +{ + struct stat st; + FILE *fp, *pp; + int error, len, osz, r; + unsigned int off, size; + char *cmd, *o; + + r = open(file, O_RDONLY); + if (r == -1) + errx(EXIT_FAILURE, "Couldn't open file '%s'", file); + error = fstat(r, &st); + if (error == -1) + errx(EXIT_FAILURE, "fstat() failed"); + if (S_ISDIR(st.st_mode)) + errx(EXIT_FAILURE, "'%s' is a directory", file); + fp = fdopen(r, "r"); + if (fp == NULL) + errx(EXIT_FAILURE, "fdopen() failed"); + osz = 1024; + o = calloc(1, osz); + if (o == NULL) + errx(EXIT_FAILURE, "Couldn't allocate memory"); + /* ELF note section header. */ + asprintf(&cmd, "/usr/bin/elfdump -c %s | grep -A 5 kern_conf" + "| tail -2 | cut -d ' ' -f 2 | paste - - -", file); + if (cmd == NULL) + errx(EXIT_FAILURE, "asprintf() failed"); + pp = popen(cmd, "r"); + if (pp == NULL) + errx(EXIT_FAILURE, "popen() failed"); + free(cmd); + len = fread(o, osz, 1, pp); + pclose(pp); + r = sscanf(o, "%d\t%d", &off, &size); + free(o); + if (r != 2) + errx(EXIT_FAILURE, "File %s doesn't contain configuration " + "file. Either unsupported, or not compiled with " + "INCLUDE_CONFIG_FILE", file); + r = fseek(fp, off, SEEK_CUR); + if (r != 0) + errx(EXIT_FAILURE, "fseek() failed"); + while ((r = fgetc(fp)) != EOF && size-- > 0) + fputc(r, stdout); + fclose(fp); +}