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