11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3237674Scharnierstatic const char copyright[] = 331558Srgrimes"@(#) Copyright (c) 1980, 1986, 1993\n\ 341558Srgrimes The Regents of the University of California. All rights reserved.\n"; 351558Srgrimes#endif /* not lint */ 361558Srgrimes 371558Srgrimes#ifndef lint 381558Srgrimesstatic char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 39114589Sobrien#endif /* not lint */ 4037674Scharnier#endif 41114589Sobrien#include <sys/cdefs.h> 42114589Sobrien__FBSDID("$FreeBSD$"); 431558Srgrimes 441558Srgrimes#include <sys/reboot.h> 45200161Sed#include <sys/time.h> 4637674Scharnier#include <sys/types.h> 4774525Siedowse#include <sys/sysctl.h> 481558Srgrimes#include <signal.h> 4937674Scharnier#include <err.h> 5037674Scharnier#include <errno.h> 5195485Swes#include <fcntl.h> 521558Srgrimes#include <pwd.h> 531558Srgrimes#include <syslog.h> 541558Srgrimes#include <stdio.h> 5578732Sdd#include <stdlib.h> 561558Srgrimes#include <string.h> 5737674Scharnier#include <unistd.h> 58202195Sed#include <utmpx.h> 591558Srgrimes 60140795Sdelphijstatic void usage(void); 61140795Sdelphijstatic u_int get_pageins(void); 621558Srgrimes 63228408Sedstatic int dohalt; 641558Srgrimes 651558Srgrimesint 6674525Siedowsemain(int argc, char *argv[]) 671558Srgrimes{ 68200161Sed struct utmpx utx; 69140795Sdelphij const struct passwd *pw; 70187956Sbz int ch, howto, i, fd, lflag, nflag, qflag, sverrno; 7174525Siedowse u_int pageins; 72228408Sed const char *user, *kernel = NULL; 731558Srgrimes 74228408Sed if (strcmp(getprogname(), "halt") == 0) { 751558Srgrimes dohalt = 1; 761558Srgrimes howto = RB_HALT; 771558Srgrimes } else 781558Srgrimes howto = 0; 79140794Sdelphij lflag = nflag = qflag = 0; 8095485Swes while ((ch = getopt(argc, argv, "dk:lnpq")) != -1) 811558Srgrimes switch(ch) { 8253523Sjdp case 'd': 8353523Sjdp howto |= RB_DUMP; 8453523Sjdp break; 8595485Swes case 'k': 8695485Swes kernel = optarg; 8795485Swes break; 8877122Snik case 'l': 891558Srgrimes lflag = 1; 901558Srgrimes break; 911558Srgrimes case 'n': 921558Srgrimes nflag = 1; 931558Srgrimes howto |= RB_NOSYNC; 941558Srgrimes break; 9517801Sjulian case 'p': 96104572Sthomas howto |= RB_POWEROFF; 9717801Sjulian break; 981558Srgrimes case 'q': 991558Srgrimes qflag = 1; 1001558Srgrimes break; 1011558Srgrimes case '?': 1021558Srgrimes default: 1031558Srgrimes usage(); 1041558Srgrimes } 1051558Srgrimes argc -= optind; 1061558Srgrimes argv += optind; 1071558Srgrimes 10853523Sjdp if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 10953523Sjdp errx(1, "cannot dump (-d) when halting; must reboot instead"); 11026676Scharnier if (geteuid()) { 11126676Scharnier errno = EPERM; 11226676Scharnier err(1, NULL); 11326676Scharnier } 1141558Srgrimes 1151558Srgrimes if (qflag) { 1161558Srgrimes reboot(howto); 11726676Scharnier err(1, NULL); 1181558Srgrimes } 1191558Srgrimes 120140794Sdelphij if (kernel != NULL) { 121143948Spjd fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC, 122143948Spjd 0444); 12395485Swes if (fd > -1) { 12497428Sgordon (void)write(fd, "nextboot_enable=\"YES\"\n", 22); 12595485Swes (void)write(fd, "kernel=\"", 8L); 12695485Swes (void)write(fd, kernel, strlen(kernel)); 12795485Swes (void)write(fd, "\"\n", 2); 12895485Swes close(fd); 12995485Swes } 13095485Swes } 13195485Swes 1321558Srgrimes /* Log the reboot. */ 1331558Srgrimes if (!lflag) { 1341558Srgrimes if ((user = getlogin()) == NULL) 1351558Srgrimes user = (pw = getpwuid(getuid())) ? 1361558Srgrimes pw->pw_name : "???"; 1371558Srgrimes if (dohalt) { 1381558Srgrimes openlog("halt", 0, LOG_AUTH | LOG_CONS); 1391558Srgrimes syslog(LOG_CRIT, "halted by %s", user); 1401558Srgrimes } else { 1411558Srgrimes openlog("reboot", 0, LOG_AUTH | LOG_CONS); 1421558Srgrimes syslog(LOG_CRIT, "rebooted by %s", user); 1431558Srgrimes } 1441558Srgrimes } 145200161Sed utx.ut_type = SHUTDOWN_TIME; 146200161Sed gettimeofday(&utx.ut_tv, NULL); 147200161Sed pututxline(&utx); 1481558Srgrimes 1491558Srgrimes /* 1501558Srgrimes * Do a sync early on, so disks start transfers while we're off 1511558Srgrimes * killing processes. Don't worry about writes done before the 1521558Srgrimes * processes die, the reboot system call syncs the disks. 1531558Srgrimes */ 1541558Srgrimes if (!nflag) 1551558Srgrimes sync(); 1561558Srgrimes 157160916Sbms /* 158160916Sbms * Ignore signals that we can get as a result of killing 159160916Sbms * parents, group leaders, etc. 160160916Sbms */ 161160916Sbms (void)signal(SIGHUP, SIG_IGN); 162160916Sbms (void)signal(SIGINT, SIG_IGN); 163160916Sbms (void)signal(SIGQUIT, SIG_IGN); 164160916Sbms (void)signal(SIGTERM, SIG_IGN); 165160916Sbms (void)signal(SIGTSTP, SIG_IGN); 166160914Sbms 167160916Sbms /* 168160916Sbms * If we're running in a pipeline, we don't want to die 169160916Sbms * after killing whatever we're writing to. 170160916Sbms */ 171160916Sbms (void)signal(SIGPIPE, SIG_IGN); 172160916Sbms 1731558Srgrimes /* Just stop init -- if we fail, we'll restart it. */ 1741558Srgrimes if (kill(1, SIGTSTP) == -1) 17526676Scharnier err(1, "SIGTSTP init"); 1761558Srgrimes 1771558Srgrimes /* Send a SIGTERM first, a chance to save the buffers. */ 178112991Srwatson if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 17926676Scharnier err(1, "SIGTERM processes"); 1801558Srgrimes 1811558Srgrimes /* 1821558Srgrimes * After the processes receive the signal, start the rest of the 1831558Srgrimes * buffers on their way. Wait 5 seconds between the SIGTERM and 18474525Siedowse * the SIGKILL to give everybody a chance. If there is a lot of 18574525Siedowse * paging activity then wait longer, up to a maximum of approx 18674525Siedowse * 60 seconds. 1871558Srgrimes */ 1881558Srgrimes sleep(2); 18974525Siedowse for (i = 0; i < 20; i++) { 19074525Siedowse pageins = get_pageins(); 19174525Siedowse if (!nflag) 19274525Siedowse sync(); 19374525Siedowse sleep(3); 19474525Siedowse if (get_pageins() == pageins) 19574525Siedowse break; 19674525Siedowse } 1971558Srgrimes 1981558Srgrimes for (i = 1;; ++i) { 1991558Srgrimes if (kill(-1, SIGKILL) == -1) { 2001558Srgrimes if (errno == ESRCH) 2011558Srgrimes break; 2021558Srgrimes goto restart; 2031558Srgrimes } 2041558Srgrimes if (i > 5) { 2051558Srgrimes (void)fprintf(stderr, 2061558Srgrimes "WARNING: some process(es) wouldn't die\n"); 2071558Srgrimes break; 2081558Srgrimes } 2091558Srgrimes (void)sleep(2 * i); 2101558Srgrimes } 2111558Srgrimes 2121558Srgrimes reboot(howto); 2131558Srgrimes /* FALLTHROUGH */ 2141558Srgrimes 2151558Srgrimesrestart: 2161558Srgrimes sverrno = errno; 21726676Scharnier errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 2181558Srgrimes strerror(sverrno)); 2191558Srgrimes /* NOTREACHED */ 2201558Srgrimes} 2211558Srgrimes 222140795Sdelphijstatic void 223199130Sdesusage(void) 2241558Srgrimes{ 225199130Sdes 226199130Sdes (void)fprintf(stderr, dohalt ? 227199130Sdes "usage: halt [-lnpq] [-k kernel]\n" : 228199130Sdes "usage: reboot [-dlnpq] [-k kernel]\n"); 2291558Srgrimes exit(1); 2301558Srgrimes} 23174525Siedowse 232140795Sdelphijstatic u_int 233201182Sedget_pageins(void) 23474525Siedowse{ 23574525Siedowse u_int pageins; 23674525Siedowse size_t len; 23774525Siedowse 23874525Siedowse len = sizeof(pageins); 23974525Siedowse if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 24074525Siedowse != 0) { 24174525Siedowse warnx("v_swappgsin"); 24274525Siedowse return (0); 24374525Siedowse } 24474525Siedowse return pageins; 24574525Siedowse} 246