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