reboot: Don't reboot if the next kernel isn't there

reboot -k garbage won't boot garbage unless /boot/garbage/kernel is
there. Refuse to reboot if it is missing, though allow -f to force
it for special-use cases. This is in keeping with nextboot.sh.

Sponsored by:		Netflix
Reviewed by:		kevans, kib, markj, emaste
Differential Revision:	https://reviews.freebsd.org/D43802
This commit is contained in:
Warner Losh 2024-02-12 11:45:01 -07:00
parent 7a3210f2ac
commit 7cb1a0e6e0
2 changed files with 38 additions and 16 deletions

View file

@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd December 20, 2017
.Dd February 8, 2024
.Dt REBOOT 8
.Os
.Sh NAME
@ -36,16 +36,16 @@
.Nd stopping and restarting the system
.Sh SYNOPSIS
.Nm halt
.Op Fl lNnpq
.Op Fl flNnpq
.Op Fl k Ar kernel
.Nm
.Op Fl cdlNnpqr
.Op Fl cdflNnpqr
.Op Fl k Ar kernel
.Nm fasthalt
.Op Fl lNnpq
.Op Fl flNnpq
.Op Fl k Ar kernel
.Nm fastboot
.Op Fl dlNnpq
.Op Fl dflNnpq
.Op Fl k Ar kernel
.Sh DESCRIPTION
The
@ -83,17 +83,22 @@ 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 k Ar kernel
Boot the specified
.Ar kernel
.It Fl k Ar kname
Boot the specified kernel
.Ar kname
on the next system boot.
If the kernel boots successfully, the
This is a one-shot option, the
.Em default
kernel will be booted on successive boots, this is a one-shot option.
If the boot fails, the system will continue attempting to boot
.Ar kernel
until the boot process is interrupted and a valid kernel booted.
This may change in the future.
kernel will be booted on successive boots.
No
.Nm reboot
or
.Nm halt
will be performed if
.Em /boot/kname/kernel
does not exist unless the
.Fl f
flag is specified.
.It Fl l
The halt or reboot is
.Em not

View file

@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/boottrace.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/time.h>
@ -59,7 +60,7 @@ main(int argc, char *argv[])
struct utmpx utx;
const struct passwd *pw;
int ch, howto, i, fd, sverrno;
bool lflag, nflag, qflag, Nflag;
bool fflag, lflag, nflag, qflag, Nflag;
uint64_t pageins;
const char *user, *kernel = NULL;
@ -68,7 +69,7 @@ main(int argc, char *argv[])
howto = RB_HALT;
} else
howto = 0;
lflag = nflag = qflag = Nflag = false;
fflag = lflag = nflag = qflag = Nflag = false;
while ((ch = getopt(argc, argv, "cdk:lNnpqr")) != -1)
switch(ch) {
case 'c':
@ -77,6 +78,9 @@ main(int argc, char *argv[])
case 'd':
howto |= RB_DUMP;
break;
case 'f':
fflag = true;
break;
case 'k':
kernel = optarg;
break;
@ -130,6 +134,19 @@ main(int argc, char *argv[])
}
if (kernel != NULL) {
if (!fflag) {
char *k;
struct stat sb;
asprintf(&k, "/boot/%s/kernel", kernel);
if (k == NULL)
errx(1, "No memory to check %s", kernel);
if (stat(k, &sb) != 0)
err(1, "stat %s", k);
if (!S_ISREG(sb.st_mode))
errx(1, "%s is not a file", k);
free(k);
}
fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC,
0444);
if (fd > -1) {