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