GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/reboot/reboot.c Lines: 0 99 0.0 %
Date: 2016-12-06 Branches: 0 75 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: reboot.c,v 1.34 2015/01/16 06:40:00 deraadt Exp $	*/
2
/*	$NetBSD: reboot.c,v 1.8 1995/10/05 05:36:22 mycroft Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1986, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <sys/reboot.h>
35
#include <sys/fcntl.h>
36
#include <sys/sysctl.h>
37
#include <sys/wait.h>
38
#include <machine/cpu.h>
39
#include <signal.h>
40
#include <pwd.h>
41
#include <errno.h>
42
#include <err.h>
43
#include <fcntl.h>
44
#include <termios.h>
45
#include <syslog.h>
46
#include <unistd.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <paths.h>
51
#include <util.h>
52
53
void	usage(void);
54
extern char *__progname;
55
56
int	dohalt;
57
58
#define _PATH_RC	"/etc/rc"
59
60
int
61
main(int argc, char *argv[])
62
{
63
	unsigned int i;
64
	struct passwd *pw;
65
	int ch, howto, lflag, nflag, pflag, qflag;
66
	char *p, *user;
67
	sigset_t mask;
68
69
	p = __progname;
70
71
	/* Nuke login shell */
72
	if (*p == '-')
73
		p++;
74
75
	howto = dohalt = lflag = nflag = pflag = qflag = 0;
76
	if (!strcmp(p, "halt")) {
77
		dohalt = 1;
78
		howto = RB_HALT;
79
	}
80
81
	while ((ch = getopt(argc, argv, "dlnpq")) != -1)
82
		switch (ch) {
83
		case 'd':
84
			howto |= RB_DUMP;
85
			break;
86
		case 'l':	/* Undocumented; used by shutdown. */
87
			lflag = 1;
88
			break;
89
		case 'n':
90
			nflag = 1;
91
			howto |= RB_NOSYNC;
92
			break;
93
		case 'p':
94
			/* Only works if we're called as halt. */
95
			if (dohalt) {
96
				pflag = 1;
97
				howto |= RB_POWERDOWN;
98
			}
99
			break;
100
		case 'q':
101
			qflag = 1;
102
			break;
103
		default:
104
			usage();
105
		}
106
	argc -= optind;
107
	argv += optind;
108
109
	if (argc)
110
		usage();
111
112
	if (geteuid())
113
		errx(1, "%s", strerror(EPERM));
114
115
#ifdef CPU_LIDSUSPEND
116
	if (howto & RB_POWERDOWN) {
117
		/* Disable suspending on laptop lid close */
118
		int mib[2];
119
		int lidsuspend = 0;
120
121
		mib[0] = CTL_MACHDEP;
122
		mib[1] = CPU_LIDSUSPEND;
123
		if (sysctl(mib, 2, NULL, NULL, &lidsuspend,
124
		    sizeof(lidsuspend)) == -1 && errno != EOPNOTSUPP)
125
			warn("sysctl");
126
	}
127
#endif /* CPU_LIDSUSPEND */
128
129
	if (qflag) {
130
		reboot(howto);
131
		err(1, "reboot");
132
	}
133
134
	/* Log the reboot. */
135
	if (!lflag)  {
136
		if ((user = getlogin()) == NULL)
137
			user = (pw = getpwuid(getuid())) ?
138
			    pw->pw_name : "???";
139
		if (dohalt) {
140
			openlog("halt", 0, LOG_AUTH | LOG_CONS);
141
			if (pflag) {
142
				syslog(LOG_CRIT,
143
					"halted (with powerdown) by %s", user);
144
			} else {
145
				syslog(LOG_CRIT, "halted by %s", user);
146
			}
147
		} else {
148
			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
149
			syslog(LOG_CRIT, "rebooted by %s", user);
150
		}
151
	}
152
	logwtmp("~", "shutdown", "");
153
154
	/*
155
	 * Do a sync early on, so disks start transfers while we're off
156
	 * killing processes.  Don't worry about writes done before the
157
	 * processes die, the reboot system call syncs the disks.
158
	 */
159
	if (!nflag)
160
		sync();
161
162
	/* Just stop init -- if we fail, we'll restart it. */
163
	if (kill(1, SIGTSTP) == -1)
164
		err(1, "SIGTSTP init");
165
166
	/* Ignore the SIGHUP we get when our parent shell dies. */
167
	(void)signal(SIGHUP, SIG_IGN);
168
169
	/*
170
	 * If we're running in a pipeline, we don't want to die
171
	 * after killing whatever we're writing to.
172
	 */
173
	(void)signal(SIGPIPE, SIG_IGN);
174
175
	if (access(_PATH_RC, R_OK) != -1) {
176
		pid_t pid;
177
		struct termios t;
178
		int fd, status;
179
180
		switch ((pid = fork())) {
181
		case -1:
182
			break;
183
		case 0:
184
			if (revoke(_PATH_CONSOLE) == -1)
185
				warn("revoke");
186
			if (setsid() == -1)
187
				warn("setsid");
188
			fd = open(_PATH_CONSOLE, O_RDWR);
189
			if (fd == -1)
190
				warn("open");
191
			dup2(fd, 0);
192
			dup2(fd, 1);
193
			dup2(fd, 2);
194
			if (fd > 2)
195
				close(fd);
196
197
			/* At a minimum... */
198
			tcgetattr(0, &t);
199
			t.c_oflag |= (ONLCR | OPOST);
200
			tcsetattr(0, TCSANOW, &t);
201
202
			execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL);
203
			_exit(1);
204
		default:
205
			/* rc exits 2 if powerdown=YES in rc.shutdown */
206
			waitpid(pid, &status, 0);
207
			if (dohalt && WIFEXITED(status) && WEXITSTATUS(status) == 2)
208
				howto |= RB_POWERDOWN;
209
		}
210
	}
211
212
	/*
213
	 * Point of no return, block all signals so we are sure to
214
	 * reach the call to reboot(2) unmolested.
215
	 */
216
	sigfillset(&mask);
217
	sigprocmask(SIG_BLOCK, &mask, NULL);
218
219
	/* Send a SIGTERM first, a chance to save the buffers. */
220
	if (kill(-1, SIGTERM) == -1) {
221
		/*
222
		 * If ESRCH, everything's OK: we're the only non-system
223
		 * process!  That can happen e.g. via 'exec reboot' in
224
		 * single-user mode.
225
		 */
226
		if (errno != ESRCH) {
227
			warn("SIGTERM processes");
228
			goto restart;
229
		}
230
	}
231
232
	/*
233
	 * After the processes receive the signal, start the rest of the
234
	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
235
	 * the SIGKILL to give everybody a chance.
236
	 */
237
	sleep(2);
238
	if (!nflag)
239
		sync();
240
	sleep(3);
241
242
	for (i = 1;; ++i) {
243
		if (kill(-1, SIGKILL) == -1) {
244
			if (errno == ESRCH)
245
				break;
246
			goto restart;
247
		}
248
		if (i > 5) {
249
			warnx("WARNING: some process(es) wouldn't die");
250
			break;
251
		}
252
		(void)sleep(2 * i);
253
	}
254
255
	reboot(howto);
256
	/* FALLTHROUGH */
257
258
restart:
259
	errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : "");
260
	/* NOTREACHED */
261
}
262
263
void
264
usage(void)
265
{
266
	fprintf(stderr, "usage: %s [-dn%sq]\n", __progname,
267
	    dohalt ? "p" : "");
268
	exit(1);
269
}