treewide: replace /sbin/sh hashbangs with /bin/sh
[unleashed.git] / usr / src / cmd / initpkg / umountall.sh
blob350de83c8c6601a2e5440227fd012df94fff3fa0
1 #!/bin/sh
3 # CDDL HEADER START
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.
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.
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]
20 # CDDL HEADER END
23 # Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
25 # Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
26 # All Rights Reserved
30 usage () {
31 if [ -n "$1" ]; then
32 echo "umountall: $1" 1>&2
34 echo "Usage:\n\tumountall [-k] [-s] [-F FSType] [-l|-r] [-Z] [-n]" 1>&2
35 echo "\tumountall [-k] [-s] [-h host] [-Z] [-n]" 1>&2
36 exit 2
39 MNTTAB=/etc/mnttab
41 # This script is installed as both /sbin/umountall (as used in some
42 # /sbin/rc? and /etc/init.d scripts) _and_ as /usr/sbin/umountall (typically
43 # PATHed from the command line). As such it should not depend on /usr
44 # being mounted (if /usr is a separate filesystem).
46 # /sbin/sh Bourne shell builtins we use:
47 # echo
48 # exit
49 # getopts
50 # test, [ ]
51 # exec
52 # read
54 # commands we use:
55 # /usr/bin/uname
56 # /sbin/umount
58 # The following /usr based commands may be used by this script (depending on
59 # command line options). We will set our PATH to find them, but where they
60 # are not present (eg, if /usr is not mounted) we will catch references to
61 # them via shell functions conditionally defined after option processing
62 # (don't use any of these commands before then).
64 # Command Command line option and use
65 # /usr/bin/sleep -k, to sleep after an fuser -c -k on the mountpoint
66 # /usr/sbin/fuser -k, to kill processes keeping a mount point busy
68 # In addition, we use /usr/bin/tail if it is available; if not we use
69 # slower shell constructs to reverse a file.
71 PATH=/sbin:/usr/sbin:/usr/bin
73 # Clear these in case they were already set in our inherited environment.
74 FSType=
75 FFLAG=
76 HOST=
77 HFLAG=
78 RFLAG=
79 LFLAG=
80 SFLAG=
81 KFLAG=
82 ZFLAG=
83 NFLAG=
84 LOCALNAME=
85 UMOUNTFLAG=
86 RemoteFSTypes=
88 # Is the passed fstype a "remote" one?
89 # Essentially: /usr/bin/grep "^$1" /etc/dfs/fstypes
90 isremote() {
91 for t in $RemoteFSTypes
93 [ "$t" = "$1" ] && return 0
94 done
95 return 1
98 # Get list of remote FS types (just once)
99 RemoteFSTypes=`while read t junk; do echo $t; done < /etc/dfs/fstypes`
103 # Process command line args
105 while getopts ?rslkF:h:Zn c
107 case $c in
108 r) RFLAG="r";;
109 l) LFLAG="l";;
110 s) SFLAG="s";;
111 k) KFLAG="k";;
112 h) if [ -n "$HFLAG" ]; then
113 usage "more than one host specified"
115 HOST=$OPTARG
116 HFLAG="h"
117 LOCALNAME=`uname -n`
119 F) if [ -n "$FFLAG" ]; then
120 usage "more than one FStype specified"
122 FSType=$OPTARG
123 FFLAG="f"
124 case $FSType in
125 ?????????*)
126 usage "FSType ${FSType} exceeds 8 characters"
127 esac;
129 Z) ZFLAG="z";;
130 n) NFLAG="n"
131 # Alias any commands that would perform real actions to
132 # something that tells what action would have been performed
133 UMOUNTFLAG="-V"
134 fuser () {
135 echo "fuser $*" 1>&2
137 sleep () {
138 : # No need to show where we'd sleep
141 \?) usage ""
143 esac
144 done
146 # Sanity checking:
147 # 1) arguments beyond those supported
148 # 2) can't specify both remote and local
149 # 3) can't specify a host with -r or -l
150 # 4) can't specify a fstype with -h
151 # 5) can't specify this host with -h (checks only uname -n)
152 # 6) can't be fstype nfs and local
153 # 7) only fstype nfs is remote
155 if [ $# -ge $OPTIND ]; then # 1
156 usage "additional arguments not supported"
159 if [ -n "$RFLAG" -a -n "$LFLAG" ]; then # 2
160 usage "options -r and -l are incompatible"
163 if [ \( -n "$RFLAG" -o -n "$LFLAG" \) -a "$HFLAG" = "h" ]; then # 3
164 usage "option -${RFLAG}${LFLAG} incompatible with -h option"
167 if [ -n "$FFLAG" -a "$HFLAG" = "h" ]; then # 4
168 usage "Specifying FStype incompatible with -h option"
171 if [ -n "$HFLAG" -a "$HOST" = "$LOCALNAME" ]; then # 5
172 usage "Specifying local host illegal for -h option"
175 if [ "$LFLAG" = "l" -a -n "$FSType" ]; then # 6
176 # remote FSType not allowed
177 isremote "$FSType" &&
178 usage "option -l and FSType ${FSType} are incompatible"
181 if [ "$RFLAG" = "r" -a -n "$FSType" ]; then # 7
182 # remote FSType required
183 isremote "$FSType" ||
184 usage "option -r and FSType ${FSType} are incompatible"
187 ZONENAME=`zonename`
190 # Take advantage of parallel unmounting at this point if we have no
191 # criteria to match and we are in the global zone
193 if [ -z "${SFLAG}${LFLAG}${RFLAG}${HFLAG}${KFLAG}${FFLAG}${ZFLAG}" -a \
194 "$ZONENAME" = "global" ]; then
195 umount -a ${UMOUNTFLAG}
196 exit # with return code of the umount -a
200 # Catch uses of /usr commands when /usr is not mounted
201 if [ -n "$KFLAG" -a -z "$NFLAG" ]; then
202 if [ ! -x /usr/sbin/fuser ]; then
203 fuser () {
204 echo "umountall: fuser -k skipped (no /usr)" 1>&2
205 # continue - not fatal
207 sleep () {
208 : # no point in sleeping if fuser is doing nothing
210 else
211 if [ ! -x /usr/bin/sleep ]; then
212 sleep () {
213 echo "umountall: sleep after fuser -k skipped (no /usr)" 1>&2
214 # continue - not fatal
221 # Shell function to avoid using /usr/bin/cut. Given a dev from a
222 # fstype=nfs line in mnttab (eg, "host:/export) extract the host
223 # component. The dev string looks like: "host:/path"
224 print_nfs_host () {
225 OIFS=$IFS
226 IFS=":"
227 set -- $*
228 echo $1
229 IFS=$OIFS
232 # Similar for smbfs, but tricky due to the optional parts
233 # of the "device" syntax. The dev strings look like:
234 # "//server/share" or "//user@server/share"
235 print_smbfs_host () {
236 OIFS=$IFS
237 IFS="/@"
238 set -- $*
239 case $# in
240 3) echo "$2";;
241 2) echo "$1";;
242 esac
243 IFS=$OIFS
247 # doumounts echos its return code to stdout, so commands used within
248 # this function should take care to produce no other output to stdout.
249 doumounts () {
251 rc=0
252 fslist=""
253 while read dev mountp fstype mode dummy
255 case "${mountp}" in
256 / | \
257 /dev | \
258 /dev/fd | \
259 /devices | \
260 /etc/mnttab | \
261 /etc/svc/volatile | \
262 /lib | \
263 /proc | \
264 /sbin | \
265 /system/contract | \
266 /system/object | \
267 /tmp | \
268 /usr | \
269 /var | \
270 /var/adm | \
271 /var/run | \
272 '' )
274 # file systems possibly mounted in the kernel or
275 # in the methods of some of the file system
276 # services
278 continue
281 if [ -n "$HFLAG" ]; then
282 thishost='-'
283 if [ "$fstype" = "nfs" ]; then
284 thishost=`print_nfs_host $dev`
286 if [ "$fstype" = "smbfs" ]; then
287 thishost=`print_smbfs_host $dev`
289 if [ "$HOST" != "$thishost" ]; then
290 continue
293 if [ -n "$FFLAG" -a "$FSType" != "$fstype" ]; then
294 continue
297 if [ -n "$LFLAG" ]; then
298 # umount local filesystems
299 isremote "$fstype" && continue
302 # Note: isremote is true for both nfs & autofs, so
303 # this will filter out autofs mounts with nfs file
304 # system mounted on the top of it.
306 # WARNING: use of any syscall on a NFS file system has
307 # the danger to go over-the-wire and could cause nfs
308 # clients to hang on shutdown, if the nfs server is
309 # down beforehand.
310 # For the reason described above, a simple test like
311 # "df -F nfs $mountp" can't be used to filter out
312 # nfs-over-autofs mounts. (isremote works OK)
314 if [ -n "$RFLAG" ]; then
315 # umount remote filesystems
316 isremote "$fstype" || continue
318 if [ "$ZONENAME" != "global" ]; then
319 for option in `echo $mode | tr , '\012'`; do
321 # should not see any zone options
322 # but our own
324 if [ "$option" = "zone=$ZONENAME" ]; then
325 break
327 done
328 if [ "$option" != "zone=$ZONENAME" ]; then
329 continue
331 # we are called from the global zone
332 else
333 for option in `echo $mode | tr , '\012'`; do
334 case "$option" in
335 zone=*)
336 option="zone="
337 break
339 esac
340 done
341 # skip mounts from non-global zones if ZFLAG is not set
342 if [ "$option" = "zone=" -a -z "$ZFLAG" ]; then
343 continue
345 # skip mounts from the global zone if ZFLAG is set
346 if [ "$option" != "zone=" -a -n "$ZFLAG" ]; then
347 continue
350 if [ -n "${KFLAG}" ]; then
351 fuser -c -k $mountp 1>&2
352 sleep 2
354 if [ -n "$SFLAG" ]; then
355 umount ${UMOUNTFLAG} ${mountp} 1>&2
356 trc=$?
357 if [ $trc -ne 0 ]; then
358 rc=$trc
360 else
361 # We want to umount in parallel
362 fslist="$fslist $mountp"
364 esac
365 done
367 if [ -n "$fslist" ]; then
368 umount -a ${UMOUNTFLAG} $fslist 1>&2
369 trc=$?
370 if [ $trc -ne 0 ]; then
371 rc=$trc
375 echo $rc
380 # /etc/mnttab has the most recent mounts last. Reverse it so that we
381 # may umount in opposite order to the original mounts.
384 if [ ! -x /usr/bin/tail ]; then
385 exec < $MNTTAB
386 REVERSED=
387 while read line; do
388 if [ -n "$REVERSED" ]; then
389 REVERSED="$line\n$REVERSED"
390 else
391 REVERSED="$line"
393 done
395 error=`echo $REVERSED | doumounts`
396 else
397 error=`tail -r $MNTTAB | doumounts`
400 exit $error