config(8): De-dupe hint/env vars within a single file

r335653 flipped the order in which hints/env files are concatenated to match
the order in which vars are processed by the kernel. This is the other
hammer to drop.

Use nv(9) to de-dupe entries within a single `hint` or `env` file, using the
latest value specified for a key. This leaves some duplicates if a variable
is specified in multiple hint/env files or via `envvar` in a kernel config,
but the reversed order of concatenation (from r335653) makes this a
non-issue as the latest-specified version will be seen first.

This change also silently rewrote hint bits to use the same sanitization
process that ian@ wrote for r335642. To the kernel, hints and env vars are
basically the same thing through early boot, then get merged into the
dynamic environment once kmem becomes available and the dynamic environment
is created. They should be subjected to the same restrictions.

libnv has been added to -legacy for the time being to support the build of
config(8) with the new cnvlist API.

Tested with:	universe (11 host & 12 host)
MFC after:	1 month
This commit is contained in:
kevans 2018-07-06 01:11:06 +00:00
parent 107a344bbb
commit d6f6a2a154
3 changed files with 105 additions and 76 deletions

View File

@ -1941,13 +1941,19 @@ update: .PHONY
_elftoolchain_libs= lib/libelf lib/libdwarf
.endif
# An updated libnv is needed for the cnv(9) API used in config(8).
# r335343 stabilized the cnvlist API used by config(8)
.if ${BOOTSTRAPPING} < 1200070
_libnv= lib/libnv
.endif
legacy: .PHONY
.if ${BOOTSTRAPPING} < ${MINIMUM_SUPPORTED_OSREL} && ${BOOTSTRAPPING} != 0
@echo "ERROR: Source upgrades from versions prior to ${MINIMUM_SUPPORTED_REL} are not supported."; \
false
.endif
.for _tool in tools/build ${_elftoolchain_libs}
.for _tool in tools/build ${_elftoolchain_libs} ${_libnv}
${_+_}@${ECHODIR} "===> ${_tool} (obj,includes,all,install)"; \
cd ${.CURDIR}/${_tool}; \
if [ -z "${NO_OBJWALK}" ]; then ${MAKE} DIRPRFX=${_tool}/ obj; fi; \

View File

@ -14,11 +14,11 @@ kernconf.c: kernconf.tmpl
${FILE2C} 'char kernconfstr[] = {' ',0};' < \
${SRCDIR}/kernconf.tmpl > kernconf.c
CFLAGS+= -I. -I${SRCDIR}
CFLAGS+= -I. -I${SRCDIR} -I${SRCTOP}/sys
NO_WMISSING_VARIABLE_DECLARATIONS=
LIBADD= l sbuf
LIBADD= l nv sbuf
CLEANFILES+= kernconf.c

View File

