shutdown.c revision 201180
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1988, 1990, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3238036Scharnierstatic const char copyright[] = 331558Srgrimes"@(#) Copyright (c) 1988, 1990, 1993\n\ 341558Srgrimes The Regents of the University of California. All rights reserved.\n"; 351558Srgrimes#endif /* not lint */ 361558Srgrimes 371558Srgrimes#ifndef lint 3841684Sbdestatic char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95"; 39114589Sobrien#endif /* not lint */ 4038036Scharnier#endif 41114589Sobrien#include <sys/cdefs.h> 42114589Sobrien__FBSDID("$FreeBSD: head/sbin/shutdown/shutdown.c 201180 2009-12-29 08:49:43Z ed $"); 431558Srgrimes 441558Srgrimes#include <sys/param.h> 451558Srgrimes#include <sys/time.h> 461558Srgrimes#include <sys/resource.h> 471558Srgrimes#include <sys/syslog.h> 481558Srgrimes 491558Srgrimes#include <ctype.h> 5038036Scharnier#include <err.h> 511558Srgrimes#include <fcntl.h> 52114763Sobrien#include <paths.h> 531558Srgrimes#include <pwd.h> 541558Srgrimes#include <setjmp.h> 551558Srgrimes#include <signal.h> 561558Srgrimes#include <stdio.h> 571558Srgrimes#include <stdlib.h> 581558Srgrimes#include <string.h> 591558Srgrimes#include <unistd.h> 601558Srgrimes 611558Srgrimes#ifdef DEBUG 621558Srgrimes#undef _PATH_NOLOGIN 631558Srgrimes#define _PATH_NOLOGIN "./nologin" 641558Srgrimes#endif 651558Srgrimes 661558Srgrimes#define H *60*60 671558Srgrimes#define M *60 681558Srgrimes#define S *1 691558Srgrimes#define NOLOG_TIME 5*60 701558Srgrimesstruct interval { 711558Srgrimes int timeleft, timetowait; 721558Srgrimes} tlist[] = { 7332399Salex { 10 H, 5 H }, 7432399Salex { 5 H, 3 H }, 7532399Salex { 2 H, 1 H }, 7632399Salex { 1 H, 30 M }, 7732399Salex { 30 M, 10 M }, 7832399Salex { 20 M, 10 M }, 7932399Salex { 10 M, 5 M }, 8032399Salex { 5 M, 3 M }, 8132399Salex { 2 M, 1 M }, 8232399Salex { 1 M, 30 S }, 8332399Salex { 30 S, 30 S }, 8432399Salex { 0 , 0 } 851558Srgrimes}; 861558Srgrimes#undef H 871558Srgrimes#undef M 881558Srgrimes#undef S 891558Srgrimes 901558Srgrimesstatic time_t offset, shuttime; 9148078Srustatic int dohalt, dopower, doreboot, killflg, mbuflen, oflag; 9279749Sddstatic char mbuf[BUFSIZ]; 9379749Sddstatic const char *nosync, *whom; 941558Srgrimes 95197560Sdelphijstatic void badtime(void); 96201180Sedstatic void perform_shutdown(void); 97197560Sdelphijstatic void finish(int); 98197560Sdelphijstatic void getoffset(char *); 99197560Sdelphijstatic void loop(void); 100197560Sdelphijstatic void nolog(void); 101197560Sdelphijstatic void timeout(int); 102197560Sdelphijstatic void timewarn(int); 103197560Sdelphijstatic void usage(const char *); 1041558Srgrimes 105140796Sdelphijextern const char **environ; 106140796Sdelphij 1071558Srgrimesint 108140796Sdelphijmain(int argc, char **argv) 1091558Srgrimes{ 11079749Sdd char *p, *endp; 1111558Srgrimes struct passwd *pw; 1121558Srgrimes int arglen, ch, len, readstdin; 1131558Srgrimes 1141558Srgrimes#ifndef DEBUG 11526737Scharnier if (geteuid()) 11626737Scharnier errx(1, "NOT super-user"); 1171558Srgrimes#endif 1181558Srgrimes nosync = NULL; 1191558Srgrimes readstdin = 0; 12048078Sru while ((ch = getopt(argc, argv, "-hknopr")) != -1) 1211558Srgrimes switch (ch) { 1221558Srgrimes case '-': 1231558Srgrimes readstdin = 1; 1241558Srgrimes break; 1251558Srgrimes case 'h': 1261558Srgrimes dohalt = 1; 1271558Srgrimes break; 1281558Srgrimes case 'k': 1291558Srgrimes killflg = 1; 1301558Srgrimes break; 1311558Srgrimes case 'n': 1321558Srgrimes nosync = "-n"; 1331558Srgrimes break; 13448078Sru case 'o': 13548078Sru oflag = 1; 13648078Sru break; 13741666Smsmith case 'p': 13841666Smsmith dopower = 1; 13941666Smsmith break; 1401558Srgrimes case 'r': 1411558Srgrimes doreboot = 1; 1421558Srgrimes break; 1431558Srgrimes case '?': 1441558Srgrimes default: 14548078Sru usage((char *)NULL); 1461558Srgrimes } 1471558Srgrimes argc -= optind; 1481558Srgrimes argv += optind; 1491558Srgrimes 1501558Srgrimes if (argc < 1) 15148078Sru usage((char *)NULL); 1521558Srgrimes 15348078Sru if (killflg + doreboot + dohalt + dopower > 1) 15448078Sru usage("incompatible switches -h, -k, -p and -r"); 15548062Sjkoshy 15648078Sru if (oflag && !(dohalt || dopower || doreboot)) 15748078Sru usage("-o requires -h, -p or -r"); 15848062Sjkoshy 15948078Sru if (nosync != NULL && !oflag) 16048078Sru usage("-n requires -o"); 16148078Sru 1621558Srgrimes getoffset(*argv++); 1631558Srgrimes 1641558Srgrimes if (*argv) { 1651558Srgrimes for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) { 1661558Srgrimes arglen = strlen(*argv); 1671558Srgrimes if ((len -= arglen) <= 2) 1681558Srgrimes break; 1691558Srgrimes if (p != mbuf) 1701558Srgrimes *p++ = ' '; 17141684Sbde memmove(p, *argv, arglen); 1721558Srgrimes p += arglen; 1731558Srgrimes } 1741558Srgrimes *p = '\n'; 1751558Srgrimes *++p = '\0'; 1761558Srgrimes } 1771558Srgrimes 1781558Srgrimes if (readstdin) { 1791558Srgrimes p = mbuf; 1801558Srgrimes endp = mbuf + sizeof(mbuf) - 2; 1811558Srgrimes for (;;) { 1821558Srgrimes if (!fgets(p, endp - p + 1, stdin)) 1831558Srgrimes break; 1841558Srgrimes for (; *p && p < endp; ++p); 1851558Srgrimes if (p == endp) { 1861558Srgrimes *p = '\n'; 1871558Srgrimes *++p = '\0'; 1881558Srgrimes break; 1891558Srgrimes } 1901558Srgrimes } 1911558Srgrimes } 1921558Srgrimes mbuflen = strlen(mbuf); 1931558Srgrimes 1941558Srgrimes if (offset) 1951558Srgrimes (void)printf("Shutdown at %.24s.\n", ctime(&shuttime)); 1961558Srgrimes else 1971558Srgrimes (void)printf("Shutdown NOW!\n"); 1981558Srgrimes 1991558Srgrimes if (!(whom = getlogin())) 2001558Srgrimes whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 2011558Srgrimes 2021558Srgrimes#ifdef DEBUG 2031558Srgrimes (void)putc('\n', stdout); 2041558Srgrimes#else 2051558Srgrimes (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN); 2061558Srgrimes { 2071558Srgrimes int forkpid; 2081558Srgrimes 2091558Srgrimes forkpid = fork(); 21026737Scharnier if (forkpid == -1) 21126737Scharnier err(1, "fork"); 21226737Scharnier if (forkpid) 21326737Scharnier errx(0, "[pid %d]", forkpid); 2141558Srgrimes } 21528613Sjoerg setsid(); 2161558Srgrimes#endif 2171558Srgrimes openlog("shutdown", LOG_CONS, LOG_AUTH); 2181558Srgrimes loop(); 21938036Scharnier return(0); 2201558Srgrimes} 2211558Srgrimes 222197560Sdelphijstatic void 223197560Sdelphijloop(void) 2241558Srgrimes{ 2251558Srgrimes struct interval *tp; 2261558Srgrimes u_int sltime; 2271558Srgrimes int logged; 2281558Srgrimes 2291558Srgrimes if (offset <= NOLOG_TIME) { 2301558Srgrimes logged = 1; 2311558Srgrimes nolog(); 2321558Srgrimes } 2331558Srgrimes else 2341558Srgrimes logged = 0; 2351558Srgrimes tp = tlist; 2361558Srgrimes if (tp->timeleft < offset) 2371558Srgrimes (void)sleep((u_int)(offset - tp->timeleft)); 2381558Srgrimes else { 23948004Sru while (tp->timeleft && offset < tp->timeleft) 2401558Srgrimes ++tp; 2411558Srgrimes /* 2421558Srgrimes * Warn now, if going to sleep more than a fifth of 2431558Srgrimes * the next wait time. 2441558Srgrimes */ 24532399Salex if ((sltime = offset - tp->timeleft)) { 24679749Sdd if (sltime > (u_int)(tp->timetowait / 5)) 2471558Srgrimes timewarn(offset); 2481558Srgrimes (void)sleep(sltime); 2491558Srgrimes } 2501558Srgrimes } 2511558Srgrimes for (;; ++tp) { 2521558Srgrimes timewarn(tp->timeleft); 2531558Srgrimes if (!logged && tp->timeleft <= NOLOG_TIME) { 2541558Srgrimes logged = 1; 2551558Srgrimes nolog(); 2561558Srgrimes } 2571558Srgrimes (void)sleep((u_int)tp->timetowait); 2581558Srgrimes if (!tp->timeleft) 2591558Srgrimes break; 2601558Srgrimes } 261201180Sed perform_shutdown(); 2621558Srgrimes} 2631558Srgrimes 2641558Srgrimesstatic jmp_buf alarmbuf; 2651558Srgrimes 26679749Sddstatic const char *restricted_environ[] = { 26732399Salex "PATH=" _PATH_STDPATH, 26832399Salex NULL 26932399Salex}; 27032399Salex 271197560Sdelphijstatic void 272140797Sdelphijtimewarn(int timeleft) 2731558Srgrimes{ 2741558Srgrimes static int first; 2751558Srgrimes static char hostname[MAXHOSTNAMELEN + 1]; 2761558Srgrimes FILE *pf; 2771558Srgrimes char wcmd[MAXPATHLEN + 4]; 2781558Srgrimes 2791558Srgrimes if (!first++) 2801558Srgrimes (void)gethostname(hostname, sizeof(hostname)); 2811558Srgrimes 2821558Srgrimes /* undoc -n option to wall suppresses normal wall banner */ 2831558Srgrimes (void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL); 28432399Salex environ = restricted_environ; 2851558Srgrimes if (!(pf = popen(wcmd, "w"))) { 2861558Srgrimes syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL); 2871558Srgrimes return; 2881558Srgrimes } 2891558Srgrimes 2901558Srgrimes (void)fprintf(pf, 2911558Srgrimes "\007*** %sSystem shutdown message from %s@%s ***\007\n", 2921558Srgrimes timeleft ? "": "FINAL ", whom, hostname); 2931558Srgrimes 2941558Srgrimes if (timeleft > 10*60) 2951558Srgrimes (void)fprintf(pf, "System going down at %5.5s\n\n", 2961558Srgrimes ctime(&shuttime) + 11); 2971558Srgrimes else if (timeleft > 59) 2981558Srgrimes (void)fprintf(pf, "System going down in %d minute%s\n\n", 2991558Srgrimes timeleft / 60, (timeleft > 60) ? "s" : ""); 3001558Srgrimes else if (timeleft) 3011558Srgrimes (void)fprintf(pf, "System going down in 30 seconds\n\n"); 3021558Srgrimes else 3031558Srgrimes (void)fprintf(pf, "System going down IMMEDIATELY\n\n"); 3041558Srgrimes 3051558Srgrimes if (mbuflen) 3061558Srgrimes (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf); 3071558Srgrimes 3081558Srgrimes /* 3091558Srgrimes * play some games, just in case wall doesn't come back 31038036Scharnier * probably unnecessary, given that wall is careful. 3111558Srgrimes */ 3121558Srgrimes if (!setjmp(alarmbuf)) { 3131558Srgrimes (void)signal(SIGALRM, timeout); 3141558Srgrimes (void)alarm((u_int)30); 3151558Srgrimes (void)pclose(pf); 3161558Srgrimes (void)alarm((u_int)0); 3171558Srgrimes (void)signal(SIGALRM, SIG_DFL); 3181558Srgrimes } 3191558Srgrimes} 3201558Srgrimes 321197560Sdelphijstatic void 322140797Sdelphijtimeout(int signo __unused) 3231558Srgrimes{ 3241558Srgrimes longjmp(alarmbuf, 1); 3251558Srgrimes} 3261558Srgrimes 327197560Sdelphijstatic void 328201180Sedperform_shutdown(void) 3291558Srgrimes{ 33032399Salex char *empty_environ[] = { NULL }; 3311558Srgrimes 3321558Srgrimes syslog(LOG_NOTICE, "%s by %s: %s", 33341666Smsmith doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" : 33441666Smsmith "shutdown", whom, mbuf); 3351558Srgrimes (void)sleep(2); 3361558Srgrimes 3371558Srgrimes (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n"); 3381558Srgrimes if (killflg) { 3391558Srgrimes (void)printf("\rbut you'll have to do it yourself\r\n"); 3404844Sats exit(0); 3411558Srgrimes } 3421558Srgrimes#ifdef DEBUG 3431558Srgrimes if (doreboot) 3441558Srgrimes (void)printf("reboot"); 3451558Srgrimes else if (dohalt) 3461558Srgrimes (void)printf("halt"); 34741666Smsmith else if (dopower) 34841666Smsmith (void)printf("power-down"); 34948078Sru if (nosync != NULL) 3501558Srgrimes (void)printf(" no sync"); 3511558Srgrimes (void)printf("\nkill -HUP 1\n"); 3521558Srgrimes#else 35348078Sru if (!oflag) { 35448078Sru (void)kill(1, doreboot ? SIGINT : /* reboot */ 35548078Sru dohalt ? SIGUSR1 : /* halt */ 35648078Sru dopower ? SIGUSR2 : /* power-down */ 35748078Sru SIGTERM); /* single-user */ 35848078Sru } else { 35948078Sru if (doreboot) { 36048078Sru execle(_PATH_REBOOT, "reboot", "-l", nosync, 36148078Sru (char *)NULL, empty_environ); 36248078Sru syslog(LOG_ERR, "shutdown: can't exec %s: %m.", 36348078Sru _PATH_REBOOT); 36448078Sru warn(_PATH_REBOOT); 36548078Sru } 36648078Sru else if (dohalt) { 36748078Sru execle(_PATH_HALT, "halt", "-l", nosync, 36848078Sru (char *)NULL, empty_environ); 36948078Sru syslog(LOG_ERR, "shutdown: can't exec %s: %m.", 37048078Sru _PATH_HALT); 37148078Sru warn(_PATH_HALT); 37248078Sru } 37348078Sru else if (dopower) { 37448078Sru execle(_PATH_HALT, "halt", "-l", "-p", nosync, 37548078Sru (char *)NULL, empty_environ); 37648078Sru syslog(LOG_ERR, "shutdown: can't exec %s: %m.", 37748078Sru _PATH_HALT); 37848078Sru warn(_PATH_HALT); 37948078Sru } 38048078Sru (void)kill(1, SIGTERM); /* to single-user */ 3811558Srgrimes } 3821558Srgrimes#endif 3831558Srgrimes finish(0); 3841558Srgrimes} 3851558Srgrimes 3861558Srgrimes#define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2; 3871558Srgrimes 388197560Sdelphijstatic void 389140797Sdelphijgetoffset(char *timearg) 3901558Srgrimes{ 39179749Sdd struct tm *lt; 39279749Sdd char *p; 3931558Srgrimes time_t now; 39432328Salex int this_year; 3951558Srgrimes 39648062Sjkoshy (void)time(&now); 39748062Sjkoshy 3981558Srgrimes if (!strcasecmp(timearg, "now")) { /* now */ 3991558Srgrimes offset = 0; 40048062Sjkoshy shuttime = now; 4011558Srgrimes return; 4021558Srgrimes } 4031558Srgrimes 4041558Srgrimes if (*timearg == '+') { /* +minutes */ 4051558Srgrimes if (!isdigit(*++timearg)) 4061558Srgrimes badtime(); 40748004Sru if ((offset = atoi(timearg) * 60) < 0) 40848004Sru badtime(); 4091558Srgrimes shuttime = now + offset; 4101558Srgrimes return; 4111558Srgrimes } 4121558Srgrimes 4131558Srgrimes /* handle hh:mm by getting rid of the colon */ 4141558Srgrimes for (p = timearg; *p; ++p) 41548956Sbillf if (!isascii(*p) || !isdigit(*p)) { 4161558Srgrimes if (*p == ':' && strlen(p) == 3) { 4171558Srgrimes p[0] = p[1]; 4181558Srgrimes p[1] = p[2]; 4191558Srgrimes p[2] = '\0'; 4201558Srgrimes } 4211558Srgrimes else 4221558Srgrimes badtime(); 42348956Sbillf } 4241558Srgrimes 4251558Srgrimes unsetenv("TZ"); /* OUR timezone */ 4261558Srgrimes lt = localtime(&now); /* current time val */ 4271558Srgrimes 4281558Srgrimes switch(strlen(timearg)) { 4291558Srgrimes case 10: 43032328Salex this_year = lt->tm_year; 4311558Srgrimes lt->tm_year = ATOI2(timearg); 43232328Salex /* 43332328Salex * check if the specified year is in the next century. 43432328Salex * allow for one year of user error as many people will 43532328Salex * enter n - 1 at the start of year n. 43632328Salex */ 43732328Salex if (lt->tm_year < (this_year % 100) - 1) 43832328Salex lt->tm_year += 100; 43932329Salex /* adjust for the year 2000 and beyond */ 44032328Salex lt->tm_year += (this_year - (this_year % 100)); 4411558Srgrimes /* FALLTHROUGH */ 4421558Srgrimes case 8: 4431558Srgrimes lt->tm_mon = ATOI2(timearg); 4441558Srgrimes if (--lt->tm_mon < 0 || lt->tm_mon > 11) 4451558Srgrimes badtime(); 4461558Srgrimes /* FALLTHROUGH */ 4471558Srgrimes case 6: 4481558Srgrimes lt->tm_mday = ATOI2(timearg); 4491558Srgrimes if (lt->tm_mday < 1 || lt->tm_mday > 31) 4501558Srgrimes badtime(); 4511558Srgrimes /* FALLTHROUGH */ 4521558Srgrimes case 4: 4531558Srgrimes lt->tm_hour = ATOI2(timearg); 4541558Srgrimes if (lt->tm_hour < 0 || lt->tm_hour > 23) 4551558Srgrimes badtime(); 4561558Srgrimes lt->tm_min = ATOI2(timearg); 4571558Srgrimes if (lt->tm_min < 0 || lt->tm_min > 59) 4581558Srgrimes badtime(); 4591558Srgrimes lt->tm_sec = 0; 4601558Srgrimes if ((shuttime = mktime(lt)) == -1) 4611558Srgrimes badtime(); 46226737Scharnier if ((offset = shuttime - now) < 0) 46326737Scharnier errx(1, "that time is already past."); 4641558Srgrimes break; 4651558Srgrimes default: 4661558Srgrimes badtime(); 4671558Srgrimes } 4681558Srgrimes} 4691558Srgrimes 4701558Srgrimes#define NOMSG "\n\nNO LOGINS: System going down at " 471197560Sdelphijstatic void 472197560Sdelphijnolog(void) 4731558Srgrimes{ 4741558Srgrimes int logfd; 4751558Srgrimes char *ct; 4761558Srgrimes 4771558Srgrimes (void)unlink(_PATH_NOLOGIN); /* in case linked to another file */ 4781558Srgrimes (void)signal(SIGINT, finish); 4791558Srgrimes (void)signal(SIGHUP, finish); 4801558Srgrimes (void)signal(SIGQUIT, finish); 4811558Srgrimes (void)signal(SIGTERM, finish); 4821558Srgrimes if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC, 4831558Srgrimes 0664)) >= 0) { 4841558Srgrimes (void)write(logfd, NOMSG, sizeof(NOMSG) - 1); 4851558Srgrimes ct = ctime(&shuttime); 4861558Srgrimes (void)write(logfd, ct + 11, 5); 4871558Srgrimes (void)write(logfd, "\n\n", 2); 4881558Srgrimes (void)write(logfd, mbuf, strlen(mbuf)); 4891558Srgrimes (void)close(logfd); 4901558Srgrimes } 4911558Srgrimes} 4921558Srgrimes 493197560Sdelphijstatic void 494140797Sdelphijfinish(int signo __unused) 4951558Srgrimes{ 49641684Sbde if (!killflg) 49741684Sbde (void)unlink(_PATH_NOLOGIN); 4981558Srgrimes exit(0); 4991558Srgrimes} 5001558Srgrimes 501197560Sdelphijstatic void 502201180Sedbadtime(void) 5031558Srgrimes{ 50438036Scharnier errx(1, "bad time format"); 5051558Srgrimes} 5061558Srgrimes 507197560Sdelphijstatic void 508140797Sdelphijusage(const char *cp) 5091558Srgrimes{ 51048078Sru if (cp != NULL) 51148078Sru warnx("%s", cp); 51248078Sru (void)fprintf(stderr, 51348078Sru "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]" 51448078Sru " time [warning-message ...]\n"); 5151558Srgrimes exit(1); 5161558Srgrimes} 517