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