#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2004,2007 
# 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.55 src/avs/fs/mmfs/ts/admin/mmremotecluster.sh, mmfs, avs_rgpfs24, rgpfs24s012a 5/2/07 15:29:27
################################################################################
#
# Usage:
#   mmremotecluster add remoteClusterName [-k keyfile] [-n contactNodes]
#
#   mmremotecluster update remoteClusterName [-C newClusterName]
#                          [-k keyfile] [-n contactNodes]
#
#   mmremotecluster delete {remoteClusterName | all}
#
#   mmremotecluster show   [remoteClusterName | all]
#
# where
#
#   remoteClusterName  is the fully-qualified name for a remote cluster that
#                      owns file systems that nodes from this cluster intend
#                      to mount.
#
#   -C newClusterName  is the new fully-qualified cluster name for an
#                      already-defined cluster remoteClusterName.
#
#   -k keyfile         is the authentication key file generated by the mmauth
#                      command on the remote cluster.
#
#   -n contactNodes    provides contact information for the remote cluster.
#                      The contactNodes parameter has the following format:
#
#                        [tcpPort=NNNN,]node1[,node2 ...]
#
#                      where
#
#                        tcpPort=NNNN  is the TCP port number to be used by the
#                                  GPFS daemon.  If not specified, GPFS will
#                                  use the default TCP port number 1191.
#
#                        node1[,node2 ...]  is a list of nodes that belong to
#                                  the remote cluster.  The nodes can be
#                                  identified through their host names or
#                                  IP addresses.  If contactNodes are not
#                                  specified, the user must enable
#                                  /var/mmfs/etc/remoteclusternodes.
#
################################################################################

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

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

# Local work files.  Names should be of the form:
#   fn=${tmpDir}fn.${mmcmd}.$$
mountCheckList=${tmpDir}mountCheckList.${mmcmd}.$$
verifiedKey=${tmpDir}verifiedKey.${mmcmd}.$$
tmpPublicKey=${tmpDir}tmpPublicKey.${mmcmd}.$$

LOCAL_FILES=" $mountCheckList $verifiedKey $tmpPublicKey "

# Local variables
usageMsg=388
contactNodesCount=0


# Local functions

##########################################################################
#
# Function:  Determine the SHA digest (fingerprint) that corresponds
#            to the public key file for the specified cluster.
#
# Input:     $1 - cluster name
#            $2 - sdrfs file to use
#
# Output:    The SHA digest string.
#
# Returns:   0 - no errors encountered
#            1 - unexpected error
#
##########################################################################
function getFingerprint  # <clusterName> <sdrfsFile>
{
  typeset sourceFile="mmremotecluster.sh"
  [[ -n $DEBUG || -n $DEBUGgetFingerprint ]] && set -x
  typeset clusterName=$1
  typeset sdrfs=$2

  typeset sdrfsLine clusterNameField lineTypeField keyLine keyFingerprint

  [[ ! -f $sdrfs ]] && return 1
  $rm -f $tmpPublicKey

  # Go through the current mmsdrfs file and retrieve the requested information.
  IFS=":"
  exec 4<&-
  exec 4< $sdrfs
  while read -u4 sdrfsLine
  do
    # Parse the line.
    set -f ; set -- $sdrfsLine ; set +f
    clusterNameField=$1
    lineTypeField=$2

    # We are interested only in the REM_CLUSTER_KEY lines for the specified cluster.
    if [[ $clusterNameField = $clusterName && $lineTypeField = $REM_CLUSTER_KEY ]]
    then
      # The public key information is everything past the first 4 fields.
      shift 4
      keyLine=$*
      keyLine="${keyLine%%+(:)}"

      # Examine the lines.  If the key was generated by the cs4b version
      # of mmauth genkey, there will be stanza lines and the fingerprint
      # will be included.  If the fingerprint is missing, or if this is
      # a key generated by a cs3b version of mmauth genkey, extract the
      # public key in a temp file.
      if [[ $keyLine = "clusterName="*            ||
            $keyLine = "clusterID="*              ||
            $keyLine = "genkeyFormat="*           ||
            $keyLine = "genkeyCompatibleFormat="* ||
            $keyLine = "keyGenNumber="*           ||
            $keyLine = "publicKey="               ||
            $keyLine = "certificate="             ]]
      then
        :  # Skip the line.

      elif [[ $keyLine = "keyDigest="* ]]
      then
        # Return the key fingerprint.
        keyFingerprint="${keyLine#keyDigest=}"
        break

      else
        # Add the line to the key file.
        IFS=""     # Reset IFS to preserve blanks and tabs.
        print -- "$keyLine" >> $tmpPublicKey
        checkForErrors "writing to file $tmpPublicKey" $?
      fi  # end of if [[ $keyLine = "clusterName="* ]]
    fi  # end of if [[ $clusterNameField = $clusterName && ...

    IFS=":" # Change the separator back to ":" for the next iteration.

  done  # end while read -u4 sdrfsLine

  IFS="$IFS_sv"  # Restore the default IFS settings.

  # If the fingerprint was not imbedded in the key stanza,
  # determine it with the help of the openssl command.
  if [[ -z $keyFingerprint && -s $tmpPublicKey ]]
  then
    keyFingerprint=$($openssl dgst -sha -hex < $tmpPublicKey)
    checkForErrors "openssl dgst -sha -hex $tmpPublicKey" $?
  fi
  [[ -z $keyFingerprint ]] && keyFingerprint="(undefined)"

  # Return the result.
  print -- "$keyFingerprint"
  return 0

}  #------------ end function getFingerprint -----------------


