svn commit: r337333 - in stable/11: . sys/kern sys/sys tools/build usr.sbin/config

Kyle Evans kevans at FreeBSD.org
Sat Aug 4 21:57:20 UTC 2018


Author: kevans
Date: Sat Aug  4 21:57:17 2018
New Revision: 337333
URL: https://svnweb.freebsd.org/changeset/base/337333

Log:
  kenv MFC: r335998, r336019, r336026, r336036, r336217, r336335, r336337,
  r336415-r336416, r336419
  
  As an aside- this has been slightly altered from the version in head to keep
  the MD and config-static environments mutually exclusive by default.
  
  This difference is a one-line change in init_static_kenv to setup the MD
  environment if the config-static environment is empty or if
  loader_env.disabled is explicitly set to 0.
  
  r335998:
  kern_environment: use any provided environments, evict hintmode/envmode
  
  At the moment, hintmode and envmode are used to indicate whether static
  hints or static env have been provided in the kernel config(5) and the
  static versions are mutually exclusive with loader(8)-provided environment.
  hintmode *can* be reconfigured later to pull from the dynamic environment,
  thus taking advantage of the loader(8) or post-kmem environment setting.
  
  This changeset fixes both problems at once to move us from a semi-confusing
  state to a consistent state: if an environment file, hints file, or
  loader(8) environment are provided, we use them in a well-known order of
  precedence:
  
  - loader(8) environment
  - static environment
  - static hints file
  
  Once the dynamic environment is setup this becomes a moot point. The
  loader(8) and static environments are merged (respecting the above order of
  precedence), and the static hints are merged in on an as-needed basis after
  the dynamic environment has been setup.
  
  Hints lookup are changed to respect all of the above. Before the dynamic
  environment is setup, lookups use the above-mentioned order and fallback to
  the next environment if a matching hint is not found. Once the dynamic
  environment is setup, that is used on its own since it captures all of the
  above information plus any dynamic kenv settings that came up later in boot.
  
  The following tangentially related changes were made to res_find:
  
  - A hintp cookie is now passed in so that related searches continue using
    the chain of environments (or dynamic environment) without relying on
    global state
  - All three environments will be searched if they actually have valid hints
    to use, rather than just choosing the first environment that actually had
    a hint and rolling with that only
  
  The hintmode sysctl has been ripped out. static_{env,hints}.disabled are
  still honored and will disable their respective environments from being used
  for hint lookups and from being merged into the dynamic environment, as
  expected.
  
  r336019:
  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.
  
  r336026:
  config(8): Fix broken ABI
  
  r336019 introduced ${SRCTOP}/sys to the include paths in order to pull in a
  new sys/{c,}nv.h. This is wrong, because the build tree's ABI isn't
  guaranteed to match what's running on the host system.
  
  Fix instead by removing -I${SRCTOP}/sys and installing the libnv headers
  with `make -C lib/libnv includes`... this may or may not get re-worked in
  the future so that a userland lib isn't installing includes from sys/.
  
  r336036:
  kern_environment: Fix SYSINIT ordering
  
  The dynamic environment was being initialized at SI_SUB_KMEM, SI_ORDER_ANY.
  I added the hint-merging at SI_SUB_KMEM, SI_ORDER_ANY as well in r335998 -
  this can only work by coincidence.
  
  Re-do both to operate at SI_SUB_KMEM + 1, SI_ORDER_FIRST and SI_ORDER_SECOND
  respectively to be safe. It's sufficiently obfuscated away as to when in
  SU_SUB_KMEM malloc will be available, and the dynamic environment cannot be
  relied upon there anyways since it's initialized at SI_ORDER_ANY.
  
  r336217:
  kern_environment: Give the static environment a chance to disable MD env
  
  This variable has been given the name "loader_env.disabled" as it's the
  primary way most people will have an MD environment. This restores the
  previously-default behavior of ignoring the loader(8) environment, which may
  be useful for vendor distributions or other scenarios where inheriting the
  loader environment may be considered a security issue or potentially
  breaking of a more locked-down environment.
  
  As the change to config(5) indicates, disabling the loader environment
  should not be a choice made lightly since it may provide ACPI hints and
  other useful things that the system can rely on to boot.
  
  An UPDATING entry has been added to mention an upgrade path for those that
  may have relied on the previous behavior.
  
  r336335 by arichardson:
  No longer install sys/nv.h and sys/cnv.h in lib/libnv/Makefile
  
  Use tools/build/Makefile to install the headers into ${WORLDTMP}/legacy
  instead. Compared to r336026 this has the minor advantage that it avoids
  unncessary header installation when building the non-bootstrap libnv.
  
  r336337:
  Unconditionally build libnv in legacy
  
  Rather than using a config(8) built from new tree linking libnv built on
  host.
  
  r336415:
  config(8): Add compatibility shims for r335998
  
  Plumb the %VERSREQ from Makefile.<arch> through to the rest of config(8).
  We've recorded the config(8) version that we're calling "the end of
  envmode and hintmode," and we'll write them out for earlier versions. Later
  kernel version bumps will remove envmode/hintmode from the kernel as needed,
  which is OK since the current kernel does not use them at all.
  
  These compatibility shims really need to go away when the major version
  rolls over...
  
  r336416:
  Fix GCC 4.2 build after r336415, proper declaration and prototype
  
  r336419:
  config(8): Invert checks; envmode/hintmode reflect "env provided"
  
  Relnotes:	yes (maybe) [The loader environment may now be used with
  the config-static environment by specifying loader_env.disabled=0 in the
  config-static environment]

