xref: /openbsd/sbin/reboot/reboot.c (revision 9179587a)
1*9179587aStedu /*	$OpenBSD: reboot.c,v 1.29 2007/05/11 01:53:07 tedu Exp $	*/
2df930be7Sderaadt /*	$NetBSD: reboot.c,v 1.8 1995/10/05 05:36:22 mycroft Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1980, 1986, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
161ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33df930be7Sderaadt #ifndef lint
34df930be7Sderaadt static char copyright[] =
35df930be7Sderaadt "@(#) Copyright (c) 1980, 1986, 1993\n\
36df930be7Sderaadt 	The Regents of the University of California.  All rights reserved.\n";
37df930be7Sderaadt #endif /* not lint */
38df930be7Sderaadt 
39df930be7Sderaadt #ifndef lint
40df930be7Sderaadt #if 0
41df930be7Sderaadt static char sccsid[] = "@(#)reboot.c	8.1 (Berkeley) 6/5/93";
42df930be7Sderaadt #else
43*9179587aStedu static char rcsid[] = "$OpenBSD: reboot.c,v 1.29 2007/05/11 01:53:07 tedu Exp $";
44df930be7Sderaadt #endif
45df930be7Sderaadt #endif /* not lint */
46df930be7Sderaadt 
4701de6d07Smickey #include <sys/types.h>
48df930be7Sderaadt #include <sys/reboot.h>
49c4849fe1Sderaadt #include <sys/fcntl.h>
503729fd61Sart #include <sys/wait.h>
51df930be7Sderaadt #include <signal.h>
52df930be7Sderaadt #include <pwd.h>
53df930be7Sderaadt #include <errno.h>
5401de6d07Smickey #include <err.h>
55a1521482Smillert #include <fcntl.h>
56ff86fde3Smillert #include <termios.h>
57df930be7Sderaadt #include <syslog.h>
58df930be7Sderaadt #include <unistd.h>
59df930be7Sderaadt #include <stdio.h>
60df930be7Sderaadt #include <stdlib.h>
61df930be7Sderaadt #include <string.h>
62833e69e8Sderaadt #include <paths.h>
6301de6d07Smickey #include <util.h>
64df930be7Sderaadt 
65c72b5b24Smillert void	usage(void);
6601de6d07Smickey extern char *__progname;
67df930be7Sderaadt 
6871025d0dSderaadt int	dohalt;
6971025d0dSderaadt 
7075a54d2eSderaadt #define _PATH_RC	"/etc/rc"
71833e69e8Sderaadt 
72df930be7Sderaadt int
73bc52e260Sderaadt main(int argc, char *argv[])
74df930be7Sderaadt {
750fd6fe2bSdhill 	unsigned int i;
76df930be7Sderaadt 	struct passwd *pw;
7771025d0dSderaadt 	int ch, howto, lflag, nflag, pflag, qflag;
78df930be7Sderaadt 	char *p, *user;
79df930be7Sderaadt 
8001de6d07Smickey 	p = __progname;
81ddf9f12cSweingart 
82ddf9f12cSweingart 	/* Nuke login shell */
8371025d0dSderaadt 	if (*p == '-')
8471025d0dSderaadt 		p++;
85ddf9f12cSweingart 
8601de6d07Smickey 	howto = dohalt = lflag = nflag = pflag = qflag = 0;
87ddf9f12cSweingart 	if (!strcmp(p, "halt")) {
88df930be7Sderaadt 		dohalt = 1;
89df930be7Sderaadt 		howto = RB_HALT;
9001de6d07Smickey 	}
9101de6d07Smickey 
92f403a9a2Sdownsj 	while ((ch = getopt(argc, argv, "dlnpq")) != -1)
93df930be7Sderaadt 		switch (ch) {
94f403a9a2Sdownsj 		case 'd':
95f403a9a2Sdownsj 			howto |= RB_DUMP;
96f403a9a2Sdownsj 			break;
97df930be7Sderaadt 		case 'l':	/* Undocumented; used by shutdown. */
98df930be7Sderaadt 			lflag = 1;
99df930be7Sderaadt 			break;
100df930be7Sderaadt 		case 'n':
101df930be7Sderaadt 			nflag = 1;
102df930be7Sderaadt 			howto |= RB_NOSYNC;
103df930be7Sderaadt 			break;
104f403a9a2Sdownsj 		case 'p':
105f403a9a2Sdownsj 			/* Only works if we're called as halt. */
106f403a9a2Sdownsj 			if (dohalt) {
107f403a9a2Sdownsj 				pflag = 1;
108f403a9a2Sdownsj 				howto |= RB_POWERDOWN;
109f403a9a2Sdownsj 			}
110f403a9a2Sdownsj 			break;
111df930be7Sderaadt 		case 'q':
112df930be7Sderaadt 			qflag = 1;
113df930be7Sderaadt 			break;
114df930be7Sderaadt 		default:
115df930be7Sderaadt 			usage();
116df930be7Sderaadt 		}
117df930be7Sderaadt 	argc -= optind;
118df930be7Sderaadt 	argv += optind;
119df930be7Sderaadt 
12071025d0dSderaadt 	if (argc)
12171025d0dSderaadt 		usage();
12271025d0dSderaadt 
123df930be7Sderaadt 	if (geteuid())
12401de6d07Smickey 		errx(1, "%s", strerror(EPERM));
125df930be7Sderaadt 
126df930be7Sderaadt 	if (qflag) {
127df930be7Sderaadt 		reboot(howto);
12801de6d07Smickey 		err(1, "reboot");
129df930be7Sderaadt 	}
130df930be7Sderaadt 
131df930be7Sderaadt 	/* Log the reboot. */
132df930be7Sderaadt 	if (!lflag)  {
133df930be7Sderaadt 		if ((user = getlogin()) == NULL)
134df930be7Sderaadt 			user = (pw = getpwuid(getuid())) ?
135df930be7Sderaadt 			    pw->pw_name : "???";
136df930be7Sderaadt 		if (dohalt) {
137df930be7Sderaadt 			openlog("halt", 0, LOG_AUTH | LOG_CONS);
138f403a9a2Sdownsj 			if (pflag) {
139f403a9a2Sdownsj 				syslog(LOG_CRIT,
140f403a9a2Sdownsj 					"halted (with powerdown) by %s", user);
141f403a9a2Sdownsj 			} else {
142df930be7Sderaadt 				syslog(LOG_CRIT, "halted by %s", user);
143f403a9a2Sdownsj 			}
144df930be7Sderaadt 		} else {
145df930be7Sderaadt 			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
146df930be7Sderaadt 			syslog(LOG_CRIT, "rebooted by %s", user);
147df930be7Sderaadt 		}
148df930be7Sderaadt 	}
149df930be7Sderaadt 	logwtmp("~", "shutdown", "");
150df930be7Sderaadt 
151df930be7Sderaadt 	/*
152df930be7Sderaadt 	 * Do a sync early on, so disks start transfers while we're off
153df930be7Sderaadt 	 * killing processes.  Don't worry about writes done before the
154df930be7Sderaadt 	 * processes die, the reboot system call syncs the disks.
155df930be7Sderaadt 	 */
156df930be7Sderaadt 	if (!nflag)
157df930be7Sderaadt 		sync();
158df930be7Sderaadt 
159df930be7Sderaadt 	/* Just stop init -- if we fail, we'll restart it. */
160df930be7Sderaadt 	if (kill(1, SIGTSTP) == -1)
16101de6d07Smickey 		err(1, "SIGTSTP init");
162df930be7Sderaadt 
163df930be7Sderaadt 	/* Ignore the SIGHUP we get when our parent shell dies. */
164df930be7Sderaadt 	(void)signal(SIGHUP, SIG_IGN);
165df930be7Sderaadt 
16639c69f54Sderaadt 	/*
16739c69f54Sderaadt 	 * If we're running in a pipeline, we don't want to die
16839c69f54Sderaadt 	 * after killing whatever we're writing to.
16939c69f54Sderaadt 	 */
17039c69f54Sderaadt 	(void)signal(SIGPIPE, SIG_IGN);
17139c69f54Sderaadt 
17275a54d2eSderaadt 	if (access(_PATH_RC, R_OK) != -1) {
173833e69e8Sderaadt 		pid_t pid;
174c4849fe1Sderaadt 		struct termios t;
175433c54bfShenning 		int fd, status;
176833e69e8Sderaadt 
177833e69e8Sderaadt 		switch ((pid = fork())) {
178833e69e8Sderaadt 		case -1:
179833e69e8Sderaadt 			break;
180833e69e8Sderaadt 		case 0:
181c4849fe1Sderaadt 			if (revoke(_PATH_CONSOLE) == -1)
18266420897Smickey 				warn("revoke");
183c4849fe1Sderaadt 			if (setsid() == -1)
18466420897Smickey 				warn("setsid");
185c4849fe1Sderaadt 			fd = open(_PATH_CONSOLE, O_RDWR);
186c4849fe1Sderaadt 			if (fd == -1)
18766420897Smickey 				warn("open");
188c4849fe1Sderaadt 			dup2(fd, 0);
189c4849fe1Sderaadt 			dup2(fd, 1);
190c4849fe1Sderaadt 			dup2(fd, 2);
191c4849fe1Sderaadt 			if (fd > 2)
192c4849fe1Sderaadt 				close(fd);
193c4849fe1Sderaadt 
194c4849fe1Sderaadt 			/* At a minimum... */
195c4849fe1Sderaadt 			tcgetattr(0, &t);
196c4849fe1Sderaadt 			t.c_oflag |= (ONLCR | OPOST);
197c4849fe1Sderaadt 			tcsetattr(0, TCSANOW, &t);
198c4849fe1Sderaadt 
199c96f6a27Sderaadt 			execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL);
200c4849fe1Sderaadt 			_exit(1);
201833e69e8Sderaadt 		default:
202433c54bfShenning 			/* rc exits 2 if powerdown=YES in rc.shutdown */
203433c54bfShenning 			waitpid(pid, &status, 0);
204*9179587aStedu 			if (dohalt && WIFEXITED(status) && WEXITSTATUS(status) == 2)
205433c54bfShenning 				howto |= RB_POWERDOWN;
206833e69e8Sderaadt 		}
207833e69e8Sderaadt 	}
208833e69e8Sderaadt 
209df930be7Sderaadt 	/* Send a SIGTERM first, a chance to save the buffers. */
21013422552Sderaadt 	if (kill(-1, SIGTERM) == -1) {
21113422552Sderaadt 		/*
21213422552Sderaadt 		 * If ESRCH, everything's OK: we're the only non-system
21313422552Sderaadt 		 * process!  That can happen e.g. via 'exec reboot' in
21413422552Sderaadt 		 * single-user mode.
21513422552Sderaadt 		 */
21613422552Sderaadt 		if (errno != ESRCH) {
21701de6d07Smickey 			warn("SIGTERM processes");
21813422552Sderaadt 			goto restart;
21913422552Sderaadt 		}
22013422552Sderaadt 	}
221df930be7Sderaadt 
222df930be7Sderaadt 	/*
223df930be7Sderaadt 	 * After the processes receive the signal, start the rest of the
224f3e19106Sderaadt 	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
225f3e19106Sderaadt 	 * the SIGKILL to give everybody a chance.
226df930be7Sderaadt 	 */
227df930be7Sderaadt 	sleep(2);
228df930be7Sderaadt 	if (!nflag)
229df930be7Sderaadt 		sync();
230f3e19106Sderaadt 	sleep(3);
231df930be7Sderaadt 
232df930be7Sderaadt 	for (i = 1;; ++i) {
233df930be7Sderaadt 		if (kill(-1, SIGKILL) == -1) {
234df930be7Sderaadt 			if (errno == ESRCH)
235df930be7Sderaadt 				break;
236df930be7Sderaadt 			goto restart;
237df930be7Sderaadt 		}
238df930be7Sderaadt 		if (i > 5) {
23901de6d07Smickey 			warnx("WARNING: some process(es) wouldn't die");
240df930be7Sderaadt 			break;
241df930be7Sderaadt 		}
242df930be7Sderaadt 		(void)sleep(2 * i);
243df930be7Sderaadt 	}
244df930be7Sderaadt 
245df930be7Sderaadt 	reboot(howto);
246df930be7Sderaadt 	/* FALLTHROUGH */
247df930be7Sderaadt 
248df930be7Sderaadt restart:
24901de6d07Smickey 	errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : "");
250df930be7Sderaadt 	/* NOTREACHED */
251df930be7Sderaadt }
252df930be7Sderaadt 
253df930be7Sderaadt void
254bc52e260Sderaadt usage(void)
255df930be7Sderaadt {
25671025d0dSderaadt 	fprintf(stderr, "usage: %s [-dn%sq]\n", __progname,
25771025d0dSderaadt 	    dohalt ? "p" : "");
258df930be7Sderaadt 	exit(1);
259df930be7Sderaadt }
260