xref: /freebsd/sbin/reboot/reboot.c (revision 94c1c907f8c78d8c8ad34b6a7d374384f8fb71b6)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1986, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/boottrace.h>
33 #include <sys/mount.h>
34 #include <sys/reboot.h>
35 #include <sys/stat.h>
36 #include <sys/sysctl.h>
37 #include <sys/time.h>
38 #include <sys/wait.h>
39 
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <paths.h>
44 #include <pwd.h>
45 #include <signal.h>
46 #include <spawn.h>
47 #include <stdbool.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <unistd.h>
53 #include <utmpx.h>
54 
55 extern char **environ;
56 
57 #define PATH_NEXTBOOT "/boot/nextboot.conf"
58 
59 static void usage(void) __dead2;
60 static uint64_t get_pageins(void);
61 
62 static bool dohalt;
63 static bool donextboot;
64 
65 #define E(...) do {				\
66 		if (force) {			\
67 			warn( __VA_ARGS__ );	\
68 			return;			\
69 		}				\
70 		err(1, __VA_ARGS__);		\
71 	} while (0)				\
72 
73 static void
zfsbootcfg(const char * pool,bool force)74 zfsbootcfg(const char *pool, bool force)
75 {
76 	const char * const av[] = {
77 		"zfsbootcfg",
78 		"-z",
79 		pool,
80 		"-n",
81 		"freebsd:nvstore",
82 		"-k",
83 		"nextboot_enable",
84 		"-v",
85 		"YES",
86 		NULL
87 	};
88 	int rv, status;
89 	pid_t p;
90 
91 	rv = posix_spawnp(&p, av[0], NULL, NULL, __DECONST(char **, av),
92 	    environ);
93 	if (rv == -1)
94 		E("system zfsbootcfg");
95 	if (waitpid(p, &status, WEXITED) < 0) {
96 		if (errno == EINTR)
97 			return;
98 		E("waitpid zfsbootcfg");
99 	}
100 	if (WIFEXITED(status)) {
101 		int e = WEXITSTATUS(status);
102 
103 		if (e == 0)
104 			return;
105 		if (e == 127)
106 			E("zfsbootcfg not found in path");
107 		E("zfsbootcfg returned %d", e);
108 	}
109 	if (WIFSIGNALED(status))
110 		E("zfsbootcfg died with signal %d", WTERMSIG(status));
111 	E("zfsbootcfg unexpected status %d", status);
112 }
113 
114 static void
write_nextboot(const char * fn,const char * env,bool force)115 write_nextboot(const char *fn, const char *env, bool force)
116 {
117 	char tmp[PATH_MAX];
118 	FILE *fp;
119 	struct statfs sfs;
120 	int tmpfd;
121 	bool supported = false;
122 	bool zfs = false;
123 
124 	if (statfs("/boot", &sfs) != 0)
125 		err(1, "statfs /boot");
126 	if (strcmp(sfs.f_fstypename, "ufs") == 0) {
127 		/*
128 		 * Only UFS supports the full nextboot protocol.
129 		 */
130 		supported = true;
131 	} else if (strcmp(sfs.f_fstypename, "zfs") == 0) {
132 		zfs = true;
133 	}
134 
135 	if (zfs) {
136 		char *slash;
137 
138 		slash = strchr(sfs.f_mntfromname, '/');
139 		if (slash != NULL)
140 			*slash = '\0';
141 		zfsbootcfg(sfs.f_mntfromname, force);
142 	}
143 
144 	if (strlcpy(tmp, fn, sizeof(tmp)) >= sizeof(tmp))
145 		E("Path too long %s", fn);
146 	if (strlcat(tmp, ".XXXXXX", sizeof(tmp)) >= sizeof(tmp))
147 		E("Path too long %s", fn);
148 	tmpfd = mkstemp(tmp);
149 	if (tmpfd == -1)
150 		E("mkstemp %s", tmp);
151 
152 	fp = fdopen(tmpfd, "w");
153 	if (fp == NULL)
154 		E("fdopen %s", tmp);
155 
156 	if (fprintf(fp, "%s%s",
157 	    supported ? "nextboot_enable=\"YES\"\n" : "",
158 	    env != NULL ? env : "") < 0) {
159 		int e;
160 
161 		e = errno;
162 		if (unlink(tmp))
163 			warn("unlink %s", tmp);
164 		errno = e;
165 		E("Can't write %s", tmp);
166 	}
167 	if (fsync(fileno(fp)) != 0)
168 		E("Can't fsync %s", fn);
169 	if (rename(tmp, fn) != 0) {
170 		int e;
171 
172 		e = errno;
173 		if (unlink(tmp))
174 			warn("unlink %s", tmp);
175 		errno = e;
176 		E("Can't rename %s to %s", tmp, fn);
177 	}
178 	fclose(fp);
179 }
180 
181 static char *
split_kv(char * raw)182 split_kv(char *raw)
183 {
184 	char *eq;
185 	int len;
186 
187 	eq = strchr(raw, '=');
188 	if (eq == NULL)
189 		errx(1, "No = in environment string %s", raw);
190 	*eq++ = '\0';
191 	len = strlen(eq);
192 	if (len == 0)
193 		errx(1, "Invalid null value %s=", raw);
194 	if (eq[0] == '"') {
195 		if (len < 2 || eq[len - 1] != '"')
196 			errx(1, "Invalid string '%s'", eq);
197 		eq[len - 1] = '\0';
198 		return (eq + 1);
199 	}
200 	return (eq);
201 }
202 
203 static void
add_env(char ** env,const char * key,const char * value)204 add_env(char **env, const char *key, const char *value)
205 {
206 	char *oldenv;
207 
208 	oldenv = *env;
209 	asprintf(env, "%s%s=\"%s\"\n", oldenv != NULL ? oldenv : "", key, value);
210 	if (env == NULL)
211 		errx(1, "No memory to build env array");
212 	free(oldenv);
213 }
214 
215 /*
216  * Different options are valid for different programs.
217  */
218 #define GETOPT_REBOOT "cDde:fk:lNno:pqr"
219 #define GETOPT_NEXTBOOT "De:fk:o:"
220 
221 int
main(int argc,char * argv[])222 main(int argc, char *argv[])
223 {
224 	struct utmpx utx;
225 	const struct passwd *pw;
226 	struct stat st;
227 	int ch, howto = 0, i, sverrno;
228 	bool Dflag, fflag, lflag, Nflag, nflag, qflag;
229 	uint64_t pageins;
230 	const char *user, *kernel = NULL, *getopts = GETOPT_REBOOT;
231 	char *env = NULL, *v;
232 
233 	if (strstr(getprogname(), "halt") != NULL) {
234 		dohalt = true;
235 		howto = RB_HALT;
236 	} else if (strcmp(getprogname(), "nextboot") == 0) {
237 		donextboot = true;
238 		getopts = GETOPT_NEXTBOOT; /* Note: reboot's extra opts return '?' */
239 	} else {
240 		/* reboot */
241 		howto = 0;
242 	}
243 	Dflag = fflag = lflag = Nflag = nflag = qflag = false;
244 	while ((ch = getopt(argc, argv, getopts)) != -1) {
245 		switch(ch) {
246 		case 'c':
247 			howto |= RB_POWERCYCLE;
248 			break;
249 		case 'D':
250 			Dflag = true;
251 			break;
252 		case 'd':
253 			howto |= RB_DUMP;
254 			break;
255 		case 'e':
256 			v = split_kv(optarg);
257 			add_env(&env, optarg, v);
258 			break;
259 		case 'f':
260 			fflag = true;
261 			break;
262 		case 'k':
263 			kernel = optarg;
264 			break;
265 		case 'l':
266 			lflag = true;
267 			break;
268 		case 'n':
269 			nflag = true;
270 			howto |= RB_NOSYNC;
271 			break;
272 		case 'N':
273 			nflag = true;
274 			Nflag = true;
275 			break;
276 		case 'o':
277 			add_env(&env, "kernel_options", optarg);
278 			break;
279 		case 'p':
280 			howto |= RB_POWEROFF;
281 			break;
282 		case 'q':
283 			qflag = true;
284 			break;
285 		case 'r':
286 			howto |= RB_REROOT;
287 			break;
288 		case '?':
289 		default:
290 			usage();
291 		}
292 	}
293 
294 	argc -= optind;
295 	argv += optind;
296 	if (argc != 0)
297 		usage();
298 
299 	if (!donextboot && !fflag && stat(_PATH_NOSHUTDOWN, &st) == 0) {
300 		errx(1, "Reboot cannot be done, " _PATH_NOSHUTDOWN
301 		    " is present");
302 	}
303 
304 	if (Dflag && ((howto & ~RB_HALT) != 0  || kernel != NULL))
305 		errx(1, "cannot delete existing nextboot config and do anything else");
306 	if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
307 		errx(1, "cannot dump (-d) when halting; must reboot instead");
308 	if (Nflag && (howto & RB_NOSYNC) != 0)
309 		errx(1, "-N cannot be used with -n");
310 	if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE))
311 		errx(1, "-c and -p cannot be used together");
312 	if ((howto & RB_REROOT) != 0 && howto != RB_REROOT)
313 		errx(1, "-r cannot be used with -c, -d, -n, or -p");
314 	if ((howto & RB_REROOT) != 0 && kernel != NULL)
315 		errx(1, "-r and -k cannot be used together, there is no next kernel");
316 
317 	if (Dflag) {
318 		struct stat sb;
319 
320 		/*
321 		 * Break the rule about stat then doing
322 		 * something. When we're booting, there's no
323 		 * race. When we're a read-only root, though, the
324 		 * read-only error takes priority over the file not
325 		 * there error in unlink. So stat it first and exit
326 		 * with success if it isn't there. Otherwise, let
327 		 * unlink sort error reporting. POSIX-1.2024 suggests
328 		 * ENOENT should be preferred to EROFS for unlink,
329 		 * but FreeBSD historically has preferred EROFS.
330 		 */
331 		if (stat(PATH_NEXTBOOT, &sb) != 0 && errno == ENOENT)
332 			exit(0);
333 		if (unlink(PATH_NEXTBOOT) != 0)
334 			warn("unlink " PATH_NEXTBOOT);
335 		exit(0);
336 	}
337 
338 	if (!donextboot && geteuid() != 0) {
339 		errno = EPERM;
340 		err(1, NULL);
341 	}
342 
343 	if (qflag) {
344 		reboot(howto);
345 		err(1, NULL);
346 	}
347 
348 	if (kernel != NULL) {
349 		if (!fflag) {
350 			char *k;
351 			struct stat sb;
352 
353 			asprintf(&k, "/boot/%s/kernel", kernel);
354 			if (k == NULL)
355 				errx(1, "No memory to check %s", kernel);
356 			if (stat(k, &sb) != 0)
357 				err(1, "stat %s", k);
358 			if (!S_ISREG(sb.st_mode))
359 				errx(1, "%s is not a file", k);
360 			free(k);
361 		}
362 		add_env(&env, "kernel", kernel);
363 	}
364 
365 	if (env != NULL)
366 		write_nextboot(PATH_NEXTBOOT, env, fflag);
367 	if (donextboot)
368 		exit (0);
369 
370 	/* Log the reboot. */
371 	if (!lflag)  {
372 		if ((user = getlogin()) == NULL)
373 			user = (pw = getpwuid(getuid())) ?
374 			    pw->pw_name : "???";
375 		if (dohalt) {
376 			openlog("halt", 0, LOG_AUTH | LOG_CONS);
377 			syslog(LOG_CRIT, "halted by %s", user);
378 		} else if (howto & RB_REROOT) {
379 			openlog("reroot", 0, LOG_AUTH | LOG_CONS);
380 			syslog(LOG_CRIT, "rerooted by %s", user);
381 		} else if (howto & RB_POWEROFF) {
382 			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
383 			syslog(LOG_CRIT, "powered off by %s", user);
384 		} else if (howto & RB_POWERCYCLE) {
385 			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
386 			syslog(LOG_CRIT, "power cycled by %s", user);
387 		} else {
388 			openlog("reboot", 0, LOG_AUTH | LOG_CONS);
389 			syslog(LOG_CRIT, "rebooted by %s", user);
390 		}
391 	}
392 	utx.ut_type = SHUTDOWN_TIME;
393 	gettimeofday(&utx.ut_tv, NULL);
394 	pututxline(&utx);
395 
396 	/*
397 	 * Do a sync early on, so disks start transfers while we're off
398 	 * killing processes.  Don't worry about writes done before the
399 	 * processes die, the reboot system call syncs the disks.
400 	 */
401 	if (!nflag)
402 		sync();
403 
404 	/*
405 	 * Ignore signals that we can get as a result of killing
406 	 * parents, group leaders, etc.
407 	 */
408 	(void)signal(SIGHUP,  SIG_IGN);
409 	(void)signal(SIGINT,  SIG_IGN);
410 	(void)signal(SIGQUIT, SIG_IGN);
411 	(void)signal(SIGTERM, SIG_IGN);
412 	(void)signal(SIGTSTP, SIG_IGN);
413 
414 	/*
415 	 * If we're running in a pipeline, we don't want to die
416 	 * after killing whatever we're writing to.
417 	 */
418 	(void)signal(SIGPIPE, SIG_IGN);
419 
420 	/*
421 	 * Only init(8) can perform rerooting.
422 	 */
423 	if (howto & RB_REROOT) {
424 		if (kill(1, SIGEMT) == -1)
425 			err(1, "SIGEMT init");
426 
427 		return (0);
428 	}
429 
430 	/* Just stop init -- if we fail, we'll restart it. */
431 	BOOTTRACE("SIGTSTP to init(8)...");
432 	if (kill(1, SIGTSTP) == -1)
433 		err(1, "SIGTSTP init");
434 
435 	/* Send a SIGTERM first, a chance to save the buffers. */
436 	BOOTTRACE("SIGTERM to all other processes...");
437 	if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
438 		err(1, "SIGTERM processes");
439 
440 	/*
441 	 * After the processes receive the signal, start the rest of the
442 	 * buffers on their way.  Wait 5 seconds between the SIGTERM and
443 	 * the SIGKILL to give everybody a chance. If there is a lot of
444 	 * paging activity then wait longer, up to a maximum of approx
445 	 * 60 seconds.
446 	 */
447 	sleep(2);
448 	for (i = 0; i < 20; i++) {
449 		pageins = get_pageins();
450 		if (!nflag)
451 			sync();
452 		sleep(3);
453 		if (get_pageins() == pageins)
454 			break;
455 	}
456 
457 	for (i = 1;; ++i) {
458 		BOOTTRACE("SIGKILL to all other processes(%d)...", i);
459 		if (kill(-1, SIGKILL) == -1) {
460 			if (errno == ESRCH)
461 				break;
462 			goto restart;
463 		}
464 		if (i > 5) {
465 			(void)fprintf(stderr,
466 			    "WARNING: some process(es) wouldn't die\n");
467 			break;
468 		}
469 		(void)sleep(2 * i);
470 	}
471 
472 	reboot(howto);
473 	/* FALLTHROUGH */
474 
475 restart:
476 	BOOTTRACE("SIGHUP to init(8)...");
477 	sverrno = errno;
478 	errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
479 	    strerror(sverrno));
480 	/* NOTREACHED */
481 }
482 
483 static void
usage(void)484 usage(void)
485 {
486 
487 	(void)fprintf(stderr, dohalt ?
488 	    "usage: halt [-clNnpq] [-k kernel]\n" :
489 	    "usage: reboot [-cdlNnpqr] [-k kernel]\n");
490 	exit(1);
491 }
492 
493 static uint64_t
get_pageins(void)494 get_pageins(void)
495 {
496 	uint64_t pageins;
497 	size_t len;
498 
499 	len = sizeof(pageins);
500 	if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
501 	    != 0) {
502 		warn("v_swappgsin");
503 		return (0);
504 	}
505 	return (pageins);
506 }
507