Revert r335995 due to accidental changes snuck in

This commit is contained in:
Kyle Evans 2018-07-05 16:28:43 +00:00
parent 81dac87135
commit e28687347f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=335997
8 changed files with 215 additions and 344 deletions

View File

@ -57,21 +57,14 @@ __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 config-generated static environment */
/* pointer to the static environment */
char *kern_envp;
/* pointer to the md-static environment */
char *md_envp;
static int md_env_len;
static int md_env_pos;
static int env_len;
static int env_pos;
static char *kernenv_next(char *);
/* dynamic environment variables */
@ -227,8 +220,15 @@ sys_kenv(td, uap)
* 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.
*
* kern_envp is set to the static_env generated by config(8). This implements
* the env keyword described in config(5).
* 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.
*
* 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
@ -237,93 +237,30 @@ sys_kenv(td, uap)
* 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() 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.
* 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.
*/
void
init_static_kenv(char *buf, size_t len)
{
char *eval;
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;
}
md_envp = buf;
md_env_len = len;
md_env_pos = 0;
/*
* 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.
*/
eval = kern_getenv("static_env.disabled");
if (eval == NULL || strcmp(eval, "1") != 0)
if (envmode == 1) {
kern_envp = static_env;
eval = kern_getenv("static_hints.disabled");
if (eval != NULL && strcmp(eval, "1") == 0)
*static_hints = '\0';
}
static void
init_dynamic_kenv_from(char *init_env, int *curpos)
{
char *cp, *cpnext, *eqpos, *found;
size_t len;
int i;
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);
goto sanitize;
}
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;
env_len = len;
env_pos = len;
} else {
kern_envp = buf;
env_len = len;
env_pos = 0;
}
}
@ -333,15 +270,34 @@ init_dynamic_kenv_from(char *init_env, int *curpos)
static void
init_dynamic_kenv(void *data __unused)
{
int dynamic_envpos;
char *cp, *cpnext;
size_t len;
int i;
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;
i = 0;
if (kern_envp && *kern_envp != '\0') {
for (cp = kern_envp; 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;
}
if (i < KENV_SIZE) {
kenvp[i] = malloc(len, M_KENV, M_WAITOK);
strcpy(kenvp[i++], cp);
explicit_bzero(cp, strlen(cp));
} else
printf(
"WARNING: too many kenv strings, ignoring %s\n",
cp);
}
}
kenvp[i] = NULL;
mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
dynamic_kenv = 1;
@ -362,11 +318,12 @@ freeenv(char *env)
* Internal functions for string lookup.
*/
static char *
_getenv_dynamic_locked(const char *name, int *idx)
_getenv_dynamic(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) &&
@ -380,20 +337,12 @@ _getenv_dynamic_locked(const char *name, int *idx)
}
static char *
_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)
_getenv_static(const char *name)
{
char *cp, *ep;
int len;
for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) {
for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
;
if (*ep != '=')
@ -406,20 +355,6 @@ _getenv_static_from(char *chkenv, 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.
@ -464,25 +399,20 @@ 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 (md_env_pos >= md_env_len)
if (env_pos >= env_len)
return (-1);
/* Check space for x=y and two nuls */
len = strlen(name) + strlen(value);
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';
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';
return (0);
} else
return (-1);
@ -498,7 +428,7 @@ kern_setenv(const char *name, const char *value)
char *buf, *cp, *oldenv;
int namelen, vallen, i;
if (dynamic_kenv == 0 && md_env_len > 0)
if (dynamic_kenv == 0 && env_len > 0)
return (setenv_static(name, value));
KENV_CHECK;

View File

@ -31,35 +31,60 @@ __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 FBACK_MDENV 0 /* MD env (e.g. loader.conf) */
#define FBACK_STENV 1 /* Static env */
#define FBACK_STATIC 2 /* static_hints */
/*
* 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;
#define HINTMODE_KENV 0
#define HINTMODE_STATIC 1
#define HINTMODE_FALLBACK 2
/*
* Access functions for device resources.
*/
static void
static_hints_to_env(void *data __unused)
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).
*/
static int
sysctl_hintmode(SYSCTL_HANDLER_ARGS)
{
const char *cp;
char *line, *eq;
int eqidx, i;
int eqidx, error, i, value;
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') {
@ -70,48 +95,20 @@ static_hints_to_env(void *data __unused)
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] = 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);
line[eqidx] = '\0';
kern_setenv(line, line + eqidx + 1);
free(line, M_TEMP);
cp += i + 1;
}
hintenv_merged = 1;
hintmode = value;
return (0);
}
/* Any time after dynamic env is setup */
SYSINIT(hintenv, SI_SUB_KMEM, SI_ORDER_ANY, 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);
}
SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW,
&hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode");
/*
* Evil wildcarding resource string lookup.
@ -119,103 +116,82 @@ _res_checkenv(char *envp)
* The start point can be remembered for incremental searches.
*/
static int
res_find(char **hintp_cookie, int *line, int *startln,
res_find(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 dyn_used = 0, fbacklvl = FBACK_MDENV, hit, i = 0, n = 0;
int n = 0, hit, i = 0;
char r_name[32];
int r_unit;
int r_unit, use_kenv = (hintmode != HINTMODE_STATIC && dynamic_kenv);
char r_resname[32];
char r_value[128];
const char *s, *cp;
char *hintp, *p;
char *p;
/*
* 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) {
if (checkmethod) {
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;
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;
}
}
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;
}
}
}
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++;
break;
default:
break;
}
if (hintp == NULL) {
if (dynamic_kenv) {
use_kenv = 1;
checkmethod = 0;
} else
hintp = kern_envp;
}
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 (dyn_used) {
if (use_kenv) {
mtx_lock(&kenv_lock);
i = 0;
}
cp = hintp;
cp = kenvp[0];
if (cp == NULL) {
mtx_unlock(&kenv_lock);
return (ENOENT);
}
} else
cp = hintp;
while (cp) {
hit = 1;
(*line)++;
@ -224,28 +200,25 @@ res_find(char **hintp_cookie, int *line, int *startln,
else
n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s",
r_name, &r_unit, r_resname, r_value);
/* 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 && n != 4) {
printf("CONFIG: invalid hint '%s'\n", cp);
p = strchr(cp, 'h');
*p = 'H';
hit = 0;
}
if (dyn_used) {
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) {
cp = kenvp[++i];
if (cp == NULL)
break;
@ -259,10 +232,10 @@ res_find(char **hintp_cookie, int *line, int *startln,
}
}
}
if (dyn_used)
if (use_kenv)
mtx_unlock(&kenv_lock);
if (cp == NULL)
goto fallback;
return ENOENT;
s = cp;
/* This is a bit of a hack, but at least is reentrant */
@ -300,13 +273,11 @@ 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(&hintp, line, startln, name, unit, resname, value,
i = res_find(line, startln, name, unit, resname, value,
ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
ret_value);
if (i == 0)
@ -315,7 +286,7 @@ resource_find(int *line, int *startln,
return ENOENT;
/* If we are still here, search for wildcard matches */
un = -1;
i = res_find(&hintp, line, startln, name, &un, resname, value,
i = res_find(line, startln, name, &un, resname, value,
ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
ret_value);
if (i == 0)

View File

@ -269,7 +269,7 @@ ttydev_open(struct cdev *dev, int oflags, int devtype __unused,
struct thread *td)
{
struct tty *tp;
int cflags, error;
int error;
tp = dev->si_drv1;
error = 0;
@ -325,14 +325,7 @@ ttydev_open(struct cdev *dev, int oflags, int devtype __unused,
if (TTY_CALLOUT(tp, dev) || dev == dev_console)
tp->t_termios.c_cflag |= CLOCAL;
cflags = 0;
if (tp->t_termios.c_cflag & CDTR_IFLOW)
cflags |= SER_DTR;
if (tp->t_termios.c_cflag & CRTS_IFLOW)
cflags |= SER_RTS;
if (cflags != 0)
ttydevsw_modem(tp, cflags, 0);
ttydevsw_modem(tp, SER_DTR|SER_RTS, 0);
error = ttydevsw_open(tp);
if (error != 0)

View File

@ -156,10 +156,11 @@ void kassert_panic(const char *fmt, ...) __printflike(1, 2);
* 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 */

View File

@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd July 5, 2018
.Dd June 26, 2018
.Dt CONFIG 5
.Os
.Sh NAME
@ -114,24 +114,12 @@ are defined in the file
.Pp
.It Ic env Ar filename
Specifies a filename containing a kernel environment definition.
.Pp
The kernel will augment this compiled-in environment with the environment
prepared for it at boot time by
The kernel normally uses an environment prepared for it at boot time
by
.Xr loader 8 .
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 static_env.disabled=1
may be specified in the
.Xr loader 8
environment to disable use of this compiled-in environment.
This option has no effect if specified in any environment after the
.Xr loader 8
environment is processed.
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 .
.Pp
This directive is useful for setting kernel tunables in
embedded environments that do not start from
@ -184,28 +172,9 @@ time (see
.Xr device.hints 5 ) .
This directive configures the kernel to use the static device configuration
listed in
.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
.Ar filename ,
unless the boot environment contains
.Va static_hints.disabled=1 .
The file
.Ar filename
must conform to the syntax specified by

View File

@ -179,6 +179,8 @@ 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 *);

View File

@ -82,7 +82,8 @@
struct device_head dtab;
char *ident;
char *env;
int envmode;
int hintmode;
int yyline;
const char *yyfile;
struct file_list_head ftab;
@ -200,6 +201,7 @@ Config_spec:
err(EXIT_FAILURE, "calloc");
hint->hint_name = $2;
STAILQ_INSERT_HEAD(&hints, hint, hint_next);
hintmode = 1;
}
System_spec:
@ -359,6 +361,7 @@ 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;
}
/*

View File

@ -197,6 +197,7 @@ makehints(void)
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");
@ -311,6 +312,7 @@ makeenv(void)
fprintf(ofp, "#include <sys/types.h>\n");
fprintf(ofp, "#include <sys/systm.h>\n");
fprintf(ofp, "\n");
fprintf(ofp, "int envmode = %d;\n", envmode);
fprintf(ofp, "char static_env[] = {\n");
STAILQ_FOREACH(envvar, &envvars, envvar_next) {
if (envvar->env_is_file) {