reboot.c revision 331722
1163953Srrs/*
2169382Srrs * Copyright (c) 1980, 1986, 1993
3235828Stuexen *	The Regents of the University of California.  All rights reserved.
4235828Stuexen *
5163953Srrs * Redistribution and use in source and binary forms, with or without
6163953Srrs * modification, are permitted provided that the following conditions
7163953Srrs * are met:
8163953Srrs * 1. Redistributions of source code must retain the above copyright
9163953Srrs *    notice, this list of conditions and the following disclaimer.
10228653Stuexen * 2. Redistributions in binary form must reproduce the above copyright
11163953Srrs *    notice, this list of conditions and the following disclaimer in the
12163953Srrs *    documentation and/or other materials provided with the distribution.
13163953Srrs * 4. Neither the name of the University nor the names of its contributors
14228653Stuexen *    may be used to endorse or promote products derived from this software
15163953Srrs *    without specific prior written permission.
16163953Srrs *
17163953Srrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20163953Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27163953Srrs * SUCH DAMAGE.
28163953Srrs */
29163953Srrs
30163953Srrs#if 0
31163953Srrs#ifndef lint
32163953Srrsstatic const char copyright[] =
33163953Srrs"@(#) Copyright (c) 1980, 1986, 1993\n\
34163953Srrs	The Regents of the University of California.  All rights reserved.\n";
35163953Srrs#endif /* not lint */
36235828Stuexen
37235828Stuexen#ifndef lint
38163953Srrsstatic char sccsid[] = "@(#)reboot.c	8.1 (Berkeley) 6/5/93";
39163953Srrs#endif /* not lint */
40163953Srrs#endif
41163953Srrs#include <sys/cdefs.h>
42163953Srrs__FBSDID("$FreeBSD: stable/11/sbin/reboot/reboot.c 331722 2018-03-29 02:50:57Z eadler $");
43179783Srrs
44170606Srrs#include <sys/reboot.h>
45163953Srrs#include <sys/time.h>
46163953Srrs#include <sys/types.h>
47163953Srrs#include <sys/sysctl.h>
48163953Srrs#include <signal.h>
49163953Srrs#include <err.h>
50163953Srrs#include <errno.h>
51170606Srrs#include <fcntl.h>
52163953Srrs#include <pwd.h>
53167598Srrs#include <syslog.h>
54167598Srrs#include <stdio.h>
55167598Srrs#include <stdlib.h>
56163953Srrs#include <string.h>
57163953Srrs#include <unistd.h>
58167598Srrs#include <utmpx.h>
59170606Srrs
60163953Srrsstatic void usage(void);
61163953Srrsstatic u_int get_pageins(void);
62163953Srrs
63163953Srrsstatic int dohalt;
64163953Srrs
65203847Stuexenint
66163953Srrsmain(int argc, char *argv[])
67167598Srrs{
68163953Srrs	struct utmpx utx;
69163953Srrs	const struct passwd *pw;
70163953Srrs	int ch, howto, i, fd, lflag, nflag, qflag, sverrno, Nflag;
71167598Srrs	u_int pageins;
72170606Srrs	const char *user, *kernel = NULL;
73163953Srrs
74169208Srrs	if (strcmp(getprogname(), "halt") == 0) {
75169208Srrs		dohalt = 1;
76169208Srrs		howto = RB_HALT;
77169208Srrs	} else
78169208Srrs		howto = 0;
79163953Srrs	lflag = nflag = qflag = Nflag = 0;
80163953Srrs	while ((ch = getopt(argc, argv, "dk:lNnpqr")) != -1)
81163953Srrs		switch(ch) {
82228031Stuexen		case 'd':
83170606Srrs			howto |= RB_DUMP;
84163953Srrs			break;
85163953Srrs		case 'k':
86163953Srrs			kernel = optarg;
87163953Srrs			break;
88163953Srrs		case 'l':
89163953Srrs			lflag = 1;
90163953Srrs			break;
91163953Srrs		case 'n':
92163953Srrs			nflag = 1;
93163953Srrs			howto |= RB_NOSYNC;
94224641Stuexen			break;
95224641Stuexen		case 'N':
96163953Srrs			nflag = 1;
97170606Srrs			Nflag = 1;
98163953Srrs			break;
99163953Srrs		case 'p':
100163953Srrs			howto |= RB_POWEROFF;
101163953Srrs			break;
102163953Srrs		case 'q':
103163953Srrs			qflag = 1;
104170606Srrs			break;
105163953Srrs		case 'r':
106163953Srrs			howto |= RB_REROOT;
107163953Srrs			break;
108163953Srrs		case '?':
109163953Srrs		default:
110163953Srrs			usage();
111170606Srrs		}
112163953Srrs	argc -= optind;
113163953Srrs	argv += optind;
114163953Srrs
115163953Srrs	if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
116170606Srrs		errx(1, "cannot dump (-d) when halting; must reboot instead");
117163953Srrs	if (Nflag && (howto & RB_NOSYNC) != 0)
118185694Srrs		errx(1, "-N cannot be used with -n");
119185694Srrs	if ((howto & RB_REROOT) != 0 && howto != RB_REROOT)
120185694Srrs		errx(1, "-r cannot be used with -d, -n, or -p");
121185694Srrs	if (geteuid()) {
122185694Srrs		errno = EPERM;
123185694Srrs		err(1, NULL);
124185694Srrs	}
125185694Srrs
126163953Srrs	if (qflag) {
127163953Srrs		reboot(howto);
128163953Srrs		err(1, NULL);
129170606Srrs	}
130163953Srrs
131169208Srrs	if (kernel != NULL) {
132169208Srrs		fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC,
133163953Srrs		    0444);
134163953Srrs		if (fd > -1) {
135202782Stuexen			(void)write(fd, "nextboot_enable=\"YES\"\n", 22);
136170606Srrs			(void)write(fd, "kernel=\"", 8L);
137163953Srrs			(void)write(fd, kernel, strlen(kernel));
138163953Srrs			(void)write(fd, "\"\n", 2);
139163953Srrs			close(fd);
140163953Srrs		}
141163953Srrs	}
142163953Srrs
143163953Srrs	/* Log the reboot. */
144163953Srrs	if (!lflag)  {
145163953Srrs		if ((user = getlogin()) == NULL)
146163953Srrs			user = (pw = getpwuid(getuid())) ?
147163953Srrs			    pw->pw_name : "???";
148170606Srrs		if (dohalt) {
149163953Srrs			openlog("halt", 0, LOG_AUTH | LOG_CONS);
150163953Srrs			syslog(LOG_CRIT, "halted by %s", user);
151163953Srrs		} else if (howto & RB_REROOT) {
152163953Srrs			openlog("reroot", 0, LOG_AUTH | LOG_CONS);
153170606Srrs			syslog(LOG_CRIT, "rerooted by %s", user);
154163953Srrs		} else {
155297662Srrs			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
156297662Srrs			syslog(LOG_CRIT, "rebooted by %s", user);
157297662Srrs		}
158297662Srrs	}
159297662Srrs	utx.ut_type = SHUTDOWN_TIME;
160297662Srrs	gettimeofday(&utx.ut_tv, NULL);
161297662Srrs	pututxline(&utx);
162297662Srrs
163298187Stuexen	/*
164297662Srrs	 * Do a sync early on, so disks start transfers while we're off
165297662Srrs	 * killing processes.  Don't worry about writes done before the
166297662Srrs	 * processes die, the reboot system call syncs the disks.
167297662Srrs	 */
168297662Srrs	if (!nflag)
169297662Srrs		sync();
170297662Srrs
171297662Srrs	/*
172163953Srrs	 * Ignore signals that we can get as a result of killing
173163953Srrs	 * parents, group leaders, etc.
174163953Srrs	 */
175163953Srrs	(void)signal(SIGHUP,  SIG_IGN);
176163953Srrs	(void)signal(SIGINT,  SIG_IGN);
177163953Srrs	(void)signal(SIGQUIT, SIG_IGN);
178163953Srrs	(void)signal(SIGTERM, SIG_IGN);
179163953Srrs	(void)signal(SIGTSTP, SIG_IGN);
180163953Srrs
181163953Srrs	/*
182163953Srrs	 * If we're running in a pipeline, we don't want to die
183163953Srrs	 * after killing whatever we're writing to.
184170606Srrs	 */
185163953Srrs	(void)signal(SIGPIPE, SIG_IGN);
186167598Srrs
187167598Srrs	/*
188170606Srrs	 * Only init(8) can perform rerooting.
189163953Srrs	 */
190163953Srrs	if (howto & RB_REROOT) {
191167598Srrs		if (kill(1, SIGEMT) == -1)
192170606Srrs			err(1, "SIGEMT init");
193163953Srrs
194163953Srrs		return (0);
195170606Srrs	}
196163953Srrs
197163953Srrs	/* Just stop init -- if we fail, we'll restart it. */
198170606Srrs	if (kill(1, SIGTSTP) == -1)
199163953Srrs		err(1, "SIGTSTP init");
200167598Srrs
201163953Srrs	/* Send a SIGTERM first, a chance to save the buffers. */
202167598Srrs	if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
203163953Srrs		err(1, "SIGTERM processes");
204163953Srrs
205170606Srrs	/*
206163953Srrs	 * After the processes receive the signal, start the rest of the
207163953Srrs	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
208163953Srrs	 * the SIGKILL to give everybody a chance. If there is a lot of
209163953Srrs	 * paging activity then wait longer, up to a maximum of approx
210163953Srrs	 * 60 seconds.
211163953Srrs	 */
212170606Srrs	sleep(2);
213163953Srrs	for (i = 0; i < 20; i++) {
214163953Srrs		pageins = get_pageins();
215170606Srrs		if (!nflag)
216163953Srrs			sync();
217163953Srrs		sleep(3);
218163953Srrs		if (get_pageins() == pageins)
219163953Srrs			break;
220170606Srrs	}
221163953Srrs
222163953Srrs	for (i = 1;; ++i) {
223163953Srrs		if (kill(-1, SIGKILL) == -1) {
224163953Srrs			if (errno == ESRCH)
225163953Srrs				break;
226170606Srrs			goto restart;
227163953Srrs		}
228163953Srrs		if (i > 5) {
229163953Srrs			(void)fprintf(stderr,
230163953Srrs			    "WARNING: some process(es) wouldn't die\n");
231170606Srrs			break;
232163953Srrs		}
233163953Srrs		(void)sleep(2 * i);
234163953Srrs	}
235163953Srrs
236170606Srrs	reboot(howto);
237163953Srrs	/* FALLTHROUGH */
238163953Srrs
239163953Srrsrestart:
240163953Srrs	sverrno = errno;
241163953Srrs	errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
242163953Srrs	    strerror(sverrno));
243163953Srrs	/* NOTREACHED */
244163953Srrs}
245163953Srrs
246163953Srrsstatic void
247163953Srrsusage(void)
248170606Srrs{
249163953Srrs
250163953Srrs	(void)fprintf(stderr, dohalt ?
251163953Srrs	    "usage: halt [-lNnpq] [-k kernel]\n" :
252163953Srrs	    "usage: reboot [-dlNnpqr] [-k kernel]\n");
253163953Srrs	exit(1);
254163953Srrs}
255163953Srrs
256163953Srrsstatic u_int
257170606Srrsget_pageins(void)
258163953Srrs{
259163953Srrs	u_int pageins;
260163953Srrs	size_t len;
261163953Srrs
262170606Srrs	len = sizeof(pageins);
263163953Srrs	if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
264185694Srrs	    != 0) {
265185694Srrs		warnx("v_swappgsin");
266185694Srrs		return (0);
267185694Srrs	}
268185694Srrs	return pageins;
269185694Srrs}
270185694Srrs