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
zfsbootcfg(const char * pool,bool force)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
write_nextboot(const char * fn,const char * env,bool force)1149dcf6cbdSWarner Losh write_nextboot(const char *fn, const char *env, bool force)
1150df5f659SWarner Losh {
11687e63f2eSMark Johnston char tmp[PATH_MAX];
1170df5f659SWarner Losh FILE *fp;
1180df5f659SWarner Losh struct statfs sfs;
11987e63f2eSMark 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
137ff7de3b4SJohn Baldwin slash = strchr(sfs.f_mntfromname, '/');
138ff7de3b4SJohn Baldwin if (slash != NULL)
1390c3ade2cSGleb Smirnoff *slash = '\0';
1400df5f659SWarner Losh zfsbootcfg(sfs.f_mntfromname, force);
1410df5f659SWarner Losh }
1420df5f659SWarner Losh
14387e63f2eSMark Johnston if (strlcpy(tmp, fn, sizeof(tmp)) >= sizeof(tmp))
14487e63f2eSMark Johnston E("Path too long %s", fn);
14587e63f2eSMark Johnston if (strlcat(tmp, ".XXXXXX", sizeof(tmp)) >= sizeof(tmp))
14687e63f2eSMark Johnston E("Path too long %s", fn);
14787e63f2eSMark Johnston tmpfd = mkstemp(tmp);
14887e63f2eSMark Johnston if (tmpfd == -1)
14987e63f2eSMark Johnston E("mkstemp %s", tmp);
15087e63f2eSMark Johnston
15187e63f2eSMark Johnston fp = fdopen(tmpfd, "w");
152cfeedadfSWarner Losh if (fp == NULL)
15387e63f2eSMark 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;
16187e63f2eSMark Johnston if (unlink(tmp))
16287e63f2eSMark Johnston warn("unlink %s", tmp);
163cfeedadfSWarner Losh errno = e;
16487e63f2eSMark Johnston E("Can't write %s", tmp);
16587e63f2eSMark Johnston }
16687e63f2eSMark Johnston if (fsync(fileno(fp)) != 0)
16787e63f2eSMark Johnston E("Can't fsync %s", fn);
16887e63f2eSMark Johnston if (rename(tmp, fn) != 0) {
16987e63f2eSMark Johnston int e;
17087e63f2eSMark Johnston
17187e63f2eSMark Johnston e = errno;
17287e63f2eSMark Johnston if (unlink(tmp))
17387e63f2eSMark Johnston warn("unlink %s", tmp);
17487e63f2eSMark Johnston errno = e;
17587e63f2eSMark Johnston E("Can't rename %s to %s", tmp, fn);
176cfeedadfSWarner Losh }
177cfeedadfSWarner Losh fclose(fp);
178cfeedadfSWarner Losh }
179cfeedadfSWarner Losh
180ecc83424SWarner Losh static char *
split_kv(char * raw)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
add_env(char ** env,const char * key,const char * value)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 */
21787e63f2eSMark Johnston #define GETOPT_REBOOT "cDde:fk:lNno:pqr"
21887e63f2eSMark Johnston #define GETOPT_NEXTBOOT "De:fk:o:"
219994cc839SWarner Losh
2208fae3551SRodney W. Grimes int
main(int argc,char * argv[])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) {
311*bec5a3c0SWarner Losh struct stat sb;
312*bec5a3c0SWarner Losh
313*bec5a3c0SWarner Losh /*
314*bec5a3c0SWarner Losh * Break the rule about stat then doing
315*bec5a3c0SWarner Losh * something. When we're booting, there's no
316*bec5a3c0SWarner Losh * race. When we're a read-only root, though, the
317*bec5a3c0SWarner Losh * read-only error takes priority over the file not
318*bec5a3c0SWarner Losh * there error in unlink. So stat it first and exit
319*bec5a3c0SWarner Losh * with success if it isn't there. Otherwise, let
320*bec5a3c0SWarner Losh * unlink sort error reporting. POSIX-1.2024 suggests
321*bec5a3c0SWarner Losh * ENOENT should be preferred to EROFS for unlink,
322*bec5a3c0SWarner Losh * but FreeBSD historically has preferred EROFS.
323*bec5a3c0SWarner Losh */
324*bec5a3c0SWarner Losh if (stat(PATH_NEXTBOOT, &sb) != 0 && errno == ENOENT)
325*bec5a3c0SWarner Losh exit(0);
326*bec5a3c0SWarner Losh if (unlink(PATH_NEXTBOOT) != 0)
327bad90cb4SWarner Losh warn("unlink " PATH_NEXTBOOT);
3282c479548SWarner Losh exit(0);
3292c479548SWarner Losh }
3302c479548SWarner Losh
331994cc839SWarner Losh if (!donextboot && geteuid() != 0) {
332994cc839SWarner Losh errno = EPERM;
333994cc839SWarner Losh err(1, NULL);
334994cc839SWarner Losh }
335994cc839SWarner Losh
3368fae3551SRodney W. Grimes if (qflag) {
3378fae3551SRodney W. Grimes reboot(howto);
338098166edSPhilippe Charnier err(1, NULL);
3398fae3551SRodney W. Grimes }
3408fae3551SRodney W. Grimes
341faa0ecddSXin LI if (kernel != NULL) {
3427cb1a0e6SWarner Losh if (!fflag) {
3437cb1a0e6SWarner Losh char *k;
3447cb1a0e6SWarner Losh struct stat sb;
3457cb1a0e6SWarner Losh
3467cb1a0e6SWarner Losh asprintf(&k, "/boot/%s/kernel", kernel);
3477cb1a0e6SWarner Losh if (k == NULL)
3487cb1a0e6SWarner Losh errx(1, "No memory to check %s", kernel);
3497cb1a0e6SWarner Losh if (stat(k, &sb) != 0)
3507cb1a0e6SWarner Losh err(1, "stat %s", k);
3517cb1a0e6SWarner Losh if (!S_ISREG(sb.st_mode))
3527cb1a0e6SWarner Losh errx(1, "%s is not a file", k);
3537cb1a0e6SWarner Losh free(k);
3547cb1a0e6SWarner Losh }
3559dcf6cbdSWarner Losh add_env(&env, "kernel", kernel);
3561de372dcSWes Peters }
3571de372dcSWes Peters
358994cc839SWarner Losh if (env != NULL)
3599dcf6cbdSWarner Losh write_nextboot(PATH_NEXTBOOT, env, fflag);
360994cc839SWarner Losh if (donextboot)
361994cc839SWarner Losh exit (0);
362994cc839SWarner Losh
3638fae3551SRodney W. Grimes /* Log the reboot. */
3648fae3551SRodney W. Grimes if (!lflag) {
3658fae3551SRodney W. Grimes if ((user = getlogin()) == NULL)
3668fae3551SRodney W. Grimes user = (pw = getpwuid(getuid())) ?
3678fae3551SRodney W. Grimes pw->pw_name : "???";
3688fae3551SRodney W. Grimes if (dohalt) {
3698fae3551SRodney W. Grimes openlog("halt", 0, LOG_AUTH | LOG_CONS);
3708fae3551SRodney W. Grimes syslog(LOG_CRIT, "halted by %s", user);
3713f5ac575SEdward Tomasz Napierala } else if (howto & RB_REROOT) {
3723f5ac575SEdward Tomasz Napierala openlog("reroot", 0, LOG_AUTH | LOG_CONS);
3733f5ac575SEdward Tomasz Napierala syslog(LOG_CRIT, "rerooted by %s", user);
3747d7d9013SWarner Losh } else if (howto & RB_POWEROFF) {
3757d7d9013SWarner Losh openlog("reboot", 0, LOG_AUTH | LOG_CONS);
3767d7d9013SWarner Losh syslog(LOG_CRIT, "powered off by %s", user);
3777d7d9013SWarner Losh } else if (howto & RB_POWERCYCLE) {
3787d7d9013SWarner Losh openlog("reboot", 0, LOG_AUTH | LOG_CONS);
3797d7d9013SWarner Losh syslog(LOG_CRIT, "power cycled by %s", user);
3808fae3551SRodney W. Grimes } else {
3818fae3551SRodney W. Grimes openlog("reboot", 0, LOG_AUTH | LOG_CONS);
3828fae3551SRodney W. Grimes syslog(LOG_CRIT, "rebooted by %s", user);
3838fae3551SRodney W. Grimes }
3848fae3551SRodney W. Grimes }
38514c69f21SEd Schouten utx.ut_type = SHUTDOWN_TIME;
38614c69f21SEd Schouten gettimeofday(&utx.ut_tv, NULL);
38714c69f21SEd Schouten pututxline(&utx);
3888fae3551SRodney W. Grimes
3898fae3551SRodney W. Grimes /*
3908fae3551SRodney W. Grimes * Do a sync early on, so disks start transfers while we're off
3918fae3551SRodney W. Grimes * killing processes. Don't worry about writes done before the
3928fae3551SRodney W. Grimes * processes die, the reboot system call syncs the disks.
3938fae3551SRodney W. Grimes */
3948fae3551SRodney W. Grimes if (!nflag)
3958fae3551SRodney W. Grimes sync();
3968fae3551SRodney W. Grimes
397d8f70938SBruce M Simpson /*
398d8f70938SBruce M Simpson * Ignore signals that we can get as a result of killing
399d8f70938SBruce M Simpson * parents, group leaders, etc.
400d8f70938SBruce M Simpson */
401b08d1553SBruce M Simpson (void)signal(SIGHUP, SIG_IGN);
402d8f70938SBruce M Simpson (void)signal(SIGINT, SIG_IGN);
403d8f70938SBruce M Simpson (void)signal(SIGQUIT, SIG_IGN);
404d8f70938SBruce M Simpson (void)signal(SIGTERM, SIG_IGN);
405d8f70938SBruce M Simpson (void)signal(SIGTSTP, SIG_IGN);
406d8f70938SBruce M Simpson
407d8f70938SBruce M Simpson /*
408d8f70938SBruce M Simpson * If we're running in a pipeline, we don't want to die
409d8f70938SBruce M Simpson * after killing whatever we're writing to.
410d8f70938SBruce M Simpson */
411d8f70938SBruce M Simpson (void)signal(SIGPIPE, SIG_IGN);
412b08d1553SBruce M Simpson
4133f5ac575SEdward Tomasz Napierala /*
4143f5ac575SEdward Tomasz Napierala * Only init(8) can perform rerooting.
4153f5ac575SEdward Tomasz Napierala */
4163f5ac575SEdward Tomasz Napierala if (howto & RB_REROOT) {
4173f5ac575SEdward Tomasz Napierala if (kill(1, SIGEMT) == -1)
4183f5ac575SEdward Tomasz Napierala err(1, "SIGEMT init");
4193f5ac575SEdward Tomasz Napierala
4203f5ac575SEdward Tomasz Napierala return (0);
4213f5ac575SEdward Tomasz Napierala }
4223f5ac575SEdward Tomasz Napierala
4238fae3551SRodney W. Grimes /* Just stop init -- if we fail, we'll restart it. */
4247b0a665dSMitchell Horne BOOTTRACE("SIGTSTP to init(8)...");
4258fae3551SRodney W. Grimes if (kill(1, SIGTSTP) == -1)
426098166edSPhilippe Charnier err(1, "SIGTSTP init");
4278fae3551SRodney W. Grimes
4288fae3551SRodney W. Grimes /* Send a SIGTERM first, a chance to save the buffers. */
4297b0a665dSMitchell Horne BOOTTRACE("SIGTERM to all other processes...");
4306ab0d6c2SRobert Watson if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
431098166edSPhilippe Charnier err(1, "SIGTERM processes");
4328fae3551SRodney W. Grimes
4338fae3551SRodney W. Grimes /*
4348fae3551SRodney W. Grimes * After the processes receive the signal, start the rest of the
4358fae3551SRodney W. Grimes * buffers on their way. Wait 5 seconds between the SIGTERM and
43685ae580cSIan Dowse * the SIGKILL to give everybody a chance. If there is a lot of
43785ae580cSIan Dowse * paging activity then wait longer, up to a maximum of approx
43885ae580cSIan Dowse * 60 seconds.
4398fae3551SRodney W. Grimes */
4408fae3551SRodney W. Grimes sleep(2);
44185ae580cSIan Dowse for (i = 0; i < 20; i++) {
44285ae580cSIan Dowse pageins = get_pageins();
4438fae3551SRodney W. Grimes if (!nflag)
4448fae3551SRodney W. Grimes sync();
4458fae3551SRodney W. Grimes sleep(3);
44685ae580cSIan Dowse if (get_pageins() == pageins)
44785ae580cSIan Dowse break;
44885ae580cSIan Dowse }
4498fae3551SRodney W. Grimes
4508fae3551SRodney W. Grimes for (i = 1;; ++i) {
4517b0a665dSMitchell Horne BOOTTRACE("SIGKILL to all other processes(%d)...", i);
4528fae3551SRodney W. Grimes if (kill(-1, SIGKILL) == -1) {
4538fae3551SRodney W. Grimes if (errno == ESRCH)
4548fae3551SRodney W. Grimes break;
4558fae3551SRodney W. Grimes goto restart;
4568fae3551SRodney W. Grimes }
4578fae3551SRodney W. Grimes if (i > 5) {
4588fae3551SRodney W. Grimes (void)fprintf(stderr,
4598fae3551SRodney W. Grimes "WARNING: some process(es) wouldn't die\n");
4608fae3551SRodney W. Grimes break;
4618fae3551SRodney W. Grimes }
4628fae3551SRodney W. Grimes (void)sleep(2 * i);
4638fae3551SRodney W. Grimes }
4648fae3551SRodney W. Grimes
4658fae3551SRodney W. Grimes reboot(howto);
4668fae3551SRodney W. Grimes /* FALLTHROUGH */
4678fae3551SRodney W. Grimes
4688fae3551SRodney W. Grimes restart:
4697b0a665dSMitchell Horne BOOTTRACE("SIGHUP to init(8)...");
4708fae3551SRodney W. Grimes sverrno = errno;
471098166edSPhilippe Charnier errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
4728fae3551SRodney W. Grimes strerror(sverrno));
4738fae3551SRodney W. Grimes /* NOTREACHED */
4748fae3551SRodney W. Grimes }
4758fae3551SRodney W. Grimes
47636737a0bSXin LI static void
usage(void)477c574558fSDag-Erling Smørgrav usage(void)
4788fae3551SRodney W. Grimes {
479c574558fSDag-Erling Smørgrav
480c574558fSDag-Erling Smørgrav (void)fprintf(stderr, dohalt ?
48125fd0815SWarner Losh "usage: halt [-clNnpq] [-k kernel]\n" :
48225fd0815SWarner Losh "usage: reboot [-cdlNnpqr] [-k kernel]\n");
4838fae3551SRodney W. Grimes exit(1);
4848fae3551SRodney W. Grimes }
48585ae580cSIan Dowse
486194cc45aSKonstantin Belousov static uint64_t
get_pageins(void)48788a8f792SEd Schouten get_pageins(void)
48885ae580cSIan Dowse {
489194cc45aSKonstantin Belousov uint64_t pageins;
49085ae580cSIan Dowse size_t len;
49185ae580cSIan Dowse
49285ae580cSIan Dowse len = sizeof(pageins);
49385ae580cSIan Dowse if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
49485ae580cSIan Dowse != 0) {
495a294b02fSKonstantin Belousov warn("v_swappgsin");
49685ae580cSIan Dowse return (0);
49785ae580cSIan Dowse }
498194cc45aSKonstantin Belousov return (pageins);
49985ae580cSIan Dowse }
500