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 2007 Sun Microsystems, Inc. All rights reserved. 24# Use is subject to license terms. 25# 26#pragma ident "%Z%%M% %I% %E% SMI" 27# 28# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T 29# All Rights Reserved 30# 31# 32 33usage () { 34 if [ -n "$1" ]; then 35 echo "umountall: $1" 1>&2 36 fi 37 echo "Usage:\n\tumountall [-k] [-s] [-F FSType] [-l|-r] [-n]" 1>&2 38 echo "\tumountall [-k] [-s] [-h host] [-n]" 1>&2 39 exit 2 40} 41 42MNTTAB=/etc/mnttab 43 44# This script is installed as both /sbin/umountall (as used in some 45# /sbin/rc? and /etc/init.d scripts) _and_ as /usr/sbin/umountall (typically 46# PATHed from the command line). As such it should not depend on /usr 47# being mounted (if /usr is a separate filesystem). 48# 49# /sbin/sh Bourne shell builtins we use: 50# echo 51# exit 52# getopts 53# test, [ ] 54# exec 55# read 56# 57# /sbin commands we use: 58# /sbin/uname 59# /sbin/umount 60# 61# The following /usr based commands may be used by this script (depending on 62# command line options). We will set our PATH to find them, but where they 63# are not present (eg, if /usr is not mounted) we will catch references to 64# them via shell functions conditionally defined after option processing 65# (don't use any of these commands before then). 66# 67# Command Command line option and use 68# /usr/bin/sleep -k, to sleep after an fuser -c -k on the mountpoint 69# /usr/sbin/fuser -k, to kill processes keeping a mount point busy 70# 71# Copyright 2007 Sun Microsystems, Inc. All rights reserved. 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 77DEFERRED_ACTIVATION_PATCH_FLAG="/var/run/.patch_loopback_mode" 78SVC_STARTD="/lib/svc/bin/svc.startd" 79 80# Clear these in case they were already set in our inherited environment. 81FSType= 82FFLAG= 83HOST= 84HFLAG= 85RFLAG= 86LFLAG= 87SFLAG= 88KFLAG= 89NFLAG= 90LOCALNAME= 91UMOUNTFLAG= 92 93 94while getopts ?rslkF:h:n c 95do 96 case $c in 97 r) RFLAG="r";; 98 l) LFLAG="l";; 99 s) SFLAG="s";; 100 k) KFLAG="k";; 101 h) if [ -n "$HFLAG" ]; then 102 usage "more than one host specified" 103 fi 104 HOST=$OPTARG 105 HFLAG="h" 106 LOCALNAME=`uname -n` 107 ;; 108 F) if [ -n "$FFLAG" ]; then 109 usage "more than one FStype specified" 110 fi 111 FSType=$OPTARG 112 FFLAG="f" 113 case $FSType in 114 ?????????*) 115 usage "FSType ${FSType} exceeds 8 characters" 116 esac; 117 ;; 118 n) NFLAG="n" 119 # Alias any commands that would perform real actions to 120 # something that tells what action would have been performed 121 UMOUNTFLAG="-V" 122 fuser () { 123 echo "fuser $*" 1>&2 124 } 125 sleep () { 126 : # No need to show where we'd sleep 127 } 128 ;; 129 \?) usage "" 130 ;; 131 esac 132done 133 134# Sanity checking: 135# 1) arguments beyond those supported 136# 2) can't specify both remote and local 137# 3) can't specify a host with -r or -l 138# 4) can't specify a fstype with -h 139# 5) can't specify this host with -h (checks only uname -n) 140# 6) can't be fstype nfs and local 141# 7) only fstype nfs is remote 142 143if [ $# -ge $OPTIND ]; then # 1 144 usage "additional arguments not supported" 145fi 146 147if [ -n "$RFLAG" -a -n "$LFLAG" ]; then # 2 148 usage "options -r and -l are incompatible" 149fi 150 151if [ \( -n "$RFLAG" -o -n "$LFLAG" \) -a "$HFLAG" = "h" ]; then # 3 152 usage "option -${RFLAG}${LFLAG} incompatible with -h option" 153fi 154 155if [ -n "$FFLAG" -a "$HFLAG" = "h" ]; then # 4 156 usage "Specifying FStype incompatible with -h option" 157fi 158 159if [ -n "$HFLAG" -a "$HOST" = "$LOCALNAME" ]; then # 5 160 usage "Specifying local host illegal for -h option" 161fi 162 163if [ "$FSType" = "nfs" -a "$LFLAG" = "l" ]; then # 6 164 usage "option -l and FSType nfs are incompatible" 165fi 166 167if [ -n "$FFLAG" -a "$FSType" != "nfs" -a -n "$RFLAG" ]; then # 7 168 usage "option -r and FSType ${FSType} are incompatible" 169fi 170 171ZONENAME=`zonename` 172 173# Check and if needed sync the boot archive before unmounting everything. 174# 175if [ -z "${RFLAG}${NFLAG}${HFLAG}${FSType}" -a "$ZONENAME" = "global" -a \ 176 `uname -p` = "i386" -a -x /sbin/bootadm ] ; then 177 /sbin/bootadm -a update_all 178fi 179 180 181# 182# If we are in deferred activation patching, and the caller is 183# svc.startd, then exit without unmounting any of the remaining 184# file systems since the call path is from shutdown. Note that 185# by the time we get here, smf stop methods for nfs, cachefs 186# etc, will have run. 187# 188if [ -f $DEFERRED_ACTIVATION_PATCH_FLAG ] ; then 189 ppid=`ps -o ppid= -p $$` # parent of umountall will be sh 190 # from system() 191 192 ppid=`ps -o ppid= -p $ppid` # parent of sh will be svc.startd 193 COMM=`ps -o comm= -p $ppid` 194 if [ "$COMM" = "$SVC_STARTD" ] ; then 195 exit 196 fi 197fi 198 199# 200# Take advantage of parallel unmounting at this point if we have no 201# criteria to match and we are in the global zone 202# 203if [ -z "${SFLAG}${LFLAG}${RFLAG}${HFLAG}${KFLAG}${FFLAG}" -a \ 204 "$ZONENAME" = "global" ]; then 205 umount -a ${UMOUNTFLAG} 206 exit # with return code of the umount -a 207fi 208 209# 210# Catch uses of /usr commands when /usr is not mounted 211if [ -n "$KFLAG" -a -z "$NFLAG" ]; then 212 if [ ! -x /usr/sbin/fuser ]; then 213 fuser () { 214 echo "umountall: fuser -k skipped (no /usr)" 1>&2 215 # continue - not fatal 216 } 217 sleep () { 218 : # no point in sleeping if fuser is doing nothing 219 } 220 else 221 if [ ! -x /usr/bin/sleep ]; then 222 sleep () { 223 echo "umountall: sleep after fuser -k skipped (no /usr)" 1>&2 224 # continue - not fatal 225 } 226 fi 227 fi 228fi 229 230# 231# Shell function to avoid using /usr/bin/cut. Given a dev from a 232# fstype=nfs line in mnttab (eg, "host:/export) extract the host 233# component. 234print_host () { 235 OIFS=$IFS 236 IFS=":" 237 set -- $* 238 echo $1 239 IFS=$OIFS 240} 241 242# 243# doumounts echos its return code to stdout, so commands used within 244# this function should take care to produce no other output to stdout. 245doumounts () { 246 ( 247 rc=0 248 fslist="" 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 continue 292 fi 293 if [ -n "$RFLAG" -a "$fstype" != "nfs" ]; then 294 continue 295 fi 296 if [ "$ZONENAME" != "global" ]; then 297 for option in `echo $mode | tr , '\012'`; do 298 # 299 # should not see any zone options 300 # but our own 301 # 302 if [ "$option" = "zone=$ZONENAME" ]; then 303 break 304 fi 305 done 306 if [ "$option" != "zone=$ZONENAME" ]; then 307 continue 308 fi 309 fi 310 if [ -n "${KFLAG}" ]; then 311 fuser -c -k $mountp 1>&2 312 sleep 2 313 fi 314 if [ -n "$SFLAG" ]; then 315 umount ${UMOUNTFLAG} ${mountp} 1>&2 316 trc=$? 317 if [ $trc -ne 0 ]; then 318 rc=$trc 319 fi 320 else 321 # We want to umount in parallel 322 fslist="$fslist $mountp" 323 fi 324 esac 325 done 326 327 if [ -n "$fslist" ]; then 328 umount -a ${UMOUNTFLAG} $fslist 1>&2 329 trc=$? 330 if [ $trc -ne 0 ]; then 331 rc=$trc 332 fi 333 fi 334 335 echo $rc 336 ) 337} 338 339# 340# /etc/mnttab has the most recent mounts last. Reverse it so that we 341# may umount in opposite order to the original mounts. 342# 343 344if [ ! -x /usr/bin/tail ]; then 345 exec < $MNTTAB 346 REVERSED= 347 while read line; do 348 if [ -n "$REVERSED" ]; then 349 REVERSED="$line\n$REVERSED" 350 else 351 REVERSED="$line" 352 fi 353 done 354 355 error=`echo $REVERSED | doumounts` 356else 357 error=`tail -r $MNTTAB | doumounts` 358fi 359 360exit $error 361