1*3dbceb11Ssf /* $OpenBSD: reboot.c,v 1.38 2017/08/22 00:30:16 sf 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
3301de6d07Smickey #include <sys/types.h>
34df930be7Sderaadt #include <sys/reboot.h>
3538bb3b35Shalex #include <sys/sysctl.h>
369efb13d0Sguenther #include <sys/time.h>
373729fd61Sart #include <sys/wait.h>
3838bb3b35Shalex #include <machine/cpu.h>
39df930be7Sderaadt #include <signal.h>
40df930be7Sderaadt #include <pwd.h>
41df930be7Sderaadt #include <errno.h>
4201de6d07Smickey #include <err.h>
43a1521482Smillert #include <fcntl.h>
44ff86fde3Smillert #include <termios.h>
45df930be7Sderaadt #include <syslog.h>
46df930be7Sderaadt #include <unistd.h>
47df930be7Sderaadt #include <stdio.h>
48df930be7Sderaadt #include <stdlib.h>
49df930be7Sderaadt #include <string.h>
50833e69e8Sderaadt #include <paths.h>
5101de6d07Smickey #include <util.h>
52df930be7Sderaadt
53c72b5b24Smillert void usage(void);
5401de6d07Smickey extern char *__progname;
55df930be7Sderaadt
5671025d0dSderaadt int dohalt;
5771025d0dSderaadt
5875a54d2eSderaadt #define _PATH_RC "/etc/rc"
59833e69e8Sderaadt
60*3dbceb11Ssf static void
sleep_while_procs(int seconds)61*3dbceb11Ssf sleep_while_procs(int seconds)
62*3dbceb11Ssf {
63*3dbceb11Ssf while (seconds > 0) {
64*3dbceb11Ssf if (kill(-1, 0) == -1 && errno == ESRCH)
65*3dbceb11Ssf return;
66*3dbceb11Ssf sleep(1);
67*3dbceb11Ssf seconds--;
68*3dbceb11Ssf }
69*3dbceb11Ssf }
70*3dbceb11Ssf
71df930be7Sderaadt int
main(int argc,char * argv[])72bc52e260Sderaadt main(int argc, char *argv[])
73df930be7Sderaadt {
740fd6fe2bSdhill unsigned int i;
75df930be7Sderaadt struct passwd *pw;
7671025d0dSderaadt int ch, howto, lflag, nflag, pflag, qflag;
77df930be7Sderaadt char *p, *user;
785b0d3c01Smillert sigset_t mask;
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
12602638669Snatano #ifdef CPU_LIDACTION
12738bb3b35Shalex if (howto & RB_POWERDOWN) {
12838bb3b35Shalex /* Disable suspending on laptop lid close */
1292d357aedSnatano int mib[] = {CTL_MACHDEP, CPU_LIDACTION};
1302d357aedSnatano int lidaction = 0;
13138bb3b35Shalex
1322d357aedSnatano if (sysctl(mib, 2, NULL, NULL, &lidaction,
1332d357aedSnatano sizeof(lidaction)) == -1 && errno != EOPNOTSUPP)
13438bb3b35Shalex warn("sysctl");
13538bb3b35Shalex }
13602638669Snatano #endif /* CPU_LIDACTION */
13738bb3b35Shalex
138df930be7Sderaadt if (qflag) {
139df930be7Sderaadt reboot(howto);
14001de6d07Smickey err(1, "reboot");
141df930be7Sderaadt }
142df930be7Sderaadt
143df930be7Sderaadt /* Log the reboot. */
144df930be7Sderaadt if (!lflag) {
145df930be7Sderaadt if ((user = getlogin()) == NULL)
146df930be7Sderaadt user = (pw = getpwuid(getuid())) ?
147df930be7Sderaadt pw->pw_name : "???";
148df930be7Sderaadt if (dohalt) {
149df930be7Sderaadt openlog("halt", 0, LOG_AUTH | LOG_CONS);
150f403a9a2Sdownsj if (pflag) {
151f403a9a2Sdownsj syslog(LOG_CRIT,
152f403a9a2Sdownsj "halted (with powerdown) by %s", user);
153f403a9a2Sdownsj } else {
154df930be7Sderaadt syslog(LOG_CRIT, "halted by %s", user);
155f403a9a2Sdownsj }
156df930be7Sderaadt } else {
157df930be7Sderaadt openlog("reboot", 0, LOG_AUTH | LOG_CONS);
158df930be7Sderaadt syslog(LOG_CRIT, "rebooted by %s", user);
159df930be7Sderaadt }
160df930be7Sderaadt }
161df930be7Sderaadt logwtmp("~", "shutdown", "");
162df930be7Sderaadt
163df930be7Sderaadt /*
164df930be7Sderaadt * Do a sync early on, so disks start transfers while we're off
165df930be7Sderaadt * killing processes. Don't worry about writes done before the
166df930be7Sderaadt * processes die, the reboot system call syncs the disks.
167df930be7Sderaadt */
168df930be7Sderaadt if (!nflag)
169df930be7Sderaadt sync();
170df930be7Sderaadt
171df930be7Sderaadt /* Just stop init -- if we fail, we'll restart it. */
172df930be7Sderaadt if (kill(1, SIGTSTP) == -1)
17301de6d07Smickey err(1, "SIGTSTP init");
174df930be7Sderaadt
175df930be7Sderaadt /* Ignore the SIGHUP we get when our parent shell dies. */
176df930be7Sderaadt (void)signal(SIGHUP, SIG_IGN);
177df930be7Sderaadt
17839c69f54Sderaadt /*
17939c69f54Sderaadt * If we're running in a pipeline, we don't want to die
18039c69f54Sderaadt * after killing whatever we're writing to.
18139c69f54Sderaadt */
18239c69f54Sderaadt (void)signal(SIGPIPE, SIG_IGN);
18339c69f54Sderaadt
18475a54d2eSderaadt if (access(_PATH_RC, R_OK) != -1) {
185833e69e8Sderaadt pid_t pid;
186c4849fe1Sderaadt struct termios t;
187433c54bfShenning int fd, status;
188833e69e8Sderaadt
189833e69e8Sderaadt switch ((pid = fork())) {
190833e69e8Sderaadt case -1:
191833e69e8Sderaadt break;
192833e69e8Sderaadt case 0:
193c4849fe1Sderaadt if (revoke(_PATH_CONSOLE) == -1)
19466420897Smickey warn("revoke");
195c4849fe1Sderaadt if (setsid() == -1)
19666420897Smickey warn("setsid");
197c4849fe1Sderaadt fd = open(_PATH_CONSOLE, O_RDWR);
198c4849fe1Sderaadt if (fd == -1)
19966420897Smickey warn("open");
200c4849fe1Sderaadt dup2(fd, 0);
201c4849fe1Sderaadt dup2(fd, 1);
202c4849fe1Sderaadt dup2(fd, 2);
203c4849fe1Sderaadt if (fd > 2)
204c4849fe1Sderaadt close(fd);
205c4849fe1Sderaadt
206c4849fe1Sderaadt /* At a minimum... */
207c4849fe1Sderaadt tcgetattr(0, &t);
208c4849fe1Sderaadt t.c_oflag |= (ONLCR | OPOST);
209c4849fe1Sderaadt tcsetattr(0, TCSANOW, &t);
210c4849fe1Sderaadt
211c96f6a27Sderaadt execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL);
212c4849fe1Sderaadt _exit(1);
213833e69e8Sderaadt default:
214433c54bfShenning /* rc exits 2 if powerdown=YES in rc.shutdown */
215433c54bfShenning waitpid(pid, &status, 0);
2169179587aStedu if (dohalt && WIFEXITED(status) && WEXITSTATUS(status) == 2)
217433c54bfShenning howto |= RB_POWERDOWN;
218833e69e8Sderaadt }
219833e69e8Sderaadt }
220833e69e8Sderaadt
2215b0d3c01Smillert /*
2225b0d3c01Smillert * Point of no return, block all signals so we are sure to
2235b0d3c01Smillert * reach the call to reboot(2) unmolested.
2245b0d3c01Smillert */
2255b0d3c01Smillert sigfillset(&mask);
2265b0d3c01Smillert sigprocmask(SIG_BLOCK, &mask, NULL);
2275b0d3c01Smillert
228df930be7Sderaadt /* Send a SIGTERM first, a chance to save the buffers. */
22913422552Sderaadt if (kill(-1, SIGTERM) == -1) {
23013422552Sderaadt /*
23113422552Sderaadt * If ESRCH, everything's OK: we're the only non-system
23213422552Sderaadt * process! That can happen e.g. via 'exec reboot' in
23313422552Sderaadt * single-user mode.
23413422552Sderaadt */
23513422552Sderaadt if (errno != ESRCH) {
23601de6d07Smickey warn("SIGTERM processes");
23713422552Sderaadt goto restart;
23813422552Sderaadt }
23913422552Sderaadt }
240df930be7Sderaadt
241df930be7Sderaadt /*
242df930be7Sderaadt * After the processes receive the signal, start the rest of the
243f3e19106Sderaadt * buffers on their way. Wait 5 seconds between the SIGTERM and
244f3e19106Sderaadt * the SIGKILL to give everybody a chance.
245df930be7Sderaadt */
246*3dbceb11Ssf sleep_while_procs(2);
247df930be7Sderaadt if (!nflag)
248df930be7Sderaadt sync();
249*3dbceb11Ssf sleep_while_procs(3);
250df930be7Sderaadt
251df930be7Sderaadt for (i = 1;; ++i) {
252df930be7Sderaadt if (kill(-1, SIGKILL) == -1) {
253df930be7Sderaadt if (errno == ESRCH)
254df930be7Sderaadt break;
255df930be7Sderaadt goto restart;
256df930be7Sderaadt }
257df930be7Sderaadt if (i > 5) {
25801de6d07Smickey warnx("WARNING: some process(es) wouldn't die");
259df930be7Sderaadt break;
260df930be7Sderaadt }
261*3dbceb11Ssf sleep_while_procs(2 * i);
262df930be7Sderaadt }
263df930be7Sderaadt
264df930be7Sderaadt reboot(howto);
265df930be7Sderaadt /* FALLTHROUGH */
266df930be7Sderaadt
267df930be7Sderaadt restart:
26801de6d07Smickey errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : "");
269df930be7Sderaadt /* NOTREACHED */
270df930be7Sderaadt }
271df930be7Sderaadt
272df930be7Sderaadt void
usage(void)273bc52e260Sderaadt usage(void)
274df930be7Sderaadt {
27571025d0dSderaadt fprintf(stderr, "usage: %s [-dn%sq]\n", __progname,
27671025d0dSderaadt dohalt ? "p" : "");
277df930be7Sderaadt exit(1);
278df930be7Sderaadt }
279