1 1.59 martin /* $NetBSD: shutdown.c,v 1.59 2024/12/07 14:08:54 martin Exp $ */ 2 1.9 cgd 3 1.1 cgd /* 4 1.7 mycroft * Copyright (c) 1988, 1990, 1993 5 1.7 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.40 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.14 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.51 lukem __COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\ 35 1.51 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.9 cgd #if 0 40 1.15 lukem static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95"; 41 1.9 cgd #else 42 1.59 martin __RCSID("$NetBSD: shutdown.c,v 1.59 2024/12/07 14:08:54 martin Exp $"); 43 1.9 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd #include <sys/param.h> 47 1.1 cgd #include <sys/time.h> 48 1.1 cgd #include <sys/resource.h> 49 1.1 cgd #include <sys/syslog.h> 50 1.7 mycroft 51 1.7 mycroft #include <ctype.h> 52 1.19 mycroft #include <err.h> 53 1.7 mycroft #include <fcntl.h> 54 1.7 mycroft #include <pwd.h> 55 1.1 cgd #include <setjmp.h> 56 1.7 mycroft #include <signal.h> 57 1.7 mycroft #include <stdio.h> 58 1.7 mycroft #include <stdlib.h> 59 1.7 mycroft #include <string.h> 60 1.26 kleink #include <time.h> 61 1.1 cgd #include <tzfile.h> 62 1.7 mycroft #include <unistd.h> 63 1.47 christos #include <errno.h> 64 1.7 mycroft 65 1.1 cgd #include "pathnames.h" 66 1.1 cgd 67 1.1 cgd #ifdef DEBUG 68 1.1 cgd #undef _PATH_NOLOGIN 69 1.1 cgd #define _PATH_NOLOGIN "./nologin" 70 1.1 cgd #undef _PATH_FASTBOOT 71 1.1 cgd #define _PATH_FASTBOOT "./fastboot" 72 1.1 cgd #endif 73 1.1 cgd 74 1.1 cgd #define H *60*60 75 1.1 cgd #define M *60 76 1.1 cgd #define S *1 77 1.1 cgd #define NOLOG_TIME 5*60 78 1.47 christos static const struct interval { 79 1.47 christos time_t timeleft, timetowait; 80 1.1 cgd } tlist[] = { 81 1.13 mikel { 10 H, 5 H }, { 5 H, 3 H }, { 2 H, 1 H }, { 1 H, 30 M }, 82 1.13 mikel { 30 M, 10 M }, { 20 M, 10 M }, { 10 M, 5 M }, { 5 M, 3 M }, 83 1.13 mikel { 2 M, 1 M }, { 1 M, 30 S }, { 30 S, 30 S }, 84 1.13 mikel { 0, 0 } 85 1.7 mycroft }; 86 1.1 cgd #undef H 87 1.1 cgd #undef M 88 1.1 cgd #undef S 89 1.1 cgd 90 1.1 cgd static time_t offset, shuttime; 91 1.47 christos static int dofast, dohalt, doreboot, killflg, nofork, nosync, dodump; 92 1.47 christos static size_t mbuflen; 93 1.27 thorpej static int dopowerdown; 94 1.53 dyoung static int dodebug, dosilent, doverbose; 95 1.29 mycroft static const char *whom; 96 1.29 mycroft static char mbuf[BUFSIZ]; 97 1.47 christos static char *bootstr; 98 1.1 cgd 99 1.49 perry static void badtime(void) __dead; 100 1.49 perry static void die_you_gravy_sucking_pig_dog(void) __dead; 101 1.47 christos static void doitfast(void); 102 1.59 martin static void dorcshutdown(const char *what); 103 1.49 perry static void finish(int) __dead; 104 1.47 christos static void getoffset(char *); 105 1.55 joerg static void loop(void) __dead; 106 1.47 christos static void nolog(void); 107 1.55 joerg static void timeout(int) __dead; 108 1.47 christos static void timewarn(time_t); 109 1.49 perry static void usage(void) __dead; 110 1.5 cgd 111 1.7 mycroft int 112 1.43 xtraeme main(int argc, char *argv[]) 113 1.1 cgd { 114 1.14 lukem char *p, *endp; 115 1.7 mycroft struct passwd *pw; 116 1.47 christos size_t arglen, len; 117 1.47 christos int ch; 118 1.1 cgd 119 1.47 christos (void)setprogname(argv[0]); 120 1.1 cgd #ifndef DEBUG 121 1.19 mycroft if (geteuid()) 122 1.50 dholland errx(1, "%s: Not super-user", strerror(EPERM)); 123 1.1 cgd #endif 124 1.53 dyoung while ((ch = getopt(argc, argv, "b:Ddfhknprvxz")) != -1) 125 1.1 cgd switch (ch) { 126 1.39 atatat case 'b': 127 1.39 atatat bootstr = optarg; 128 1.39 atatat break; 129 1.19 mycroft case 'd': 130 1.19 mycroft dodump = 1; 131 1.1 cgd break; 132 1.25 fair case 'D': 133 1.25 fair nofork = 1; 134 1.25 fair break; 135 1.1 cgd case 'f': 136 1.1 cgd dofast = 1; 137 1.1 cgd break; 138 1.27 thorpej case 'p': 139 1.27 thorpej dopowerdown = 1; 140 1.27 thorpej /* FALLTHROUGH */ 141 1.1 cgd case 'h': 142 1.1 cgd dohalt = 1; 143 1.1 cgd break; 144 1.1 cgd case 'k': 145 1.1 cgd killflg = 1; 146 1.1 cgd break; 147 1.1 cgd case 'n': 148 1.11 mikel nosync = 1; 149 1.1 cgd break; 150 1.1 cgd case 'r': 151 1.1 cgd doreboot = 1; 152 1.1 cgd break; 153 1.53 dyoung case 'v': 154 1.53 dyoung doverbose = 1; 155 1.53 dyoung break; 156 1.53 dyoung case 'x': 157 1.53 dyoung dodebug = 1; 158 1.53 dyoung break; 159 1.53 dyoung case 'z': 160 1.53 dyoung dosilent = 1; 161 1.53 dyoung break; 162 1.1 cgd case '?': 163 1.1 cgd default: 164 1.1 cgd usage(); 165 1.1 cgd } 166 1.1 cgd argc -= optind; 167 1.1 cgd argv += optind; 168 1.1 cgd 169 1.1 cgd if (argc < 1) 170 1.1 cgd usage(); 171 1.1 cgd 172 1.20 mycroft if (dodump && !dohalt && !doreboot) 173 1.20 mycroft doreboot = 1; 174 1.20 mycroft 175 1.1 cgd if (dofast && nosync) { 176 1.50 dholland warnx("Incompatible options -f and -n"); 177 1.1 cgd usage(); 178 1.1 cgd } 179 1.20 mycroft if (dohalt && doreboot) { 180 1.27 thorpej const char *which_flag = dopowerdown ? "p" : "h"; 181 1.27 thorpej 182 1.50 dholland warnx("Incompatible options -%s and -r", which_flag); 183 1.12 jtk usage(); 184 1.12 jtk } 185 1.19 mycroft 186 1.1 cgd getoffset(*argv++); 187 1.1 cgd 188 1.30 ross if (argv[0]) { 189 1.21 mycroft if (strcmp(argv[0], "-") || argv[1]) { 190 1.19 mycroft for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) { 191 1.19 mycroft arglen = strlen(*argv); 192 1.19 mycroft if ((len -= arglen) <= 2) 193 1.19 mycroft break; 194 1.19 mycroft if (p != mbuf) 195 1.19 mycroft *p++ = ' '; 196 1.47 christos (void)memmove(p, *argv, arglen); 197 1.19 mycroft p += arglen; 198 1.19 mycroft } 199 1.19 mycroft *p = '\n'; 200 1.19 mycroft *++p = '\0'; 201 1.19 mycroft } else { 202 1.19 mycroft p = mbuf; 203 1.19 mycroft endp = mbuf + sizeof(mbuf) - 2; 204 1.19 mycroft for (;;) { 205 1.19 mycroft if (!fgets(p, endp - p + 1, stdin)) 206 1.19 mycroft break; 207 1.19 mycroft for (; *p && p < endp; ++p); 208 1.19 mycroft if (p == endp) { 209 1.19 mycroft *p = '\n'; 210 1.19 mycroft *++p = '\0'; 211 1.19 mycroft break; 212 1.19 mycroft } 213 1.1 cgd } 214 1.1 cgd } 215 1.30 ross } 216 1.1 cgd mbuflen = strlen(mbuf); 217 1.1 cgd 218 1.1 cgd if (offset) 219 1.1 cgd (void)printf("Shutdown at %.24s.\n", ctime(&shuttime)); 220 1.1 cgd else 221 1.1 cgd (void)printf("Shutdown NOW!\n"); 222 1.1 cgd 223 1.1 cgd if (!(whom = getlogin())) 224 1.1 cgd whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 225 1.1 cgd 226 1.1 cgd #ifdef DEBUG 227 1.1 cgd (void)putc('\n', stdout); 228 1.1 cgd #else 229 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN); 230 1.25 fair if (nofork == 0) { 231 1.1 cgd int forkpid; 232 1.1 cgd 233 1.1 cgd forkpid = fork(); 234 1.1 cgd if (forkpid == -1) { 235 1.1 cgd perror("shutdown: fork"); 236 1.1 cgd exit(1); 237 1.1 cgd } 238 1.1 cgd if (forkpid) { 239 1.1 cgd (void)printf("shutdown: [pid %d]\n", forkpid); 240 1.1 cgd exit(0); 241 1.1 cgd } 242 1.46 jnemeth (void)setsid(); 243 1.1 cgd } 244 1.1 cgd #endif 245 1.1 cgd openlog("shutdown", LOG_CONS, LOG_AUTH); 246 1.1 cgd loop(); 247 1.7 mycroft /* NOTREACHED */ 248 1.13 mikel #ifdef __GNUC__ 249 1.13 mikel return 1; 250 1.13 mikel #endif 251 1.1 cgd } 252 1.1 cgd 253 1.55 joerg static void 254 1.43 xtraeme loop(void) 255 1.1 cgd { 256 1.47 christos const struct interval *tp; 257 1.1 cgd u_int sltime; 258 1.1 cgd int logged; 259 1.1 cgd 260 1.1 cgd if (offset <= NOLOG_TIME) { 261 1.1 cgd logged = 1; 262 1.1 cgd nolog(); 263 1.1 cgd } 264 1.1 cgd else 265 1.1 cgd logged = 0; 266 1.1 cgd tp = tlist; 267 1.1 cgd if (tp->timeleft < offset) 268 1.1 cgd (void)sleep((u_int)(offset - tp->timeleft)); 269 1.1 cgd else { 270 1.1 cgd while (offset < tp->timeleft) 271 1.1 cgd ++tp; 272 1.1 cgd /* 273 1.7 mycroft * Warn now, if going to sleep more than a fifth of 274 1.1 cgd * the next wait time. 275 1.1 cgd */ 276 1.13 mikel if ((sltime = offset - tp->timeleft) != 0) { 277 1.1 cgd if (sltime > tp->timetowait / 5) 278 1.7 mycroft timewarn(offset); 279 1.1 cgd (void)sleep(sltime); 280 1.1 cgd } 281 1.1 cgd } 282 1.1 cgd for (;; ++tp) { 283 1.7 mycroft timewarn(tp->timeleft); 284 1.1 cgd if (!logged && tp->timeleft <= NOLOG_TIME) { 285 1.1 cgd logged = 1; 286 1.1 cgd nolog(); 287 1.1 cgd } 288 1.1 cgd (void)sleep((u_int)tp->timetowait); 289 1.1 cgd if (!tp->timeleft) 290 1.1 cgd break; 291 1.1 cgd } 292 1.1 cgd die_you_gravy_sucking_pig_dog(); 293 1.1 cgd } 294 1.1 cgd 295 1.1 cgd static jmp_buf alarmbuf; 296 1.1 cgd 297 1.55 joerg static void 298 1.47 christos timewarn(time_t timeleft) 299 1.1 cgd { 300 1.1 cgd static int first; 301 1.1 cgd static char hostname[MAXHOSTNAMELEN + 1]; 302 1.7 mycroft FILE *pf; 303 1.1 cgd char wcmd[MAXPATHLEN + 4]; 304 1.1 cgd 305 1.28 mrg if (!first++) { 306 1.1 cgd (void)gethostname(hostname, sizeof(hostname)); 307 1.28 mrg hostname[sizeof(hostname) - 1] = '\0'; 308 1.28 mrg } 309 1.1 cgd 310 1.1 cgd /* undoc -n option to wall suppresses normal wall banner */ 311 1.28 mrg (void)snprintf(wcmd, sizeof wcmd, "%s -n", _PATH_WALL); 312 1.47 christos if ((pf = popen(wcmd, "w")) == NULL) { 313 1.47 christos syslog(LOG_ERR, "%s: Can't find `%s' (%m)", getprogname(), 314 1.47 christos _PATH_WALL); 315 1.1 cgd return; 316 1.1 cgd } 317 1.1 cgd 318 1.1 cgd (void)fprintf(pf, 319 1.1 cgd "\007*** %sSystem shutdown message from %s@%s ***\007\n", 320 1.5 cgd timeleft ? "": "FINAL ", whom, hostname); 321 1.1 cgd 322 1.5 cgd if (timeleft > 10*60) 323 1.1 cgd (void)fprintf(pf, "System going down at %5.5s\n\n", 324 1.1 cgd ctime(&shuttime) + 11); 325 1.5 cgd else if (timeleft > 59) 326 1.47 christos (void)fprintf(pf, "System going down in %ld minute%s\n\n", 327 1.47 christos (long)timeleft / 60, (timeleft > 60) ? "s" : ""); 328 1.5 cgd else if (timeleft) 329 1.1 cgd (void)fprintf(pf, "System going down in 30 seconds\n\n"); 330 1.1 cgd else 331 1.1 cgd (void)fprintf(pf, "System going down IMMEDIATELY\n\n"); 332 1.1 cgd 333 1.1 cgd if (mbuflen) 334 1.56 apb (void)fwrite(mbuf, 1, mbuflen, pf); 335 1.1 cgd 336 1.1 cgd /* 337 1.1 cgd * play some games, just in case wall doesn't come back 338 1.41 dsainty * probably unnecessary, given that wall is careful. 339 1.1 cgd */ 340 1.1 cgd if (!setjmp(alarmbuf)) { 341 1.1 cgd (void)signal(SIGALRM, timeout); 342 1.1 cgd (void)alarm((u_int)30); 343 1.1 cgd (void)pclose(pf); 344 1.1 cgd (void)alarm((u_int)0); 345 1.1 cgd (void)signal(SIGALRM, SIG_DFL); 346 1.1 cgd } 347 1.1 cgd } 348 1.1 cgd 349 1.47 christos static void 350 1.47 christos /*ARGSUSED*/ 351 1.43 xtraeme timeout(int signo) 352 1.1 cgd { 353 1.1 cgd longjmp(alarmbuf, 1); 354 1.1 cgd } 355 1.1 cgd 356 1.47 christos static void 357 1.44 xtraeme die_you_gravy_sucking_pig_dog(void) 358 1.1 cgd { 359 1.50 dholland const char *what; 360 1.1 cgd 361 1.50 dholland if (doreboot) { 362 1.50 dholland what = "reboot"; 363 1.50 dholland } else if (dohalt && dopowerdown) { 364 1.50 dholland what = "poweroff"; 365 1.50 dholland } else if (dohalt) { 366 1.50 dholland what = "halt"; 367 1.50 dholland } else { 368 1.50 dholland what = "shutdown"; 369 1.50 dholland } 370 1.50 dholland 371 1.50 dholland syslog(LOG_NOTICE, "%s by %s: %s", what, whom, mbuf); 372 1.1 cgd (void)sleep(2); 373 1.1 cgd 374 1.1 cgd (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n"); 375 1.1 cgd if (killflg) { 376 1.1 cgd (void)printf("\rbut you'll have to do it yourself\r\n"); 377 1.7 mycroft finish(0); 378 1.1 cgd } 379 1.1 cgd if (dofast) 380 1.1 cgd doitfast(); 381 1.59 martin dorcshutdown(what); 382 1.20 mycroft if (doreboot || dohalt) { 383 1.53 dyoung const char *args[20]; 384 1.45 christos const char **arg, *path; 385 1.48 jnemeth #ifndef DEBUG 386 1.47 christos int serrno; 387 1.48 jnemeth #endif 388 1.20 mycroft 389 1.20 mycroft arg = &args[0]; 390 1.20 mycroft if (doreboot) { 391 1.20 mycroft path = _PATH_REBOOT; 392 1.20 mycroft *arg++ = "reboot"; 393 1.20 mycroft } else { 394 1.20 mycroft path = _PATH_HALT; 395 1.20 mycroft *arg++ = "halt"; 396 1.20 mycroft } 397 1.53 dyoung if (doverbose) 398 1.53 dyoung *arg++ = "-v"; 399 1.53 dyoung if (dodebug) 400 1.53 dyoung *arg++ = "-x"; 401 1.53 dyoung if (dosilent) 402 1.53 dyoung *arg++ = "-z"; 403 1.20 mycroft if (dodump) 404 1.20 mycroft *arg++ = "-d"; 405 1.20 mycroft if (nosync) 406 1.20 mycroft *arg++ = "-n"; 407 1.27 thorpej if (dopowerdown) 408 1.27 thorpej *arg++ = "-p"; 409 1.20 mycroft *arg++ = "-l"; 410 1.39 atatat if (bootstr) 411 1.39 atatat *arg++ = bootstr; 412 1.57 uwe *arg++ = NULL; 413 1.20 mycroft #ifndef DEBUG 414 1.52 riz (void)unlink(_PATH_NOLOGIN); 415 1.47 christos (void)execve(path, __UNCONST(args), NULL); 416 1.47 christos serrno = errno; 417 1.50 dholland syslog(LOG_ERR, "Can't exec `%s' (%m)", path); 418 1.47 christos errno = serrno; 419 1.47 christos warn("Can't exec `%s'", path); 420 1.20 mycroft #else 421 1.20 mycroft printf("%s", path); 422 1.20 mycroft for (arg = &args[0]; *arg; arg++) 423 1.20 mycroft printf(" %s", *arg); 424 1.20 mycroft printf("\n"); 425 1.20 mycroft #endif 426 1.20 mycroft } else { 427 1.20 mycroft #ifndef DEBUG 428 1.20 mycroft (void)kill(1, SIGTERM); /* to single user */ 429 1.1 cgd #else 430 1.20 mycroft printf("kill 1\n"); 431 1.20 mycroft #endif 432 1.1 cgd } 433 1.7 mycroft finish(0); 434 1.1 cgd } 435 1.1 cgd 436 1.23 mycroft #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) 437 1.1 cgd 438 1.55 joerg static void 439 1.43 xtraeme getoffset(char *timearg) 440 1.1 cgd { 441 1.14 lukem struct tm *lt; 442 1.14 lukem char *p; 443 1.7 mycroft time_t now; 444 1.18 mycroft int yearset; 445 1.1 cgd 446 1.32 enami (void)time(&now); 447 1.1 cgd if (!strcasecmp(timearg, "now")) { /* now */ 448 1.1 cgd offset = 0; 449 1.32 enami shuttime = now; 450 1.1 cgd return; 451 1.1 cgd } 452 1.1 cgd 453 1.1 cgd if (*timearg == '+') { /* +minutes */ 454 1.42 dsl if (!isdigit((unsigned char)*++timearg)) 455 1.1 cgd badtime(); 456 1.1 cgd offset = atoi(timearg) * 60; 457 1.1 cgd shuttime = now + offset; 458 1.1 cgd return; 459 1.1 cgd } 460 1.1 cgd 461 1.1 cgd /* handle hh:mm by getting rid of the colon */ 462 1.1 cgd for (p = timearg; *p; ++p) 463 1.42 dsl if (!isascii(*p) || !isdigit((unsigned char)*p)) { 464 1.1 cgd if (*p == ':' && strlen(p) == 3) { 465 1.1 cgd p[0] = p[1]; 466 1.1 cgd p[1] = p[2]; 467 1.1 cgd p[2] = '\0'; 468 1.1 cgd } 469 1.1 cgd else 470 1.1 cgd badtime(); 471 1.30 ross } 472 1.1 cgd 473 1.47 christos (void)unsetenv("TZ"); /* OUR timezone */ 474 1.1 cgd lt = localtime(&now); /* current time val */ 475 1.1 cgd 476 1.18 mycroft lt->tm_sec = 0; 477 1.18 mycroft 478 1.18 mycroft yearset = 0; 479 1.18 mycroft switch (strlen(timearg)) { 480 1.18 mycroft case 12: 481 1.23 mycroft lt->tm_year = ATOI2(timearg) * 100 - TM_YEAR_BASE; 482 1.18 mycroft yearset = 1; 483 1.18 mycroft /* FALLTHROUGH */ 484 1.1 cgd case 10: 485 1.18 mycroft if (yearset) { 486 1.23 mycroft lt->tm_year += ATOI2(timearg); 487 1.18 mycroft } else { 488 1.18 mycroft yearset = ATOI2(timearg); 489 1.58 kre if (yearset < 20) 490 1.58 kre lt->tm_year = yearset + 2100 - TM_YEAR_BASE; 491 1.58 kre else 492 1.23 mycroft lt->tm_year = yearset + 2000 - TM_YEAR_BASE; 493 1.18 mycroft } 494 1.1 cgd /* FALLTHROUGH */ 495 1.1 cgd case 8: 496 1.1 cgd lt->tm_mon = ATOI2(timearg); 497 1.18 mycroft --lt->tm_mon; 498 1.1 cgd /* FALLTHROUGH */ 499 1.1 cgd case 6: 500 1.1 cgd lt->tm_mday = ATOI2(timearg); 501 1.1 cgd /* FALLTHROUGH */ 502 1.1 cgd case 4: 503 1.1 cgd lt->tm_hour = ATOI2(timearg); 504 1.18 mycroft /* FALLTHROUGH */ 505 1.18 mycroft case 2: 506 1.1 cgd lt->tm_min = ATOI2(timearg); 507 1.1 cgd break; 508 1.1 cgd default: 509 1.1 cgd badtime(); 510 1.18 mycroft } 511 1.18 mycroft 512 1.18 mycroft if ((shuttime = mktime(lt)) == -1) 513 1.18 mycroft badtime(); 514 1.19 mycroft if ((offset = shuttime - now) < 0) 515 1.19 mycroft errx(1, "time is already past"); 516 1.33 bad } 517 1.33 bad 518 1.55 joerg static void 519 1.59 martin dorcshutdown(const char *arg) 520 1.33 bad { 521 1.59 martin static char cmd[sizeof(_PATH_RCSHUTDOWN) + 64]; 522 1.59 martin 523 1.59 martin if (arg) { 524 1.59 martin snprintf(cmd, sizeof(cmd), "set -- %s && . " _PATH_RCSHUTDOWN, 525 1.59 martin arg); 526 1.59 martin cmd[sizeof(cmd)-1] = 0; 527 1.59 martin arg = cmd; 528 1.59 martin } else { 529 1.59 martin arg = ". " _PATH_RCSHUTDOWN; 530 1.59 martin } 531 1.59 martin 532 1.33 bad (void)printf("\r\nAbout to run shutdown hooks...\r\n"); 533 1.47 christos #ifndef DEBUG 534 1.47 christos (void)setuid(0); 535 1.59 martin (void)system(arg); 536 1.47 christos #endif 537 1.37 jdolecek (void)sleep(5); /* Give operator a chance to abort this. */ 538 1.36 jdolecek (void)printf("\r\nDone running shutdown hooks.\r\n"); 539 1.1 cgd } 540 1.1 cgd 541 1.1 cgd #define FSMSG "fastboot file for fsck\n" 542 1.55 joerg static void 543 1.43 xtraeme doitfast(void) 544 1.1 cgd { 545 1.1 cgd int fastfd; 546 1.1 cgd 547 1.1 cgd if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC, 548 1.1 cgd 0664)) >= 0) { 549 1.1 cgd (void)write(fastfd, FSMSG, sizeof(FSMSG) - 1); 550 1.1 cgd (void)close(fastfd); 551 1.1 cgd } 552 1.1 cgd } 553 1.1 cgd 554 1.1 cgd #define NOMSG "\n\nNO LOGINS: System going down at " 555 1.55 joerg static void 556 1.43 xtraeme nolog(void) 557 1.1 cgd { 558 1.1 cgd int logfd; 559 1.7 mycroft char *ct; 560 1.1 cgd 561 1.1 cgd (void)unlink(_PATH_NOLOGIN); /* in case linked to another file */ 562 1.1 cgd (void)signal(SIGINT, finish); 563 1.1 cgd (void)signal(SIGHUP, finish); 564 1.1 cgd (void)signal(SIGQUIT, finish); 565 1.1 cgd (void)signal(SIGTERM, finish); 566 1.1 cgd if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC, 567 1.1 cgd 0664)) >= 0) { 568 1.1 cgd (void)write(logfd, NOMSG, sizeof(NOMSG) - 1); 569 1.1 cgd ct = ctime(&shuttime); 570 1.1 cgd (void)write(logfd, ct + 11, 5); 571 1.1 cgd (void)write(logfd, "\n\n", 2); 572 1.1 cgd (void)write(logfd, mbuf, strlen(mbuf)); 573 1.1 cgd (void)close(logfd); 574 1.1 cgd } 575 1.1 cgd } 576 1.1 cgd 577 1.47 christos static void 578 1.47 christos /*ARGSUSED*/ 579 1.43 xtraeme finish(int signo) 580 1.1 cgd { 581 1.28 mrg 582 1.6 mycroft if (!killflg) 583 1.6 mycroft (void)unlink(_PATH_NOLOGIN); 584 1.1 cgd exit(0); 585 1.1 cgd } 586 1.1 cgd 587 1.47 christos static void 588 1.43 xtraeme badtime(void) 589 1.1 cgd { 590 1.28 mrg 591 1.19 mycroft warnx("illegal time format"); 592 1.19 mycroft usage(); 593 1.1 cgd } 594 1.1 cgd 595 1.47 christos static void 596 1.43 xtraeme usage(void) 597 1.1 cgd { 598 1.28 mrg 599 1.19 mycroft (void)fprintf(stderr, 600 1.54 wiz "Usage: %s [-Ddfhknprvxz] [-b bootstr] time [message ... | -]\n", 601 1.47 christos getprogname()); 602 1.1 cgd exit(1); 603 1.1 cgd } 604