GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/reboot/reboot.c Lines: 0 102 0.0 %
Date: 2017-11-07 Branches: 0 77 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: reboot.c,v 1.38 2017/08/22 00:30:16 sf 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/sysctl.h>
36
#include <sys/time.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
static void
61
sleep_while_procs(int seconds)
62
{
63
	while (seconds > 0) {
64
		if (kill(-1, 0) == -1 && errno == ESRCH)
65
			return;
66
		sleep(1);
67
		seconds--;
68
	}
69
}
70
71
int
72
main(int argc, char *argv[])
73
{
74
	unsigned int i;
75
	struct passwd *pw;
76
	int ch, howto, lflag, nflag, pflag, qflag;
77
	char *p, *user;
78
	sigset_t mask;
79
80
	p = __progname;
81
82
	/* Nuke login shell */
83
	if (*p == '-')
84
		p++;
85
86
	howto = dohalt = lflag = nflag = pflag = qflag = 0;
87
	if (!strcmp(p, "halt")) {
88
		dohalt = 1;
89
		howto = RB_HALT;
90
	}
91
92
	while ((ch = getopt(argc, argv, "dlnpq")) != -1)
93
		switch (ch) {
94
		case 'd':
95
			howto |= RB_DUMP;
96
			break;
97
		case 'l':	/* Undocumented; used by shutdown. */
98
			lflag = 1;
99
			break;
100
		case 'n':
101
			nflag = 1;
102
			howto |= RB_NOSYNC;
103
			break;
104
		case 'p':
105
			/* Only works if we're called as halt. */
106
			if (dohalt) {
107
				pflag = 1;
108
				howto |= RB_POWERDOWN;
109
			}
110
			break;
111
		case 'q':
112
			qflag = 1;
113
			break;
114
		default:
115
			usage();
116
		}
117
	argc -= optind;
118
	argv += optind;
119
120
	if (argc)
121
		usage();
122
123
	if (geteuid())
124
		errx(1, "%s", strerror(EPERM));
125
126
#ifdef CPU_LIDACTION
127
	if (howto & RB_POWERDOWN) {
128
		/* Disable suspending on laptop lid close */
129
		int mib[] = {CTL_MACHDEP, CPU_LIDACTION};
130
		int lidaction = 0;
131
132
		if (sysctl(mib, 2, NULL, NULL, &lidaction,
133
		    sizeof(lidaction)) == -1 && errno != EOPNOTSUPP)
134
			warn("sysctl");
135
	}
136
#endif /* CPU_LIDACTION */
137
138
	if (qflag) {
139
		reboot(howto);
140
		err(1, "reboot");
141
	}
142
143
	/* Log the reboot. */
144
	if (!lflag)  {
145
		if ((user = getlogin()) == NULL)
146
			user = (pw = getpwuid(getuid())) ?
147
			    pw->pw_name : "???";
148
		if (dohalt) {
149
			openlog("halt", 0, LOG_AUTH | LOG_CONS);
150
			if (pflag) {
151
				syslog(LOG_CRIT,
152
					"halted (with powerdown) by %s", user);
153
			} else {
154
				syslog(LOG_CRIT, "halted by %s", user);
155
			}
156
		} else {
157
			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
158
			syslog(LOG_CRIT, "rebooted by %s", user);
159
		}
160
	}
161
	logwtmp("~", "shutdown", "");
162
163
	/*
164
	 * Do a sync early on, so disks start transfers while we're off
165
	 * killing processes.  Don't worry about writes done before the
166
	 * processes die, the reboot system call syncs the disks.
167
	 */
168
	if (!nflag)
169
		sync();
170
171
	/* Just stop init -- if we fail, we'll restart it. */
172
	if (kill(1, SIGTSTP) == -1)
173
		err(1, "SIGTSTP init");
174
175
	/* Ignore the SIGHUP we get when our parent shell dies. */
176
	(void)signal(SIGHUP, SIG_IGN);
177
178
	/*
179
	 * If we're running in a pipeline, we don't want to die
180
	 * after killing whatever we're writing to.
181
	 */
182
	(void)signal(SIGPIPE, SIG_IGN);
183
184
	if (access(_PATH_RC, R_OK) != -1) {
185
		pid_t pid;
186
		struct termios t;
187
		int fd, status;
188
189
		switch ((pid = fork())) {
190
		case -1:
191
			break;
192
		case 0:
193
			if (revoke(_PATH_CONSOLE) == -1)
194
				warn("revoke");
195
			if (setsid() == -1)
196
				warn("setsid");
197
			fd = open(_PATH_CONSOLE, O_RDWR);
198
			if (fd == -1)
199
				warn("open");
200
			dup2(fd, 0);
201
			dup2(fd, 1);
202
			dup2(fd, 2);
203
			if (fd > 2)
204
				close(fd);
205
206
			/* At a minimum... */
207
			tcgetattr(0, &t);
208
			t.c_oflag |= (ONLCR | OPOST);
209
			tcsetattr(0, TCSANOW, &t);
210
211
			execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL);
212
			_exit(1);
213
		default:
214
			/* rc exits 2 if powerdown=YES in rc.shutdown */
215
			waitpid(pid, &status, 0);
216
			if (dohalt && WIFEXITED(status) && WEXITSTATUS(status) == 2)
217
				howto |= RB_POWERDOWN;
218
		}
219
	}
220
221
	/*
222
	 * Point of no return, block all signals so we are sure to
223
	 * reach the call to reboot(2) unmolested.
224
	 */
225
	sigfillset(&mask);
226
	sigprocmask(SIG_BLOCK, &mask, NULL);
227
228
	/* Send a SIGTERM first, a chance to save the buffers. */
229
	if (kill(-1, SIGTERM) == -1) {
230
		/*
231
		 * If ESRCH, everything's OK: we're the only non-system
232
		 * process!  That can happen e.g. via 'exec reboot' in
233
		 * single-user mode.
234
		 */
235
		if (errno != ESRCH) {
236
			warn("SIGTERM processes");
237
			goto restart;
238
		}
239
	}
240
241
	/*
242
	 * After the processes receive the signal, start the rest of the
243
	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
244
	 * the SIGKILL to give everybody a chance.
245
	 */
246
	sleep_while_procs(2);
247
	if (!nflag)
248
		sync();
249
	sleep_while_procs(3);
250
251
	for (i = 1;; ++i) {
252
		if (kill(-1, SIGKILL) == -1) {
253
			if (errno == ESRCH)
254
				break;
255
			goto restart;
256
		}
257
		if (i > 5) {
258
			warnx("WARNING: some process(es) wouldn't die");
259
			break;
260
		}
261
		sleep_while_procs(2 * i);
262
	}
263
264
	reboot(howto);
265
	/* FALLTHROUGH */
266
267
restart:
268
	errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : "");
269
	/* NOTREACHED */
270
}
271
272
void
273
usage(void)
274
{
275
	fprintf(stderr, "usage: %s [-dn%sq]\n", __progname,
276
	    dohalt ? "p" : "");
277
	exit(1);
278
}