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 { 1160df5f659SWarner Losh FILE *fp; 1170df5f659SWarner Losh struct statfs sfs; 1180df5f659SWarner Losh bool supported = false; 1190df5f659SWarner Losh bool zfs = false; 1200df5f659SWarner Losh 1210df5f659SWarner Losh if (statfs("/boot", &sfs) != 0) 1220df5f659SWarner Losh err(1, "statfs /boot"); 1230df5f659SWarner Losh if (strcmp(sfs.f_fstypename, "ufs") == 0) { 1240df5f659SWarner Losh /* 1250df5f659SWarner Losh * Only UFS supports the full nextboot protocol. 1260df5f659SWarner Losh */ 1270df5f659SWarner Losh supported = true; 1280df5f659SWarner Losh } else if (strcmp(sfs.f_fstypename, "zfs") == 0) { 1290df5f659SWarner Losh zfs = true; 1300df5f659SWarner Losh } 1310df5f659SWarner Losh 1320df5f659SWarner Losh if (zfs) { 133*0c3ade2cSGleb Smirnoff char *slash; 134*0c3ade2cSGleb Smirnoff 135*0c3ade2cSGleb Smirnoff if ((slash = strchr(sfs.f_mntfromname, '/')) == NULL) 136*0c3ade2cSGleb Smirnoff E("Can't find ZFS pool name in %s", sfs.f_mntfromname); 137*0c3ade2cSGleb Smirnoff *slash = '\0'; 1380df5f659SWarner Losh zfsbootcfg(sfs.f_mntfromname, force); 1390df5f659SWarner Losh } 1400df5f659SWarner Losh 141cfeedadfSWarner Losh fp = fopen(fn, "w"); 142cfeedadfSWarner Losh if (fp == NULL) 1439dcf6cbdSWarner Losh E("Can't create %s", fn); 144cfeedadfSWarner Losh 1459dcf6cbdSWarner Losh if (fprintf(fp,"%s%s", 1460df5f659SWarner Losh supported ? "nextboot_enable=\"YES\"\n" : "", 1479dcf6cbdSWarner Losh env != NULL ? env : "") < 0) { 148cfeedadfSWarner Losh int e; 149cfeedadfSWarner Losh 150cfeedadfSWarner Losh e = errno; 151cfeedadfSWarner Losh fclose(fp); 152cfeedadfSWarner Losh if (unlink(fn)) 153cfeedadfSWarner Losh warn("unlink %s", fn); 154cfeedadfSWarner Losh errno = e; 155cfeedadfSWarner Losh E("Can't write %s", fn); 156cfeedadfSWarner Losh } 157cfeedadfSWarner Losh fclose(fp); 158cfeedadfSWarner Losh } 159cfeedadfSWarner Losh 160ecc83424SWarner Losh static char * 161ecc83424SWarner Losh split_kv(char *raw) 162ecc83424SWarner Losh { 163ecc83424SWarner Losh char *eq; 164ecc83424SWarner Losh int len; 165ecc83424SWarner Losh 166ecc83424SWarner Losh eq = strchr(raw, '='); 167ecc83424SWarner Losh if (eq == NULL) 168ecc83424SWarner Losh errx(1, "No = in environment string %s", raw); 169ecc83424SWarner Losh *eq++ = '\0'; 170ecc83424SWarner Losh len = strlen(eq); 171ecc83424SWarner Losh if (len == 0) 172ecc83424SWarner Losh errx(1, "Invalid null value %s=", raw); 173ecc83424SWarner Losh if (eq[0] == '"') { 174ecc83424SWarner Losh if (len < 2 || eq[len - 1] != '"') 175ecc83424SWarner Losh errx(1, "Invalid string '%s'", eq); 176ecc83424SWarner Losh eq[len - 1] = '\0'; 177ecc83424SWarner Losh return (eq + 1); 178ecc83424SWarner Losh } 179ecc83424SWarner Losh return (eq); 180ecc83424SWarner Losh } 181ecc83424SWarner Losh 182ecc83424SWarner Losh static void 183ecc83424SWarner Losh add_env(char **env, const char *key, const char *value) 184ecc83424SWarner Losh { 185ecc83424SWarner Losh char *oldenv; 186ecc83424SWarner Losh 187ecc83424SWarner Losh oldenv = *env; 188ecc83424SWarner Losh asprintf(env, "%s%s=\"%s\"\n", oldenv != NULL ? oldenv : "", key, value); 189ecc83424SWarner Losh if (env == NULL) 190ecc83424SWarner Losh errx(1, "No memory to build env array"); 191ecc83424SWarner Losh free(oldenv); 192ecc83424SWarner Losh } 193ecc83424SWarner Losh 194994cc839SWarner Losh /* 195994cc839SWarner Losh * Different options are valid for different programs. 196994cc839SWarner Losh */ 197994cc839SWarner Losh #define GETOPT_REBOOT "cDde:k:lNno:pqr" 198994cc839SWarner Losh #define GETOPT_NEXTBOOT "De:k:o:" 199994cc839SWarner Losh 2008fae3551SRodney W. Grimes int 20185ae580cSIan Dowse main(int argc, char *argv[]) 2028fae3551SRodney W. Grimes { 20314c69f21SEd Schouten struct utmpx utx; 20436737a0bSXin LI const struct passwd *pw; 205e32de962SWarner Losh int ch, howto = 0, i, sverrno; 2062c479548SWarner Losh bool Dflag, fflag, lflag, Nflag, nflag, qflag; 207194cc45aSKonstantin Belousov uint64_t pageins; 208994cc839SWarner Losh const char *user, *kernel = NULL, *getopts = GETOPT_REBOOT; 209ecc83424SWarner Losh char *env = NULL, *v; 210ecc83424SWarner Losh 2116760585aSEric van Gyzen if (strstr(getprogname(), "halt") != NULL) { 2127a3210f2SWarner Losh dohalt = true; 2138fae3551SRodney W. Grimes howto = RB_HALT; 214994cc839SWarner Losh } else if (strcmp(getprogname(), "nextboot") == 0) { 215994cc839SWarner Losh donextboot = true; 216994cc839SWarner Losh getopts = GETOPT_NEXTBOOT; /* Note: reboot's extra opts return '?' */ 217994cc839SWarner Losh } else { 218e32de962SWarner Losh /* reboot */ 2198fae3551SRodney W. Grimes howto = 0; 220994cc839SWarner Losh } 2212c479548SWarner Losh Dflag = fflag = lflag = Nflag = nflag = qflag = false; 222994cc839SWarner Losh while ((ch = getopt(argc, argv, getopts)) != -1) { 2238fae3551SRodney W. Grimes switch(ch) { 2247d7d9013SWarner Losh case 'c': 2257d7d9013SWarner Losh howto |= RB_POWERCYCLE; 2267d7d9013SWarner Losh break; 2272c479548SWarner Losh case 'D': 2282c479548SWarner Losh Dflag = true; 2292c479548SWarner Losh break; 23085c981ccSJohn Polstra case 'd': 23185c981ccSJohn Polstra howto |= RB_DUMP; 23285c981ccSJohn Polstra break; 233ecc83424SWarner Losh case 'e': 234ecc83424SWarner Losh v = split_kv(optarg); 235ecc83424SWarner Losh add_env(&env, optarg, v); 236ecc83424SWarner Losh break; 2377cb1a0e6SWarner Losh case 'f': 2387cb1a0e6SWarner Losh fflag = true; 2397cb1a0e6SWarner Losh break; 2401de372dcSWes Peters case 'k': 2411de372dcSWes Peters kernel = optarg; 2421de372dcSWes Peters break; 2436714dac4SNik Clayton case 'l': 2447a3210f2SWarner Losh lflag = true; 2458fae3551SRodney W. Grimes break; 2468fae3551SRodney W. Grimes case 'n': 2477a3210f2SWarner Losh nflag = true; 2488fae3551SRodney W. Grimes howto |= RB_NOSYNC; 2498fae3551SRodney W. Grimes break; 2506237ce08SSteven Hartland case 'N': 2517a3210f2SWarner Losh nflag = true; 2527a3210f2SWarner Losh Nflag = true; 2536237ce08SSteven Hartland break; 25491d24077SWarner Losh case 'o': 25591d24077SWarner Losh add_env(&env, "kernel_options", optarg); 25691d24077SWarner Losh break; 25747be7466SJulian Elischer case 'p': 258cfde77fbSThomas Quinot howto |= RB_POWEROFF; 25947be7466SJulian Elischer break; 2608fae3551SRodney W. Grimes case 'q': 2617a3210f2SWarner Losh qflag = true; 2628fae3551SRodney W. Grimes break; 2633f5ac575SEdward Tomasz Napierala case 'r': 2643f5ac575SEdward Tomasz Napierala howto |= RB_REROOT; 2653f5ac575SEdward Tomasz Napierala break; 2668fae3551SRodney W. Grimes case '?': 2678fae3551SRodney W. Grimes default: 2688fae3551SRodney W. Grimes usage(); 2698fae3551SRodney W. Grimes } 270994cc839SWarner Losh } 271994cc839SWarner Losh 2728fae3551SRodney W. Grimes argc -= optind; 2738fae3551SRodney W. Grimes argv += optind; 2742e23ded5SRodney W. Grimes if (argc != 0) 2752e23ded5SRodney W. Grimes usage(); 2768fae3551SRodney W. Grimes 2772c479548SWarner Losh if (Dflag && ((howto & ~RB_HALT) != 0 || kernel != NULL)) 2782c479548SWarner Losh errx(1, "cannot delete existing nextboot config and do anything else"); 27985c981ccSJohn Polstra if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT)) 28085c981ccSJohn Polstra errx(1, "cannot dump (-d) when halting; must reboot instead"); 2816237ce08SSteven Hartland if (Nflag && (howto & RB_NOSYNC) != 0) 2826237ce08SSteven Hartland errx(1, "-N cannot be used with -n"); 2837d7d9013SWarner Losh if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE)) 2847d7d9013SWarner Losh errx(1, "-c and -p cannot be used together"); 2853f5ac575SEdward Tomasz Napierala if ((howto & RB_REROOT) != 0 && howto != RB_REROOT) 2867d7d9013SWarner Losh errx(1, "-r cannot be used with -c, -d, -n, or -p"); 287a78bc42bSWarner Losh if ((howto & RB_REROOT) != 0 && kernel != NULL) 288a78bc42bSWarner Losh errx(1, "-r and -k cannot be used together, there is no next kernel"); 2898fae3551SRodney W. Grimes 2902c479548SWarner Losh if (Dflag) { 2912c479548SWarner Losh if (unlink(PATH_NEXTBOOT) != 0) 2922c479548SWarner Losh err(1, "unlink %s", PATH_NEXTBOOT); 2932c479548SWarner Losh exit(0); 2942c479548SWarner Losh } 2952c479548SWarner Losh 296994cc839SWarner Losh if (!donextboot && geteuid() != 0) { 297994cc839SWarner Losh errno = EPERM; 298994cc839SWarner Losh err(1, NULL); 299994cc839SWarner Losh } 300994cc839SWarner Losh 3018fae3551SRodney W. Grimes if (qflag) { 3028fae3551SRodney W. Grimes reboot(howto); 303098166edSPhilippe Charnier err(1, NULL); 3048fae3551SRodney W. Grimes } 3058fae3551SRodney W. Grimes 306faa0ecddSXin LI if (kernel != NULL) { 3077cb1a0e6SWarner Losh if (!fflag) { 3087cb1a0e6SWarner Losh char *k; 3097cb1a0e6SWarner Losh struct stat sb; 3107cb1a0e6SWarner Losh 3117cb1a0e6SWarner Losh asprintf(&k, "/boot/%s/kernel", kernel); 3127cb1a0e6SWarner Losh if (k == NULL) 3137cb1a0e6SWarner Losh errx(1, "No memory to check %s", kernel); 3147cb1a0e6SWarner Losh if (stat(k, &sb) != 0) 3157cb1a0e6SWarner Losh err(1, "stat %s", k); 3167cb1a0e6SWarner Losh if (!S_ISREG(sb.st_mode)) 3177cb1a0e6SWarner Losh errx(1, "%s is not a file", k); 3187cb1a0e6SWarner Losh free(k); 3197cb1a0e6SWarner Losh } 3209dcf6cbdSWarner Losh add_env(&env, "kernel", kernel); 3211de372dcSWes Peters } 3221de372dcSWes Peters 323994cc839SWarner Losh if (env != NULL) 3249dcf6cbdSWarner Losh write_nextboot(PATH_NEXTBOOT, env, fflag); 325994cc839SWarner Losh if (donextboot) 326994cc839SWarner Losh exit (0); 327994cc839SWarner Losh 3288fae3551SRodney W. Grimes /* Log the reboot. */ 3298fae3551SRodney W. Grimes if (!lflag) { 3308fae3551SRodney W. Grimes if ((user = getlogin()) == NULL) 3318fae3551SRodney W. Grimes user = (pw = getpwuid(getuid())) ? 3328fae3551SRodney W. Grimes pw->pw_name : "???"; 3338fae3551SRodney W. Grimes if (dohalt) { 3348fae3551SRodney W. Grimes openlog("halt", 0, LOG_AUTH | LOG_CONS); 3358fae3551SRodney W. Grimes syslog(LOG_CRIT, "halted by %s", user); 3363f5ac575SEdward Tomasz Napierala } else if (howto & RB_REROOT) { 3373f5ac575SEdward Tomasz Napierala openlog("reroot", 0, LOG_AUTH | LOG_CONS); 3383f5ac575SEdward Tomasz Napierala syslog(LOG_CRIT, "rerooted by %s", user); 3397d7d9013SWarner Losh } else if (howto & RB_POWEROFF) { 3407d7d9013SWarner Losh openlog("reboot", 0, LOG_AUTH | LOG_CONS); 3417d7d9013SWarner Losh syslog(LOG_CRIT, "powered off by %s", user); 3427d7d9013SWarner Losh } else if (howto & RB_POWERCYCLE) { 3437d7d9013SWarner Losh openlog("reboot", 0, LOG_AUTH | LOG_CONS); 3447d7d9013SWarner Losh syslog(LOG_CRIT, "power cycled by %s", user); 3458fae3551SRodney W. Grimes } else { 3468fae3551SRodney W. Grimes openlog("reboot", 0, LOG_AUTH | LOG_CONS); 3478fae3551SRodney W. Grimes syslog(LOG_CRIT, "rebooted by %s", user); 3488fae3551SRodney W. Grimes } 3498fae3551SRodney W. Grimes } 35014c69f21SEd Schouten utx.ut_type = SHUTDOWN_TIME; 35114c69f21SEd Schouten gettimeofday(&utx.ut_tv, NULL); 35214c69f21SEd Schouten pututxline(&utx); 3538fae3551SRodney W. Grimes 3548fae3551SRodney W. Grimes /* 3558fae3551SRodney W. Grimes * Do a sync early on, so disks start transfers while we're off 3568fae3551SRodney W. Grimes * killing processes. Don't worry about writes done before the 3578fae3551SRodney W. Grimes * processes die, the reboot system call syncs the disks. 3588fae3551SRodney W. Grimes */ 3598fae3551SRodney W. Grimes if (!nflag) 3608fae3551SRodney W. Grimes sync(); 3618fae3551SRodney W. Grimes 362d8f70938SBruce M Simpson /* 363d8f70938SBruce M Simpson * Ignore signals that we can get as a result of killing 364d8f70938SBruce M Simpson * parents, group leaders, etc. 365d8f70938SBruce M Simpson */ 366b08d1553SBruce M Simpson (void)signal(SIGHUP, SIG_IGN); 367d8f70938SBruce M Simpson (void)signal(SIGINT, SIG_IGN); 368d8f70938SBruce M Simpson (void)signal(SIGQUIT, SIG_IGN); 369d8f70938SBruce M Simpson (void)signal(SIGTERM, SIG_IGN); 370d8f70938SBruce M Simpson (void)signal(SIGTSTP, SIG_IGN); 371d8f70938SBruce M Simpson 372d8f70938SBruce M Simpson /* 373d8f70938SBruce M Simpson * If we're running in a pipeline, we don't want to die 374d8f70938SBruce M Simpson * after killing whatever we're writing to. 375d8f70938SBruce M Simpson */ 376d8f70938SBruce M Simpson (void)signal(SIGPIPE, SIG_IGN); 377b08d1553SBruce M Simpson 3783f5ac575SEdward Tomasz Napierala /* 3793f5ac575SEdward Tomasz Napierala * Only init(8) can perform rerooting. 3803f5ac575SEdward Tomasz Napierala */ 3813f5ac575SEdward Tomasz Napierala if (howto & RB_REROOT) { 3823f5ac575SEdward Tomasz Napierala if (kill(1, SIGEMT) == -1) 3833f5ac575SEdward Tomasz Napierala err(1, "SIGEMT init"); 3843f5ac575SEdward Tomasz Napierala 3853f5ac575SEdward Tomasz Napierala return (0); 3863f5ac575SEdward Tomasz Napierala } 3873f5ac575SEdward Tomasz Napierala 3888fae3551SRodney W. Grimes /* Just stop init -- if we fail, we'll restart it. */ 3897b0a665dSMitchell Horne BOOTTRACE("SIGTSTP to init(8)..."); 3908fae3551SRodney W. Grimes if (kill(1, SIGTSTP) == -1) 391098166edSPhilippe Charnier err(1, "SIGTSTP init"); 3928fae3551SRodney W. Grimes 3938fae3551SRodney W. Grimes /* Send a SIGTERM first, a chance to save the buffers. */ 3947b0a665dSMitchell Horne BOOTTRACE("SIGTERM to all other processes..."); 3956ab0d6c2SRobert Watson if (kill(-1, SIGTERM) == -1 && errno != ESRCH) 396098166edSPhilippe Charnier err(1, "SIGTERM processes"); 3978fae3551SRodney W. Grimes 3988fae3551SRodney W. Grimes /* 3998fae3551SRodney W. Grimes * After the processes receive the signal, start the rest of the 4008fae3551SRodney W. Grimes * buffers on their way. Wait 5 seconds between the SIGTERM and 40185ae580cSIan Dowse * the SIGKILL to give everybody a chance. If there is a lot of 40285ae580cSIan Dowse * paging activity then wait longer, up to a maximum of approx 40385ae580cSIan Dowse * 60 seconds. 4048fae3551SRodney W. Grimes */ 4058fae3551SRodney W. Grimes sleep(2); 40685ae580cSIan Dowse for (i = 0; i < 20; i++) { 40785ae580cSIan Dowse pageins = get_pageins(); 4088fae3551SRodney W. Grimes if (!nflag) 4098fae3551SRodney W. Grimes sync(); 4108fae3551SRodney W. Grimes sleep(3); 41185ae580cSIan Dowse if (get_pageins() == pageins) 41285ae580cSIan Dowse break; 41385ae580cSIan Dowse } 4148fae3551SRodney W. Grimes 4158fae3551SRodney W. Grimes for (i = 1;; ++i) { 4167b0a665dSMitchell Horne BOOTTRACE("SIGKILL to all other processes(%d)...", i); 4178fae3551SRodney W. Grimes if (kill(-1, SIGKILL) == -1) { 4188fae3551SRodney W. Grimes if (errno == ESRCH) 4198fae3551SRodney W. Grimes break; 4208fae3551SRodney W. Grimes goto restart; 4218fae3551SRodney W. Grimes } 4228fae3551SRodney W. Grimes if (i > 5) { 4238fae3551SRodney W. Grimes (void)fprintf(stderr, 4248fae3551SRodney W. Grimes "WARNING: some process(es) wouldn't die\n"); 4258fae3551SRodney W. Grimes break; 4268fae3551SRodney W. Grimes } 4278fae3551SRodney W. Grimes (void)sleep(2 * i); 4288fae3551SRodney W. Grimes } 4298fae3551SRodney W. Grimes 4308fae3551SRodney W. Grimes reboot(howto); 4318fae3551SRodney W. Grimes /* FALLTHROUGH */ 4328fae3551SRodney W. Grimes 4338fae3551SRodney W. Grimes restart: 4347b0a665dSMitchell Horne BOOTTRACE("SIGHUP to init(8)..."); 4358fae3551SRodney W. Grimes sverrno = errno; 436098166edSPhilippe Charnier errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "", 4378fae3551SRodney W. Grimes strerror(sverrno)); 4388fae3551SRodney W. Grimes /* NOTREACHED */ 4398fae3551SRodney W. Grimes } 4408fae3551SRodney W. Grimes 44136737a0bSXin LI static void 442c574558fSDag-Erling Smørgrav usage(void) 4438fae3551SRodney W. Grimes { 444c574558fSDag-Erling Smørgrav 445c574558fSDag-Erling Smørgrav (void)fprintf(stderr, dohalt ? 44625fd0815SWarner Losh "usage: halt [-clNnpq] [-k kernel]\n" : 44725fd0815SWarner Losh "usage: reboot [-cdlNnpqr] [-k kernel]\n"); 4488fae3551SRodney W. Grimes exit(1); 4498fae3551SRodney W. Grimes } 45085ae580cSIan Dowse 451194cc45aSKonstantin Belousov static uint64_t 45288a8f792SEd Schouten get_pageins(void) 45385ae580cSIan Dowse { 454194cc45aSKonstantin Belousov uint64_t pageins; 45585ae580cSIan Dowse size_t len; 45685ae580cSIan Dowse 45785ae580cSIan Dowse len = sizeof(pageins); 45885ae580cSIan Dowse if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0) 45985ae580cSIan Dowse != 0) { 460a294b02fSKonstantin Belousov warn("v_swappgsin"); 46185ae580cSIan Dowse return (0); 46285ae580cSIan Dowse } 463194cc45aSKonstantin Belousov return (pageins); 46485ae580cSIan Dowse } 465