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