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