#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2005,2006 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)22 1.4.1.2 src/avs/fs/mmfs/ts/admin/mmumount.sh, mmfs, avs_rgpfs24, rgpfs24s006a 8/29/06 15:12:46
##############################################################################
#
#  Unmount GPFS file systems on one or more nodes in the cluster.
#
#  Usage:
#    mmumount {Device | MountPoint | all | all_local | all_remote} [-f]
#             [-a | -N {Node[,Node...] | NodeFile | NodeClass}]
#  or
#    mmumount Device -f -C {all_remote | ClusterName} [-N Node[,Node...]]
#
#  where:
#
#    Device | MountPoint | all | all_local | all_remote
#        Specifies the file systems to be unmounted.
#        Only file systems that are owned by this cluster can be specified
#        in conjuction with the -C option.
#
#    -a  Unmount the file systems on all nodes in the cluster.
#
#    -f  Force the unmount to take place even though the file system may
#        still be in use.
#
#    -N {Node[,Node...] | NodeFile | NodeClass}
#        Specifies the nodes on which the unmount is to take place.
#
#    -C { all_remote | ClusterName }
#        Specifies the clusters on which the file system is to be unmounted.
#        Only remote clusters should be specified with this form of the command.
#        Use the first form of the command to unmount file systems on nodes in
#        the local cluster.
#
#        -C all_remote denotes all clusters other than the one from which
#        the command is ussued (this cluster).
#
#
#  Usage notes:
#
#    If not explicitly-specified otherwise, the file systems are unmounted on
#    the local node only.
#
#    The first form of the command should be used to unmount file systems on
#    nodes that belong to the local cluster.
#
#    The second form of the command should be used when it is necessary to
#    internally force unmount file systems that are owned by this cluster
#    but are mounted on nodes that belong to some other cluster.
#
#    When a file system is internally force unmounted with the second form of
#    the mmumount command, the affected nodes may still show the file system
#    as mounted (although the data is not accessible).  It is the responsibility
#    of the system administrator to clear the mount state by issuing the OS
#    umount command.
#
#    When the -N parameter is specified in conjunction with -C ClusterName,
#    the specified node names are assumed to refer to nodes that belong to
#    the specified remote cluster (as shown by mmlsmount).  The mmunmount
#    command cannot verify upfront the accuracy of this information.
#
##############################################################################

# Include global declarations and service routines.
. /usr/lpp/mmfs/bin/mmglobfuncs
. /usr/lpp/mmfs/bin/mmsdrfsdef

sourceFile="mmumount.sh"
[[ -n $DEBUG || -n $DEBUGmmumount ]] && set -x
$mmTRACE_ENTER "$*"


# Local variables

usageMsg=396
rc=0


#######################
# Mainline processing
#######################


