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