1 /* 2 * Copyright (c) 1983,1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1983,1986 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)shutdown.c 5.7 (Berkeley) 12/26/87"; 15 #endif not lint 16 17 #include <stdio.h> 18 #include <ctype.h> 19 #include <signal.h> 20 #include <setjmp.h> 21 #include <utmp.h> 22 #include <pwd.h> 23 #include <sys/time.h> 24 #include <sys/resource.h> 25 #include <sys/param.h> 26 #include <sys/syslog.h> 27 28 /* 29 * /etc/shutdown when [messages] 30 * 31 * allow super users to tell users and remind users 32 * of iminent shutdown of unix 33 * and shut it down automatically 34 * and even reboot or halt the machine if they desire 35 */ 36 37 #define REBOOT "/etc/reboot" 38 #define HALT "/etc/halt" 39 #define MAXINTS 20 40 #define HOURS *3600 41 #define MINUTES *60 42 #define SECONDS 43 #define NLOG 600 /* no of bytes possible for message */ 44 #define NOLOGTIME 5 MINUTES 45 #define IGNOREUSER "sleeper" 46 47 char hostname[MAXHOSTNAMELEN]; 48 49 int timeout(); 50 time_t getsdt(); 51 void finish(); 52 53 extern char *ctime(); 54 extern struct tm *localtime(); 55 extern long time(); 56 57 extern char *strcpy(); 58 extern char *strncat(); 59 extern off_t lseek(); 60 61 struct utmp utmp; 62 int sint; 63 int stogo; 64 char tpath[] = "/dev/"; 65 int nlflag = 1; /* nolog yet to be done */ 66 int killflg = 1; 67 int doreboot = 0; 68 int halt = 0; 69 int fast = 0; 70 char *nosync = NULL; 71 char nosyncflag[] = "-n"; 72 char term[sizeof tpath + sizeof utmp.ut_line]; 73 char tbuf[BUFSIZ]; 74 char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 75 char nolog2[NLOG+1]; 76 #ifdef DEBUG 77 char nologin[] = "nologin"; 78 char fastboot[] = "fastboot"; 79 #else 80 char nologin[] = "/etc/nologin"; 81 char fastboot[] = "/fastboot"; 82 #endif 83 time_t nowtime; 84 jmp_buf alarmbuf; 85 86 struct interval { 87 int stogo; 88 int sint; 89 } interval[] = { 90 4 HOURS, 1 HOURS, 91 2 HOURS, 30 MINUTES, 92 1 HOURS, 15 MINUTES, 93 30 MINUTES, 10 MINUTES, 94 15 MINUTES, 5 MINUTES, 95 10 MINUTES, 5 MINUTES, 96 5 MINUTES, 3 MINUTES, 97 2 MINUTES, 1 MINUTES, 98 1 MINUTES, 30 SECONDS, 99 0 SECONDS, 0 SECONDS 100 }; 101 102 char *shutter, *getlogin(); 103 104 main(argc,argv) 105 int argc; 106 char **argv; 107 { 108 register i, ufd; 109 register char *f; 110 char *ts; 111 time_t sdt; 112 int h, m; 113 int first; 114 FILE *termf; 115 struct passwd *pw, *getpwuid(); 116 extern char *strcat(); 117 extern uid_t geteuid(); 118 119 shutter = getlogin(); 120 if (shutter == 0 && (pw = getpwuid(getuid()))) 121 shutter = pw->pw_name; 122 if (shutter == 0) 123 shutter = "???"; 124 (void) gethostname(hostname, sizeof (hostname)); 125 openlog("shutdown", 0, LOG_AUTH); 126 argc--, argv++; 127 while (argc > 0 && (f = argv[0], *f++ == '-')) { 128 while (i = *f++) switch (i) { 129 case 'k': 130 killflg = 0; 131 continue; 132 case 'n': 133 nosync = nosyncflag; 134 continue; 135 case 'f': 136 fast = 1; 137 continue; 138 case 'r': 139 doreboot = 1; 140 continue; 141 case 'h': 142 halt = 1; 143 continue; 144 default: 145 fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 146 exit(1); 147 } 148 argc--, argv++; 149 } 150 if (argc < 1) { 151 /* argv[0] is not available after the argument handling. */ 152 printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n"); 153 finish(); 154 } 155 if (fast && (nosync == nosyncflag)) { 156 printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n"); 157 finish(); 158 } 159 if (geteuid()) { 160 fprintf(stderr, "NOT super-user\n"); 161 finish(); 162 } 163 nowtime = time((long *)0); 164 sdt = getsdt(argv[0]); 165 argc--, argv++; 166 nolog2[0] = '\0'; 167 while (argc-- > 0) { 168 (void) strcat(nolog2, " "); 169 (void) strcat(nolog2, *argv++); 170 } 171 m = ((stogo = sdt - nowtime) + 30)/60; 172 h = m/60; 173 m %= 60; 174 ts = ctime(&sdt); 175 printf("Shutdown at %5.5s (in ", ts+11); 176 if (h > 0) 177 printf("%d hour%s ", h, h != 1 ? "s" : ""); 178 printf("%d minute%s) ", m, m != 1 ? "s" : ""); 179 #ifndef DEBUG 180 (void) signal(SIGHUP, SIG_IGN); 181 (void) signal(SIGQUIT, SIG_IGN); 182 (void) signal(SIGINT, SIG_IGN); 183 #endif 184 (void) signal(SIGTTOU, SIG_IGN); 185 (void) signal(SIGTERM, finish); 186 (void) signal(SIGALRM, timeout); 187 (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN); 188 (void) fflush(stdout); 189 #ifndef DEBUG 190 if (i = fork()) { 191 printf("[pid %d]\n", i); 192 exit(0); 193 } 194 #else 195 (void) putc('\n', stdout); 196 #endif 197 sint = 1 HOURS; 198 f = ""; 199 ufd = open("/etc/utmp",0); 200 if (ufd < 0) { 201 perror("shutdown: /etc/utmp"); 202 exit(1); 203 } 204 first = 1; 205 for (;;) { 206 for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 207 sint = interval[i].sint; 208 if (stogo > 0 && (stogo-sint) < interval[i].stogo) 209 sint = stogo - interval[i].stogo; 210 if (stogo <= NOLOGTIME && nlflag) { 211 nlflag = 0; 212 nolog(sdt); 213 } 214 if (sint >= stogo || sint == 0) 215 f = "FINAL "; 216 nowtime = time((long *)0); 217 (void) lseek(ufd, 0L, 0); 218 while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp) 219 if (utmp.ut_name[0] && 220 strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 221 if (setjmp(alarmbuf)) 222 continue; 223 (void) strcpy(term, tpath); 224 (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line); 225 (void) alarm(3); 226 #ifdef DEBUG 227 if ((termf = stdout) != NULL) 228 #else 229 if ((termf = fopen(term, "w")) != NULL) 230 #endif 231 { 232 (void) alarm(0); 233 setbuf(termf, tbuf); 234 fprintf(termf, "\n\r\n"); 235 warn(termf, sdt, nowtime, f); 236 if (first || sdt - nowtime > 1 MINUTES) { 237 if (*nolog2) 238 fprintf(termf, "\t...%s", nolog2); 239 } 240 (void) fputc('\r', termf); 241 (void) fputc('\n', termf); 242 (void) alarm(5); 243 #ifdef DEBUG 244 (void) fflush(termf); 245 #else 246 (void) fclose(termf); 247 #endif 248 (void) alarm(0); 249 } 250 } 251 if (stogo <= 0) { 252 printf("\n\007\007System shutdown time has arrived\007\007\n"); 253 syslog(LOG_CRIT, "%s by %s: %s", 254 doreboot ? "reboot" : halt ? "halt" : "shutdown", 255 shutter, nolog2); 256 sleep(2); 257 (void) unlink(nologin); 258 if (!killflg) { 259 printf("but you'll have to do it yourself\n"); 260 finish(); 261 } 262 if (fast) 263 doitfast(); 264 #ifndef DEBUG 265 if (doreboot) 266 execle(REBOOT, "reboot", "-l", nosync, 0, 0); 267 if (halt) 268 execle(HALT, "halt", "-l", nosync, 0, 0); 269 (void) kill(1, SIGTERM); /* to single user */ 270 #else 271 if (doreboot) 272 printf("REBOOT"); 273 if (halt) 274 printf(" HALT"); 275 if (fast) 276 printf(" -l %s (without fsck's)\n", nosync); 277 else 278 printf(" -l %s\n", nosync); 279 else 280 printf("kill -HUP 1\n"); 281 282 #endif 283 finish(); 284 } 285 stogo = sdt - time((long *) 0); 286 if (stogo > 0 && sint > 0) 287 sleep((unsigned)(sint<stogo ? sint : stogo)); 288 stogo -= sint; 289 first = 0; 290 } 291 } 292 293 time_t 294 getsdt(s) 295 register char *s; 296 { 297 time_t t, t1, tim; 298 register char c; 299 struct tm *lt; 300 301 if (strcmp(s, "now") == 0) 302 return(nowtime); 303 if (*s == '+') { 304 ++s; 305 t = 0; 306 for (;;) { 307 c = *s++; 308 if (!isdigit(c)) 309 break; 310 t = t * 10 + c - '0'; 311 } 312 if (t <= 0) 313 t = 5; 314 t *= 60; 315 tim = time((long *) 0) + t; 316 return(tim); 317 } 318 t = 0; 319 while (strlen(s) > 2 && isdigit(*s)) 320 t = t * 10 + *s++ - '0'; 321 if (*s == ':') 322 s++; 323 if (t > 23) 324 goto badform; 325 tim = t*60; 326 t = 0; 327 while (isdigit(*s)) 328 t = t * 10 + *s++ - '0'; 329 if (t > 59) 330 goto badform; 331 tim += t; 332 tim *= 60; 333 t1 = time((long *) 0); 334 lt = localtime(&t1); 335 t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 336 if (tim < t || tim >= (24*3600)) { 337 /* before now or after midnight */ 338 printf("That must be tomorrow\nCan't you wait till then?\n"); 339 finish(); 340 } 341 return (t1 + tim - t); 342 badform: 343 printf("Bad time format\n"); 344 finish(); 345 /*NOTREACHED*/ 346 } 347 348 warn(term, sdt, now, type) 349 FILE *term; 350 time_t sdt, now; 351 char *type; 352 { 353 char *ts; 354 register delay = sdt - now; 355 356 if (delay > 8) 357 while (delay % 5) 358 delay++; 359 360 fprintf(term, 361 "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", 362 type, shutter, hostname); 363 364 ts = ctime(&sdt); 365 if (delay > 10 MINUTES) 366 fprintf(term, "System going down at %5.5s\r\n", ts+11); 367 else if (delay > 95 SECONDS) { 368 fprintf(term, "System going down in %d minute%s\r\n", 369 (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 370 } else if (delay > 0) { 371 fprintf(term, "System going down in %d second%s\r\n", 372 delay, delay != 1 ? "s" : ""); 373 } else 374 fprintf(term, "System going down IMMEDIATELY\r\n"); 375 } 376 377 doitfast() 378 { 379 FILE *fastd; 380 381 if ((fastd = fopen(fastboot, "w")) != NULL) { 382 putc('\n', fastd); 383 (void) fclose(fastd); 384 } 385 } 386 387 nolog(sdt) 388 time_t sdt; 389 { 390 FILE *nologf; 391 392 (void) unlink(nologin); /* in case linked to std file */ 393 if ((nologf = fopen(nologin, "w")) != NULL) { 394 fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 395 if (*nolog2) 396 fprintf(nologf, "\t%s\n", nolog2 + 1); 397 (void) fclose(nologf); 398 } 399 } 400 401 void 402 finish() 403 { 404 (void) signal(SIGTERM, SIG_IGN); 405 (void) unlink(nologin); 406 exit(0); 407 } 408 409 timeout() 410 { 411 longjmp(alarmbuf, 1); 412 } 413