#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2004,2005 
# 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 
# @(#)17 1.14 src/avs/fs/mmfs/ts/admin/mmdsm.sh, mmfs, avs_rgpfs24, rgpfs240610b 7/21/05 01:45:41
#############################################################################
#
# Common interface module for DSM support.
#
# Usage:  mmdsm <action> <arg1> <arg2> ...
#
# where action is one of the following:
#
#   dsmGetClusterType - retrieve the GPFS cluster type
#   dsmGetNodeNumber  - retrieve the local node's GPFS node number
#   dsmGetNodesetId   - retrieve the nodeset to which this node belongs
#   dsmGetNodeCount   - retrieve the number of nodes in the nodeset
#   dsmPutHsmdata     - store the HSM data for a given nodeset
#   dsmGetHsmdata     - retrieve the HSM data for a given nodeset
#   dsmPutHsmversion  - store the version information for the HSM data
#   dsmGetHsmversion  - retrieve the version information for the HSM data
#   dsmGetConfigServerState - verify both config servers are up
#   dsmGetFileSystems       - create a list of all file systems
#   dsmIsFileSystemLocal    - check if a file system is local or remote
#
# For additional information and description of arguments and
# return codes, see the prolog of the corresponding function.
#
#############################################################################

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

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

# To get mmdsm error messages, specify a file name in the dsmLog variable.
# If this variable is not defined, all error messages will be discarded.
[[ -z $dsmLog ]] && dsmLog="/dev/null"

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

LOCAL_FILES=" "


# Local variables
rc=0


# Local functions


###########################################################################
#
# Function:  Called if there is an interrupt before changes are committed.
#            Removes temporary files and unlocks the sdr if necessary.
#
# Input:     None
#
# Output:    None
#
# Returns:   Exits with code 2
#
###########################################################################
function localPretrap
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGlocalPretrap ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset ec=0

  trap "" HUP INT QUIT KILL    # Disable traps so we won't get interrupted.

  [[ -z $MMMODE ]] && determineMode 2>> $dsmLog

  # We come here if an interrupt was received and
  # no changes have been made to the sdrfs file.
  # Display any buffered error messages that might be there.
  [[ -s $errMsg ]] && $cat $errMsg 1>&2 2>> $dsmLog
  printErrorMsg 306 $mmcmd 2>> $dsmLog
  $rm -f $GLOBAL_FILES $LOCAL_FILES

  if [[ $gpfsLocked = yes ]]
  then
    setRunningCommand null $primaryServer
    ec=$?
    if [[ $ec -ne 0 ]]
    then
      printErrorMsg 171 $mmcmd "function setRunningCommand" $ec 2>> $dsmLog
    fi
  fi

  [[ $envLocked = yes ]] &&  \
    freeEnvLock >/dev/null 2>> $dsmLog
  envLocked=no

  [[ $sdrLocked = yes ]] &&  \
    freeLockOnServer $primaryServer $ourNodeNumber >/dev/null 2>> $dsmLog
  sdrLocked=no

  trap - HUP INT QUIT KILL     # Restore interrupts.
  exit 2

}  #--------- end of function localPretrap ---------------------------


###########################################################################
#
# Function:  Called if there is an interrupt after changes were committed.
#            Removes temporary files and unlocks the sdr if necessary.
#
# Input:     None
#
# Output:    None
#
# Returns:   Exits with code 2
#
###########################################################################
function localPosttrap
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGlocalPosttrap ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset ec=0

  trap "" HUP INT QUIT KILL    # Disable traps so we won't get interrupted.

  [[ -z $MMMODE ]] && determineMode 2>> $dsmLog

  # Interrupt received: changes not propagated.
  # Display any buffered error messages that might be there.
  [[ -s $errMsg ]] && $cat $errMsg 1>&2 2>> $dsmLog
  printErrorMsg 32 $mmcmd 2>> $dsmLog
  $rm -f $GLOBAL_FILES $LOCAL_FILES

  if [[ $gpfsLocked = yes ]]
  then
    setRunningCommand null $primaryServer
    ec=$?
    if [[ $ec -ne 0 ]]
    then
      printErrorMsg 171 $mmcmd "function setRunningCommand" $ec 2>> $dsmLog
    fi
  fi

  [[ $envLocked = yes ]] &&  \
    freeEnvLock >/dev/null 2>> $dsmLog
  envLocked=no

  [[ $sdrLocked = yes ]] &&  \
    freeLockOnServer $primaryServer $ourNodeNumber >/dev/null 2>> $dsmLog
  sdrLocked=no

  trap - HUP INT QUIT KILL     # Restore interrupts.
  exit 2

}  #--------- end of function localPosttrap ---------------------------