Modified:
  stable/11/Makefile.inc1
  stable/11/sys/kern/kern_environment.c
  stable/11/sys/kern/subr_hints.c
  stable/11/sys/sys/systm.h
  stable/11/tools/build/Makefile
  stable/11/usr.sbin/config/Makefile
  stable/11/usr.sbin/config/config.5
  stable/11/usr.sbin/config/config.h
  stable/11/usr.sbin/config/config.y
  stable/11/usr.sbin/config/configvers.h
  stable/11/usr.sbin/config/main.c
  stable/11/usr.sbin/config/mkmakefile.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/Makefile.inc1
==============================================================================
--- stable/11/Makefile.inc1	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/Makefile.inc1	Sat Aug  4 21:57:17 2018	(r337333)
@@ -1629,7 +1629,7 @@ legacy: .PHONY
 	@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} lib/libnv
 	${_+_}@${ECHODIR} "===> ${_tool} (obj,includes,all,install)"; \
 	    cd ${.CURDIR}/${_tool}; \
 	    ${MAKE} DIRPRFX=${_tool}/ obj; \

Modified: stable/11/sys/kern/kern_environment.c
==============================================================================
--- stable/11/sys/kern/kern_environment.c	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/sys/kern/kern_environment.c	Sat Aug  4 21:57:17 2018	(r337333)
@@ -55,14 +55,21 @@ __FBSDID("$FreeBSD$");
 
 #include <security/mac/mac_framework.h>
 
+static char *_getenv_dynamic_locked(const char *name, int *idx);
+static char *_getenv_dynamic(const char *name, int *idx);
+
 static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
 
 #define KENV_SIZE	512	/* Maximum number of environment strings */
 
-/* pointer to the static environment */
+/* pointer to the config-generated static environment */
 char		*kern_envp;
-static int	env_len;
-static int	env_pos;
+
+/* pointer to the md-static environment */
+char		*md_envp;
+static int	md_env_len;
+static int	md_env_pos;
+
 static char	*kernenv_next(char *);
 
 /* dynamic environment variables */
@@ -218,16 +225,9 @@ done:
  * environment obtained from a boot loader, or to provide an empty buffer into
  * which MD code can store an initial environment using kern_setenv() calls.
  *
- * When a copy of an initial environment is passed in, we start by scanning that
- * env for overrides to the compiled-in envmode and hintmode variables.
+ * kern_envp is set to the static_env generated by config(8).  This implements
+ * the env keyword described in config(5).
  *
- * If the global envmode is 1, the environment is initialized from the global
- * static_env[], regardless of the arguments passed.  This implements the env
- * keyword described in config(5).  In this case env_pos is set to env_len,
- * causing kern_setenv() to return -1 (if len > 0) or panic (if len == 0) until
- * the dynamic environment is available.  The envmode and static_env variables
- * are defined in env.c which is generated by config(8).
- *
  * If len is non-zero, the caller is providing an empty buffer.  The caller will
  * subsequently use kern_setenv() to add up to len bytes of initial environment
  * before the dynamic environment is available.
@@ -235,72 +235,126 @@ done:
  * If len is zero, the caller is providing a pre-loaded buffer containing
  * environment strings.  Additional strings cannot be added until the dynamic
  * environment is available.  The memory pointed to must remain stable at least
