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
40usage() {
41	echo "Usage: $0 [ -y ] [ -g<grace> ] [ -i<initstate> ] [ message ]"
42	exit 1
43}
44
45notify() {
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
54nologin=/etc/nologin
55
56# Set the PATH so that to guarentee behavior of shell built in commands
57# (such as echo).
58
59PATH=/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
65if [ ! -d /usr/bin ]
66then
67	echo "$0:  /usr is not mounted.  Mount /usr or use init to shutdown."
68	exit 1
69fi
70
71if [ -x /usr/bin/id ]
72then
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
79else
80	echo "$0:  can't check user id."
81	exit 2
82fi
83
84# Get options (defaults immediately below):
85
86grace=60
87askconfirmation=yes
88initstate=s
89
90while getopts g:i:y? c
91do
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
125done
126shift $(($OPTIND - 1))
127
128echo '\nShutdown started.    \c'
129/usr/bin/date
130echo
131
132NODENAME=`uname -n`
133
134cd /
135
136trap "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
140for 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
186done
187
188# Confirm that we really want to shutdown.
189
190if [ ${askconfirmation} ]
191then
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
201fi
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 ! ! !
207Log off now or risk your files being damaged
208$*")
209
210if [ ${grace} -gt 0 ]
211then
212	/usr/bin/sleep ${grace}
213fi
214
215# Go to the requested initstate.
216
217
218echo "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
224i=0
225# Try three times, sleeping one second each time...
226while [ ! -e /etc/svc/volatile/repository_door -a $i -lt 3 ]; do
227	sleep 1
228	i=$(($i + 1))
229done
230
231if [ ! -e /etc/svc/volatile/repository_door ]; then
232	notify "Could not find repository door, init-state change may fail!"
233fi
234
235/sbin/init ${initstate}
236