xref: /titanic_51/usr/src/cmd/initpkg/umountall.sh (revision 5087e485d482853e61c9d38d8197dee892c7f43d)
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#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26#	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
27#	  All Rights Reserved
28#
29#
30
31usage () {
32	if [ -n "$1" ]; then
33		echo "umountall: $1" 1>&2
34	fi
35	echo "Usage:\n\tumountall [-k] [-s] [-F FSType] [-l|-r] [-Z] [-n]" 1>&2
36	echo "\tumountall [-k] [-s] [-h host] [-Z] [-n]" 1>&2
37	exit 2
38}
39
40MNTTAB=/etc/mnttab
41
42# This script is installed as both /sbin/umountall (as used in some
43# /sbin/rc? and /etc/init.d scripts) _and_ as /usr/sbin/umountall (typically
44# PATHed from the command line).  As such it should not depend on /usr
45# being mounted (if /usr is a separate filesystem).
46#
47# /sbin/sh Bourne shell builtins we use:
48#	echo
49#	exit
50#	getopts
51#	test, [ ]
52#	exec
53#	read
54#
55# /sbin commands we use:
56#	/sbin/uname
57#	/sbin/umount
58#
59# The following /usr based commands may be used by this script (depending on
60# command line options).  We will set our PATH to find them, but where they
61# are not present (eg, if /usr is not mounted) we will catch references to
62# them via shell functions conditionally defined after option processing
63# (don't use any of these commands before then).
64#
65#	Command		Command line option and use
66# /usr/bin/sleep	-k, to sleep after an fuser -c -k on the mountpoint
67# /usr/sbin/fuser	-k, to kill processes keeping a mount point busy
68#
69# In addition, we use /usr/bin/tail if it is available; if not we use
70# slower shell constructs to reverse a file.
71
72PATH=/sbin:/usr/sbin:/usr/bin
73
74DEFERRED_ACTIVATION_PATCH_FLAG="/var/run/.patch_loopback_mode"
75SVC_STARTD="/lib/svc/bin/svc.startd"
76
77# Clear these in case they were already set in our inherited environment.
78FSType=
79FFLAG=
80HOST=
81HFLAG=
82RFLAG=
83LFLAG=
84SFLAG=
85KFLAG=
86ZFLAG=
87NFLAG=
88LOCALNAME=
89UMOUNTFLAG=
90
91
92while getopts ?rslkF:h:Zn c
93do
94	case $c in
95	r)	RFLAG="r";;
96	l)	LFLAG="l";;
97	s)	SFLAG="s";;
98	k) 	KFLAG="k";;
99	h)	if [ -n "$HFLAG" ]; then
100			usage "more than one host specified"
101		fi
102		HOST=$OPTARG
103		HFLAG="h"
104		LOCALNAME=`uname -n`
105		;;
106	F)	if [ -n "$FFLAG" ]; then
107			usage "more than one FStype specified"
108		fi
109		FSType=$OPTARG
110		FFLAG="f"
111		case $FSType in
112		?????????*)
113			usage "FSType ${FSType} exceeds 8 characters"
114		esac;
115		;;
116	Z)	ZFLAG="z";;
117	n)	NFLAG="n"
118		# Alias any commands that would perform real actions to
119		# something that tells what action would have been performed
120		UMOUNTFLAG="-V"
121		fuser () {
122			echo "fuser $*" 1>&2
123		}
124		sleep () {
125			: # No need to show where we'd sleep
126		}
127		;;
128	\?)	usage ""
129		;;
130	esac
131done
132
133# Sanity checking:
134#	1) arguments beyond those supported
135#	2) can't specify both remote and local
136#	3) can't specify a host with -r or -l
137#	4) can't specify a fstype with -h
138#	5) can't specify this host with -h (checks only uname -n)
139#	6) can't be fstype nfs and local
140#	7) only fstype nfs is remote
141
142if [ $# -ge $OPTIND ]; then						# 1
143	usage "additional arguments not supported"
144fi
145
146if [ -n "$RFLAG" -a -n "$LFLAG" ]; then					# 2
147	usage "options -r and -l are incompatible"
148fi
149
150if [ \( -n "$RFLAG" -o -n "$LFLAG" \) -a "$HFLAG" = "h" ]; then		# 3
151	usage "option -${RFLAG}${LFLAG} incompatible with -h option"
152fi
153
154if [ -n "$FFLAG" -a "$HFLAG" = "h" ]; then				# 4
155	usage "Specifying FStype incompatible with -h option"
156fi
157
158if [ -n "$HFLAG" -a "$HOST" = "$LOCALNAME" ]; then			# 5
159	usage "Specifying local host illegal for -h option"
160fi
161
162if [ "$FSType" = "nfs" -a "$LFLAG" = "l" ]; then			# 6
163	usage "option -l and FSType nfs are incompatible"
164fi
165
166if [ -n "$FFLAG" -a "$FSType" != "nfs"  -a -n "$RFLAG" ]; then		# 7
167	usage "option -r and FSType ${FSType} are incompatible"
168fi
169
170ZONENAME=`zonename`
171
172# Check and if needed sync the boot archive before unmounting everything.
173#
174if [ -z "${RFLAG}${NFLAG}${HFLAG}${FSType}" -a "$ZONENAME" = "global" \
175    -a -x /sbin/bootadm ] ; then
176	/sbin/bootadm -a update_all
177fi
178
179
180#
181# If we are in deferred activation patching, and the caller is
182# svc.startd, then exit without unmounting any of the remaining
183# file systems since the call path is from shutdown.  Note that
184# by the time we get here, smf stop methods for nfs, cachefs
185# etc, will have run.
186#
187if [ -f $DEFERRED_ACTIVATION_PATCH_FLAG ] ; then
188	ppid=`ps -o ppid= -p $$`	# parent of umountall will be sh
189					# from system()
190
191	ppid=`ps -o ppid= -p $ppid`	# parent of sh will be svc.startd
192	COMM=`ps -o comm= -p $ppid`
193	if [ "$COMM" = "$SVC_STARTD" ] ; then
194		exit
195	fi
196fi
197
198#
199# Take advantage of parallel unmounting at this point if we have no
200# criteria to match and we are in the global zone
201#
202if [ -z "${SFLAG}${LFLAG}${RFLAG}${HFLAG}${KFLAG}${FFLAG}${ZFLAG}" -a \
203    "$ZONENAME" = "global" ]; then
204	umount -a ${UMOUNTFLAG}
205	exit			# with return code of the umount -a
206fi
207
208#
209# Catch uses of /usr commands when /usr is not mounted
210if [ -n "$KFLAG" -a -z "$NFLAG" ]; then
211	if [ ! -x /usr/sbin/fuser ]; then
212		fuser () {
213			echo "umountall: fuser -k skipped (no /usr)" 1>&2
214			# continue - not fatal
215		}
216		sleep () {
217			: # no point in sleeping if fuser is doing nothing
218		}
219	else
220		if [ ! -x /usr/bin/sleep ]; then
221			sleep () {
222				echo "umountall: sleep after fuser -k skipped (no /usr)" 1>&2
223				# continue - not fatal
224			}
225		fi
226	fi
227fi
228
229#
230# Shell function to avoid using /usr/bin/cut.  Given a dev from a
231# fstype=nfs line in mnttab (eg, "host:/export) extract the host
232# component.
233print_host () {
234	OIFS=$IFS
235	IFS=":"
236	set -- $*
237	echo $1
238	IFS=$OIFS
239}
240
241#
242# doumounts echos its return code to stdout, so commands used within
243# this function should take care to produce no other output to stdout.
244doumounts () {
245	(
246	rc=0
247	fslist=""
248	while read dev mountp fstype mode dummy
249	do
250		case "${mountp}" in
251		/			| \
252		/dev			| \
253		/dev/fd			| \
254		/devices		| \
255		/etc/mnttab		| \
256		/etc/svc/volatile	| \
257		/lib			| \
258		/proc			| \
259		/sbin			| \
260		/system/contract	| \
261		/system/object		| \
262		/tmp			| \
263		/usr			| \
264		/var			| \
265		/var/adm		| \
266		/var/run		| \
267		'' )
268			#
269			# file systems possibly mounted in the kernel or
270			# in the methods of some of the file system
271			# services
272			#
273			continue
274			;;
275		* )
276			if [ -n "$HFLAG" ]; then
277				if [ "$fstype" = "nfs" ]; then
278					thishost=`print_host $dev`
279					if [ "$HOST" != "$thishost" ]; then
280						continue
281					fi
282				else
283					continue
284				fi
285			fi
286			if [ -n "$FFLAG" -a "$FSType" != "$fstype" ]; then
287				continue
288			fi
289			if [ -n "$LFLAG" -a "$fstype" = "nfs" ]; then
290				continue
291			fi
292			if [ -n "$RFLAG" -a "$fstype" != "nfs" ]; then
293				continue
294			fi
295			if [ "$ZONENAME" != "global" ]; then
296				for option in `echo $mode | tr , '\012'`; do
297					#
298					# should not see any zone options
299					# but our own
300					#
301					if [ "$option" = "zone=$ZONENAME" ]; then
302						break
303					fi
304				done
305				if [ "$option" != "zone=$ZONENAME" ]; then
306					continue
307				fi
308			# we are called from the global zone
309			else
310				for option in `echo $mode | tr , '\012'`; do
311					case "$option" in
312					zone=*)
313						option="zone="
314						break
315					;;
316					esac
317				done
318				# skip mounts from non-global zones if ZFLAG is not set
319				if [ "$option" = "zone=" -a -z "$ZFLAG" ]; then
320					continue
321				fi
322				# skip mounts from the global zone if ZFLAG is set
323				if [ "$option" != "zone=" -a -n "$ZFLAG" ]; then
324					continue
325				fi
326			fi
327			if [ -n "${KFLAG}" ]; then
328				fuser -c -k $mountp 1>&2
329				sleep 2
330			fi
331			if [ -n "$SFLAG" ]; then
332				umount ${UMOUNTFLAG} ${mountp} 1>&2
333				trc=$?
334				if [ $trc -ne 0 ]; then
335					rc=$trc
336				fi
337			else
338				# We want to umount in parallel
339				fslist="$fslist $mountp"
340			fi
341		esac
342	done
343
344	if [ -n "$fslist" ]; then
345		umount -a ${UMOUNTFLAG} $fslist 1>&2
346		trc=$?
347		if [ $trc -ne 0 ]; then
348			rc=$trc
349		fi
350	fi
351
352	echo $rc
353	)
354}
355
356#
357# /etc/mnttab has the most recent mounts last.  Reverse it so that we
358# may umount in opposite order to the original mounts.
359#
360
361if [ ! -x /usr/bin/tail ]; then
362	exec < $MNTTAB
363	REVERSED=
364	while read line; do
365		if [ -n "$REVERSED" ]; then
366        		REVERSED="$line\n$REVERSED"
367		else
368			REVERSED="$line"
369		fi
370	done
371
372	error=`echo $REVERSED | doumounts`
373else
374	error=`tail -r $MNTTAB | doumounts`
375fi
376
377exit $error
378