reboot: Implement -e from nextboot

Implement -e foo=bar to add loader environment variables to
nextboot.conf. bar is enclosed in quotes if it isn't already.

Sponsored by:		Netflix
Differential Revision:	https://reviews.freebsd.org/D43827
This commit is contained in:
Warner Losh 2024-02-12 11:45:48 -07:00
parent 0df5f65908
commit ecc834241f
2 changed files with 64 additions and 4 deletions

View file

@ -37,15 +37,19 @@
.Sh SYNOPSIS
.Nm halt
.Op Fl DflNnpq
.Op Fl e Ar variable=value
.Op Fl k Ar kernel
.Nm
.Op Fl cDdflNnpqr
.Op Fl e Ar variable=value
.Op Fl k Ar kernel
.Nm fasthalt
.Op Fl DflNnpq
.Op Fl e Ar variable=value
.Op Fl k Ar kernel
.Nm fastboot
.Op Fl dDflNnpq
.Op Fl e Ar variable=value
.Op Fl k Ar kernel
.Sh DESCRIPTION
The
@ -87,6 +91,21 @@ This option is
supported only when rebooting, and it has no effect unless a dump
device has previously been specified with
.Xr dumpon 8 .
.It Fl e Ar variable=value
Sets
.Va variable
to
.Va value
in the loader's and kernel's environment.
If
.Va value
is not already enclosed in double quotes, they will be added before writing to the
.Nm nextboot
configuration.
Care should be taken if
.Va value
contains any characters that are special to the shell or loader's configuration
parsing code.
.It Fl k Ar kname
Boot the specified kernel
.Ar kname

View file

@ -88,7 +88,7 @@ zfsbootcfg(const char *pool, bool force)
}
static void
write_nextboot(const char *fn, const char *kernel, bool force)
write_nextboot(const char *fn, const char *env, const char *kernel, bool force)
{
FILE *fp;
struct statfs sfs;
@ -114,8 +114,9 @@ write_nextboot(const char *fn, const char *kernel, bool force)
if (fp == NULL)
E("Can't create %s to boot %s", fn, kernel);
if (fprintf(fp,"%skernel=\"%s\"\n",
if (fprintf(fp,"%s%skernel=\"%s\"\n",
supported ? "nextboot_enable=\"YES\"\n" : "",
env != NULL ? env : "",
kernel) < 0) {
int e;
@ -129,6 +130,40 @@ write_nextboot(const char *fn, const char *kernel, bool force)
fclose(fp);
}
static char *
split_kv(char *raw)
{
char *eq;
int len;
eq = strchr(raw, '=');
if (eq == NULL)
errx(1, "No = in environment string %s", raw);
*eq++ = '\0';
len = strlen(eq);
if (len == 0)
errx(1, "Invalid null value %s=", raw);
if (eq[0] == '"') {
if (len < 2 || eq[len - 1] != '"')
errx(1, "Invalid string '%s'", eq);
eq[len - 1] = '\0';
return (eq + 1);
}
return (eq);
}
static void
add_env(char **env, const char *key, const char *value)
{
char *oldenv;
oldenv = *env;
asprintf(env, "%s%s=\"%s\"\n", oldenv != NULL ? oldenv : "", key, value);
if (env == NULL)
errx(1, "No memory to build env array");
free(oldenv);
}
int
main(int argc, char *argv[])
{
@ -138,6 +173,8 @@ main(int argc, char *argv[])
bool Dflag, fflag, lflag, Nflag, nflag, qflag;
uint64_t pageins;
const char *user, *kernel = NULL;
char *env = NULL, *v;
if (strstr(getprogname(), "halt") != NULL) {
dohalt = true;
@ -145,7 +182,7 @@ main(int argc, char *argv[])
} else
howto = 0;
Dflag = fflag = lflag = Nflag = nflag = qflag = false;
while ((ch = getopt(argc, argv, "cDdk:lNnpqr")) != -1)
while ((ch = getopt(argc, argv, "cDde:k:lNnpqr")) != -1)
switch(ch) {
case 'c':
howto |= RB_POWERCYCLE;
@ -156,6 +193,10 @@ main(int argc, char *argv[])
case 'd':
howto |= RB_DUMP;
break;
case 'e':
v = split_kv(optarg);
add_env(&env, optarg, v);
break;
case 'f':
fflag = true;
break;
@ -233,7 +274,7 @@ main(int argc, char *argv[])
errx(1, "%s is not a file", k);
free(k);
}
write_nextboot(PATH_NEXTBOOT, kernel, fflag);
write_nextboot(PATH_NEXTBOOT, env, kernel, fflag);
}
/* Log the reboot. */