#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,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 
# @(#)83 1.109.1.2 src/avs/fs/mmfs/ts/admin/mmfsfuncs.sh, mmfs, avs_rgpfs24, rgpfs24s012a 3/29/07 13:07:03
######################################################################


######################################################################
#  Pull in operating system dependent functions and declarations.
######################################################################
[[ -e ${mmcmdDir}/mmfsfuncs.$osName ]] &&  \
  . ${mmcmdDir}/mmfsfuncs.$osName


##################################################################
#
# Function:  Given a disk name, find the file system to which
#            the disk belongs.
#
# Input:     $1 - Name of disk
#            $2 - Name of mmsdrfs file
#
# Output:    $1 - File system name
#
# Returns:   0 - file system found
#            1 - file system not found
#
##################################################################
function findFSforDisk  #  <diskName>  <sdrfs>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGfindFSforDisk ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset diskName=$1
  typeset sdrfs=$2
  typeset rc fsName

  # The awk script looks at all SG_DISKS lines.
  # If the disk name field matches the value in $diskName,
  # we have located the line that we are looking for.
  # Print the file system device name and stop.
  fsName=$($awk -F: '                              \
    /':$SG_DISKS:'/ {                              \
      if ($'$DISK_NAME_Field' == "'$diskName'" &&  \
          $'$DEV_NAME_Field' != "'$NO_DEVICE'") {  \
        { print $'$DEV_NAME_Field' }               \
        { exit 0 }                                 \
      }                                            \
    }                                              \
  ' $sdrfs)
  checkForErrors awk $?

  if [[ -n $fsName ]]
  then
    print -- $fsName
    return 0
  else
    return 1
  fi

}  #----- end of function findFSforDisk ------------------


##################################################################
#
# Function:  Given a disk name, find the corresponding SG_DISKS
#            line and return the value of the specified field.
#
# Input:     $1 - field whose value should be returned
#            $2 - name of disk for which info is sought
#            $3 - name of mmsdrfs file to search
#
# Output:    $1 - value of the requested field
#
# Returns:   0 - disk found and requested value returned
#            1 - disk not found
#
##################################################################
function getDiskInfo  #  <returnField> <diskName> <sdrfs>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetDiskInfo ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset returnField=$1
  typeset diskName=$2
  typeset sdrfs=$3
  typeset rc result

  # The awk script looks at SG_DISKS lines.
  # If the diskname field matches the value in $diskName,
  # we have located the line that we are looking for.
  # Print the value of the requested field and stop.
  result=$($awk -F: '                              \
    /':$SG_DISKS:'/ {                              \
      if ($'$DISK_NAME_Field' == "'$diskName'") {  \
        { print $'$returnField' }                  \
        { exit 0 }                                 \
      }                                            \
    }                                              \
  ' $sdrfs)
  checkForErrors awk $?

  if [[ -n $result ]]
  then
    print -- $result
    return 0
  else
    return 1
  fi

}  #----- end of function getDiskInfo --------------------


