|
|
1.1 root 1: /*
2: * Copyright (c) 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)shutdown.c 5.15 (Berkeley) 6/22/90";
28: #endif /* not lint */
29:
30: #include <sys/param.h>
31: #include <sys/time.h>
32: #include <sys/file.h>
33: #include <sys/resource.h>
34: #include <sys/syslog.h>
35: #include <sys/signal.h>
36: #include <setjmp.h>
37: #include <tzfile.h>
38: #include <pwd.h>
39: #include <stdio.h>
40: #include <ctype.h>
41: #include "pathnames.h"
42:
43: #ifdef DEBUG
44: #undef _PATH_NOLOGIN
45: #define _PATH_NOLOGIN "./nologin"
46: #undef _PATH_FASTBOOT
47: #define _PATH_FASTBOOT "./fastboot"
48: #endif
49:
50: #define H *60*60
51: #define M *60
52: #define S *1
53: #define NOLOG_TIME 5*60
54: struct interval {
55: int timeleft, timetowait;
56: } tlist[] = {
57: 10 H, 5 H, 5 H, 3 H, 2 H, 1 H, 1 H, 30 M,
58: 30 M, 10 M, 20 M, 10 M, 10 M, 5 M, 5 M, 3 M,
59: 2 M, 1 M, 1 M, 30 S, 30 S, 30 S,
60: 0, 0,
61: }, *tp = tlist;
62: #undef H
63: #undef M
64: #undef S
65:
66: static time_t offset, shuttime;
67: static int dofast, dohalt, doreboot, killflg, mbuflen;
68: static char *nosync, *whom, mbuf[BUFSIZ];
69:
70: main(argc, argv)
71: int argc;
72: char **argv;
73: {
74: extern int optind;
75: register char *p, *endp;
76: int arglen, ch, len, readstdin;
77: struct passwd *pw, *getpwuid();
78: char *strcat(), *getlogin();
79: uid_t geteuid();
80:
81: #ifndef DEBUG
82: if (geteuid()) {
83: (void)fprintf(stderr, "shutdown: NOT super-user\n");
84: exit(1);
85: }
86: #endif
87: nosync = NULL;
88: readstdin = 0;
89: while ((ch = getopt(argc, argv, "-fhknr")) != EOF)
90: switch (ch) {
91: case '-':
92: readstdin = 1;
93: break;
94: case 'f':
95: dofast = 1;
96: break;
97: case 'h':
98: dohalt = 1;
99: break;
100: case 'k':
101: killflg = 1;
102: break;
103: case 'n':
104: nosync = "-n";
105: break;
106: case 'r':
107: doreboot = 1;
108: break;
109: case '?':
110: default:
111: usage();
112: }
113: argc -= optind;
114: argv += optind;
115:
116: if (argc < 1)
117: usage();
118:
119: if (dofast && nosync) {
120: (void)fprintf(stderr,
121: "shutdown: incompatible switches -f and -n.\n");
122: usage();
123: }
124: if (doreboot && dohalt) {
125: (void)fprintf(stderr,
126: "shutdown: incompatible switches -h and -r.\n");
127: usage();
128: }
129: getoffset(*argv++);
130:
131: if (*argv) {
132: for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
133: arglen = strlen(*argv);
134: if ((len -= arglen) <= 2)
135: break;
136: if (p != mbuf)
137: *p++ = ' ';
138: bcopy(*argv, p, arglen);
139: p += arglen;
140: }
141: *p = '\n';
142: *++p = '\0';
143: }
144:
145: if (readstdin) {
146: p = mbuf;
147: endp = mbuf + sizeof(mbuf) - 2;
148: for (;;) {
149: if (!fgets(p, endp - p + 1, stdin))
150: break;
151: for (; *p && p < endp; ++p);
152: if (p == endp) {
153: *p = '\n';
154: *++p = '\0';
155: break;
156: }
157: }
158: }
159: mbuflen = strlen(mbuf);
160:
161: if (offset)
162: (void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
163: else
164: (void)printf("Shutdown NOW!\n");
165:
166: if (!(whom = getlogin()))
167: whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
168:
169: #ifdef DEBUG
170: (void)putc('\n', stdout);
171: #else
172: (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
173: {
174: int forkpid;
175:
176: forkpid = fork();
177: if (forkpid == -1) {
178: perror("shutdown: fork");
179: exit(1);
180: }
181: if (forkpid) {
182: (void)printf("shutdown: [pid %d]\n", forkpid);
183: exit(0);
184: }
185: }
186: #endif
187: openlog("shutdown", LOG_CONS, LOG_AUTH);
188: loop();
189: /*NOTREACHED*/
190: }
191:
192: loop()
193: {
194: u_int sltime;
195: int logged;
196:
197: if (offset <= NOLOG_TIME) {
198: logged = 1;
199: nolog();
200: }
201: else
202: logged = 0;
203: tp = tlist;
204: if (tp->timeleft < offset)
205: (void)sleep((u_int)(offset - tp->timeleft));
206: else {
207: while (offset < tp->timeleft)
208: ++tp;
209: /*
210: * warn now, if going to sleep more than a fifth of
211: * the next wait time.
212: */
213: if (sltime = offset - tp->timeleft) {
214: if (sltime > tp->timetowait / 5)
215: warn();
216: (void)sleep(sltime);
217: }
218: }
219: for (;; ++tp) {
220: warn();
221: if (!logged && tp->timeleft <= NOLOG_TIME) {
222: logged = 1;
223: nolog();
224: }
225: (void)sleep((u_int)tp->timetowait);
226: if (!tp->timeleft)
227: break;
228: }
229: die_you_gravy_sucking_pig_dog();
230: }
231:
232: static jmp_buf alarmbuf;
233:
234: warn()
235: {
236: static int first;
237: static char hostname[MAXHOSTNAMELEN + 1];
238: char wcmd[MAXPATHLEN + 4];
239: FILE *pf;
240: char *ctime();
241: void timeout();
242:
243: if (!first++)
244: (void)gethostname(hostname, sizeof(hostname));
245:
246: /* undoc -n option to wall suppresses normal wall banner */
247: (void)sprintf(wcmd, "%s -n", _PATH_WALL);
248: if (!(pf = popen(wcmd, "w"))) {
249: syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
250: return;
251: }
252:
253: (void)fprintf(pf,
254: "\007*** %sSystem shutdown message from %s@%s ***\007\n",
255: tp->timeleft ? "": "FINAL ", whom, hostname);
256:
257: if (tp->timeleft > 10*60)
258: (void)fprintf(pf, "System going down at %5.5s\n\n",
259: ctime(&shuttime) + 11);
260: else if (tp->timeleft > 59)
261: (void)fprintf(pf, "System going down in %d minute%s\n\n",
262: tp->timeleft / 60, (tp->timeleft > 60) ? "s" : "");
263: else if (tp->timeleft)
264: (void)fprintf(pf, "System going down in 30 seconds\n\n");
265: else
266: (void)fprintf(pf, "System going down IMMEDIATELY\n\n");
267:
268: if (mbuflen)
269: (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
270:
271: /*
272: * play some games, just in case wall doesn't come back
273: * probably unecessary, given that wall is careful.
274: */
275: if (!setjmp(alarmbuf)) {
276: (void)signal(SIGALRM, timeout);
277: (void)alarm((u_int)30);
278: (void)pclose(pf);
279: (void)alarm((u_int)0);
280: (void)signal(SIGALRM, SIG_DFL);
281: }
282: }
283:
284: void
285: timeout()
286: {
287: longjmp(alarmbuf, 1);
288: }
289:
290: die_you_gravy_sucking_pig_dog()
291: {
292: void finish();
293:
294: syslog(LOG_NOTICE, "%s by %s: %s",
295: doreboot ? "reboot" : dohalt ? "halt" : "shutdown", whom, mbuf);
296: (void)sleep(2);
297:
298: (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
299: if (killflg) {
300: (void)printf("\rbut you'll have to do it yourself\r\n");
301: finish();
302: }
303: if (dofast)
304: doitfast();
305: #ifdef DEBUG
306: if (doreboot)
307: (void)printf("reboot");
308: else if (dohalt)
309: (void)printf("halt");
310: if (nosync)
311: (void)printf(" no sync");
312: if (dofast)
313: (void)printf(" no fsck");
314: (void)printf("\nkill -HUP 1\n");
315: #else
316: if (doreboot) {
317: execle(_PATH_REBOOT, "reboot", "-l", nosync, 0);
318: syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_REBOOT);
319: perror("shutdown");
320: }
321: else if (dohalt) {
322: execle(_PATH_HALT, "halt", "-l", nosync, 0);
323: syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_HALT);
324: perror("shutdown");
325: }
326: (void)kill(1, SIGTERM); /* to single user */
327: #endif
328: finish();
329: }
330:
331: #define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2;
332:
333: getoffset(timearg)
334: register char *timearg;
335: {
336: register struct tm *lt;
337: register char *p;
338: time_t now, time();
339:
340: if (!strcasecmp(timearg, "now")) { /* now */
341: offset = 0;
342: return;
343: }
344:
345: (void)time(&now);
346: if (*timearg == '+') { /* +minutes */
347: if (!isdigit(*++timearg))
348: badtime();
349: offset = atoi(timearg) * 60;
350: shuttime = now + offset;
351: return;
352: }
353:
354: /* handle hh:mm by getting rid of the colon */
355: for (p = timearg; *p; ++p)
356: if (!isascii(*p) || !isdigit(*p))
357: if (*p == ':' && strlen(p) == 3) {
358: p[0] = p[1];
359: p[1] = p[2];
360: p[2] = '\0';
361: }
362: else
363: badtime();
364:
365: unsetenv("TZ"); /* OUR timezone */
366: lt = localtime(&now); /* current time val */
367:
368: switch(strlen(timearg)) {
369: case 10:
370: lt->tm_year = ATOI2(timearg);
371: /* FALLTHROUGH */
372: case 8:
373: lt->tm_mon = ATOI2(timearg);
374: if (--lt->tm_mon < 0 || lt->tm_mon > 11)
375: badtime();
376: /* FALLTHROUGH */
377: case 6:
378: lt->tm_mday = ATOI2(timearg);
379: if (lt->tm_mday < 1 || lt->tm_mday > 31)
380: badtime();
381: /* FALLTHROUGH */
382: case 4:
383: lt->tm_hour = ATOI2(timearg);
384: if (lt->tm_hour < 0 || lt->tm_hour > 23)
385: badtime();
386: lt->tm_min = ATOI2(timearg);
387: if (lt->tm_min < 0 || lt->tm_min > 59)
388: badtime();
389: lt->tm_sec = 0;
390: if ((shuttime = mktime(lt)) == -1)
391: badtime();
392: if ((offset = shuttime - now) < 0) {
393: (void)fprintf(stderr,
394: "shutdown: that time is already past.\n");
395: exit(1);
396: }
397: break;
398: default:
399: badtime();
400: }
401: }
402:
403: #define FSMSG "fastboot file for fsck\n"
404: doitfast()
405: {
406: int fastfd;
407:
408: if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC,
409: 0664)) >= 0) {
410: (void)write(fastfd, FSMSG, sizeof(FSMSG) - 1);
411: (void)close(fastfd);
412: }
413: }
414:
415: #define NOMSG "\n\nNO LOGINS: System going down at "
416: nolog()
417: {
418: int logfd;
419: char *ct, *ctime();
420: void finish();
421:
422: (void)unlink(_PATH_NOLOGIN); /* in case linked to another file */
423: (void)signal(SIGINT, finish);
424: (void)signal(SIGHUP, finish);
425: (void)signal(SIGQUIT, finish);
426: (void)signal(SIGTERM, finish);
427: if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
428: 0664)) >= 0) {
429: (void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
430: ct = ctime(&shuttime);
431: (void)write(logfd, ct + 11, 5);
432: (void)write(logfd, "\n\n", 2);
433: (void)write(logfd, mbuf, strlen(mbuf));
434: (void)close(logfd);
435: }
436: }
437:
438: void
439: finish()
440: {
441: (void)unlink(_PATH_NOLOGIN);
442: exit(0);
443: }
444:
445: badtime()
446: {
447: (void)fprintf(stderr, "shutdown: bad time format.\n");
448: exit(1);
449: }
450:
451: usage()
452: {
453: fprintf(stderr, "usage: shutdown [-fhknr] shutdowntime [ message ]\n");
454: exit(1);
455: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.