################################################################
#
# Function:  Create a list with the names of the file
#            systems in a given cluster.
#
# Input:     $1 - cluster name
#            $2 - sdrfs file to use
#
# Output:    A line with the local and remote file system names
#            for all file systems in the requested cluster.
#            The names have the following format:
#               localFSname (remoteFSname) ...
#
# Returns:   0 - success
#            1 - error encountered
#
################################################################
function getFileSystemList   # <clusterName> <sdrfs>
{
  typeset sourceFile="mmremotecluster.sh"
  [[ -n $DEBUG || -n $DEBUGgetFileSystemList ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset clusterName=$1
  typeset sdrfs=$2

  [[ ! -s $sdrfs ]] &&  \
    checkForErrors "getFileSystemList: Missing or empty file $sdrfs" 1

  $awk -F: '                                           \
    $'$NODESETID_Field' == "'$clusterName'" &&         \
    $'$LINE_TYPE_Field' == "'$SG_HEADR'"    {          \
      if ( $'$FS_TYPE_Field' == "'$remotefs'" ) {      \
        { fsList = fsList $'$DEV_NAME_Field' " ("      \
                   $'$REMOTE_DEV_NAME_Field' ")  " }   \
      }                                                \
      else {                                           \
        { fsList = fsList $'$DEV_NAME_Field' "  " }    \
      }                                                \
    }                                                  \
    END { print fsList }                               \
  ' $sdrfs
  checkForErrors awk $?

  $mmTRACE_EXIT "rc=$rc"
  return $rc

}  #------ end of function getFileSystemList -----------------



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


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

action=$arg1
[[ -z $action ]] &&  \
  syntaxError "missingArgs" $usageMsg

remoteClusterName=$arg2
checkName clusterName 255 "$remoteClusterName"
[[ $? -ne 0 ]] && cleanupAndExit

# Allow "ls" to be used in place of "show".
[[ $action = ls ]] && action=show

# remoteClusterName must be specified for all actions.
# The only exception is the "show" subcommand where "all"
# will be assumed if remoteClusterName is omitted.
if [[ -z $remoteClusterName ]]
then
  if [[ $action = show ]]
  then
    remoteClusterName=all
  elif [[ $action = add || $action = update || $action = delete ]]
  then
    syntaxError "missingArgs" $usageMsg
  else
    syntaxError "keyword" $usageMsg "$action"
  fi
fi  # end of if [[ -z $remoteClusterName ]]

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

# Continue with the rest of the parameters.
if [[ $action = show || $action = delete ]]
then
  # No other arguments are expected.
  [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3

elif [[ $action = add || $action = update ]]
then
  shift 2    # Move past the cluster name in the parameter list.

  # Process the individual arguments and the values associated with them.
  while getopts :C:k:n: OPT
  do
    case $OPT in

      C) [[ -n $Cflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         Cflag="-$OPT"; Carg=$OPTARG;
         [[ $action != update ]] &&  \
           syntaxError "invalidOption" $usageMsg "-$OPT"
         checkName clusterName 255 "$Carg"
         [[ $? -ne 0 ]] && cleanupAndExit
         ;;

      k) [[ -n $kflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         kflag="-$OPT"; karg=$OPTARG;
         [[ -z $karg ]] && karg=DELETE
         ;;

      n) [[ -n $nflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         nflag="-$OPT"; narg=$OPTARG;
         [[ -z $narg ]] && narg=DELETE
         ;;

       +[Ckn) # Invalid option.
          syntaxError "invalidOption" $usageMsg $OPT
          ;;

       :) # Missing argument.
          syntaxError "missingValue" $usageMsg $OPTARG
          ;;

       *) # Invalid option.
          syntaxError "invalidOption" $usageMsg $OPTARG
          ;;
    esac
  done

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

  # Initialize local variables.
  contactNodes=$narg
  newClusterName=$Carg
  keyfile=$karg

  # Check the list of contact nodes.
  if [[ -n $contactNodes &&
        $contactNodes != DELETE && ! -x $remoteclusternodes ]]
  then
    # Parse the list and verify that the names can be resolved.
    IFS=","
    for nodeName in $contactNodes
    do
      IFS="$IFS_sv"

      # Skip over the tcpPort information.
      [[ $nodeName = tcpPort=+([0-9]) ]] && continue

      # Verify the name is resolvable.
      hostResult=$($host $nodeName)
      set -f ; set -- $hostResult ; set +f
      ipa=${3%%,*}   # Exclude everything after the first comma.
      if [[ -z $ipa ]]
      then
        # Invalid node name specified.
        printErrorMsg 54 $mmcmd $nodeName
        cleanupAndExit
      fi
      (( contactNodesCount += 1 ))
      IFS=","
    done  # end of for nodeName in $contactNodes
    IFS="$IFS_sv"
  fi  # end of if [[ -n $contactNodes ]]

else
  # Invalid action requested.
  syntaxError "keyword" $usageMsg "$action"
fi  # end of if [[ $action = show || $action = delete ]]


#####################################################################
# 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 and will obtain the sdr lock.
#####################################################################
if [[ $action = show ]]
then
  trap pretrap2 HUP INT QUIT KILL
  gpfsInitOutput=$(gpfsInit nolock)
  rc=$?
else
  trap pretrap HUP INT QUIT KILL
  gpfsInitOutput=$(gpfsInit $lockId)
  rc=$?
fi
setGlobalVar $rc $gpfsInitOutput


#######################################################################
# Perform any remaining parameter checking that requires knowledge of
# the sdrfsFormatLevel level (set by gpfsInit above).  Ensure the user
# is not trying to utilize function that has not been enabled yet.
#######################################################################
# Ensure the key file exists and has the correct format.
if [[ -n $keyfile && $keyfile != DELETE ]]
then
  verifyPublicKeyFile $keyfile $sdrfsFormatLevel $verifiedKey  \
                      $newClusterName $remoteClusterName
  [[ $? -ne 0 ]] && cleanupAndExit

  if [[ $sdrfsFormatLevel -eq 0 ]]
  then
    # Ensure that the provided key file was generated by a 2.3 version of mmauth.
    $grep -q -e "^clusterName=" $verifiedKey >/dev/null 2>&1
    rc=$?
    if [[ $rc -eq 0 ]]
    then
      print -u2 "$mmcmd:  The specified public key file cannot be handled until you"
      print -u2 "    run \"mmchconfig release=LATEST\" to activate the new function."
      cleanupAndExit
    fi
  fi  # end of if [[ $sdrfsFormatLevel -eq 0 ]]
fi  # end of if [[ -n $keyfile && $keyfile != DELETE ]]


#############################################################################
#
# Go through the mmsdrfs file.
#
# If action is "add", ensure that we can safely add the new remote cluster.
#
# If action is "update", make the needed changes to the mmsdrfs file.
#
# If action is "delete", remove the appropriate lines from the mmsdrfs file.
#
# If action is "show", extract and display the relevant information.
#
#############################################################################
$rm -f $newsdrfs $nodefile $mountCheckList
IFS=":"
exec 3<&-
exec 3< $mmsdrfsFile
while read -u3 sdrfsLine
do
  # Parse the line.
  set -f ; set -A v -- - $sdrfsLine ; set +f

  IFS="$IFS_sv"   # Restore the default IFS settings.
  printLine=true  # Assume the line will be printed.

  # Change some of the fields depending on the type of line.
  case ${v[$LINE_TYPE_Field]} in

    $VERSION_LINE )
      # Increment the generation number.
      newGenNumber=${v[$SDRFS_GENNUM_Field]}+1
      v[$SDRFS_GENNUM_Field]=$newGenNumber

      ourClusterName=${v[$CLUSTER_NAME_Field]}

      if [[ $ourClusterName = $remoteClusterName && $action = add ||
            $ourClusterName = $newClusterName && $action = update ]]
      then
        # The cluster name is the name of the local cluster.
        printErrorMsg 202 $mmcmd $ourClusterName
        cleanupAndExit
      fi
      ;;

    $MEMBER_NODE )
      # Add the reliable node name to nodefile.
      print -- "${v[$REL_HOSTNAME_Field]}" >> $nodefile
      checkForErrors "writing to file $nodefile" $?

      # If this is the line for the node that is executing
      # this command, set the preferredNode variable.
      [[ ${v[$NODE_NUMBER_Field]} = $ourNodeNumber ]] &&  \
        preferredNode=${v[$REL_HOSTNAME_Field]}
      ;;

    $REM_CLUSTER )
      if [[ ${v[$NODESETID_Field]} = $remoteClusterName ||
            $remoteClusterName = all && ($action = show || $action = delete) ]]
      then
        clusterFound=yes
        # Processing depends on the specified action:
        case $action in
          add )
            # The remote cluster is already defined.
            printErrorMsg 316 $mmcmd $remoteClusterName
            cleanupAndExit
            ;;

          update )
            [[ -n $newClusterName ]] &&  \
              v[$NODESETID_Field]=$newClusterName
            [[ -n $contactNodes ]] &&  \
              v[$CONTACT_NODES_Field]=$contactNodes
            [[ $contactNodes = DELETE ]] &&  \
              v[$CONTACT_NODES_Field]=""
            ;;

          delete )
            printLine=false
            ;;

          show )
            # Display the cluster name.
            header=$(printInfoMsg 442)
            printf "%-16s %s\n" "$header" "${v[$NODESETID_Field]}"

            # Display the contact nodes.
            header=$(printInfoMsg 446)
            contactNodes=""
            if [[ -x $remoteclusternodes ]]
            then
              contactNodes=$($remoteclusternodes ${v[$NODESETID_Field]})
              [[ -n $contactNodes ]] &&  \
                contactNodes="$contactNodes  (from $remoteclusternodes)"
            fi
            if  [[ -z $contactNodes ]]
            then
              contactNodes="${v[$CONTACT_NODES_Field]}"
              [[ -z $contactNodes ]] &&  \
                contactNodes="(none specified)"
            fi
            printf "%-16s %s\n" "$header" "$contactNodes"

            # Display the SHA digest (public key fingerprint).
            header=$(printInfoMsg 444)
            keyFingerprint=$(getFingerprint ${v[$NODESETID_Field]} $mmsdrfsFile)
            printf "%-16s %s\n" "$header" "$keyFingerprint"

            # Display the file system names.
            header=$(printInfoMsg 447)
            fsList=$(getFileSystemList ${v[$NODESETID_Field]} $mmsdrfsFile)
            checkForErrors getFileSystemList $?
            [[ -z $fsList ]] && fsList="(none defined)"
            printf "%-16s %s\n\n" "$header" "$fsList"
            ;;

          *) checkForErrors "unexpected action $action" 1
            ;;

        esac  # end of case $action in
      fi  # end of if [[ ${v[$NODESETID_Field]} = $remoteClusterName ]]
      ;;

    $REM_CLUSTER_KEY )
      if [[ ${v[$NODESETID_Field]} = $remoteClusterName ||
            $remoteClusterName = all && ($action = show || $action = delete) ]]
      then
        # Processing depends on the specified action:
        case $action in
          add )
            # The remote cluster is already defined.
            printErrorMsg 316 $mmcmd $remoteClusterName
            cleanupAndExit
            ;;

          update )
            [[ -n $keyfile ]] &&  \
              printLine=false

            if [[ -n $newClusterName ]]
            then
              v[$NODESETID_Field]=$newClusterName
              [[ ${v[$LINE_NUMBER_Field]} = 1 ]] &&  \
                v[$KEY_Field]="clusterName=$newClusterName"
            fi
            ;;

          delete )
            printLine=false
            ;;

          show )
            :  # There is nothing to do for now.
            ;;

          *) checkForErrors "unexpected action $action" 1
            ;;
        esac  # end of case $action in
      fi  # end of if [[ ${v[$NODESETID_Field]} = $remoteClusterName ]]
      ;;

    $SG_HEADR )
      if [[ ${v[$NODESETID_Field]} != $HOME_CLUSTER &&
            ($remoteClusterName = ${v[$NODESETID_Field]} ||
             $remoteClusterName = "all") ]]
      then
        remoteFSfound=yes
        # Processing depends on the specified action:
        case $action in
          add )
            corruptedSdrFileExit 145 "$sdrfsLine"
            cleanupAndExit
            ;;

          update )
            if [[ -n $newClusterName || -n $keyfile ]]
            then
              # Generate the fully-qualified name for the file system.
              # Put it, together with the local device name, on the list
              # of file systems that should not be mounted.
              fsFullName="${v[$NODESETID_Field]}:${v[$REMOTE_DEV_NAME_Field]}"
              print -- "$fsFullName ${v[$DEV_NAME_Field]}" >> $mountCheckList
              checkForErrors "writing to file $mountCheckList" $?

              [[ -n $newClusterName ]] &&  \
                v[$NODESETID_Field]=$newClusterName
            fi
            ;;

          delete )
            # Generate the fully-qualified name for the file system.
            # Put it, together with the local device name, on the list
            # of file systems that should not be mounted.
            fsFullName="${v[$NODESETID_Field]}:${v[$REMOTE_DEV_NAME_Field]}"
            print -- "$fsFullName ${v[$DEV_NAME_Field]}" >> $mountCheckList
            checkForErrors "writing to file $mountCheckList" $?

            printLine=false
            ;;

          show )
            :  # There is nothing to do for now.
            ;;

          *) checkForErrors "unexpected action $action" 1
            ;;

        esac  # end of case $action in
      fi  # end of if [[ ${v[$NODESETID_Field]} = $remoteClusterName ]]
      ;;

    $SG_ETCFS )
      if [[ ${v[$NODESETID_Field]} != $HOME_CLUSTER &&
            ($remoteClusterName = ${v[$NODESETID_Field]} ||
             $remoteClusterName = "all") ]]
      then
        # Processing depends on the specified action:
        case $action in
          add )
            corruptedSdrFileExit 146 "$sdrfsLine"
            cleanupAndExit
            ;;

          update )
            [[ -n $newClusterName ]] &&  \
              v[$NODESETID_Field]=$newClusterName
            ;;

          delete )
            printLine=false
            ;;

          show )
            :  # There is nothing to do for now.
            ;;

          *) checkForErrors "unexpected action $action" 1
            ;;

        esac  # end of case $action in
      fi  # end of if [[ ${v[$NODESETID_Field]} = $remoteClusterName ]]
      ;;

    $SG_MOUNT )
      if [[ ${v[$NODESETID_Field]} != $HOME_CLUSTER &&
            ($remoteClusterName = ${v[$NODESETID_Field]} ||
             $remoteClusterName = "all") ]]
      then
        # Processing depends on the specified action:
        case $action in
          add )
            corruptedSdrFileExit 147 "$sdrfsLine"
            cleanupAndExit
            ;;

          update )
            [[ -n $newClusterName ]] &&  \
              v[$NODESETID_Field]=$newClusterName
            ;;

          delete )
            printLine=false
            ;;

          show )
            :  # There is nothing to do for now.
            ;;

          *) checkForErrors "unexpected action $action" 1
            ;;

        esac  # end of case $action in
      fi  # end of if [[ ${v[$NODESETID_Field]} = $remoteClusterName ]]
      ;;

    * ) : # Pass all other lines without a change.
      ;;

  esac  # end of Change some of the fields

  # Build and write the line to the new mmsdrfs file.
  if [[ $printLine = true ]]
  then
    print_newLine >> $newsdrfs
    checkForErrors "writing to file $newsdrfs" $?
  fi

  IFS=":"  # Change the separator back to ":" for the next iteration.

