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