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 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 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 * 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 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 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 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 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