1 /* $OpenBSD: reboot.c,v 1.29 2007/05/11 01:53:07 tedu 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 #ifndef lint 34 static char copyright[] = 35 "@(#) Copyright (c) 1980, 1986, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 42 #else 43 static char rcsid[] = "$OpenBSD: reboot.c,v 1.29 2007/05/11 01:53:07 tedu Exp $"; 44 #endif 45 #endif /* not lint */ 46 47 #include <sys/types.h> 48 #include <sys/reboot.h> 49 #include <sys/fcntl.h> 50 #include <sys/wait.h> 51 #include <signal.h> 52 #include <pwd.h> 53 #include <errno.h> 54 #include <err.h> 55 #include <fcntl.h> 56 #include <termios.h> 57 #include <syslog.h> 58 #include <unistd.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <paths.h> 63 #include <util.h> 64 65 void usage(void); 66 extern char *__progname; 67 68 int dohalt; 69 70 #define _PATH_RC "/etc/rc" 71 72 int 73 main(int argc, char *argv[]) 74 { 75 unsigned int i; 76 struct passwd *pw; 77 int ch, howto, lflag, nflag, pflag, qflag; 78 char *p, *user; 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 if (qflag) { 127 reboot(howto); 128 err(1, "reboot"); 129 } 130 131 /* Log the reboot. */ 132 if (!lflag) { 133 if ((user = getlogin()) == NULL) 134 user = (pw = getpwuid(getuid())) ? 135 pw->pw_name : "???"; 136 if (dohalt) { 137 openlog("halt", 0, LOG_AUTH | LOG_CONS); 138 if (pflag) { 139 syslog(LOG_CRIT, 140 "halted (with powerdown) by %s", user); 141 } else { 142 syslog(LOG_CRIT, "halted by %s", user); 143 } 144 } else { 145 openlog("reboot", 0, LOG_AUTH | LOG_CONS); 146 syslog(LOG_CRIT, "rebooted by %s", user); 147 } 148 } 149 logwtmp("~", "shutdown", ""); 150 151 /* 152 * Do a sync early on, so disks start transfers while we're off 153 * killing processes. Don't worry about writes done before the 154 * processes die, the reboot system call syncs the disks. 155 */ 156 if (!nflag) 157 sync(); 158 159 /* Just stop init -- if we fail, we'll restart it. */ 160 if (kill(1, SIGTSTP) == -1) 161 err(1, "SIGTSTP init"); 162 163 /* Ignore the SIGHUP we get when our parent shell dies. */ 164 (void)signal(SIGHUP, SIG_IGN); 165 166 /* 167 * If we're running in a pipeline, we don't want to die 168 * after killing whatever we're writing to. 169 */ 170 (void)signal(SIGPIPE, SIG_IGN); 171 172 if (access(_PATH_RC, R_OK) != -1) { 173 pid_t pid; 174 struct termios t; 175 int fd, status; 176 177 switch ((pid = fork())) { 178 case -1: 179 break; 180 case 0: 181 if (revoke(_PATH_CONSOLE) == -1) 182 warn("revoke"); 183 if (setsid() == -1) 184 warn("setsid"); 185 fd = open(_PATH_CONSOLE, O_RDWR); 186 if (fd == -1) 187 warn("open"); 188 dup2(fd, 0); 189 dup2(fd, 1); 190 dup2(fd, 2); 191 if (fd > 2) 192 close(fd); 193 194 /* At a minimum... */ 195 tcgetattr(0, &t); 196 t.c_oflag |= (ONLCR | OPOST); 197 tcsetattr(0, TCSANOW, &t); 198 199 execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL); 200 _exit(1); 201 default: 202 /* rc exits 2 if powerdown=YES in rc.shutdown */ 203 waitpid(pid, &status, 0); 204 if (dohalt && WIFEXITED(status) && WEXITSTATUS(status) == 2) 205 howto |= RB_POWERDOWN; 206 } 207 } 208 209 /* Send a SIGTERM first, a chance to save the buffers. */ 210 if (kill(-1, SIGTERM) == -1) { 211 /* 212 * If ESRCH, everything's OK: we're the only non-system 213 * process! That can happen e.g. via 'exec reboot' in 214 * single-user mode. 215 */ 216 if (errno != ESRCH) { 217 warn("SIGTERM processes"); 218 goto restart; 219 } 220 } 221 222 /* 223 * After the processes receive the signal, start the rest of the 224 * buffers on their way. Wait 5 seconds between the SIGTERM and 225 * the SIGKILL to give everybody a chance. 226 */ 227 sleep(2); 228 if (!nflag) 229 sync(); 230 sleep(3); 231 232 for (i = 1;; ++i) { 233 if (kill(-1, SIGKILL) == -1) { 234 if (errno == ESRCH) 235 break; 236 goto restart; 237 } 238 if (i > 5) { 239 warnx("WARNING: some process(es) wouldn't die"); 240 break; 241 } 242 (void)sleep(2 * i); 243 } 244 245 reboot(howto); 246 /* FALLTHROUGH */ 247 248 restart: 249 errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : ""); 250 /* NOTREACHED */ 251 } 252 253 void 254 usage(void) 255 { 256 fprintf(stderr, "usage: %s [-dn%sq]\n", __progname, 257 dohalt ? "p" : ""); 258 exit(1); 259 } 260