reboot.c revision 140794
114630Sokutsu/* 214630Sokutsu * Copyright (c) 1980, 1986, 1993 314630Sokutsu * The Regents of the University of California. All rights reserved. 414630Sokutsu * 514630Sokutsu * Redistribution and use in source and binary forms, with or without 614630Sokutsu * modification, are permitted provided that the following conditions 714630Sokutsu * are met: 814630Sokutsu * 1. Redistributions of source code must retain the above copyright 914630Sokutsu * notice, this list of conditions and the following disclaimer. 1014630Sokutsu * 2. Redistributions in binary form must reproduce the above copyright 1114630Sokutsu * notice, this list of conditions and the following disclaimer in the 1214630Sokutsu * documentation and/or other materials provided with the distribution. 1314630Sokutsu * 4. Neither the name of the University nor the names of its contributors 1414630Sokutsu * may be used to endorse or promote products derived from this software 1514630Sokutsu * without specific prior written permission. 1614630Sokutsu * 1714630Sokutsu * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1814630Sokutsu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1914630Sokutsu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2014630Sokutsu * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2114630Sokutsu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2214630Sokutsu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2314630Sokutsu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2414630Sokutsu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2514630Sokutsu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2614630Sokutsu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2714630Sokutsu * SUCH DAMAGE. 2814630Sokutsu */ 2914630Sokutsu 3014630Sokutsu#if 0 3114630Sokutsu#ifndef lint 3214630Sokutsustatic const char copyright[] = 3314630Sokutsu"@(#) Copyright (c) 1980, 1986, 1993\n\ 3414630Sokutsu The Regents of the University of California. All rights reserved.\n"; 3514630Sokutsu#endif /* not lint */ 3614630Sokutsu 3714630Sokutsu#ifndef lint 3814630Sokutsustatic char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 3914630Sokutsu#endif /* not lint */ 4014630Sokutsu#endif 4114630Sokutsu#include <sys/cdefs.h> 4214630Sokutsu__FBSDID("$FreeBSD: head/sbin/reboot/reboot.c 140794 2005-01-25 08:14:00Z delphij $"); 4314630Sokutsu 4414630Sokutsu#include <sys/reboot.h> 4514630Sokutsu#include <sys/types.h> 4614630Sokutsu#include <sys/sysctl.h> 4714630Sokutsu#include <signal.h> 4814630Sokutsu#include <err.h> 4914630Sokutsu#include <errno.h> 5014630Sokutsu#include <fcntl.h> 5114630Sokutsu#include <libutil.h> 5214630Sokutsu#include <pwd.h> 5314630Sokutsu#include <syslog.h> 5414630Sokutsu#include <stdio.h> 5514630Sokutsu#include <stdlib.h> 5614630Sokutsu#include <string.h> 5714630Sokutsu#include <unistd.h> 5814630Sokutsu 5914630Sokutsuvoid usage(void); 6014630Sokutsuu_int get_pageins(void); 6114630Sokutsu 6214630Sokutsuint dohalt; 6314630Sokutsu 6414630Sokutsuint 6514630Sokutsumain(int argc, char *argv[]) 6614630Sokutsu{ 6714630Sokutsu struct passwd *pw; 6814630Sokutsu int ch, howto, i, fd, lflag, nflag, qflag, pflag, sverrno; 6914630Sokutsu u_int pageins; 7014630Sokutsu char *kernel = NULL, *p; 7114630Sokutsu const char *user; 7214630Sokutsu 7314630Sokutsu if (strstr((p = rindex(*argv, '/')) ? p + 1 : *argv, "halt")) { 7414630Sokutsu dohalt = 1; 7514630Sokutsu howto = RB_HALT; 7614630Sokutsu } else 7714630Sokutsu howto = 0; 7814630Sokutsu lflag = nflag = qflag = 0; 7914630Sokutsu while ((ch = getopt(argc, argv, "dk:lnpq")) != -1) 8014630Sokutsu switch(ch) { 8114630Sokutsu case 'd': 8214630Sokutsu howto |= RB_DUMP; 8314630Sokutsu break; 8414630Sokutsu case 'k': 8514630Sokutsu kernel = optarg; 8614630Sokutsu break; 8714630Sokutsu case 'l': 8814630Sokutsu lflag = 1; 8914630Sokutsu break; 9014630Sokutsu case 'n': 9114630Sokutsu nflag = 1; 9214630Sokutsu howto |= RB_NOSYNC; 9314630Sokutsu break; 9414630Sokutsu case 'p': 9514630Sokutsu pflag = 1; 9614630Sokutsu howto |= RB_POWEROFF; 9714630Sokutsu break; 9814630Sokutsu case 'q': 9914630Sokutsu qflag = 1; 10014630Sokutsu break; 10114630Sokutsu case '?': 10214630Sokutsu default: 10314630Sokutsu usage(); 10414630Sokutsu } 10514630Sokutsu argc -= optind; 10614630Sokutsu argv += optind; 10714630Sokutsu 10814630Sokutsu if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 10914630Sokutsu errx(1, "cannot dump (-d) when halting; must reboot instead"); 11014630Sokutsu if (geteuid()) { 11114630Sokutsu errno = EPERM; 11214630Sokutsu err(1, NULL); 11314630Sokutsu } 11414630Sokutsu 11514630Sokutsu if (qflag) { 11614630Sokutsu reboot(howto); 11714630Sokutsu err(1, NULL); 11814630Sokutsu } 11914630Sokutsu 12014630Sokutsu if (kernel != NULL) { 12114630Sokutsu fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT, 0444); 12214630Sokutsu if (fd > -1) { 12314630Sokutsu (void)write(fd, "nextboot_enable=\"YES\"\n", 22); 12414630Sokutsu (void)write(fd, "kernel=\"", 8L); 12514630Sokutsu (void)write(fd, kernel, strlen(kernel)); 12614630Sokutsu (void)write(fd, "\"\n", 2); 12714630Sokutsu close(fd); 12814630Sokutsu } 12914630Sokutsu } 13014630Sokutsu 13114630Sokutsu /* Log the reboot. */ 13214630Sokutsu if (!lflag) { 13314630Sokutsu if ((user = getlogin()) == NULL) 13414630Sokutsu user = (pw = getpwuid(getuid())) ? 13514630Sokutsu pw->pw_name : "???"; 13614630Sokutsu if (dohalt) { 13714630Sokutsu openlog("halt", 0, LOG_AUTH | LOG_CONS); 13814630Sokutsu syslog(LOG_CRIT, "halted by %s", user); 13914630Sokutsu } else { 14014630Sokutsu openlog("reboot", 0, LOG_AUTH | LOG_CONS); 14114630Sokutsu syslog(LOG_CRIT, "rebooted by %s", user); 14214630Sokutsu } 14314630Sokutsu } 14414630Sokutsu logwtmp("~", "shutdown", ""); 14514630Sokutsu 14614630Sokutsu /* 14714630Sokutsu * Do a sync early on, so disks start transfers while we're off 14814630Sokutsu * killing processes. Don't worry about writes done before the 14914630Sokutsu * processes die, the reboot system call syncs the disks. 15014630Sokutsu */ 15114630Sokutsu if (!nflag) 15214630Sokutsu sync(); 15314630Sokutsu 15414630Sokutsu /* Just stop init -- if we fail, we'll restart it. */ 15514630Sokutsu if (kill(1, SIGTSTP) == -1) 15614630Sokutsu err(1, "SIGTSTP init"); 15714630Sokutsu 15814630Sokutsu /* Ignore the SIGHUP we get when our parent shell dies. */ 15914630Sokutsu (void)signal(SIGHUP, SIG_IGN); 16014630Sokutsu 16114630Sokutsu /* Send a SIGTERM first, a chance to save the buffers. */ 16214630Sokutsu if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 16314630Sokutsu err(1, "SIGTERM processes"); 16414630Sokutsu 16514630Sokutsu /* 16614630Sokutsu * After the processes receive the signal, start the rest of the 16714630Sokutsu * buffers on their way. Wait 5 seconds between the SIGTERM and 16814630Sokutsu * the SIGKILL to give everybody a chance. If there is a lot of 16914630Sokutsu * paging activity then wait longer, up to a maximum of approx 17014630Sokutsu * 60 seconds. 17114630Sokutsu */ 17214630Sokutsu sleep(2); 17314630Sokutsu for (i = 0; i < 20; i++) { 17414630Sokutsu pageins = get_pageins(); 17514630Sokutsu if (!nflag) 17614630Sokutsu sync(); 17714630Sokutsu sleep(3); 17814630Sokutsu if (get_pageins() == pageins) 17914630Sokutsu break; 18014630Sokutsu } 18114630Sokutsu 18214630Sokutsu for (i = 1;; ++i) { 18314630Sokutsu if (kill(-1, SIGKILL) == -1) { 18414630Sokutsu if (errno == ESRCH) 18514630Sokutsu break; 18614630Sokutsu goto restart; 18714630Sokutsu } 18814630Sokutsu if (i > 5) { 18914630Sokutsu (void)fprintf(stderr, 19014630Sokutsu "WARNING: some process(es) wouldn't die\n"); 19114630Sokutsu break; 19214630Sokutsu } 19314630Sokutsu (void)sleep(2 * i); 19414630Sokutsu } 19514630Sokutsu 19614630Sokutsu reboot(howto); 19714630Sokutsu /* FALLTHROUGH */ 19814630Sokutsu 19914630Sokutsurestart: 20014630Sokutsu sverrno = errno; 20114630Sokutsu errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 20214630Sokutsu strerror(sverrno)); 20314630Sokutsu /* NOTREACHED */ 20414630Sokutsu} 20514630Sokutsu 20614630Sokutsuvoid 20714630Sokutsuusage() 20814630Sokutsu{ 20914630Sokutsu (void)fprintf(stderr, "usage: %s [-dnpq] [-k kernel]\n", 21014630Sokutsu dohalt ? "halt" : "reboot"); 21114630Sokutsu exit(1); 21214630Sokutsu} 21314630Sokutsu 21414630Sokutsuu_int 21514630Sokutsuget_pageins() 21614630Sokutsu{ 21714630Sokutsu u_int pageins; 21814630Sokutsu size_t len; 21914630Sokutsu 22014630Sokutsu len = sizeof(pageins); 22114630Sokutsu if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 22214630Sokutsu != 0) { 22314630Sokutsu warnx("v_swappgsin"); 22414630Sokutsu return (0); 22514630Sokutsu } 22614630Sokutsu return pageins; 22714630Sokutsu} 22814630Sokutsu