@ -49,6 +49,8 @@ static const char rcsid[] =
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/cnv.h>
#include <sys/nv.h>
#include <sys/param.h>
#include "y.tab.h"
#include "config.h"
@ -62,6 +64,10 @@ static void do_objs(FILE *);
static void do_before_depend(FILE *);
static int opteq(const char *, const char *);
static void read_files(void);
static void sanitize_envline(char *result, const char *src);
static void process_into_file(char *line, FILE *ofp);
static void process_into_nvlist(char *line, nvlist_t *nvl);
static void dump_nvlist(nvlist_t *nvl, FILE *ofp);
static void errout(const char *fmt, ...)
{
@ -180,64 +186,6 @@ makefile(void)
moveifchanged(path("Makefile.new"), path("Makefile"));
}
/*
* Build hints.c from the skeleton
*/
void
makehints(void)
{
FILE *ifp, *ofp;
char line[BUFSIZ];
char *s;
struct hint *hint;
ofp = fopen(path("hints.c.new"), "w");
if (ofp == NULL)
err(1, "%s", path("hints.c.new"));
fprintf(ofp, "#include <sys/types.h>\n");
fprintf(ofp, "#include <sys/systm.h>\n");
fprintf(ofp, "\n");
fprintf(ofp, "char static_hints[] = {\n");
STAILQ_FOREACH(hint, &hints, hint_next) {
ifp = fopen(hint->hint_name, "r");
if (ifp == NULL)
err(1, "%s", hint->hint_name);
while (fgets(line, BUFSIZ, ifp) != NULL) {
/* zap trailing CR and/or LF */
while ((s = strrchr(line, '\n')) != NULL)
*s = '\0';
while ((s = strrchr(line, '\r')) != NULL)
*s = '\0';
/* remove # comments */
s = strchr(line, '#');
if (s)
*s = '\0';
/* remove any whitespace and " characters */
s = line;
while (*s) {
if (*s == ' ' || *s == '\t' || *s == '"') {
while (*s) {
s[0] = s[1];
s++;
}
/* start over */
s = line;
continue;
}
s++;
}
/* anything left? */
if (*line == '\0')
continue;
fprintf(ofp, "\"%s\\0\"\n", line);
}
fclose(ifp);
}
fprintf(ofp, "\"\\0\"\n};\n");
fclose(ofp);
moveifchanged(path("hints.c.new"), path("hints.c"));
}
static void
sanitize_envline(char *result, const char *src)
{
@ -295,6 +243,87 @@ sanitize_envline(char *result, const char *src)
*dst = 0;
}
static void
process_into_file(char *line, FILE *ofp)
{
char result[BUFSIZ];
sanitize_envline(result, line);
/* anything left? */
if (*result == '\0')
return;
fprintf(ofp, "\"%s\\0\"\n", result);
}
static void
process_into_nvlist(char *line, nvlist_t *nvl)
{
char result[BUFSIZ], *s;
sanitize_envline(result, line);
/* anything left? */
if (*result == '\0')
return;
s = strchr(result, '=');
*s = 0;
if (nvlist_exists(nvl, result))
nvlist_free(nvl, result);
nvlist_add_string(nvl, result, s + 1);
}
static void
dump_nvlist(nvlist_t *nvl, FILE *ofp)
{
const char *name;
void *cookie;
if (nvl == NULL)
return;
while (!nvlist_empty(nvl)) {
cookie = NULL;
name = nvlist_next(nvl, NULL, &cookie);
fprintf(ofp, "\"%s=%s\\0\"\n", name,
cnvlist_get_string(cookie));
cnvlist_free_string(cookie);
}
}
/*
* Build hints.c from the skeleton
*/
void
makehints(void)
{
FILE *ifp, *ofp;
nvlist_t *nvl;
char line[BUFSIZ];
struct hint *hint;
ofp = fopen(path("hints.c.new"), "w");
if (ofp == NULL)
err(1, "%s", path("hints.c.new"));
fprintf(ofp, "#include <sys/types.h>\n");
fprintf(ofp, "#include <sys/systm.h>\n");
fprintf(ofp, "\n");
fprintf(ofp, "char static_hints[] = {\n");
nvl = nvlist_create(0);
STAILQ_FOREACH(hint, &hints, hint_next) {
ifp = fopen(hint->hint_name, "r");
if (ifp == NULL)
err(1, "%s", hint->hint_name);
while (fgets(line, BUFSIZ, ifp) != NULL)
process_into_nvlist(line, nvl);
dump_nvlist(nvl, ofp);
fclose(ifp);
}
nvlist_destroy(nvl);
fprintf(ofp, "\"\\0\"\n};\n");
fclose(ofp);
moveifchanged(path("hints.c.new"), path("hints.c"));
}
/*
* Build env.c from the skeleton
*/
@ -302,7 +331,8 @@ void
makeenv(void)
{
FILE *ifp, *ofp;
char line[BUFSIZ], result[BUFSIZ], *linep;
nvlist_t *nvl;
char line[BUFSIZ];
struct envvar *envvar;
ofp = fopen(path("env.c.new"), "w");
@ -312,27 +342,20 @@ makeenv(void)
fprintf(ofp, "#include <sys/systm.h>\n");
fprintf(ofp, "\n");
fprintf(ofp, "char static_env[] = {\n");
nvl = nvlist_create(0);
STAILQ_FOREACH(envvar, &envvars, envvar_next) {
if (envvar->env_is_file) {
ifp = fopen(envvar->env_str, "r");
if (ifp == NULL)
err(1, "%s", envvar->env_str);
while (fgets(line, BUFSIZ, ifp) != NULL) {
sanitize_envline(result, line);
/* anything left? */
if (*result == '\0')
continue;
fprintf(ofp, "\"%s\\0\"\n", result);
}
while (fgets(line, BUFSIZ, ifp) != NULL)
process_into_nvlist(line, nvl);
dump_nvlist(nvl, ofp);
fclose(ifp);
} else {
linep = envvar->env_str;
sanitize_envline(result, linep);
if (*result == '\0')
continue;
fprintf(ofp, "\"%s\\0\"\n", result);
}
} else
process_into_file(envvar->env_str, ofp);
}
nvlist_destroy(nvl);
fprintf(ofp, "\"\\0\"\n};\n");
fclose(ofp);
moveifchanged(path("env.c.new"), path("env.c"));