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