##########################################################################
#
# Function:  Retrieve the name of the nodeset to which this node belongs.
#
# Input:     None.
#
# Output:    Nodeset identifier or zero.
#
# Returns:   0 - no errors encountered
#            non-zero - unexpected error
#
##########################################################################
function dsmGetNodesetId  #
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmGetNodesetId ]] && set -x

  # Ensure that the local copy of the mmsdrfs is up-to-date.
  gpfsInitOutput=$(gpfsInit nolock)
  setGlobalVar $? $gpfsInitOutput

  # Display the nodeset name.
  print -- "$nsId"

  return 0

}  #------------ end function dsmGetNodesetId -----------------


##########################################################################
#
# Function:  Retrieve the number of nodes in the current nodeset.
#
# Input:     None.
#
# Output:    Number of nodes.
#
# Returns:   0 - no errors encountered
#            non-zero - unexpected error
#
##########################################################################
function dsmGetNodeCount  #
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmGetNodeCount ]] && set -x

  # Ensure that the local copy of the mmsdrfs is up-to-date.
  gpfsInitOutput=$(gpfsInit nolock)
  setGlobalVar $? $gpfsInitOutput

  # Find out the number of nodes in the local nodeset.
  # The result is displayed on stdout.
  getNodesetInfo $NODE_COUNT_Field $nsId $mmsdrfsFile

  return 0

}  #------------ end function dsmGetNodeCount -----------------


##########################################################################
#
# Function:  Append the specified file with HSM data to the mmsdrfs file.
#
# Input:     $1 - nodeset to which the data pertains
#            $2 - path name of file to store in the sdr or DELETE
#            $3 - path name of file with version information (optional)
#            $4 - mmsdrfs file version (generation) number (optional)
#
# Returns:   0 - no errors encountered
#            non-zero - unexpected error
#
##########################################################################
function dsmPutHsmdata  # <nodesetId> <inputFile> [<versionFile> [<genNumber>]]
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmPutHsmdata ]] && set -x
  typeset hsmNodesetId=$1
  typeset inputFile=$2
  typeset versionFile=$3
  typeset genNumber=$4

  typeset gpfsInitOutput sdrfsLine printLine inLine rc
  typeset replaceVersionInfo=''
  typeset removeHSMdata=''
  typeset -i lineNumber=0

  [[ -z $genNumber ]] && genNumber=0

  if [[ $hsmNodesetId = DELETE ]]
  then
    removeHSMdata=yes
  else
    [[ ! -f $inputFile ]] && cleanupAndExit
    [[ -f $versionFile ]] && replaceVersionInfo=yes
  fi

  #######################################################################
  # Ensure that the local copy of the mmsdrfs is up-to-date.
  #######################################################################
  gpfsInitOutput=$(gpfsInit $lockId)
  setGlobalVar $? $gpfsInitOutput

  ########################################################################
  # Go through the current mmsdrfs file.  Increment the generation
  # number and build the node name list that will be needed later.
  # Remove all HSMDATA lines that are currently in the file so that
  # they can be replaced with their new version.
  ########################################################################
  $rm -f $newsdrfs $nodefile
  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.

    case ${v[$LINE_TYPE_Field]} in

      $VERSION_LINE )
        # If requested, ensure that the current version of the mmsdrfs
        # file matches the caller's version of the data.
        [[ $genNumber -gt 0 && $genNumber -ne ${v[$SDRFS_GENNUM_Field]} ]] &&  \
          return 52  # ESTALE

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

      $MEMBER_NODE )
        # Collect the reliable names of all nodes in the cluster.
        print -- "${v[$REL_HOSTNAME_Field]}" >> $nodefile
        checkForErrors "writing to file $nodefile" $?
        ;;

      $HSMDATA )
        # This is a line with HSM data.
        # Remove the line if it is for the right nodeset.
        [[ ${v[$HSM_NODESET_Field]} = $hsmNodesetId || -n $removeHSMdata ]] && \
          printLine=false
        ;;

      $HSMVERSION )
        # This is a HSMVERSION line.
        # Remove the line from the mmsdrfs file if the
        # version information will be updated as well.
        [[ -n $replaceVersionInfo || -n $removeHSMdata ]] &&  \
          printLine=false
        ;;

      * )  # Not interested in any other lines.
        ;;

    esac  # end of case ${v[$LINE_TYPE_Field]} in

    # 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 while read -u3

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

  #########################################################
  # Append the user-provided input file to the sdrfs file.
  #########################################################
  if [[ -z $removeHSMdata ]]
  then
    exec 3<&-
    exec 3< $inputFile
    IFS=""     # Reset IFS to preserve blanks and tabs.
    while read -u3 inLine
    do
      lineNumber=$lineNumber+1
      print -- "$DSM_DATA:$HSMDATA:$hsmNodesetId:$lineNumber:$inLine" >> $newsdrfs
    done
    checkForErrors "writing to file $newsdrfs" $?
    IFS="$IFS_sv"
  fi  # end of if [[ -z $removeHSMdata ]]

  #########################################################
  # If the version information needs to be updated as well,
  # append the user-provided input file to the sdrfs file.
  #########################################################
  if [[ -n $replaceVersionInfo && -z $removeHSMdata ]]
  then
    exec 3<&-
    exec 3< $versionFile
    IFS=""     # Reset IFS to preserve blanks and tabs.
    lineNumber=0
    while read -u3 inLine
    do
      lineNumber=$lineNumber+1
      print -- "$DSM_DATA:$HSMVERSION::$lineNumber:$inLine" >> $newsdrfs
    done
    checkForErrors "writing to file $newsdrfs" $?
    IFS="$IFS_sv"
  fi  # end of if [[ -n $replaceVersionInfo && -z $removeHSMdata ]]

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

  ####################################################################
  # Put the new mmsdrfs file into the sdr.  This commits the changes.
  ####################################################################
  trap "" HUP INT QUIT KILL
  gpfsObjectInfo=$(commitChanges  \
     $nsId $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer)
  rc=$?
  if [[ $rc -ne 0 ]]
  then
    # The commit step failed.
    printErrorMsg 381 $mmcmd
    cleanupAndExit
  fi

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

  ###############################################
  # Propagate the changes to all affected nodes.
  ###############################################
  propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber

  return 0

}  #------------ end function dsmPutHsmdata -----------------