############################################################################
#
# Function:  Given an mm disk descriptor and its corresponding free
#            SG_DISKS line, this routine validates the parameters,
#            converts the descriptor to ts format, and generates
#            an updated SG_DISKS line.
#
# Input:     $1 - disk descriptor in mm format
#            $2 - the current (free) SG_DISKS line for the disk
#            $3 - file system to which the disk will be assigned
#                   or $NO_DEVICE if invoked from mmcrnsd
#                   or $CHANGE_NSD if invoked from mmchnsd
#            $4 - nodeset to which the file system belongs
#                   or $FREE_DISK if invoked from mmcrnsd
#            $5 - status string with which to update DISK_STATUS_Field
#                   when a match is found; NULL if no value
#            $6 - (optional) Default disk usage if usage is not
#                   specified in the mm disk descriptor.
#                   "oldDiskUsage" is used when replacing a disk.
#
# Output:    $1 - updated SG_DISKS line for the disk
#            $2 - Disk descriptor in TS format
#            $3 - Disk usage
#
# Returns:   0 - valid descriptor
#            1 - invalid descriptor
#
############################################################################
function validateAndConvertNsdDescriptor  # <mmDiskDesc> <freeDiskLine>
                                          # <fs> <nodesetId> <statusString>
                                          # [<defaultUsage>]
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGvalidateAndConvertNsdDescriptor ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset mmDiskDesc=$1
  typeset freeDiskLine=$2
  typeset deviceName=$3
  typeset nodesetId=$4
  typeset statusString=$5
  typeset defaultUsage=$6

  typeset updatedDiskLine diskName diskUsage failureGroup ipa storagePool
  typeset primaryNsdAdminNode newPrimaryNsdAdminNode
  typeset primaryNsdDaemonNode newPrimaryNsdDaemonNode
  typeset backupNsdAdminNode newBackupNsdAdminNode
  typeset backupNsdDaemonNode newBackupNsdDaemonNode
  typeset -i primaryNodeNumber defaultFailureGroup

  typeset driverType="nsd"
  typeset sectorSize=""
  typeset hasMetaData=1
  typeset hasData=1
  typeset addingDiskToFS=""
  typeset replacingDisk=""

  [[ $statusString = NULL ]] && statusString=""
  [[ $defaultUsage = oldDiskUsage ]] && replacingDisk=yes

  ######################################################################
  # Parse the mm descriptor and the current SG_DISKS line for the disk.
  ######################################################################
  IFS=":"
  set -f ; set -- $mmDiskDesc ; set +f
  diskName=${1#+(/)dev+(/)}       # name stripped of /dev/ prefix
  newPrimaryNsdAdminNode=$2
  newBackupNsdAdminNode=$3
  diskUsage=$4
  failureGroup=$5
  storagePool=$7

  set -f ; set -A v -- - $freeDiskLine ; set +f
  IFS="$IFS_sv"

  #################################################################
  # Determine who the caller is.  The logic depends on whether
  # we are creating a new disk (mmcrnsd), adding an already
  # existing disk to a file system (mmcrfs, mmadddisk, mmrpldisk)
  # or changing some of the disk attributes (mmchnsd).
  #################################################################
  if [[ $deviceName = $NO_DEVICE ]]
  then
    # Creating a new disk.  Verify that the disk name is specified.
    deviceName=""
    if [[ -z $diskName ]]
    then
      # The disk name must be specified in the disk descriptor.
      printErrorMsg 23 $mmcmd
      return 1
    fi
  elif [[ $deviceName = $CHANGE_NSD ]]
  then
    # The caller is mmchnsd or mmimportfs.
    # The disk may or may not belong to a file system.
    deviceName=${v[$DEV_NAME_Field]}
    [[ $deviceName = $NO_DEVICE ]] && deviceName=""
  else
    # The caller is mmcrfs, mmadddisk, or mmrpldisk.
    # The file system is known.
    addingDiskToFS=yes
  fi

  #######################################################
  # Verify the diskUsage parameter and set the ts flags.
  #######################################################
  [[ -z $defaultUsage ]] && defaultUsage=dataAndMetadata

  [[ -z $diskUsage ]] && diskUsage=$defaultUsage

  if [[ $diskUsage = dataAndMetadata ]]
  then
    :  # There is nothing to do; use default values.
  elif [[ $diskUsage = metadataOnly ]]
  then
    hasData=0
  elif [[ $diskUsage = dataOnly ]]
  then
    hasMetaData=0
  elif [[ $diskUsage = descOnly ]]
  then
    hasData=0
    hasMetaData=0
  elif [[ $diskUsage = oldDiskUsage ]]
  then
    hasData=""
    hasMetaData=""
    diskUsage=${v[$DISK_USAGE_Field]}
  else
    # The disk usage parameter is invalid.
    printErrorMsg 24 $mmcmd
    return 1
  fi

  #######################################################
  # Verify the NSD server node values.
  #######################################################

  # If a server node was specified, make sure that it is valid
  # and convert it if necessary to an admin node adapter name.
  if [[ -n $newPrimaryNsdAdminNode ]]
  then
    newPrimaryNsdAdminNode=$(checkAndConvertNodeValue  \
      $newPrimaryNsdAdminNode $REL_HOSTNAME_Field)
    [[ $? -ne 0 ]] && return 1
    newPrimaryNsdDaemonNode=$(checkAndConvertNodeValue  \
      $newPrimaryNsdAdminNode $DAEMON_NODENAME_Field)
    [[ $? -ne 0 ]] && return 1
  fi
  if [[ -n $newBackupNsdAdminNode ]]
  then
    newBackupNsdAdminNode=$(checkAndConvertNodeValue  \
      $newBackupNsdAdminNode $REL_HOSTNAME_Field)
    [[ $? -ne 0 ]] && return 1
    newBackupNsdDaemonNode=$(checkAndConvertNodeValue  \
      $newBackupNsdAdminNode $DAEMON_NODENAME_Field)
    [[ $? -ne 0 ]] && return 1
  fi

  # Are we adding disks to a file system?
  if [[ -n $addingDiskToFS ]]
  then
    # If adding an existing disk to some file system,
    # the descriptor cannot have NSD server nodes that
    # are different than the ones already defined.
    # Note:  Under normal circumstances, the server fields
    #        in the disk descriptor should be null.
    primaryNsdAdminNode=${v[$NSD_PRIMARY_NODE_Field]}
    primaryNsdDaemonNode=${v[$DAEMON_NSD_PRIMARY_Field]}
    backupNsdAdminNode=${v[$NSD_BACKUP_NODE_Field]}
    backupNsdDaemonNode=${v[$DAEMON_NSD_BACKUP_Field]}

    if [[ -n $newPrimaryNsdAdminNode &&  \
          $newPrimaryNsdAdminNode != $primaryNsdAdminNode ]]
    then
      # The server node in the disk descriptor is not valid.
      printErrorMsg 201 $mmcmd $newPrimaryNsdAdminNode
      return 1
    fi
    if [[ -n $newBackupNsdAdminNode &&  \
          $newBackupNsdAdminNode != $backupNsdAdminNode ]]
    then
      # The server node in the disk descriptor is not valid.
      printErrorMsg 201 $mmcmd $newBackupNsdAdminNode
      return 1
    fi
  else
    # If creating a new disk or changing an existing one,
    # accept the server node values from the descriptor.
    primaryNsdAdminNode=$newPrimaryNsdAdminNode
    primaryNsdDaemonNode=$newPrimaryNsdDaemonNode
    backupNsdAdminNode=$newBackupNsdAdminNode
    backupNsdDaemonNode=$newBackupNsdDaemonNode

    if [[ -n $backupNsdAdminNode && -z $primaryNsdAdminNode ]]
    then
      # The primary NSD node is not specified.
      printErrorMsg 491 $mmcmd $diskName
      return 1
    fi
  fi  # end of if [[ -n $addingDiskToFS ]]

  # If a primary NSD node was specified, find its node number
  # in order to compute the default failure group value.
  if [[ -n $primaryNsdAdminNode ]]
  then
    if [[ $backupNsdAdminNode = $primaryNsdAdminNode ]]
    then
      # The primary and backup NSD servers must be different nodes.
      printErrorMsg 492 $mmcmd
      return 1
    fi

    primaryNodeNumber=$(checkAndConvertNodeValue $primaryNsdAdminNode $NODE_NUMBER_Field)
    [[ $? -ne 0 ]] && return 1

    # The default failure group is the primary server number + 4000.
    defaultFailureGroup=$primaryNodeNumber+4000
  fi  # end of if [[ -n $primaryNsdAdminNode ]]

  ##############################
  # Failure group verification
  ##############################
  if [[ -n $replacingDisk ]]
  then
    : # Let tsrpldisk handle the failure group.

  elif [[ -n $failureGroup ]]
  then
    # Validate the user-supplied value.
    if [[ $failureGroup != ?(-)+([0-9]) ]]
    then
      # Invalid integer
      printErrorMsg 199 $mmcmd $failureGroup
      return 1
    fi

    if [[ $failureGroup -ge -1 && $failureGroup -le 4000 ||
          -n $primaryNsdAdminNode && $failureGroup -eq $defaultFailureGroup ]]
    then
      : # The user-specified failure group looks reasonable.
    else
      # Invalid failure group range.
      printErrorMsg 30 $mmcmd
      return 1
    fi

  elif [[ -n $primaryNsdAdminNode ]]
  then
    # Set the failure group to the server node number + 4000.
    failureGroup=$defaultFailureGroup

  else
    # If all else fails, go with negative one.
    failureGroup="-1"
  fi  # end of if [[ -n $replacingDisk ]]

  #############################
  # Storage pool verification
  #############################
  # Check the storage pool name if one was specified.
  if [[ -n $storagePool && $storagePool != "system" ]]
  then
    # Check whether the disk is to be used for metadata.
    if [[ $hasMetaData = 1 || $diskUsage = descOnly ]]
    then
      # The disk usage is not compatible with the storage pool. 
      printErrorMsg 239 $mmcmd $diskUsage $storagePool
      return 1
    fi

    # Check whether the storage pool name conforms to naming rules.
    # If it does not, issue an error message and exit with a non-zero rc.
    checkName poolName 255 "$storagePool"
    [[ $? -ne 0 ]] && return 1
  fi

  ##############################################################
  # Everything seems to be OK.  Generate the output and return.
  ##############################################################
  # Build the ts version of the descriptor.
  tsDiskDesc="$diskName:$driverType:$sectorSize:$failureGroup:"
  tsDiskDesc="${tsDiskDesc}$hasMetaData:$hasData:$storagePool"

  # Update fields in the SG_DISKS line as necessary.
  [[ -z $deviceName ]] && deviceName=$NO_DEVICE
  v[$NODESETID_Field]=$nodesetId
  v[$DEV_NAME_Field]=$deviceName
  v[$FAILURE_GROUP_Field]=$failureGroup
  v[$DISK_USAGE_Field]=$diskUsage
  v[$DISK_TYPE_Field]=$driverType
  v[$DISK_STATUS_Field]=$statusString
  v[$NSD_PRIMARY_NODE_Field]=$primaryNsdAdminNode
  v[$NSD_BACKUP_NODE_Field]=$backupNsdAdminNode
  v[$DAEMON_NSD_PRIMARY_Field]=$primaryNsdDaemonNode
  v[$DAEMON_NSD_BACKUP_Field]=$backupNsdDaemonNode
  v[$STORAGE_POOL_Field]=$storagePool
  updatedDiskLine=$(print_newLine)

  # Print the results.
  print -- "$updatedDiskLine $tsDiskDesc $diskUsage"

  return 0

}  #----- end of function validateAndConvertNsdDescriptor ---------


