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