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