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