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