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