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