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