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 } 279