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 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 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 * 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 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 234 shutdown(int howto) 235 { 236 char sigstr[SIG2STR_MAX]; 237 int signo = 238 howto & RB_POWERCYCLE ? SIGWINCH : 239 howto & RB_POWEROFF ? SIGUSR2 : 240 howto & RB_HALT ? SIGUSR1 : 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 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 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 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