xref: /freebsd/sbin/reboot/reboot.c (revision bec5a3c046ba2bd970679a31f7227f260bef4935)
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