##########################################################################
#
# Function:  Retrieve the HSM data from the mmsdrfs file.
#
# Input:     $1 - nodeset to which the data pertains
#            $2 - name of a file where to store the HSM data
#            $3 - (optional) assume cached data is current
#
# Returns:   0 - no errors encountered
#            1 - unexpected error
#            3 - HSM data not found in the repository
#
##########################################################################
function dsmGetHsmdata  # <nodesetId> <outputFile> [norefresh]
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmGetHsmdata ]] && set -x
  typeset hsmNodesetId=$1
  typeset outputFile=$2
  typeset -l refreshArg=$3

  typeset gpfsInitOutput sdrfsLine nodesetIdField hsmNodesetField
  typeset lineTypeField outLine

  #######################################################################
  # Ensure that the local copy of the mmsdrfs is up-to-date.
  #######################################################################
  if [[ $refreshArg != "norefresh" ]]
  then
    gpfsInitOutput=$(gpfsInit nolock)
    setGlobalVar $? $gpfsInitOutput
  fi

  ##############################################################################
  # Go through the current mmsdrfs file and retrieve the requested information.
  ##############################################################################
  $rm -f $outputFile
  IFS=":"
  exec 3<&-
  exec 3< $mmsdrfsFile
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -- $sdrfsLine ; set +f
    nodesetIdField=$1
    lineTypeField=$2
    hsmNodesetField=$3

    # We are interested only in the HSMDATA lines for
    # the specified HSM nodeset id.
    if [[ $nodesetIdField = $DSM_DATA &&
          $lineTypeField  = $HSMDATA  &&
          $hsmNodesetField = $hsmNodesetId ]]
    then
      # The HSM information is everything past the first 4 fields.
      shift 4
      outLine=$*

      # To preserve tabs, temporarily set IFS to new line only.
      IFS="
