Index: usr.sbin/config/config.h =================================================================== --- usr.sbin/config/config.h +++ usr.sbin/config/config.h @@ -140,6 +140,14 @@ SLIST_HEAD(, opt_list) otab; +struct envvar { + char *env_key; + char *env_val; + STAILQ_ENTRY(envvar) envvar_next; +}; + +STAILQ_HEAD(envvar_head, envvar) envvars; + struct hint { char *hint_name; STAILQ_ENTRY(hint) hint_next; Index: usr.sbin/config/config.5 =================================================================== --- usr.sbin/config/config.5 +++ usr.sbin/config/config.5 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 21, 2016 +.Dd June 22, 2018 .Dt CONFIG 5 .Os .Sh NAME @@ -124,6 +124,20 @@ This directive is useful for setting kernel tunables in embedded environments that do not start from .Xr loader 8 . +.\" -------- ENVVAR -------- +.Pp +.It Ic envvar Ar setting +Specifies an individual environment setting to be added to the kernel's +compiled-in environment. +.Ar setting +must be of the form +.Dq Va name=value +without any quotes included in the value or the right hand side of the setting. +All environment variables specified with +.Ic envvar +will be set after any +.Ic env +files are included. .\" -------- FILES -------- .Pp .It Ic files Ar filename Index: usr.sbin/config/config.y =================================================================== --- usr.sbin/config/config.y +++ usr.sbin/config/config.y @@ -12,6 +12,7 @@ %token DEVICE %token NODEVICE %token ENV +%token ENVVAR %token EQUALS %token PLUSEQUALS %token HINTS @@ -193,6 +194,16 @@ env = $2; envmode = 1; } | + ENVVAR ID EQUALS ID { + struct envvar *envvar; + + envvar = (struct envvar *)calloc(1, sizeof (struct envvar)); + if (envvar == NULL) + err(EXIT_FAILURE, "calloc"); + envvar->env_key = $2; + envvar->env_val = $4; + STAILQ_INSERT_TAIL(&envvars, envvar, envvar_next); + } | HINTS ID { struct hint *hint; Index: usr.sbin/config/lang.l =================================================================== --- usr.sbin/config/lang.l +++ usr.sbin/config/lang.l @@ -70,6 +70,7 @@ { "nodevice", NODEVICE }, { "nodevices", NODEVICE }, { "env", ENV }, + { "envvar", ENVVAR }, { "hints", HINTS }, { "ident", IDENT }, { "machine", ARCH }, /* MACHINE is defined in /sys/param.h */ Index: usr.sbin/config/main.c =================================================================== --- usr.sbin/config/main.c +++ usr.sbin/config/main.c @@ -204,6 +204,7 @@ STAILQ_INIT(&fntab); STAILQ_INIT(&ftab); STAILQ_INIT(&hints); + STAILQ_INIT(&envvars); if (yyparse()) exit(3); Index: usr.sbin/config/mkmakefile.c =================================================================== --- usr.sbin/config/mkmakefile.c +++ usr.sbin/config/mkmakefile.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -238,6 +239,63 @@ moveifchanged(path("hints.c.new"), path("hints.c")); } +static void +sanitize_envline(char *result, const char *src) +{ + const char *eq; + char c, *dst; + bool leading; + + /* If there is no '=' it's not a well-formed name=value line. */ + if ((eq = strchr(src, '=')) == NULL) { + *result = 0; + return; + } + dst = result; + + /* Copy chars before the '=', skipping any leading spaces/quotes. */ + leading = true; + while (src < eq) { + c = *src++; + if (leading && (isspace(c) || c == '"')) + continue; + *dst++ = c; + leading = false; + } + + /* If it was all leading space, we don't have a well-formed line. */ + if (leading) { + *result = 0; + return; + } + + /* Trim spaces/quotes immediately before the '=', then copy the '='. */ + while (isspace(dst[-1]) || dst[-1] == '"') + --dst; + *dst++ = *src++; + + /* Copy chars after the '=', skipping any leading whitespace. */ + leading = true; + while ((c = *src++) != 0) { + if (leading && (isspace(c) || c == '"')) + continue; + *dst++ = c; + leading = false; + } + + /* If it was all leading space, it's a valid 'var=' (nil value). */ + if (leading) { + *dst = 0; + return; + } + + /* Trim trailing whitespace and quotes. */ + while (isspace(dst[-1]) || dst[-1] == '"') + --dst; + + *dst = 0; +} + /* * Build env.c from the skeleton */ @@ -245,8 +303,9 @@ makeenv(void) { FILE *ifp, *ofp; - char line[BUFSIZ]; - char *s; + char line[BUFSIZ], result[BUFSIZ], *linep; + int linesz; + struct envvar *envvar; if (env) { ifp = fopen(env, "r"); @@ -265,35 +324,23 @@ fprintf(ofp, "char static_env[] = {\n"); if (ifp) { 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++; - } + sanitize_envline(result, line); /* anything left? */ - if (*line == '\0') + if (*result == '\0') continue; - fprintf(ofp, "\"%s\\0\"\n", line); + fprintf(ofp, "\"%s\\0\"\n", result); } } + STAILQ_FOREACH(envvar, &envvars, envvar_next) { + linesz = strlen(envvar->env_key) + strlen(envvar->env_val) + 2; + linep = malloc(linesz); + sprintf(linep, "%s=%s", envvar->env_key, envvar->env_val); + linep[linesz - 1] = '\0'; + sanitize_envline(result, linep); + if (*result == '\0') + continue; + fprintf(ofp, "\"%s\\0\"\n", result); + } fprintf(ofp, "\"\\0\"\n};\n"); if (ifp) fclose(ifp);