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] [-Z] [-n]" 1>&2 36 echo "\tumountall [-k] [-s] [-h host] [-Z] [-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# In addition, we use /usr/bin/tail if it is available; if not we use 70# slower shell constructs to reverse a file. 71 72PATH=/sbin:/usr/sbin:/usr/bin 73 74DEFERRED_ACTIVATION_PATCH_FLAG="/var/run/.patch_loopback_mode" 75SVC_STARTD="/lib/svc/bin/svc.startd" 76 77# Clear these in case they were already set in our inherited environment. 78FSType= 79FFLAG= 80HOST= 81HFLAG= 82RFLAG= 83LFLAG= 84SFLAG= 85KFLAG= 86ZFLAG= 87NFLAG= 88LOCALNAME= 89UMOUNTFLAG= 90 91 92while getopts ?rslkF:h:Zn 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 Z) ZFLAG="z";; 117 n) NFLAG="n" 118 # Alias any commands that would perform real actions to 119 # something that tells what action would have been performed 120 UMOUNTFLAG="-V" 121 fuser () { 122 echo "fuser $*" 1>&2 123 } 124 sleep () { 125 : # No need to show where we'd sleep 126 } 127 ;; 128 \?) usage "" 129 ;; 130 esac 131done 132 133# Sanity checking: 134# 1) arguments beyond those supported 135# 2) can't specify both remote and local 136# 3) can't specify a host with -r or -l 137# 4) can't specify a fstype with -h 138# 5) can't specify this host with -h (checks only uname -n) 139# 6) can't be fstype nfs and local 140# 7) only fstype nfs is remote 141 142if [ $# -ge $OPTIND ]; then # 1 143 usage "additional arguments not supported" 144fi 145 146if [ -n "$RFLAG" -a -n "$LFLAG" ]; then # 2 147 usage "options -r and -l are incompatible" 148fi 149 150if [ \( -n "$RFLAG" -o -n "$LFLAG" \) -a "$HFLAG" = "h" ]; then # 3 151 usage "option -${RFLAG}${LFLAG} incompatible with -h option" 152fi 153 154if [ -n "$FFLAG" -a "$HFLAG" = "h" ]; then # 4 155 usage "Specifying FStype incompatible with -h option" 156fi 157 158if [ -n "$HFLAG" -a "$HOST" = "$LOCALNAME" ]; then # 5 159 usage "Specifying local host illegal for -h option" 160fi 161 162if [ "$FSType" = "nfs" -a "$LFLAG" = "l" ]; then # 6 163 usage "option -l and FSType nfs are incompatible" 164fi 165 166if [ -n "$FFLAG" -a "$FSType" != "nfs" -a -n "$RFLAG" ]; then # 7 167 usage "option -r and FSType ${FSType} are incompatible" 168fi 169 170ZONENAME=`zonename` 171 172# Check and if needed sync the boot archive before unmounting everything. 173# 174if [ -z "${RFLAG}${NFLAG}${HFLAG}${FSType}" -a "$ZONENAME" = "global" \ 175 -a -x /sbin/bootadm ] ; then 176 /sbin/bootadm -a update_all 177fi 178 179 180# 181# If we are in deferred activation patching, and the caller is 182# svc.startd, then exit without unmounting any of the remaining 183# file systems since the call path is from shutdown. Note that 184# by the time we get here, smf stop methods for nfs, cachefs 185# etc, will have run. 186# 187if [ -f $DEFERRED_ACTIVATION_PATCH_FLAG ] ; then 188 ppid=`ps -o ppid= -p $$` # parent of umountall will be sh 189 # from system() 190 191 ppid=`ps -o ppid= -p $ppid` # parent of sh will be svc.startd 192 COMM=`ps -o comm= -p $ppid` 193 if [ "$COMM" = "$SVC_STARTD" ] ; then 194 exit 195 fi 196fi 197 198# 199# Take advantage of parallel unmounting at this point if we have no 200# criteria to match and we are in the global zone 201# 202if [ -z "${SFLAG}${LFLAG}${RFLAG}${HFLAG}${KFLAG}${FFLAG}${ZFLAG}" -a \ 203 "$ZONENAME" = "global" ]; then 204 umount -a ${UMOUNTFLAG} 205 exit # with return code of the umount -a 206fi 207 208# 209# Catch uses of /usr commands when /usr is not mounted 210if [ -n "$KFLAG" -a -z "$NFLAG" ]; then 211 if [ ! -x /usr/sbin/fuser ]; then 212 fuser () { 213 echo "umountall: fuser -k skipped (no /usr)" 1>&2 214 # continue - not fatal 215 } 216 sleep () { 217 : # no point in sleeping if fuser is doing nothing 218 } 219 else 220 if [ ! -x /usr/bin/sleep ]; then 221 sleep () { 222 echo "umountall: sleep after fuser -k skipped (no /usr)" 1>&2 223 # continue - not fatal 224 } 225 fi 226 fi 227fi 228 229# 230# Shell function to avoid using /usr/bin/cut. Given a dev from a 231# fstype=nfs line in mnttab (eg, "host:/export) extract the host 232# component. 233print_host () { 234 OIFS=$IFS 235 IFS=":" 236 set -- $* 237 echo $1 238 IFS=$OIFS 239} 240 241# 242# doumounts echos its return code to stdout, so commands used within 243# this function should take care to produce no other output to stdout. 244doumounts () { 245 ( 246 rc=0 247 fslist="" 248 nfslist="" 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 nfslist="$nfslist $mountp" 292 continue 293 fi 294 # 295 # This will filter out autofs mounts with nfs file 296 # system mounted on the top of it. 297 # 298 # WARNING: use of any syscall on a NFS file system has 299 # the danger to go over-the-wire and could cause nfs 300 # clients to hang on shutdown, if the nfs server is 301 # down beforehand. 302 # For the reason described above, a simple test like 303 # "df -F nfs $mountp" can't be used to filter out 304 # nfs-over-autofs mounts. We loop over a list instead: 305 # 306 if [ -n "$LFLAG" -a -n "$nfslist" -a "$fstype" = "autofs" ] 307 then 308 for m in $nfslist; do 309 if [ "$mountp" = "$m" ]; then 310 # Resume the outer while loop 311 continue 2 312 fi 313 done 314 fi 315 if [ -n "$RFLAG" -a "$fstype" != "nfs" ]; then 316 continue 317 fi 318 if [ "$ZONENAME" != "global" ]; then 319 for option in `echo $mode | tr , '\012'`; do 320 # 321 # should not see any zone options 322 # but our own 323 # 324 if [ "$option" = "zone=$ZONENAME" ]; then 325 break 326 fi 327 done 328 if [ "$option" != "zone=$ZONENAME" ]; then 329 continue 330 fi 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 338 ;; 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 344 fi 345 # skip mounts from the global zone if ZFLAG is set 346 if [ "$option" != "zone=" -a -n "$ZFLAG" ]; then 347 continue 348 fi 349 fi 350 if [ -n "${KFLAG}" ]; then 351 fuser -c -k $mountp 1>&2 352 sleep 2 353 fi 354 if [ -n "$SFLAG" ]; then 355 umount ${UMOUNTFLAG} ${mountp} 1>&2 356 trc=$? 357 if [ $trc -ne 0 ]; then 358 rc=$trc 359 fi 360 else 361 # We want to umount in parallel 362 fslist="$fslist $mountp" 363 fi 364 esac 365 done 366 367 if [ -n "$fslist" ]; then 368 umount -a ${UMOUNTFLAG} $fslist 1>&2 369 trc=$? 370 if [ $trc -ne 0 ]; then 371 rc=$trc 372 fi 373 fi 374 375 echo $rc 376 ) 377} 378 379# 380# /etc/mnttab has the most recent mounts last. Reverse it so that we 381# may umount in opposite order to the original mounts. 382# 383 384if [ ! -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" 392 fi 393 done 394 395 error=`echo $REVERSED | doumounts` 396else 397 error=`tail -r $MNTTAB | doumounts` 398fi 399 400exit $error 401