reboot.c revision 331722
1163953Srrs/* 2169382Srrs * Copyright (c) 1980, 1986, 1993 3235828Stuexen * The Regents of the University of California. All rights reserved. 4235828Stuexen * 5163953Srrs * Redistribution and use in source and binary forms, with or without 6163953Srrs * modification, are permitted provided that the following conditions 7163953Srrs * are met: 8163953Srrs * 1. Redistributions of source code must retain the above copyright 9163953Srrs * notice, this list of conditions and the following disclaimer. 10228653Stuexen * 2. Redistributions in binary form must reproduce the above copyright 11163953Srrs * notice, this list of conditions and the following disclaimer in the 12163953Srrs * documentation and/or other materials provided with the distribution. 13163953Srrs * 4. Neither the name of the University nor the names of its contributors 14228653Stuexen * may be used to endorse or promote products derived from this software 15163953Srrs * without specific prior written permission. 16163953Srrs * 17163953Srrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27163953Srrs * SUCH DAMAGE. 28163953Srrs */ 29163953Srrs 30163953Srrs#if 0 31163953Srrs#ifndef lint 32163953Srrsstatic const char copyright[] = 33163953Srrs"@(#) Copyright (c) 1980, 1986, 1993\n\ 34163953Srrs The Regents of the University of California. All rights reserved.\n"; 35163953Srrs#endif /* not lint */ 36235828Stuexen 37235828Stuexen#ifndef lint 38163953Srrsstatic char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 39163953Srrs#endif /* not lint */ 40163953Srrs#endif 41163953Srrs#include <sys/cdefs.h> 42163953Srrs__FBSDID("$FreeBSD: stable/11/sbin/reboot/reboot.c 331722 2018-03-29 02:50:57Z eadler $"); 43179783Srrs 44170606Srrs#include <sys/reboot.h> 45163953Srrs#include <sys/time.h> 46163953Srrs#include <sys/types.h> 47163953Srrs#include <sys/sysctl.h> 48163953Srrs#include <signal.h> 49163953Srrs#include <err.h> 50163953Srrs#include <errno.h> 51170606Srrs#include <fcntl.h> 52163953Srrs#include <pwd.h> 53167598Srrs#include <syslog.h> 54167598Srrs#include <stdio.h> 55167598Srrs#include <stdlib.h> 56163953Srrs#include <string.h> 57163953Srrs#include <unistd.h> 58167598Srrs#include <utmpx.h> 59170606Srrs 60163953Srrsstatic void usage(void); 61163953Srrsstatic u_int get_pageins(void); 62163953Srrs 63163953Srrsstatic int dohalt; 64163953Srrs 65203847Stuexenint 66163953Srrsmain(int argc, char *argv[]) 67167598Srrs{ 68163953Srrs struct utmpx utx; 69163953Srrs const struct passwd *pw; 70163953Srrs int ch, howto, i, fd, lflag, nflag, qflag, sverrno, Nflag; 71167598Srrs u_int pageins; 72170606Srrs const char *user, *kernel = NULL; 73163953Srrs 74169208Srrs if (strcmp(getprogname(), "halt") == 0) { 75169208Srrs dohalt = 1; 76169208Srrs howto = RB_HALT; 77169208Srrs } else 78169208Srrs howto = 0; 79163953Srrs lflag = nflag = qflag = Nflag = 0; 80163953Srrs while ((ch = getopt(argc, argv, "dk:lNnpqr")) != -1) 81163953Srrs switch(ch) { 82228031Stuexen case 'd': 83170606Srrs howto |= RB_DUMP; 84163953Srrs break; 85163953Srrs case 'k': 86163953Srrs kernel = optarg; 87163953Srrs break; 88163953Srrs case 'l': 89163953Srrs lflag = 1; 90163953Srrs break; 91163953Srrs case 'n': 92163953Srrs nflag = 1; 93163953Srrs howto |= RB_NOSYNC; 94224641Stuexen break; 95224641Stuexen case 'N': 96163953Srrs nflag = 1; 97170606Srrs Nflag = 1; 98163953Srrs break; 99163953Srrs case 'p': 100163953Srrs howto |= RB_POWEROFF; 101163953Srrs break; 102163953Srrs case 'q': 103163953Srrs qflag = 1; 104170606Srrs break; 105163953Srrs case 'r': 106163953Srrs howto |= RB_REROOT; 107163953Srrs break; 108163953Srrs case '?': 109163953Srrs default: 110163953Srrs usage(); 111170606Srrs } 112163953Srrs argc -= optind; 113163953Srrs argv += optind; 114163953Srrs 115163953Srrs if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 116170606Srrs errx(1, "cannot dump (-d) when halting; must reboot instead"); 117163953Srrs if (Nflag && (howto & RB_NOSYNC) != 0) 118185694Srrs errx(1, "-N cannot be used with -n"); 119185694Srrs if ((howto & RB_REROOT) != 0 && howto != RB_REROOT) 120185694Srrs errx(1, "-r cannot be used with -d, -n, or -p"); 121185694Srrs if (geteuid()) { 122185694Srrs errno = EPERM; 123185694Srrs err(1, NULL); 124185694Srrs } 125185694Srrs 126163953Srrs if (qflag) { 127163953Srrs reboot(howto); 128163953Srrs err(1, NULL); 129170606Srrs } 130163953Srrs 131169208Srrs if (kernel != NULL) { 132169208Srrs fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC, 133163953Srrs 0444); 134163953Srrs if (fd > -1) { 135202782Stuexen (void)write(fd, "nextboot_enable=\"YES\"\n", 22); 136170606Srrs (void)write(fd, "kernel=\"", 8L); 137163953Srrs (void)write(fd, kernel, strlen(kernel)); 138163953Srrs (void)write(fd, "\"\n", 2); 139163953Srrs close(fd); 140163953Srrs } 141163953Srrs } 142163953Srrs 143163953Srrs /* Log the reboot. */ 144163953Srrs if (!lflag) { 145163953Srrs if ((user = getlogin()) == NULL) 146163953Srrs user = (pw = getpwuid(getuid())) ? 147163953Srrs pw->pw_name : "???"; 148170606Srrs if (dohalt) { 149163953Srrs openlog("halt", 0, LOG_AUTH | LOG_CONS); 150163953Srrs syslog(LOG_CRIT, "halted by %s", user); 151163953Srrs } else if (howto & RB_REROOT) { 152163953Srrs openlog("reroot", 0, LOG_AUTH | LOG_CONS); 153170606Srrs syslog(LOG_CRIT, "rerooted by %s", user); 154163953Srrs } else { 155297662Srrs openlog("reboot", 0, LOG_AUTH | LOG_CONS); 156297662Srrs syslog(LOG_CRIT, "rebooted by %s", user); 157297662Srrs } 158297662Srrs } 159297662Srrs utx.ut_type = SHUTDOWN_TIME; 160297662Srrs gettimeofday(&utx.ut_tv, NULL); 161297662Srrs pututxline(&utx); 162297662Srrs 163298187Stuexen /* 164297662Srrs * Do a sync early on, so disks start transfers while we're off 165297662Srrs * killing processes. Don't worry about writes done before the 166297662Srrs * processes die, the reboot system call syncs the disks. 167297662Srrs */ 168297662Srrs if (!nflag) 169297662Srrs sync(); 170297662Srrs 171297662Srrs /* 172163953Srrs * Ignore signals that we can get as a result of killing 173163953Srrs * parents, group leaders, etc. 174163953Srrs */ 175163953Srrs (void)signal(SIGHUP, SIG_IGN); 176163953Srrs (void)signal(SIGINT, SIG_IGN); 177163953Srrs (void)signal(SIGQUIT, SIG_IGN); 178163953Srrs (void)signal(SIGTERM, SIG_IGN); 179163953Srrs (void)signal(SIGTSTP, SIG_IGN); 180163953Srrs 181163953Srrs /* 182163953Srrs * If we're running in a pipeline, we don't want to die 183163953Srrs * after killing whatever we're writing to. 184170606Srrs */ 185163953Srrs (void)signal(SIGPIPE, SIG_IGN); 186167598Srrs 187167598Srrs /* 188170606Srrs * Only init(8) can perform rerooting. 189163953Srrs */ 190163953Srrs if (howto & RB_REROOT) { 191167598Srrs if (kill(1, SIGEMT) == -1) 192170606Srrs err(1, "SIGEMT init"); 193163953Srrs 194163953Srrs return (0); 195170606Srrs } 196163953Srrs 197163953Srrs /* Just stop init -- if we fail, we'll restart it. */ 198170606Srrs if (kill(1, SIGTSTP) == -1) 199163953Srrs err(1, "SIGTSTP init"); 200167598Srrs 201163953Srrs /* Send a SIGTERM first, a chance to save the buffers. */ 202167598Srrs if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 203163953Srrs err(1, "SIGTERM processes"); 204163953Srrs 205170606Srrs /* 206163953Srrs * After the processes receive the signal, start the rest of the 207163953Srrs * buffers on their way. Wait 5 seconds between the SIGTERM and 208163953Srrs * the SIGKILL to give everybody a chance. If there is a lot of 209163953Srrs * paging activity then wait longer, up to a maximum of approx 210163953Srrs * 60 seconds. 211163953Srrs */ 212170606Srrs sleep(2); 213163953Srrs for (i = 0; i < 20; i++) { 214163953Srrs pageins = get_pageins(); 215170606Srrs if (!nflag) 216163953Srrs sync(); 217163953Srrs sleep(3); 218163953Srrs if (get_pageins() == pageins) 219163953Srrs break; 220170606Srrs } 221163953Srrs 222163953Srrs for (i = 1;; ++i) { 223163953Srrs if (kill(-1, SIGKILL) == -1) { 224163953Srrs if (errno == ESRCH) 225163953Srrs break; 226170606Srrs goto restart; 227163953Srrs } 228163953Srrs if (i > 5) { 229163953Srrs (void)fprintf(stderr, 230163953Srrs "WARNING: some process(es) wouldn't die\n"); 231170606Srrs break; 232163953Srrs } 233163953Srrs (void)sleep(2 * i); 234163953Srrs } 235163953Srrs 236170606Srrs reboot(howto); 237163953Srrs /* FALLTHROUGH */ 238163953Srrs 239163953Srrsrestart: 240163953Srrs sverrno = errno; 241163953Srrs errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 242163953Srrs strerror(sverrno)); 243163953Srrs /* NOTREACHED */ 244163953Srrs} 245163953Srrs 246163953Srrsstatic void 247163953Srrsusage(void) 248170606Srrs{ 249163953Srrs 250163953Srrs (void)fprintf(stderr, dohalt ? 251163953Srrs "usage: halt [-lNnpq] [-k kernel]\n" : 252163953Srrs "usage: reboot [-dlNnpqr] [-k kernel]\n"); 253163953Srrs exit(1); 254163953Srrs} 255163953Srrs 256163953Srrsstatic u_int 257170606Srrsget_pageins(void) 258163953Srrs{ 259163953Srrs u_int pageins; 260163953Srrs size_t len; 261163953Srrs 262170606Srrs len = sizeof(pageins); 263163953Srrs if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 264185694Srrs != 0) { 265185694Srrs warnx("v_swappgsin"); 266185694Srrs return (0); 267185694Srrs } 268185694Srrs return pageins; 269185694Srrs} 270185694Srrs