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 <kernelfile> 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@
This commit is contained in:
parent
fbe4fc2ec0
commit
744b947ef8
@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/proc.h>
|
||||
@ -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");
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -38,6 +38,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
|
@ -70,6 +70,7 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
17
usr.sbin/config/kernconf.tmpl
Normal file
17
usr.sbin/config/kernconf.tmpl
Normal file
@ -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 */
|
@ -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;
|
||||
|
@ -43,9 +43,12 @@ static const char rcsid[] =
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user