#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,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 
# @(#)78 1.40 src/avs/fs/mmfs/ts/admin/mmchdisk.sh, mmfs, avs_rgpfs24, rgpfs240610b 11/11/05 09:29:00
#########################################################################
#
# Usage:
#   mmchdisk Device {resume | start} -a
#            [-N {all | mount | Node[,Node...] | NodeFile | NodeClass}]
# or
#   mmchdisk Device {suspend | resume | stop | start | change}
#            -d "DiskDesc[;DiskDesc...]"
#            [-N {all | mount | Node[,Node...] | NodeFile | NodeClass}]
#
#########################################################################

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

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


# Local variables

usageMsg=287
integer rc=0
integer nodeCount=0
# argList=""   # argList without quotes around disk list
# argListQ=""  # argList with quotes around disk list


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

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

device=$arg1     # file system name (always the first parameter)
action=$arg2     # action to be taken for the disks (always the 2nd parameter) 
shift 2          # Drop the device name and disk state from the parameter list.

# Parse the optional parameters.  Special care must be taken when creating
# argList because the disk names in the -d option are separated by the ';'
# character.  For invocations via mmcommon, the argument lists must be
# enclosed in quotes.  For direct (local) invocations of tschdisk,
# the argument lists must not have surrounding quotes.  Detailed checking
# of supported keywords is left to tschdisk.
while getopts :ad:N: OPT
do
  case $OPT in
    a) # Change the state of all disks in the file system.
       [[ -n $aflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       [[ -n $dflag ]] &&  \
         syntaxError "invalidCombination"  $usageMsg "-a" "-d"
       aflag=yes
       argList="$action -$OPT"
       argListQ="$action -$OPT"
       ;;

    d) # Change the state of the specified disks.
       [[ -n $dflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       [[ -n $aflag ]] &&  \
         syntaxError "invalidCombination"  $usageMsg "-a" "-d"
       diskDescList=$OPTARG
       dflag=yes
       [[ "$diskDescList" = *+([,${BLANKchar}${TABchar}])* ]] &&  \
         syntaxError "badSeparator_notSemicolon" $noUsageMsg
       argList="$action -$OPT $OPTARG "
       argListQ="$action -$OPT \"$OPTARG\" "
       ;;

    N) # Specify the nodes on which to restripe.
       [[ -n $Nflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       nodeList="$OPTARG"
       Nflag="-N $OPTARG"
       ;;

    :) # missing required value after an option
       syntaxError "missingValue" $usageMsg $OPTARG
       ;;

    +[adN]) # plus flags are not allowed
       syntaxError "invalidOption" $usageMsg $OPT
       ;;

    *) # invalid option specified
       syntaxError "invalidOption" $usageMsg $OPTARG
       ;;
   esac
done

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


########################################################################
# Set up trap exception handling and call the gpfsInit function.
# It will ensure that the local copy of the mmsdrfs and the rest of the
# GPFS system files are up-to-date.  We only lock the sdr if mmchdisk
# was invoked with the change action.
########################################################################
if [[ $action = change ]]
then
  trap pretrap HUP INT QUIT KILL
  gpfsInitOutput=$(gpfsInit $lockId)
else
  trap pretrap2 HUP INT QUIT KILL
  gpfsInitOutput=$(gpfsInit nolock)
fi
setGlobalVar $? $gpfsInitOutput

# Determine the lookup order for resolving host names.
[[ $osName != AIX ]] && resolveOrder=$(setHostResolveOrder)


###########################################################
# Make sure the specified file system exists and is local.
###########################################################
findFSoutput=$(findFS "$device" $mmsdrfsFile)
[[ -z $findFSoutput ]] && cleanupAndExit

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

# Exit with a message if the command was invoked for a remote file system.
if [[ $fsHomeCluster != $HOME_CLUSTER ]]
then
  # Command is not allowed for remote file systems.
  printErrorMsg 106 $mmcmd $device $fsHomeCluster
  cleanupAndExit
fi


###################################################################
# If a keyword or a list of nodes was specified via the -N option,
# verify the input and add it to the argList and argListQ strings.
###################################################################
if [[ -n $Nflag ]]
then
  if [[ $nodeList = all || $nodeList = mount ]]
  then
    # Add the keyword ("all" or "mount") to the argList and argListQ strings.
    argList="$argList -N $nodeList "
    argListQ="$argListQ -N \"$nodeList\" "
  else
    # Verify the node list and convert it to a file of daemon node names.
    createVerifiedNodefile "$nodeList" $DAEMON_NODENAME_Field no $nodefile
    [[ $? -ne 0 ]] && cleanupAndExit

    # Convert the output data from a file to a comma-separated list.
    newNodeList=$(print -- $(cat $nodefile) | $sed 's/ /,/g')

    # Add the verified node list to the argList and argListQ strings.
    argList="$argList -N $newNodeList "
    argListQ="$argListQ -N \"$newNodeList\" "
  fi  # end of if [[ $nodeList = all || $nodeList = mount ]]
fi  # end of if [[ -n $Nflag ]]


#######################################################################
# If the cluster to which this node belongs is the same as the cluster
# in which the file system resides, invoke the command directly.
#######################################################################
if [[ $nsId = $fsHomeCluster ]]
then
  ${mmcmdDir}/${links}/mmchdisk $fqDeviceName $argList 2>$errMsg
  rc=$(remapRC $?)

  # If the command completed successfully, or if there is an
  # unacceptable error, display any error messages and get out.
  # If the action was "change", update the mmsdrfs file before exiting.
  if [[ $rc -ne $MM_DaemonDown && $rc -ne $MM_QuorumWait ]]
  then
    [[ -s $errMsg ]] && $cat $errMsg 1>&2
    if [[ $rc -eq $MM_ConnectionReset ]]
    then
      # An internode connection was reset.
      printErrorMsg 257 $mmcmd
    fi

    # Update the mmsdrfs file and unlock the sdr if the action was "change".
    if [[ $action = change ]]
    then
      # Reconcile the sdrfs file with the GPFS daemon's view of the filesystem.
      $cp $mmsdrfsFile $newsdrfs
      reconcileSdrfsWithDaemon $deviceName $newsdrfs
      rc2=$?
      if [[ $rc2 -ne 0 ]]
      then
        # reconcileSdrfsWithDaemon failed.
        printErrorMsg 171 $mmcmd reconcileSdrfsWithDaemon $rc2
        # Tell the user to run mmcommon recoverfs against the file system.
        printErrorMsg 190 $mmcmd $deviceName $deviceName
        cleanupAndExit $rc
      fi

      # Get the generation number from the version line of the new sdrfs file.
      versionLine=$($head -1 $newsdrfs)
      IFS=':'
      set -f ; set -- $versionLine ; set +f
      newGenNumber=$6
      IFS="$IFS_sv"

      # Commit the reconciled version of the sdrfs file to the server
      # so the admin scripts and the daemon are in sync.
      trap "" HUP INT QUIT KILL   # Disable interrupts until the commit is done.
      gpfsObjectInfo=$(commitChanges $fsHomeCluster $nsId $gpfsObjectInfo  \
                         $newGenNumber $newsdrfs $primaryServer)
      if [[ $? -ne 0 ]]
      then
        # We were unable to replace the file in the sdr.
        printErrorMsg 381 $mmcmd
        # Tell the user to run mmcommon recoverfs against the filesystem.
        printErrorMsg 190 $mmcmd $deviceName $deviceName
      fi

      # Unlock the sdr.
      [[ $sdrLocked = yes ]] &&  \
        freeLockOnServer $primaryServer $ourNodeNumber >/dev/null
      sdrLocked=no
      trap localPosttrap HUP INT QUIT KILL

      # Propagate the new mmsdrfs file.  This process is asynchronous.
      propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber

    fi  # end of if [[ $action = change ]]

    cleanupAndExit $rc

  fi  # end of if [[ $rc -ne $MM_DaemonDown && $rc -ne $MM_QuorumWait ]]

fi  # end of if [[ $nsId = $fsHomeCluster ]]
$rm -f $errMsg


############################################################################
# If the local daemon is not available, send the command to an active node.
############################################################################

# Create a file with the reliable names of the nodes
# in the cluster to which the file system belongs.
nodeCount=$(getNodeFile $REL_HOSTNAME_Field $fsHomeCluster $mmsdrfsFile $nodefile)
if [[ $nodeCount -eq 0 ]]
then
  # The cluster is empty; there is nobody to run the command.
  printErrorMsg 171 $mmcmd "getNodeFile (nodeCount=0)" 1
  cleanupAndExit
fi

# Try the nodes one by one until you find a node that can execute the command.
preferredNode=0     # We have no idea where to go first; let mmcommon decide.
$mmcommon linkCommand $preferredNode $nodefile mmchdisk $fqDeviceName "$argListQ"
rc=$?

# Update the mmsdrfs file and unlock the sdr if the action was "change"
# and the cluster state allowed the mmchdisk to be attempted.
if [[ $action = change ]]
then
  if [[ $rc -ne $MM_DaemonDown && $rc -ne $MM_QuorumWait ]]
  then
    # Reconcile the sdrfs file with the GPFS daemon's view of the filesystem.
    $cp $mmsdrfsFile $newsdrfs
    reconcileSdrfsWithDaemon $deviceName $newsdrfs
    rc2=$?
    if [[ $rc2 -ne 0 ]]
    then
      # reconcileSdrfsWithDaemon failed.
      printErrorMsg 171 $mmcmd reconcileSdrfsWithDaemon $rc2
      # Tell the user to run mmcommon recoverfs against the file system.
      printErrorMsg 190 $mmcmd $deviceName $deviceName
      cleanupAndExit $rc
    fi

    # Get the generation number from the version line of the new sdrfs file.
    versionLine=$($head -1 $newsdrfs)
    IFS=':'
    set -f ; set -- $versionLine ; set +f
    newGenNumber=$6
    IFS="$IFS_sv"

    # Commit the reconciled version of the sdrfs file to the server
    # so the admin scripts and the daemon are in sync.
    trap "" HUP INT QUIT KILL   # Disable interrupts until the commit is done.
    gpfsObjectInfo=$(commitChanges $fsHomeCluster $nsId $gpfsObjectInfo  \
                       $newGenNumber $newsdrfs $primaryServer)
    if [[ $? -ne 0 ]]
    then
      # We were unable to replace the file in the sdr.
      printErrorMsg 381 $mmcmd
      # Tell the user to run mmcommon recoverfs against the filesystem.
      printErrorMsg 190 $mmcmd $deviceName $deviceName
    fi

    # Unlock the sdr.
    [[ $sdrLocked = yes ]] &&  \
      freeLockOnServer $primaryServer $ourNodeNumber >/dev/null
    sdrLocked=no
    trap localPosttrap HUP INT QUIT KILL

    # Propagate the new mmsdrfs file.  This process is asynchronous.
    propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber

  else
    # The cluster state did not allow mmchdisk to run.  Just unlock the sdr.
    [[ $sdrLocked = yes ]] &&  \
      freeLockOnServer $primaryServer $ourNodeNumber >/dev/null
    sdrLocked=no
    trap localPosttrap HUP INT QUIT KILL

  fi  # end of if [[ $rc -ne $MM_DaemonDown && $rc -ne $MM_QuorumWait ]]

fi  # end of if [[ $action = change ]]

cleanupAndExit $rc

