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