##################################
# Process each of the arguments.
##################################
[[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] &&  \
  syntaxError "help" $usageMsg

[[ $argc -lt 1  ]] &&  \
  syntaxError "missingArgs" $usageMsg

# Figure out what was specified on the command line.
if [[ $arg1 = /* && $arg1 != +(/)dev+(/)* ]]
then
  # If the first argument starts with a "/" but not "/dev/",
  # it is assumed to be a fully-qualified mount point.
  mountPoint=$arg1
else
  # Otherwise, the argument is assumed to be the device name
  # of a file system (or the key word "all").
  device=$arg1
  deviceName=${device##+(/)dev+(/)}  # Name stripped of /dev/ prefix.
fi  # end of if [[ $arg1 = "/"* && $arg1 != +(/)dev+(/)* ]]

# Drop the name from the parameter list.
shift 1

# Process the rest of the options.
while getopts :afC:N: OPT
do
  case $OPT in

    a) [[ -n $aflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       aflag="-$OPT"
       [[ -n $Nflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg "-a" "-N"
       [[ -n $Cflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg "-a" "-C"
       initRequired=yes
       ;;

    f) [[ -n $fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       fflag="-$OPT"
       ;;

    C) [[ -n $Cflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Cflag="-$OPT"
       clusterName="$OPTARG"
       [[ -n $aflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg "-a" "-C"
       [[ -n $mountPoint ]] &&  \
         syntaxError "help" $usageMsg
       [[ $clusterName = *,* ]] &&  \
         syntaxError "help" $usageMsg
       initRequired=yes
       ;;

    N) [[ -n $Nflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Nflag="-$OPT"
       nodenames="$OPTARG"
       [[ -n $aflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg "-a" "-N"
       initRequired=yes
       ;;

    :) syntaxError "missingValue" $usageMsg $OPTARG
       ;;

    +[afCN])
       syntaxError "invalidOption" $usageMsg "$OPT"
       ;;

    *) syntaxError "invalidOption" $usageMsg $OPTARG
       ;;

  esac
done

shift OPTIND-1
[[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1

# Some additional restrictions for the -C version of the command.
if [[ -n $Cflag ]]
then
  [[ $clusterName = *,* ]] && syntaxError "help" $usageMsg
  [[ -n $mountPoint ]] && syntaxError "help" $usageMsg
  [[ $device = all  ]] && device=all_local
fi


##################################################################
# Set up trap exception handling.  If more than the local node
# is affected, ensure the local copy of the mmsdrfs and the rest
# of the GPFS system files are up-to-date.
##################################################################
trap pretrap2 HUP INT QUIT KILL
if [[ -n $initRequired ]]
then
  gpfsInitOutput=$(gpfsInit nolock)
  setGlobalVar $? $gpfsInitOutput
fi


#######################################################
# Create a file containing all of the specified nodes.
#######################################################
if [[ -n $aflag ]]
then
  # Get a list of the nodes.
  getNodeList $REL_HOSTNAME_Field $GLOBAL_ID $mmsdrfsFile > $nodefile

elif [[ -n $Cflag ]]
then
  # Get a list of the nodes in this cluster.
  getNodeList $REL_HOSTNAME_Field $GLOBAL_ID $mmsdrfsFile > $nodefile

  # Decide what to pass to the tsunmount command.
  # If the -N option is specified in conjuction with -C,
  # the scope is limited to the specified nodes.
  if [[ -n $Nflag ]]
  then
    affectedNodes="-n $nodenames"
  else
    affectedNodes="-C $clusterName"
  fi

elif [[ -n $Nflag ]]
then
  # Convert the passed data into a file containing admin node names.
  createVerifiedNodefile "$nodenames" $REL_HOSTNAME_Field no $nodefile
  [[ $? -ne 0 ]] && cleanupAndExit

else
  : # Nothing to do.  Only the local node is affected.
fi  # end of if [[ -n $aflag ]]


######################################
# Verify the file system device name.
######################################
if [[ $device = all ]]
then
  # Ensure there are file systems to unmount.
  $awk -F: '                                \
    BEGIN { rc = '$MM_FsNotFound' }         \
    $'$LINE_TYPE_Field' == "'$SG_HEADR'" {  \
      { rc = 0 }                            \
      { exit }                              \
    }                                       \
  END { exit rc }                           \
  ' $mmsdrfsFile
  rc=$?

  if [[ $rc = $MM_FsNotFound ]]
  then
    # No file systems were found in the cluster.
    printErrorMsg 200 $mmcmd
    cleanupAndExit $rc
  else
    # Check for unexpected errors
    checkForErrors awk $rc
  fi

  fsList=all

elif [[ $device = all_local ]]
then
  # Create a list of the file systems to unmount.
  fsList=$($awk -F: '                        \
    $'$LINE_TYPE_Field' == "'$SG_HEADR'" &&  \
    $'$FS_TYPE_Field'   == "'$localfs'"   {  \
      { printf $'$DEV_NAME_Field' "," }      \
    }                                        \
  ' $mmsdrfsFile)
  checkForErrors awk $rc

  if [[ -z $fsList ]]
  then
    # No file systems were found in the cluster.
    printErrorMsg 200 $mmcmd
    cleanupAndExit $MM_FsNotFound
  fi

  fsList=${fsList%%,}

elif [[ $device = all_remote ]]
then
  # Only locally owned file systems can be specified with the -C option.
  if [[ -n $Cflag ]]
  then
    # Command is not allowed for remote file systems.
    printErrorMsg 469 $mmcmd $Cflag
    cleanupAndExit
  fi

  # Create a list of the file systems to unmount.
  fsList=$($awk -F: '                        \
    $'$LINE_TYPE_Field' == "'$SG_HEADR'" &&  \
    $'$FS_TYPE_Field'   == "'$remotefs'"  {  \
      { printf $'$DEV_NAME_Field' "," }      \
    }                                        \
  ' $mmsdrfsFile)
  checkForErrors awk $rc

  if [[ -z $fsList ]]
  then
    # No remote file systems were found in the cluster.
    printErrorMsg 193 $mmcmd
    cleanupAndExit $MM_FsNotFound
  fi

  fsList=${fsList%%,}

elif [[ -n $device ]]
then
  # Ensure the specified file system exists.
  findFSoutput=$(findFS "$device" $mmsdrfsFile device)
  [[ -z $findFSoutput ]] && cleanupAndExit

  # Parse the output from the findFS function.
  set -f ; set -- $findFSoutput ; set +f
  fqDeviceName=$1
  deviceName=$2
  fsHomeCluster=$3

  # Only locally owned file systems can be specified with the -C option.
  if [[ -n $Cflag && $fsHomeCluster != $HOME_CLUSTER ]]
  then
    # Command is not allowed for remote file systems.
    printErrorMsg 472 $mmcmd $device $fsHomeCluster $Cflag
    cleanupAndExit
  fi

  fsList=$deviceName

else
  # A mount point was specified.  Since it can be anything,
  # there is no point in searching the mmsdrfs file.
  : # Let the unmount function handle it.
fi  # end of if [[ $device = all ]]

# Ensure we have the proper credentials.
[[ $getCredCalled = no ]] && getCred


###################################################
# Unmount the file systems on the specified nodes.
###################################################

# Unmounting file systems ...
printInfoMsg 426 "$(date)" $mmcmd

if [[ ! -s $nodefile ]]
then
  # The request is to unmount file systems on the local node only.
  if [[ -n $device ]]
  then
    $mmremote unmountFileSystems $fsList "$fflag"
    rc=$?
  else
    $mmremote unmountMountpoint $mountPoint "$fflag"
    rc=$?
  fi

elif [[ -n $Cflag ]]
then
  # The request is to internally force unmount one or more file systems.
  IFS=','
  for deviceName in $fsList
  do
    IFS="$IFS_sv"
    $mmcommon onactive $preferredNode $nodefile                     \
                       $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK  \
                       tsunmount "$deviceName $affectedNodes"
    IFS=',' # Move to the next file system.
  done  # end of for deviceName in $fsList
  IFS="$IFS_sv"

else
  # The request is to unmount file systems on a number
  # of nodes in the local cluster.
  if [[ -n $device ]]
  then
    $mmcommon onall $nodefile $unreachedNodes  \
      unmountFileSystems $fsList "$fflag"
    rc=$?
  else
    $mmcommon onall $nodefile $unreachedNodes  \
      unmountMountpoint $mountPoint "$fflag"
    rc=$?
  fi
fi  # end of if [[ ! -s $nodefile ]]

# If any nodes could not be reached, tell the user which ones.
if [[ -s $unreachedNodes ]]
then
  # The following nodes could not be reached: . . .
  printErrorMsg 270 $mmcmd
  $cat $unreachedNodes 1>&2
fi

cleanupAndExit $rc

