|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)shutdown.c 4.19 (Berkeley) 83/06/17";
3: #endif
4:
5: #include <stdio.h>
6: #include <ctype.h>
7: #include <signal.h>
8: #include <utmp.h>
9: #include <sys/time.h>
10: #include <sys/resource.h>
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
19: */
20: #ifdef DEBUG
21: #define LOGFILE "shutdown.log"
22: #else
23: #define LOGFILE "/usr/adm/shutdownlog"
24: #endif
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
31: #define NLOG 20 /* no of args possible for message */
32: #define NOLOGTIME 5 MINUTES
33: #define IGNOREUSER "sleeper"
34:
35: char hostname[32];
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: time_t nowtime;
61:
62: struct 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,
71: 10 MINUTES, 5 MINUTES,
72: 5 MINUTES, 3 MINUTES,
73: 2 MINUTES, 1 MINUTES,
74: 1 MINUTES, 30 SECONDS,
75: 0 SECONDS, 0 SECONDS
76: };
77:
78: char *shutter, *getlogin();
79:
80: main(argc,argv)
81: int argc;
82: char **argv;
83: {
84: register i, ufd;
85: register char **mess, *f;
86: char *ts;
87: time_t sdt;
88: int h, m;
89: int first;
90: FILE *termf;
91:
92: shutter = getlogin();
93: gethostname(hostname, sizeof (hostname));
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) {
113: printf("Usage: %s [ -krh ] shutdowntime [ message ]\n",
114: argv[0]);
115: finish();
116: }
117: if (geteuid()) {
118: fprintf(stderr, "NOT super-user\n");
119: finish();
120: }
121: nowtime = time((time_t *)0);
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;
129: m = ((stogo = sdt - nowtime) + 30)/60;
130: h = m/60;
131: m %= 60;
132: ts = ctime(&sdt);
133: printf("Shutdown at %5.5s (in ", ts+11);
134: if (h > 0)
135: printf("%d hour%s ", h, h != 1 ? "s" : "");
136: printf("%d minute%s) ", m, m != 1 ? "s" : "");
137: #ifndef DEBUG
138: signal(SIGHUP, SIG_IGN);
139: signal(SIGQUIT, SIG_IGN);
140: signal(SIGINT, SIG_IGN);
141: #endif
142: signal(SIGTTOU, SIG_IGN);
143: signal(SIGTERM, finish);
144: signal(SIGALRM, do_nothing);
145: setpriority(PRIO_PROCESS, 0, PRIO_MIN);
146: fflush(stdout);
147: #ifndef DEBUG
148: if (i = fork()) {
149: printf("[pid %d]\n", i);
150: exit(0);
151: }
152: #else
153: putc('\n', stdout);
154: #endif
155: sint = 1 HOURS;
156: f = "";
157: ufd = open("/etc/utmp",0);
158: if (ufd < 0) {
159: perror("shutdown: /etc/utmp");
160: exit(1);
161: }
162: first = 1;
163: for (;;) {
164: for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++)
165: sint = interval[i].sint;
166: if (stogo > 0 && (stogo-sint) < interval[i].stogo)
167: sint = stogo - interval[i].stogo;
168: if (stogo <= NOLOGTIME && nlflag) {
169: nlflag = 0;
170: nolog(sdt);
171: }
172: if (sint >= stogo || sint == 0)
173: f = "FINAL ";
174: nowtime = time((time_t *) 0);
175: lseek(ufd, 0L, 0);
176: while (read(ufd,&utmp,sizeof utmp)==sizeof utmp)
177: if (utmp.ut_name[0] &&
178: strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) {
179: strcpy(term, tpath);
180: strncat(term, utmp.ut_line, sizeof utmp.ut_line);
181: alarm(3);
182: #ifdef DEBUG
183: if ((termf = stdout) != NULL)
184: #else
185: if ((termf = fopen(term, "w")) != NULL)
186: #endif
187: {
188: alarm(0);
189: setbuf(termf, tbuf);
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...");
195: for (mess = nolog2; *mess; mess++)
196: fprintf(termf, " %s", *mess);
197: }
198: fputc('\r', termf);
199: fputc('\n', termf);
200: alarm(5);
201: #ifdef DEBUG
202: fflush(termf);
203: #else
204: fclose(termf);
205: #endif
206: alarm(0);
207: }
208: }
209: if (stogo <= 0) {
210: printf("\n\007\007System shutdown time has arrived\007\007\n");
211: log_entry(sdt);
212: unlink(nologin);
213: if (!killflg) {
214: printf("but you'll have to do it yourself\n");
215: finish();
216: }
217: #ifndef DEBUG
218: kill(-1, SIGTERM); /* terminate everyone */
219: sleep(5); /* & wait while they die */
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: }
232: stogo = sdt - time((time_t *) 0);
233: if (stogo > 0 && sint > 0)
234: sleep(sint<stogo ? sint : stogo);
235: stogo -= sint;
236: first = 0;
237: }
238: }
239:
240: time_t
241: getsdt(s)
242: register char *s;
243: {
244: time_t t, t1, tim;
245: register char c;
246: struct tm *lt;
247:
248: if (strcmp(s, "now") == 0)
249: return(nowtime);
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;
262: tim = time((time_t *) 0) + t;
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;
280: t1 = time((time_t *) 0);
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: }
288: return (t1 + tim - t);
289: badform:
290: printf("Bad time format\n");
291: finish();
292: }
293:
294: warn(term, sdt, now, type)
295: FILE *term;
296: time_t sdt, now;
297: char *type;
298: {
299: char *ts;
300: register delay = sdt - now;
301:
302: if (delay > 8)
303: while (delay % 5)
304: delay++;
305:
306: if (shutter)
307: fprintf(term,
308: "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n",
309: type, shutter, hostname);
310: else
311: fprintf(term,
312: "\007\007\t*** %sSystem shutdown message (%s) ***\r\n\n",
313: type, hostname);
314:
315: ts = ctime(&sdt);
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" : "");
324: } else
325: fprintf(term, "System going down IMMEDIATELY\r\n");
326: }
327:
328: nolog(sdt)
329: time_t sdt;
330: {
331: FILE *nologf;
332: register char **mess;
333:
334: unlink(nologin); /* in case linked to std file */
335: if ((nologf = fopen(nologin, "w")) != NULL) {
336: fprintf(nologf, nolog1, (ctime(&sdt)) + 11);
337: putc('\t', nologf);
338: for (mess = nolog2; *mess; mess++)
339: fprintf(nologf, " %s", *mess);
340: putc('\n', nologf);
341: fclose(nologf);
342: }
343: }
344:
345: finish()
346: {
347: signal(SIGTERM, SIG_IGN);
348: unlink(nologin);
349: exit(0);
350: }
351:
352: do_nothing()
353: {
354:
355: signal(SIGALRM, do_nothing);
356: }
357:
358: /*
359: * make an entry in the shutdown log
360: */
361:
362: char *days[] = {
363: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
364: };
365:
366: char *months[] = {
367: "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
368: "Oct", "Nov", "Dec"
369: };
370:
371: log_entry(now)
372: time_t now;
373: {
374: register FILE *fp;
375: register char **mess;
376: struct tm *tm, *localtime();
377:
378: tm = localtime(&now);
379: fp = fopen(LOGFILE, "a");
380: if (fp == NULL) {
381: printf("Shutdown: log entry failed\n");
382: return;
383: }
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);
388: for (mess = nolog2; *mess; mess++)
389: fprintf(fp, " %s", *mess);
390: if (shutter)
391: fprintf(fp, " (by %s!%s)", hostname, shutter);
392: fputc('\n', fp);
393: fclose(fp);
394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.