diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8 index e9a23ef84d69..0a2fb91b6b0b 100644 --- a/sbin/reboot/reboot.8 +++ b/sbin/reboot/reboot.8 @@ -1,193 +1,198 @@ .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" 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 .Nm reboot , .Nm halt , .Nm fastboot , .Nm fasthalt .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 .Nm halt and .Nm utilities 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. .Pp The options are as follows: .Bl -tag -width indent .It Fl c The system will turn off the power and then turn it back on if it can. If the power down action fails, the system will halt or reboot normally, depending on whether .Nm halt or .Nm was called. At the present time, only the .Xr ipmi 4 driver implements the power cycle functionality and only on hardware with a BMC that supports power cycling. Unlike power off, the amount of hardware that supports power cycling is small. .It Fl d The system is requested to create a crash dump. 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 logged to the system log. This option is intended for applications such as .Xr shutdown 8 , that call .Nm or .Nm halt and log this themselves. .It Fl N The file system cache is not flushed during the initial process clean-up, however the kernel level .Xr reboot 2 is still processed with a sync. This option can be useful for performing a .Dq best-effort reboot when devices might be unavailable. This can happen when devices have been disconnected, such as with .Xr iscsi 4 . .It Fl n The file system cache is not flushed. This option should probably not be used. .It Fl p The system will turn off the power if it can. If the power down action fails, the system will halt or reboot normally, depending on whether .Nm halt or .Nm was called. .It Fl q The system is halted or restarted quickly and ungracefully, and only the flushing of the file system cache is performed (if the .Fl n option is not specified). This option should probably not be used. .It Fl r The system kills all processes, unmounts all filesystems, mounts the new root filesystem, and begins the usual startup sequence. After changing vfs.root.mountfrom with .Xr kenv 1 , .Nm Fl r can be used to change the root filesystem while preserving kernel state. This requires the .Xr tmpfs 5 kernel module to be loaded because .Xr init 8 needs a place to store itself after the old root is unmounted, but before the new root is in place. .El .Pp The .Nm fasthalt and .Nm fastboot utilities are nothing more than aliases for the .Nm halt and .Nm utilities. .Pp Normally, 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. .Sh EXAMPLES Replace current root filesystem with UFS mounted from .Pa /dev/ada0s1a : .Bd -literal -offset indent kenv vfs.root.mountfrom=ufs:/dev/ada0s1a reboot -r .Ed .Pp This mechanism can also be used with NFS, with a caveat that it only works with NFSv4, and requires a numeric IPv4 address: .Bd -literal -offset indent kenv vfs.root.mountfrom=nfs:192.168.1.1:/share/name reboot -r .Ed .Sh SEE ALSO .Xr kenv 1 , .Xr getutxent 3 , .Xr ipmi 4 , .Xr boot 8 , .Xr dumpon 8 , .Xr nextboot 8 , .Xr savecore 8 , .Xr shutdown 8 , .Xr sync 8 .Sh HISTORY A .Nm utility appeared in .Bx 4.0 . diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c index 7dcebef69b85..4eb5e8590589 100644 --- a/sbin/reboot/reboot.c +++ b/sbin/reboot/reboot.c @@ -1,280 +1,297 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void usage(void) __dead2; static uint64_t get_pageins(void); static bool dohalt; int 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; if (strstr(getprogname(), "halt") != NULL) { dohalt = true; 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': howto |= RB_POWERCYCLE; break; case 'd': howto |= RB_DUMP; break; + case 'f': + fflag = true; + break; case 'k': kernel = optarg; break; case 'l': lflag = true; break; case 'n': nflag = true; howto |= RB_NOSYNC; break; case 'N': nflag = true; Nflag = true; break; case 'p': howto |= RB_POWEROFF; break; case 'q': qflag = true; break; case 'r': howto |= RB_REROOT; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 0) usage(); if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) errx(1, "cannot dump (-d) when halting; must reboot instead"); if (Nflag && (howto & RB_NOSYNC) != 0) errx(1, "-N cannot be used with -n"); if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE)) 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 && kernel != NULL) errx(1, "-r and -k cannot be used together, there is no next kernel"); if (geteuid()) { errno = EPERM; err(1, NULL); } if (qflag) { reboot(howto); err(1, NULL); } 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) { (void)write(fd, "nextboot_enable=\"YES\"\n", 22); (void)write(fd, "kernel=\"", 8L); (void)write(fd, kernel, strlen(kernel)); (void)write(fd, "\"\n", 2); close(fd); } } /* Log the reboot. */ if (!lflag) { if ((user = getlogin()) == NULL) user = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; if (dohalt) { openlog("halt", 0, LOG_AUTH | LOG_CONS); syslog(LOG_CRIT, "halted by %s", user); } else if (howto & RB_REROOT) { openlog("reroot", 0, LOG_AUTH | LOG_CONS); syslog(LOG_CRIT, "rerooted by %s", user); } else if (howto & RB_POWEROFF) { openlog("reboot", 0, LOG_AUTH | LOG_CONS); syslog(LOG_CRIT, "powered off by %s", user); } else if (howto & RB_POWERCYCLE) { openlog("reboot", 0, LOG_AUTH | LOG_CONS); syslog(LOG_CRIT, "power cycled by %s", user); } else { openlog("reboot", 0, LOG_AUTH | LOG_CONS); syslog(LOG_CRIT, "rebooted by %s", user); } } utx.ut_type = SHUTDOWN_TIME; gettimeofday(&utx.ut_tv, NULL); pututxline(&utx); /* * Do a sync early on, so disks start transfers while we're off * killing processes. Don't worry about writes done before the * processes die, the reboot system call syncs the disks. */ if (!nflag) sync(); /* * Ignore signals that we can get as a result of killing * parents, group leaders, etc. */ (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGTERM, SIG_IGN); (void)signal(SIGTSTP, SIG_IGN); /* * If we're running in a pipeline, we don't want to die * after killing whatever we're writing to. */ (void)signal(SIGPIPE, SIG_IGN); /* * Only init(8) can perform rerooting. */ if (howto & RB_REROOT) { if (kill(1, SIGEMT) == -1) err(1, "SIGEMT init"); return (0); } /* Just stop init -- if we fail, we'll restart it. */ BOOTTRACE("SIGTSTP to init(8)..."); if (kill(1, SIGTSTP) == -1) err(1, "SIGTSTP init"); /* Send a SIGTERM first, a chance to save the buffers. */ BOOTTRACE("SIGTERM to all other processes..."); if (kill(-1, SIGTERM) == -1 && errno != ESRCH) err(1, "SIGTERM processes"); /* * After the processes receive the signal, start the rest of the * buffers on their way. Wait 5 seconds between the SIGTERM and * the SIGKILL to give everybody a chance. If there is a lot of * paging activity then wait longer, up to a maximum of approx * 60 seconds. */ sleep(2); for (i = 0; i < 20; i++) { pageins = get_pageins(); if (!nflag) sync(); sleep(3); if (get_pageins() == pageins) break; } for (i = 1;; ++i) { BOOTTRACE("SIGKILL to all other processes(%d)...", i); if (kill(-1, SIGKILL) == -1) { if (errno == ESRCH) break; goto restart; } if (i > 5) { (void)fprintf(stderr, "WARNING: some process(es) wouldn't die\n"); break; } (void)sleep(2 * i); } reboot(howto); /* FALLTHROUGH */ restart: BOOTTRACE("SIGHUP to init(8)..."); sverrno = errno; errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", strerror(sverrno)); /* NOTREACHED */ } static void usage(void) { (void)fprintf(stderr, dohalt ? "usage: halt [-clNnpq] [-k kernel]\n" : "usage: reboot [-cdlNnpqr] [-k kernel]\n"); exit(1); } static uint64_t get_pageins(void) { uint64_t pageins; size_t len; len = sizeof(pageins); if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) != 0) { warn("v_swappgsin"); return (0); } return (pageins); }