shutdown.c revision 1.36
1199989Srdivacky/*	$OpenBSD: shutdown.c,v 1.36 2009/12/24 10:06:35 sobrado Exp $	*/
2199989Srdivacky/*	$NetBSD: shutdown.c,v 1.9 1995/03/18 15:01:09 cgd Exp $	*/
3199989Srdivacky
4199989Srdivacky/*
5199989Srdivacky * Copyright (c) 1988, 1990, 1993
6199989Srdivacky *	The Regents of the University of California.  All rights reserved.
7199989Srdivacky *
8199989Srdivacky * Redistribution and use in source and binary forms, with or without
9199989Srdivacky * modification, are permitted provided that the following conditions
10199989Srdivacky * are met:
11199989Srdivacky * 1. Redistributions of source code must retain the above copyright
12199989Srdivacky *    notice, this list of conditions and the following disclaimer.
13199989Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
14199989Srdivacky *    notice, this list of conditions and the following disclaimer in the
15199989Srdivacky *    documentation and/or other materials provided with the distribution.
16199989Srdivacky * 3. Neither the name of the University nor the names of its contributors
17199989Srdivacky *    may be used to endorse or promote products derived from this software
18199989Srdivacky *    without specific prior written permission.
19199989Srdivacky *
20199989Srdivacky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21199989Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22199989Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23199989Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24199989Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25199989Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26199989Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27199989Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28199989Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29199989Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30199989Srdivacky * SUCH DAMAGE.
31199989Srdivacky */
32199989Srdivacky
33199989Srdivacky#include <sys/param.h>
34199989Srdivacky#include <sys/resource.h>
35199989Srdivacky#include <sys/syslog.h>
36199989Srdivacky#include <sys/types.h>
37199989Srdivacky#include <sys/wait.h>
38199989Srdivacky
39207618Srdivacky#include <ctype.h>
40199989Srdivacky#include <fcntl.h>
41199989Srdivacky#include <sys/termios.h>
42199989Srdivacky#include <pwd.h>
43199989Srdivacky#include <setjmp.h>
44199989Srdivacky#include <signal.h>
45199989Srdivacky#include <stdio.h>
46199989Srdivacky#include <stdlib.h>
47199989Srdivacky#include <string.h>
48199989Srdivacky#include <time.h>
49199989Srdivacky#include <tzfile.h>
50199989Srdivacky#include <unistd.h>
51199989Srdivacky#include <errno.h>
52199989Srdivacky#include <err.h>
53199989Srdivacky
54199989Srdivacky#include "pathnames.h"
55199989Srdivacky
56199989Srdivacky#ifdef DEBUG
57199989Srdivacky#undef _PATH_NOLOGIN
58199989Srdivacky#define	_PATH_NOLOGIN	"./nologin"
59199989Srdivacky#undef _PATH_FASTBOOT
60199989Srdivacky#define	_PATH_FASTBOOT	"./fastboot"
61199989Srdivacky#endif
62207618Srdivacky
63199989Srdivacky#define	H		*60*60
64199989Srdivacky#define	M		*60
65199989Srdivacky#define	S		*1
66199989Srdivacky#define	NOLOG_TIME	5*60
67199989Srdivackystruct interval {
68199989Srdivacky	int timeleft, timetowait;
69199989Srdivacky} tlist[] = {
70199989Srdivacky	{ 10 H,  5 H },
71199989Srdivacky	{  5 H,  3 H },
72199989Srdivacky	{  2 H,  1 H },
73199989Srdivacky	{  1 H, 30 M },
74199989Srdivacky	{ 30 M, 10 M },
75199989Srdivacky	{ 20 M, 10 M },
76199989Srdivacky	{ 10 M,  5 M },
77199989Srdivacky	{  5 M,  3 M },
78199989Srdivacky	{  2 M,  1 M },
79199989Srdivacky	{  1 M, 30 S },
80199989Srdivacky	{ 30 S, 30 S },
81199989Srdivacky	{    0,    0 }
82199989Srdivacky};
83199989Srdivacky#undef H
84199989Srdivacky#undef M
85199989Srdivacky#undef S
86199989Srdivacky
87199989Srdivackystatic time_t offset, shuttime;
88199989Srdivackystatic int dofast, dohalt, doreboot, dopower, dodump, mbuflen, nosync;
89199989Srdivackystatic sig_atomic_t killflg;
90199989Srdivackystatic char *whom, mbuf[BUFSIZ];
91199989Srdivacky
92201360Srdivackyvoid badtime(void);
93199989Srdivackyvoid __dead die_you_gravy_sucking_pig_dog(void);
94199989Srdivackyvoid doitfast(void);
95199989Srdivackyvoid __dead finish(int);
96199989Srdivackyvoid getoffset(char *);
97199989Srdivackyvoid __dead loop(void);
98201360Srdivackyvoid nolog(void);
99199989Srdivackyvoid timeout(int);
100199989Srdivackyvoid timewarn(int);
101199989Srdivackyvoid usage(void);
102199989Srdivacky
103199989Srdivackyint
104199989Srdivackymain(int argc, char *argv[])
105199989Srdivacky{
106199989Srdivacky	int arglen, ch, len, readstdin = 0;
107201360Srdivacky	struct passwd *pw;
108201360Srdivacky	char *p, *endp;
109201360Srdivacky	pid_t forkpid;
110201360Srdivacky
111199989Srdivacky#ifndef DEBUG
112199989Srdivacky	if (geteuid())
113199989Srdivacky		errx(1, "NOT super-user");
114199989Srdivacky#endif
115199989Srdivacky	while ((ch = getopt(argc, argv, "dfhknpr-")) != -1)
116199989Srdivacky		switch (ch) {
117199989Srdivacky		case '-':
118199989Srdivacky			readstdin = 1;
119199989Srdivacky			break;
120199989Srdivacky		case 'd':
121199989Srdivacky			dodump = 1;
122199989Srdivacky			break;
123199989Srdivacky		case 'f':
124199989Srdivacky			dofast = 1;
125199989Srdivacky			break;
126199989Srdivacky		case 'h':
127199989Srdivacky			dohalt = 1;
128199989Srdivacky			break;
129199989Srdivacky		case 'k':
130199989Srdivacky			killflg = 1;
131199989Srdivacky			break;
132199989Srdivacky		case 'n':
133199989Srdivacky			nosync = 1;
134199989Srdivacky			break;
135199989Srdivacky		case 'p':
136199989Srdivacky			dopower = 1;
137199989Srdivacky			break;
138199989Srdivacky		case 'r':
139199989Srdivacky			doreboot = 1;
140199989Srdivacky			break;
141199989Srdivacky		default:
142199989Srdivacky			usage();
143199989Srdivacky		}
144199989Srdivacky	argc -= optind;
145207618Srdivacky	argv += optind;
146207618Srdivacky
147199989Srdivacky	if (argc < 1)
148199989Srdivacky		usage();
149199989Srdivacky
150199989Srdivacky	if (dofast && nosync) {
151199989Srdivacky		(void)fprintf(stderr,
152199989Srdivacky		    "shutdown: incompatible switches -f and -n.\n");
153207618Srdivacky		usage();
154207618Srdivacky	}
155199989Srdivacky	if (doreboot && dohalt) {
156199989Srdivacky		(void)fprintf(stderr,
157199989Srdivacky		    "shutdown: incompatible switches -h and -r.\n");
158199989Srdivacky		usage();
159199989Srdivacky	}
160199989Srdivacky	if (dopower && !dohalt) {
161199989Srdivacky		(void)fprintf(stderr,
162199989Srdivacky		    "shutdown: switch -p must be used with -h.\n");
163199989Srdivacky		usage();
164199989Srdivacky	}
165202375Srdivacky	getoffset(*argv++);
166199989Srdivacky
167199989Srdivacky	if (*argv) {
168199989Srdivacky		for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
169199989Srdivacky			arglen = strlen(*argv);
170199989Srdivacky			if ((len -= arglen) <= 2)
171199989Srdivacky				break;
172199989Srdivacky			if (p != mbuf)
173199989Srdivacky				*p++ = ' ';
174202375Srdivacky			memcpy(p, *argv, arglen);
175199989Srdivacky			p += arglen;
176199989Srdivacky		}
177199989Srdivacky		*p = '\n';
178199989Srdivacky		*++p = '\0';
179202375Srdivacky	}
180199989Srdivacky
181199989Srdivacky	if (readstdin) {
182199989Srdivacky		p = mbuf;
183199989Srdivacky		endp = mbuf + sizeof(mbuf) - 2;
184199989Srdivacky		for (;;) {
185207618Srdivacky			if (!fgets(p, endp - p + 1, stdin))
186207618Srdivacky				break;
187199989Srdivacky			for (; *p &&  p < endp; ++p)
188199989Srdivacky				;
189199989Srdivacky			if (p == endp) {
190199989Srdivacky				*p = '\n';
191199989Srdivacky				*++p = '\0';
192199989Srdivacky				break;
193199989Srdivacky			}
194199989Srdivacky		}
195199989Srdivacky	}
196207618Srdivacky	mbuflen = strlen(mbuf);
197199989Srdivacky
198199989Srdivacky	if (offset)
199199989Srdivacky		(void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
200199989Srdivacky	else
201199989Srdivacky		(void)printf("Shutdown NOW!\n");
202199989Srdivacky
203199989Srdivacky	if (!(whom = getlogin()))
204199989Srdivacky		whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
205199989Srdivacky
206199989Srdivacky#ifdef DEBUG
207199989Srdivacky	(void)putc('\n', stdout);
208199989Srdivacky#else
209199989Srdivacky	(void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
210199989Srdivacky
211199989Srdivacky	forkpid = fork();
212199989Srdivacky	if (forkpid == -1)
213199989Srdivacky		err(1, "fork");
214199989Srdivacky	if (forkpid) {
215199989Srdivacky		(void)printf("shutdown: [pid %ld]\n", (long)forkpid);
216199989Srdivacky		exit(0);
217199989Srdivacky	}
218207618Srdivacky	setsid();
219199989Srdivacky#endif
220199989Srdivacky	openlog("shutdown", LOG_CONS, LOG_AUTH);
221199989Srdivacky	loop();
222199989Srdivacky	/* NOTREACHED */
223207618Srdivacky}
224199989Srdivacky
225199989Srdivackyvoid
226199989Srdivackyloop(void)
227199989Srdivacky{
228199989Srdivacky	struct interval *tp;
229199989Srdivacky	u_int sltime;
230199989Srdivacky	int logged;
231199989Srdivacky
232199989Srdivacky	if (offset <= NOLOG_TIME) {
233202375Srdivacky		logged = 1;
234202375Srdivacky		nolog();
235199989Srdivacky	} else
236199989Srdivacky		logged = 0;
237199989Srdivacky	tp = tlist;
238199989Srdivacky	if (tp->timeleft < offset)
239199989Srdivacky		(void)sleep((u_int)(offset - tp->timeleft));
240207618Srdivacky	else {
241199989Srdivacky		while (offset < tp->timeleft)
242199989Srdivacky			++tp;
243199989Srdivacky		/*
244199989Srdivacky		 * Warn now, if going to sleep more than a fifth of
245199989Srdivacky		 * the next wait time.
246199989Srdivacky		 */
247199989Srdivacky		if ((sltime = offset - tp->timeleft)) {
248207618Srdivacky			if (sltime > tp->timetowait / 5)
249199989Srdivacky				timewarn(offset);
250199989Srdivacky			(void)sleep(sltime);
251199989Srdivacky		}
252199989Srdivacky	}
253199989Srdivacky	for (;; ++tp) {
254199989Srdivacky		timewarn(tp->timeleft);
255199989Srdivacky		if (!logged && tp->timeleft <= NOLOG_TIME) {
256199989Srdivacky			logged = 1;
257199989Srdivacky			nolog();
258199989Srdivacky		}
259199989Srdivacky		(void)sleep((u_int)tp->timetowait);
260207618Srdivacky		if (!tp->timeleft)
261207618Srdivacky			break;
262199989Srdivacky	}
263199989Srdivacky	die_you_gravy_sucking_pig_dog();
264199989Srdivacky}
265199989Srdivacky
266199989Srdivackystatic jmp_buf alarmbuf;
267199989Srdivacky
268199989Srdivackystatic char *restricted_environ[] = {
269199989Srdivacky	"PATH=" _PATH_STDPATH,
270199989Srdivacky	NULL
271199989Srdivacky};
272199989Srdivacky
273199989Srdivackyvoid
274199989Srdivackytimewarn(int timeleft)
275199989Srdivacky{
276199989Srdivacky	static char hostname[MAXHOSTNAMELEN];
277199989Srdivacky	char wcmd[MAXPATHLEN + 4];
278207618Srdivacky	extern char **environ;
279199989Srdivacky	static int first;
280199989Srdivacky	FILE *pf;
281199989Srdivacky
282199989Srdivacky	if (!first++)
283199989Srdivacky		(void)gethostname(hostname, sizeof(hostname));
284199989Srdivacky
285199989Srdivacky	/* undoc -n option to wall suppresses normal wall banner */
286199989Srdivacky	(void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL);
287199989Srdivacky	environ = restricted_environ;
288199989Srdivacky	if (!(pf = popen(wcmd, "w"))) {
289199989Srdivacky		syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
290199989Srdivacky		return;
291199989Srdivacky	}
292199989Srdivacky
293199989Srdivacky	(void)fprintf(pf,
294199989Srdivacky	    "\007*** %sSystem shutdown message from %s@%s ***\007\n",
295199989Srdivacky	    timeleft ? "": "FINAL ", whom, hostname);
296199989Srdivacky
297199989Srdivacky	if (timeleft > 10*60)
298199989Srdivacky		(void)fprintf(pf, "System going down at %5.5s\n\n",
299207618Srdivacky		    ctime(&shuttime) + 11);
300199989Srdivacky	else if (timeleft > 59)
301207618Srdivacky		(void)fprintf(pf, "System going down in %d minute%s\n\n",
302207618Srdivacky		    timeleft / 60, (timeleft > 60) ? "s" : "");
303206124Srdivacky	else if (timeleft)
304199989Srdivacky		(void)fprintf(pf, "System going down in 30 seconds\n\n");
305199989Srdivacky	else
306199989Srdivacky		(void)fprintf(pf, "System going down IMMEDIATELY\n\n");
307199989Srdivacky
308207618Srdivacky	if (mbuflen)
309199989Srdivacky		(void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
310199989Srdivacky
311199989Srdivacky	/*
312199989Srdivacky	 * play some games, just in case wall doesn't come back
313199989Srdivacky	 * probably unnecessary, given that wall is careful.
314199989Srdivacky	 */
315199989Srdivacky	if (!setjmp(alarmbuf)) {
316199989Srdivacky		(void)signal(SIGALRM, timeout);
317199989Srdivacky		(void)alarm((u_int)30);
318199989Srdivacky		(void)pclose(pf);
319199989Srdivacky		(void)alarm((u_int)0);
320199989Srdivacky		(void)signal(SIGALRM, SIG_DFL);
321199989Srdivacky	}
322199989Srdivacky}
323199989Srdivacky
324199989Srdivackyvoid
325199989Srdivackytimeout(int signo)
326199989Srdivacky{
327199989Srdivacky	longjmp(alarmbuf, 1);		/* XXX signal/longjmp resource leaks */
328199989Srdivacky}
329199989Srdivacky
330199989Srdivackyvoid
331201360Srdivackydie_you_gravy_sucking_pig_dog(void)
332201360Srdivacky{
333207618Srdivacky
334199989Srdivacky	syslog(LOG_NOTICE, "%s by %s: %s",
335203954Srdivacky	    doreboot ? "reboot" : dohalt ? "halt" : "shutdown", whom, mbuf);
336203954Srdivacky	(void)sleep(2);
337203954Srdivacky
338203954Srdivacky	(void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
339203954Srdivacky	if (killflg) {
340207618Srdivacky		(void)printf("\rbut you'll have to do it yourself\r\n");
341199989Srdivacky		finish(0);
342207618Srdivacky	}
343199989Srdivacky	if (dofast)
344199989Srdivacky		doitfast();
345199989Srdivacky#ifdef DEBUG
346199989Srdivacky	if (doreboot)
347199989Srdivacky		(void)printf("reboot");
348199989Srdivacky	else if (dohalt)
349199989Srdivacky		(void)printf("halt");
350199989Srdivacky	if (nosync)
351199989Srdivacky		(void)printf(" no sync");
352199989Srdivacky	if (dofast)
353199989Srdivacky		(void)printf(" no fsck");
354199989Srdivacky	if (dodump)
355199989Srdivacky		(void)printf(" with dump");
356207618Srdivacky	(void)printf("\nkill -HUP 1\n");
357199989Srdivacky#else
358207618Srdivacky	if (doreboot) {
359207618Srdivacky		execle(_PATH_REBOOT, "reboot", "-l",
360199989Srdivacky		    (nosync ? "-n" : (dodump ? "-d" : NULL)),
361207618Srdivacky		    (dodump ? "-d" : NULL), (char *)NULL, (char *)NULL);
362207618Srdivacky		syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_REBOOT);
363199989Srdivacky		warn(_PATH_REBOOT);
364207618Srdivacky	}
365207618Srdivacky	else if (dohalt) {
366207618Srdivacky		execle(_PATH_HALT, "halt", "-l",
367207618Srdivacky		    (dopower ? "-p" : (nosync ? "-n" : (dodump ? "-d" : NULL))),
368199989Srdivacky		    (nosync ? "-n" : (dodump ? "-d" : NULL)),
369199989Srdivacky		    (dodump ? "-d" : NULL), (char *)NULL, (char *)NULL);
370199989Srdivacky		syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_HALT);
371199989Srdivacky		warn(_PATH_HALT);
372207618Srdivacky	}
373207618Srdivacky	if (access(_PATH_RC, R_OK) != -1) {
374207618Srdivacky		pid_t pid;
375207618Srdivacky		struct termios t;
376207618Srdivacky		int fd;
377199989Srdivacky
378199989Srdivacky		switch ((pid = fork())) {
379199989Srdivacky		case -1:
380199989Srdivacky			break;
381207618Srdivacky		case 0:
382207618Srdivacky			if (revoke(_PATH_CONSOLE) == -1)
383207618Srdivacky				perror("revoke");
384199989Srdivacky			if (setsid() == -1)
385199989Srdivacky				perror("setsid");
386207618Srdivacky			fd = open(_PATH_CONSOLE, O_RDWR);
387207618Srdivacky			if (fd == -1)
388207618Srdivacky				perror("open");
389199989Srdivacky			dup2(fd, 0);
390199989Srdivacky			dup2(fd, 1);
391207618Srdivacky			dup2(fd, 2);
392207618Srdivacky			if (fd > 2)
393207618Srdivacky				close(fd);
394199989Srdivacky
395199989Srdivacky			/* At a minimum... */
396207618Srdivacky			tcgetattr(0, &t);
397207618Srdivacky			t.c_oflag |= (ONLCR | OPOST);
398207618Srdivacky			tcsetattr(0, TCSANOW, &t);
399199989Srdivacky
400207618Srdivacky			execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL);
401207618Srdivacky			_exit(1);
402207618Srdivacky		default:
403199989Srdivacky			waitpid(pid, NULL, 0);
404199989Srdivacky		}
405207618Srdivacky	}
406207618Srdivacky	(void)kill(1, SIGTERM);		/* to single user */
407199989Srdivacky#endif
408207618Srdivacky	finish(0);
409207618Srdivacky}
410199989Srdivacky
411199989Srdivacky#define	ATOI2(p)	(p[0] - '0') * 10 + (p[1] - '0'); p += 2;
412199989Srdivacky
413207618Srdivackyvoid
414207618Srdivackygetoffset(char *timearg)
415199989Srdivacky{
416207618Srdivacky	struct tm *lt;
417207618Srdivacky	int this_year;
418207618Srdivacky	time_t now;
419207618Srdivacky	char *p;
420207618Srdivacky
421207618Srdivacky	if (!strcasecmp(timearg, "now")) {		/* now */
422207618Srdivacky		offset = 0;
423207618Srdivacky		return;
424207618Srdivacky	}
425207618Srdivacky
426207618Srdivacky	(void)time(&now);
427207618Srdivacky	if (*timearg == '+') {				/* +minutes */
428207618Srdivacky		if (!isdigit(*++timearg))
429207618Srdivacky			badtime();
430207618Srdivacky		offset = atoi(timearg) * 60;
431207618Srdivacky		shuttime = now + offset;
432207618Srdivacky		return;
433207618Srdivacky	}
434207618Srdivacky
435207618Srdivacky	/* handle hh:mm by getting rid of the colon */
436207618Srdivacky	for (p = timearg; *p; ++p) {
437207618Srdivacky		if (!isascii(*p) || !isdigit(*p)) {
438199989Srdivacky			if (*p == ':' && strlen(p) == 3) {
439207618Srdivacky				p[0] = p[1];
440207618Srdivacky				p[1] = p[2];
441207618Srdivacky				p[2] = '\0';
442207618Srdivacky			} else
443207618Srdivacky				badtime();
444207618Srdivacky		}
445207618Srdivacky	}
446207618Srdivacky
447207618Srdivacky	unsetenv("TZ");					/* OUR timezone */
448207618Srdivacky	lt = localtime(&now);				/* current time val */
449207618Srdivacky
450207618Srdivacky	switch (strlen(timearg)) {
451199989Srdivacky	case 10:
452207618Srdivacky		this_year = lt->tm_year;
453207618Srdivacky		lt->tm_year = ATOI2(timearg);
454207618Srdivacky		/*
455199989Srdivacky		 * check if the specified year is in the next century.
456207618Srdivacky		 * allow for one year of user error as many people will
457207618Srdivacky		 * enter n - 1 at the start of year n.
458199989Srdivacky		 */
459207618Srdivacky		if (lt->tm_year < (this_year % 100) - 1)
460207618Srdivacky			lt->tm_year += 100;
461199989Srdivacky		/* adjust for the year 2000 and beyond */
462207618Srdivacky		lt->tm_year += (this_year - (this_year % 100));
463207618Srdivacky		/* FALLTHROUGH */
464207618Srdivacky	case 8:
465207618Srdivacky		lt->tm_mon = ATOI2(timearg);
466207618Srdivacky		if (--lt->tm_mon < 0 || lt->tm_mon > 11)
467207618Srdivacky			badtime();
468201360Srdivacky		/* FALLTHROUGH */
469207618Srdivacky	case 6:
470207618Srdivacky		lt->tm_mday = ATOI2(timearg);
471207618Srdivacky		if (lt->tm_mday < 1 || lt->tm_mday > 31)
472199989Srdivacky			badtime();
473207618Srdivacky		/* FALLTHROUGH */
474207618Srdivacky	case 4:
475207618Srdivacky		lt->tm_hour = ATOI2(timearg);
476207618Srdivacky		if (lt->tm_hour < 0 || lt->tm_hour > 23)
477207618Srdivacky			badtime();
478207618Srdivacky		lt->tm_min = ATOI2(timearg);
479199989Srdivacky		if (lt->tm_min < 0 || lt->tm_min > 59)
480207618Srdivacky			badtime();
481207618Srdivacky		lt->tm_sec = 0;
482207618Srdivacky		if ((shuttime = mktime(lt)) == -1)
483207618Srdivacky			badtime();
484199989Srdivacky		if ((offset = shuttime - now) < 0)
485207618Srdivacky			errx(1, "that time is already past.");
486199989Srdivacky		break;
487199989Srdivacky	default:
488207618Srdivacky		badtime();
489199989Srdivacky	}
490199989Srdivacky}
491199989Srdivacky
492207618Srdivacky#define	FSMSG	"fastboot file for fsck\n"
493207618Srdivackyvoid
494207618Srdivackydoitfast(void)
495207618Srdivacky{
496207618Srdivacky	int fastfd;
497207618Srdivacky
498207618Srdivacky	if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC,
499207618Srdivacky	    0664)) >= 0) {
500207618Srdivacky		(void)write(fastfd, FSMSG, sizeof(FSMSG) - 1);
501207618Srdivacky		(void)close(fastfd);
502207618Srdivacky	}
503207618Srdivacky}
504199989Srdivacky
505199989Srdivacky#define	NOMSG	"\n\nNO LOGINS: System going down at "
506199989Srdivackyvoid
507199989Srdivackynolog(void)
508199989Srdivacky{
509	int logfd;
510	char *ct;
511
512	(void)unlink(_PATH_NOLOGIN);	/* in case linked to another file */
513	(void)signal(SIGINT, finish);
514	(void)signal(SIGHUP, finish);
515	(void)signal(SIGQUIT, finish);
516	(void)signal(SIGTERM, finish);
517	if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
518	    0664)) >= 0) {
519		(void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
520		ct = ctime(&shuttime);
521		(void)write(logfd, ct + 11, 5);
522		(void)write(logfd, "\n\n", 2);
523		(void)write(logfd, mbuf, strlen(mbuf));
524		(void)close(logfd);
525	}
526}
527
528void
529finish(int signo)
530{
531	if (!killflg)
532		(void)unlink(_PATH_NOLOGIN);
533	if (signo == 0)
534		exit(0);
535	else
536		_exit(0);
537}
538
539void
540badtime(void)
541{
542	errx(1, "bad time format.");
543}
544
545void
546usage(void)
547{
548	fprintf(stderr, "usage: shutdown [-] [-dfhknpr] time [warning-message ...]\n");
549	exit(1);
550}
551