"
      # Strip trailing colons and add the line to the output file.
      print -- "${outLine%%+(:)}" >> $outputFile
      checkForErrors "writing to file $outputFile" $?
      IFS=":" # Change the separator back to ":" for the next iteration
    fi

  done  # end while read -u3 sdrfsLine

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

  if [[ -s $outputFile ]]
  then
    return 0  # HSM data successfully retrieved.
  else
    return 3  # HSM data does not exist.
  fi

}  #------------ end function dsmGetHsmdata -----------------


##########################################################################
#
# Function:  Append the version information for the HSM data.
#
# Input:     $1 - path name of file to store in the sdr
#            $2 - mmsdrfs file version (generation) number (optional)
#
# Returns:   0 - no errors encountered
#            non-zero - unexpected error
#
##########################################################################
function dsmPutHsmversion  # <inputFile> [<genNumber>]
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmPutHsmversion ]] && set -x
  typeset inputFile=$1
  typeset genNumber=$2

  typeset gpfsInitOutput sdrfsLine printLine inLine rc
  typeset -i lineNumber=0

  [[ ! -f $inputFile ]] && cleanupAndExit
  [[ -z $genNumber ]] && genNumber=0

  #################################################################
  # Ensure that the local copy of the mmsdrfs is up-to-date.
  #################################################################
  gpfsInitOutput=$(gpfsInit $lockId)
  setGlobalVar $? $gpfsInitOutput

  #################################################################
  # Go through the current mmsdrfs file.  Increment the generation
  # number and build the node name list that will be needed later.
  # Remove all HSMVERSION lines that are currently in the file
  # so that they can be replaced with their new version.
  #################################################################
  $rm -f $newsdrfs $nodefile
  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.

    case ${v[$LINE_TYPE_Field]} in

      $VERSION_LINE )
        # If requested, ensure that the current version of the mmsdrfs
        # file matches the caller's version of the data.
        [[ $genNumber -gt 0 && $genNumber -ne ${v[$SDRFS_GENNUM_Field]} ]] &&  \
          return 52  # ESTALE

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

      $MEMBER_NODE )
        # Collect the reliable names of all nodes in the cluster.
        print -- "${v[$REL_HOSTNAME_Field]}" >> $nodefile
        checkForErrors "writing to file $nodefile" $?
        ;;

      $HSMVERSION )
        # This is a HSMVERSION line.
        # Remove the line from the mmsdrfs file.
        printLine=false
        ;;

      * )  # Not interested in any other lines.
        ;;

    esac  # end of case ${v[$LINE_TYPE_Field]} in

    # 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 while read -u3

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

  #########################################################
  # Append the user-provided input file to the sdrfs file.
  #########################################################
  exec 3<&-
  exec 3< $inputFile
  IFS=""     # Reset IFS to preserve blanks and tabs.
  while read -u3 inLine
  do
    lineNumber=$lineNumber+1
    print -- "$DSM_DATA:$HSMVERSION::$lineNumber:$inLine" >> $newsdrfs
  done
  checkForErrors "writing to file $newsdrfs" $?
  IFS="$IFS_sv"

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

  ####################################################################
  # Put the new mmsdrfs file into the sdr.  This commits the changes.
  ####################################################################
  trap "" HUP INT QUIT KILL
  gpfsObjectInfo=$(commitChanges  \
     $nsId $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer)
  rc=$?
  if [[ $rc -ne 0 ]]
  then
    # The commit step failed.
    printErrorMsg 381 $mmcmd
    cleanupAndExit
  fi

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

  ###############################################
  # Propagate the changes to all affected nodes.
  ###############################################
  propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber

  return 0

}  #------------ end function dsmPutHsmversion -----------------