done  # end of while read -u3 mmsdrfsFile

IFS="$IFS_sv"  # Restore the default IFS settings.


if [[ -z $clusterFound && $action != add ]]
then
  if [[ $remoteClusterName = all && ($action = show || $action = delete) ]]
  then
    # There are no remote cluster definitions.
    printErrorMsg 262 $mmcmd
  else
    # The remote cluster is not defined.
    printErrorMsg 263 $mmcmd $remoteClusterName
  fi
  cleanupAndExit
fi  # end of if [[ -z $clusterFound ]]


#########################################
# Additional action-specific processing.
#########################################

if [[ $action = add ]]
then
  # Generate the needed information for the mmsdrfs file.

  if [[ $contactNodesCount -eq 0 && ! -x $remoteclusternodes ]]
  then
    # No contact nodes were provided for the cluster.
    printErrorMsg 177 $mmcmd $remoteClusterName
    cleanupAndExit
  fi

  # Add the information for the remote cluster to the mmsdrfs file.
  newLine="$remoteClusterName:$REM_CLUSTER:::$contactNodes:"
  print -- "$newLine" >> $newsdrfs
  checkForErrors "writing to file $newsdrfs" $?

  # Process the -k keyfile option.
  if [[ -n $keyfile ]]
  then
    # Add the key to the mmsdrfs file.
    appendFile $remoteClusterName $verifiedKey $REM_CLUSTER_KEY $newsdrfs
    checkForErrors  \
       "appendFile $remoteClusterName $verifiedKey $REM_CLUSTER_KEY $newsdrfs" $?
    refreshAuthNeeded=yes
  fi  # end of if [[ -n $keyfile ]]
