reboot.c revision 160914
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: head/sbin/reboot/reboot.c 160914 2006-08-02 12:42:20Z bms $"); 431558Srgrimes 441558Srgrimes#include <sys/reboot.h> 4537674Scharnier#include <sys/types.h> 4674525Siedowse#include <sys/sysctl.h> 471558Srgrimes#include <signal.h> 4837674Scharnier#include <err.h> 4937674Scharnier#include <errno.h> 5095485Swes#include <fcntl.h> 5137674Scharnier#include <libutil.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> 581558Srgrimes 59140795Sdelphijstatic void usage(void); 60140795Sdelphijstatic u_int get_pageins(void); 611558Srgrimes 621558Srgrimesint dohalt; 631558Srgrimes 641558Srgrimesint 6574525Siedowsemain(int argc, char *argv[]) 661558Srgrimes{ 67140795Sdelphij const struct passwd *pw; 68140794Sdelphij int ch, howto, i, fd, lflag, nflag, qflag, pflag, sverrno; 6974525Siedowse u_int pageins; 70140795Sdelphij const char *p, *user, *kernel = NULL; 711558Srgrimes 722171Sdg if (strstr((p = rindex(*argv, '/')) ? p + 1 : *argv, "halt")) { 731558Srgrimes dohalt = 1; 741558Srgrimes howto = RB_HALT; 751558Srgrimes } else 761558Srgrimes howto = 0; 77140794Sdelphij lflag = nflag = qflag = 0; 7895485Swes while ((ch = getopt(argc, argv, "dk:lnpq")) != -1) 791558Srgrimes switch(ch) { 8053523Sjdp case 'd': 8153523Sjdp howto |= RB_DUMP; 8253523Sjdp break; 8395485Swes case 'k': 8495485Swes kernel = optarg; 8595485Swes break; 8677122Snik case 'l': 871558Srgrimes lflag = 1; 881558Srgrimes break; 891558Srgrimes case 'n': 901558Srgrimes nflag = 1; 911558Srgrimes howto |= RB_NOSYNC; 921558Srgrimes break; 9317801Sjulian case 'p': 9417801Sjulian pflag = 1; 95104572Sthomas howto |= RB_POWEROFF; 9617801Sjulian break; 971558Srgrimes case 'q': 981558Srgrimes qflag = 1; 991558Srgrimes break; 1001558Srgrimes case '?': 1011558Srgrimes default: 1021558Srgrimes usage(); 1031558Srgrimes } 1041558Srgrimes argc -= optind; 1051558Srgrimes argv += optind; 1061558Srgrimes 10753523Sjdp if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 10853523Sjdp errx(1, "cannot dump (-d) when halting; must reboot instead"); 10926676Scharnier if (geteuid()) { 11026676Scharnier errno = EPERM; 11126676Scharnier err(1, NULL); 11226676Scharnier } 1131558Srgrimes 1141558Srgrimes if (qflag) { 1151558Srgrimes reboot(howto); 11626676Scharnier err(1, NULL); 1171558Srgrimes } 1181558Srgrimes 119140794Sdelphij if (kernel != NULL) { 120143948Spjd fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC, 121143948Spjd 0444); 12295485Swes if (fd > -1) { 12397428Sgordon (void)write(fd, "nextboot_enable=\"YES\"\n", 22); 12495485Swes (void)write(fd, "kernel=\"", 8L); 12595485Swes (void)write(fd, kernel, strlen(kernel)); 12695485Swes (void)write(fd, "\"\n", 2); 12795485Swes close(fd); 12895485Swes } 12995485Swes } 13095485Swes 1311558Srgrimes /* Log the reboot. */ 1321558Srgrimes if (!lflag) { 1331558Srgrimes if ((user = getlogin()) == NULL) 1341558Srgrimes user = (pw = getpwuid(getuid())) ? 1351558Srgrimes pw->pw_name : "???"; 1361558Srgrimes if (dohalt) { 1371558Srgrimes openlog("halt", 0, LOG_AUTH | LOG_CONS); 1381558Srgrimes syslog(LOG_CRIT, "halted by %s", user); 1391558Srgrimes } else { 1401558Srgrimes openlog("reboot", 0, LOG_AUTH | LOG_CONS); 1411558Srgrimes syslog(LOG_CRIT, "rebooted by %s", user); 1421558Srgrimes } 1431558Srgrimes } 1441558Srgrimes logwtmp("~", "shutdown", ""); 1451558Srgrimes 1461558Srgrimes /* 1471558Srgrimes * Do a sync early on, so disks start transfers while we're off 1481558Srgrimes * killing processes. Don't worry about writes done before the 1491558Srgrimes * processes die, the reboot system call syncs the disks. 1501558Srgrimes */ 1511558Srgrimes if (!nflag) 1521558Srgrimes sync(); 1531558Srgrimes 154160914Sbms /* Ignore the SIGHUP we get when our parent shell dies. */ 155160914Sbms (void)signal(SIGHUP, SIG_IGN); 156160914Sbms 1571558Srgrimes /* Just stop init -- if we fail, we'll restart it. */ 1581558Srgrimes if (kill(1, SIGTSTP) == -1) 15926676Scharnier err(1, "SIGTSTP init"); 1601558Srgrimes 1611558Srgrimes /* Send a SIGTERM first, a chance to save the buffers. */ 162112991Srwatson if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 16326676Scharnier err(1, "SIGTERM processes"); 1641558Srgrimes 1651558Srgrimes /* 1661558Srgrimes * After the processes receive the signal, start the rest of the 1671558Srgrimes * buffers on their way. Wait 5 seconds between the SIGTERM and 16874525Siedowse * the SIGKILL to give everybody a chance. If there is a lot of 16974525Siedowse * paging activity then wait longer, up to a maximum of approx 17074525Siedowse * 60 seconds. 1711558Srgrimes */ 1721558Srgrimes sleep(2); 17374525Siedowse for (i = 0; i < 20; i++) { 17474525Siedowse pageins = get_pageins(); 17574525Siedowse if (!nflag) 17674525Siedowse sync(); 17774525Siedowse sleep(3); 17874525Siedowse if (get_pageins() == pageins) 17974525Siedowse break; 18074525Siedowse } 1811558Srgrimes 1821558Srgrimes for (i = 1;; ++i) { 1831558Srgrimes if (kill(-1, SIGKILL) == -1) { 1841558Srgrimes if (errno == ESRCH) 1851558Srgrimes break; 1861558Srgrimes goto restart; 1871558Srgrimes } 1881558Srgrimes if (i > 5) { 1891558Srgrimes (void)fprintf(stderr, 1901558Srgrimes "WARNING: some process(es) wouldn't die\n"); 1911558Srgrimes break; 1921558Srgrimes } 1931558Srgrimes (void)sleep(2 * i); 1941558Srgrimes } 1951558Srgrimes 1961558Srgrimes reboot(howto); 1971558Srgrimes /* FALLTHROUGH */ 1981558Srgrimes 1991558Srgrimesrestart: 2001558Srgrimes sverrno = errno; 20126676Scharnier errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 2021558Srgrimes strerror(sverrno)); 2031558Srgrimes /* NOTREACHED */ 2041558Srgrimes} 2051558Srgrimes 206140795Sdelphijstatic void 2071558Srgrimesusage() 2081558Srgrimes{ 209141611Sru (void)fprintf(stderr, "usage: %s [-%slnpq] [-k kernel]\n", 210141611Sru getprogname(), dohalt ? "" : "d"); 2111558Srgrimes exit(1); 2121558Srgrimes} 21374525Siedowse 214140795Sdelphijstatic u_int 21574525Siedowseget_pageins() 21674525Siedowse{ 21774525Siedowse u_int pageins; 21874525Siedowse size_t len; 21974525Siedowse 22074525Siedowse len = sizeof(pageins); 22174525Siedowse if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 22274525Siedowse != 0) { 22374525Siedowse warnx("v_swappgsin"); 22474525Siedowse return (0); 22574525Siedowse } 22674525Siedowse return pageins; 22774525Siedowse} 228