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