fi  # end of if [[ $action = add ]]


if [[ $action = update ]]
then
  if [[ -z $newClusterName && -z $contactNodes && -z $keyfile ]]
  then
    # No changes were made.
    printErrorMsg 323 $mmcmd
    cleanupAndExit
  fi

  # Update the cluster name if changed.
  [[ -n $newClusterName ]] && remoteClusterName=$newClusterName

  # Process the -n contactNodes option.
  if [[ -n $contactNodes ]]
  then
    if [[ $contactNodes != DELETE  &&
          $contactNodesCount -eq 0 &&
          ! -x $remoteclusternodes ]]
    then
      # No contact nodes were provided for the cluster.
      printErrorMsg 177 $mmcmd $remoteClusterName
      cleanupAndExit
    fi
    propagateOptions="rereadContactNodes${remoteClusterName},${propagateOptions}"
  fi  # end of if [[ -n $contactNodes ]]

  # Process the -k keyfile option.
  if [[ -n $keyfile ]]
  then
    if [[ $keyfile != DELETE ]]
    then
      # Add the key to the mmsdrfs file.
      appendFile $remoteClusterName $verifiedKey $REM_CLUSTER_KEY $newsdrfs
      checkForErrors  \
         "appendFile $remoteClusterName $verifiedKey $REM_CLUSTER_KEY $newsdrfs" $?
    fi  # end of if [[ $keyfile != DELETE ]]
    refreshAuthNeeded=yes
  fi  # end of if [[ -n $keyfile ]]
