1 #!/sbin/sh
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
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.
13 #
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]
19 #
20 # CDDL HEADER END
21 #
22 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 # Use is subject to license terms.
24 #
25 # Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
26 # All Rights Reserved
27
28 #
29 # Copyright 2017, OmniTI Computer Consulting, Inc. All rights reserved.
30 #
31
32 # Sequence performed to change the init state of a machine. Only allows
33 # transitions to states 0,1,5,6,s,S (i.e.: down or administrative states).
34
35 # This procedure checks to see if you are permitted and allows an
36 # interactive shutdown. The actual change of state, killing of
37 # processes and such are performed by the new init state, say 0,
38 # and its /sbin/rc0.
39
40 usage() {
41 echo "Usage: $0 [ -y ] [ -g<grace> ] [ -i<initstate> ] [ message ]"
42 exit 1
43 }
44
45 notify() {
46 /usr/sbin/wall -a <<-!
47 $*
48 !
49 # We used to do rwall here if showmounts had any output, but
50 # rwall is a potential security hole, and it could block this, so
51 # we don't bother with it anymore.
52 }
53
54 nologin=/etc/nologin
55
56 # Set the PATH so that to guarentee behavior of shell built in commands
57 # (such as echo).
58
59 PATH=/usr/sbin:/usr/bin:/sbin
60
61 # Initial sanity checks:
62 # Make sure /usr is mounted
63 # Check the user id (only root can run shutdown)
64
65 if [ ! -d /usr/bin ]
66 then
67 echo "$0: /usr is not mounted. Mount /usr or use init to shutdown."
68 exit 1
69 fi
70
71 if [ -x /usr/bin/id ]
72 then
73 eval `/usr/bin/id | /usr/bin/sed 's/[^a-z0-9=].*//'`
74 if [ "${uid:=0}" -ne 0 ]
75 then
76 echo "$0: Only root can run $0"
77 exit 2
78 fi
79 else
80 echo "$0: can't check user id."
81 exit 2
82 fi
83
84 # Get options (defaults immediately below):
85
86 grace=60
87 askconfirmation=yes
88 initstate=s
89
90 while getopts g:i:y? c
91 do
92 case $c in
93 g)
94 case $OPTARG in
95 *[!0-9]* )
96 echo "$0: -g requires a numeric option"
97 usage
98 ;;
99 [0-9]* )
100 grace=$OPTARG
101 ;;
102 esac
103 ;;
104 i)
105 case $OPTARG in
106 [Ss0156])
107 initstate=$OPTARG
108 ;;
109 [234abcqQ])
110 echo "$0: Initstate $OPTARG is not for system shutdown"
111 exit 1
112 ;;
113 *)
114 echo "$0: $OPTARG is not a valid initstate"
115 usage
116 ;;
117 esac
118 ;;
119 y)
120 askconfirmation=
121 ;;
122 \?) usage
123 ;;
124 esac
125 done
126 shift $(($OPTIND - 1))
127
128 echo '\nShutdown started. \c'
129 /usr/bin/date
130 echo
131
132 NODENAME=`uname -n`
133
134 cd /
135
136 trap "rm $nologin >/dev/null 2>&1 ;exit 1" 1 2 15
137
138 # If other users are on the system (and any grace period is given), warn them.
139
140 for i in 7200 3600 1800 1200 600 300 120 60 30 10; do
141 if [ ${grace} -gt $i ]
142 then
143 hours=$((${grace} / 3600))
144 minutes=$((${grace} % 3600 / 60))
145 seconds=$((${grace} % 60))
146 time=""
147 if [ ${hours} -gt 1 ]
148 then
149 time="${hours} hours "
150 elif [ ${hours} -eq 1 ]
151 then
152 time="1 hour "
153 fi
154 if [ ${minutes} -gt 1 ]
155 then
156 time="${time}${minutes} minutes "
157 elif [ ${minutes} -eq 1 ]
158 then
159 time="${time}1 minute "
160 fi
161 if [ ${hours} -eq 0 -a ${seconds} -gt 0 ]
162 then
163 if [ ${seconds} -eq 1 ]
164 then
165 time="${time}${seconds} second"
166 else
167 time="${time}${seconds} seconds"
168 fi
169 fi
170
171 (notify \
172 "The system ${NODENAME} will be shut down in ${time}
173 $*")
174
175 rm $nologin >/dev/null 2>&1
176 cat > $nologin <<-!
177
178 NO LOGINS: System going down in ${time}
179 $*
180
181 !
182
183 /usr/bin/sleep $((${grace} - $i))
184 grace=$i
185 fi
186 done
187
188 # Confirm that we really want to shutdown.
189
190 if [ ${askconfirmation} ]
191 then
192 echo "Do you want to continue? (y or n): \c"
193 read b
194 if [ "$b" != "y" ]
195 then
196 notify "False Alarm: The system ${NODENAME} will not be brought down."
197 echo 'Shutdown aborted.'
198 rm $nologin >/dev/null 2>&1
199 exit 1
200 fi
201 fi
202
203 # Final shutdown message, and sleep away the final 10 seconds (or less).
204
205 (notify \
206 "THE SYSTEM ${NODENAME} IS BEING SHUT DOWN NOW ! ! !
207 Log off now or risk your files being damaged
208 $*")
209
210 if [ ${grace} -gt 0 ]
211 then
212 /usr/bin/sleep ${grace}
213 fi
214
215 # Go to the requested initstate.
216
217
218 echo "Changing to init state $initstate - please wait"
219
220 # We might be racing with a system that's still booting.
221 # Before starting init, check to see if smf(5) is running. The easiest way
222 # to do this is to check for the existence of the repository service door.
223
224 i=0
225 # Try three times, sleeping one second each time...
226 while [ ! -e /etc/svc/volatile/repository_door -a $i -lt 3 ]; do
227 sleep 1
228 i=$(($i + 1))
229 done
230
231 if [ ! -e /etc/svc/volatile/repository_door ]; then
232 notify "Could not find repository door, init-state change may fail!"
233 fi
234
235 /sbin/init ${initstate}