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