xref: /minix3/sbin/reboot/reboot.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: reboot.c,v 1.40 2012/11/04 22:28:16 christos Exp $	*/
2a06e2ab3SBen Gras 
3a06e2ab3SBen Gras /*
4a06e2ab3SBen Gras  * Copyright (c) 1980, 1986, 1993
5a06e2ab3SBen Gras  *	The Regents of the University of California.  All rights reserved.
6a06e2ab3SBen Gras  *
7a06e2ab3SBen Gras  * Redistribution and use in source and binary forms, with or without
8a06e2ab3SBen Gras  * modification, are permitted provided that the following conditions
9a06e2ab3SBen Gras  * are met:
10a06e2ab3SBen Gras  * 1. Redistributions of source code must retain the above copyright
11a06e2ab3SBen Gras  *    notice, this list of conditions and the following disclaimer.
12a06e2ab3SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
13a06e2ab3SBen Gras  *    notice, this list of conditions and the following disclaimer in the
14a06e2ab3SBen Gras  *    documentation and/or other materials provided with the distribution.
15a06e2ab3SBen Gras  * 3. Neither the name of the University nor the names of its contributors
16a06e2ab3SBen Gras  *    may be used to endorse or promote products derived from this software
17a06e2ab3SBen Gras  *    without specific prior written permission.
18a06e2ab3SBen Gras  *
19a06e2ab3SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20a06e2ab3SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21a06e2ab3SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22a06e2ab3SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23a06e2ab3SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24a06e2ab3SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25a06e2ab3SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26a06e2ab3SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27a06e2ab3SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28a06e2ab3SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29a06e2ab3SBen Gras  * SUCH DAMAGE.
30a06e2ab3SBen Gras  */
31a06e2ab3SBen Gras 
32a06e2ab3SBen Gras #include <sys/cdefs.h>
33a06e2ab3SBen Gras 
34a06e2ab3SBen Gras #ifndef lint
35a06e2ab3SBen Gras __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1993\
36a06e2ab3SBen Gras  The Regents of the University of California.  All rights reserved.");
37a06e2ab3SBen Gras #endif /* not lint */
38a06e2ab3SBen Gras 
39a06e2ab3SBen Gras #ifndef lint
40a06e2ab3SBen Gras #if 0
41a06e2ab3SBen Gras static char sccsid[] = "@(#)reboot.c	8.1 (Berkeley) 6/5/93";
42a06e2ab3SBen Gras #else
43*84d9c625SLionel Sambuc __RCSID("$NetBSD: reboot.c,v 1.40 2012/11/04 22:28:16 christos Exp $");
44a06e2ab3SBen Gras #endif
45a06e2ab3SBen Gras #endif /* not lint */
46a06e2ab3SBen Gras 
47a06e2ab3SBen Gras #include <sys/reboot.h>
48a06e2ab3SBen Gras 
49a06e2ab3SBen Gras #include <err.h>
50a06e2ab3SBen Gras #include <errno.h>
51a06e2ab3SBen Gras #include <pwd.h>
52a06e2ab3SBen Gras #include <signal.h>
53a06e2ab3SBen Gras #include <stdio.h>
54a06e2ab3SBen Gras #include <stdlib.h>
55a06e2ab3SBen Gras #include <string.h>
56a06e2ab3SBen Gras #include <syslog.h>
57a06e2ab3SBen Gras #include <unistd.h>
58a06e2ab3SBen Gras #include <util.h>
59*84d9c625SLionel Sambuc #ifdef SUPPORT_UTMPX
60*84d9c625SLionel Sambuc #include <utmpx.h>
61*84d9c625SLionel Sambuc #endif
62a06e2ab3SBen Gras 
63a06e2ab3SBen Gras __dead static void usage(void);
64a06e2ab3SBen Gras 
65a06e2ab3SBen Gras static int dohalt;
66a06e2ab3SBen Gras static int dopoweroff;
67a06e2ab3SBen Gras 
68a06e2ab3SBen Gras int
main(int argc,char * argv[])69a06e2ab3SBen Gras main(int argc, char *argv[])
70a06e2ab3SBen Gras {
71a06e2ab3SBen Gras 	const char *progname;
72*84d9c625SLionel Sambuc #if !defined(__minix)
73*84d9c625SLionel Sambuc 	int i;
74*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
75a06e2ab3SBen Gras 	struct passwd *pw;
76a06e2ab3SBen Gras 	int ch, howto, lflag, nflag, qflag, sverrno, len;
77a06e2ab3SBen Gras 	const char *user;
78a06e2ab3SBen Gras 	char *bootstr, **av;
79a06e2ab3SBen Gras 
80a06e2ab3SBen Gras 	progname = getprogname();
81a06e2ab3SBen Gras 	if (progname[0] == '-')
82a06e2ab3SBen Gras 		progname++;
83a06e2ab3SBen Gras 	if (strcmp(progname, "halt") == 0) {
84a06e2ab3SBen Gras 		dohalt = 1;
85a06e2ab3SBen Gras 		howto = RB_HALT;
86a06e2ab3SBen Gras 	} else if (strcmp(progname, "poweroff") == 0) {
87a06e2ab3SBen Gras 		dopoweroff = 1;
88a06e2ab3SBen Gras 		howto = RB_HALT | RB_POWERDOWN;
89a06e2ab3SBen Gras 	} else
90a06e2ab3SBen Gras 		howto = 0;
91a06e2ab3SBen Gras 	lflag = nflag = qflag = 0;
92a06e2ab3SBen Gras 	while ((ch = getopt(argc, argv, "dlnpqvxz")) != -1)
93a06e2ab3SBen Gras 		switch(ch) {
94a06e2ab3SBen Gras 		case 'd':
95a06e2ab3SBen Gras 			howto |= RB_DUMP;
96a06e2ab3SBen Gras 			break;
97a06e2ab3SBen Gras 		case 'l':
98a06e2ab3SBen Gras 			lflag = 1;
99a06e2ab3SBen Gras 			break;
100a06e2ab3SBen Gras 		case 'n':
101a06e2ab3SBen Gras 			nflag = 1;
102a06e2ab3SBen Gras 			howto |= RB_NOSYNC;
103a06e2ab3SBen Gras 			break;
104a06e2ab3SBen Gras 		case 'p':
105a06e2ab3SBen Gras 			if (dohalt == 0)
106a06e2ab3SBen Gras 				usage();
107a06e2ab3SBen Gras 			howto |= RB_POWERDOWN;
108a06e2ab3SBen Gras 			break;
109a06e2ab3SBen Gras 		case 'q':
110a06e2ab3SBen Gras 			qflag = 1;
111a06e2ab3SBen Gras 			break;
112a06e2ab3SBen Gras 		case 'v':
113a06e2ab3SBen Gras 			howto |= AB_VERBOSE;
114a06e2ab3SBen Gras 			break;
115a06e2ab3SBen Gras 		case 'x':
116a06e2ab3SBen Gras 			howto |= AB_DEBUG;
117a06e2ab3SBen Gras 			break;
118a06e2ab3SBen Gras 		case 'z':
119a06e2ab3SBen Gras 			howto |= AB_SILENT;
120a06e2ab3SBen Gras 			break;
121a06e2ab3SBen Gras 		case '?':
122a06e2ab3SBen Gras 		default:
123a06e2ab3SBen Gras 			usage();
124a06e2ab3SBen Gras 		}
125a06e2ab3SBen Gras 	argc -= optind;
126a06e2ab3SBen Gras 	argv += optind;
127a06e2ab3SBen Gras 
128a06e2ab3SBen Gras 	if (argc) {
129a06e2ab3SBen Gras 		for (av = argv, len = 0; *av; av++)
130a06e2ab3SBen Gras 			len += strlen(*av) + 1;
131a06e2ab3SBen Gras 		bootstr = malloc(len + 1);
132a06e2ab3SBen Gras 		*bootstr = '\0';		/* for first strcat */
133a06e2ab3SBen Gras 		for (av = argv; *av; av++) {
134a06e2ab3SBen Gras 			strcat(bootstr, *av);
135a06e2ab3SBen Gras 			strcat(bootstr, " ");
136a06e2ab3SBen Gras 		}
137a06e2ab3SBen Gras 		bootstr[len - 1] = '\0';	/* to kill last space */
138a06e2ab3SBen Gras 		howto |= RB_STRING;
139a06e2ab3SBen Gras 	} else
140a06e2ab3SBen Gras 		bootstr = NULL;
141a06e2ab3SBen Gras 
142a06e2ab3SBen Gras 	if (geteuid())
143a06e2ab3SBen Gras 		errx(1, "%s", strerror(EPERM));
144a06e2ab3SBen Gras 
145a06e2ab3SBen Gras 	if (qflag) {
146a06e2ab3SBen Gras 		reboot(howto, bootstr);
147a06e2ab3SBen Gras 		err(1, "reboot");
148a06e2ab3SBen Gras 	}
149a06e2ab3SBen Gras 
150a06e2ab3SBen Gras 	/* Log the reboot. */
151a06e2ab3SBen Gras 	if (!lflag)  {
152a06e2ab3SBen Gras 		if ((user = getlogin()) == NULL)
153a06e2ab3SBen Gras 			user = (pw = getpwuid(getuid())) ?
154a06e2ab3SBen Gras 			    pw->pw_name : "???";
155a06e2ab3SBen Gras 		if (dohalt) {
156a06e2ab3SBen Gras 			openlog("halt", LOG_CONS, LOG_AUTH);
157a06e2ab3SBen Gras 			syslog(LOG_CRIT, "halted by %s", user);
158a06e2ab3SBen Gras 		} else if (dopoweroff) {
159a06e2ab3SBen Gras 			openlog("poweroff", LOG_CONS, LOG_AUTH);
160a06e2ab3SBen Gras 			syslog(LOG_CRIT, "powered off by %s", user);
161a06e2ab3SBen Gras 		} else {
162a06e2ab3SBen Gras 			openlog("reboot", LOG_CONS, LOG_AUTH);
163a06e2ab3SBen Gras 			if (bootstr)
164a06e2ab3SBen Gras 				syslog(LOG_CRIT, "rebooted by %s: %s", user,
165a06e2ab3SBen Gras 				    bootstr);
166a06e2ab3SBen Gras 			else
167a06e2ab3SBen Gras 				syslog(LOG_CRIT, "rebooted by %s", user);
168a06e2ab3SBen Gras 		}
169a06e2ab3SBen Gras 	}
170a06e2ab3SBen Gras #ifdef SUPPORT_UTMP
171a06e2ab3SBen Gras 	logwtmp("~", "shutdown", "");
172a06e2ab3SBen Gras #endif
173a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
174a06e2ab3SBen Gras 	logwtmpx("~", "shutdown", "", INIT_PROCESS, 0);
175a06e2ab3SBen Gras #endif
176a06e2ab3SBen Gras 
177a06e2ab3SBen Gras 	/*
178a06e2ab3SBen Gras 	 * Do a sync early on, so disks start transfers while we're off
179a06e2ab3SBen Gras 	 * killing processes.  Don't worry about writes done before the
180a06e2ab3SBen Gras 	 * processes die, the reboot system call syncs the disks.
181a06e2ab3SBen Gras 	 */
182a06e2ab3SBen Gras 	if (!nflag)
183a06e2ab3SBen Gras 		sync();
184a06e2ab3SBen Gras 
185a06e2ab3SBen Gras 	/*
186a06e2ab3SBen Gras 	 * Ignore signals that we can get as a result of killing
187a06e2ab3SBen Gras 	 * parents, group leaders, etc.
188a06e2ab3SBen Gras 	 */
189a06e2ab3SBen Gras 	(void)signal(SIGHUP,  SIG_IGN);
190a06e2ab3SBen Gras 	(void)signal(SIGINT,  SIG_IGN);
191a06e2ab3SBen Gras 	(void)signal(SIGQUIT, SIG_IGN);
192a06e2ab3SBen Gras 	(void)signal(SIGTERM, SIG_IGN);
193a06e2ab3SBen Gras 	(void)signal(SIGTSTP, SIG_IGN);
194a06e2ab3SBen Gras 
195a06e2ab3SBen Gras 	/*
196a06e2ab3SBen Gras 	 * If we're running in a pipeline, we don't want to die
197a06e2ab3SBen Gras 	 * after killing whatever we're writing to.
198a06e2ab3SBen Gras 	 */
199a06e2ab3SBen Gras 	(void)signal(SIGPIPE, SIG_IGN);
200a06e2ab3SBen Gras 
201a06e2ab3SBen Gras 	/* Just stop init -- if we fail, we'll restart it. */
202a06e2ab3SBen Gras 	if (kill(1, SIGTSTP) == -1)
203a06e2ab3SBen Gras 		err(1, "SIGTSTP init");
204a06e2ab3SBen Gras 
205a06e2ab3SBen Gras 	/* Send a SIGTERM first, a chance to save the buffers. */
206a06e2ab3SBen Gras 	if (kill(-1, SIGTERM) == -1) {
207a06e2ab3SBen Gras 		/*
208a06e2ab3SBen Gras 		 * If ESRCH, everything's OK: we're the only non-system
209a06e2ab3SBen Gras 		 * process!  That can happen e.g. via 'exec reboot' in
210a06e2ab3SBen Gras 		 * single-user mode.
211a06e2ab3SBen Gras 		 */
212a06e2ab3SBen Gras 		if (errno != ESRCH) {
213a06e2ab3SBen Gras 			warn("SIGTERM all processes");
214a06e2ab3SBen Gras 			goto restart;
215a06e2ab3SBen Gras 		}
216a06e2ab3SBen Gras 	}
217a06e2ab3SBen Gras 
218a06e2ab3SBen Gras 	/*
219a06e2ab3SBen Gras 	 * After the processes receive the signal, start the rest of the
220a06e2ab3SBen Gras 	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
221a06e2ab3SBen Gras 	 * the SIGKILL to pretend to give everybody a chance.
222a06e2ab3SBen Gras 	 */
223a06e2ab3SBen Gras 	sleep(2);
224a06e2ab3SBen Gras 	if (!nflag)
225a06e2ab3SBen Gras 		sync();
226a06e2ab3SBen Gras 	sleep(3);
227a06e2ab3SBen Gras 
228*84d9c625SLionel Sambuc #if !defined(__minix)
229a06e2ab3SBen Gras 	for (i = 1;; ++i) {
230a06e2ab3SBen Gras 		if (kill(-1, SIGKILL) == -1) {
231a06e2ab3SBen Gras 			if (errno == ESRCH)
232a06e2ab3SBen Gras 				break;
233a06e2ab3SBen Gras 			warn("SIGKILL all processes");
234a06e2ab3SBen Gras 			goto restart;
235a06e2ab3SBen Gras 		}
236a06e2ab3SBen Gras 		if (i > 5) {
237a06e2ab3SBen Gras 			warnx("WARNING: some process(es) wouldn't die");
238a06e2ab3SBen Gras 			break;
239a06e2ab3SBen Gras 		}
240a06e2ab3SBen Gras 		(void)sleep(2 * i);
241a06e2ab3SBen Gras 	}
242*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
243a06e2ab3SBen Gras 
244a06e2ab3SBen Gras 	reboot(howto, bootstr);
245a06e2ab3SBen Gras 	warn("reboot()");
246a06e2ab3SBen Gras 	/* FALLTHROUGH */
247a06e2ab3SBen Gras 
248a06e2ab3SBen Gras restart:
249a06e2ab3SBen Gras 	sverrno = errno;
250a06e2ab3SBen Gras 	errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
251a06e2ab3SBen Gras 	    strerror(sverrno));
252a06e2ab3SBen Gras 	/* NOTREACHED */
253a06e2ab3SBen Gras }
254a06e2ab3SBen Gras 
255a06e2ab3SBen Gras static void
usage(void)256a06e2ab3SBen Gras usage(void)
257a06e2ab3SBen Gras {
258a06e2ab3SBen Gras 	const char *pflag = dohalt ? "p" : "";
259a06e2ab3SBen Gras 
260a06e2ab3SBen Gras 	(void)fprintf(stderr, "usage: %s [-dln%sqvxz] [-- <boot string>]\n",
261a06e2ab3SBen Gras 	    getprogname(), pflag);
262a06e2ab3SBen Gras 	exit(1);
263a06e2ab3SBen Gras }
264