1 /* $OpenBSD: reboot.c,v 1.22 2001/11/05 07:39:17 mpech 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1980, 1986, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 46 #else 47 static char rcsid[] = "$OpenBSD: reboot.c,v 1.22 2001/11/05 07:39:17 mpech Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 #include <sys/types.h> 52 #include <sys/reboot.h> 53 #include <sys/fcntl.h> 54 #include <sys/wait.h> 55 #include <signal.h> 56 #include <pwd.h> 57 #include <errno.h> 58 #include <err.h> 59 #include <fcntl.h> 60 #include <termios.h> 61 #include <syslog.h> 62 #include <unistd.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <paths.h> 67 #include <util.h> 68 69 void usage __P((void)); 70 extern char *__progname; 71 72 #define _PATH_RC "/etc/rc" 73 74 int 75 main(argc, argv) 76 int argc; 77 char *argv[]; 78 { 79 int i; 80 struct passwd *pw; 81 int ch, howto, dohalt, lflag, nflag, pflag, qflag, sverrno; 82 char *p, *user; 83 84 p = __progname; 85 86 /* Nuke login shell */ 87 if(*p == '-') p++; 88 89 howto = dohalt = lflag = nflag = pflag = qflag = 0; 90 if (!strcmp(p, "halt")) { 91 dohalt = 1; 92 howto = RB_HALT; 93 } 94 95 while ((ch = getopt(argc, argv, "dlnpq")) != -1) 96 switch(ch) { 97 case 'd': 98 howto |= RB_DUMP; 99 break; 100 case 'l': /* Undocumented; used by shutdown. */ 101 lflag = 1; 102 break; 103 case 'n': 104 nflag = 1; 105 howto |= RB_NOSYNC; 106 break; 107 case 'p': 108 /* Only works if we're called as halt. */ 109 if (dohalt) { 110 pflag = 1; 111 howto |= RB_POWERDOWN; 112 } 113 break; 114 case 'q': 115 qflag = 1; 116 break; 117 case '?': 118 default: 119 usage(); 120 } 121 argc -= optind; 122 argv += optind; 123 124 if (geteuid()) 125 errx(1, "%s", strerror(EPERM)); 126 127 if (qflag) { 128 reboot(howto); 129 err(1, "reboot"); 130 } 131 132 /* Log the reboot. */ 133 if (!lflag) { 134 if ((user = getlogin()) == NULL) 135 user = (pw = getpwuid(getuid())) ? 136 pw->pw_name : "???"; 137 if (dohalt) { 138 openlog("halt", 0, LOG_AUTH | LOG_CONS); 139 if (pflag) { 140 syslog(LOG_CRIT, 141 "halted (with powerdown) by %s", user); 142 } else { 143 syslog(LOG_CRIT, "halted by %s", user); 144 } 145 } else { 146 openlog("reboot", 0, LOG_AUTH | LOG_CONS); 147 syslog(LOG_CRIT, "rebooted by %s", user); 148 } 149 } 150 logwtmp("~", "shutdown", ""); 151 152 /* 153 * Do a sync early on, so disks start transfers while we're off 154 * killing processes. Don't worry about writes done before the 155 * processes die, the reboot system call syncs the disks. 156 */ 157 if (!nflag) 158 sync(); 159 160 /* Just stop init -- if we fail, we'll restart it. */ 161 if (kill(1, SIGTSTP) == -1) 162 err(1, "SIGTSTP init"); 163 164 /* Ignore the SIGHUP we get when our parent shell dies. */ 165 (void)signal(SIGHUP, SIG_IGN); 166 167 /* 168 * If we're running in a pipeline, we don't want to die 169 * after killing whatever we're writing to. 170 */ 171 (void)signal(SIGPIPE, SIG_IGN); 172 173 if (access(_PATH_RC, R_OK) != -1) { 174 pid_t pid; 175 struct termios t; 176 int fd; 177 178 switch ((pid = fork())) { 179 case -1: 180 break; 181 case 0: 182 if (revoke(_PATH_CONSOLE) == -1) 183 warn("revoke"); 184 if (setsid() == -1) 185 warn("setsid"); 186 fd = open(_PATH_CONSOLE, O_RDWR); 187 if (fd == -1) 188 warn("open"); 189 dup2(fd, 0); 190 dup2(fd, 1); 191 dup2(fd, 2); 192 if (fd > 2) 193 close(fd); 194 195 /* At a minimum... */ 196 tcgetattr(0, &t); 197 t.c_oflag |= (ONLCR | OPOST); 198 tcsetattr(0, TCSANOW, &t); 199 200 execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL); 201 _exit(1); 202 default: 203 waitpid(pid, NULL, 0); 204 } 205 } 206 207 /* Send a SIGTERM first, a chance to save the buffers. */ 208 if (kill(-1, SIGTERM) == -1) { 209 /* 210 * If ESRCH, everything's OK: we're the only non-system 211 * process! That can happen e.g. via 'exec reboot' in 212 * single-user mode. 213 */ 214 if (errno != ESRCH) { 215 warn("SIGTERM processes"); 216 goto restart; 217 } 218 } 219 220 /* 221 * After the processes receive the signal, start the rest of the 222 * buffers on their way. Wait 5 seconds between the SIGTERM and 223 * the SIGKILL to give everybody a chance. 224 */ 225 sleep(2); 226 if (!nflag) 227 sync(); 228 sleep(3); 229 230 for (i = 1;; ++i) { 231 if (kill(-1, SIGKILL) == -1) { 232 if (errno == ESRCH) 233 break; 234 goto restart; 235 } 236 if (i > 5) { 237 warnx("WARNING: some process(es) wouldn't die"); 238 break; 239 } 240 (void)sleep(2 * i); 241 } 242 243 reboot(howto); 244 /* FALLTHROUGH */ 245 246 restart: 247 sverrno = errno; 248 errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : ""); 249 /* NOTREACHED */ 250 } 251 252 void 253 usage() 254 { 255 (void)fprintf(stderr, "usage: %s [-dlnpq]\n", __progname); 256 exit(1); 257 } 258