18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 48fae3551SRodney W. Grimes * Copyright (c) 1980, 1986, 1993 58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 68fae3551SRodney W. Grimes * 78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 98fae3551SRodney W. Grimes * are met: 108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 178fae3551SRodney W. Grimes * without specific prior written permission. 188fae3551SRodney W. Grimes * 198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 298fae3551SRodney W. Grimes * SUCH DAMAGE. 308fae3551SRodney W. Grimes */ 318fae3551SRodney W. Grimes 327b0a665dSMitchell Horne #include <sys/boottrace.h> 330df5f659SWarner Losh #include <sys/mount.h> 347b0a665dSMitchell Horne #include <sys/reboot.h> 357cb1a0e6SWarner Losh #include <sys/stat.h> 3685ae580cSIan Dowse #include <sys/sysctl.h> 377b0a665dSMitchell Horne #include <sys/time.h> 3833a2406eSWarner Losh #include <sys/wait.h> 397b0a665dSMitchell Horne 40098166edSPhilippe Charnier #include <err.h> 419448def9SPhilippe Charnier #include <errno.h> 421de372dcSWes Peters #include <fcntl.h> 439448def9SPhilippe Charnier #include <pwd.h> 447a3210f2SWarner Losh #include <signal.h> 4533a2406eSWarner Losh #include <spawn.h> 467a3210f2SWarner Losh #include <stdbool.h> 479448def9SPhilippe Charnier #include <stdio.h> 48cafefe8cSDima Dorfman #include <stdlib.h> 499448def9SPhilippe Charnier #include <string.h> 507a3210f2SWarner Losh #include <syslog.h> 519448def9SPhilippe Charnier #include <unistd.h> 52bf8959b0SEd Schouten #include <utmpx.h> 538fae3551SRodney W. Grimes 542546c543SWarner Losh extern char **environ; 552546c543SWarner Losh 56cfeedadfSWarner Losh #define PATH_NEXTBOOT "/boot/nextboot.conf" 57cfeedadfSWarner Losh 5865f3be91SAlfonso Gregory static void usage(void) __dead2; 59194cc45aSKonstantin Belousov static uint64_t get_pageins(void); 608fae3551SRodney W. Grimes 617a3210f2SWarner Losh static bool dohalt; 62994cc839SWarner Losh static bool donextboot; 638fae3551SRodney W. Grimes 64cfeedadfSWarner Losh #define E(...) do { \ 65cfeedadfSWarner Losh if (force) { \ 66cfeedadfSWarner Losh warn( __VA_ARGS__ ); \ 67cfeedadfSWarner Losh return; \ 68cfeedadfSWarner Losh } \ 69cfeedadfSWarner Losh err(1, __VA_ARGS__); \ 70cfeedadfSWarner Losh } while (0) \ 71cfeedadfSWarner Losh 720df5f659SWarner Losh static void 730df5f659SWarner Losh zfsbootcfg(const char *pool, bool force) 740df5f659SWarner Losh { 7533a2406eSWarner Losh const char * const av[] = { 7633a2406eSWarner Losh "zfsbootcfg", 7733a2406eSWarner Losh "-z", 7833a2406eSWarner Losh pool, 7933a2406eSWarner Losh "-n", 8033a2406eSWarner Losh "freebsd:nvstore", 8133a2406eSWarner Losh "-k", 823aefe675SGleb Smirnoff "nextboot_enable", 8333a2406eSWarner Losh "-v", 8433a2406eSWarner Losh "YES", 8533a2406eSWarner Losh NULL 8633a2406eSWarner Losh }; 8733a2406eSWarner Losh int rv, status; 8833a2406eSWarner Losh pid_t p; 890df5f659SWarner Losh 9033a2406eSWarner Losh rv = posix_spawnp(&p, av[0], NULL, NULL, __DECONST(char **, av), 9133a2406eSWarner Losh environ); 920df5f659SWarner Losh if (rv == -1) 930df5f659SWarner Losh E("system zfsbootcfg"); 9433a2406eSWarner Losh if (waitpid(p, &status, WEXITED) < 0) { 9533a2406eSWarner Losh if (errno == EINTR) 9633a2406eSWarner Losh return; 9733a2406eSWarner Losh E("waitpid zfsbootcfg"); 9833a2406eSWarner Losh } 9933a2406eSWarner Losh if (WIFEXITED(status)) { 10033a2406eSWarner Losh int e = WEXITSTATUS(status); 10133a2406eSWarner Losh 10233a2406eSWarner Losh if (e == 0) 10333a2406eSWarner Losh return; 10433a2406eSWarner Losh if (e == 127) 1050df5f659SWarner Losh E("zfsbootcfg not found in path"); 10633a2406eSWarner Losh E("zfsbootcfg returned %d", e); 10733a2406eSWarner Losh } 10833a2406eSWarner Losh if (WIFSIGNALED(status)) 10933a2406eSWarner Losh E("zfsbootcfg died with signal %d", WTERMSIG(status)); 11033a2406eSWarner Losh E("zfsbootcfg unexpected status %d", status); 1110df5f659SWarner Losh } 1120df5f659SWarner Losh 1130df5f659SWarner Losh static void 1149dcf6cbdSWarner Losh write_nextboot(const char *fn, const char *env, bool force) 1150df5f659SWarner Losh { 116*87e63f2eSMark Johnston char tmp[PATH_MAX]; 1170df5f659SWarner Losh FILE *fp; 1180df5f659SWarner Losh struct statfs sfs; 119*87e63f2eSMark Johnston int tmpfd; 1200df5f659SWarner Losh bool supported = false; 1210df5f659SWarner Losh bool zfs = false; 1220df5f659SWarner Losh 1230df5f659SWarner Losh if (statfs("/boot", &sfs) != 0) 1240df5f659SWarner Losh err(1, "statfs /boot"); 1250df5f659SWarner Losh if (strcmp(sfs.f_fstypename, "ufs") == 0) { 1260df5f659SWarner Losh /* 1270df5f659SWarner Losh * Only UFS supports the full nextboot protocol. 1280df5f659SWarner Losh */ 1290df5f659SWarner Losh supported = true; 1300df5f659SWarner Losh } else if (strcmp(sfs.f_fstypename, "zfs") == 0) { 1310df5f659SWarner Losh zfs = true; 1320df5f659SWarner Losh } 1330df5f659SWarner Losh 1340df5f659SWarner Losh if (zfs) { 1350c3ade2cSGleb Smirnoff char *slash; 1360c3ade2cSGleb Smirnoff 1370c3ade2cSGleb Smirnoff if ((slash = strchr(sfs.f_mntfromname, '/')) == NULL) 1380c3ade2cSGleb Smirnoff E("Can't find ZFS pool name in %s", sfs.f_mntfromname); 1390c3ade2cSGleb Smirnoff *slash = '\0'; 1400df5f659SWarner Losh zfsbootcfg(sfs.f_mntfromname, force); 1410df5f659SWarner Losh } 1420df5f659SWarner Losh 143*87e63f2eSMark Johnston if (strlcpy(tmp, fn, sizeof(tmp)) >= sizeof(tmp)) 144*87e63f2eSMark Johnston E("Path too long %s", fn); 145*87e63f2eSMark Johnston if (strlcat(tmp, ".XXXXXX", sizeof(tmp)) >= sizeof(tmp)) 146*87e63f2eSMark Johnston E("Path too long %s", fn); 147*87e63f2eSMark Johnston tmpfd = mkstemp(tmp); 148*87e63f2eSMark Johnston if (tmpfd == -1) 149*87e63f2eSMark Johnston E("mkstemp %s", tmp); 150*87e63f2eSMark Johnston 151*87e63f2eSMark Johnston fp = fdopen(tmpfd, "w"); 152cfeedadfSWarner Losh if (fp == NULL) 153*87e63f2eSMark Johnston E("fdopen %s", tmp); 154cfeedadfSWarner Losh 1559dcf6cbdSWarner Losh if (fprintf(fp, "%s%s", 1560df5f659SWarner Losh supported ? "nextboot_enable=\"YES\"\n" : "", 1579dcf6cbdSWarner Losh env != NULL ? env : "") < 0) { 158cfeedadfSWarner Losh int e; 159cfeedadfSWarner Losh 160cfeedadfSWarner Losh e = errno; 161*87e63f2eSMark Johnston if (unlink(tmp)) 162*87e63f2eSMark Johnston warn("unlink %s", tmp); 163cfeedadfSWarner Losh errno = e; 164*87e63f2eSMark Johnston E("Can't write %s", tmp); 165*87e63f2eSMark Johnston } 166*87e63f2eSMark Johnston if (fsync(fileno(fp)) != 0) 167*87e63f2eSMark Johnston E("Can't fsync %s", fn); 168*87e63f2eSMark Johnston if (rename(tmp, fn) != 0) { 169*87e63f2eSMark Johnston int e; 170*87e63f2eSMark Johnston 171*87e63f2eSMark Johnston e = errno; 172*87e63f2eSMark Johnston if (unlink(tmp)) 173*87e63f2eSMark Johnston warn("unlink %s", tmp); 174*87e63f2eSMark Johnston errno = e; 175*87e63f2eSMark Johnston E("Can't rename %s to %s", tmp, fn); 176cfeedadfSWarner Losh } 177cfeedadfSWarner Losh fclose(fp); 178cfeedadfSWarner Losh } 179cfeedadfSWarner Losh 180ecc83424SWarner Losh static char * 181ecc83424SWarner Losh split_kv(char *raw) 182ecc83424SWarner Losh { 183ecc83424SWarner Losh char *eq; 184ecc83424SWarner Losh int len; 185ecc83424SWarner Losh 186ecc83424SWarner Losh eq = strchr(raw, '='); 187ecc83424SWarner Losh if (eq == NULL) 188ecc83424SWarner Losh errx(1, "No = in environment string %s", raw); 189ecc83424SWarner Losh *eq++ = '\0'; 190ecc83424SWarner Losh len = strlen(eq); 191ecc83424SWarner Losh if (len == 0) 192ecc83424SWarner Losh errx(1, "Invalid null value %s=", raw); 193ecc83424SWarner Losh if (eq[0] == '"') { 194ecc83424SWarner Losh if (len < 2 || eq[len - 1] != '"') 195ecc83424SWarner Losh errx(1, "Invalid string '%s'", eq); 196ecc83424SWarner Losh eq[len - 1] = '\0'; 197ecc83424SWarner Losh return (eq + 1); 198ecc83424SWarner Losh } 199ecc83424SWarner Losh return (eq); 200ecc83424SWarner Losh } 201ecc83424SWarner Losh 202ecc83424SWarner Losh static void 203ecc83424SWarner Losh add_env(char **env, const char *key, const char *value) 204ecc83424SWarner Losh { 205ecc83424SWarner Losh char *oldenv; 206ecc83424SWarner Losh 207ecc83424SWarner Losh oldenv = *env; 208ecc83424SWarner Losh asprintf(env, "%s%s=\"%s\"\n", oldenv != NULL ? oldenv : "", key, value); 209ecc83424SWarner Losh if (env == NULL) 210ecc83424SWarner Losh errx(1, "No memory to build env array"); 211ecc83424SWarner Losh free(oldenv); 212ecc83424SWarner Losh } 213ecc83424SWarner Losh 214994cc839SWarner Losh /* 215994cc839SWarner Losh * Different options are valid for different programs. 216994cc839SWarner Losh */ 217*87e63f2eSMark Johnston #define GETOPT_REBOOT "cDde:fk:lNno:pqr" 218*87e63f2eSMark Johnston #define GETOPT_NEXTBOOT "De:fk:o:" 219994cc839SWarner Losh 2208fae3551SRodney W. Grimes int 22185ae580cSIan Dowse main(int argc, char *argv[]) 2228fae3551SRodney W. Grimes { 22314c69f21SEd Schouten struct utmpx utx; 22436737a0bSXin LI const struct passwd *pw; 225e32de962SWarner Losh int ch, howto = 0, i, sverrno; 2262c479548SWarner Losh bool Dflag, fflag, lflag, Nflag, nflag, qflag; 227194cc45aSKonstantin Belousov uint64_t pageins; 228994cc839SWarner Losh const char *user, *kernel = NULL, *getopts = GETOPT_REBOOT; 229ecc83424SWarner Losh char *env = NULL, *v; 230ecc83424SWarner Losh 2316760585aSEric van Gyzen if (strstr(getprogname(), "halt") != NULL) { 2327a3210f2SWarner Losh dohalt = true; 2338fae3551SRodney W. Grimes howto = RB_HALT; 234994cc839SWarner Losh } else if (strcmp(getprogname(), "nextboot") == 0) { 235994cc839SWarner Losh donextboot = true; 236994cc839SWarner Losh getopts = GETOPT_NEXTBOOT; /* Note: reboot's extra opts return '?' */ 237994cc839SWarner Losh } else { 238e32de962SWarner Losh /* reboot */ 2398fae3551SRodney W. Grimes howto = 0; 240994cc839SWarner Losh } 2412c479548SWarner Losh Dflag = fflag = lflag = Nflag = nflag = qflag = false; 242994cc839SWarner Losh while ((ch = getopt(argc, argv, getopts)) != -1) { 2438fae3551SRodney W. Grimes switch(ch) { 2447d7d9013SWarner Losh case 'c': 2457d7d9013SWarner Losh howto |= RB_POWERCYCLE; 2467d7d9013SWarner Losh break; 2472c479548SWarner Losh case 'D': 2482c479548SWarner Losh Dflag = true; 2492c479548SWarner Losh break; 25085c981ccSJohn Polstra case 'd': 25185c981ccSJohn Polstra howto |= RB_DUMP; 25285c981ccSJohn Polstra break; 253ecc83424SWarner Losh case 'e': 254ecc83424SWarner Losh v = split_kv(optarg); 255ecc83424SWarner Losh add_env(&env, optarg, v); 256ecc83424SWarner Losh break; 2577cb1a0e6SWarner Losh case 'f': 2587cb1a0e6SWarner Losh fflag = true; 2597cb1a0e6SWarner Losh break; 2601de372dcSWes Peters case 'k': 2611de372dcSWes Peters kernel = optarg; 2621de372dcSWes Peters break; 2636714dac4SNik Clayton case 'l': 2647a3210f2SWarner Losh lflag = true; 2658fae3551SRodney W. Grimes break; 2668fae3551SRodney W. Grimes case 'n': 2677a3210f2SWarner Losh nflag = true; 2688fae3551SRodney W. Grimes howto |= RB_NOSYNC; 2698fae3551SRodney W. Grimes break; 2706237ce08SSteven Hartland case 'N': 2717a3210f2SWarner Losh nflag = true; 2727a3210f2SWarner Losh Nflag = true; 2736237ce08SSteven Hartland break; 27491d24077SWarner Losh case 'o': 27591d24077SWarner Losh add_env(&env, "kernel_options", optarg); 27691d24077SWarner Losh break; 27747be7466SJulian Elischer case 'p': 278cfde77fbSThomas Quinot howto |= RB_POWEROFF; 27947be7466SJulian Elischer break; 2808fae3551SRodney W. Grimes case 'q': 2817a3210f2SWarner Losh qflag = true; 2828fae3551SRodney W. Grimes break; 2833f5ac575SEdward Tomasz Napierala case 'r': 2843f5ac575SEdward Tomasz Napierala howto |= RB_REROOT; 2853f5ac575SEdward Tomasz Napierala break; 2868fae3551SRodney W. Grimes case '?': 2878fae3551SRodney W. Grimes default: 2888fae3551SRodney W. Grimes usage(); 2898fae3551SRodney W. Grimes } 290994cc839SWarner Losh } 291994cc839SWarner Losh 2928fae3551SRodney W. Grimes argc -= optind; 2938fae3551SRodney W. Grimes argv += optind; 2942e23ded5SRodney W. Grimes if (argc != 0) 2952e23ded5SRodney W. Grimes usage(); 2968fae3551SRodney W. Grimes 2972c479548SWarner Losh if (Dflag && ((howto & ~RB_HALT) != 0 || kernel != NULL)) 2982c479548SWarner Losh errx(1, "cannot delete existing nextboot config and do anything else"); 29985c981ccSJohn Polstra if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 30085c981ccSJohn Polstra errx(1, "cannot dump (-d) when halting; must reboot instead"); 3016237ce08SSteven Hartland if (Nflag && (howto & RB_NOSYNC) != 0) 3026237ce08SSteven Hartland errx(1, "-N cannot be used with -n"); 3037d7d9013SWarner Losh if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE)) 3047d7d9013SWarner Losh errx(1, "-c and -p cannot be used together"); 3053f5ac575SEdward Tomasz Napierala if ((howto & RB_REROOT) != 0 && howto != RB_REROOT) 3067d7d9013SWarner Losh errx(1, "-r cannot be used with -c, -d, -n, or -p"); 307a78bc42bSWarner Losh if ((howto & RB_REROOT) != 0 && kernel != NULL) 308a78bc42bSWarner Losh errx(1, "-r and -k cannot be used together, there is no next kernel"); 3098fae3551SRodney W. Grimes 3102c479548SWarner Losh if (Dflag) { 311bad90cb4SWarner Losh if (unlink(PATH_NEXTBOOT) != 0 && errno != ENOENT) 312bad90cb4SWarner Losh warn("unlink " PATH_NEXTBOOT); 3132c479548SWarner Losh exit(0); 3142c479548SWarner Losh } 3152c479548SWarner Losh 316994cc839SWarner Losh if (!donextboot && geteuid() != 0) { 317994cc839SWarner Losh errno = EPERM; 318994cc839SWarner Losh err(1, NULL); 319994cc839SWarner Losh } 320994cc839SWarner Losh 3218fae3551SRodney W. Grimes if (qflag) { 3228fae3551SRodney W. Grimes reboot(howto); 323098166edSPhilippe Charnier err(1, NULL); 3248fae3551SRodney W. Grimes } 3258fae3551SRodney W. Grimes 326faa0ecddSXin LI if (kernel != NULL) { 3277cb1a0e6SWarner Losh if (!fflag) { 3287cb1a0e6SWarner Losh char *k; 3297cb1a0e6SWarner Losh struct stat sb; 3307cb1a0e6SWarner Losh 3317cb1a0e6SWarner Losh asprintf(&k, "/boot/%s/kernel", kernel); 3327cb1a0e6SWarner Losh if (k == NULL) 3337cb1a0e6SWarner Losh errx(1, "No memory to check %s", kernel); 3347cb1a0e6SWarner Losh if (stat(k, &sb) != 0) 3357cb1a0e6SWarner Losh err(1, "stat %s", k); 3367cb1a0e6SWarner Losh if (!S_ISREG(sb.st_mode)) 3377cb1a0e6SWarner Losh errx(1, "%s is not a file", k); 3387cb1a0e6SWarner Losh free(k); 3397cb1a0e6SWarner Losh } 3409dcf6cbdSWarner Losh add_env(&env, "kernel", kernel); 3411de372dcSWes Peters } 3421de372dcSWes Peters 343994cc839SWarner Losh if (env != NULL) 3449dcf6cbdSWarner Losh write_nextboot(PATH_NEXTBOOT, env, fflag); 345994cc839SWarner Losh if (donextboot) 346994cc839SWarner Losh exit (0); 347994cc839SWarner Losh 3488fae3551SRodney W. Grimes /* Log the reboot. */ 3498fae3551SRodney W. Grimes if (!lflag) { 3508fae3551SRodney W. Grimes if ((user = getlogin()) == NULL) 3518fae3551SRodney W. Grimes user = (pw = getpwuid(getuid())) ? 3528fae3551SRodney W. Grimes pw->pw_name : "???"; 3538fae3551SRodney W. Grimes if (dohalt) { 3548fae3551SRodney W. Grimes openlog("halt", 0, LOG_AUTH | LOG_CONS); 3558fae3551SRodney W. Grimes syslog(LOG_CRIT, "halted by %s", user); 3563f5ac575SEdward Tomasz Napierala } else if (howto & RB_REROOT) { 3573f5ac575SEdward Tomasz Napierala openlog("reroot", 0, LOG_AUTH | LOG_CONS); 3583f5ac575SEdward Tomasz Napierala syslog(LOG_CRIT, "rerooted by %s", user); 3597d7d9013SWarner Losh } else if (howto & RB_POWEROFF) { 3607d7d9013SWarner Losh openlog("reboot", 0, LOG_AUTH | LOG_CONS); 3617d7d9013SWarner Losh syslog(LOG_CRIT, "powered off by %s", user); 3627d7d9013SWarner Losh } else if (howto & RB_POWERCYCLE) { 3637d7d9013SWarner Losh openlog("reboot", 0, LOG_AUTH | LOG_CONS); 3647d7d9013SWarner Losh syslog(LOG_CRIT, "power cycled by %s", user); 3658fae3551SRodney W. Grimes } else { 3668fae3551SRodney W. Grimes openlog("reboot", 0, LOG_AUTH | LOG_CONS); 3678fae3551SRodney W. Grimes syslog(LOG_CRIT, "rebooted by %s", user); 3688fae3551SRodney W. Grimes } 3698fae3551SRodney W. Grimes } 37014c69f21SEd Schouten utx.ut_type = SHUTDOWN_TIME; 37114c69f21SEd Schouten gettimeofday(&utx.ut_tv, NULL); 37214c69f21SEd Schouten pututxline(&utx); 3738fae3551SRodney W. Grimes 3748fae3551SRodney W. Grimes /* 3758fae3551SRodney W. Grimes * Do a sync early on, so disks start transfers while we're off 3768fae3551SRodney W. Grimes * killing processes. Don't worry about writes done before the 3778fae3551SRodney W. Grimes * processes die, the reboot system call syncs the disks. 3788fae3551SRodney W. Grimes */ 3798fae3551SRodney W. Grimes if (!nflag) 3808fae3551SRodney W. Grimes sync(); 3818fae3551SRodney W. Grimes 382d8f70938SBruce M Simpson /* 383d8f70938SBruce M Simpson * Ignore signals that we can get as a result of killing 384d8f70938SBruce M Simpson * parents, group leaders, etc. 385d8f70938SBruce M Simpson */ 386b08d1553SBruce M Simpson (void)signal(SIGHUP, SIG_IGN); 387d8f70938SBruce M Simpson (void)signal(SIGINT, SIG_IGN); 388d8f70938SBruce M Simpson (void)signal(SIGQUIT, SIG_IGN); 389d8f70938SBruce M Simpson (void)signal(SIGTERM, SIG_IGN); 390d8f70938SBruce M Simpson (void)signal(SIGTSTP, SIG_IGN); 391d8f70938SBruce M Simpson 392d8f70938SBruce M Simpson /* 393d8f70938SBruce M Simpson * If we're running in a pipeline, we don't want to die 394d8f70938SBruce M Simpson * after killing whatever we're writing to. 395d8f70938SBruce M Simpson */ 396d8f70938SBruce M Simpson (void)signal(SIGPIPE, SIG_IGN); 397b08d1553SBruce M Simpson 3983f5ac575SEdward Tomasz Napierala /* 3993f5ac575SEdward Tomasz Napierala * Only init(8) can perform rerooting. 4003f5ac575SEdward Tomasz Napierala */ 4013f5ac575SEdward Tomasz Napierala if (howto & RB_REROOT) { 4023f5ac575SEdward Tomasz Napierala if (kill(1, SIGEMT) == -1) 4033f5ac575SEdward Tomasz Napierala err(1, "SIGEMT init"); 4043f5ac575SEdward Tomasz Napierala 4053f5ac575SEdward Tomasz Napierala return (0); 4063f5ac575SEdward Tomasz Napierala } 4073f5ac575SEdward Tomasz Napierala 4088fae3551SRodney W. Grimes /* Just stop init -- if we fail, we'll restart it. */ 4097b0a665dSMitchell Horne BOOTTRACE("SIGTSTP to init(8)..."); 4108fae3551SRodney W. Grimes if (kill(1, SIGTSTP) == -1) 411098166edSPhilippe Charnier err(1, "SIGTSTP init"); 4128fae3551SRodney W. Grimes 4138fae3551SRodney W. Grimes /* Send a SIGTERM first, a chance to save the buffers. */ 4147b0a665dSMitchell Horne BOOTTRACE("SIGTERM to all other processes..."); 4156ab0d6c2SRobert Watson if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 416098166edSPhilippe Charnier err(1, "SIGTERM processes"); 4178fae3551SRodney W. Grimes 4188fae3551SRodney W. Grimes /* 4198fae3551SRodney W. Grimes * After the processes receive the signal, start the rest of the 4208fae3551SRodney W. Grimes * buffers on their way. Wait 5 seconds between the SIGTERM and 42185ae580cSIan Dowse * the SIGKILL to give everybody a chance. If there is a lot of 42285ae580cSIan Dowse * paging activity then wait longer, up to a maximum of approx 42385ae580cSIan Dowse * 60 seconds. 4248fae3551SRodney W. Grimes */ 4258fae3551SRodney W. Grimes sleep(2); 42685ae580cSIan Dowse for (i = 0; i < 20; i++) { 42785ae580cSIan Dowse pageins = get_pageins(); 4288fae3551SRodney W. Grimes if (!nflag) 4298fae3551SRodney W. Grimes sync(); 4308fae3551SRodney W. Grimes sleep(3); 43185ae580cSIan Dowse if (get_pageins() == pageins) 43285ae580cSIan Dowse break; 43385ae580cSIan Dowse } 4348fae3551SRodney W. Grimes 4358fae3551SRodney W. Grimes for (i = 1;; ++i) { 4367b0a665dSMitchell Horne BOOTTRACE("SIGKILL to all other processes(%d)...", i); 4378fae3551SRodney W. Grimes if (kill(-1, SIGKILL) == -1) { 4388fae3551SRodney W. Grimes if (errno == ESRCH) 4398fae3551SRodney W. Grimes break; 4408fae3551SRodney W. Grimes goto restart; 4418fae3551SRodney W. Grimes } 4428fae3551SRodney W. Grimes if (i > 5) { 4438fae3551SRodney W. Grimes (void)fprintf(stderr, 4448fae3551SRodney W. Grimes "WARNING: some process(es) wouldn't die\n"); 4458fae3551SRodney W. Grimes break; 4468fae3551SRodney W. Grimes } 4478fae3551SRodney W. Grimes (void)sleep(2 * i); 4488fae3551SRodney W. Grimes } 4498fae3551SRodney W. Grimes 4508fae3551SRodney W. Grimes reboot(howto); 4518fae3551SRodney W. Grimes /* FALLTHROUGH */ 4528fae3551SRodney W. Grimes 4538fae3551SRodney W. Grimes restart: 4547b0a665dSMitchell Horne BOOTTRACE("SIGHUP to init(8)..."); 4558fae3551SRodney W. Grimes sverrno = errno; 456098166edSPhilippe Charnier errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 4578fae3551SRodney W. Grimes strerror(sverrno)); 4588fae3551SRodney W. Grimes /* NOTREACHED */ 4598fae3551SRodney W. Grimes } 4608fae3551SRodney W. Grimes 46136737a0bSXin LI static void 462c574558fSDag-Erling Smørgrav usage(void) 4638fae3551SRodney W. Grimes { 464c574558fSDag-Erling Smørgrav 465c574558fSDag-Erling Smørgrav (void)fprintf(stderr, dohalt ? 46625fd0815SWarner Losh "usage: halt [-clNnpq] [-k kernel]\n" : 46725fd0815SWarner Losh "usage: reboot [-cdlNnpqr] [-k kernel]\n"); 4688fae3551SRodney W. Grimes exit(1); 4698fae3551SRodney W. Grimes } 47085ae580cSIan Dowse 471194cc45aSKonstantin Belousov static uint64_t 47288a8f792SEd Schouten get_pageins(void) 47385ae580cSIan Dowse { 474194cc45aSKonstantin Belousov uint64_t pageins; 47585ae580cSIan Dowse size_t len; 47685ae580cSIan Dowse 47785ae580cSIan Dowse len = sizeof(pageins); 47885ae580cSIan Dowse if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 47985ae580cSIan Dowse != 0) { 480a294b02fSKonstantin Belousov warn("v_swappgsin"); 48185ae580cSIan Dowse return (0); 48285ae580cSIan Dowse } 483194cc45aSKonstantin Belousov return (pageins); 48485ae580cSIan Dowse } 485