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