##########################################################################
#
# Function:  Retrieve the version information for the HSM data.
#
# Input:     $1 - name of a file where to store the data
#            $2 - (optional) assume cached data is current
#
# Output:    current version (generation) number of the mmsdrfs file.
#
# Returns:   0 - no errors encountered
#            1 - unexpected error
#            3 - data not found in the repository
#
##########################################################################
function dsmGetHsmversion  # <outputFile> [norefresh]
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmGetHsmversion ]] && set -x
  typeset outputFile=$1
  typeset -l refreshArg=$2

  typeset gpfsInitOutput sdrfsLine nodesetIdField lineTypeField outLine
  typeset genNumber

  ###########################################################
  # Ensure that the local copy of the mmsdrfs is up-to-date.
  ###########################################################
  if [[ $refreshArg != "norefresh" ]]
  then
    gpfsInitOutput=$(gpfsInit nolock)
    setGlobalVar $? $gpfsInitOutput
  fi

  ##############################################################################
  # Go through the current mmsdrfs file and retrieve the requested information.
  ##############################################################################
  $rm -f $outputFile
  IFS=":"
  exec 3<&-
  exec 3< $mmsdrfsFile
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -- $sdrfsLine ; set +f
    nodesetIdField=$1
    lineTypeField=$2

    # Get the current mmsdrfs gen number.
    [[ $lineTypeField = $VERSION_LINE ]] && genNumber=$6

    # We are interested only in the HSMVERSION lines.
    if [[ $nodesetIdField = $DSM_DATA && $lineTypeField = $HSMVERSION ]]
    then
      # The HSM version information is everything past the first 4 fields.
      shift 4
      outLine=$*

      # To preserve tabs, temporarily set IFS to new line only.
      IFS="
"
      # Strip trailing colons and add the line to the output file.
      print -- "${outLine%%+(:)}" >> $outputFile
      checkForErrors "writing to file $outputFile" $?
      IFS=":" # Change the separator back to ":" for the next iteration.
    fi

  done  # end while read -u3 sdrfsLine

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

  print -- "$genNumber"
  if [[ -s $outputFile ]]
  then
    return 0  # HSM version information successfully retrieved.
  else
    return 3  # HSM version information does not exist.
  fi

}  #------------ end function dsmGetHsmversion -----------------


###################################################################
#
# Function:  Check whether both the primary and backup config
#            servers are available.
#
# Input:     $1 - (optional) assume cached data is current
#
# Output:    getConfigServerState:<up | down>
#
# Returns:   0 - both config servers are available.
#            1 - at least one of the servers does not respond,
#                or some other unexpected error.
#
###################################################################
function getConfigServerState
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGgetConfigServerState ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset -l refreshArg=$1

  typeset versionLine=""
  typeset serverState="up"
  typeset rc=0
  typeset primaryServer backupServer

  # Ensure that the local copy of the mmsdrfs is up-to-date.
  if [[ $refreshArg != "norefresh" ]]
  then
    gpfsInitOutput=$(gpfsInit nolock)
    setGlobalVar $? $gpfsInitOutput
  fi

  # Parse the version line of the mmsdrfs file.
  versionLine=$($head -1 $mmsdrfsFile)
  IFS=':'
  set -f ; set -A v -- - $versionLine ; set +f
  IFS="$IFS_sv"

  # Perform a quick sanity check.
  [[ ${v[$LINE_TYPE_Field]} != $VERSION_LINE ]] &&  \
    corruptedSdrFileExit 143 "$versionLine"

  # Get the config server names.
  primaryServer=${v[$PRIMARY_SERVER_Field]}
  backupServer=${v[$BACKUP_SERVER_Field]}
  [[ $backupServer = "_NOSECONDARY_" ]] && backupServer=""

  # Verify the primary server is reachable.
  isNodeReachable $primaryServer
  rc=$?
  [[ $rc -ne 0 ]] && serverState=down

  # Verify the backup server is reachable.
  if [[ $rc -eq 0 && -n $backupServer ]]
  then
    isNodeReachable $backupServer
    rc=$?
    [[ $rc -ne 0 ]] && serverState=down
  fi

  # Generate and display the result.
  print -- "getConfigServerState:$serverState"

  return $rc

}  #------ end of function getConfigServerState -------------------