########################################################################
#
# Function:  Invoke tspreparedisk to generate an unique identifier
#            and record it on the disk.  If invoked by mmimportfs,
#            move the sg descriptor to sector 8 if necessary.
#
# Input:     $1 - name of the underlying disk to use
#            $2 - value of verification flag (-v option of mmcrnsd)
#            $3 - invoking command
#            $4 - nsd subtype
#                   (if "NULL" is passed, createNsd will determine it)
#
# Output:    NSD disk type followed by the output from tspreparedisk
#
# Returns:   0 - success
#            non-zero - unexpected error
#
########################################################################
function createNsd  # <diskName> <vflag> <invokingCommand> <nsdSubtype>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGcreateNsd ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset diskName=$1
  typeset vflag=$2
  typeset invokingCommand=$3
  typeset nsdSubtype=$4

  typeset device tscmdParms tspreparediskOutput
  typeset unfenceAttempted=""
  typeset rc=0
  typeset ec=0

  if [[ $nsdSubtype = NULL ]]
  then
    # Determine the type of the underlying disk.
    nsdSubtype=$(determineNsdSubtype $diskName)
    rc=$?
    if [[ $rc -ne 0 || -z $nsdSubtype ]]
    then
      # Print result and return.
      print error tspreparedisk:0:0:0:0:3901:0:0
      [[ $rc -eq 0 ]] && rc=1
      return $rc
    fi
  fi  # end of if [[ $nsdSubtype = NULL ]]

  # Ensure the sg descriptor starts in sector 8.
  if [[ $invokingCommand = mmimportfs ]]
  then
    tspreparediskOutput=$($tspreparedisk -m $diskName 2>$errMsg)
    rc=$?

    # If we fail because this is a fenced-out VSD,
    # unfence the disk and retry the tspreparedisk.
    if [[ $rc -eq 50 && $nsdSubtype = vsd ]]
    then
      $rm -f $errMsg
      unfenceVSDdisk $diskName
      ec=$?
      unfenceAttempted=yes
      if [[ $ec -eq 0 ]]
      then
        tspreparediskOutput=$($tspreparedisk -m $diskName 2>$errMsg)
        rc=$?
      fi
    fi  # end of if [[ $rc -eq 50 && $nsdSubtype = vsd ]]

    # Check the result from the tspreparedisk command.
    if [[ $rc -ne 0 || -z $tspreparediskOutput ]]
    then
      # Print result and return.
      [[ -s $errMsg ]] && $cat $errMsg 1>&2
      $rm -f $errMsg
      print error tspreparedisk:$rc:0:0:0:3902:0:0
      [[ $rc -eq 0 ]] && rc=1
      return $rc
    fi
    $rm -f $errMsg
  fi  # end of if [[ $invokingCommand = mmimportfs ]]

  # Construct the fully-qualified device name.
  # Note that this is required for the -n and -N options
  # of tspreparedisk, but not for the -m option.
  if [[ $diskName = /* ]]
  then
    device=$diskName
  elif [[ $osName = AIX ]]
  then
    device=/dev/r$diskName
  else
    device=/dev/$diskName
  fi

  # Determine the parameters to specify on the tspreparedisk command.
  # If the -v flag on the mmcrnsd command was set to yes, do not
  # overwrite an existing pvid.  Otherwise, unconditionally generate
  # a new pvid.
  if [[ $vflag = yes ]]
  then
    tscmdParms="-n $device -t $nsdSubtype"
  else
    tscmdParms="-N $device -t $nsdSubtype"
  fi

  # Invoke tspreparedisk to generate and write a unique pvid on the disk.
  tspreparediskOutput=$($tspreparedisk $tscmdParms)
  rc=$?

  # If there is failure because this is a fenced-out VSD,
  # unfence the disk and retry the tspreparedisk.
  if [[ $rc -eq 50 && $nsdSubtype = vsd && -z $unfenceAttempted ]]
  then
    unfenceVSDdisk $diskName
    ec=$?
    if [[ $ec -eq 0 ]]
    then
      tspreparediskOutput=$($tspreparedisk $tscmdParms)
      rc=$?
    fi
  fi  # end of if [[ $rc -eq 50 && $nsdSubtype = vsd && -z $unfenceAttempted ]]

  # Output the NSD subtype and the result from tspreparedisk.
  print $nsdSubtype $tspreparediskOutput
  return $rc

}  #----- end of function createNsd ----------------------


##############################################################################
#
# Function:  Invoke tspreparedisk to configure disks for use as quorum disks.
#
# Input:     $1 - file with the SG_DISK lines for the disks
#            $2 - comma-separated list of quorum node numbers
#            $3 - comma-separated list of quorum node names
#            $4 - invoking command
#
# Output:    None
#
# Returns:   0 - success
#            non-zero - unexpected error
#
##############################################################################
function formatPaxosDisks  # <diskLines> <quorumNodeNumbers>
                           # <quorumNodeNames> <invokingCommand>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGformatPaxosDisks ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset diskLines=$1
  typeset quorumNodeNumbers=$2
  typeset quorumNodeNames=$3
  typeset invokingCommand=$4

  typeset rc=0
  typeset formatPaxosDisks_rc=0
  typeset wOpt=""
  typeset sdrfsLine diskName pvid nsdSubtype fOpt rc2
  typeset magicWord fsName nodeName invokedNode result

  [[ $invokingCommand = mmaddnode ]] && wOpt="-w"

  # Read the SG_DISK lines and process the disks one by one.
  $rm -f $errMsg
  IFS=":"
  exec 3<&-
  exec 3< $diskLines
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f
    IFS="$IFS_sv"
    diskName=${v[$DISK_NAME_Field]}
    pvid=${v[$PVID_Field]}
    nsdSubtype=${v[$NSD_SUBTYPE_Field]}

    if [[ ${v[$NODESETID_Field]} = $FREE_DISK ]]
    then
      fOpt=""
    else
      fOpt="-f"
    fi

    # Loop through the list of nodes, invoking the tspreparedisk command
    # to format the disk.  We continue looping until we succeed on some node.
    IFS=","
    for nodeName in $quorumNodeNames
    do
      IFS="$IFS_sv"
      if [[ $nodeName = $ourNodeName ]]
      then
        # Execute the command locally.
        result=$($mmremote adminCmd tspreparedisk  \
                    -p $pvid -t $nsdSubtype -q $quorumNodeNumbers $fOpt $wOpt)
        rc=$?
        invokedNode=$ourNodeName
        tspreparediskOutput="$result"
      else
        # Check whether the node can be reached.
        isNodeReachable $nodeName
        if [[ $? -eq 0 ]]
        then
          # Invoke mmdsh to execute the command on the node.
          result=$($mmdsh -vL $nodeName $mmremote adminCmd tspreparedisk  \
                      -p $pvid -t $nsdSubtype -q $quorumNodeNumbers $fOpt $wOpt)
          rc=$?
          invokedNode=${result%%: *}
          tspreparediskOutput=${result#* }
          tspreparediskOutput=${tspreparediskOutput## }
        else
          rc=$MM_HostDown
        fi  # end of if [[ $? -eq 0 ]]
      fi  # end of if [[ $nodeName = $ourNodeName ]]

      # Parse the result from tspreparedisk.
      IFS=":"
      set -f ; set -- $tspreparediskOutput ; set +f
      magicWord=$1
      rc2=$2
      IFS="$IFS_sv"

      # Issue an appropriate message if the node was unable
      # to execute tspreparedisk successfully.
      if [[ $rc -ne 0 || $magicWord != tspreparedisk || $rc2 -ne 0 ]]
      then
        # Something went wrong with this disk.
        # Try to make sense of the error.
        if [[ $rc -eq $MM_HostDown ]]
        then
          # The node is not reachable.
          printErrorMsg 340 $mmcmd $nodeName 2>> $errMsg
        elif [[ $magicWord = tspreparedisk ]]
        then
          # tspreparedisk executed but it was not happy about something.
          if [[ $rc2 = 1 ]]       # E_PERM
          then
            # Permission was denied for disk.
            printErrorMsg 523 "$invokedNode: $mmcmd" "$diskName" 2>> $errMsg
          elif [[ $rc2 = 2 ]]     # E_NOENT
          then
            # The disk was not found.
            printErrorMsg 524 "$invokedNode: $mmcmd" "$diskName" 2>> $errMsg
          elif [[ $rc2 = 5 ]]     # E_IO
          then
            # I/O error
            printErrorMsg 525 "$invokedNode: $mmcmd" "$diskName" 2>> $errMsg
          elif [[ $rc2 = 19 ]]    # E_NODEV
          then
            # A return code of ENODEV was returned for the disk.
            printErrorMsg 187 $mmcmd $invokedNode "$diskName" 2>> $errMsg
          elif [[ $rc2 = 50 ]]    # E_NOCONNECT
          then
            # The disk is fenced out.
            printErrorMsg 395 $mmcmd $invokedNode "$diskName" 2>> $errMsg
          elif [[ $rc2 = 214 ]]   # E_VALIDATE
          then
            # Disk validation error.
            printErrorMsg 539 "$invokedNode: $mmcmd" "$diskName" $rc2 2>>$errMsg
          elif [[ $rc2 = 221 ]]   # E_BALSPACE
          then
            # There is no space in the descriptor for the paxos sectors.
            printErrorMsg 531 "$invokedNode: $mmcmd" "$diskName" 2>> $errMsg
          elif [[ $rc2 = 236 ]]   # E_FORMAT_INCOMPAT
          then
            # The disk belongs to a back level file system or
            # it is not in ready state.
            fsName=$(findFSforDisk "$diskName" $mmsdrfsFile)
            printErrorMsg 528 "$invokedNode: $mmcmd" "$diskName" $fsName 2>> $errMsg
          else
            # Show the result from tspreparedisk.
            print -u2 "$tspreparediskOutput" 2>> $errMsg
            # There was an unexpected error from tspreparedisk.
            printErrorMsg 171 "$invokedNode: $mmcmd"  \
              "tspreparedisk -p $pvid -t $nsdSubtype -q $quorumNodeNumbers $fOpt $wOpt" $rc2 2>> $errMsg
          fi  # end of if [[ $rc2 = 1 ]]
        else
          # Something is really wrong.  Output error information if any.
          [[ -n $result ]] && print -u2 "$nodeName: $result" 2>> $errMsg
        fi  # end of if [[ $magicWord = tspreparedisk ]]
      fi  # end of if [[ $rc -ne 0 || $magicWord != tspreparedisk || $rc2 -ne 0 ]]

      # Exit the loop if tspreparedisk succeeded.
      [[ $rc -eq 0 && $magicWord = tspreparedisk && $rc2 -eq 0 ]] && break

      IFS=","  # Change the field separator back to "," for the next iteration.
    done  # end of for nodeName in $quorumNodeNames
    IFS="$IFS_sv"

    # If no node was able to run tspreparedisk successfully,
    # show all of the error messages and set a failure return code.
    if [[ $rc -ne 0 || $magicWord != tspreparedisk || $rc2 -ne 0 ]]
    then
      $cat $errMsg 1>&2
      # Failed while processing the disk.
      printErrorMsg 529 $mmcmd "$diskName"
      formatPaxosDisks_rc=1
    fi  # end of if [[ $rc -ne 0 || $magicWord != tspreparedisk || $rc2 -ne 0 ]]

    # Reset things needed for the next iteration.
    $rm -f $errMsg
    IFS=":"

  done  # end of while read -u3 sdrfsLine
  IFS="$IFS_sv"

  return $formatPaxosDisks_rc

}  #----- end of function formatPaxosDisks --------------------


############################################################################
#
# Function:  Send nsd data obtained from the tspreparedisk -s command
#            (and other sources) for all nsds on this node to stdout.
#
# Input:     X flag (optional; if set, it specifies that eXtra information
#              should be returned in the remarks field)
#
# Output:    colon-separated nsd information from the "tspreparedisk -s"
#              command (and other sources if the X flag was specified)
#
# Returns:   0 - success
#
############################################################################
function getLocalNsdData   # [<Xflag>]
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetLocalNsdData ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset Xflag=$1
  typeset tspreparediskLine nsid deviceName localDevice deviceType vgname
  typeset vsdDataNeeded=yes

  # Obtain the output of the tspreparedisk -s command.
  $tspreparedisk -s > $tsOutputFile 2> $errMsg

  # Read and process the output.
  exec 4<&-
  exec 4< $tsOutputFile
  while read -u4 tspreparediskLine
  do
    # Parse the tspreparedisk output line.
    set -f ; set -- $tspreparediskLine ; set +f
    nsid=$1
    localDevice=$2
    deviceType=$3

    # If this is an AIX environment, replace the /dev/r prefix with /dev/.
    if [[ $osName = AIX && $localDevice = +(/)dev+(/)r* ]]
    then
      deviceName=${localDevice##+(/)dev+(/)r}
      localDevice=/dev/$deviceName
    fi

    if [[ -z $Xflag ]]
    then
      # Here if -m or -M was specified.
      # If this is not an error line, print the data.
      [[ $nsid != tspreparedisk* ]] &&  \
        print "getLocalNsdData:$nsid:$localDevice:$deviceType::" >> $nsdDataFile
    else
      # Here if -X was specified.
      # Obtain information for the remarks field for certain types of disks.
      remarks=""
      if [[ $osName = AIX ]]
      then
        if [[ $deviceType = vsd ]]
        then
          # Obtain VSD information for the remarks field.
          if [[ $vsdDataNeeded = yes ]]
          then
            getVsdRpdNodeData $tmpNodes
            LC_ALL=C $lsvsd -l > $vsdNamesFile 2>/dev/null
            LC_ALL=C $vsdatalst -v > $diskfile  2>/dev/null
            LC_ALL=C $vsdatalst -g > $volGroupFile 2>/dev/null
            $touch $tmpNodes $vsdNamesFile $diskfile $volGroupFile
            vsdDataNeeded=no
          fi
          remarks=$(obtainVsdInfo $deviceName $tmpNodes $vsdNamesFile $diskfile $volGroupFile)
        elif [[ $deviceType = lv ]]
        then
          # Obtain logical volume information for the remarks field.
          vgname=$(LC_ALL=C $lslv -L $deviceName 2>/dev/null | $awk '/VOLUME GROUP:/ {print $6}')
          [[ -z vgname ]] && vgname=unknown
          remarks="lv=$deviceName,vg=$vgname"
        fi  # end of if [[ $deviceType = vsd ]]
      fi  # end of if [[ $osName = AIX ]]

      # If this is not an error line, print the data.
      [[ $nsid != tspreparedisk* ]] &&  \
        print "getLocalNsdData:$nsid:$localDevice:$deviceType:$remarks:" >> $nsdDataFile
    fi    # end of if [[ -z $Xflag ]]
  done  # end of while read -u4 tspreparediskLine

  # Send the colon-separated output and any error messages to stdout.
  $touch $nsdDataFile    # Make sure the file exists even if empty.
  cat $nsdDataFile $errMsg
  return 0

}  #----- end of function getLocalNsdData ---------------------


####################################################################
#
# Function:  Find out the local device name for the disk with
#            the specified pvid.
#
# Input:     $1 - pvid of the disk being looked up
#            $2 - nsd subtype of the disk being looked up
#
# Output:    A line with the following ':' separated fields:
#            - magic word 'getLocalDiskName'
#            - local disk name
#            - return code from tspreparedisk -p
#            - always 0 (used to be return code from tsnsdreset -q)
#
# Returns:   0 - success
#            1 - unexpected error
#
####################################################################
function getLocalDiskName  # <pvid> <nsdSubtype>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetLocalDiskName ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset pvid=$1
  typeset nsdSubtype=$2

  typeset tspreparediskOutput magicWord pvid
  typeset localDiskName=""
  typeset rc=0
  typeset rc1=0
  typeset rc2=0

  # Use the nsd commands to determine the local device name.

  # Find out the local device name.
  tspreparediskOutput=$($tspreparedisk -p $pvid -t $nsdSubtype 2>$errMsg2)
  rc=$?

  # Parse the output from the tspreparedisk command.
  IFS=":"
  set -f ; set -- $tspreparediskOutput ; set +f
  magicWord=$1
  rc1=$2
  pvid=$3
  localDiskName=$4
  IFS="$IFS_sv"

  if [[ $magicWord != tspreparedisk ]]
  then
    # Unexpected error.  Print error messages and give up.
    [[ -s $errMsg2 ]] && $cat $errMsg2 1>&2
    $rm -f $errMsg2
    [[ $rc -eq 0 ]] && rc=1
    printErrorMsg 171  \
      "getLocalDiskName" "tspreparedisk -p $pvid -t $nsdSubtype" $rc
    return 1
  fi
  $rm -f $errMsg2

  # If this is an AIX environment, replace the /dev/r prefix with /dev/.
  if [[ $osName = AIX && $localDiskName = +(/)dev+(/)r* ]]
  then
    localDiskName=${localDiskName##+(/)dev+(/)r}
    localDiskName=/dev/$localDiskName
  fi

  if [[ $rc -eq 0 && -n $localDiskName ]]
  then
    # tspreparedisk worked and we have a good answer.
    print -- "getLocalDiskName:$localDiskName:$rc1:$rc2"
    return 0
  fi

  if [[ $MMMODE = single ]]
  then
    # If in single mode, there is nothing more to try; give up.
    print -- "getLocalDiskName:$UNRESOLVED:$rc1:$rc2"
    return 0
  fi

  # If we are here, tspreparedisk failed to find out the local disk name.
  # There may be many reasons for this, one of which is that the disk is
  # being reserved by some other node and we cannot verify the pvid.
  # Assuming this is the case, we will look at the nsd map file and will
  # attempt to determine the mapping from there keeping in mind that the
  # answer is not 100% guaranteed to be correct anymore.

  # Search the nsd map file for an entry with our pvid.
  if [[ -s $nsdmap ]]
  then
    localDiskName=$($awk ' {   \
      if ($1 == "'$pvid'") {   \
        { print $2 }           \
        { exit 0 }             \
      }                        \
    } ' $nsdmap)
    checkForErrors "awk $nsdmap" $?
  fi  # end of if [[ -s $nsdmap ]]

  # If no matching pvid found in the hints file, give up.
  if [[ -z $localDiskName ]]
  then
    print -- "getLocalDiskName:$UNRESOLVED:$rc1:$rc2"
    return 0
  fi

  # tspreparedisk should have been able to verify the pvid;
  # most likely this is a different disk.
  print -- "getLocalDiskName:$UNRESOLVED:$rc1:$rc2"

  return 0

}  #----- end of function getLocalDiskName ---------------


#############################################################
#
# Function:  Select an unused device minor number.
#
# Input:     $1 - list of currently-assigned minor numbers.
#
# Output:    A minor number for the /dev entry.
#
# Returns:   Zero if successful, non-zero otherwise.
#
#############################################################
function assignDevMinor  # <existingMinorNumbers>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGassignDevMinor ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset existingMinorNumbers="$1"

  typeset x devMinor
  typeset rc=0

  # Set the initial devMinor number.  The first 50 numbers
  # are reserved for existing file systems that do not play
  # by the new rules yet.
  devMinor=$((minMinorNumber + 50))

  # Keep looping until we either find an unused minor number,
  # or we run out of numbers.
  while ((devMinor <= maxMinorNumber))
  do
    # Scan the currently-assigned minor numbers.
    for x in $existingMinorNumbers
    do
      # If the number that we want is already in use,
      # get out of the for loop.
      [[ $x = $devMinor ]] && break
    done

    # If the number that we want is free, we are done.
    [[ $x != $devMinor ]] && break

    # No luck so far, try the next number.
    devMinor=$((devMinor + 1))

  done # end of while ((devMinor <= maxMinorNumber))

  # If the number is out of range, return null and let
  # mmfsmknod worry about it.  This should never happen
  # since we do not support more than 32 file systems.
  if [[ $devMinor -gt $maxMinorNumber ]]
  then
    rc=1
    devMinor=""
  fi

  # Return the result.
  print -- $devMinor
  return $rc

}  #----- end of function assignDevMinor -----------------


#############################################################
#
# Function:  Find the disk info (pvid, vgname, lvname) that
#            corresponds to the raw disk name.
#
# Input:     $1 - raw disk name (eg: hdisk7, sda2).
#
# Output:    The disk information:  pvid, vgname, lvname.
#
# Returns:   Zero if successful, non-zero otherwise.
#
#############################################################
function getRawDiskInfo  # <rawDiskName>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetRawDiskInfo ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset rawDiskName=$1

  typeset pvid vgname lvname lspvOutput
  integer rc=0

  # Find out the disks pvid and local volume group.
  lspvOutput=$($lspv | $grep -w $rawDiskName)
  rc=$?
  set -f ; set -- $lspvOutput ; set +f
  pvid=$2
  vgname=$3
  if [[ $rc -ne 0 || -z $pvid || -z $vgname ]]
  then
    printErrorMsg 232 $mmcmd $rawDiskName lspv
    return $rc
  fi

  if [[ $vgname != None && $vgname != gpfs ]]
  then
    # Determine the name of the logical volume that corresponds to this
    # volume group.  If there is more than one lv ...?
    lvname=$(LC_ALL=C $lsvg -l $vgname 2>/dev/null | $grep mmfs | $awk '{ print $1 }')
    rc=$?
    if [[ $rc -ne 0 || -z $lvname ]]
    then
      printErrorMsg 104 "$mmcmd" "lsvg -l $vgname"
      return 1
    fi
  else
    # We come here if vgname = None or vgname = gpfs (the latter being
    # indicative of an old, no-longer-used nsd for which mmdelnsd was not run).
    # Tell the user no disks were found.
    printErrorMsg 418 $mmcmd
    return 1
  fi

  print -- $pvid $vgname $lvname
  return 0

}  #----- end of function getRawDiskInfo -----------------


#############################################################
#
# Function:  Find the VSD name corresponding to the vgname.
#
# Input:     $1 - vg name
#
# Output:    The VSD name.
#
# Returns:   Zero if successful, non-zero otherwise.
#
#############################################################
function getVSDName  # <vgname>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetVSDName ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset vgname=$1

  typeset vsdname gvg
  integer rc=0

  gvg=$($vsdatalst -g | $awk '{ if ($2 == "'"$vgname"'") print $1 }')
  if [[ -z $gvg ]]
  then
    printErrorMsg 232 $mmcmd $vgname "vsdatalst -g"
    print -- ""
    return 1
  else
    vsdname=$($vsdatalst -v |  \
                $awk '{if ($3 == "'"$gvg"'") print $1}')
    rc=$?
    if [[ $rc -ne 0 || -z $vsdname ]]
    then
      printErrorMsg 232 $mmcmd $vgname "vsdatalst -v"
      print -- ""
      return 1
    fi
  fi

 print -- $vsdname
 return 0

}  #----- end of function getVSDName ---------------------


#############################################################
#
# Function:  Find the NSD disk name.
#
# Input:     $1 - rawdisk, lv, or vsdname
#
# Output:    the NSD disk name
#
# Returns:   zero if successful, non-zero otherwise
#
#############################################################
function getNSDName  # <rawName>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetNSDName ]] && set -x
  $mmTRACE_ENTER "$*"
  rawName=$1
  typeset rc=0

  typeset gpfsDiskName tspreparediskOutput pvid

  if [[ $osName = AIX ]]
  then
    rawName="r$rawName"
  fi

  tspreparediskOutput=$($tspreparedisk -s | $grep -w "/dev/$rawName")
  rc=$?

  # Parse the output from the tspreparedisk command.
  IF=":"
  set -f ; set -- $tspreparediskOutput ; set +f
  pvid=$1
  [[ $rc -ne 0 || -z $pvid ]] && return 1

  # Search for the nsd disk name in the mmsdrfs file.
  gpfsDiskName=$($awk -F: '                \
    /':$SG_DISKS:'/ {                      \
      if ($'$PVID_Field' == "'$pvid'") {   \
        { print $'$DISK_NAME_Field' }      \
        { exit 0 }                         \
      }                                    \
    }
  ' $mmsdrfsFile)

  checkForErrors awk $?
  if [[ -n $gpfsDiskName ]]
  then
    print -- $gpfsDiskName
    return 0
  else
    return 1
  fi

}  #----- end of function getNSDName ---------------------


###############################################################
#
# Function:  Find the GPFS disk name given the raw disk name.
#
# Input:     $1 - raw disk name (eg: hdisk, sda)
#
# Output:    the GPFS disk name
#
# Returns:   zero if successful, non-zero otherwise
#
###############################################################
function getGpfsDiskName   #  <rawDiskName>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGgetGpfsDiskName ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset rawDiskName=$1

  typeset rawDiskInfo pvid vgname lvname vsdname gpfsDiskName

  # Check the GPFS cluster type.
  [[ -z $MMMODE ]] && determineMode

  # Call routine to obtain the name of the NSD.
  gpfsDiskName=$(getNSDName $rawDiskName)

  # If the NSD was not found and this is a Linux node,
  # return with a failure rc; there is nothing more we can do.
  [[ -z $gpfsDiskName && $osName = Linux ]] && return 1

  # Did we get the name of the NSD?
  if [[ -z $gpfsDiskName ]]
  then
    # We did not get the name of the NSD.
    # Check whether this is an AIX logical volume.
    rawDiskInfo=$(getRawDiskInfo $rawDiskName)
    set -f ; set -- $rawDiskInfo ; set +f
    pvid=$1
    vgname=$2
    lvname=$3

    # If we did not find an lv, return with a failing rc;
    # the disk is not known.
    [[ -z $lvname ]] && return 1

    # Check for an NSD name corresponding to the lv.
    gpfsDiskName=$(getNSDName $lvname)
    if [[ -z $gpfsDiskName ]]
    then
      # If still no NSD was found, check whether this is a VSD.
      vsdname=$(getVSDName $vgname)
      if [[ -n $vsdname ]]
      then
        # Check for an NSD name corresponding to the vsd.
        gpfsDiskName=$(getNSDName $vsdname)
        [[ -z $gpfsDiskName ]] && return 1
      else
        # We did not find the NSD.  Return with a failing rc.
        return 1
      fi
    fi
  fi  # end of if [[ -z $gpfsDiskName ]]

  # Output the GPFS disk name and return.
  print -- $gpfsDiskName
  return 0

}  #----- end of function getGpfsDiskName -----------------------


###########################################################################
#
# Function:  Reset (i.e., set to the null string) the status field
#            of SG_DISKS lines for the specified filesystem if their
#            disk status value matches the passed status string,
#            thus causing the disk to be reported to the GPFS daemon
#            by future invocations of the getEFOptions routine.
#
#            This routine is called after a ts disk command has completed
#            successfully.
#
# Input:     $1 - file system name
#            $2 - passed sdrfs file
#            $3 - 1st status string used to identify SG_DISK lines
#                   whose disk status fields need to be reset;
#                   the only acceptable values are "mmadd" and "mmdel"
#            $4 - optional 2nd status string used to identify SG_DISK
#                   lines whose disk status fields need to be reset;
#                   if specified, the only acceptable value is "mmdel";
#                   this option is used by mmrpldisk which does both
#                   an add and a delete
#
# Output:    The sdrfs file has been updated (the DISK_STATUS field
#              of any SG_DISKS line for the specified filesystem is
#              reset if the disk status matches the passed values)
#
# Returns:   0 - the passed sdrfs file was successfully updated
#
###########################################################################
function resetDiskStatus  # <fsname> <sdrfsFile> <status1> [<status2>]
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGresetDiskStatus ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset fsname=$1
  typeset sdrfsFile=$2
  typeset status1=$3
  typeset status2=$4

  typeset oddState
  typeset outfile=${sdrfs}tmp

  $rm -f $outfile

  oddState=$($awk -F:  '                                                          \
    BEGIN {                                                                       \
      { oddstate = "no" }                                                         \
      { c = ":" }                                                                 \
    }                                                                             \
    # If this is the global header line, increment the gen number.                \
    /^'$GLOBAL_ID:$VERSION_LINE:'/ {                                              \
      { $'$SDRFS_GENNUM_Field' = $'$SDRFS_GENNUM_Field' + 1 }                     \
      { print  $1":" $2":" $3":" $4":" $5":" $6":" $7":" $8":" $9":"$10":"        \
              $11":"$12":"$13":"$14":"$15":"$16":"$17":"$18":"$19":"$20":"        \
              $21":"$22":"$23":"$24":"$25":"$26":"$27":" >> "'$outfile'" }        \
      { next }                                                                    \
    }                                                                             \
    # Save the SG_HEADR line for the specified filesystem as two                  \
    # strings - the parts before and after ODD_STATE_Field ($6).                  \
    /':$SG_HEADR:$fsname:'/ {                                                     \
      { sgh1 =  $1 c $2 c  $3 c  $4 c  $5 }                                       \
      { sgh2 =  $7 c $8 c  $9 c $10 c $11 c $12 c $13 c $14 c $15 c $16 c $17 c } \
      { sgh2 = sgh2 $18 c $19 c $20 c $21 c $22 c $23 c $24 c $25 c $26 c $27 c } \
      { next }                                                                    \
    }                                                                             \
    # Check for SG_DISKS lines for the specified filesystem.                      \
    /':$SG_DISKS:$fsname:'/ {                                                     \
      # Does the disk status value match the first passed value?                  \
      if ( $'$DISK_STATUS_Field' == "'$status1'" ) {                              \
        # The disk status value matches.  Process the line.                       \
        if ( "'$status1'" == "mmadd" ) {                                          \
          # For mmadd, we simply reset the disk status field.                     \
          { $'$DISK_STATUS_Field' = "" }                                          \
          { print  $1":" $2":" $3":" $4":" $5":" $6":" $7":" $8":" $9":"$10":"    \
                  $11":"$12":"$13":"$14":"$15":"$16":"$17":"$18":"$19":"$20":"    \
                  $21":"$22":"$23":"$24":"$25":"$26":"$27":" >> "'$outfile'" }    \
        } else {                                                                  \
          if ( "'$status1'" == "mmdel" ) {                                        \
            # For mmdel, we change the disk into a free disk                      \
            # and reset the disk status field.                                    \
            { $'$NODESETID_Field' = "'$FREE_DISK'" }                              \
            { $'$DEV_NAME_Field' = "'$NO_DEVICE'" }                               \
            { $'$LINE_NUMBER_Field' = "0" }                                       \
            { $'$DISK_STATUS_Field' = "" }                                        \
            { print  $1":" $2":" $3":" $4":" $5":" $6":" $7":" $8":" $9":"$10":"  \
                    $11":"$12":"$13":"$14":"$15":"$16":"$17":"$18":"$19":"$20":"  \
                    $21":"$22":"$23":"$24":"$25":"$26":"$27":" >> "'$outfile'" }  \
          }                                                                       \
        }                                                                         \
        { next }                                                                  \
      } else {                                                                    \
        # Does the disk status value match a second passed value of mmdel?        \
        if ( "'$status2'" == "mmdel" && $'$DISK_STATUS_Field' == "'$status2'" ) { \
          # The disk status value matches and is mmdel.                           \
          # We change the disk into a free disk and reset the status field.       \
          { $'$NODESETID_Field' = "'$FREE_DISK'" }                                \
          { $'$DEV_NAME_Field' = "'$NO_DEVICE'" }                                 \
          { $'$LINE_NUMBER_Field' = "0" }                                         \
          { $'$DISK_STATUS_Field' = "" }                                          \
          { print  $1":" $2":" $3":" $4":" $5":" $6":" $7":" $8":" $9":"$10":"    \
                  $11":"$12":"$13":"$14":"$15":"$16":"$17":"$18":"$19":"$20":"    \
                  $21":"$22":"$23":"$24":"$25":"$26":"$27":" >> "'$outfile'" }    \
          { next }                                                                \
        } else {                                                                  \
          # The disk status value does not match anything.                        \
          # Echo the line as is and check whether the disk is in an odd state.    \
          { print $0 >> "'$outfile'" }                                            \
          if ( $'$DISK_STATUS_Field' != "" &&                                     \
               $'$DISK_STATUS_Field' != "ready" ) {                               \
            { oddstate = "yes" }                                                  \
          }                                                                       \
          { next }                                                                \
        }                                                                         \
      }                                                                           \
    }                                                                             \
    # All other lines are echoed without change.                                  \
    { print $0 >> "'$outfile'" }                                                  \
    END {                                                                         \
      { print sgh1 ":" oddstate ":" sgh2 >> "'$outfile'" }                        \
    }                                                                             \
  ' $sdrfsFile)
  checkForErrors awk $?

  # Print a message for the user if any disks are in an odd state.
  [[ $oddState = yes ]] && printErrorMsg 103 $mmcmd $fsname $fsname

  # Sort the updated version of the sdrfs file.
  LC_ALL=C $SORT_MMSDRFS $outfile -o $outfile
  checkForErrors "sorting $outfile" $?

  # The file was updated successfully.  Copy it to the input file.
  $mv $outfile $sdrfsFile
  checkForErrors "resetDiskStatus:  mv $outfile $sdrfsFile " $?

  return 0

}  #----- end of function resetDiskStatus -----------------------


##########################################################################
#
# Function:  Compare the daemon's list of disks for the file system
#            with that contained in the passed sdrfs file.
#            If they disagree, change the sdrfs file to agree
#            with the information returned by the daemon.
#            If any of the disks of the file system are in an
#            "odd state", the "odd state" flag is set to "yes"
#            in the SG_HEADR line for the file system (otherwise
#            it is set to "no").
#
# Input:     $1 - file system name
#            $2 - passed sdrfs file
#
# Output:    The SG_DISKS lines in the sdrfs file for the specified
#              file system now agree with the daemon's view of the disks.
#
# Returns:   0 - the passed sdrfs file now agrees with the daemon
#                  for the disks in the specified file system
#            Any other return code indicates an unexpected error.
#
##########################################################################
function reconcileSdrfsWithDaemon  # <fsname> <sdrfsFile>
{
  typeset sourceFile="mmfsfuncs.sh"
  [[ -n $DEBUG || -n $DEBUGreconcileSdrfsWithDaemon ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset fsname=$1
  typeset sdrfsFile=$2

  typeset mmlsdiskLine sdrfsLine nodesetId diskName sgh1 sgh2
  typeset failureGroup holdsMetadata holdsData diskStatus
  typeset oddState="no"
  typeset rc=0
  integer nodeCount=0
  integer seqNo=0

  # Print message:  "Verifying file system configuration information ..."
  printInfoMsg 473

  # Determine the nodeset to which this filesystem belongs.
  nodesetId=$($awk -F: '                           \
    /':$SG_HEADR:'/ {                              \
      if ( $'$DEV_NAME_Field' == "'$fsname'" ) {   \
        {print $'$NODESETID_Field'}                \
        { exit 0 }                                 \
      }                                            \
    }                                              \
  ' $sdrfsFile)
  checkForErrors awk $?

  # Obtain the daemon's list of disks for the filesystem.
  # If the nodeset to which this node belongs is the same as the nodeset
  # in which the file system resides, invoke the command directly.
  if [[ $nsId = $nodesetId ]]
  then
    ${mmcmdDir}/${links}/mmlsdisk $fsname >$tmpfile2 2>$errMsg
    rc=$(remapRC $?)

    # If the command failed in a way that a remote invocation will not
    # make a difference, display any error messages and get out.
    if [[ $rc -ne $MM_DaemonDown &&
          $rc -ne $MM_QuorumWait &&
          $rc -ne 0              ]]
    then
      [[ -s $errMsg ]] && $cat $errMsg 1>&2
      $rm -f $errMsg
      if [[ $rc -eq $MM_ConnectionReset ]]
      then
        # An internode connection was reset.
        printErrorMsg 257 $mmcmd
      fi
      return $rc
    fi
  else
    # Set rc to a non-zero value so we will try the mmlsdisk cmd remotely.
    rc=$MM_DaemonDown
  fi
  $rm -f $errMsg

  # If the mmlsdisk call has not succeeded yet,
  # issue the mmlsdisk command on a remote node.
  if [[ $rc -ne 0 ]]
  then
    # Create a file with the reliable names that form
    # the nodeset to which the file system belongs.
    nodeCount=$(getNodeFile $REL_HOSTNAME_Field $nodesetId $sdrfsFile $nodefile)
    if [[ $nodeCount -eq 0 ]]
    then
      # The nodeset is empty; there is nobody to run the command.
      printErrorMsg 171 $mmcmd "getNodeFile (nodeCount=0)" 1
      return 1
    fi

    # Try the nodes one by one until a node is able to execute the command.
    preferredNode=0   # We have no idea where to go first; let mmcommon decide.
    $mmcommon linkCommand $preferredNode $nodefile  \
                                mmlsdisk $fsname >$tmpfile2 2>$errMsg
    rc=$?
    if [[ $rc -ne 0 ]]
    then
      [[ -s $errMsg ]] && $cat $errMsg 1>&2
      $rm -f $errMsg
      if [[ $rc -eq $MM_ConnectionReset ]]
      then
        # An internode connection was reset.
        printErrorMsg 257 $mmcmd
      fi
      return $rc
    fi
  fi
  $rm -f $errMsg

  # Remove the header lines from the mmlsdisk output.
  $tail -n +4 $tmpfile2 > $tmpfile
  checkForErrors "tail -n +4 $tmpfile2 $tmpfile" $?

  # One more sanity check before we proceed.
  if [[ ! -s $tmpfile ]]
  then
    printErrorMsg 171 reconcileSdrfsWithDaemon "tslsdisk - missing disk information" 1
    return 1
  fi


  ##########################################################################
  # Go through the passed sdrfs file.  Increment the generation number.
  # Make any needed changes to SG_DISKS lines for the specified filesystem.
  ##########################################################################
  # Delete the temporary file that will be created.
  $rm -f $sdrfs

  IFS=":"           # Change the field separator to ':'.
  exec 3<&-
  exec 3< $sdrfsFile
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f

    IFS="$IFS_sv"
    printLine=true

    # Selectively alter some of the fields in the line.
    case ${v[$LINE_TYPE_Field]} in

      $VERSION_LINE )  # This is the global header line.
        # Increment the generation number
        newGenNumber=${v[$SDRFS_GENNUM_Field]}+1
        v[$SDRFS_GENNUM_Field]=$newGenNumber
        ;;

      $SG_HEADR )  # This is the header line for some file system.
        # If this is the header for the specified file system,
        # save the line's contents into two strings that will be used
        # later in creating the SG_HEADR line.  We can't create the
        # line now because we don't know how to set the "odd state"
        # field for the file system yet.
        if [[ ${v[$DEV_NAME_Field]} = $fsname ]]
        then
          printLine=false
          sgh1=${v[1]}:${v[2]}:${v[3]}:${v[4]}:${v[5]}
          sgh2=${v[7]}:${v[8]}:${v[9]}:${v[10]}:${v[11]}:${v[12]}:${v[13]}
          sgh2=$sgh2:${v[14]}:${v[15]}:${v[16]}:${v[17]}:${v[18]}:${v[19]}
          sgh2=$sgh2:${v[20]}:${v[21]}:${v[22]}:${v[23]}:${v[24]}
        fi
        ;;

      $SG_DISKS )  # This line describes a disk.
        # If this disk belongs to the file system or is a free disk,
        # make the SG_DISKS line agree with the daemon's data about the disk.
        if [[ ${v[$DEV_NAME_Field]} = $fsname  ||
              ${v[$NODESETID_Field]} = $FREE_DISK ]]
        then
          # Locate the line for this disk in the mmlsdisk output file.
          $rm -f $tmpfile2
          mmlsdiskLine=$($awk '                                           \
            # If the line is for our disk, output it to $mmlsdiskLine     \
            # but do not append it to tmpfile2.                           \
            $1 == "'${v[$DISK_NAME_Field]}'" {                            \
              { print $0 }                                                \
              { next }                                                    \
            }                                                             \
            # If the line is for some other disk, append it to tmpfile2.  \
            { print $0 >> "'$tmpfile2'" }                                 \
          ' $tmpfile)
          checkForErrors awk $?

          # Prepare the mmlsdisk output file for the next iteration.
          # It will contain all of its prior lines except the line
          # for the disk that is currently being processed.
          $touch $tmpfile2   # Make sure the file exists even if empty.
          $mv $tmpfile2 $tmpfile
          checkForErrors "mv $tmpfile2 $tmpfile" $?

          if [[ -z $mmlsdiskLine ]]
          then
            # The daemon doesn't know about this disk.
            # If the SG_DISKS line indicates the disk belongs to the
            # filesystem, change the SG_DISKS line into a free disk line.
            if [[ ${v[$DEV_NAME_Field]} = $fsname ]]
            then
              v[$NODESETID_Field]=$FREE_DISK
              v[$DEV_NAME_Field]=$NO_DEVICE
              v[$LINE_NUMBER_Field]=0
              v[$EXCLUDE_Field]=$includedDisk
              v[$DISK_STATUS_Field]=""
            fi
          else
            # The daemon says this disk is part of the filesystem.
            # Update the SG_DISKS line fields with the data from
            # mmlsdisk so that it is current.
            set -f ; set -- $mmlsdiskLine ; set +f
            failureGroup=$4
            holdsMetadata=$5
            holdsData=$6
            diskStatus=$7
            v[$FAILURE_GROUP_Field]=$failureGroup
            if [[ $holdsData = yes ]]
            then
              if [[ $holdsMetadata = yes ]]
              then
                v[$DISK_USAGE_Field]=dataAndMetadata
              else
                v[$DISK_USAGE_Field]=dataOnly
              fi
            else
              if [[ $holdsMetadata = yes ]]
              then
                v[$DISK_USAGE_Field]=metadataOnly
              else
                v[$DISK_USAGE_Field]=descOnly
              fi
            fi
            [[ $diskStatus = allocmap* ||
               $diskStatus = being*    ||
               $diskStatus = removing* ]] && diskStatus=$diskStatus$8
            v[$DISK_STATUS_Field]=$diskStatus
            [[ $diskStatus != ready && $diskStatus != "" ]] && oddState="yes"

            # If the disk is listed as a free disk, change the SG_DISKS
            # line to indicate that the disk is part of the filesystem.
            if [[ ${v[$NODESETID_Field]} = $FREE_DISK ]]
            then
              v[$NODESETID_Field]=$nodesetId
              v[$DEV_NAME_Field]=$fsname
            fi

            # Update the sequence number.
            seqNo=seqNo+1
            v[$LINE_NUMBER_Field]=$seqNo
          fi  # end of if [[ -z $mmlsdiskLine ]]
        fi  # end of if [[ disk belongs to filesystem or disk is a free disk ]]
        ;;

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

    esac  # end Change some of the fields

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

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

  done  # end while read -u3 sdrfsLine

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

  # Issue informational error messages for any active disks
  # reported by the daemon but not found in the sdrfs file.
  if [[ -s $tmpfile ]]
  then
    $rm -f $tmpfile2
    exec 3<&-
    exec 3< $tmpfile
    while read -u3 mmlsdiskLine
    do
      # Parse the line.
      set -f ; set -- $mmlsdiskLine ; set +f
      diskStatus=$7
      if [[ $diskStatus = "ready" ]]
      then
        print -- $mmlsdiskLine >> $tmpfile2
      else
        oddState=yes  # Set flag to let caller know he has odd-state disks.
      fi
    done  # end of while read -u3 mmlsdiskLine
    if [[ -s $tmpfile2 ]]
    then
      # Active disks are missing from the GPFS configuration data.
      printErrorMsg 102 $mmcmd
      $cat $tmpfile2 1>&2
      return 1
    fi
  fi  # end of if [[ -s $tmpfile ]]

  # Create/store the SG_HEADER line for the file system in the sdrfs file,
  # using the odd state flag that was set if any of the disks in the
  # file system were in an odd state.
  print -- "$sgh1:$oddState:$sgh2" >> $sdrfs
  checkForErrors "writing to file $sdrfs" $?

  # Print a message for the user if any disks are in an odd state.
  [[ $oddState = yes ]] && printErrorMsg 266 $mmcmd $fsname

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

  # Everything seems to have gone ok so far.
  # Rename the file so that the caller can find it.
  $mv $sdrfs $sdrfsFile
  checkForErrors "mv $sdrfs $sdrfsFile" $?

  # Return to the caller.
  return 0

}  #----- end of function reconcileSdrfsWithDaemon --------------