- * until sysinit runs init_dynamic_kenv().  If no initial environment is
- * available from the boot loader, passing a NULL pointer allows the static_env
- * to be installed if it is configured.
+ * until sysinit runs init_dynamic_kenv() and preferably until after SI_SUB_KMEM
+ * is finished so that subr_hints routines may continue to use it until the
+ * environments have been fully merged at the end of the pass.  If no initial
+ * environment is available from the boot loader, passing a NULL pointer allows
+ * the static_env to be installed if it is configured.  In this case, any call
+ * to kern_setenv() prior to the setup of the dynamic environment will result in
+ * a panic.
  */
 void
 init_static_kenv(char *buf, size_t len)
 {
-	char *cp;
-	
-	for (cp = buf; cp != NULL && cp[0] != '\0'; cp += strlen(cp) + 1) {
-		if (strcmp(cp, "static_env.disabled=1") == 0)
-			envmode = 0;
-		if (strcmp(cp, "static_hints.disabled=1") == 0)
-			hintmode = 0;
-	}
+	char *eval;
 
-	if (envmode == 1) {
-		kern_envp = static_env;
-		env_len = len;
-		env_pos = len;
-	} else {
-		kern_envp = buf;
-		env_len = len;
-		env_pos = 0;
+	/*
+	 * Give the static environment a chance to disable the loader(8)
+	 * environment first.  This is done with loader_env.disabled=1.
+	 *
+	 * static_env and static_hints may both be disabled, but in slightly
+	 * different ways.  For static_env, we just don't setup kern_envp and
+	 * it's as if a static env wasn't even provided.  For static_hints,
+	 * we effectively zero out the buffer to stop the rest of the kernel
+	 * from being able to use it.
+	 *
+	 * We're intentionally setting this up so that static_hints.disabled may
+	 * be specified in either the MD env or the static env. This keeps us
+	 * consistent in our new world view.
+	 *
+	 * As a warning, the static environment may not be disabled in any way
+	 * if the static environment has disabled the loader environment.
+	 */
+	kern_envp = static_env;
+	eval = kern_getenv("loader_env.disabled");
+	if (*kern_envp == '\0' || (eval != NULL && strcmp(eval, "0") == 0)) {
+		md_envp = buf;
+		md_env_len = len;
+		md_env_pos = 0;
+
+		eval = kern_getenv("static_env.disabled");
+		if (eval != NULL && strcmp(eval, "1") == 0)
+			*kern_envp = '\0';
 	}
+	eval = kern_getenv("static_hints.disabled");
+	if (eval != NULL && strcmp(eval, "1") == 0)
+		*static_hints = '\0';
 }
 
-/*
- * Setup the dynamic kernel environment.
- */
 static void
-init_dynamic_kenv(void *data __unused)
+init_dynamic_kenv_from(char *init_env, int *curpos)
 {
-	char *cp, *cpnext;
+	char *cp, *cpnext, *eqpos, *found;
 	size_t len;
 	int i;
 
-	kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
-		M_WAITOK | M_ZERO);
-	i = 0;
-	if (kern_envp && *kern_envp != '\0') {
-		for (cp = kern_envp; cp != NULL; cp = cpnext) {
+	if (init_env && *init_env != '\0') {
+		found = NULL;
+		i = *curpos;
+		for (cp = init_env; cp != NULL; cp = cpnext) {
 			cpnext = kernenv_next(cp);
 			len = strlen(cp) + 1;
 			if (len > KENV_MNAMELEN + 1 + KENV_MVALLEN + 1) {
 				printf(
 				"WARNING: too long kenv string, ignoring %s\n",
 				    cp);
-				continue;
+				goto sanitize;
 			}
-			if (i < KENV_SIZE) {
-				kenvp[i] = malloc(len, M_KENV, M_WAITOK);
-				strcpy(kenvp[i++], cp);
-				explicit_bzero(cp, strlen(cp));
-			} else
+			eqpos = strchr(cp, '=');
+			if (eqpos == NULL) {
 				printf(
+				"WARNING: malformed static env value, ignoring %s\n",
+				    cp);
+				goto sanitize;
+			}
+			*eqpos = 0;
+			/*
+			 * De-dupe the environment as we go.  We don't add the
+			 * duplicated assignments because config(8) will flip
+			 * the order of the static environment around to make
+			 * kernel processing match the order of specification
+			 * in the kernel config.
+			 */
+			found = _getenv_dynamic_locked(cp, NULL);
+			*eqpos = '=';
+			if (found != NULL)
+				goto sanitize;
+			if (i > KENV_SIZE) {
+				printf(
 				"WARNING: too many kenv strings, ignoring %s\n",
 				    cp);
+				goto sanitize;
+			}
+
+			kenvp[i] = malloc(len, M_KENV, M_WAITOK);
+			strcpy(kenvp[i++], cp);
+sanitize:
+			explicit_bzero(cp, len - 1);
 		}
+		*curpos = i;
 	}
-	kenvp[i] = NULL;
+}
 
+/*
+ * Setup the dynamic kernel environment.
+ */
+static void
+init_dynamic_kenv(void *data __unused)
+{
+	int dynamic_envpos;
+
+	kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
+		M_WAITOK | M_ZERO);
+
+	dynamic_envpos = 0;
+	init_dynamic_kenv_from(md_envp, &dynamic_envpos);
+	init_dynamic_kenv_from(kern_envp, &dynamic_envpos);
+	kenvp[dynamic_envpos] = NULL;
+
 	mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
 	dynamic_kenv = 1;
 }
-SYSINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, init_dynamic_kenv, NULL);
+SYSINIT(kenv, SI_SUB_KMEM + 1, SI_ORDER_FIRST, init_dynamic_kenv, NULL);
 
 void
 freeenv(char *env)
