diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8 --- a/sbin/reboot/reboot.8 +++ b/sbin/reboot/reboot.8 @@ -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 @@ 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 diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c --- a/sbin/reboot/reboot.c +++ b/sbin/reboot/reboot.c @@ -88,7 +88,7 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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. */