fi  # end of if [[ $action = update ]]


# if [[ $action = delete ]]
# then
#   : # Add additional processing if needed.
# fi


if [[ $action = show ]]
then
  # There is nothing more to do.
  cleanupAndExit 0
fi


############################################
# Sort the new version of the mmsdrfs file.
############################################
LC_ALL=C $SORT_MMSDRFS $newsdrfs -o $newsdrfs
checkForErrors "sorting $newsdrfs" $?


############################################
# Lock the gpfs object to prevent daemons
# from starting during the commit phase.
############################################
[[ $getCredCalled = no ]] && getCred
setRunningCommand "$mmcmd" $primaryServer
checkForErrors setRunningCommand $?
gpfsLocked=yes


################################################################
# Make sure that file systems that should not be mounted
# are indeed not mounted.  Note that the scope of the mount
# restriction is our own cluster only.  It is OK for the file
# systems to be mounted elsewhere.
################################################################
if [[ -s $mountCheckList ]]
then
  exec 3<&-
  exec 3< $mountCheckList
  while read -u3 mountCheckLine
  do
    # Parse the line.
    set -f ; set -- $mountCheckLine ; set +f
    fsFullName=$1
    localDevName=$2

    # Keep going if this file system belongs to a cluster that
    # already has been determined to be down or unreachable.
    [[ $skipList = *" ${fsFullName%%:*} "* ]] && continue

    $mmcommon onactive $preferredNode $nodefile $NO_FILE_COPY   \
       $fsFullName $ourClusterName $NO_LINK $MOUNT_CHECK_ONLY ldev=$localDevName 2>$errMsg
    rc=$?
    if [[ $rc -eq $MM_FsMounted ]]
    then
      # The file system is still mounted (messages were issued by mmcommon).
      cleanupAndExit
    elif [[ $rc -eq $MM_FsNotFound || $rc -eq $MM_Remotefs ]]
    then
      # The file system was not found, so it cannot be mounted.
      rc=0
    elif [[ $rc -eq $MM_HostDown ||
            $rc -eq $MM_TimedOut ||
            $rc -eq $MM_UnknownCluster ||
            $rc -eq $MM_SecurityCfg ||
            $rc -eq $MM_AuthorizationFailed ]]
    then
      # We failed to connect to the remote cluster.
      rc=0
      if [[ $remoteClusterName = all ]]
      then
        # We are dealing with more than one remote cluster.
        # Do not try to contact this cluster any more.
        # Note:  The trailing blank is important!
        skipList="${skipList} ${fsFullName%%:*} "
      else
        # There is only one remote cluster, and we could not connect to it.
        # Exit the loop since none of its file systems can be mounted.
        break
      fi
    elif [[ $rc -eq $MM_DaemonDown ]]
    then
      # GPFS is down on all nodes in the local cluster.
      # There are no mounted file systems, so exit the loop.
      rc=0
      break
    elif [[ $rc -eq $MM_ConnectionReset ]]
    then
      # An internode connection was reset.
      printErrorMsg 257 $mmcmd
      cleanupAndExit
    elif [[ $rc -ne 0 ]]
    then
      if [[ -s $errMsg ]]
      then
        # Show the error messages from the daemon.
        $cat $errMsg 1>&2
      else
        # The mount check failed and there were no messages from the daemon.
        printErrorMsg 104 $mmcmd "mmcommon onactive $fsFullName MOUNT_CHECK"
      fi
      # The command was unable to determine whether the file system is mounted.
      printErrorMsg 564 $mmcmd $localDevName
      cleanupAndExit
    fi  # end of if [[ $rc -eq $MM_FsMounted ]]
    $rm -f $errMsg
  done  # end of while read -u3 mountCheckLine
  $rm -f $errMsg
fi  # end of if [[ -s $mountCheckList ]]


############################################################
# Replace the mmsdrfs file in the sdr with the new version.
############################################################
trap "" HUP INT QUIT KILL
gpfsObjectInfo=$(commitChanges  \
   $nsId $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer)
rc=$?
if [[ $rc -ne 0 ]]
then
  # The commit step failed; we cannot replace the file in the sdr.
  printErrorMsg 381 $mmcmd
  cleanupAndExit
fi


##################
# Unlock the sdr.
##################
freeLockOnServer $primaryServer $ourNodeNumber >/dev/null
sdrLocked=no
trap posttrap HUP INT QUIT KILL

# Issue "command was successful" message.
printErrorMsg 272 $mmcmd


#####################################################
# Asynchronously propagate the changes to all nodes.
#####################################################
propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber $propagateOptions

if [[ -n $refreshAuthNeeded ]]
then
  # Notify all currently-running nodes to refresh their key files.
  $mmcommon onactive $preferredNode $nodefile    \
    $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK  \
    tsdsh $mmremote refreshAuth >$tmpfile 2>&1
fi

cleanupAndExit 0