@@ -316,12 +370,11 @@ freeenv(char *env)
  * Internal functions for string lookup.
  */
 static char *
-_getenv_dynamic(const char *name, int *idx)
+_getenv_dynamic_locked(const char *name, int *idx)
 {
 	char *cp;
 	int len, i;
 
-	mtx_assert(&kenv_lock, MA_OWNED);
 	len = strlen(name);
 	for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
 		if ((strncmp(cp, name, len) == 0) &&
@@ -335,12 +388,20 @@ _getenv_dynamic(const char *name, int *idx)
 }
 
 static char *
-_getenv_static(const char *name)
+_getenv_dynamic(const char *name, int *idx)
 {
+
+	mtx_assert(&kenv_lock, MA_OWNED);
+	return (_getenv_dynamic_locked(name, idx));
+}
+
+static char *
+_getenv_static_from(char *chkenv, const char *name)
+{
 	char *cp, *ep;
 	int len;
 
-	for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
+	for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) {
 		for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
 			;
 		if (*ep != '=')
@@ -353,6 +414,20 @@ _getenv_static(const char *name)
 	return (NULL);
 }
 
+static char *
+_getenv_static(const char *name)
+{
+	char *val;
+
+	val = _getenv_static_from(md_envp, name);
+	if (val != NULL)
+		return (val);
+	val = _getenv_static_from(kern_envp, name);
+	if (val != NULL)
+		return (val);
+	return (NULL);
+}
+
 /*
  * Look up an environment variable by name.
  * Return a pointer to the string if found.
@@ -397,20 +472,25 @@ testenv(const char *name)
 	return (0);
 }
 
+/*
+ * Set an environment variable in the MD-static environment.  This cannot
+ * feasibly be done on config(8)-generated static environments as they don't
+ * generally include space for extra variables.
+ */
 static int
 setenv_static(const char *name, const char *value)
 {
 	int len;
 
-	if (env_pos >= env_len)
+	if (md_env_pos >= md_env_len)
 		return (-1);
 
 	/* Check space for x=y and two nuls */
 	len = strlen(name) + strlen(value);
-	if (len + 3 < env_len - env_pos) {
-		len = sprintf(&kern_envp[env_pos], "%s=%s", name, value);
-		env_pos += len+1;
-		kern_envp[env_pos] = '\0';
+	if (len + 3 < md_env_len - md_env_pos) {
+		len = sprintf(&md_envp[md_env_pos], "%s=%s", name, value);
+		md_env_pos += len+1;
+		md_envp[md_env_pos] = '\0';
 		return (0);
 	} else
 		return (-1);
@@ -426,7 +506,7 @@ kern_setenv(const char *name, const char *value)
 	char *buf, *cp, *oldenv;
 	int namelen, vallen, i;
 
-	if (dynamic_kenv == 0 && env_len > 0)
+	if (dynamic_kenv == 0 && md_env_len > 0)
 		return (setenv_static(name, value));
 
 	KENV_CHECK;

Modified: stable/11/sys/kern/subr_hints.c
==============================================================================
--- stable/11/sys/kern/subr_hints.c	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/sys/kern/subr_hints.c	Sat Aug  4 21:57:17 2018	(r337333)
@@ -29,61 +29,36 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/lock.h>
+#include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
 
-#define	HINTMODE_KENV		0
-#define	HINTMODE_STATIC		1
-#define	HINTMODE_FALLBACK	2
+#define	FBACK_MDENV	0	/* MD env (e.g. loader.conf) */
+#define	FBACK_STENV	1	/* Static env */
+#define	FBACK_STATIC	2	/* static_hints */
 
 /*
- * Access functions for device resources.
+ * We'll use hintenv_merged to indicate that the dynamic environment has been
+ * properly prepared for hint usage.  This implies that the dynamic environment
+ * has already been setup (dynamic_kenv) and that we have added any supplied
+ * static_hints to the dynamic environment.
  */
+static int	hintenv_merged;
 
-static int checkmethod = 1;
-static char *hintp;
-
 /*
- * Define kern.hintmode sysctl, which only accept value 2, that cause to
- * switch from Static KENV mode to Dynamic KENV. So systems that have hints
- * compiled into kernel will be able to see/modify KENV (and hints too).
+ * Access functions for device resources.
  */
 
-static int
-sysctl_hintmode(SYSCTL_HANDLER_ARGS)
+static void
+static_hints_to_env(void *data __unused)
 {
 	const char *cp;
 	char *line, *eq;
-	int eqidx, error, i, value;
+	int eqidx, i;
 
-	value = hintmode;
-
-	/* Fetch candidate for new hintmode value */
-	error = sysctl_handle_int(oidp, &value, 0, req);
-	if (error || req->newptr == NULL)
-		return (error);
-
-	if (value != HINTMODE_FALLBACK)
-		/* Only accept swithing to hintmode 2 */
-		return (EINVAL);
-
-	/*
-	 * The rest of the sysctl handler is just making sure that our
-	 * environment is consistent with the world we've already seen.
-	 * If we came from kenv at all, then we have nothing to do: static
-	 * kenv will get merged into dynamic kenv as soon as kmem becomes
-	 * available, dynamic kenv is the environment we'd be setting these
-	 * things in anyways. Therefore, we have nothing left to do unless
-	 * we came from a static hints configuration.
-	 */
-	if (hintmode != HINTMODE_STATIC) {
-		hintmode = value;
-		return (0);
-	}
-
 	cp = static_hints;
 	while (cp && *cp != '\0') {
 		eq = strchr(cp, '=');
@@ -93,103 +68,152 @@ sysctl_hintmode(SYSCTL_HANDLER_ARGS)
 		eqidx = eq - cp;
 
 		i = strlen(cp);
-		line = malloc(i+1, M_TEMP, M_WAITOK);
+		line = malloc(i + 1, M_TEMP, M_WAITOK);
 		strcpy(line, cp);
-		line[eqidx] = '\0';
-		kern_setenv(line, line + eqidx + 1);
+		line[eqidx] = line[i] = '\0';
+		/*
+		 * Before adding a hint to the dynamic environment, check if
+		 * another value for said hint has already been added.  This is
+		 * needed because static environment overrides static hints and
+		 * dynamic environment overrides all.
+		 */
+		if (testenv(line) == 0)
+			kern_setenv(line, line + eqidx + 1);
 		free(line, M_TEMP);
 		cp += i + 1;
 	}
-
-	hintmode = value;
-	return (0);
+	hintenv_merged = 1;
 }
 
-SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW,
-    &hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode");
+/* Any time after dynamic env is setup */
+SYSINIT(hintenv, SI_SUB_KMEM + 1, SI_ORDER_SECOND, static_hints_to_env, NULL);
 
 /*
+ * Checks the environment to see if we even have any hints.  If it has no hints,
+ * then res_find can take the hint that there's no point in searching it and
+ * either move on to the next environment or fail early.
+ */
+static bool
+_res_checkenv(char *envp)
+{
+	char *cp;
+
+	cp = envp;
+	while (cp) {
+		if (strncmp(cp, "hint.", 5) == 0)
+			return (true);
+		while (*cp != '\0')
+			cp++;
+		cp++;
+		if (*cp == '\0')
+			break;
+	}
+	return (false);
+}
+
+/*
  * Evil wildcarding resource string lookup.
  * This walks the supplied env string table and returns a match.
  * The start point can be remembered for incremental searches.
  */
 static int
-res_find(int *line, int *startln,
+res_find(char **hintp_cookie, int *line, int *startln,
     const char *name, int *unit, const char *resname, const char *value,
     const char **ret_name, int *ret_namelen, int *ret_unit,
     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
 {
-	int n = 0, hit, i = 0;
+	int dyn_used = 0, fbacklvl = FBACK_MDENV, hit, i = 0, n = 0;
 	char r_name[32];
-	int r_unit, use_kenv = (hintmode != HINTMODE_STATIC && dynamic_kenv);
+	int r_unit;
 	char r_resname[32];
 	char r_value[128];
 	const char *s, *cp;
-	char *p;
+	char *hintp, *p;
 
-	if (checkmethod) {
-		hintp = NULL;
 
-		switch (hintmode) {
-		case HINTMODE_KENV:	/* loader hints in environment only */
-			break;
-		case HINTMODE_STATIC:	/* static hints only */
-			hintp = static_hints;
-			checkmethod = 0;
-			break;
-		case HINTMODE_FALLBACK:		/* fallback mode */
-			if (dynamic_kenv) {
-				mtx_lock(&kenv_lock);
-				cp = kenvp[0];
-				for (i = 0; cp != NULL; cp = kenvp[++i]) {
-					if (!strncmp(cp, "hint.", 5)) {
-						use_kenv = 1;
-						checkmethod = 0;
-						break;
-					}
+	/*
+	 * We are expecting that the caller will pass us a hintp_cookie that
+	 * they are tracking.  Upon entry, if *hintp_cookie is *not* set, this
+	 * indicates to us that we should be figuring out based on the current
+	 * environment where to search.  This keeps us sane throughout the
+	 * entirety of a single search.
+	 */
+	if (*hintp_cookie == NULL) {
+		hintp = NULL;
+		if (hintenv_merged) {
+			/*
+			 * static_hints, if it was previously used, has
+			 * already been folded in to the environment
+			 * by this point.
+			 */
+			mtx_lock(&kenv_lock);
+			cp = kenvp[0];
+			for (i = 0; cp != NULL; cp = kenvp[++i]) {
+				if (!strncmp(cp, "hint.", 5)) {
+					hintp = kenvp[0];
+					break;
 				}
-				mtx_unlock(&kenv_lock);
-			} else {
-				cp = kern_envp;
-				while (cp) {
-					if (strncmp(cp, "hint.", 5) == 0) {
-						cp = NULL;
-						hintp = kern_envp;
-						break;
-					}
-					while (*cp != '\0')
-						cp++;
-					cp++;
-					if (*cp == '\0') {
-						cp = NULL;
-						hintp = static_hints;
-						break;
-					}
-				}
 			}
-			break;
-		default:
-			break;
-		}
-		if (hintp == NULL) {
-			if (dynamic_kenv) {
-				use_kenv = 1;
-				checkmethod = 0;
-			} else
+			mtx_unlock(&kenv_lock);
+			dyn_used = 1;
+		} else {
+			/*
+			 * We'll have a chance to keep coming back here until
+			 * we've actually exhausted all of our possibilities.
+			 * We might have chosen the MD/Static env because it
+			 * had some kind of hints, but perhaps it didn't have
+			 * the hint we are looking for.  We don't provide any
+			 * fallback when searching the dynamic environment.
+			 */
+fallback:
+			if (dyn_used || fbacklvl >= FBACK_STATIC)
+				return (ENOENT);
+
+			if (fbacklvl <= FBACK_MDENV &&
+			    _res_checkenv(md_envp)) {
+				hintp = md_envp;
+				goto found;
+			}
+			fbacklvl++;
+
+			if (fbacklvl <= FBACK_STENV &&
+			    _res_checkenv(kern_envp)) {
 				hintp = kern_envp;
+				goto found;
+			}
+			fbacklvl++;
+
+			/* We'll fallback to static_hints if needed/can */
+			if (fbacklvl <= FBACK_STATIC &&
+			    _res_checkenv(static_hints))
+				hintp = static_hints;
+found:
+			fbacklvl++;
 		}
+
+		if (hintp == NULL)
+			return (ENOENT);
+		*hintp_cookie = hintp;
+	} else {
+		hintp = *hintp_cookie;
+		if (hintenv_merged && hintp == kenvp[0])
+			dyn_used = 1;
+		else
+			/*
+			 * If we aren't using the dynamic environment, we need
+			 * to run through the proper fallback procedure again.
+			 * This is so that we do continuations right if we're
+			 * working with *line and *startln.
+			 */
+			goto fallback;
 	}
 
-	if (use_kenv) {
+	if (dyn_used) {
 		mtx_lock(&kenv_lock);
 		i = 0;
-		cp = kenvp[0];
-		if (cp == NULL) {
-			mtx_unlock(&kenv_lock);
-			return (ENOENT);
-		}
-	} else
-		cp = hintp;
+	}
+
+	cp = hintp;
 	while (cp) {
 		hit = 1;
 		(*line)++;
@@ -198,25 +222,28 @@ res_find(int *line, int *startln,
 		else
 			n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s",
 			    r_name, &r_unit, r_resname, r_value);
-		if (hit && n != 4) {
-			printf("CONFIG: invalid hint '%s'\n", cp);
-			p = strchr(cp, 'h');
-			*p = 'H';
-			hit = 0;
+		/* We'll circumvent all of the checks if we already know */
+		if (hit) {
+			if (n != 4) {
+				printf("CONFIG: invalid hint '%s'\n", cp);
+				p = strchr(cp, 'h');
+				*p = 'H';
+				hit = 0;
+			}
+			if (hit && startln && *startln >= 0 && *line < *startln)
+				hit = 0;
+			if (hit && name && strcmp(name, r_name) != 0)
+				hit = 0;
+			if (hit && unit && *unit != r_unit)
+				hit = 0;
+			if (hit && resname && strcmp(resname, r_resname) != 0)
+				hit = 0;
+			if (hit && value && strcmp(value, r_value) != 0)
+				hit = 0;
+			if (hit)
+				break;
 		}
-		if (hit && startln && *startln >= 0 && *line < *startln)
-			hit = 0;
-		if (hit && name && strcmp(name, r_name) != 0)
-			hit = 0;
-		if (hit && unit && *unit != r_unit)
-			hit = 0;
-		if (hit && resname && strcmp(resname, r_resname) != 0)
-			hit = 0;
-		if (hit && value && strcmp(value, r_value) != 0)
-			hit = 0;
-		if (hit)
-			break;
-		if (use_kenv) {
+		if (dyn_used) {
 			cp = kenvp[++i];
 			if (cp == NULL)
 				break;
@@ -230,10 +257,10 @@ res_find(int *line, int *startln,
 			}
 		}
 	}
-	if (use_kenv)
+	if (dyn_used)
 		mtx_unlock(&kenv_lock);
 	if (cp == NULL)
-		return ENOENT;
+		goto fallback;
 
 	s = cp;
 	/* This is a bit of a hack, but at least is reentrant */
@@ -271,11 +298,13 @@ resource_find(int *line, int *startln,
 {
 	int i;
 	int un;
+	char *hintp;
 
 	*line = 0;
+	hintp = NULL;
 
 	/* Search for exact unit matches first */
-	i = res_find(line, startln, name, unit, resname, value,
+	i = res_find(&hintp, line, startln, name, unit, resname, value,
 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
 	    ret_value);
 	if (i == 0)
@@ -284,7 +313,7 @@ resource_find(int *line, int *startln,
 		return ENOENT;
 	/* If we are still here, search for wildcard matches */
 	un = -1;
-	i = res_find(line, startln, name, &un, resname, value,
+	i = res_find(&hintp, line, startln, name, &un, resname, value,
 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
 	    ret_value);
 	if (i == 0)

Modified: stable/11/sys/sys/systm.h
==============================================================================
--- stable/11/sys/sys/systm.h	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/sys/sys/systm.h	Sat Aug  4 21:57:17 2018	(r337333)
@@ -148,11 +148,10 @@ void	kassert_panic(const char *fmt, ...)  __printflike
  * XXX most of these variables should be const.
  */
 extern int osreldate;
-extern int envmode;
-extern int hintmode;		/* 0 = off. 1 = config, 2 = fallback */
 extern int dynamic_kenv;
 extern struct mtx kenv_lock;
 extern char *kern_envp;
+extern char *md_envp;
 extern char static_env[];
 extern char static_hints[];	/* by config for now */
 

Modified: stable/11/tools/build/Makefile
==============================================================================
--- stable/11/tools/build/Makefile	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/tools/build/Makefile	Sat Aug  4 21:57:17 2018	(r337333)
@@ -49,4 +49,7 @@ SRCS=		dummy.c
 SUBDIR=		cross-build
 .endif
 
+# Needed to build config (since it uses libnv)
+SYSINCS+=	${SRCTOP}/sys/sys/nv.h ${SRCTOP}/sys/sys/cnv.h
+
 .include <bsd.lib.mk>

Modified: stable/11/usr.sbin/config/Makefile
==============================================================================
--- stable/11/usr.sbin/config/Makefile	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/Makefile	Sat Aug  4 21:57:17 2018	(r337333)
@@ -18,7 +18,7 @@ CFLAGS+= -I. -I${SRCDIR}
 
 NO_WMISSING_VARIABLE_DECLARATIONS=
 
-LIBADD=	l sbuf
+LIBADD=	l nv sbuf
 
 CLEANFILES+=	kernconf.c
 

Modified: stable/11/usr.sbin/config/config.5
==============================================================================
--- stable/11/usr.sbin/config/config.5	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/config.5	Sat Aug  4 21:57:17 2018	(r337333)
@@ -23,7 +23,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 26, 2018
+.Dd July 11, 2018
 .Dt CONFIG 5
 .Os
 .Sh NAME
@@ -114,13 +114,36 @@ are defined in the file
 .Pp
 .It Ic env Ar filename
 Specifies a filename containing a kernel environment definition.
-The kernel normally uses an environment prepared for it at boot time
-by
+.Pp
+The kernel will augment this compiled-in environment with the environment
+prepared for it at boot time by
 .Xr loader 8 .
-This directive makes the kernel ignore the boot environment and use
-the compiled-in environment instead, unless the boot environment contains
-.Va static_env.disabled=1 .
+Environment variables specified in the
+.Xr loader 8
+environment will take precedence over environment variables specified in
+.Ar filename ,
+and environment variables specified in the dynamic environment take precedence
+over both of these.
 .Pp
+.Va loader_env.disabled=1
+may be specified in the static environment to disable the
+.Xr loader 8
+environment.
+Disabling the
+.Xr loader 8
+should be done with caution and due consideration for whether or not it supplies
+environment variables needed for properly booting the system.
+.Pp
+.Va static_env.disabled=1
+may be specified in the
+.Xr loader 8
+environment to disable use of the static environment.
+This option has no effect if specified in any environment after the
+.Xr loader 8
+environment is processed.
+This option is not usable in conjunction with
+.Va loader_env.disabled .
+.Pp
 This directive is useful for setting kernel tunables in
 embedded environments that do not start from
 .Xr loader 8 .
@@ -172,9 +195,28 @@ time (see
 .Xr device.hints 5 ) .
 This directive configures the kernel to use the static device configuration
 listed in
-.Ar filename ,
-unless the boot environment contains
-.Va static_hints.disabled=1 .
+.Ar filename .
+.Pp
+Hints provided in this static device configuration will be overwritten in the
+order in which they're encountered.
+Hints in the compiled-in environment takes precedence over compiled-in hints,
+and hints in the environment prepared for the kernel by
+.Xr loader 8
+takes precedence over hints in the compiled-in environment.
+.Pp
+Once the dynamic environment becomes available, all compiled-in hints will be
+added to the dynamic environment if they do not already have an override in
+the dynamic environment.
+The dynamic environment will then be used for all searches of hints.
+.Pp
+.Va static_hints.disabled=1
+may be specified in either a compiled-in environment or the
+.Xr loader 8
+environment to disable use of these hints files.
+This option has no effect if specified in any environment after the
+.Xr loader 8
+environment is processed.
+.Pp
 The file
 .Ar filename
 must conform to the syntax specified by

Modified: stable/11/usr.sbin/config/config.h
==============================================================================
--- stable/11/usr.sbin/config/config.h	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/config.h	Sat Aug  4 21:57:17 2018	(r337333)
@@ -177,8 +177,6 @@ SLIST_HEAD(, includepath) includepath;
 extern char	*ident;
 extern char	kernconfstr[];
 extern int	do_trace;
-extern int	envmode;
-extern int	hintmode;
 extern int	incignore;
 
 char	*get_word(FILE *);
@@ -212,6 +210,7 @@ extern int	debugging;
 extern int	found_defaults;
 
 extern int	maxusers;
+extern int	versreq;
 
 extern char *PREFIX;		/* Config file name - for error messages */
 extern char srcdir[];		/* root of the kernel source tree */

Modified: stable/11/usr.sbin/config/config.y
==============================================================================
--- stable/11/usr.sbin/config/config.y	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/config.y	Sat Aug  4 21:57:17 2018	(r337333)
@@ -80,8 +80,7 @@
 
 struct	device_head dtab;
 char	*ident;
-int	envmode;
-int	hintmode;
+char	*env;
 int	yyline;
 const	char *yyfile;
 struct  file_list_head ftab;
@@ -199,7 +198,6 @@ Config_spec:
 			err(EXIT_FAILURE, "calloc");	
 		hint->hint_name = $2;
 		STAILQ_INSERT_HEAD(&hints, hint, hint_next);
-		hintmode = 1;
 	        }
 
 System_spec:
@@ -359,7 +357,6 @@ newenvvar(char *name, bool is_file)
 	envvar->env_str = name;
 	envvar->env_is_file = is_file;
 	STAILQ_INSERT_HEAD(&envvars, envvar, envvar_next);
-	envmode = 1;
 }
 
 /*

Modified: stable/11/usr.sbin/config/configvers.h
==============================================================================
--- stable/11/usr.sbin/config/configvers.h	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/configvers.h	Sat Aug  4 21:57:17 2018	(r337333)
@@ -49,5 +49,8 @@
  *
  * $FreeBSD$
  */
-#define	CONFIGVERS	600015
+#define	CONFIGVERS	600016
 #define	MAJOR_VERS(x)	((x) / 100000)
+
+/* Last config(8) version to require envmode/hintmode */
+#define	CONFIGVERS_ENVMODE_REQ	600015

Modified: stable/11/usr.sbin/config/main.c
==============================================================================
--- stable/11/usr.sbin/config/main.c	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/main.c	Sat Aug  4 21:57:17 2018	(r337333)
@@ -84,12 +84,14 @@ int	incignore;
  * literally).
  */
 int	filebased = 0;
+int	versreq;
 
 static void configfile(void);
 static void get_srcdir(void);
 static void usage(void);
 static void cleanheaders(char *);
 static void kernconfdump(const char *);
+static void badversion(void);
 static void checkversion(void);
 extern int yyparse(void);
 
@@ -740,8 +742,8 @@ kernconfdump(const char *file)
 	fclose(fp);
 }
 
-static void 
-badversion(int versreq)
+static void
+badversion(void)
 {
 	fprintf(stderr, "ERROR: version of config(8) does not match kernel!\n");
 	fprintf(stderr, "config version = %d, ", CONFIGVERS);
@@ -761,7 +763,6 @@ checkversion(void)
 {
 	FILE *ifp;
 	char line[BUFSIZ];
-	int versreq;
 
 	ifp = open_makefile_template();
 	while (fgets(line, BUFSIZ, ifp) != 0) {
@@ -773,7 +774,7 @@ checkversion(void)
 		if (MAJOR_VERS(versreq) == MAJOR_VERS(CONFIGVERS) &&
 		    versreq <= CONFIGVERS)
 			continue;
-		badversion(versreq);
+		badversion();
 	}
 	fclose(ifp);
 }

Modified: stable/11/usr.sbin/config/mkmakefile.c
==============================================================================
--- stable/11/usr.sbin/config/mkmakefile.c	Sat Aug  4 21:54:30 2018	(r337332)
+++ stable/11/usr.sbin/config/mkmakefile.c	Sat Aug  4 21:57:17 2018	(r337333)
@@ -47,6 +47,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"
@@ -60,6 +62,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, ...)
 {
@@ -178,65 +184,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, "int hintmode = %d;\n", hintmode);
-	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;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list