reboot.c revision 201182
112580Speter/* 212580Speter * Copyright (c) 1980, 1986, 1993 312580Speter * The Regents of the University of California. All rights reserved. 412580Speter * 512580Speter * Redistribution and use in source and binary forms, with or without 612580Speter * modification, are permitted provided that the following conditions 712580Speter * are met: 812580Speter * 1. Redistributions of source code must retain the above copyright 912580Speter * notice, this list of conditions and the following disclaimer. 1012580Speter * 2. Redistributions in binary form must reproduce the above copyright 1112580Speter * notice, this list of conditions and the following disclaimer in the 1212580Speter * documentation and/or other materials provided with the distribution. 1312580Speter * 4. Neither the name of the University nor the names of its contributors 1412580Speter * may be used to endorse or promote products derived from this software 1512580Speter * without specific prior written permission. 1612580Speter * 1712580Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1812580Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1912580Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2012580Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2112580Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2212580Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2312580Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2412580Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2512580Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2612580Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2712580Speter * SUCH DAMAGE. 2812580Speter */ 2912580Speter 3012580Speter#if 0 3112580Speter#ifndef lint 3212580Speterstatic const char copyright[] = 3312580Speter"@(#) Copyright (c) 1980, 1986, 1993\n\ 3412580Speter The Regents of the University of California. All rights reserved.\n"; 3512580Speter#endif /* not lint */ 3612580Speter 3792451Smarkm#ifndef lint 3842585Speterstatic char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93"; 3942585Speter#endif /* not lint */ 4012580Speter#endif 4142585Speter#include <sys/cdefs.h> 4272842Sgshapiro__FBSDID("$FreeBSD: head/sbin/reboot/reboot.c 201182 2009-12-29 09:13:20Z ed $"); 4342585Speter 4442585Speter#include <sys/reboot.h> 4512580Speter#include <sys/time.h> 4672842Sgshapiro#include <sys/types.h> 4750958Speter#include <sys/sysctl.h> 48147357Sgshapiro#include <signal.h> 4972842Sgshapiro#include <err.h> 5072842Sgshapiro#include <errno.h> 5190801Sgshapiro#include <fcntl.h> 5272842Sgshapiro#include <pwd.h> 5372842Sgshapiro#include <syslog.h> 5472842Sgshapiro#include <stdio.h> 5572842Sgshapiro#include <stdlib.h> 5672842Sgshapiro#include <string.h> 5790811Sgshapiro#define _ULOG_POSIX_NAMES 5890811Sgshapiro#include <ulog.h> 5990811Sgshapiro#include <unistd.h> 6090811Sgshapiro 6190811Sgshapirostatic void usage(void); 6292933Sgshapirostatic u_int get_pageins(void); 6392933Sgshapiro 6493231Sgshapiroint dohalt; 6593231Sgshapiro 66105302Skeramidaint 67105302Skeramidamain(int argc, char *argv[]) 6892933Sgshapiro{ 6979693Sgshapiro struct utmpx utx; 7079693Sgshapiro const struct passwd *pw; 7179693Sgshapiro int ch, howto, i, fd, lflag, nflag, qflag, sverrno; 7272842Sgshapiro u_int pageins; 7392933Sgshapiro const char *p, *user, *kernel = NULL; 7473197Sgshapiro 7572842Sgshapiro if (strstr((p = rindex(*argv, '/')) ? p + 1 : *argv, "halt")) { 7651616Sjmb dohalt = 1; 7772842Sgshapiro howto = RB_HALT; 7872842Sgshapiro } else 7964622Sgshapiro howto = 0; 8064622Sgshapiro lflag = nflag = qflag = 0; 8172842Sgshapiro while ((ch = getopt(argc, argv, "dk:lnpq")) != -1) 8272842Sgshapiro switch(ch) { 8372842Sgshapiro case 'd': 84123820Sgshapiro howto |= RB_DUMP; 85123820Sgshapiro break; 86123820Sgshapiro case 'k': 8773303Sgshapiro kernel = optarg; 8897029Sgshapiro break; 8972842Sgshapiro case 'l': 9072842Sgshapiro lflag = 1; 9172842Sgshapiro break; 9272842Sgshapiro case 'n': 93 nflag = 1; 94 howto |= RB_NOSYNC; 95 break; 96 case 'p': 97 howto |= RB_POWEROFF; 98 break; 99 case 'q': 100 qflag = 1; 101 break; 102 case '?': 103 default: 104 usage(); 105 } 106 argc -= optind; 107 argv += optind; 108 109 if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 110 errx(1, "cannot dump (-d) when halting; must reboot instead"); 111 if (geteuid()) { 112 errno = EPERM; 113 err(1, NULL); 114 } 115 116 if (qflag) { 117 reboot(howto); 118 err(1, NULL); 119 } 120 121 if (kernel != NULL) { 122 fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC, 123 0444); 124 if (fd > -1) { 125 (void)write(fd, "nextboot_enable=\"YES\"\n", 22); 126 (void)write(fd, "kernel=\"", 8L); 127 (void)write(fd, kernel, strlen(kernel)); 128 (void)write(fd, "\"\n", 2); 129 close(fd); 130 } 131 } 132 133 /* Log the reboot. */ 134 if (!lflag) { 135 if ((user = getlogin()) == NULL) 136 user = (pw = getpwuid(getuid())) ? 137 pw->pw_name : "???"; 138 if (dohalt) { 139 openlog("halt", 0, LOG_AUTH | LOG_CONS); 140 syslog(LOG_CRIT, "halted by %s", user); 141 } else { 142 openlog("reboot", 0, LOG_AUTH | LOG_CONS); 143 syslog(LOG_CRIT, "rebooted by %s", user); 144 } 145 } 146 utx.ut_type = SHUTDOWN_TIME; 147 gettimeofday(&utx.ut_tv, NULL); 148 pututxline(&utx); 149 150 /* 151 * Do a sync early on, so disks start transfers while we're off 152 * killing processes. Don't worry about writes done before the 153 * processes die, the reboot system call syncs the disks. 154 */ 155 if (!nflag) 156 sync(); 157 158 /* 159 * Ignore signals that we can get as a result of killing 160 * parents, group leaders, etc. 161 */ 162 (void)signal(SIGHUP, SIG_IGN); 163 (void)signal(SIGINT, SIG_IGN); 164 (void)signal(SIGQUIT, SIG_IGN); 165 (void)signal(SIGTERM, SIG_IGN); 166 (void)signal(SIGTSTP, SIG_IGN); 167 168 /* 169 * If we're running in a pipeline, we don't want to die 170 * after killing whatever we're writing to. 171 */ 172 (void)signal(SIGPIPE, SIG_IGN); 173 174 /* Just stop init -- if we fail, we'll restart it. */ 175 if (kill(1, SIGTSTP) == -1) 176 err(1, "SIGTSTP init"); 177 178 /* Send a SIGTERM first, a chance to save the buffers. */ 179 if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 180 err(1, "SIGTERM processes"); 181 182 /* 183 * After the processes receive the signal, start the rest of the 184 * buffers on their way. Wait 5 seconds between the SIGTERM and 185 * the SIGKILL to give everybody a chance. If there is a lot of 186 * paging activity then wait longer, up to a maximum of approx 187 * 60 seconds. 188 */ 189 sleep(2); 190 for (i = 0; i < 20; i++) { 191 pageins = get_pageins(); 192 if (!nflag) 193 sync(); 194 sleep(3); 195 if (get_pageins() == pageins) 196 break; 197 } 198 199 for (i = 1;; ++i) { 200 if (kill(-1, SIGKILL) == -1) { 201 if (errno == ESRCH) 202 break; 203 goto restart; 204 } 205 if (i > 5) { 206 (void)fprintf(stderr, 207 "WARNING: some process(es) wouldn't die\n"); 208 break; 209 } 210 (void)sleep(2 * i); 211 } 212 213 reboot(howto); 214 /* FALLTHROUGH */ 215 216restart: 217 sverrno = errno; 218 errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 219 strerror(sverrno)); 220 /* NOTREACHED */ 221} 222 223static void 224usage(void) 225{ 226 227 (void)fprintf(stderr, dohalt ? 228 "usage: halt [-lnpq] [-k kernel]\n" : 229 "usage: reboot [-dlnpq] [-k kernel]\n"); 230 exit(1); 231} 232 233static u_int 234get_pageins(void) 235{ 236 u_int pageins; 237 size_t len; 238 239 len = sizeof(pageins); 240 if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 241 != 0) { 242 warnx("v_swappgsin"); 243 return (0); 244 } 245 return pageins; 246} 247