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