###################################################################
#
# Function:  Create a list of all local and remote file systems.
#
# Input:     $1 - name of a file where to store the result
#            $2 - (optional) assume cached data is current
#
# Output:    A file with all file system device names, one per line.
#            The names of all local file systems found in the cluster
#            are preceded by "0:",  while the names of the remote file
#            systems are preceded by "93:" (MM_Remotefs).
#
# Returns:    0 - success
#            19 - no file systems found
#            nn - some other unexpected error
#
###################################################################
function dsmGetFileSystems # <outputFile> [<norefresh>]
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmGetFileSystems ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset outputFile=$1
  typeset -l refreshArg=$2

  typeset rc=0


  # Ensure that the local copy of the mmsdrfs is up-to-date.
  if [[ $refreshArg != "norefresh" ]]
  then
    gpfsInitOutput=$(gpfsInit nolock)
    setGlobalVar $? $gpfsInitOutput
  fi

  # Generate the requested information.
  $rm -f $outputFile
  $awk -F: '                                                       \
    BEGIN { rc = '$MM_DeviceNotFound' }                            \
    $'$LINE_TYPE_Field' == "'$SG_HEADR'"  {                        \
      if ($'$FS_TYPE_Field' == "'$remotefs'") {                    \
        { print "93:/dev/"$'$DEV_NAME_Field' >> "'$outputFile'" }  \
      }                                                            \
      else {                                                       \
        { print "0:/dev/"$'$DEV_NAME_Field' >> "'$outputFile'" }   \
      }                                                            \
      { rc = 0 }                                                   \
    }                                                              \
    END { exit rc }                                                \
  ' $mmsdrfsFile
  rc=$?

  return $rc

}  #------ end of function dsmGetFileSystems -------------------


