4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
40 #pragma ident "%Z%%M% %I% %E% SMI"
49 #include <sys/resource.h>
50 #include <sys/param.h>
51 #include <sys/types.h>
52 #include <sys/errno.h>
54 #include <rpc/pmap_clnt.h>
55 #include <rpcsvc/mount.h>
56 #include <rpcsvc/rwall.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
61 #include <sys/syslog.h>
66 * /usr/etc/shutdown when [messages]
68 * allow super users to tell users and remind users
69 * of iminent shutdown of unix
70 * and shut it down automatically
71 * and even reboot or halt the machine if they desire
74 #define EPATH "PATH=/usr/ucb:/usr/bin:/usr/sbin:"
75 #define REBOOT "/usr/sbin/reboot"
76 #define HALT "/usr/sbin/halt"
81 #define NLOG 600 /* no of bytes possible for message */
82 #define NOLOGTIME 5 MINUTES
83 #define IGNOREUSER "sleeper"
90 char hostname
[MAXHOSTNAMELEN
];
93 extern char *malloc();
96 extern struct tm
*localtime();
98 extern char *strcpy();
99 extern char *strncat();
100 extern off_t
lseek();
106 char tpath
[] = "/dev/";
107 int nlflag
= 1; /* nolog yet to be done */
113 char nosyncflag
[] = "-n";
114 char term
[sizeof tpath
+ sizeof (utmpx
->ut_line
)];
116 char nolog1
[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
119 char fastboot
[] = "fastboot";
121 char fastboot
[] = "/fastboot";
123 char nologin
[] = "/etc/nologin";
134 30 MINUTES
, 10 MINUTES
,
135 15 MINUTES
, 5 MINUTES
,
136 10 MINUTES
, 5 MINUTES
,
137 5 MINUTES
, 3 MINUTES
,
138 2 MINUTES
, 1 MINUTES
,
139 1 MINUTES
, 30 SECONDS
,
143 char *msg1
= "shutdown: '%c' - unknown flag\n";
144 char *msg2
= "Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n";
145 char *msg3
= "Usage: shutdown [ -krhfn ] shutdowntime [ message ]";
146 char *msg4
= "Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n";
147 char *msg5
= "Usage: shutdown [ -krhfn ] shutdowntime [ message ]";
148 char *msg6
= "\n\007\007System shutdown time has arrived\007\007\n";
149 char *msg7
= "but you'll have to do it yourself\n";
150 char *msg8
= "but you'll have to do it yourself";
151 char *msg9
= "-l (without fsck's)\n";
152 char *msg10
= "-l %s\n";
153 char *msg11
= " (without fsck's)\n";
154 char *msg12
= "That must be tomorrow\nCan't you wait till then?\n";
155 char *msg13
= "That must be tomorrow";
156 char *msg14
= "Can't you wait till then?";
157 char *msg15
= "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n";
158 char *msg16
= "System going down at %5.5s\r\n";
159 char *msg17
= "System going down in %d minute%s\r\n";
160 char *msg18
= "System going down in %d second%s\r\n";
161 char *msg19
= "System going down IMMEDIATELY\r\n";
162 char *msg20
= "Can't get PID for init\n";
164 char *shutter
, *getlogin();
166 static void timeout(void);
167 static void gethostlist(void);
168 static void finish(char *, char *, int);
169 static void nolog(time_t);
170 static void rprintf(char *, char *);
171 static void rwarn(char *, time_t, time_t, char *, int);
172 static void doitfast(void);
173 static void warn(FILE *, time_t, time_t, char *, int);
174 static time_t getsdt(char *);
181 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID
, &init_pid
,
182 sizeof (init_pid
)) != sizeof (init_pid
)) {
183 (void) fprintf(stderr
, gettext(msg20
));
190 main(int argc
, char **argv
)
200 struct passwd
*pw
, *getpwuid();
201 extern char *strcat();
202 extern uid_t
geteuid();
204 char *shutdown_program
;
205 char *shutdown_action
;
208 (void) setlocale(LC_ALL
, "");
210 #if !defined(TEXT_DOMAIN)
211 #define TEXT_DOMAIN "SYS_TEST"
213 (void) textdomain(TEXT_DOMAIN
);
215 audit_shutdown_setup(argc
, argv
);
217 shutter
= getlogin();
218 if (shutter
== 0 && (pw
= getpwuid(getuid())))
219 shutter
= pw
->pw_name
;
222 (void) gethostname(hostname
, sizeof (hostname
));
223 openlog("shutdown", 0, LOG_AUTH
);
225 while (argc
> 0 && (f
= argv
[0], *f
++ == '-')) {
244 (void) fprintf(stderr
, gettext(msg1
),
246 (void) fprintf(stderr
, gettext(msg2
));
247 finish(gettext(msg3
), "", 1);
253 (void) fprintf(stderr
, gettext(msg4
));
254 finish(gettext(msg5
), "", 1);
256 if (doreboot
&& halt
) {
257 (void) fprintf(stderr
,
258 gettext("shutdown: Incompatible switches '-r' & '-h'\n"));
259 finish(gettext("shutdown: Incompatible switches '-r' & '-h'"),
262 if (fast
&& (nosync
== nosyncflag
)) {
263 (void) fprintf(stderr
,
264 gettext("shutdown: Incompatible switches '-f' & '-n'\n"));
265 finish(gettext("shutdown: Incompatible switches '-f' & '-n'"),
269 (void) fprintf(stderr
, gettext("shutdown: NOT super-user\n"));
270 finish(gettext("shutdown: NOT super-user"), "", 1);
273 nowtime
= time((time_t *)NULL
);
274 sdt
= getsdt(argv
[0]);
279 if (i
+ strlen(*argv
) > NLOG
)
280 break; /* no more room for the message */
281 i
+= strlen(*argv
) + 1;
282 (void) strcat(mesg
, *argv
++);
283 (void) strcat(mesg
, " ");
286 mesg
[i
- 1] = '\0'; /* remove trailing blank */
287 m
= ((stogo
= sdt
- nowtime
) + 30)/60;
291 (void) printf(gettext("Shutdown at %5.5s (in "), ts
+11);
293 (void) printf("%d hour%s ", h
, h
!= 1 ? "s" : "");
294 (void) printf("%d minute%s) ", m
, m
!= 1 ? "s" : "");
296 (void) signal(SIGHUP
, SIG_IGN
);
297 (void) signal(SIGQUIT
, SIG_IGN
);
298 (void) signal(SIGINT
, SIG_IGN
);
300 (void) signal(SIGTTOU
, SIG_IGN
);
301 (void) signal(SIGINT
, finish_sig
);
302 (void) signal(SIGALRM
, (void(*)())timeout
);
303 (void) setpriority(PRIO_PROCESS
, 0, PRIO_MIN
);
304 (void) fflush(stdout
);
307 (void) printf(gettext("[pid %d]\n"), i
);
311 (void) putc('\n', stdout
);
317 shutdown_program
= REBOOT
;
318 shutdown_action
= "reboot";
320 shutdown_program
= HALT
;
321 shutdown_action
= "halt";
323 shutdown_program
= NULL
;
324 shutdown_action
= "shutdown";
327 for (i
= 0; stogo
<= interval
[i
].stogo
&& interval
[i
].sint
; i
++)
328 sint
= interval
[i
].sint
;
329 if (stogo
> 0 && (stogo
-sint
) < interval
[i
].stogo
)
330 sint
= stogo
- interval
[i
].stogo
;
331 if (stogo
<= NOLOGTIME
&& nlflag
) {
335 if (sint
>= stogo
|| sint
== 0)
337 nowtime
= time((time_t *)NULL
);
341 while ((utmpx
= getutxent()) != NULL
) {
342 if (utmpx
->ut_name
[0] &&
343 strncmp(utmpx
->ut_name
, IGNOREUSER
,
344 sizeof (utmpx
->ut_name
))) {
346 * don't write to pty's unless they're rlogin sessions
348 if (utmpx
->ut_type
!= USER_PROCESS
&&
349 utmpx
->ut_user
[0] != '\0')
352 if (setjmp(alarmbuf
))
354 (void) strcpy(term
, tpath
);
355 (void) strncat(term
, utmpx
->ut_line
,
356 sizeof (utmpx
->ut_line
));
359 /* check if device is really a tty */
360 if ((fd
= open(term
, O_WRONLY
|O_NOCTTY
)) == -1) {
361 fprintf(stderr
, gettext("Cannot open %s.\n"),
368 gettext("%.*s in utmpx is not a tty\n"),
369 sizeof (utmpx
->ut_line
), utmpx
->ut_line
);
370 syslog(LOG_CRIT
, "%.*s in utmpx is not "
371 "a tty\n", sizeof (utmpx
->ut_line
),
380 if ((termf
= stdout
) != NULL
)
382 if ((termf
= fopen(term
, "w")) != NULL
)
387 (void) fprintf(termf
, "\n\r\n");
388 warn(termf
, sdt
, nowtime
, f
, first
);
391 (void) fflush(termf
);
393 (void) fclose(termf
);
402 for (hl
= hostlist
; hl
!= NULL
; hl
= hl
->nxt
)
403 rwarn(hl
->host
, sdt
, nowtime
, f
, first
);
405 (void) printf(gettext(msg6
));
407 syslog(LOG_CRIT
, "%s by %s: %s",
408 shutdown_action
, shutter
, mesg
);
410 syslog(LOG_CRIT
, "%s by %s",
411 shutdown_action
, shutter
);
413 (void) unlink(nologin
);
415 (void) printf(gettext(msg7
));
416 finish(gettext(msg8
), "", 0);
421 (void) putenv(EPATH
);
422 if (shutdown_program
!= NULL
) {
423 audit_shutdown_success();
424 execlp(shutdown_program
, shutdown_program
,
425 "-l", nosync
, (char *)0);
427 if (geteuid() == 0) {
428 audit_shutdown_success();
431 if (getzoneid() == GLOBAL_ZONEID
) {
433 "/sbin/bootadm -a update_all");
436 (void) kill(get_initpid(), SIGINT
); /* sync */
437 (void) kill(get_initpid(), SIGINT
); /* sync */
441 if (shutdown_program
) {
442 (void) printf("%s ", shutdown_program
);
444 (void) printf(gettext(msg9
));
445 else if (nosync
!= NULL
)
446 (void) printf(gettext(msg10
), nosync
);
448 (void) printf(gettext("-l\n"));
450 (void) printf("/sbin/bootadm -a update_all");
451 (void) printf("kill -INT 1");
453 (void) printf(gettext(msg11
));
460 stogo
= sdt
- time((time_t *)NULL
);
461 if (stogo
> 0 && sint
> 0)
462 sleep((unsigned)(sint
< stogo
? sint
: stogo
));
477 if (strcmp(s
, "now") == 0)
482 for (c_count
= 1; ; c_count
++) {
491 t
= t
* 10 + c
- '0';
496 tim
= time((time_t *)NULL
) + t
;
500 while (strlen(s
) > 2 && isdigit(*s
))
501 t
= t
* 10 + *s
++ - '0';
509 t
= t
* 10 + *s
++ - '0';
514 t1
= time((time_t *)NULL
);
516 t
= lt
->tm_sec
+ lt
->tm_min
*60 + lt
->tm_hour
*3600;
517 if (tim
< t
|| tim
>= (24*3600)) {
518 /* before now or after midnight */
519 (void) printf(gettext(msg12
));
520 finish(gettext(msg13
), gettext(msg14
), 0);
522 return (t1
+ tim
- t
);
524 (void) printf(gettext("Bad time format\n"));
525 finish(gettext("Bad time format"), "", 0);
531 warn(FILE *termf
, time_t sdt
, time_t now
, char *type
, int first
)
534 time_t delay
= sdt
- now
;
540 (void) fprintf(termf
, gettext(msg15
), type
, shutter
, hostname
);
543 if (delay
> 10 MINUTES
)
544 (void) fprintf(termf
, gettext(msg16
), ts
+11);
545 else if (delay
> 95 SECONDS
) {
546 (void) fprintf(termf
, gettext(msg17
), (delay
+30)/60,
547 (delay
+30)/60 != 1 ? "s" : "");
548 } else if (delay
> 0) {
549 (void) fprintf(termf
, gettext(msg18
), delay
,
550 delay
!= 1 ? "s" : "");
552 (void) fprintf(termf
, gettext(msg19
));
554 if (first
|| sdt
- now
> 1 MINUTES
) {
556 (void) fprintf(termf
, "\t...%s\r\n", mesg
);
565 if ((fastd
= fopen(fastboot
, "w")) != NULL
) {
566 (void) putc('\n', fastd
);
567 (void) fclose(fastd
);
572 rwarn(char *host
, time_t sdt
, time_t now
, char *type
, int first
)
575 time_t delay
= sdt
- now
;
583 "\007\007\t*** %sShutdown message for %s from %s@%s ***\r\n\n",
584 type
, hostname
, shutter
, hostname
);
586 bufp
= mbuf
+ strlen(mbuf
);
587 if (delay
> 10 MINUTES
) {
588 (void) sprintf(bufp
, "%s going down at %5.5s\r\n", hostname
,
590 } else if (delay
> 95 SECONDS
) {
591 (void) sprintf(bufp
, "%s going down in %d minute%s\r\n",
592 hostname
, (delay
+30)/60, (delay
+30)/60 != 1 ? "s" : "");
593 } else if (delay
> 0) {
594 (void) sprintf(bufp
, "%s going down in %d second%s\r\n",
595 hostname
, delay
, delay
!= 1 ? "s" : "");
597 (void) sprintf(bufp
, "%s going down IMMEDIATELY\r\n",
600 bufp
= mbuf
+ strlen(mbuf
);
601 if (first
|| sdt
- now
> 1 MINUTES
) {
603 (void) sprintf(bufp
, "\t...%s\r\n", mesg
);
609 rprintf(char *host
, char *bufp
)
614 (void) fprintf(stderr
, gettext("about to call %s\n"), host
);
616 if (err
= callrpcfast(host
, (rpcprog_t
)WALLPROG
, (rpcvers_t
)WALLVERS
,
617 (rpcproc_t
)WALLPROC_WALL
, xdr_dirpath
, (char *)&bufp
, xdr_void
,
620 (void) fprintf(stderr
, gettext("couldn't make rpc call: "));
622 (void) fprintf(stderr
, "\n");
632 (void) unlink(nologin
); /* in case linked to std file */
633 if ((nologf
= fopen(nologin
, "w")) != NULL
) {
634 (void) fprintf(nologf
, nolog1
, (ctime(&sdt
)) + 11);
636 (void) fprintf(nologf
, "\t%s\n", mesg
);
637 (void) fclose(nologf
);
644 finish("SIGINT", "", 1);
648 finish(char *s1
, char *s2
, int exitcode
)
650 (void) signal(SIGINT
, SIG_IGN
);
657 (void) signal(SIGALRM
, (void(*)())timeout
);
658 longjmp(alarmbuf
, 1);
665 struct mountbody
*ml
;
667 struct sockaddr_in addr
;
669 static struct timeval TIMEOUT
= { 25, 0 };
672 * check for portmapper
674 get_myaddress(&addr
);
675 s
= socket(AF_INET
, SOCK_STREAM
, 0);
678 if (connect(s
, (struct sockaddr
*)&addr
, sizeof (addr
)) < 0)
683 * First try tcp, then drop back to udp if
684 * tcp is unavailable (an old version of mountd perhaps)
685 * Using tcp is preferred because it can handle
686 * arbitrarily long export lists.
688 cl
= clnt_create(hostname
, (ulong_t
)MOUNTPROG
, (ulong_t
)MOUNTVERS
,
691 cl
= clnt_create(hostname
, (ulong_t
)MOUNTPROG
,
692 (ulong_t
)MOUNTVERS
, "udp");
694 if (rpc_createerr
.cf_stat
!= RPC_PROGNOTREGISTERED
) {
695 clnt_pcreateerror("shutdown warning");
702 if (clnt_call(cl
, MOUNTPROC_DUMP
,
703 xdr_void
, 0, xdr_mountlist
, (char *)&ml
, TIMEOUT
) != RPC_SUCCESS
) {
704 clnt_perror(cl
, "shutdown warning");
707 for (; ml
!= NULL
; ml
= ml
->ml_next
) {
708 for (hl
= hostlist
; hl
!= NULL
; hl
= hl
->nxt
)
709 if (strcmp(ml
->ml_hostname
, hl
->host
) == 0)
711 hl
= (struct hostlist
*)malloc(sizeof (struct hostlist
));
712 hl
->host
= ml
->ml_hostname
;
720 * Don't want to wait for usual portmapper timeout you get with
721 * callrpc or clnt_call, so use rmtcall instead. Use timeout
722 * of 8 secs, based on the per try timeout of 3 secs for rmtcall
725 callrpcfast(char *host
, rpcprog_t prognum
, rpcprog_t versnum
,
726 rpcprog_t procnum
, xdrproc_t inproc
, xdrproc_t outproc
,
729 struct sockaddr_in server_addr
;
731 struct timeval rpctimeout
;
734 if ((hp
= gethostbyname(host
)) == NULL
)
735 return ((int)RPC_UNKNOWNHOST
);
736 bcopy(hp
->h_addr
, (char *)&server_addr
.sin_addr
, hp
->h_length
);
737 server_addr
.sin_family
= AF_INET
;
738 server_addr
.sin_port
= 0;
739 rpctimeout
.tv_sec
= 8;
740 rpctimeout
.tv_usec
= 0;
741 return ((int)pmap_rmtcall(&server_addr
, prognum
, versnum
, procnum
,
742 inproc
, in
, outproc
, out
, rpctimeout
, &port
));