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