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