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