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