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 dofast;
63 static bool dohalt;
64 static bool donextboot;
65
66 #define E(...) do { \
67 if (force) { \
68 warn( __VA_ARGS__ ); \
69 return; \
70 } \
71 err(1, __VA_ARGS__); \
72 } while (0) \
73
74 static void
zfsbootcfg(const char * pool,bool force)75 zfsbootcfg(const char *pool, bool force)
76 {
77 const char * const av[] = {
78 "zfsbootcfg",
79 "-z",
80 pool,
81 "-n",
82 "freebsd:nvstore",
83 "-k",
84 "nextboot_enable",
85 "-v",
86 "YES",
87 NULL
88 };
89 int rv, status;
90 pid_t p;
91
92 rv = posix_spawnp(&p, av[0], NULL, NULL, __DECONST(char **, av),
93 environ);
94 if (rv == -1)
95 E("system zfsbootcfg");
96 if (waitpid(p, &status, WEXITED) < 0) {
97 if (errno == EINTR)
98 return;
99 E("waitpid zfsbootcfg");
100 }
101 if (WIFEXITED(status)) {
102 int e = WEXITSTATUS(status);
103
104 if (e == 0)
105 return;
106 if (e == 127)
107 E("zfsbootcfg not found in path");
108 E("zfsbootcfg returned %d", e);
109 }
110 if (WIFSIGNALED(status))
111 E("zfsbootcfg died with signal %d", WTERMSIG(status));
112 E("zfsbootcfg unexpected status %d", status);
113 }
114
115 static void
write_nextboot(const char * fn,const char * env,bool append,bool force)116 write_nextboot(const char *fn, const char *env, bool append, bool force)
117 {
118 char tmp[PATH_MAX];
119 FILE *fp;
120 struct statfs sfs;
121 ssize_t ret;
122 int fd, tmpfd;
123 bool supported = false;
124 bool zfs = false;
125
126 if (statfs("/boot", &sfs) != 0)
127 err(1, "statfs /boot");
128 if (strcmp(sfs.f_fstypename, "ufs") == 0) {
129 /*
130 * Only UFS supports the full nextboot protocol.
131 */
132 supported = true;
133 } else if (strcmp(sfs.f_fstypename, "zfs") == 0) {
134 zfs = true;
135 }
136
137 if (zfs) {
138 char *slash;
139
140 slash = strchr(sfs.f_mntfromname, '/');
141 if (slash != NULL)
142 *slash = '\0';
143 zfsbootcfg(sfs.f_mntfromname, force);
144 }
145
146 if (strlcpy(tmp, fn, sizeof(tmp)) >= sizeof(tmp))
147 E("Path too long %s", fn);
148 if (strlcat(tmp, ".XXXXXX", sizeof(tmp)) >= sizeof(tmp))
149 E("Path too long %s", fn);
150
151 tmpfd = mkstemp(tmp);
152 if (tmpfd == -1)
153 E("mkstemp %s", tmp);
154
155 fp = fdopen(tmpfd, "w");
156 if (fp == NULL)
157 E("fdopen %s", tmp);
158
159 if (append) {
160 if ((fd = open(fn, O_RDONLY)) < 0) {
161 if (errno != ENOENT)
162 E("open %s", fn);
163 } else {
164 do {
165 ret = copy_file_range(fd, NULL, tmpfd, NULL,
166 SSIZE_MAX, 0);
167 if (ret < 0)
168 E("copy %s to %s", fn, tmp);
169 } while (ret > 0);
170 close(fd);
171 }
172 }
173
174 if (fprintf(fp, "%s%s",
175 supported ? "nextboot_enable=\"YES\"\n" : "",
176 env != NULL ? env : "") < 0) {
177 int e;
178
179 e = errno;
180 if (unlink(tmp))
181 warn("unlink %s", tmp);
182 errno = e;
183 E("Can't write %s", tmp);
184 }
185 if (fsync(fileno(fp)) != 0)
186 E("Can't fsync %s", fn);
187 if (rename(tmp, fn) != 0) {
188 int e;
189
190 e = errno;
191 if (unlink(tmp))
192 warn("unlink %s", tmp);
193 errno = e;
194 E("Can't rename %s to %s", tmp, fn);
195 }
196 fclose(fp);
197 }
198
199 static char *
split_kv(char * raw)200 split_kv(char *raw)
201 {
202 char *eq;
203 int len;
204
205 eq = strchr(raw, '=');
206 if (eq == NULL)
207 errx(1, "No = in environment string %s", raw);
208 *eq++ = '\0';
209 len = strlen(eq);
210 if (len == 0)
211 errx(1, "Invalid null value %s=", raw);
212 if (eq[0] == '"') {
213 if (len < 2 || eq[len - 1] != '"')
214 errx(1, "Invalid string '%s'", eq);
215 eq[len - 1] = '\0';
216 return (eq + 1);
217 }
218 return (eq);
219 }
220
221 static void
add_env(char ** env,const char * key,const char * value)222 add_env(char **env, const char *key, const char *value)
223 {
224 char *oldenv;
225
226 oldenv = *env;
227 asprintf(env, "%s%s=\"%s\"\n", oldenv != NULL ? oldenv : "", key, value);
228 if (env == NULL)
229 errx(1, "No memory to build env array");
230 free(oldenv);
231 }
232
233 static void
shutdown(int howto)234 shutdown(int howto)
235 {
236 char sigstr[SIG2STR_MAX];
237 int signo =
238 howto & RB_HALT ? SIGUSR1 :
239 howto & RB_POWEROFF ? SIGUSR2 :
240 howto & RB_POWERCYCLE ? SIGWINCH :
241 howto & RB_REROOT ? SIGEMT :
242 SIGINT;
243
244 (void)sig2str(signo, sigstr);
245 BOOTTRACE("SIG%s to init(8)...", sigstr);
246 if (kill(1, signo) == -1)
247 err(1, "SIG%s init", sigstr);
248 exit(0);
249 }
250
251 /*
252 * Different options are valid for different programs.
253 */
254 #define GETOPT_REBOOT "cDde:fk:lNno:pqr"
255 #define GETOPT_NEXTBOOT "aDe:fk:o:"
256
257 int
main(int argc,char * argv[])258 main(int argc, char *argv[])
259 {
260 struct utmpx utx;
261 struct stat st;
262 const struct passwd *pw;
263 const char *progname, *user;
264 const char *kernel = NULL, *getopts = GETOPT_REBOOT;
265 char *env = NULL, *v;
266 uint64_t pageins;
267 int ch, howto = 0, i, sverrno;
268 bool aflag, Dflag, fflag, lflag, Nflag, nflag, qflag;
269
270 progname = getprogname();
271 if (strncmp(progname, "fast", 4) == 0) {
272 dofast = true;
273 progname += 4;
274 }
275 if (strcmp(progname, "halt") == 0) {
276 dohalt = true;
277 howto = RB_HALT;
278 } else if (strcmp(progname, "nextboot") == 0) {
279 donextboot = true;
280 getopts = GETOPT_NEXTBOOT; /* Note: reboot's extra opts return '?' */
281 } else {
282 /* reboot */
283 howto = 0;
284 }
285 aflag = Dflag = fflag = lflag = Nflag = nflag = qflag = false;
286 while ((ch = getopt(argc, argv, getopts)) != -1) {
287 switch(ch) {
288 case 'a':
289 aflag = true;
290 break;
291 case 'c':
292 howto |= RB_POWERCYCLE;
293 break;
294 case 'D':
295 Dflag = true;
296 break;
297 case 'd':
298 howto |= RB_DUMP;
299 break;
300 case 'e':
301 v = split_kv(optarg);
302 add_env(&env, optarg, v);
303 break;
304 case 'f':
305 fflag = true;
306 break;
307 case 'k':
308 kernel = optarg;
309 break;
310 case 'l':
311 lflag = true;
312 break;
313 case 'n':
314 nflag = true;
315 howto |= RB_NOSYNC;
316 break;
317 case 'N':
318 nflag = true;
319 Nflag = true;
320 break;
321 case 'o':
322 add_env(&env, "kernel_options", optarg);
323 break;
324 case 'p':
325 howto |= RB_POWEROFF;
326 break;
327 case 'q':
328 qflag = true;
329 break;
330 case 'r':
331 howto |= RB_REROOT;
332 break;
333 case '?':
334 default:
335 usage();
336 }
337 }
338
339 argc -= optind;
340 argv += optind;
341 if (argc != 0)
342 usage();
343
344 if (!donextboot && !fflag && stat(_PATH_NOSHUTDOWN, &st) == 0) {
345 errx(1, "Reboot cannot be done, " _PATH_NOSHUTDOWN
346 " is present");
347 }
348
349 if (Dflag && ((howto & ~RB_HALT) != 0 || kernel != NULL))
350 errx(1, "cannot delete existing nextboot config and do anything else");
351 if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
352 errx(1, "cannot dump (-d) when halting; must reboot instead");
353 if (Nflag && (howto & RB_NOSYNC) != 0)
354 errx(1, "-N cannot be used with -n");
355 if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE))
356 errx(1, "-c and -p cannot be used together");
357 if ((howto & RB_REROOT) != 0 && howto != RB_REROOT)
358 errx(1, "-r cannot be used with -c, -d, -n, or -p");
359 if ((howto & RB_REROOT) != 0 && dofast)
360 errx(1, "-r cannot be performed in fast mode");
361 if ((howto & RB_REROOT) != 0 && kernel != NULL)
362 errx(1, "-r and -k cannot be used together, there is no next kernel");
363
364 if (Dflag) {
365 struct stat sb;
366
367 /*
368 * Break the rule about stat then doing
369 * something. When we're booting, there's no
370 * race. When we're a read-only root, though, the
371 * read-only error takes priority over the file not
372 * there error in unlink. So stat it first and exit
373 * with success if it isn't there. Otherwise, let
374 * unlink sort error reporting. POSIX-1.2024 suggests
375 * ENOENT should be preferred to EROFS for unlink,
376 * but FreeBSD historically has preferred EROFS.
377 */
378 if (stat(PATH_NEXTBOOT, &sb) != 0 && errno == ENOENT)
379 exit(0);
380 if (unlink(PATH_NEXTBOOT) != 0)
381 warn("unlink " PATH_NEXTBOOT);
382 exit(0);
383 }
384
385 if (!donextboot && geteuid() != 0) {
386 errno = EPERM;
387 err(1, NULL);
388 }
389
390 if (qflag) {
391 reboot(howto);
392 err(1, NULL);
393 }
394
395 if (kernel != NULL) {
396 if (!fflag) {
397 char *k;
398 struct stat sb;
399
400 asprintf(&k, "/boot/%s/kernel", kernel);
401 if (k == NULL)
402 errx(1, "No memory to check %s", kernel);
403 if (stat(k, &sb) != 0)
404 err(1, "stat %s", k);
405 if (!S_ISREG(sb.st_mode))
406 errx(1, "%s is not a file", k);
407 free(k);
408 }
409 add_env(&env, "kernel", kernel);
410 }
411
412 if (env != NULL)
413 write_nextboot(PATH_NEXTBOOT, env, aflag, fflag);
414 if (donextboot)
415 exit (0);
416
417 /* Log the reboot. */
418 if (!lflag) {
419 if ((user = getlogin()) == NULL)
420 user = (pw = getpwuid(getuid())) ?
421 pw->pw_name : "???";
422 if (dohalt) {
423 openlog("halt", 0, LOG_AUTH | LOG_CONS);
424 syslog(LOG_CRIT, "halted by %s", user);
425 } else if (howto & RB_REROOT) {
426 openlog("reroot", 0, LOG_AUTH | LOG_CONS);
427 syslog(LOG_CRIT, "rerooted by %s", user);
428 } else if (howto & RB_POWEROFF) {
429 openlog("reboot", 0, LOG_AUTH | LOG_CONS);
430 syslog(LOG_CRIT, "powered off by %s", user);
431 } else if (howto & RB_POWERCYCLE) {
432 openlog("reboot", 0, LOG_AUTH | LOG_CONS);
433 syslog(LOG_CRIT, "power cycled by %s", user);
434 } else {
435 openlog("reboot", 0, LOG_AUTH | LOG_CONS);
436 syslog(LOG_CRIT, "rebooted by %s", user);
437 }
438 }
439 utx.ut_type = SHUTDOWN_TIME;
440 gettimeofday(&utx.ut_tv, NULL);
441 pututxline(&utx);
442
443 /*
444 * Do a sync early on, so disks start transfers while we're off
445 * killing processes. Don't worry about writes done before the
446 * processes die, the reboot system call syncs the disks.
447 */
448 if (!nflag)
449 sync();
450
451 /*
452 * Ignore signals that we can get as a result of killing
453 * parents, group leaders, etc.
454 */
455 (void)signal(SIGHUP, SIG_IGN);
456 (void)signal(SIGINT, SIG_IGN);
457 (void)signal(SIGQUIT, SIG_IGN);
458 (void)signal(SIGTERM, SIG_IGN);
459 (void)signal(SIGTSTP, SIG_IGN);
460
461 /*
462 * If we're running in a pipeline, we don't want to die
463 * after killing whatever we're writing to.
464 */
465 (void)signal(SIGPIPE, SIG_IGN);
466
467 /*
468 * Common case: clean shutdown.
469 */
470 if (!dofast)
471 shutdown(howto);
472
473 /* Just stop init -- if we fail, we'll restart it. */
474 BOOTTRACE("SIGTSTP to init(8)...");
475 if (kill(1, SIGTSTP) == -1)
476 err(1, "SIGTSTP init");
477
478 /* Send a SIGTERM first, a chance to save the buffers. */
479 BOOTTRACE("SIGTERM to all other processes...");
480 if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
481 err(1, "SIGTERM processes");
482
483 /*
484 * After the processes receive the signal, start the rest of the
485 * buffers on their way. Wait 5 seconds between the SIGTERM and
486 * the SIGKILL to give everybody a chance. If there is a lot of
487 * paging activity then wait longer, up to a maximum of approx
488 * 60 seconds.
489 */
490 sleep(2);
491 for (i = 0; i < 20; i++) {
492 pageins = get_pageins();
493 if (!nflag)
494 sync();
495 sleep(3);
496 if (get_pageins() == pageins)
497 break;
498 }
499
500 for (i = 1;; ++i) {
501 BOOTTRACE("SIGKILL to all other processes(%d)...", i);
502 if (kill(-1, SIGKILL) == -1) {
503 if (errno == ESRCH)
504 break;
505 goto restart;
506 }
507 if (i > 5) {
508 (void)fprintf(stderr,
509 "WARNING: some process(es) wouldn't die\n");
510 break;
511 }
512 (void)sleep(2 * i);
513 }
514
515 reboot(howto);
516 /* FALLTHROUGH */
517
518 restart:
519 BOOTTRACE("SIGHUP to init(8)...");
520 sverrno = errno;
521 errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
522 strerror(sverrno));
523 /* NOTREACHED */
524 }
525
526 static void
usage(void)527 usage(void)
528 {
529 if (donextboot) {
530 fprintf(stderr, "usage: nextboot [-aDf] "
531 "[-e name=value] [-k kernel] [-o options]\n");
532 } else {
533 fprintf(stderr, "usage: %s%s [-%sflNnpq%s] "
534 "[-e name=value] [-k kernel] [-o options]\n",
535 dofast ? "fast" : "",
536 dohalt ? "halt" : dofast ? "boot" : "reboot",
537 dohalt ? "D" : "cDd",
538 dohalt || dofast ? "" : "r");
539 }
540 exit(1);
541 }
542
543 static uint64_t
get_pageins(void)544 get_pageins(void)
545 {
546 uint64_t pageins;
547 size_t len;
548
549 len = sizeof(pageins);
550 if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
551 != 0) {
552 warn("v_swappgsin");
553 return (0);
554 }
555 return (pageins);
556 }
557