reboot: Default to a clean shutdown

* If invoked as fasthalt or fastboot, behavior is unchanged.

* If not invoked as fasthalt or fastboot, we simply signal init(8),
  just like shutdown(8) does, instead of taking the system down
  ourselves.

* Since only init can handle the RB_REROOT case, the -r flag is not
  supported in fast mode.

* Update the usage string to correctly reflect the program being run
  (fast or normal; halt, boot, or nextboot) and the options available
  in each case.

* Update the manual page to make the distinction between normal and
  fast mode clear, better explain what shutdown(8) still does that
  reboot(8) does not, and add a historical note explaining what the
  difference between the two used to be.

MFC after:	1 month
Relnotes:	yes
Reviewed by:	imp
Differential Revision:	https://reviews.freebsd.org/D54117
This commit is contained in:
Dag-Erling Smørgrav
2025-12-10 15:45:57 +01:00
parent 80203a27e9
commit 4453ec5b87
2 changed files with 88 additions and 32 deletions
+46 -16
View File
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd April 12, 2025
.Dd December 8, 2025
.Dt REBOOT 8
.Os
.Sh NAME
@@ -60,16 +60,25 @@ The
.Nm halt
and
.Nm
utilities flush the file system cache to disk, send all running processes
a
utilities stop and restart the system, respectively.
.Pp
Both utilities have two distinct modes of operation.
In normal mode, they send a signal to the
.Xr init 8
process, which shuts down running services and stops or restarts the
system.
In fast mode, they flush the file system cache to disk, send all
running processes a
.Dv SIGTERM
(and subsequently a
.Dv SIGKILL )
and, respectively, halt or restart the system.
The action is logged, including entering a shutdown record into the user
accounting database.
and stop or restart the system themselves.
Services are killed, not shut down, which may result in data loss.
.Pp
The options are as follows:
In either mode, the action is logged, including entering a shutdown
record into the user accounting database.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl c
The system will turn off the power and then turn it back on if it can.
@@ -111,14 +120,17 @@ Care should be taken if
contains any characters that are special to the shell or loader's configuration
parsing code.
.It Fl f
Force reboot.
Forced mode.
Normally,
.Nm halt
or
.Nm
checks for the presence of the next kernel,
and absence of the
.Pa /var/run/noshutdown
file.
Without this flag, reboot is denied if one of the conditions failed.
Without this flag, the operation is rejected if one of these checks
fails.
.It Fl k Ar kname
Boot the specified kernel
.Ar kname
@@ -195,17 +207,20 @@ The
.Nm fasthalt
and
.Nm fastboot
utilities are nothing more than aliases for the
utilities invoke
.Nm halt
and
.Nm
utilities.
.Nm ,
respectively, in fast mode.
.Pp
Normally, the
The
.Xr shutdown 8
utility is used when the system needs to be halted or restarted, giving
users advance warning of their impending doom and cleanly terminating
specific programs.
utility can be used to not only stop or restart the system right away,
but also schedule a stop or restart in the future, and will, unlike
.Nm halt
and
.Nm ,
give users advance warning of their impending doom.
.Sh EXAMPLES
Replace current root filesystem with UFS mounted from
.Pa /dev/ada0s1a :
@@ -236,3 +251,18 @@ A
.Nm
utility appeared in
.Bx 4.0 .
.Pp
Historically, the
.Xr shutdown 8
utility was used when the system needed to be halted or restarted
cleanly in the normal course of operations, and the
.Nm halt
and
.Nm
utilities were blunt instruments used only in single-user mode or if
exceptional circumstances made a normal shutdown impractical.
As other operating systems did away with this distinction, and it
became clear that many users were unaware of it and were using
.Nm
in the belief that it performed a clean shutdown, it was rewritten to
conform to that expectation.
+42 -16
View File
@@ -59,6 +59,7 @@ extern char **environ;
static void usage(void) __dead2;
static uint64_t get_pageins(void);
static bool dofast;
static bool dohalt;
static bool donextboot;
@@ -229,6 +230,24 @@ add_env(char **env, const char *key, const char *value)
free(oldenv);
}
static void
shutdown(int howto)
{
char sigstr[SIG2STR_MAX];
int signo =
howto & RB_HALT ? SIGUSR1 :
howto & RB_POWEROFF ? SIGUSR2 :
howto & RB_POWERCYCLE ? SIGWINCH :
howto & RB_REROOT ? SIGEMT :
SIGINT;
(void)sig2str(signo, sigstr);
BOOTTRACE("SIG%s to init(8)...", sigstr);
if (kill(1, signo) == -1)
err(1, "SIG%s init", sigstr);
exit(0);
}
/*
* Different options are valid for different programs.
*/
@@ -239,18 +258,24 @@ int
main(int argc, char *argv[])
{
struct utmpx utx;
const struct passwd *pw;
struct stat st;
const struct passwd *pw;
const char *progname, *user;
const char *kernel = NULL, *getopts = GETOPT_REBOOT;
char *env = NULL, *v;
uint64_t pageins;
int ch, howto = 0, i, sverrno;
bool aflag, Dflag, fflag, lflag, Nflag, nflag, qflag;
uint64_t pageins;
const char *user, *kernel = NULL, *getopts = GETOPT_REBOOT;
char *env = NULL, *v;
if (strstr(getprogname(), "halt") != NULL) {
progname = getprogname();
if (strncmp(progname, "fast", 4) == 0) {
dofast = true;
progname += 4;
}
if (strcmp(progname, "halt") == 0) {
dohalt = true;
howto = RB_HALT;
} else if (strcmp(getprogname(), "nextboot") == 0) {
} else if (strcmp(progname, "nextboot") == 0) {
donextboot = true;
getopts = GETOPT_NEXTBOOT; /* Note: reboot's extra opts return '?' */
} else {
@@ -331,6 +356,8 @@ main(int argc, char *argv[])
errx(1, "-c and -p cannot be used together");
if ((howto & RB_REROOT) != 0 && howto != RB_REROOT)
errx(1, "-r cannot be used with -c, -d, -n, or -p");
if ((howto & RB_REROOT) != 0 && dofast)
errx(1, "-r cannot be performed in fast mode");
if ((howto & RB_REROOT) != 0 && kernel != NULL)
errx(1, "-r and -k cannot be used together, there is no next kernel");
@@ -438,14 +465,10 @@ main(int argc, char *argv[])
(void)signal(SIGPIPE, SIG_IGN);
/*
* Only init(8) can perform rerooting.
* Common case: clean shutdown.
*/
if (howto & RB_REROOT) {
if (kill(1, SIGEMT) == -1)
err(1, "SIGEMT init");
return (0);
}
if (!dofast)
shutdown(howto);
/* Just stop init -- if we fail, we'll restart it. */
BOOTTRACE("SIGTSTP to init(8)...");
@@ -507,9 +530,12 @@ usage(void)
fprintf(stderr, "usage: nextboot [-aDf] "
"[-e name=value] [-k kernel] [-o options]\n");
} else {
fprintf(stderr, dohalt ?
"usage: halt [-clNnpq] [-k kernel]\n" :
"usage: reboot [-cdlNnpqr] [-k kernel]\n");
fprintf(stderr, "usage: %s%s [-%sflNnpq%s] "
"[-e name=value] [-k kernel] [-o options]\n",
dofast ? "fast" : "",
dohalt ? "halt" : dofast ? "boot" : "reboot",
dohalt ? "D" : "cDd",
dohalt || dofast ? "" : "r");
}
exit(1);
}