###################################################################
#
# Function:  Check whether a given file system is local or remote.
#
# Input:     $1 - file system device name
#            $2 - (optional) assume cached data is current
#
# Output:     0 - file system is local
#            93 - file system is remote
#
# Returns:    0 - file system is local
#            93 - file system is remote
#            19 - file system not found
#            nn - some other unexpected error
#
###################################################################
function dsmIsFileSystemLocal   # <deviceName> [<norefresh>]
{
  typeset sourceFile="mmdsm.sh"
  [[ -n $DEBUG || -n $DEBUGdsmIsFileSystemLocal ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset device=$1
  typeset -l refreshArg=$2

  typeset rc=0
  typeset gpfsInitOutput findFSoutput fqDeviceName deviceName fsHomeCluster

  # Ensure that the local copy of the mmsdrfs is up-to-date.
  if [[ $refreshArg != "norefresh" ]]
  then
    gpfsInitOutput=$(gpfsInit nolock)
    setGlobalVar $? $gpfsInitOutput
  fi

  # Make sure the specified file system exists and is local.
  findFSoutput=$(findFS "$device" $mmsdrfsFile)
  rc=$?
  [[ $rc -ne 0 || -z $findFSoutput ]] && return $rc

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

  # Figure out the proper return information.
  if [[ $fsHomeCluster = $HOME_CLUSTER ]]
  then
    print -- "0"
    rc=0
  else
    print -- "$MM_Remotefs"
    rc=$MM_Remotefs
  fi

  return $rc

}  #------ end of function dsmIsFileSystemLocal -------------------


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

# Set local trap routine.
trap localPretrap HUP INT QUIT KILL

[[ $dsmLog != "/dev/null" ]] &&  \
  print -- "$(date) ENTER: mmdsm $*"  >> $dsmLog

kword=$arg1
if [[ -z $kword ]]
then
  # Missing keyword
  printErrorMsg 133 $mmcmd NULL
  cleanupAndExit
fi

# Determine the execution environment.
[[ -z $MMMODE ]] && determineMode 2>> $dsmLog

# Make sure we have the proper credentials.
[[ $getCredCalled = no ]] && getCred 2>> $dsmLog


# Perform the requested action.
case $kword in

                     #-------------------------
  dsmGetClusterType) # mmdsm dsmGetClusterType
                     #-------------------------
    # Retrieve the GPFS cluster type.
    print -- "$MMMODE"
    rc=$?
    ;;

                    #------------------------
  dsmGetNodeNumber) # mmdsm dsmGetNodeNumber
                    #------------------------
    # Retrieve the local node data.
    getLocalNodeData 2>> $dsmLog
    [[ -n $ourNodeNumber ]] && print -- "$ourNodeNumber"
    rc=$?
    ;;

                    #------------------------
  dsmGetNodesetId)  # mmdsm dsmGetNodesetId
                    #------------------------
    # Retrieve the nodeset name.
    dsmGetNodesetId 2>> $dsmLog
    rc=$?
    ;;

                    #------------------------
  dsmGetNodeCount)  # mmdsm dsmGetNodeCount
                    #------------------------
    # Retrieve the number of nodes in the nodeset.
    dsmGetNodeCount 2>> $dsmLog
    rc=$?
    ;;

                  #----------------------------------------------------------
  dsmGetHsmdata)  # mmdsm dsmGetHsmdata <nodesetId> <outputFile> [norefresh]
                  #----------------------------------------------------------
    if [[ $argc -lt 3 ]]
    then
      operands=" <nodesetId> <outputFile> [norefresh] "
      printErrorMsg 260 $mmcmd $kword "$operands"
      cleanupAndExit
    fi

    # Retrieve the HSM data.
    dsmGetHsmdata "$arg2" "$arg3" "$arg4"  2>> $dsmLog
    rc=$?
    ;;

                  #-------------------------------------------------------------
  dsmPutHsmdata)  # mmdsm dsmPutHsmdata <nodesetId> <inputFile>
                  #                     [<versionFile> [<mmsdrfsVersion>]]
                  #-------------------------------------------------------------
    if [[ $argc -lt 2 ]]
    then
      operands=" {<nodesetId> | DELETE} <inputFile> [<versionFile> [<mmsdrfsVersion>]] "
      printErrorMsg 260 $mmcmd $kword "$operands"
      cleanupAndExit
    fi

    # Store the HSM data in the mmsdrfs file.
    dsmPutHsmdata "$arg2" "$arg3" "$arg4" "$arg5"  2>> $dsmLog
    rc=$?
    ;;

                     #-------------------------------------------------
  dsmGetHsmversion)  # mmdsm dsmGetHsmversion <outputFile> [norefresh]
                     #-------------------------------------------------
    if [[ $argc -lt 2 ]]
    then
      operands=" <outputFile> [norefresh] "
      printErrorMsg 260 $mmcmd $kword "$operands"
      cleanupAndExit
    fi

    # Retrieve the version information for the HSM data.
    dsmGetHsmversion "$arg2" "$arg3"  2>> $dsmLog
    rc=$?
    ;;

                     #-------------------------------------------------------
  dsmPutHsmversion)  # mmdsm dsmPutHsmversion <inputFile> [<mmsdrfsVersion>]
                     #-------------------------------------------------------
    if [[ $argc -lt 2 ]]
    then
      operands=" <inputFile> [<mmsdrfsVersion>] "
      printErrorMsg 260 $mmcmd $kword "$operands"
      cleanupAndExit
    fi

    # Store the version information for the HSM data.
    dsmPutHsmversion "$arg2" "$arg3"  2>> $dsmLog
    rc=$?
    ;;

                            #-------------------------------------------
  dsmGetConfigServerState)  # mmdsm dsmGetConfigServerState [norefresh]
                            #-------------------------------------------
    # Confirm that both config servers are available.
    getConfigServerState "$arg2"  2>> $dsmLog
    rc=$?
    ;;

                      #--------------------------------------------------
  dsmGetFileSystems)  # mmdsm dsmGetFileSystems <outputFile> [norefresh]
                      #--------------------------------------------------
    if [[ $argc -lt 2 ]]
    then
      operands=" <outputFile> [norefresh] "
      printErrorMsg 260 $mmcmd $kword "$operands"
      cleanupAndExit
    fi

    # Retrieve the file system information.
    dsmGetFileSystems "$arg2" "$arg3" 2>> $dsmLog
    rc=$?
    ;;

                         #-----------------------------------------------------
  dsmIsFileSystemLocal)  # mmdsm dsmIsFileSystemLocal <deviceName> [norefresh]
                         #-----------------------------------------------------
    if [[ $argc -lt 2 ]]
    then
      operands=" <deviceName> [<norefresh>] "
      printErrorMsg 260 $mmcmd $kword "$operands"
      cleanupAndExit
    fi

    # Find out if a file system is local or remote.
    dsmIsFileSystemLocal "$arg2" "$arg3"  2>> $dsmLog
    rc=$?
    ;;

        #--------------------------
  * )   # Unknown action requested
        #--------------------------
    # Invalid keyword
    printErrorMsg 133 $mmcmd $kword
    cleanupAndExit
    ;;

esac  # end Perform the requested action

[[ $dsmLog != "/dev/null" ]] &&  \
  print -- "$(date) EXIT (rc=$rc)" >> $dsmLog

cleanupAndExit $rc 2>> $dsmLog

