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