1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1980, 1986, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#if 0
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1980, 1986, 1993\n\
36	The Regents of the University of California.  All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40static char sccsid[] = "@(#)reboot.c	8.1 (Berkeley) 6/5/93";
41#endif /* not lint */
42#endif
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD$");
45
46#include <sys/reboot.h>
47#include <sys/time.h>
48#include <sys/types.h>
49#include <sys/sysctl.h>
50#include <signal.h>
51#include <err.h>
52#include <errno.h>
53#include <fcntl.h>
54#include <pwd.h>
55#include <syslog.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <unistd.h>
60#include <utmpx.h>
61
62static void usage(void);
63static u_int get_pageins(void);
64
65static int dohalt;
66
67int
68main(int argc, char *argv[])
69{
70	struct utmpx utx;
71	const struct passwd *pw;
72	int ch, howto, i, fd, lflag, nflag, qflag, sverrno, Nflag;
73	u_int pageins;
74	const char *user, *kernel = NULL;
75
76	if (strstr(getprogname(), "halt") != NULL) {
77		dohalt = 1;
78		howto = RB_HALT;
79	} else
80		howto = 0;
81	lflag = nflag = qflag = Nflag = 0;
82	while ((ch = getopt(argc, argv, "cdk:lNnpqr")) != -1)
83		switch(ch) {
84		case 'c':
85			howto |= RB_POWERCYCLE;
86			break;
87		case 'd':
88			howto |= RB_DUMP;
89			break;
90		case 'k':
91			kernel = optarg;
92			break;
93		case 'l':
94			lflag = 1;
95			break;
96		case 'n':
97			nflag = 1;
98			howto |= RB_NOSYNC;
99			break;
100		case 'N':
101			nflag = 1;
102			Nflag = 1;
103			break;
104		case 'p':
105			howto |= RB_POWEROFF;
106			break;
107		case 'q':
108			qflag = 1;
109			break;
110		case 'r':
111			howto |= RB_REROOT;
112			break;
113		case '?':
114		default:
115			usage();
116		}
117	argc -= optind;
118	argv += optind;
119	if (argc != 0)
120		usage();
121
122	if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
123		errx(1, "cannot dump (-d) when halting; must reboot instead");
124	if (Nflag && (howto & RB_NOSYNC) != 0)
125		errx(1, "-N cannot be used with -n");
126	if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE))
127		errx(1, "-c and -p cannot be used together");
128	if ((howto & RB_REROOT) != 0 && howto != RB_REROOT)
129		errx(1, "-r cannot be used with -c, -d, -n, or -p");
130	if (geteuid()) {
131		errno = EPERM;
132		err(1, NULL);
133	}
134
135	if (qflag) {
136		reboot(howto);
137		err(1, NULL);
138	}
139
140	if (kernel != NULL) {
141		fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC,
142		    0444);
143		if (fd > -1) {
144			(void)write(fd, "nextboot_enable=\"YES\"\n", 22);
145			(void)write(fd, "kernel=\"", 8L);
146			(void)write(fd, kernel, strlen(kernel));
147			(void)write(fd, "\"\n", 2);
148			close(fd);
149		}
150	}
151
152	/* Log the reboot. */
153	if (!lflag)  {
154		if ((user = getlogin()) == NULL)
155			user = (pw = getpwuid(getuid())) ?
156			    pw->pw_name : "???";
157		if (dohalt) {
158			openlog("halt", 0, LOG_AUTH | LOG_CONS);
159			syslog(LOG_CRIT, "halted by %s", user);
160		} else if (howto & RB_REROOT) {
161			openlog("reroot", 0, LOG_AUTH | LOG_CONS);
162			syslog(LOG_CRIT, "rerooted by %s", user);
163		} else if (howto & RB_POWEROFF) {
164			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
165			syslog(LOG_CRIT, "powered off by %s", user);
166		} else if (howto & RB_POWERCYCLE) {
167			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
168			syslog(LOG_CRIT, "power cycled by %s", user);
169		} else {
170			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
171			syslog(LOG_CRIT, "rebooted by %s", user);
172		}
173	}
174	utx.ut_type = SHUTDOWN_TIME;
175	gettimeofday(&utx.ut_tv, NULL);
176	pututxline(&utx);
177
178	/*
179	 * Do a sync early on, so disks start transfers while we're off
180	 * killing processes.  Don't worry about writes done before the
181	 * processes die, the reboot system call syncs the disks.
182	 */
183	if (!nflag)
184		sync();
185
186	/*
187	 * Ignore signals that we can get as a result of killing
188	 * parents, group leaders, etc.
189	 */
190	(void)signal(SIGHUP,  SIG_IGN);
191	(void)signal(SIGINT,  SIG_IGN);
192	(void)signal(SIGQUIT, SIG_IGN);
193	(void)signal(SIGTERM, SIG_IGN);
194	(void)signal(SIGTSTP, SIG_IGN);
195
196	/*
197	 * If we're running in a pipeline, we don't want to die
198	 * after killing whatever we're writing to.
199	 */
200	(void)signal(SIGPIPE, SIG_IGN);
201
202	/*
203	 * Only init(8) can perform rerooting.
204	 */
205	if (howto & RB_REROOT) {
206		if (kill(1, SIGEMT) == -1)
207			err(1, "SIGEMT init");
208
209		return (0);
210	}
211
212	/* Just stop init -- if we fail, we'll restart it. */
213	if (kill(1, SIGTSTP) == -1)
214		err(1, "SIGTSTP init");
215
216	/* Send a SIGTERM first, a chance to save the buffers. */
217	if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
218		err(1, "SIGTERM processes");
219
220	/*
221	 * After the processes receive the signal, start the rest of the
222	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
223	 * the SIGKILL to give everybody a chance. If there is a lot of
224	 * paging activity then wait longer, up to a maximum of approx
225	 * 60 seconds.
226	 */
227	sleep(2);
228	for (i = 0; i < 20; i++) {
229		pageins = get_pageins();
230		if (!nflag)
231			sync();
232		sleep(3);
233		if (get_pageins() == pageins)
234			break;
235	}
236
237	for (i = 1;; ++i) {
238		if (kill(-1, SIGKILL) == -1) {
239			if (errno == ESRCH)
240				break;
241			goto restart;
242		}
243		if (i > 5) {
244			(void)fprintf(stderr,
245			    "WARNING: some process(es) wouldn't die\n");
246			break;
247		}
248		(void)sleep(2 * i);
249	}
250
251	reboot(howto);
252	/* FALLTHROUGH */
253
254restart:
255	sverrno = errno;
256	errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
257	    strerror(sverrno));
258	/* NOTREACHED */
259}
260
261static void
262usage(void)
263{
264
265	(void)fprintf(stderr, dohalt ?
266	    "usage: halt [-clNnpq] [-k kernel]\n" :
267	    "usage: reboot [-cdlNnpqr] [-k kernel]\n");
268	exit(1);
269}
270
271static u_int
272get_pageins(void)
273{
274	u_int pageins;
275	size_t len;
276
277	len = sizeof(pageins);
278	if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
279	    != 0) {
280		warnx("v_swappgsin");
281		return (0);
282	}
283	return pageins;
284}
285