--- src.o/sys/kern/kern_mib.c Sun Aug 21 18:03:31 2005 +++ src/sys/kern/kern_mib.c Wed Mar 21 06:17:57 2007 @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -294,6 +295,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, diff -ur src.o/usr.sbin/config/Makefile src/usr.sbin/config/Makefile --- src.o/usr.sbin/config/Makefile Fri Dec 9 06:46:40 2005 +++ src/usr.sbin/config/Makefile Sat Mar 17 20:46:58 2007 @@ -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 -ur src.o/usr.sbin/config/config.8 src/usr.sbin/config/config.8 --- src.o/usr.sbin/config/config.8 Sat Oct 21 20:09:51 2006 +++ src/usr.sbin/config/config.8 Wed Mar 21 06:17:57 2007 @@ -38,6 +38,7 @@ .Nm .Op Fl Vgp .Op Fl d Ar destdir +.Op Fl k Ar kernel .Ar SYSTEM_NAME .Sh DESCRIPTION .\" This is the old version of the @@ -87,6 +88,8 @@ to the directory given. .It Fl g Configure a system for debugging. +.It Fl k Ar kernel +Print configuration settings of a kernel file. .It Fl p Configure a system for profiling; for example, .Xr kgmon 8 diff -ur src.o/usr.sbin/config/config.h src/usr.sbin/config/config.h --- src.o/usr.sbin/config/config.h Tue Oct 24 00:31:59 2006 +++ src/usr.sbin/config/config.h Wed Mar 21 06:17:57 2007 @@ -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 @@ 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 @@ 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 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 -ur src.o/usr.sbin/config/config.y src/usr.sbin/config/config.y --- src.o/usr.sbin/config/config.y Tue Oct 24 00:31:59 2006 +++ src/usr.sbin/config/config.y Wed Mar 21 06:17:57 2007 @@ -70,6 +70,7 @@ * $FreeBSD: src/usr.sbin/config/config.y,v 1.76 2006/10/24 00:31:59 imp Exp $ */ +#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 @@ 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 @@ Config_spec SEMICOLON | INCLUDE ID SEMICOLON - = { include($2, 0); }; + = { + if (incignore == 0) + include($2, 0); + }; | FILES ID SEMICOLON = { newfile($2); }; @@ -170,11 +177,11 @@ 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 @@ = { 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 @@ 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 @@ * 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 @@ { struct device *np; - if (finddev(name)) { + if (finddev(&dtab, name)) { printf("WARNING: duplicate device `%s' encountered.\n", name); return; } @@ -375,17 +384,36 @@ } /* - * 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 @@ { 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 @@ * 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); } } Only in src/usr.sbin/config/: kernconf.tmpl diff -ur src.o/usr.sbin/config/lang.l src/usr.sbin/config/lang.l --- src.o/usr.sbin/config/lang.l Sat Dec 3 20:04:24 2005 +++ src/usr.sbin/config/lang.l Sat Mar 17 20:46:58 2007 @@ -207,6 +207,30 @@ 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 @@ 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 @@ 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 -ur src.o/usr.sbin/config/main.c src/usr.sbin/config/main.c --- src.o/usr.sbin/config/main.c Tue Oct 24 00:31:59 2006 +++ src/usr.sbin/config/main.c Wed Mar 21 06:17:59 2007 @@ -43,9 +43,12 @@ #include #include +#include #include #include #include + +#include #include #include #include @@ -73,11 +76,13 @@ int debugging; int profiling; int found_defaults; +int incignore; 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,9 +101,10 @@ 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, "d:gk:pV")) != -1) switch (ch) { case 'V': printf("%d\n", CONFIGVERS); @@ -112,6 +118,9 @@ case 'g': debugging++; break; + case 'k': + kernfile = optarg; + break; case 'p': profiling++; break; @@ -122,23 +131,23 @@ 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 +165,16 @@ } 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 +220,12 @@ (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,7 +249,8 @@ usage(void) { - fprintf(stderr, "usage: config [-Vgp] [-d destdir] sysname\n"); + fprintf(stderr, "usage: config [[-Vgp] [-d destdir] sysname |" + " [-k kernel]]\n"); exit(1); } @@ -362,40 +377,125 @@ 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"); + int filebased; + + /* + * This is hint to make sure we're able to support old behaviour. + */ + filebased = 0; + + /* 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(); } /* @@ -523,4 +623,49 @@ hl->h_name = s; 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) +{ + FILE *fp; + int len, osz, r; + unsigned int off, size; + char *cmd, *o; + + osz = 1024; + o = calloc(1, osz); + assert(o != 0); + asprintf(&cmd, "/usr/bin/elfdump -c %s | grep -A 5 kern_conf" + "| tail -2 | cut -d ' ' -f 2 | paste - - -", file); + assert(cmd != NULL); + fp = popen(cmd, "r"); + free(cmd); + assert(fp != NULL); + len = fread(o, osz, 1, fp); + pclose(fp); + r = sscanf(o, "%d\t%d", &off, &size); + /* ELF note section header. */ + if (r != 2) + errx(EXIT_FAILURE, "File %s doesn't contain configuration " + "file. Either unsupported, or not compiled with " + "INCLUDE_CONFIG_FILE", file); + free(o); + o = calloc(1, size); + assert(o != NULL); + osz = size; + fp = fopen(file, "r"); + r = fseek(fp, off, SEEK_CUR); + assert(r == 0); + while ((r = fgetc(fp)) != EOF && osz > 0) { + fputc(r, stdout); + osz--; + } + fclose(fp); + free(o); } Only in src/usr.sbin/config/: tags