shutdown.c revision 92883
162587Sitojun/*
278064Sume * Copyright (c) 1988, 1990, 1993
362587Sitojun *	The Regents of the University of California.  All rights reserved.
454263Sshin *
554263Sshin * Redistribution and use in source and binary forms, with or without
654263Sshin * modification, are permitted provided that the following conditions
754263Sshin * are met:
854263Sshin * 1. Redistributions of source code must retain the above copyright
954263Sshin *    notice, this list of conditions and the following disclaimer.
1054263Sshin * 2. Redistributions in binary form must reproduce the above copyright
1154263Sshin *    notice, this list of conditions and the following disclaimer in the
1254263Sshin *    documentation and/or other materials provided with the distribution.
1354263Sshin * 3. All advertising materials mentioning features or use of this software
1454263Sshin *    must display the following acknowledgement:
1554263Sshin *	This product includes software developed by the University of
1654263Sshin *	California, Berkeley and its contributors.
1754263Sshin * 4. Neither the name of the University nor the names of its contributors
1854263Sshin *    may be used to endorse or promote products derived from this software
1954263Sshin *    without specific prior written permission.
2054263Sshin *
2154263Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2254263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2354263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2454263Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2554263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2654263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2754263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2854263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2954263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3054263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3154263Sshin * SUCH DAMAGE.
3254263Sshin */
3354263Sshin
3454263Sshin#ifndef lint
3554263Sshinstatic const char copyright[] =
3654263Sshin"@(#) Copyright (c) 1988, 1990, 1993\n\
3754263Sshin	The Regents of the University of California.  All rights reserved.\n";
3854263Sshin#endif /* not lint */
3954263Sshin
4054263Sshin#ifndef lint
4154263Sshin#if 0
4254263Sshinstatic char sccsid[] = "@(#)shutdown.c	8.4 (Berkeley) 4/28/95";
4354263Sshin#endif
4454263Sshinstatic const char rcsid[] =
4554263Sshin  "$FreeBSD: head/sbin/shutdown/shutdown.c 92883 2002-03-21 13:20:49Z imp $";
4662587Sitojun#endif /* not lint */
4779106Sbrooks
4879106Sbrooks#include <sys/param.h>
4979106Sbrooks#include <sys/time.h>
5054263Sshin#include <sys/resource.h>
5154263Sshin#include <sys/syslog.h>
5254263Sshin
5354263Sshin#include <ctype.h>
5454263Sshin#include <err.h>
5554263Sshin#include <fcntl.h>
5654263Sshin#include <pwd.h>
5754263Sshin#include <setjmp.h>
5854263Sshin#include <signal.h>
5954263Sshin#include <stdio.h>
6078064Sume#include <stdlib.h>
6178064Sume#include <string.h>
6254263Sshin#include <unistd.h>
6354263Sshin
6479106Sbrooks#include "pathnames.h"
6554263Sshin
6654263Sshin#ifdef DEBUG
6754263Sshin#undef _PATH_NOLOGIN
6854263Sshin#define	_PATH_NOLOGIN	"./nologin"
6954263Sshin#endif
7054263Sshin
7154263Sshin#define	H		*60*60
7254263Sshin#define	M		*60
7354263Sshin#define	S		*1
7454263Sshin#define	NOLOG_TIME	5*60
7562587Sitojunstruct interval {
7654263Sshin	int timeleft, timetowait;
7754263Sshin} tlist[] = {
7862587Sitojun	{ 10 H,  5 H },
7954263Sshin	{  5 H,  3 H },
8054263Sshin	{  2 H,  1 H },
8154263Sshin	{  1 H, 30 M },
8254263Sshin	{ 30 M, 10 M },
8379106Sbrooks	{ 20 M, 10 M },
8479106Sbrooks	{ 10 M,  5 M },
8562587Sitojun	{  5 M,  3 M },
8679106Sbrooks	{  2 M,  1 M },
8779106Sbrooks	{  1 M, 30 S },
8889065Smsmith	{ 30 S, 30 S },
8979106Sbrooks	{  0  ,  0   }
9083998Sbrooks};
9183998Sbrooks#undef H
9283998Sbrooks#undef M
9383998Sbrooks#undef S
9483998Sbrooks
9579106Sbrooksstatic time_t offset, shuttime;
9679106Sbrooksstatic int dohalt, dopower, doreboot, killflg, mbuflen, oflag;
9779106Sbrooksstatic char mbuf[BUFSIZ];
9879106Sbrooksstatic const char *nosync, *whom;
9979106Sbrooks
10079106Sbrooksvoid badtime(void);
10179106Sbrooksvoid die_you_gravy_sucking_pig_dog(void);
10279106Sbrooksvoid finish(int);
10362587Sitojunvoid getoffset(char *);
10479106Sbrooksvoid loop(void);
10562587Sitojunvoid nolog(void);
10679106Sbrooksvoid timeout(int);
10782884Sjulianvoid timewarn(int);
10879106Sbrooksvoid usage(const char *);
10979106Sbrooks
11079106Sbrooksint
11179106Sbrooksmain(argc, argv)
11279106Sbrooks	int argc;
11379106Sbrooks	char *argv[];
11462587Sitojun{
11562587Sitojun	char *p, *endp;
11679106Sbrooks	struct passwd *pw;
11779106Sbrooks	int arglen, ch, len, readstdin;
11879106Sbrooks
11979106Sbrooks#ifndef DEBUG
12079106Sbrooks	if (geteuid())
12179106Sbrooks		errx(1, "NOT super-user");
12279106Sbrooks#endif
12379106Sbrooks	nosync = NULL;
12462587Sitojun	readstdin = 0;
12554263Sshin	while ((ch = getopt(argc, argv, "-hknopr")) != -1)
12662587Sitojun		switch (ch) {
12762587Sitojun		case '-':
12862587Sitojun			readstdin = 1;
12962587Sitojun			break;
13062587Sitojun		case 'h':
13162587Sitojun			dohalt = 1;
13262587Sitojun			break;
13362587Sitojun		case 'k':
13462587Sitojun			killflg = 1;
13562587Sitojun			break;
13662587Sitojun		case 'n':
13762587Sitojun			nosync = "-n";
13862587Sitojun			break;
13979106Sbrooks		case 'o':
14079106Sbrooks			oflag = 1;
14179106Sbrooks			break;
14279106Sbrooks		case 'p':
14354263Sshin			dopower = 1;
14479106Sbrooks			break;
14578064Sume		case 'r':
14654263Sshin			doreboot = 1;
14779106Sbrooks			break;
14879106Sbrooks		case '?':
14962587Sitojun		default:
15079106Sbrooks			usage((char *)NULL);
15179106Sbrooks		}
15279106Sbrooks	argc -= optind;
15379106Sbrooks	argv += optind;
15479106Sbrooks
15579106Sbrooks	if (argc < 1)
15679106Sbrooks		usage((char *)NULL);
15779106Sbrooks
15879106Sbrooks	if (killflg + doreboot + dohalt + dopower > 1)
15979106Sbrooks		usage("incompatible switches -h, -k, -p and -r");
16079106Sbrooks
16179106Sbrooks	if (oflag && !(dohalt || dopower || doreboot))
16279106Sbrooks		usage("-o requires -h, -p or -r");
16379106Sbrooks
16479106Sbrooks	if (nosync != NULL && !oflag)
16579106Sbrooks		usage("-n requires -o");
16679106Sbrooks
16779106Sbrooks	getoffset(*argv++);
16879106Sbrooks
16979106Sbrooks	if (*argv) {
17079106Sbrooks		for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
17179106Sbrooks			arglen = strlen(*argv);
17262587Sitojun			if ((len -= arglen) <= 2)
17379106Sbrooks				break;
17479106Sbrooks			if (p != mbuf)
17579106Sbrooks				*p++ = ' ';
17679106Sbrooks			memmove(p, *argv, arglen);
17779106Sbrooks			p += arglen;
17879106Sbrooks		}
17979106Sbrooks		*p = '\n';
18062587Sitojun		*++p = '\0';
18162587Sitojun	}
18279106Sbrooks
18379106Sbrooks	if (readstdin) {
18479106Sbrooks		p = mbuf;
18579106Sbrooks		endp = mbuf + sizeof(mbuf) - 2;
18679106Sbrooks		for (;;) {
18779106Sbrooks			if (!fgets(p, endp - p + 1, stdin))
18862587Sitojun				break;
18979106Sbrooks			for (; *p &&  p < endp; ++p);
19079106Sbrooks			if (p == endp) {
19179106Sbrooks				*p = '\n';
19279106Sbrooks				*++p = '\0';
19362587Sitojun				break;
19462587Sitojun			}
19579106Sbrooks		}
19679106Sbrooks	}
19778064Sume	mbuflen = strlen(mbuf);
19879106Sbrooks
19979106Sbrooks	if (offset)
20078064Sume		(void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
20179106Sbrooks	else
20279106Sbrooks		(void)printf("Shutdown NOW!\n");
20379106Sbrooks
20479106Sbrooks	if (!(whom = getlogin()))
20579106Sbrooks		whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
20679106Sbrooks
20783998Sbrooks#ifdef DEBUG
20883998Sbrooks	(void)putc('\n', stdout);
20983997Sbrooks#else
21079106Sbrooks	(void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
21179106Sbrooks	{
21279106Sbrooks		int forkpid;
21379106Sbrooks
21479106Sbrooks		forkpid = fork();
21579106Sbrooks		if (forkpid == -1)
21679106Sbrooks			err(1, "fork");
21779106Sbrooks		if (forkpid)
21879106Sbrooks			errx(0, "[pid %d]", forkpid);
21979106Sbrooks	}
22079106Sbrooks	setsid();
22183997Sbrooks#endif
22279106Sbrooks	openlog("shutdown", LOG_CONS, LOG_AUTH);
22379106Sbrooks	loop();
22479106Sbrooks	return(0);
22579106Sbrooks}
22679106Sbrooks
22779106Sbrooksvoid
22879106Sbrooksloop()
22979106Sbrooks{
23079106Sbrooks	struct interval *tp;
23183998Sbrooks	u_int sltime;
23283998Sbrooks	int logged;
23379106Sbrooks
23479106Sbrooks	if (offset <= NOLOG_TIME) {
23579106Sbrooks		logged = 1;
23679106Sbrooks		nolog();
23779106Sbrooks	}
23879106Sbrooks	else
23979106Sbrooks		logged = 0;
24079106Sbrooks	tp = tlist;
24179106Sbrooks	if (tp->timeleft < offset)
24279106Sbrooks		(void)sleep((u_int)(offset - tp->timeleft));
24379106Sbrooks	else {
24479106Sbrooks		while (tp->timeleft && offset < tp->timeleft)
24579106Sbrooks			++tp;
24679106Sbrooks		/*
24779106Sbrooks		 * Warn now, if going to sleep more than a fifth of
24879106Sbrooks		 * the next wait time.
24979106Sbrooks		 */
25079106Sbrooks		if ((sltime = offset - tp->timeleft)) {
25179106Sbrooks			if (sltime > (u_int)(tp->timetowait / 5))
25279106Sbrooks				timewarn(offset);
25379106Sbrooks			(void)sleep(sltime);
25479106Sbrooks		}
25579106Sbrooks	}
25679106Sbrooks	for (;; ++tp) {
25779106Sbrooks		timewarn(tp->timeleft);
25879106Sbrooks		if (!logged && tp->timeleft <= NOLOG_TIME) {
25979106Sbrooks			logged = 1;
26079106Sbrooks			nolog();
26179106Sbrooks		}
26279106Sbrooks		(void)sleep((u_int)tp->timetowait);
26379106Sbrooks		if (!tp->timeleft)
26483997Sbrooks			break;
26579106Sbrooks	}
26679106Sbrooks	die_you_gravy_sucking_pig_dog();
26779106Sbrooks}
26879106Sbrooks
26962587Sitojunstatic jmp_buf alarmbuf;
27079106Sbrooks
27179106Sbrooksstatic const char *restricted_environ[] = {
27279106Sbrooks	"PATH=" _PATH_STDPATH,
27379106Sbrooks	NULL
27479106Sbrooks};
27583997Sbrooks
27683997Sbrooksvoid
27779106Sbrookstimewarn(timeleft)
27879106Sbrooks	int timeleft;
27979106Sbrooks{
28079106Sbrooks	static int first;
28179106Sbrooks	static char hostname[MAXHOSTNAMELEN + 1];
28279106Sbrooks	FILE *pf;
28362587Sitojun	char wcmd[MAXPATHLEN + 4];
28479106Sbrooks	extern const char **environ;
28554263Sshin
28679106Sbrooks	if (!first++)
28754263Sshin		(void)gethostname(hostname, sizeof(hostname));
28854263Sshin
28979106Sbrooks	/* undoc -n option to wall suppresses normal wall banner */
29079106Sbrooks	(void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL);
29179106Sbrooks	environ = restricted_environ;
29279106Sbrooks	if (!(pf = popen(wcmd, "w"))) {
29379106Sbrooks		syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
29454263Sshin		return;
29579106Sbrooks	}
29683997Sbrooks
29779106Sbrooks	(void)fprintf(pf,
29862587Sitojun	    "\007*** %sSystem shutdown message from %s@%s ***\007\n",
29962587Sitojun	    timeleft ? "": "FINAL ", whom, hostname);
30062587Sitojun
30162587Sitojun	if (timeleft > 10*60)
30262587Sitojun		(void)fprintf(pf, "System going down at %5.5s\n\n",
30362587Sitojun		    ctime(&shuttime) + 11);
30462587Sitojun	else if (timeleft > 59)
30562587Sitojun		(void)fprintf(pf, "System going down in %d minute%s\n\n",
30662587Sitojun		    timeleft / 60, (timeleft > 60) ? "s" : "");
30762587Sitojun	else if (timeleft)
30862587Sitojun		(void)fprintf(pf, "System going down in 30 seconds\n\n");
30962587Sitojun	else
31062587Sitojun		(void)fprintf(pf, "System going down IMMEDIATELY\n\n");
31162587Sitojun
31262587Sitojun	if (mbuflen)
31362587Sitojun		(void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
31462587Sitojun
31562587Sitojun	/*
31662587Sitojun	 * play some games, just in case wall doesn't come back
31762587Sitojun	 * probably unnecessary, given that wall is careful.
31862587Sitojun	 */
31962587Sitojun	if (!setjmp(alarmbuf)) {
32062587Sitojun		(void)signal(SIGALRM, timeout);
32162587Sitojun		(void)alarm((u_int)30);
32262587Sitojun		(void)pclose(pf);
32362587Sitojun		(void)alarm((u_int)0);
32462587Sitojun		(void)signal(SIGALRM, SIG_DFL);
32562587Sitojun	}
32662587Sitojun}
32762587Sitojun
32862587Sitojunvoid
32962587Sitojuntimeout(signo)
33062587Sitojun	int signo __unused;
33162587Sitojun{
33262587Sitojun	longjmp(alarmbuf, 1);
33362587Sitojun}
33462587Sitojun
33562587Sitojunvoid
33662587Sitojundie_you_gravy_sucking_pig_dog()
33762587Sitojun{
33862587Sitojun	char *empty_environ[] = { NULL };
33962587Sitojun
34062587Sitojun	syslog(LOG_NOTICE, "%s by %s: %s",
34162587Sitojun	    doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" :
34262587Sitojun	    "shutdown", whom, mbuf);
34362587Sitojun	(void)sleep(2);
34462587Sitojun
34562587Sitojun	(void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
34662587Sitojun	if (killflg) {
34762587Sitojun		(void)printf("\rbut you'll have to do it yourself\r\n");
34862587Sitojun		exit(0);
34962587Sitojun	}
35062587Sitojun#ifdef DEBUG
35162587Sitojun	if (doreboot)
35262587Sitojun		(void)printf("reboot");
35362587Sitojun	else if (dohalt)
35462587Sitojun		(void)printf("halt");
35554263Sshin	else if (dopower)
35654263Sshin		(void)printf("power-down");
35754263Sshin	if (nosync != NULL)
35854263Sshin		(void)printf(" no sync");
35954263Sshin	(void)printf("\nkill -HUP 1\n");
36054263Sshin#else
36154263Sshin	if (!oflag) {
36278064Sume		(void)kill(1, doreboot ? SIGINT :	/* reboot */
36354263Sshin			      dohalt ? SIGUSR1 :	/* halt */
36454263Sshin			      dopower ? SIGUSR2 :	/* power-down */
36554263Sshin			      SIGTERM);			/* single-user */
36654263Sshin	} else {
36754263Sshin		if (doreboot) {
36854263Sshin			execle(_PATH_REBOOT, "reboot", "-l", nosync,
36954263Sshin				(char *)NULL, empty_environ);
37054263Sshin			syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
37154263Sshin				_PATH_REBOOT);
37254263Sshin			warn(_PATH_REBOOT);
37362587Sitojun		}
37454263Sshin		else if (dohalt) {
37554263Sshin			execle(_PATH_HALT, "halt", "-l", nosync,
37654263Sshin				(char *)NULL, empty_environ);
37754263Sshin			syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
37854263Sshin				_PATH_HALT);
37954263Sshin			warn(_PATH_HALT);
38054263Sshin		}
38162587Sitojun		else if (dopower) {
38254263Sshin			execle(_PATH_HALT, "halt", "-l", "-p", nosync,
38354263Sshin				(char *)NULL, empty_environ);
38454263Sshin			syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
38554263Sshin				_PATH_HALT);
38654263Sshin			warn(_PATH_HALT);
38754263Sshin		}
38854263Sshin		(void)kill(1, SIGTERM);		/* to single-user */
38954263Sshin	}
39054263Sshin#endif
39154263Sshin	finish(0);
39254263Sshin}
39354263Sshin
39454263Sshin#define	ATOI2(p)	(p[0] - '0') * 10 + (p[1] - '0'); p += 2;
39554263Sshin
39654263Sshinvoid
39754263Sshingetoffset(timearg)
39854263Sshin	char *timearg;
39978064Sume{
40054263Sshin	struct tm *lt;
40154263Sshin	char *p;
40254263Sshin	time_t now;
40354263Sshin	int this_year;
40462587Sitojun
40554263Sshin	(void)time(&now);
40654263Sshin
40762587Sitojun	if (!strcasecmp(timearg, "now")) {		/* now */
40854263Sshin		offset = 0;
40954263Sshin		shuttime = now;
41078064Sume		return;
41178064Sume	}
41262587Sitojun
41362587Sitojun	if (*timearg == '+') {				/* +minutes */
41478064Sume		if (!isdigit(*++timearg))
41554263Sshin			badtime();
41654263Sshin		if ((offset = atoi(timearg) * 60) < 0)
41754263Sshin			badtime();
41854263Sshin		shuttime = now + offset;
41954263Sshin		return;
42054263Sshin	}
42154263Sshin
42254263Sshin	/* handle hh:mm by getting rid of the colon */
42354263Sshin	for (p = timearg; *p; ++p)
42454263Sshin		if (!isascii(*p) || !isdigit(*p)) {
42554263Sshin			if (*p == ':' && strlen(p) == 3) {
42654263Sshin				p[0] = p[1];
42762587Sitojun				p[1] = p[2];
42854263Sshin				p[2] = '\0';
42978064Sume			}
43054263Sshin			else
43154263Sshin				badtime();
43254263Sshin		}
43354263Sshin
43478064Sume	unsetenv("TZ");					/* OUR timezone */
43578064Sume	lt = localtime(&now);				/* current time val */
43654263Sshin
43754263Sshin	switch(strlen(timearg)) {
43854263Sshin	case 10:
43954263Sshin		this_year = lt->tm_year;
44054263Sshin		lt->tm_year = ATOI2(timearg);
44154263Sshin		/*
44254263Sshin		 * check if the specified year is in the next century.
44354263Sshin		 * allow for one year of user error as many people will
44454263Sshin		 * enter n - 1 at the start of year n.
44569152Sjlemon		 */
44678064Sume		if (lt->tm_year < (this_year % 100) - 1)
44754263Sshin			lt->tm_year += 100;
44854263Sshin		/* adjust for the year 2000 and beyond */
44954263Sshin		lt->tm_year += (this_year - (this_year % 100));
45054263Sshin		/* FALLTHROUGH */
45154263Sshin	case 8:
45254263Sshin		lt->tm_mon = ATOI2(timearg);
45354263Sshin		if (--lt->tm_mon < 0 || lt->tm_mon > 11)
45462587Sitojun			badtime();
45562587Sitojun		/* FALLTHROUGH */
45654263Sshin	case 6:
45754263Sshin		lt->tm_mday = ATOI2(timearg);
45854263Sshin		if (lt->tm_mday < 1 || lt->tm_mday > 31)
45954263Sshin			badtime();
46054263Sshin		/* FALLTHROUGH */
46154263Sshin	case 4:
46254263Sshin		lt->tm_hour = ATOI2(timearg);
46354263Sshin		if (lt->tm_hour < 0 || lt->tm_hour > 23)
46454263Sshin			badtime();
46578064Sume		lt->tm_min = ATOI2(timearg);
46662587Sitojun		if (lt->tm_min < 0 || lt->tm_min > 59)
46754263Sshin			badtime();
46854263Sshin		lt->tm_sec = 0;
46978064Sume		if ((shuttime = mktime(lt)) == -1)
47062587Sitojun			badtime();
47154263Sshin		if ((offset = shuttime - now) < 0)
47254263Sshin			errx(1, "that time is already past.");
47354263Sshin		break;
47483998Sbrooks	default:
47583998Sbrooks		badtime();
47683998Sbrooks	}
47783998Sbrooks}
47883998Sbrooks
47983998Sbrooks#define	NOMSG	"\n\nNO LOGINS: System going down at "
48054263Sshinvoid
48154263Sshinnolog()
48254263Sshin{
48354263Sshin	int logfd;
48454263Sshin	char *ct;
48554263Sshin
48654263Sshin	(void)unlink(_PATH_NOLOGIN);	/* in case linked to another file */
48754263Sshin	(void)signal(SIGINT, finish);
48854263Sshin	(void)signal(SIGHUP, finish);
48954263Sshin	(void)signal(SIGQUIT, finish);
49054263Sshin	(void)signal(SIGTERM, finish);
49154263Sshin	if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
49254263Sshin	    0664)) >= 0) {
49354263Sshin		(void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
49454263Sshin		ct = ctime(&shuttime);
49554263Sshin		(void)write(logfd, ct + 11, 5);
49654263Sshin		(void)write(logfd, "\n\n", 2);
49754263Sshin		(void)write(logfd, mbuf, strlen(mbuf));
49854263Sshin		(void)close(logfd);
49954263Sshin	}
50054263Sshin}
50154263Sshin
50254263Sshinvoid
50354263Sshinfinish(signo)
50454263Sshin	int signo __unused;
50554263Sshin{
50683998Sbrooks	if (!killflg)
50783998Sbrooks		(void)unlink(_PATH_NOLOGIN);
50883998Sbrooks	exit(0);
50983998Sbrooks}
51054263Sshin
51154263Sshinvoid
51254263Sshinbadtime()
51369152Sjlemon{
51469152Sjlemon	errx(1, "bad time format");
51569152Sjlemon}
51654263Sshin
51754263Sshinvoid
51854263Sshinusage(cp)
51954263Sshin	const char *cp;
52054263Sshin{
52154263Sshin	if (cp != NULL)
52262587Sitojun		warnx("%s", cp);
52354263Sshin	(void)fprintf(stderr,
52454263Sshin	    "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]"
52554263Sshin	    " time [warning-message ...]\n");
52654263Sshin	exit(1);
52754263Sshin}
52854263Sshin