1*9179587aStedu /* $OpenBSD: reboot.c,v 1.29 2007/05/11 01:53:07 tedu Exp $ */ 2df930be7Sderaadt /* $NetBSD: reboot.c,v 1.8 1995/10/05 05:36:22 mycroft Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1980, 1986, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 161ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors 17df930be7Sderaadt * may be used to endorse or promote products derived from this software 18df930be7Sderaadt * without specific prior written permission. 19df930be7Sderaadt * 20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30df930be7Sderaadt * SUCH DAMAGE. 31df930be7Sderaadt */ 32df930be7Sderaadt 33df930be7Sderaadt #ifndef lint 34df930be7Sderaadt static char copyright[] = 35df930be7Sderaadt "@(#) Copyright (c) 1980, 1986, 1993\n\ 36df930be7Sderaadt The Regents of the University of California. All rights reserved.\n"; 37df930be7Sderaadt #endif /* not lint */ 38df930be7Sderaadt 39df930be7Sderaadt #ifndef lint 40df930be7Sderaadt #if 0 41df930be7Sderaadt static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 42df930be7Sderaadt #else 43*9179587aStedu static char rcsid[] = "$OpenBSD: reboot.c,v 1.29 2007/05/11 01:53:07 tedu Exp $"; 44df930be7Sderaadt #endif 45df930be7Sderaadt #endif /* not lint */ 46df930be7Sderaadt 4701de6d07Smickey #include <sys/types.h> 48df930be7Sderaadt #include <sys/reboot.h> 49c4849fe1Sderaadt #include <sys/fcntl.h> 503729fd61Sart #include <sys/wait.h> 51df930be7Sderaadt #include <signal.h> 52df930be7Sderaadt #include <pwd.h> 53df930be7Sderaadt #include <errno.h> 5401de6d07Smickey #include <err.h> 55a1521482Smillert #include <fcntl.h> 56ff86fde3Smillert #include <termios.h> 57df930be7Sderaadt #include <syslog.h> 58df930be7Sderaadt #include <unistd.h> 59df930be7Sderaadt #include <stdio.h> 60df930be7Sderaadt #include <stdlib.h> 61df930be7Sderaadt #include <string.h> 62833e69e8Sderaadt #include <paths.h> 6301de6d07Smickey #include <util.h> 64df930be7Sderaadt 65c72b5b24Smillert void usage(void); 6601de6d07Smickey extern char *__progname; 67df930be7Sderaadt 6871025d0dSderaadt int dohalt; 6971025d0dSderaadt 7075a54d2eSderaadt #define _PATH_RC "/etc/rc" 71833e69e8Sderaadt 72df930be7Sderaadt int 73bc52e260Sderaadt main(int argc, char *argv[]) 74df930be7Sderaadt { 750fd6fe2bSdhill unsigned int i; 76df930be7Sderaadt struct passwd *pw; 7771025d0dSderaadt int ch, howto, lflag, nflag, pflag, qflag; 78df930be7Sderaadt char *p, *user; 79df930be7Sderaadt 8001de6d07Smickey p = __progname; 81ddf9f12cSweingart 82ddf9f12cSweingart /* Nuke login shell */ 8371025d0dSderaadt if (*p == '-') 8471025d0dSderaadt p++; 85ddf9f12cSweingart 8601de6d07Smickey howto = dohalt = lflag = nflag = pflag = qflag = 0; 87ddf9f12cSweingart if (!strcmp(p, "halt")) { 88df930be7Sderaadt dohalt = 1; 89df930be7Sderaadt howto = RB_HALT; 9001de6d07Smickey } 9101de6d07Smickey 92f403a9a2Sdownsj while ((ch = getopt(argc, argv, "dlnpq")) != -1) 93df930be7Sderaadt switch (ch) { 94f403a9a2Sdownsj case 'd': 95f403a9a2Sdownsj howto |= RB_DUMP; 96f403a9a2Sdownsj break; 97df930be7Sderaadt case 'l': /* Undocumented; used by shutdown. */ 98df930be7Sderaadt lflag = 1; 99df930be7Sderaadt break; 100df930be7Sderaadt case 'n': 101df930be7Sderaadt nflag = 1; 102df930be7Sderaadt howto |= RB_NOSYNC; 103df930be7Sderaadt break; 104f403a9a2Sdownsj case 'p': 105f403a9a2Sdownsj /* Only works if we're called as halt. */ 106f403a9a2Sdownsj if (dohalt) { 107f403a9a2Sdownsj pflag = 1; 108f403a9a2Sdownsj howto |= RB_POWERDOWN; 109f403a9a2Sdownsj } 110f403a9a2Sdownsj break; 111df930be7Sderaadt case 'q': 112df930be7Sderaadt qflag = 1; 113df930be7Sderaadt break; 114df930be7Sderaadt default: 115df930be7Sderaadt usage(); 116df930be7Sderaadt } 117df930be7Sderaadt argc -= optind; 118df930be7Sderaadt argv += optind; 119df930be7Sderaadt 12071025d0dSderaadt if (argc) 12171025d0dSderaadt usage(); 12271025d0dSderaadt 123df930be7Sderaadt if (geteuid()) 12401de6d07Smickey errx(1, "%s", strerror(EPERM)); 125df930be7Sderaadt 126df930be7Sderaadt if (qflag) { 127df930be7Sderaadt reboot(howto); 12801de6d07Smickey err(1, "reboot"); 129df930be7Sderaadt } 130df930be7Sderaadt 131df930be7Sderaadt /* Log the reboot. */ 132df930be7Sderaadt if (!lflag) { 133df930be7Sderaadt if ((user = getlogin()) == NULL) 134df930be7Sderaadt user = (pw = getpwuid(getuid())) ? 135df930be7Sderaadt pw->pw_name : "???"; 136df930be7Sderaadt if (dohalt) { 137df930be7Sderaadt openlog("halt", 0, LOG_AUTH | LOG_CONS); 138f403a9a2Sdownsj if (pflag) { 139f403a9a2Sdownsj syslog(LOG_CRIT, 140f403a9a2Sdownsj "halted (with powerdown) by %s", user); 141f403a9a2Sdownsj } else { 142df930be7Sderaadt syslog(LOG_CRIT, "halted by %s", user); 143f403a9a2Sdownsj } 144df930be7Sderaadt } else { 145df930be7Sderaadt openlog("reboot", 0, LOG_AUTH | LOG_CONS); 146df930be7Sderaadt syslog(LOG_CRIT, "rebooted by %s", user); 147df930be7Sderaadt } 148df930be7Sderaadt } 149df930be7Sderaadt logwtmp("~", "shutdown", ""); 150df930be7Sderaadt 151df930be7Sderaadt /* 152df930be7Sderaadt * Do a sync early on, so disks start transfers while we're off 153df930be7Sderaadt * killing processes. Don't worry about writes done before the 154df930be7Sderaadt * processes die, the reboot system call syncs the disks. 155df930be7Sderaadt */ 156df930be7Sderaadt if (!nflag) 157df930be7Sderaadt sync(); 158df930be7Sderaadt 159df930be7Sderaadt /* Just stop init -- if we fail, we'll restart it. */ 160df930be7Sderaadt if (kill(1, SIGTSTP) == -1) 16101de6d07Smickey err(1, "SIGTSTP init"); 162df930be7Sderaadt 163df930be7Sderaadt /* Ignore the SIGHUP we get when our parent shell dies. */ 164df930be7Sderaadt (void)signal(SIGHUP, SIG_IGN); 165df930be7Sderaadt 16639c69f54Sderaadt /* 16739c69f54Sderaadt * If we're running in a pipeline, we don't want to die 16839c69f54Sderaadt * after killing whatever we're writing to. 16939c69f54Sderaadt */ 17039c69f54Sderaadt (void)signal(SIGPIPE, SIG_IGN); 17139c69f54Sderaadt 17275a54d2eSderaadt if (access(_PATH_RC, R_OK) != -1) { 173833e69e8Sderaadt pid_t pid; 174c4849fe1Sderaadt struct termios t; 175433c54bfShenning int fd, status; 176833e69e8Sderaadt 177833e69e8Sderaadt switch ((pid = fork())) { 178833e69e8Sderaadt case -1: 179833e69e8Sderaadt break; 180833e69e8Sderaadt case 0: 181c4849fe1Sderaadt if (revoke(_PATH_CONSOLE) == -1) 18266420897Smickey warn("revoke"); 183c4849fe1Sderaadt if (setsid() == -1) 18466420897Smickey warn("setsid"); 185c4849fe1Sderaadt fd = open(_PATH_CONSOLE, O_RDWR); 186c4849fe1Sderaadt if (fd == -1) 18766420897Smickey warn("open"); 188c4849fe1Sderaadt dup2(fd, 0); 189c4849fe1Sderaadt dup2(fd, 1); 190c4849fe1Sderaadt dup2(fd, 2); 191c4849fe1Sderaadt if (fd > 2) 192c4849fe1Sderaadt close(fd); 193c4849fe1Sderaadt 194c4849fe1Sderaadt /* At a minimum... */ 195c4849fe1Sderaadt tcgetattr(0, &t); 196c4849fe1Sderaadt t.c_oflag |= (ONLCR | OPOST); 197c4849fe1Sderaadt tcsetattr(0, TCSANOW, &t); 198c4849fe1Sderaadt 199c96f6a27Sderaadt execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL); 200c4849fe1Sderaadt _exit(1); 201833e69e8Sderaadt default: 202433c54bfShenning /* rc exits 2 if powerdown=YES in rc.shutdown */ 203433c54bfShenning waitpid(pid, &status, 0); 204*9179587aStedu if (dohalt && WIFEXITED(status) && WEXITSTATUS(status) == 2) 205433c54bfShenning howto |= RB_POWERDOWN; 206833e69e8Sderaadt } 207833e69e8Sderaadt } 208833e69e8Sderaadt 209df930be7Sderaadt /* Send a SIGTERM first, a chance to save the buffers. */ 21013422552Sderaadt if (kill(-1, SIGTERM) == -1) { 21113422552Sderaadt /* 21213422552Sderaadt * If ESRCH, everything's OK: we're the only non-system 21313422552Sderaadt * process! That can happen e.g. via 'exec reboot' in 21413422552Sderaadt * single-user mode. 21513422552Sderaadt */ 21613422552Sderaadt if (errno != ESRCH) { 21701de6d07Smickey warn("SIGTERM processes"); 21813422552Sderaadt goto restart; 21913422552Sderaadt } 22013422552Sderaadt } 221df930be7Sderaadt 222df930be7Sderaadt /* 223df930be7Sderaadt * After the processes receive the signal, start the rest of the 224f3e19106Sderaadt * buffers on their way. Wait 5 seconds between the SIGTERM and 225f3e19106Sderaadt * the SIGKILL to give everybody a chance. 226df930be7Sderaadt */ 227df930be7Sderaadt sleep(2); 228df930be7Sderaadt if (!nflag) 229df930be7Sderaadt sync(); 230f3e19106Sderaadt sleep(3); 231df930be7Sderaadt 232df930be7Sderaadt for (i = 1;; ++i) { 233df930be7Sderaadt if (kill(-1, SIGKILL) == -1) { 234df930be7Sderaadt if (errno == ESRCH) 235df930be7Sderaadt break; 236df930be7Sderaadt goto restart; 237df930be7Sderaadt } 238df930be7Sderaadt if (i > 5) { 23901de6d07Smickey warnx("WARNING: some process(es) wouldn't die"); 240df930be7Sderaadt break; 241df930be7Sderaadt } 242df930be7Sderaadt (void)sleep(2 * i); 243df930be7Sderaadt } 244df930be7Sderaadt 245df930be7Sderaadt reboot(howto); 246df930be7Sderaadt /* FALLTHROUGH */ 247df930be7Sderaadt 248df930be7Sderaadt restart: 24901de6d07Smickey errx(1, kill(1, SIGHUP) == -1 ? "(can't restart init): " : ""); 250df930be7Sderaadt /* NOTREACHED */ 251df930be7Sderaadt } 252df930be7Sderaadt 253df930be7Sderaadt void 254bc52e260Sderaadt usage(void) 255df930be7Sderaadt { 25671025d0dSderaadt fprintf(stderr, "usage: %s [-dn%sq]\n", __progname, 25771025d0dSderaadt dohalt ? "p" : ""); 258df930be7Sderaadt exit(1); 259df930be7Sderaadt } 260