#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1997,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 
# @(#)17 1.231.2.15 src/avs/fs/mmfs/ts/admin/mmchconfig.sh, mmfs, avs_rgpfs24, rgpfs24s012a 4/2/07 12:58:05
################################################################################
#
# Usage:  mmchconfig Attribute=value[,Attribute=value...] [-i | -I]
#                    [-N {Node[,Node...] | NodeFile | NodeClass}]
#
# where
#   -i        specifies immediate.  The change takes place immediately, not
#             just on the next restart.  This is currently only valid with
#             a subset of config attributes.
#
#   -I        specifies immediate ONLY.  The change takes place immediately
#             and does not have any effect on the next restart.
#             This is currently only valid with a subset of config attributes.
#
#   -N Node,Node,...  Specify the nodes whose states are to be changed.
#   -N NodeFile       NodeClass may be one of several possible node classes
#   -N NodeClass      (e.g., quorumnodes, managernodes, nsdnodes, etc.)
#                     If none of -N, -n, or nodelist is specified, the entire
#                     cluster is changed; otherwise, the changes are made to
#                     the specified nodes.
#                     Do not use -N to do an update to an omitted node as the
#                     output is not the same as running without nodefile.
#                     -N cannot be specified with the obsolete -n or nodelist
#                     options.
#
# Obsolete but still supported options:
#
#    -n NodeFile  is a file containing a list of nodes.
#                 If none of -N, -n, or nodelist is not specified,
#                 the entire cluster is changed; otherwise, the changes
#                 are made to the specified nodes.
#                 Do not use -n NodeFile to do an update to an omitted node
#                 as the output is not the same as running without -n NodeFile.
#                 -n cannot be specified with -N or nodelist.
#
#    nodelist     is a list of nodes separated by commas.
#                 If none of -N, -n, or nodelist is not specified,
#                 the entire cluster is changed; otherwise, the changes
#                 are made to the specified nodes.
#                 Do not use nodelist to do an update to an omitted node
#                 as the output is not the same as running without nodelist.
#                 nodelist cannot be specified with -N or -n.
#
# Notes on attributes:
#
#   The attributes that can be changed are divided into two main categories:
#     - externally-documented attributes
#     - internal configuration parameters to be used only under the
#       direction of IBM service
#
#   The externally-documented attributes are:
#
#     pagepool           specifies the size of the area in the shared memory
#                        segment from which buffers are allocated for data
#                        that is read/written from/to disk.
#
#     maxFilesToCache    specifies the number of recently used but closed
#                        files which will have their inodes cached.
#
#     maxStatCache       number of entries to keep in the stat cache
#                        files which will have their inodes cached.
#
#     dataStructureDump  specifies a directory to store dumps.  Specify
#                        'no' to turn off the feature altogether (no dumps).
#                        Specify 'yes' to send the dumps to /tmp/mmfs.
#
#     unmountOnDiskFail  controls how the daemon will respond when
#                        a disk failure is detected.
#
#     dmapiEventTimeout  controls the blocking of NFS and DFS threads
#
#     dmapiSessionFailureTimeout  controls the blocking of file operation
#                                 threads when there is a failure
#
#     dmapiMountTimeout  controls the blocking of mount operations
#
#     autoload           controls whether the daemon will start up
#                        automatically when nodes boot
#
#     designation        dash-separated list of node roles:
#                          client, manager, quorum.
#
#     uidDomain          specifies the UID/GID domain to be used.
#
#     automountDir       specifies the directory to be used by the Linux
#                        automounter for GPFS file systems that have the
#                        automount option specified.  The default directory
#                        is /gpfs/autmountdir.  This parameter does not
#                        apply to AIX environments.
#
#     tiebreakerDisks    controls whether GPFS will use a node quorum plus
#                        tiebreaker disks algorithm in place of the regular
#                        node-based quorum algorithm.  The tiebreaker disks
#                        do not have to belong to any particular file system.
#                        The disks are specified as a disk list.  If there
#                        are more than one disk, delimit each name with a
#                        semicolon and enclose the list in quotation marks.
#                        If "no" is specified, GPFS reverts to the traditional
#                        node-based quorum algorithm.  The disks must be
#                        directly accessible from the quorum nodes.
#
#     maxblocksize       max data block size the file system supports
#
#     release            bring the configuration information for the
#                        cluster to the latest format version.  Set the
#                        maxFeatureLevel config parameter to the latest
#                        release level or to the specified level.
#
#     allowRemoteConnections  controls whether outside nodes can connect
#                             to nodes in this GPFS cluster.  This is a
#                             global switch in addition to any other security
#                             mechanism that may be established.
#
#     cipherList         controls whether GPFS network communication
#                        between local nodes and remote nodes is secured.
#                        If cipherList is not specified, or if the value
#                        DEFAULT is specified, then GPFS will not authenticate
#                        or check authorization for network connections.
#                        If cipherList is specified, then it should be a valid
#                        cipher list as documented by man ciphers(1).
#
#     updateDiskType     causes the disk subtype information to be reevaluated.
#
################################################################################

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

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

# Local work files.  Names should be of the form:
#   fn=${tmpDir}fn.${mmcmd}.$$
chnodes=${tmpDir}chnodes.${mmcmd}.$$
diskLines=${tmpDir}diskLines.${mmcmd}.$$
oldcfgFile=${tmpDir}oldcfgFile.${mmcmd}.$$
tmpcfgFile=${tmpDir}tmpcfgFile.${mmcmd}.$$
inputNodes=${tmpDir}inputNodes.${mmcmd}.$$
allnodes=${tmpDir}allnodes.${mmcmd}.$$
undeterminedNodes=${tmpDir}undeterminedNodes.${mmcmd}.$$

LOCAL_FILES=" $chnodes $diskLines $undeterminedNodes $tmpcfgFile  \
              $inputNodes $allnodes $oldcfgFile "


# Local variables

usageMsg=289
noUsageMsg=0
integer intValue
integer nodeCount
integer n
integer requiredSize
integer keyGenNumber
mmsdrfsModified=no
mmfscfgModified=no
mmfscfgChange=no
synchronousNotify=no
typeset -l attr_lc
rc=0


# Local routines


################################################################################
#
# The mmchconfigCommonProcessing function extracts the mmfs.cfg information
# into a work file, checks the command line node list, increments the mmsdrfs
# gen number and creates needed node lists.  If any error is encountered,
# the mmchconfig command is terminated.
#
# Note:  This function uses only global variables.  Watch out for side effects.
#
################################################################################
function mmchconfigCommonProcessing
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGmmchconfigCommonProcessing ]] && set -x
  $mmTRACE_ENTER "$*"

  # Execute this function only once.
  [[ $mmchconfigInitialized = yes ]] &&  \
    return 0

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

  # Go through the current mmsdrfs file.  Increment the generation
  # number and build the node name lists that will be needed later.
  # Cross check the node list provided on the command line, if any.
  $rm -f $newsdrfs $tmpfile $nodefile $oldcfgFile $allnodes
  argcust=""
  coreQuorumDefined=""
  nodeCount=0
  IFS=":"            # Change the field separator to ':'.
  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.
    changeThisNode=no
    printLine=true

    case ${v[$LINE_TYPE_Field]} in

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

        ourClusterName=${v[$CLUSTER_NAME_Field]}
        ;;

      $NODESET_HDR )
        daemonVersionInEffect=${v[$MIN_DAEMON_VERSION_Field]}
        currentCipherList=${v[$CIPHER_LIST_Field]}
        [[ -z $currentCipherList ]] && currentCipherList=DEFAULT
        ;;

      $MEMBER_NODE )
        # This line represents a currently-active node.
        nodeCount=$nodeCount+1

        # Find out if any of the nodes are designated as core quorum nodes.
        [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]] &&  \
          coreQuorumDefined=yes

        # Create a file with all nodes in the cluster.
        # Note that this is in addition to $nodefile below.
        print -- "${v[$REL_HOSTNAME_Field]}" >> $allnodes
        checkForErrors "writing to file $allnodes" $?

        if [[ -z $arglist ]]
        then
          # If no node list or node file was provided, collect the
          # reliable node names of all the nodes in the cluster.
          print -- "${v[$REL_HOSTNAME_Field]}" >> $nodefile
          checkForErrors "writing to file $nodefile" $?

        else
          # See if this node is one of the nodes in the command line list.
          # The awk script checks whether the IP address in the chnodes file
          # matches the IP address in the current MEMBER_NODE line.
          # If yes, the changeThisNode flag will be set to 'yes'.
          # All other lines are passed unchanged and written to a tmpfile.
          $touch $tmpfile
          changeThisNode=$($awk '            \
            BEGIN { found = "false" }        \
            $1 == "'${v[$IPA_Field]}'" {     \
              if ( found == "false" ) {      \
                { found = "true" }           \
                { print "yes" }              \
                { next }                     \
              }                              \
            }                                \
            { print $0 >> "'$tmpfile'"}      \
          ' $chnodes)

          if [[ $changeThisNode = yes ]]
          then
            print -- "${v[$REL_HOSTNAME_Field]}" >> $nodefile
            checkForErrors "writing to file $nodefile" $?
            # Add the short name to a list of node names to be used
            # with the mmfixcfg command.
            [[ -z $argcust ]]  \
               && argcust=${v[$NODE_NAME_Field]}  \
               || argcust="$argcust,${v[$NODE_NAME_Field]}"
          fi

          # At this point, tmpfile contains all of the original lines in
          # file chnodes, except the line that matches the current node,
          # if there was such a line in the first place.  Make tmpfile
          # the chnodes file for the next iteration.  In this way,
          # if everything is OK with the user's input, the chnodes file
          # should be empty after we are finished.
          $mv $tmpfile $chnodes
          checkForErrors "mv $tmpfile $chnodes" $?

        fi  # end of if [[ -z $arglist ]]

        # Designate this node as a "preferred node".
        [[ ${v[$NODE_NUMBER_Field]} = $ourNodeNumber ]] &&  \
          preferredNode=${v[$REL_HOSTNAME_Field]}
        ;;

      $MMFSCFG )
        # Remove the line from the mmsdrfs file for now.  The mmfs.cfg
        # information will be added back before committing the changes.
        printLine=false

        # Extract the mmfs.cfg information.
        # It is everything past the first 4 fields.
        cfgLine="${v[5]}:${v[6]}:${v[7]}:${v[8]}:${v[9]}:${v[10]}:${v[11]}"
        cfgLine="$cfgLine:${v[12]}:${v[13]}:${v[14]}:${v[15]}:${v[16]}"
        cfgLine="$cfgLine:${v[17]}:${v[18]}:${v[19]}:${v[20]}:${v[21]}:${v[22]}"

        # To preserve tabs, temporarily set IFS to new line only.
        IFS="
"
        # Strip trailing colons and write the line to the file.
        print -- "${cfgLine%%+(:)}" >> $oldcfgFile
        checkForErrors "writing to file $oldcfgFile" $?
        IFS="$IFS_sv"  # Restore the default IFS settings.
        ;;

      * )  # We are not interested in any other lines.
        ;;

    esac  # end Change some of the fields

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

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

  done  # end while read -u3 sdrfsLine

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

  # If a node list or node file was specified on the command line
  # and the chnodes file is not empty, either some node names
  # were specified more than once or not all of the node names
  # belong to the GPFS cluster.
  if [[ -n $nodeNames && -s $chnodes ]]
  then
    # Get the name of the first offending node.
    tmpLine=$($head -1 $chnodes)
    set -f ; set -- $tmpLine ; set +f
    nodeName=$2
    printErrorMsg 290 $mmcmd $nodeName
    cleanupAndExit
  fi

  # Make working copies of the mmfs.cfg file.
  $cp $oldcfgFile $newcfg
  checkForErrors "cp $oldcfgFile $newcfg" $?
  $cp $oldcfgFile $tmpcfgFile
  checkForErrors "cp $oldcfgFile $tmpcfgFile" $?

  mmchconfigInitialized=yes

  return 0

}  #--------- end of mmchconfigCommonProcessing ----------------


###################################################################
#
# Function:  Ensures that the data in the mmsdrfs file is brought
#            up to date.  The things that take place here change
#            from release to release.
#
# Input:     $1 - mmsdrfs file to update.
#
# Output:    An updated mmsdrfs file.
#
# Returns:   0 - Success.
#            1 - Error detected; appropriate messages issued.
#
####################################################################
function convertMmsdrfsFile  #  <sdrfsFile>
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGconvertMmsdrfsFile ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset sdrfs=$1

  typeset firstChoice secondChoice getLocalDiskNameOutput magicWord
  typeset localDiskName rc rc1 nodeName failedDisks
  typeset secLevel


  # Go through the mmsdrfs file and make the needed changes.
  $rm -f $tmpsdrfs
  IFS=":"
  exec 3<&-
  exec 3< $sdrfs
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f
    IFS="$IFS_sv"

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

      $VERSION_LINE )
        # Return if there is nothing to do.
        startingSdrfsFormat=${v[$SDRFS_FORMAT_Field]}
        [[ $startingSdrfsFormat -eq $CURRENT_SDRFS_FORMAT ]] &&  \
          return 0

        # Assume everything will work out.
        v[$SDRFS_FORMAT_Field]=$CURRENT_SDRFS_FORMAT

        # New fields since rel 2.3 (sdrfs format level 0):
        #   NEW_KEY_Field COMMITTED_KEY_Field

        [[ -z ${v[$NEW_KEY_Field]} ]] &&  \
          v[$NEW_KEY_Field]=0

        [[ -z ${v[$COMMITTED_KEY_Field]} ]] &&  \
          v[$COMMITTED_KEY_Field]=${v[$NEW_KEY_Field]}

        [[ -z ${v[$SECLEVEL_Field]} ]] &&  \
          v[$SECLEVEL_Field]=0
        secLevel=${v[$SECLEVEL_Field]}

        [[ -z ${v[$KEYFILE_FORMAT_Field]} ]] &&  \
          v[$KEYFILE_FORMAT_Field]=0
        ;;

     $NODESET_HDR )
        # New fields since rel 2.3 (sdrfs format level 0):
        #   CIPHER_LIST_Field
        [[ $secLevel -gt 0 && -z ${v[$CIPHER_LIST_Field]} ]] &&  \
          v[$CIPHER_LIST_Field]=AUTHONLY
        ;;

      $MEMBER_NODE )
        # New fields since rel 2.3 (sdrfs format level 0):
        #   DAEMON_NODENAME_Field ADMIN_SHORTNAME_Field

        [[ -z ${v[$DAEMON_NODENAME_Field]} ]] &&  \
          v[$DAEMON_NODENAME_Field]=${v[$REL_HOSTNAME_Field]}

        [[ -z ${v[$ADMIN_SHORTNAME_Field]} ]] &&  \
          v[$ADMIN_SHORTNAME_Field]=${v[$NODE_NAME_Field]}
        ;;

      $SG_MOUNT )
        # New fields since rel 2.3 (sdrfs format level 0):
        #   QUOTA_OPT_Field (additional filesetquota indicator)

        [[ ${v[$QUOTA_OPT_Field]} != $QUOTA_DISACTIVATED ]] &&  \
          v[$QUOTA_OPT_Field]=$QUOTA_ACTIVATED
        ;;

      $SG_DISKS )
        # New fields since rel 2.3 (sdrfs format level 0):
        #   STORAGE_POOL_Field DAEMON_NSD_PRIMARY_Field DAEMON_NSD_BACKUP_Field

        # If storage pool is not assigned, assume the system pool.
        [[ -z ${v[$STORAGE_POOL_Field]} ]] &&  \
          v[$STORAGE_POOL_Field]="system"

        # Fill in the missing daemon node names of NSD servers.
        if [[ -z ${v[$DAEMON_NSD_PRIMARY_Field]} &&
              -n ${v[$NSD_PRIMARY_NODE_Field]}   ]]
        then
          v[$DAEMON_NSD_PRIMARY_Field]=$(checkAndConvertNodeValue  \
                 ${v[$NSD_PRIMARY_NODE_Field]} $DAEMON_NODENAME_Field)
          checkForErrors "checkAndConvertNodeValue ${v[$NSD_PRIMARY_NODE_Field]}" $?
        fi  # end of if [[ -z ${v[$DAEMON_NSD_PRIMARY_Field]} && ...

        if [[ -z ${v[$DAEMON_NSD_BACKUP_Field]} &&
              -n ${v[$NSD_BACKUP_NODE_Field]}   ]]
        then
          v[$DAEMON_NSD_BACKUP_Field]=$(checkAndConvertNodeValue  \
                 ${v[$NSD_BACKUP_NODE_Field]} $DAEMON_NODENAME_Field)
          checkForErrors "checkAndConvertNodeValue ${v[$NSD_BACKUP_NODE_Field]}" $?
        fi  # end of if [[ -z ${v[$DAEMON_NSD_BACKUP_Field]} && ...

        # Fill in the missing disk names of underlying lvs or vsds.
        if [[ ${v[$DISK_TYPE_Field]} = nsd &&
              (${v[$NSD_SUBTYPE_Field]} = lv ||
               ${v[$NSD_SUBTYPE_Field]} = vsd) &&
              -z ${v[$NSD_SUBTYPE_DISKNAME_Field]} ]]
        then
          # This an nsd built from an lv or a vsd but the name of
          # the underlying lv or vsd is not recorded.

          # Determine the node to ask about the nsd.
          if [[ -z ${v[$NSD_PRIMARY_NODE_Field]} ]]
          then
            firstChoice=$ourNodeName
            secondChoice=""
          elif [[ ${v[$NSD_PRIMARY_NODE_Field]} = $ourNodeName ]]
          then
            firstChoice=$ourNodeName
            secondChoice=${v[$NSD_BACKUP_NODE_Field]}
          elif [[ ${v[$NSD_BACKUP_NODE_Field]} = $ourNodeName ]]
          then
            firstChoice=$ourNodeName
            secondChoice=${v[$NSD_PRIMARY_NODE_Field]}
          else
            firstChoice=${v[$NSD_PRIMARY_NODE_Field]}
            secondChoice=${v[$NSD_BACKUP_NODE_Field]}
          fi  # end of if [[ -z ${v[$NSD_PRIMARY_NODE_Field]} ]]

          # Determine the local device name.
          if [[ $firstChoice = $ourNodeName ]]
          then
            getLocalDiskNameOutput=$(getLocalDiskName  \
              ${v[$PVID_Field]} ${v[$NSD_SUBTYPE_Field]} 2>$errMsg)
            rc=$?
          else
            getLocalDiskNameOutput=$($mmcommon on1 $firstChoice getLocalDiskName  \
              ${v[$PVID_Field]} ${v[$NSD_SUBTYPE_Field]} 2>$errMsg)
            rc=$?
          fi

          # Parse the output from the getLocalDiskName function.
          IFS=":"
          set -f ; set -- $getLocalDiskNameOutput ; set +f
          magicWord=$1
          localDiskName=$2
          rc1=$3   # rcode from tspreparedisk -p <pvid> -t <nsdSubtype>
          IFS="$IFS_sv"
          nodeName=$firstChoice

          if [[ $rc != 0 || $magicWord != getLocalDiskName || $rc1 -ne 0 ]]
          then
            # getLocalDiskName failed.  If there is a second choice, try again.
            # Note that because of the way firstChoice and secondChoice
            # were determined, secondChoice cannot be the local node.
            if [[ -n $secondChoice ]]
            then
              getLocalDiskNameOutput=$($mmcommon on1 $secondChoice getLocalDiskName  \
                ${v[$PVID_Field]} ${v[$NSD_SUBTYPE_Field]} 2>$errMsg)
              rc=$?

              # Parse the output from the getLocalDiskName function.
              IFS=":"
              set -f ; set -- $getLocalDiskNameOutput ; set +f
              magicWord=$1
              localDiskName=$2
              rc1=$3   # rcode from tspreparedisk -p <pvid> -t <nsdSubtype>
              IFS="$IFS_sv"
              nodeName=$secondChoice
            fi  # end of if [[ -n $secondChoice ]]
          fi  # end of if [[ $rc != 0 || $magicWord != getLocalDiskName ...

          if [[ $magicWord = getLocalDiskName ]]
          then
            if [[ $rc1 -eq 0 ]]
            then
              # Strip away the /dev/ prefix from the device name and then
              # store the local disk name in the nsdSubtypeDiskname field.
              localDiskName=${localDiskName##+(/)dev+(/)}
              v[$NSD_SUBTYPE_DISKNAME_Field]=$localDiskName
            else
              # The disk information was not obtained.  Add the nsd to
              # the list of failed disks, output any error info received,
              # and issue an appropriate message.
              failedDisks="$failedDisks\n\t${v[$DISK_NAME_Field]}"
              [[ -s $errMsg ]] && $cat $errMsg 1>&2
              if [[ $rc1 -eq $MM_DeviceNotFound ]]
              then
                printErrorMsg 187 $mmcmd $nodeName ${v[$DISK_NAME_Field]}
              else
                printErrorMsg 337 $mmcmd ${v[$DISK_NAME_Field]} $nodeName
              fi
            fi  # end of if [[ $rc1 -eq 0 ]]
          else
            # The disk information was not obtained.  Add the nsd to
            # the list of failed disks, output any error info received,
            # and issue an appropriate message.
            failedDisks="$failedDisks\n\t${v[$DISK_NAME_Field]}"
            [[ -s $errMsg ]] && $cat $errMsg 1>&2
            printErrorMsg 337 $mmcmd ${v[$DISK_NAME_Field]} $nodeName
          fi  # end of if [[ $magicWord = getLocalDiskName ]]
          $rm -f $errMsg
        fi  # end of if [[ ${v[$DISK_TYPE_Field]} = nsd && ...
        ;;

      $AUTHORIZED_CLUSTER )
        # The format of the public key file changed since
        # rel 2.3 (sdrfs format level 0).  The new information
        # is dynamically inserted by updateMmfsEnvironment.
        ;;

      $REM_CLUSTER_KEY )
        # The format of the public key file changed since
        # rel 2.3 (sdrfs format level 0).  The new information
        # is dynamically inserted by updateMmfsEnvironment.
        ;;

      * )  # We are not interested in any other lines.
        ;;

    esac  # end Change some of the fields

    # Build and write the line to the temp version of the mmsdrfs file.
    print_newLine >> $tmpsdrfs
    checkForErrors "writing to file $tmpsdrfs" $?

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

  done  # end while read -u3 sdrfsLine

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

  if [[ -n $failedDisks ]]
  then
    # If we failed for any disks, tell the user which ones
    # and instruct him to re-run the command.
    printErrorMsg 176 $mmcmd "$failedDisks"
    printErrorMsg 344 $mmcmd "mmchconfig release=LATEST"

    # Do not change the format level if we were not able
    # to fill in all of the missing information.
    $rm -f $sdrfs
    $awk -F:  '                                                                \
      /^'$GLOBAL_ID:$VERSION_LINE:'/ {                                         \
         # If this is the version line, update the format field.               \
         { $'$SDRFS_FORMAT_Field' = "'$startingSdrfsFormat'" }                 \
         { 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":" >> "'$sdrfs'" }    \
         { next }                                                              \
      }                                                                        \
      # All other lines are echoed without change.                             \
      { print $0 >> "'$sdrfs'" }                                               \
    ' $tmpsdrfs
    checkForErrors awk $?
  fi  # end of if [[ -n $failedDisks ]]

  # The sdrfs file was successfuly updated.
  # Replace the old mmsdrfs file with the new one.
  $mv -f $tmpsdrfs $sdrfs
  checkForErrors "mv $tmpsdrfs $sdrfs" $?

  return 0

}  #----- end of convertMmsdrfsFile ----------------------------


###########################################################################
#
# Function:  Determines the release level of the code installed on the
#            specified set of nodes.  Accordingly, updates the relevant
#            MEMBER_NODE line fields.
#
# Input:     $1 - file with the reliable hostnames of the nodes to check
#            $2 - mmsdrfs file to update (or just the MEMBER_NODE lines)
#            $3 - file that will contain the names of the failed nodes
#
# Output:    A string with the following format:
#            getInstalledCodeLevel:rc:status:maxDaemonVers:minDaemonVers
#
# Returns:   0 - At least some of the nodes were processed successfully.
#            1 - Error detected; appropriate messages issued.
#
###########################################################################
function getInstalledCodeLevel  # <nodefile> <sdrfsFile> <failedNodes>
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGgetInstalledCodeLevel ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset nodefile=$1
  typeset sdrfs=$2
  typeset failedNodes=$3

  typeset mmcommonOutput nodeName nodeNumber keyword cmdVersion
  typeset installedDaemonVersion installedProductVersion installedOsName
  typeset nodeSuccessfullyProcessed=""
  typeset status="incomplete"
  typeset maxDaemonVersion=0
  typeset minDaemonVersion=100000
  typeset outfile=${sdrfs}tmp$$
  typeset rc=0

  if [[ ! -s $nodefile || ! -s $sdrfs ]]
  then
    # Something is very wrong; there are missing input parms.
    printErrorMsg 260 getInstalledCodeLevel "<nodefile> <sdrfsFile>"
    rc=1
    print -- "getInstalledCodeLevel:$rc:unexpected_failure:0:0:"
    return $rc
  fi

  # Request the release level information for all of the nodes.
  $mmcommon onall $nodefile $unreachedNodes mmVersion2 >$tmpfile 2>&1
  rc=$?
  if [[ ! -s $tmpfile ]]
  then
    # We didn't even get out of this box.
    printErrorMsg 171 "getInstalledCodeLevel" "mmcommon onall $nodefile mmVersion2" $rc
    [[ $rc -eq 0 ]] && rc=1
    print -- "getInstalledCodeLevel:$rc:unexpected_failure:0:0:"
    return $rc
  fi

  # Initialize the list of failed nodes.  Assume all will fail.
  $cp $nodefile $failedNodes
  rc=$?
  if [[ $rc -ne 0 ]]
  then
    # Unexpected error from cp.
    printErrorMsg 171 "getInstalledCodeLevel" "cp $nodefile $failedNodes" $rc
    print -- "getInstalledCodeLevel:$rc:unexpected_failure:0:0:"
    return $rc
  fi

  # Parse the output.  The normal output from mmremote mmVersion2
  # starts with the keyword mmVersion2.  Any lines that do not start
  # with this keyword are assumed to be error messages.
  $rm -f $errMsg
  IFS=":"
  exec 3<&-
  exec 3< $tmpfile
  while read -u3 mmcommonOutput
  do
    set -f ; set -- $mmcommonOutput ; set +f
    nodeName=$1
    keyword=$2
    cmdVersion=$3
    nodeNumber=$4
    installedDaemonVersion=$5
    installedProductVersion=$6
    installedOsName=$7
    IFS="$IFS_sv"

    if [[ $keyword != *( )mmVersion2 ]]
    then
      # Unexpected line, assume it is error information.
      print -- "$mmcommonOutput" >> $errMsg
      continue
    fi

    # Keep track of highest and lowest daemon versions found.
    [[ $installedDaemonVersion -gt $maxDaemonVersion ]] &&  \
      maxDaemonVersion=$installedDaemonVersion
    [[ $installedDaemonVersion -lt $minDaemonVersion ]] &&  \
      minDaemonVersion=$installedDaemonVersion

    # Find in the mmsdrfs file the MEMBER_NODE line that corresponds
    # to this node and update the fields accordingly.
    processedNode=$($awk -F: '                                               \
      $'$LINE_TYPE_Field'   == "'$MEMBER_NODE'" &&                           \
      $'$NODE_NUMBER_Field' == "'$nodeNumber'"   {                           \
        { $'$DAEMON_VERSION_Field'  = "'$installedDaemonVersion'" }          \
        { $'$PRODUCT_VERSION_Field' = "'$installedProductVersion'" }         \
        { $'$OS_NAME_Field'         = "'$installedOsName'" }                 \
        { 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'" } \
        { print "'$nodeName'" }                                              \
        { next }                                                             \
      }                                                                      \
      # All other lines are echoed without change.                           \
      { print $0 >> "'$outfile'" }                                           \
    ' $sdrfs)
    rc=$?
    if [[ $rc -ne 0 ]]
    then
      # Unexpected awk error.
      printErrorMsg 171 "getInstalledCodeLevel" "awk" $rc
      print -- "getInstalledCodeLevel:$rc:unexpected_failure:0:0:"
      return $rc
    fi

    # The file was updated successfully.  Replace the original file with it.
    $mv $outfile $sdrfs
    rc=$?
    if [[ $rc -ne 0 ]]
    then
      # Unexpected error from mv.
      printErrorMsg 171 "getInstalledCodeLevel" "mv $outfile $sdrfs" $rc
      print -- "getInstalledCodeLevel:$rc:unexpected_failure:0:0:"
      return $rc
    fi
    $mmsync $sdrfs

    # If the node was found in the sdrfs file,
    # remove it from the failed nodes list.
    if [[ -n $processedNode ]]
    then
      $grep -v -w $processedNode $failedNodes >$tmpfile2
      $mv $tmpfile2 $failedNodes
      rc=$?
      if [[ $rc -ne 0 ]]
      then
        # Unexpected error from mv.
        printErrorMsg 171 "getInstalledCodeLevel" "mv $tmpfile2 $failedNodes" $rc
        print -- "getInstalledCodeLevel:$rc:unexpected_failure:0:0:"
        return $rc
      fi
      nodeSuccessfullyProcessed=yes
    fi

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

  done  # end of while read -u3 mmcommonOutput

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


  # Determine the overall result.
  if [[ -s $failedNodes ]]
  then
    # There is a failure.  Put out as much error information as possible.
    [[ -s $errMsg ]] && $cat $errMsg 1>&2

    if [[ -n $nodeSuccessfullyProcessed ]]
    then
      # The GPFS release level could not be determined on some of the nodes.
      printErrorMsg 575 $mmcmd "$($cat $failedNodes | $sed "s/^/$TABchar/")"
    else
      # The GPFS release level could not be determined on any of the nodes.
      printErrorMsg 576 $mmcmd
    fi
    # Tell the guy what to do.
    printErrorMsg 577 $mmcmd "     mmchconfig release=LATEST [-N NodeList]"
    rc=1
    status="incomplete"

  else
    # Complete success; the release level was determined on all nodes.
    rc=0
    status="complete"
  fi  # end if [[ -s $failedNodes ]]
  $rm -f $errMsg

  # Print out the results string and exit.
  print -- "getInstalledCodeLevel:$rc:$status:$maxDaemonVersion:$minDaemonVersion"
  return 0

}  #----- end of function getInstalledCodeLevel ------------------


####################################################################
#
#
# Function:  Determines the release level of the installed code.
#            If appropriate, updates the version information in
#            the NODESET_HDR line.
#
# Input:    $1 - release level:  LATEST or specific daemon version
#           $2 - file with the reliable hostnames of the nodes
#           $3 - mmsdrfs file to use
#
# Output:   A string with the following format:
#            setNodesetVersionFields:rc:status:DaemonVersion:
#
# Output:   Updated mmsdrfs file
#
# Returns:  Always zero; rc imbedded in output string.
#
####################################################################
function setNodesetVersionFields # <release> <nodeFile> <sdrfsFile>
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGsetNodesetVersionFields ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset -u releaseLevel=$1
  typeset nodefile=$2
  typeset sdrfs=$3

  typeset lowestVersion=100000
  typeset highestVersion=0
  typeset osEnvironment=$osName
  typeset daemonVersionChanged=no
  typeset rc=0

  typeset result keyword status maxDaemonVersionFound minDaemonVersionFound
  typeset oldNodesetVersion sdrfsLine printLine nodesetHdr ec
  typeset newDaemonVersion

  ########################################################################
  # Verify the release level information is up-to-date and that
  # the values for the daemon version fields are set correctly.
  #
  # Note that if the version is being increased, because new level
  # of code is installed on all nodes, the change can be made without
  # requiring daemon shutdown.  But if the request is to lower the value,
  # the daemon must be down and a node list cannot be specified.
  # These checks have been made prior to calling this routine.
  ########################################################################

  if [[ $releaseLevel = LATEST ]]
  then
    # Update the DAEMON_VERSION_Field on the MEMBER_NODE node lines.
    # Depending on how the mmchconfig command was invoked, either all
    # of the nodes in the cluster will be affected, or just a subset.
    result=$(getInstalledCodeLevel $nodefile $sdrfs $undeterminedNodes)
    ec=$?

    # Parse the result.
    IFS=':'
    set -f ; set -- $result ; set +f
    IFS="$IFS_sv"
    keyword=$1
    rc=$2
    status=$3
    maxDaemonVersionFound=$4
    minDaemonVersionFound=$5

    if [[ $keyword != getInstalledCodeLevel ]]
    then
      # Unexpected error.  Show error information and return.
      [[ -n $result ]] && print -u2 "$result"
      printErrorMsg 171 $mmcmd  \
        "getInstalledCodeLevel: collecting relese information" $ec
      [[ $ec -eq 0 ]] && ec=1
      print -- "setNodesetVersionFields:$ec:unchanged:0:"
      return 0
    fi

    if [[ $status != complete ]]
    then
      # The release level could not be determined on at least some of the nodes
      # or there was some other unexpected error.  Messages should have already
      # been issued.

      # Find out the existing version (needed for message 579 below).
      oldNodesetVersion=$(getNodesetInfo $MIN_DAEMON_VERSION_Field $nodesetId $sdrfs)
      [[ -z $oldNodesetVersion ]] && oldNodesetVersion=unknown

      # The GPFS release level remains unchanged.
      printErrorMsg 579 $mmcmd  \
        $oldNodesetVersion $(releaseToProductVersion $oldNodesetVersion)
      print -- "setNodesetVersionFields:$rc:unchanged:0:"
      return 0
    fi

  else
    # Convert the input release parameter to daemon version.
    newDaemonVersion=$(releaseToDaemonVersion $releaseLevel)
    if [[ $newDaemonVersion -eq 0 ]]
    then
      # Invalid value specified
      printErrorMsg 13 "$mmcmd" "release=$releaseLevel"
      rc=1
      print -- "setNodesetVersionFields:$rc:unchanged:0:"
      return 0
    fi
  fi  # end if [[ $releaseLevel = LATEST ]]


  # So far things seem to have worked out OK.  See if there is
  # a need to change the version fields in the NODESET_HDR line.

  # Go through the mmsdrfs file.  Keep track of the installed daemon
  # versions on each node.  Record the lowest version in the NODESET_HDR line.
  $rm -f $tmpsdrfs $undeterminedNodes
  IFS=":"
  exec 3<&-
  exec 3< $sdrfs
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f
    IFS="$IFS_sv"
    printLine=true

    case ${v[$LINE_TYPE_Field]} in

      $NODESET_HDR )
        # Save the line and, if appropriate, change the nodeset version field.
        nodesetHdr="$sdrfsLine"
        oldNodesetVersion=${v[$MIN_DAEMON_VERSION_Field]}
        if [[ $releaseLevel = LATEST ]]
        then
          printLine=false
        else
          if [[ $newDaemonVersion -lt $oldNodesetVersion ]]
          then
            v[$MIN_DAEMON_VERSION_Field]=$newDaemonVersion
            daemonVersionChanged=yes
          fi
        fi  # end if [[ $releaseLevel = LATEST ]]
        ;;

      $MEMBER_NODE )
        if [[ $releaseLevel = LATEST ]]
        then
          # Keep track of the daemon versions.
          [[ -z ${v[$DAEMON_VERSION_Field]} ]] &&  \
            print -- "${v[$REL_HOSTNAME_Field]}" >> $undeterminedNodes
          [[ ${v[$DAEMON_VERSION_Field]} -lt $lowestVersion ]] &&  \
            lowestVersion=${v[$DAEMON_VERSION_Field]}
          [[ ${v[$DAEMON_VERSION_Field]} -gt $highestVersion ]] &&  \
            highestVersion=${v[$DAEMON_VERSION_Field]}
          [[ -n ${v[$OS_NAME_Field]} && ${v[$OS_NAME_Field]} != $osEnvironment ]] &&  \
            osEnvironment="mixed"
        fi  # end of if [[ $releaseLevel = LATEST ]]
        ;;

      * )  # We are not interested in any other lines.
        ;;

    esac  # end Change some of the fields

    # Build and write the line to the temp version of the mmsdrfs file.
    if [[ $printLine = true ]]
    then
      print_newLine >> $tmpsdrfs
      checkForErrors "writing to file $tmpsdrfs" $?
    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.

  # Update the version numbers in the NODESET_HDR line as needed.
  if [[ $releaseLevel = LATEST ]]
  then
    # Parse the saved NODESET_HDR line.
    IFS=':'
    set -f ; set -A v -- - $nodesetHdr ; set +f
    IFS="$IFS_sv"

    # Update the version fields with their latest values.
    v[$MIN_DAEMON_VERSION_Field]=$lowestVersion
    v[$MAX_DAEMON_VERSION_Field]=$highestVersion
    v[$OS_ENVIRONMENT_Field]=$osEnvironment

    # Recreate the NODESET_HDR line and put it back.
    nodesetHdr=$(print_newLine)
    print -- "$nodesetHdr" >> $tmpsdrfs
    checkForErrors "writing to file $tmpsdrfs" $?

    if [[ $oldNodesetVersion -lt $lowestVersion ]]
    then
      daemonVersionChanged=yes
      newDaemonVersion=$lowestVersion
    fi

    # Examine the results so far and issue additional messages as needed.
    if [[ $lowestVersion -ne $highestVersion ]]
    then
      # Not all nodes are at the same level.
      if [[ -s $undeterminedNodes ]]
      then
        # The GPFS release level could not be determined on some of the nodes.
        printErrorMsg 575 $mmcmd "$($cat $undeterminedNodes | $sed "s/^/$TABchar/")"

        # Tell the guy what to do.
        printErrorMsg 577 $mmcmd "     mmchconfig release=LATEST [NodeList]"
      else
        # The cluster contains nodes that are at different release levels.
        [[ -z $lowestVersion ]] && lowestVersion=unknown
        printErrorMsg 582 $mmcmd  \
          $lowestVersion $(releaseToProductVersion $lowestVersion)  \
          $highestVersion  $(releaseToProductVersion $highestVersion)

        # Tell the guy what to do.
        printErrorMsg 578 $mmcmd "     mmchconfig release=LATEST [NodeList]"
      fi
    fi  # if [[ $lowestVersion -ne $highestVersion ]]

  fi  # end if [[ $releaseLevel = LATEST ]]

  # Sort and rename the updated version of the mmsdrfs file.
  LC_ALL=C $SORT_MMSDRFS $tmpsdrfs -o $sdrfs
  checkForErrors "sorting file $tmpsdrfs" $?
  $mmsync $sdrfs

  # Put out the final messages and return.
  if [[ $daemonVersionChanged = yes ]]
  then
    [[ -z $oldNodesetVersion ]] && oldNodesetVersion=unknown
    # The GPFS release level for the cluster will be changed.
    printErrorMsg 581 $mmcmd  \
      $oldNodesetVersion $(releaseToProductVersion $oldNodesetVersion)  \
      $newDaemonVersion  $(releaseToProductVersion $newDaemonVersion)
    print -- "setNodesetVersionFields:$rc:changed:$newDaemonVersion:"
  elif [[ -n $oldNodesetVersion ]]
  then
    # The GPFS release level remains unchanged.
    printErrorMsg 579 $mmcmd  \
      $oldNodesetVersion $(releaseToProductVersion $oldNodesetVersion)
    print -- "setNodesetVersionFields:$rc:unchanged:$oldNodesetVersion:"
  else
    # The GPFS release level cannot be determined.
    printErrorMsg 580 $mmcmd  \
      $initialDaemonVersion $(releaseToProductVersion $initialDaemonVersion)
    print -- "setNodesetVersionFields:$rc:undefined:$initialDaemonVersion:"
  fi  # end if [[ $daemonVersionChanged = yes ]]


  return 0

}  #--------- end of setNodesetVersionFields ----------------


##########################################################################
#
# Function:  Set the node designation field to the specified value.
#
# Input:     $1 - node designations list
#            $2 - mmsdrfs file to use
#            $3 - file with the reliable names of the nodes to change
#                 If not specified, all nodes in the cluster are changed.
#
# Output:    Updated mmsdrfs file.
#
# Returns:   0 - Node designation changed successfully.
#            Any other return code indicates unexpected error.
#
##########################################################################
function changeNodeDesignation # <designation> <mmsdrfsFile> [<nodeFile>]
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGchangeNodeDesignation ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset nodeRoles=$1
  typeset sdrfs=$2
  typeset nodeFile=$3
  typeset allNodeNames=$4

  typeset designation=""
  typeset quorumField=""
  typeset quorumNodeCount=0
  typeset newQuorumNodes=""
  typeset oldQuorumNodes=""
  typeset diskQuorumInEffect=""
  typeset rc=0

  typeset -l role
  typeset changeThisNode quorumNodeNumbers quorumNodeNames

  # Parse the node designations list.
  IFS="-"
  set -f ; set -- $nodeRoles ; set +f
  IFS="$IFS_sv"
  while [[ -n $1 ]]
  do
    role=$1  # Convert the node's role to lower case only.
    case $role in

      $CLIENT  ) designation=$CLIENT  ;;

      $MANAGER ) designation=$MANAGER ;;

      $QUORUM  ) quorumField=$quorumNode ;;

      $NONQUORUM ) quorumField=$nonQuorumNode ;;

      * ) # Invalid node designations specified.
        printErrorMsg 293 $mmcmd "$nodeRoles"
        cleanupAndExit
        ;;
    esac
    # Move to the next field.
    shift
  done  # end while [[ -n $1 ]]

  # If nodes are going to be defined as quorum nodes,
  # find out whether disk-based quorum is in effect.
  if [[ $quorumField = $quorumNode ]]
  then
    diskQuorumInEffect=$(showCfgValue tiebreakerDisks no $ourShortName $oldcfgFile)
    [[ $diskQuorumInEffect = no ]] && diskQuorumInEffect=""
  fi

  # Go through the mmsdrfs file.
  # Change the designation field on all applicable MEMBER_NODE lines.
  $rm -f $tmpsdrfs $chnodes $diskLines
  IFS=":"
  exec 3<&-
  exec 3< $sdrfs
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f

    IFS="$IFS_sv"
    changeThisNode=no

    case ${v[$LINE_TYPE_Field]} in

      $MEMBER_NODE )
        if [[ -z $nodeFile ]]
        then
          # If no argument list is provided,
          # all MEMBER_NODE lines are changed.
          changeThisNode=yes
        else
          # See if this node is one of the nodes in the command line list.
          changeThisNode=$($awk '                    \
             $1 == "'${v[$REL_HOSTNAME_Field]}'" {   \
               { print "yes" }                       \
               { exit }                              \
             }                                       \
          ' $nodeFile)
        fi  # end if [[ -z $nodeFile ]]

        if [[ $changeThisNode = yes ]]
        then
          # Handle quorum/nonquorum changes.
          if [[ -n $quorumField ]]
          then
            if [[ $quorumField = $quorumNode ]]
            then
              # When a nonquorum node will become a quorum node,
              # mark the node as 'new'.
              if [[ ${v[$CORE_QUORUM_Field]} = $nonQuorumNode ]]
              then
                v[$ADDNODE_STATE_Field]=$NEW_NODE
                newQuorumNodes=yes
              fi
            else
              # When changing a node's designation from quorum to
              # nonquorum, GPFS must be down on the affected nodes.
              [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]] &&  \
                print -- "${v[$REL_HOSTNAME_Field]}" >> $chnodes

              # Clear the new node flag in case it is still set.
              v[$ADDNODE_STATE_Field]=$OLD_NODE
            fi  # end if [[ $quorumField = $quorumNode ]]

            # Set the new value.
            v[$CORE_QUORUM_Field]=$quorumField
          fi  # end of if [[ -n $quorumField ]]

          # Handle client/manager changes.
          [[ -n $designation ]] &&  \
            v[$DESIGNATION_Field]=$designation
        fi  # end of if [[ $changeThisNode = yes ]]

        if [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]]
        then
          (( quorumNodeCount += 1 ))
          if [[ -z $quorumNodeNames ]]
          then
            # This is the first node to add to the lists.
            quorumNodeNumbers="${v[$NODE_NUMBER_Field]}"
            quorumNodeNames="${v[$REL_HOSTNAME_Field]}"
          else
            if [[ ${v[$REL_HOSTNAME_Field]} = $ourNodeName ]]
            then
              # This is the local node; add it at the front of the lists
              # so it will be the first quorum node used.
              quorumNodeNumbers="${v[$NODE_NUMBER_Field]},${quorumNodeNumbers}"
              quorumNodeNames="${v[$REL_HOSTNAME_Field]},${quorumNodeNames}"
            else
              # This is not the local node; add it at the end of the lists.
              quorumNodeNumbers="${quorumNodeNumbers},${v[$NODE_NUMBER_Field]}"
              quorumNodeNames="${quorumNodeNames},${v[$REL_HOSTNAME_Field]}"
            fi
          fi  # end of if [[ -z $quorumNodeNames ]]
          [[ ${v[$ADDNODE_STATE_Field]} = $OLD_NODE ]] &&  \
            oldQuorumNodes=yes
        fi  # end of if [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]]
        ;;

      $SG_DISKS )
        # Collect the lines that represent the quorum disks.
        if [[ -n $diskQuorumInEffect && ${v[$PAXOS_Field]} = $PaxosDisk ]]
        then
          print_newLine >> $diskLines
          checkForErrors "writing to file $diskLines" $?
        fi  # end if [[ -n $diskQuorumInEffect && ...
        ;;

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

    esac  # end Change some of the fields

    # Build and write the line to the new mmsdrfs file.
    print_newLine >> $tmpsdrfs
    checkForErrors "writing to file $tmpsdrfs" $?

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

  done  # end while read -u3 sdrfsLine

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

  # Ensure that there is at least one quorum node in the cluster.
  if [[ $quorumNodeCount -eq 0 ]]
  then
    printErrorMsg 53 $mmcmd
    cleanupAndExit
  fi

  # Perform additional processing if disk-based quorum is in effect.
  if [[ -n $diskQuorumInEffect ]]
  then
    # Fail the command if there are more than eight quorum nodes.
    if [[ $quorumNodeCount -gt 8 ]]
    then
      # There are more than 8 quorum nodes while tiebreaker disks are in use.
      printErrorMsg 131 $mmcmd
      cleanupAndExit
    fi

    # The quorum disks must be reformatted.
    if [[ -n $newQuorumNodes ]]
    then
      formatPaxosDisks $diskLines $quorumNodeNumbers $quorumNodeNames mmaddnode
      if [[ $? -ne 0 ]]
      then
        # GPFS failed to initialize the tiebreaker disks.
        printErrorMsg 132 $mmcmd
        cleanupAndExit
      fi
    fi
  fi  # end of if [[ -n $diskQuorumInEffect ]]

  # If, as a result of this command, all quorum nodes will end up
  # being marked as "new", the daemon must be stopped everywhere
  # and the addnode state field reset to "old".
  if [[ -z $oldQuorumNodes ]]
  then
    # Ensure the daemon is down everywhere.
    if [[ -z $daemonInactiveVerified ]]
    then
      printInfoMsg 339
      verifyDaemonInactive $allnodes $mmcmd
      [[ $? -ne 0 ]] && cleanupAndExit
      daemonInactiveVerified=yes
    fi

    # Reset the addnode state of all nodes to 'old'.
    $rm -f $tmpfile
    $awk -F:  '                                                                \
       # If this is a node line, clear the addnode state field.                \
       /'^$HOME_CLUSTER:$MEMBER_NODE:'/ {                                      \
         { $'$ADDNODE_STATE_Field' = "'$OLD_NODE'" }                           \
         { 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":" >> "'$tmpfile'" }  \
          { next }                                                             \
       }                                                                       \
       # All other lines are echoed without change.                            \
       { print $0 >> "'$tmpfile'" }                                            \
       END { print gen }                                                       \
    ' $tmpsdrfs
    checkForErrors awk $?

    # The file was updated successfully.
    $mv $tmpfile $tmpsdrfs
    checkForErrors "mv $tmpfile $tmpsdrfs" $?
  fi  # end of if [[ -z $oldQuorumNodes ]]

  # If needed, ensure the daemon is down on the affected nodes.
  # Do not set the daemonInactiveVerified flag because we are
  # dealing with only a small subset of the nodes.
  if [[ -s $chnodes && -z $daemonInactiveVerified ]]
  then
    printInfoMsg 453
    verifyDaemonInactive $chnodes $mmcmd
    [[ $? -ne 0 ]] && cleanupAndExit
  fi

  # Everything seems to have gone OK so far.
  # No need to sort the mmsdrfs file this time,
  # just rename it so that the caller can find it.
  $mv $tmpsdrfs $sdrfs
  checkForErrors "mv $tmpsdrfs $sdrfs" $?

  return 0

}  #----- end of function changeNodeDesignation ------------------


##########################################################################
#
# Function:  Set the add node state field to the specified value
#
# Input:     $1 - new state
#            $2 - mmsdrfs file to use
#            $3 - file with the reliable names of the nodes to change
#                 If not specified, all nodes in the cluster are changed.
#            $4 - file to hold the names of all nodes in the cluster
#
# Output:    Updated mmsdrfs file
#
# Returns:   0 - node state changed successfully
#            Any other return code indicates unexpected error.
#
##########################################################################
function changeAddNodeState  # <state> <sdrfsFile> [<nodeFile> <allNodeNames>]
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGchangeAddNodeState ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset new_state=$1
  typeset sdrfs=$2
  typeset nodeFile=$3
  typeset allNodeNames=$4

  typeset rc=0
  typeset changeThisNode

  if [[ $new_state = "new" ]]
  then
    new_state=$NEW_NODE
  elif [[ $new_state = "old" ]]
  then
    new_state=$OLD_NODE
  else
    # Unexpected error
    printErrorMsg 171 "$mmcmd" "$1" $2
    cleanupAndExit
  fi

  # Clear files that will be created.
  $rm -f $tmpsdrfs
  [[ -n $allNodeNames ]] && $rm -f $allNodeNames

  # Go through the mmsdrfs file.  Increment the generation number.
  # Change the add node state field on all applicable MEMBER_NODE lines.
  IFS=":"           # Change the field separator to ':'.
  exec 3<&-
  exec 3< $sdrfs
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f

    IFS="$IFS_sv"
    changeThisNode=no

    case ${v[$LINE_TYPE_Field]} in

      $MEMBER_NODE )
        if [[ -z $nodeFile ]]
        then
          # If no argument list is provided,
          # all MEMBER_NODE lines are changed.
          changeThisNode=yes
        else
          # See if this node is one of the nodes in the command line list.
          # The awk script checks if the name in the node file
          # matches the reliable name in the current MEMBER_NODE line.
          # If yes, the changeThisNode flag will be set to 'yes'.
          changeThisNode=$($awk '                    \
             $1 == "'${v[$REL_HOSTNAME_Field]}'" {   \
               { print "yes" }                       \
               { exit }                              \
             }                                       \
          ' $nodeFile)
        fi  # end of if [[ -z $nodeFile ]]

        [[ $changeThisNode = yes ]] &&  \
          v[$ADDNODE_STATE_Field]=$new_state

        [[ -n $allNodeNames ]] &&  \
          print -- "${v[$REL_HOSTNAME_Field]}" >> $allNodeNames
        ;;

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

    esac  # end Change some of the fields

    # Build and write the line to the new mmsdrfs file.
    print_newLine >> $tmpsdrfs
    checkForErrors "writing to file $tmpsdrfs" $?

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

  done  # end while read -u3 sdrfsLine

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

  # Everything seems to have gone OK so far.
  # No need to sort the mmsdrfs file this time,
  # just rename it so that the caller can find it.
  $mv $tmpsdrfs $sdrfs
  checkForErrors "mv $tmpsdrfs $sdrfs" $?

  $mmTRACE_EXIT rc=0
  return 0

}  #----- end of function changeAddNodeState ---------------------


######################################################################
#
# Function:  Reevaluate the disk subtype field information for all
#            disks in the cluster.
#
# Input:     $1 - all or file name with disk names, one per line.
#            $2 - mmsdrfs file to use
#
# Output:    Updated mmsdrfs file
#
# Returns:   0 - disk subtypes changed successfully.
#            Any other return code indicates unexpected error.
#
######################################################################
function updateDiskType  # <all | filename> <mmsdrfsFile>
{
  [[ -n $DEBUG || -n $DEBUGupdateDiskType ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset disksToChange=$1
  typeset sdrfs=$2

  typeset rc=0
  typeset disksNotUpdated=""
  typeset noDisksChanged=yes
  typeset diskSubtypeUpdated newDiskSubtype nodeName

  # Some initializations.
  [[ $disksToChange = yes ]] && disksToChange=all

  # If file name specified, verify the file exists.
  if [[ $disksToChange != all && ! -f $disksToChange ]]
  then
    # Can't read the file with disk names.
    printErrorMsg 43 $mmcmd $disksToChange
    cleanupAndExit
  fi

  # Define a file for extended error information.
  errMsgLog=${rasDir}errMsgLog.${mmcmd}.$$

  # Cleanup old logs that were not touched for over 10 days.
  $find ${rasDir} -name "errMsgLog.${mmcmd}.*"  \
      -atime +10 -mtime +10 -exec $rm -f {} \; >/dev/null 2>/dev/null

  $rm -f $tmpsdrfs $errMsgLog $nodefile

  # Sort the file using the line type field as a primary key.
  $sort -t: -k 2,2 -k 1,1  $sdrfs -o $sdrfs

  # Go through the mmsdrfs file.  Increment the generation number.
  # Change the subtype field on all applicable SG_DISK lines.
  IFS=":"
  exec 3<&-
  exec 3< $sdrfs
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f

    IFS="$IFS_sv"

    case ${v[$LINE_TYPE_Field]} in

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

      $SG_DISKS )
        # Assume something will go wrong.
        diskSubtypeUpdated=no
        reevaluateThisDisk=no

        # Determine whether we are interested in this disk.
        if [[ $disksToChange != all ]]
        then
          # disksToChange is the name of a file with disk names.
          diskName=$($grep -w ${v[$DISK_NAME_Field]} $disksToChange 2>/dev/null)
          [[ -n $diskName ]] && reevaluateThisDisk=yes
        else
          reevaluateThisDisk=yes
        fi

        if [[ $reevaluateThisDisk = yes ]]
        then
          # Assume the disk is directly attached and known on this node.
          # Determine its subtype.
          newDiskSubtype=$(determineDiskSubtype  \
                           ${v[$DISK_NAME_Field]} reevaluate 2>>$errMsgLog)
          rc=$?

          # If the disk type was successfully re-evaluated, record it
          # in the mmsdrfs file.  Otherwise, try to find a node that can
          # give us an answer.
          if [[ $rc -eq 0 && -n $newDiskSubtype ]]
          then
            v[$DISK_SUBTYPE_Field]=$newDiskSubtype
            diskSubtypeUpdated=yes
          else
            # Decide where to look for the disk.
            # Until the above is done better, try the nodes one at a time.
            for nodeName in $($cat $nodefile)
            do
              newDiskSubtype=$($mmcommon on1 $nodeName  \
                  determineDiskSubtype ${v[$DISK_NAME_Field]} reevaluate 2>>$errMsgLog)
              rc=$?
              if [[ $rc -eq 0 && -n $newDiskSubtype ]]
              then
                v[$DISK_SUBTYPE_Field]=$newDiskSubtype
                diskSubtypeUpdated=yes
                break
              fi
            done  # end for nodeName in $($cat $nodefile)
          fi  # end if [[ $rc -eq 0 && -n $newDiskSubtype ]]

          # If we were not able to determine the new disk type,
          # add the disk to the list of failed/unchanged disks.
          if [[ $diskSubtypeUpdated = no ]]
          then
            disksNotUpdated="$disksNotUpdated\n\t${v[$DISK_NAME_Field]}"
          else
            noDisksChanged=no
          fi
        fi  # end if [[ $reevaluateThisDisk = yes ]]
        ;;

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

    esac  # end Change some of the fields

    # Build and write the line to the new mmsdrfs file.
    print_newLine >> $tmpsdrfs
    checkForErrors "writing to file $tmpsdrfs" $?

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

  done  # end while read -u3 sdrfsLine

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

  if [[ $noDisksChanged = yes ]]
  then
    # We were not able to change any of the disks.
    print -u2 "$mmcmd:  Not able to determine the disk type for any of the disks."
  elif [[ -n $disksNotUpdated ]]
  then
    # Tell the user which disks failed.
    print -u2 "$mmcmd:  Not able to determine the disk type for the following disks: $disksNotUpdated"
    print -u2 "$mmcmd:  Reissue the command from a node that has access to the disks."
    [[ -s $errMsgLog ]] &&  \
      print -u2 "$mmcmd:  File $errMsgLog contains additional error information."
  else
    :  # All disks were successfully re-evaluated.
  fi

  [[ ! -s $errMsgLog ]] && $rm -f $errMsgLog

  # Everything seems to have gone OK so far.
  # Put the file back in the correct order and return.
  LC_ALL=C $SORT_MMSDRFS $tmpsdrfs -o $sdrfs
  checkForErrors sort $?

  return 0

}  #----- end of function updateDiskType -------------------------


####################################################################
#
# Function:  Define disks for use by the disk quorum algorithm.
#
# Input:     $1 - comma-separated list of NSD names
#            $2 - mmsdrfs file to use
#
# Output:    None.
#
# Returns:   0 - quorum disks defined successfully
#            Any other return code indicates unexpected error.
#
####################################################################
function setDiskQuorum # <diskNameList> <mmsdrfsFile>
{
  [[ -n $DEBUG || -n $DEBUGsetDiskQuorum ]] && set -x
  $mmTRACE_ENTER "$*"

  typeset diskNameList=$1
  typeset sdrfs=$2

  typeset rc=0
  typeset quorumNodeNumbers=""
  typeset quorumNodeNames=""
  typeset quorumNodeCount=0
  typeset diskCount=0

  typeset diskList sdrfsLine assignThisDisk
  typeset diskName tempList

  # Create a blank-separated list of the disk names.
  IFS=";"
  for diskName in $diskNameList
  do
    [[ -z $diskName ]] && continue
    diskList="${diskList}${diskName}${BLANKchar}"
    (( diskCount += 1 ))
  done  # end for diskName in $diskNameList
  IFS="$IFS_sv"

  if [[ $diskCount -gt 3 ]]
  then
    print -u2 "$mmcmd: More than three disks specified."
    return 1
  fi

  # Go through the mmsdrfs file and collect needed information.
  $rm -f $tmpsdrfs $diskLines
  IFS=":"
  exec 3<&-
  exec 3< $sdrfs
  while read -u3 sdrfsLine
  do
    # Parse the line.
    set -f ; set -A v -- - $sdrfsLine ; set +f

    IFS="$IFS_sv"

    case ${v[$LINE_TYPE_Field]} in

      $MEMBER_NODE )   # This line describes a node.
        # Collect information about the quorum nodes in the cluster.
        if [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]]
        then
          (( quorumNodeCount += 1 ))
          if [[ -z $quorumNodeNames ]]
          then
            # This is the first node to add to the lists.
            quorumNodeNumbers="${v[$NODE_NUMBER_Field]}"
            quorumNodeNames="${v[$REL_HOSTNAME_Field]}"
          else
            if [[ ${v[$REL_HOSTNAME_Field]} = $ourNodeName ]]
            then
              # This is the local node; add it at the front of the lists
              # so it will be the first quorum node used.
              quorumNodeNumbers="${v[$NODE_NUMBER_Field]},${quorumNodeNumbers}"
              quorumNodeNames="${v[$REL_HOSTNAME_Field]},${quorumNodeNames}"
            else
              # This is not the local node; add it at the end of the lists.
              quorumNodeNumbers="${quorumNodeNumbers},${v[$NODE_NUMBER_Field]}"
              quorumNodeNames="${quorumNodeNames},${v[$REL_HOSTNAME_Field]}"
            fi
          fi  # end of if [[ -z $quorumNodeNames ]]
        fi  # end of if [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]]
        ;;

      $SG_DISKS )
        # Determine whether we are interested in this disk.
        tempList=""
        assignThisDisk=no
        for diskName in $diskList
        do
          if [[ ${v[$DISK_NAME_Field]} = $diskName ]]
          then
            # The disk represented by the current SG_DISKS line
            # is one of the disks that we want.

            if [[ $assignThisDisk = no ]]
            then
              # If we see this disk for the first time,
              # mark it as a quorum (Paxos) disk.
              assignThisDisk=yes

            else
              # We have already seen this name during the current iteration.
              # It must be a duplicate entry in the command line list.
              printErrorMsg 88 $mmcmd $diskName
              return 1
            fi  # end of if [[ $assignThisDisk = no ]]

          else
            # diskName does not match the name of the disk in the current
            # SG_DISKS line.  Add diskName to the temporary list.
            tempList="$tempList $diskName"
          fi  # end of if [[ ${v[$DISK_NAME_Field]} = $diskName ]]
        done  # end of for diskName in $diskList

        # At this point we know if the current SG_DISKS line represents
        # a disk that will be designated as a quorum disk.
        # If yes, mark the disk accordingly and save the line for later
        # processing.  Otherwise, clear the field; this may be an old
        # disk that is not needed anymore.
        if [[ $assignThisDisk = yes ]]
        then
          v[$PAXOS_Field]=$PaxosDisk
          print_newLine >> $diskLines
          checkForErrors "writing to file $diskLines" $?
        else
          v[$PAXOS_Field]=""
        fi

         # Initialize diskList for the next iteration.
         diskList=$tempList
        ;;

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

    esac  # end Change some of the fields

    # Build and write the line to the new mmsdrfs file.
    print_newLine >> $tmpsdrfs
    checkForErrors "writing to file $tmpsdrfs" $?

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

  done  # end while read -u3 sdrfsLine

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

  # Replace the old sdrfs file with the new one.
  $mv $tmpsdrfs $sdrfs
  checkForErrors "mv $tmpsdrfs $sdrfs" $?

  # Disk-based quorum is not allowed if there are more than eight quorum nodes.
  if [[ $quorumNodeCount -gt 8 ]]
  then
    # There are more than 8 quorum nodes while tiebreaker disks are in use.
    printErrorMsg 131 $mmcmd
    return 1
  fi

  # If there are still entries left in diskList list, this means
  # that the user specified disks that do not belong to the cluster.
  if [[ -n $diskList ]]
  then
    # Disks not known to GPFS.
    printErrorMsg 486 $mmcmd "$diskList"
    return 1
  fi

  # Things are OK so far.  Start formatting the disks.
  formatPaxosDisks $diskLines $quorumNodeNumbers $quorumNodeNames mmchconfig
  if [[ $? -ne 0 ]]
  then
    # GPFS failed to initialize the tiebreaker disks.
    printErrorMsg 132 $mmcmd
    return 1
  fi

  # Everything must be OK.
  return 0

}  #----- end of function setDiskQuorum --------------------------


#######################################################################
#
# Function:  Verifies that the mmfixcfg command executed successfully.
#            If the return code from the command is not zero,
#            the function issues a message, and exits via the
#            cleanupAndExit routine.
#
# Input:     $1 - name of the parameter being changed
#            $2 - return code from the mmfixcfg command
#
# Output:    None
#
# Returns:   0 - command finished successfully
#            If error, no return; processing is stopped.
#
#######################################################################
function checkForMmfixcfgErrors   # <argument> <rc>
{
  typeset sourceFile="mmchconfig.sh"
  [[ -n $DEBUG || -n $DEBUGcheckForMmfixcfgErrors ]] && set -x
  $mmTRACE_ENTER "$*"

  if [ $2 != "0" ]
  then
    # mmfixcfg error
    printErrorMsg 79 "$mmcmd" "$1"
    cleanupAndExit
  fi

  $mmTRACE_EXIT "rc=0"

}  #----- end of function checkForMmfixcfgErrors -----------------



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


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

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

# The attributes to be changed are always the first argument.
attributeList=$arg1
shift 1
argc=argc-1

while getopts :iIn:N: OPT
do
  case $OPT in

    i) # immediate option
       [[ $iarg = yes ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       immediate="-i";
       iarg=yes
       argc=argc-1
       ;;

    I) # immediate-only option
       [[ $Iarg = yes ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       immediate="-I";
       immediateOnly=yes
       Iarg=yes
       argc=argc-1
       ;;

    n) # node names file
       [[ -n $narg ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       nflag="-$OPT"
       narg=$OPTARG
       argc=argc-2
       [[ -n $Nflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg $nflag $Nflag
       ;;

    N) # node names list, file, or class
       [[ -n $Narg ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Nflag="-$OPT"
       Narg=$OPTARG
       argc=argc-2
       [[ -n $nflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg $Nflag $nflag
       ;;

    +[iInN]) # Invalid option
       syntaxError "invalidOption" $usageMsg $OPT
       ;;

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

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

  esac

done   # end of while getopts :iIn:N: OPT

# Drop the processed options from the parameter list.
shift OPTIND-1

# Complete the parameter checking.
if [[ -n $Narg ]]
then
  # Set vars to indicate that node names were specified.
  nodeNames=$Narg
  arglist=yes

elif [[ -z $narg ]]
then
  # If the -n option is not used, a list of node names is allowed.
  if [[ $argc -eq 1 ]]
  then
    # If there is exactly one string left,
    # it is assumed to be a list of nodes.
    arglist=$1

    # Convert the input node list into a file.
    $rm -f $inputNodes
    IFS=','
    for nodeName in $arglist
    do
      print -- "$nodeName" >> $inputNodes
      checkForErrors "writing to $inputNodes" $?
    done
    IFS="$IFS_sv"    # Restore the default IFS settings.
    nodeNames=$inputNodes
    arglist=yes

  elif [[ $argc -gt 1 ]]
  then
    # If more than one string is left, we have a syntax error.
    syntaxError "extraArg" $usageMsg "$2"
  else
    # No node names were specified.
    :  # Do nothing; the change is for all nodes.
  fi

else
  # -n was specified, so there should be no other parms.
  [[ $argc -gt 0 ]] &&  \
    syntaxError "extraArg" $usageMsg "$1"

  nodeNames=$narg
  arglist=yes

fi   # end of if [[ -n $Narg ]]

# If a node list or node file was specified on the command line,
# create a file containing the IP address and the original node
# identifier of each of the nodes.
if [[ -n $nodeNames ]]
then
  createVerifiedNodefile $nodeNames $IPA_Field yes $chnodes
  [[ $? -ne 0 ]] && cleanupAndExit
fi


#######################################################################
# Set up trap exception handling and call the gpfsInit function.
# It will ensure that the local copy of the mmsdrfs and the rest of
# the GPFS system files are up-to-date and will obtain the sdr lock.
#######################################################################
trap pretrap HUP INT QUIT KILL
gpfsInitOutput=$(gpfsInit $lockId)
setGlobalVar $? $gpfsInitOutput


########################################################################
# Call the mmchconfigCommonProcessing local function.  It makes sure
# that the input node list has no errors in it, and performs other
# common for all attributes processing.  If any error is discovered,
# the function terminates the command via the cleanupAndExit routine.
########################################################################
mmchconfigCommonProcessing


###############################################
# Start of main loop
###############################################
IFS=","
for attributePair in $attributeList
do
  # Parse the attribute=value pair.
  IFS="="
  set -f ; set -- $attributePair ; set +f
  attr=$1
  value=$2
  junk=$3
  IFS="$IFS_sv"

  [[ $attributePair != *=* || -n $junk ]] &&  \
    syntaxError "invalidAttrValuePair" $usageMsg $attributePair

  [[ -z $value || $value = DELETE ]] && value=DEFAULT


  # Processing depends on the attribute type being changed.
  ignoreNodeList=""
  attr_lc=$attr        # Convert attr to lower case only.
  case $attr_lc in

    #-----------
    "pagepool" )  # Documented attribute
    #-----------
      if [[ $value != DEFAULT ]]
      then
        # Verify the value is an integer.
        # Range checking is left for the daemon.
        intValue=$(checkIntRange pagepool $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tschpool command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tschpoolParms="$tschpoolParms -s 64M "
        else
          tschpoolParms="$tschpoolParms -s $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="pagepool"
      mmfscfgChange=yes
      ;;


    #------------------
    "maxbufferdescs" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxBufferDescs $value 512 1000000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxBufferDescs"
      mmfscfgChange=yes
      ;;


    #------------------
    "maxfilestocache" )  # Documented attribute
    #------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxFilesToCache $value 1 100000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxFilesToCache"
      mmfscfgChange=yes
      ;;


    #---------------
    "maxstatcache" )  # Documented attribute
    #---------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxStatCache $value 0 10000000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxStatCache"
      mmfscfgChange=yes
      ;;


    #------------------
    "statcachedirpct" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange statCacheDirPct $value 0 90)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="statCacheDirPct"
      mmfscfgChange=yes
      ;;


    #-------------------
    "maxdiskaddrbuffs" )
    #-------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxDiskAddrBuffs $value 0 1000000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxDiskAddrBuffs"
      mmfscfgChange=yes
      ;;


    #--------------------
    "datastructuredump" )  # Documented attribute
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        # Acceptable values are 'yes', 'no' or an absolute path name.
        if [[ $value != yes && $value != no && $value = ${value#/} ]]
        then
          printErrorMsg 149 $mmcmd dataStructureDump $value
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr yes "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dataStructureDump"
      mmfscfgChange=yes
      ;;


    #-----------------------------
    "datastructuredumponsgpanic" )
    #-----------------------------
      if [[ $value != DEFAULT ]]
      then
        # Acceptable values are 'yes', 'no' or an absolute path name.
        if [[ $value != yes && $value != no && $value = ${value#/} ]]
        then
          printErrorMsg 149 $mmcmd dataStructureDumpOnSGPanic $value
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr no "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dataStructureDumpOnSGPanic"
      mmfscfgChange=yes
      ;;


    #---------
    "envvar" )    # Documented attribute
    #---------
      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="envVar"
      mmfscfgChange=yes
      ;;


    #------------
    "uiddomain" )    # Documented attribute
    #------------
      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="uidDomain"
      mmfscfgChange=yes
      ;;


    #---------------
    "automountdir" )       # Documented attribute
    #---------------
      if [[ $value != DEFAULT ]]
      then
        # The value must be an absolute path name.
        if [[ $value = ${value#/} ]]
        then
          printErrorMsg 149 $mmcmd automountDir $value
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="automountDir"
      mmfscfgChange=yes
      ;;


    #-------------------------
    "allowremoteconnections" )
    #-------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="allowRemoteConnections"
      mmfscfgChange=yes
      ;;


    #------------------------
    "allowdummyconnections" )
    #------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="allowDummyConnections"
      mmfscfgChange=yes
      ;;


    #-----------------
    "openssllibname" )
    #-----------------
      # Make the change to the work copy of the mmfs.cfg file.
      attr="openssllibname"
      mmfscfgChange=yes
      ;;


    #-------------
    "cipherlist" )  # Documented attribute
    #-------------
      [[ $value = EMPTY ]] && value=DEFAULT

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      if [[ $value != DEFAULT ]]
      then
        # Ensure OpenSSL is installed.
        if [[ ! -x $openssl ]]
        then
          print -u2 "$mmcmd: $openssl not found."
          print -u2 "     Ensure the OpenSSL code is properly installed."
          cleanupAndExit
        fi

        # Replace any colons in the cipher list string with commas.
        cipherList=$(print -- "$value" | $sed 's/:/,/g')

        # Ensure the version of openssl installed on this node
        # understands cipherList before setting it.
        if [[ $cipherList = "AUTHONLY" ]]
        then
          ciphers=$($openssl ciphers "NULL-SHA")
        elif [[ $cipherList = *"AUTHONLY"* ]]
        then
          print -u2 "$mmcmd:  AUTHONLY cannot be specified in conjunction with other ciphers."
        else
          ciphers=$($openssl ciphers rsa "$cipherList")
        fi

        if [[ $cipherList != "AUTHONLY" && $sdrfsFormatLevel -eq 0 ]]
        then
          print -u2 "$mmcmd:  Support for cipher lists other than AUTHONLY has not been enabled yet."
          print -u2 "    Run \"mmchconfig release=LATEST\" to activate the new function."
          cleanupAndExit
        fi

        if [[ -z "$ciphers" ]]
        then
          # The specified cipher list is not supported.
          printErrorMsg 483 $mmcmd "$value"
          cleanupAndExit
        else
          :  # The new cipher list is acceptable.
        fi  # end of if [[ -z "$ciphers" ]]

        secLevel=1

      else
        cipherList=""
        secLevel=0
      fi  # end of if [[ $value != DEFAULT ]]

      # Make the change in the working copy of the mmsdrfs file.
      # Return the genkey generation number.
      keyGenNumber=$($awk -F:  '                                                  \
         /^'$GLOBAL_ID:$VERSION_LINE:'/ {                                         \
            # If this is the version line, update the SECLEVEL field.             \
            { $'$SECLEVEL_Field' = "'$secLevel'" }                                \
            { 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":" >> "'$tmpsdrfs'" } \
            # Return the current value of the genkey generation number.           \
            { print $'$NEW_KEY_Field' }                                           \
            { next }                                                              \
         }                                                                        \
         /^'$HOME_CLUSTER:$NODESET_HDR:'/ {                                       \
            # If this is the header line, update the cipher list field.           \
            { $'$CIPHER_LIST_Field' = "'$cipherList'" }                           \
            { 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":" >> "'$tmpsdrfs'" } \
            { next }                                                              \
         }                                                                        \
         # All other lines are echoed without change.                             \
         { print $0 >> "'$tmpsdrfs'" }                                            \
      ' $newsdrfs)
      checkForErrors awk $?

      # Ensure that an authentication key file exists.
      if [[ $keyGenNumber -eq 0 && $secLevel -gt 0 ]]
      then
        # Run "mmauth genkey" first.
        printErrorMsg 307 $mmcmd
        cleanupAndExit
      fi

      # The file was updated successfully.
      $mv $tmpsdrfs $newsdrfs
      checkForErrors "mv $tmpsdrfs $newsdrfs" $?
      mmsdrfsModified=yes

      # The daemon must be down on all nodes if the multiple keys support
      # has not been activated yet or if we are about to switch from
      # a non-secure to a secure environment or vice-versa.
      if [[ $sdrfsFormatLevel -eq 0 || $currentCipherList != $value &&
            ( $currentCipherList = DEFAULT || $value = DEFAULT ) ]]
      then
        if [[ -z $daemonInactiveVerified ]]
        then
          printInfoMsg 339
          verifyDaemonInactive $allnodes $mmcmd
          [[ $? -ne 0 ]] && cleanupAndExit
          daemonInactiveVerified=yes
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="cipherList"
      mmfscfgChange=yes
      ;;


    #----------------------
    "maxreceiverthreads" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxReceiverThreads $value 1 128)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxReceiverThreads"
      mmfscfgChange=yes
      ;;


    #--------------------
    "dmapieventtimeout" )  # Documented attribute
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange dmapiEventTimeout $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 86400000 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dmapiEventTimeout"
      mmfscfgChange=yes
      ;;


    #-----------------------------
    "dmapisessionfailuretimeout" )  # Documented attribute
    #-----------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange dmapiSessionFailureTimeout $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 0 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dmapiSessionFailureTimeout"
      mmfscfgChange=yes
      ;;


    #--------------------
    "dmapimounttimeout" )  # Documented attribute
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange dmapiMountTimeout $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 60 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dmapiMountTimeout"
      mmfscfgChange=yes
      ;;


    #------------------
    "tiebreakerdisks" )        # Documented attribute
    #------------------
      if [[ "$value" = *+([-:${BLANKchar}${TABchar}])* ]]
      then
        # Use semi-colon (;) to separate the disk names.
        printErrorMsg 62 $mmcmd
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Daemon must be down when changing quorum semantics.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # If going back to regular node quorum, nothing special to do.
      # If switching to disk-based quorum, or if changing the set
      # of quorum disks, call the setDiskQuorum routine to
      # prepare the disks.
      if [[ $value != no && $value != DEFAULT ]]
      then
        setDiskQuorum "$value" $newsdrfs
        rc=$?
        if [[ $rc -ne 0 ]]
        then
          # Command failed.
          printErrorMsg 389 $mmcmd
          cleanupAndExit $rc
        fi
      fi  # end of if [[ $value != no && $value != DEFAULT ]]

      # Make the change to the work copy of the mmfs.cfg file.
      attr="tiebreakerDisks"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;


    #------------------
    "minquorumnodes" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange minQuorumNodes $value 1 5)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="minQuorumNodes"
      mmfscfgChange=yes
      ;;


    #--------------
    "designation" )  # Documented attribute
    #--------------
      # The detailed syntax check is done in function changeNodeDesignation.
      if [[ "$value" = *+([;:${BLANKchar}${TABchar}])* ]]
      then
        # Use the dash character to separate multiple node designations.
        printErrorMsg 61 $mmcmd
        cleanupAndExit
      fi
      [[ $value = DEFAULT ]] && value=quorum-client

      # Ensure there will be at least one quorum node in the cluster.
      if [[ $value = *nonquorum* && -z "$arglist" ]]
      then
        printErrorMsg 53 $mmcmd
        cleanupAndExit
      fi

      # Make the change in the MEMBER_NODE lines.
      if [[ -z "$arglist" ]]
      then
        changeNodeDesignation "$value" $newsdrfs
        rc=$?
      else
        changeNodeDesignation "$value" $newsdrfs $nodefile
        rc=$?
      fi
      [[ $rc -ne 0 ]] && cleanupAndExit
      mmsdrfsModified=yes
      [[ $propagateOptions != *rereadNodeList* ]] &&  \
        propagateOptions=rereadNodeList,${propagateOptions}
      ;;


    #-----------
    "autoload" )   # Documented attribute
    #-----------
      # Check the new attribute value.
      [[ $value = DEFAULT ]] && value=no
      if [[ $value != yes && $value != no ]]
      then
        printErrorMsg 37 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="autoload"
      mmfscfgChange=yes
      ;;


    #---------------
    "maxblocksize" )   # Documented attribute
    #---------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxblocksize $value 16K 16M)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxblocksize"
      mmfscfgChange=yes
      ;;


    #-----------------
    "updatedisktype" )     # Documented attribute
    #-----------------
      [[ $value = DEFAULT ]] && value=all
      if [[ $value != "all" && $value != "yes" && $value != /* ]]
      then
        # Incorrect value for this option.
        printErrorMsg 153 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Reevaluate the disk type for all disks in the cluster.
      updateDiskType $value $newsdrfs
      rc=$?
      [[ $rc -ne 0 ]] && cleanupAndExit
      mmsdrfsModified=yes
      ;;


    #-------------
    "pindaemon"  )
    #-------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="pindaemon"
      mmfscfgChange=yes
      ;;


    #-------------------------
    "tcpport" | "tsctcpport" )
    #-------------------------
      # Convert attribute value into a simple integer.
      [[ $value = DEFAULT ]] && value=$defaultTcpPort
      intValue=$(checkIntRange tscTcpPort $value)
      [[ $? -ne 0 ]] && cleanupAndExit

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Find and parse the NODESET_HDR line.
      sdrfsLine=$($grep -e "^$nodesetId:$NODESET_HDR::" $newsdrfs)
      IFS=":"
      set -f ; set -A v -- - $sdrfsLine ; set +f
      IFS="$IFS_sv"

      # Set the new value and put the line back
      v[$TCP_PORT_Field]=$value
      newLine=$(print_newLine)
      newGenNumber=$(updateSdrfsFile $newsdrfs "$nodesetId:$NODESET_HDR::" $newLine)
      checkForErrors "updateSdrfsFile $newsdrfs" $?

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="tscTcpPort"
      mmfscfgChange=yes
      ;;


    #-------------------------------------------
    "gpfseventsport" | "eventsexportertcpport" )
    #-------------------------------------------
      if [[ $value = DEFAULT ]]
      then
        # The default is the value of tscTcpPort, whatever it happens to be.
        # This is reflected by storing null in the mmsdrfs file.
        value=""
      else
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange eventsExporterTcpPort $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change in the working copy of the mmsdrfs file.
      $awk -F:  '                                                                 \
         # If this is the NODESET_HDR line, update the EVENTS_PORT_Field.         \
         /^'$HOME_CLUSTER:$NODESET_HDR:'/ {                                       \
            { $'$EVENTS_PORT_Field' = "'$value'" }                                \
            { 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":" >> "'$tmpsdrfs'" } \
            { next }                                                              \
         }                                                                        \
         # All other lines are echoed without change.                             \
         { print $0 >> "'$tmpsdrfs'" }                                            \
      ' $newsdrfs
      checkForErrors awk $?

      # The file was updated successfully.
      $mv $tmpsdrfs $newsdrfs
      checkForErrors "mv $tmpsdrfs $newsdrfs" $?
      mmsdrfsModified=yes

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      [[ -z $value ]] && value=DEFAULT
      attr="eventsExporterTcpPort"
      mmfscfgChange=yes
      ;;


    #-------------------------------------
    "gpfsobjectport" | "mmgetobjdport" | \
    "mmsdrservport" | "mmsdrservtcpport" )
    #-------------------------------------
      if [[ $value = DEFAULT ]]
      then
        # The default is the value of tscTcpPort, whatever it happens to be.
        # This is reflected by storing null in the mmsdrfs file.  Note that
        # zero is an acceptable value - it means that mmsdrserv should not
        # be used at all.
        value=""
      else
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange mmsdrservTcpPort $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change in the working copy of the mmsdrfs file.
      # The script will also determine if it is necessary to ensure
      # that GPFS is not running on the config server nodes.
      daemonMustBeDown=$($awk -F:  '                                              \
         /^'$HOME_CLUSTER:$NODESET_HDR:'/ {                                       \
            { daemonPort = $'$TCP_PORT_Field' }                                   \
            { oldSdrPort = $'$GETOBJECT_PORT_Field' }                             \
            { newSdrPort = "'$value'" }                                           \
            # Decide if the daemon must be down.                                  \
            if ( oldSdrPort == "" || oldSdrPort == daemonPort ||                  \
                 newSdrPort == "" || newSdrPort == daemonPort ) {                 \
              { print "yes" }                                                     \
            }                                                                     \
            # Update the GETOBJECT_PORT_Field with its new value.                 \
            { $'$GETOBJECT_PORT_Field' = "'$value'" }                             \
            { 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":" >> "'$tmpsdrfs'" } \
            { next }                                                              \
         }                                                                        \
         # All other lines are echoed without change.                             \
         { print $0 >> "'$tmpsdrfs'" }                                            \
      ' $newsdrfs)
      checkForErrors awk $?

      # The file was updated successfully.
      $mv $tmpsdrfs $newsdrfs
      checkForErrors "mv $tmpsdrfs $newsdrfs" $?
      mmsdrfsModified=yes

      # Since we are changing the TCP port number, the currently running
      # mmsdrserv daemons must be killed before the new instances can be
      # started.  This is done as part of the commit process.
      commitOption=KILLSDRSERV

      # Depending on the old and new values of the sdrserv port,
      # it may be necessary to shutdown GPFS on the primary and
      # backup server for the change to be accomplished.  If this
      # is not done, the config servers may be left over returning
      # stale information or mmsdrserv requests may fail because
      # an already running daemon cannot take over sdrserv duties.
      if [[ -n $daemonMustBeDown && -z $daemonInactiveVerified ]]
      then
        print -- "${primaryServer}\n${backupServer}" > $tmpNodes
        checkForErrors "writing to file $tmpNodes" $?

        # Verify the daemon is down; do not lock the Gpfs object.
        printInfoMsg 453
        verifyDaemonInactive $tmpNodes
        [[ $? -ne 0 ]] && cleanupAndExit
      fi  # end of if [[ -n $daemonMustBeDown ]]
      ;;


    #-------------------
    "mmsdrservtimeout" )
    #-------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange mmsdrservTimeout $value 1 3600)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="mmsdrservTimeout"
      mmfscfgChange=yes
      ;;


    #----------------------
    "mmsdrservworkerpool" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange mmsdrservWorkerPool $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="mmsdrservWorkerPool"
      mmfscfgChange=yes
      ;;


    #-----------
    "priority" )
    #-----------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange priority $value 1 99)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ $value = DEFAULT ]]
      then
        tsctlParms="$tsctlParms $attr 40 "
      else
        tsctlParms="$tsctlParms $attr $value "
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="priority"
      mmfscfgChange=yes
      ;;


    #----------------------
    "maxdatashippoolsize" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxDataShipPoolSize $value 32K 1M)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxDataShipPoolSize"
      mmfscfgChange=yes
      ;;


    #--------------
    "dmapienable" )
    #--------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dmapiEnable"
      mmfscfgChange=yes
      ;;


    #---------------------
    "dmapiworkerthreads" )
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange dmapiWorkerThreads $value 1 24)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dmapiWorkerThreads"
      mmfscfgChange=yes
      ;;


    #--------------------
    "dmapieventbuffers" )
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange dmapiEventBuffers $value 1 128)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dmapiEventBuffers"
      mmfscfgChange=yes
      ;;


    #-------------
    "tscprimary" )
    #-------------
      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="tscPrimary"
      mmfscfgChange=yes
      ;;


    #--------------
    "clustertype" )
    #--------------
      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="clusterType"
      mmfscfgChange=yes
      ;;


    #--------------
    "clustername" )
    #--------------
      # Note:  This value should be changed via mmchcluster -C only.

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="clusterName"
      mmfscfgChange=yes
      ;;


    #------------
    "clusterid" )
    #------------
      # Note:  This value should not be changed.

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="clusterID"
      mmfscfgChange=yes
      ;;


    #--------------------
    "autosgloadbalance" )
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr no "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="autoSgLoadBalance"
      mmfscfgChange=yes
      ;;


    #----------------
    "tscworkerpool" )
    #----------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange tscWorkerPool $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="tscWorkerPool"
      mmfscfgChange=yes
      ;;


    #----------------------
    "socketrcvbuffersize" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange socketRcvBufferSize $value 0)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="socketRcvBufferSize"
      mmfscfgChange=yes
      ;;


    #----------------------
    "socketsndbuffersize" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange socketSndBufferSize $value 0)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="socketSndBufferSize"
      mmfscfgChange=yes
      ;;


    #-----------------------
    "writealldescreplicas" )
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="writeAllDescReplicas"
      mmfscfgChange=yes
      ;;


    #---------------------------
    "waitforvsd" | "wait4rvsd" )
    #---------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="wait4RVSD"
      mmfscfgChange=yes
      ;;


    #---------------
    "usedisklease" )
    #---------------
      # Check the new attribute value.
      [[ $value = DEFAULT ]] && value=yes
      if [[ $value != yes && $value != no ]]
      then
        printErrorMsg 37 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate && $value = no ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # When turning off useDiskLease, the daemon must be down on all nodes.
      if [[ $value = no && -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # If needed, set parameters for the tsctl command.
      [[ -n $immediate ]] &&  \
        tsctlParms_onactive="$tsctlParms_onactive $attr $value "

      # Make the change to the work copy of the mmfs.cfg file.
      attr="useDiskLease"
      mmfscfgChange=yes
      ;;


    #----------------
    "leaseduration" )
    #----------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange leaseDuration $value 5 1800)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="leaseDuration"
      mmfscfgChange=yes
      ;;


    #--------------------
    "leaserecoverywait" )
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange leaseRecoveryWait $value 1 1800)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="leaseRecoveryWait"
      mmfscfgChange=yes
      ;;


    #------------------
    "leasedmstimeout" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange leaseDMSTimeout $value 0 1800)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="leaseDMSTimeout"
      mmfscfgChange=yes
      ;;


    #------------
    "pingperiod" )
    #------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange pingPeriod $value 1 10)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="pingPeriod"
      mmfscfgChange=yes
      ;;


    #-------------------
    "totalpingtimeout" )
    #-------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange totalPingTimeout $value 1 1800)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="totalPingTimeout"
      mmfscfgChange=yes
      ;;


    #-----------------------
    "minmissedpingtimeout" )
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange minMissedPingTimeout $value 1 300)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="minMissedPingTimeout"
      mmfscfgChange=yes
      ;;


    #-----------------------
    "maxmissedpingtimeout" )
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxMissedPingTimeout $value 1 300)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxMissedPingTimeout"
      mmfscfgChange=yes
      ;;


    #-----------------------
    "sendtimeout" )
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange sendTimeout $value 1 300)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="sendTimeout"
      mmfscfgChange=yes
      ;;


    #------------------
    "prefetchtimeout" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange prefetchTimeout $value 2 30)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 5 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="prefetchTimeout"
      mmfscfgChange=yes
      ;;


    #------------------
    "prefetchthreads" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange prefetchThreads $value 2 550)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="prefetchThreads"
      mmfscfgChange=yes
      ;;


    #--------------
    "prefetchpct" )
    #--------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange prefetchPct $value 0 60)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="prefetchPct"
      mmfscfgChange=yes
      ;;


    #-------------
    "hotlistpct" )
    #-------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange hotlistPct $value 0 60)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="hotlistPct"
      mmfscfgChange=yes
      ;;


    #-----------------
    "worker1threads" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange worker1Threads $value 1 550)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="worker1Threads"
      mmfscfgChange=yes
      ;;


    #-----------------
    "worker3threads" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange worker3Threads $value 1 64)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="worker3Threads"
      mmfscfgChange=yes
      ;;


    #----------
    "maxmbps" )
    #----------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxMBpS $value 1 100000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 150 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxMBpS"
      mmfscfgChange=yes
      ;;


    #------------------
    "takeovertimeout" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange takeovertimeout $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 600 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="takeovertimeout"
      mmfscfgChange=yes
      ;;


    #------------------------
    "pcttokenmgrstorageuse" )
    #------------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange pctTokenMgrStorageUse $value 1 90)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 25 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="pctTokenMgrStorageUse"
      mmfscfgChange=yes
      ;;


    #----------------------------------------
    "unmountondiskfail" | "panicondiskfail" )    # Documented attribute
    #----------------------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no && $value != meta ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr no "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="unmountOnDiskFail"
      mmfscfgChange=yes
      ;;


    #------------
    "crashdump" )
    #------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange crashdump $value 0 1)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 0 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="crashdump"
      mmfscfgChange=yes
      ;;


    #-------------------------
    "assertonstructureerror" )
    #-------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr no "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="assertOnStructureError"
      mmfscfgChange=yes
      ;;


    #--------
    "trace" )
    #--------
      # If requested, change the trace levels on the running daemon.
      if [[ -n $immediate && -s $nodefile ]]
      then
        if [[ $value = DEFAULT ]]
        then
          $mmcommon onall $nodefile $unreachedNodes  \
                             adminCmd mmfsadm trace "all 0"
        else
          $mmcommon onall $nodefile $unreachedNodes  \
                             adminCmd mmfsadm trace "$value"
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="trace"
      mmfscfgChange=yes
      ;;


    #------
    "res" )            # Resource tracking options
    #------
      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="res"
      mmfscfgChange=yes
      ;;


    #---------------------
    "asyncsocketnotify"  )
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="asyncSocketNotify"
      mmfscfgChange=yes
      ;;


    #------------
    "pinmaster" )
    #------------
      # value must have the following format: "stack:256K data:4096K"
      # The range for stack is 64K to 4M
      # The range for data is 64K to 128M

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="pinmaster"
      mmfscfgChange=yes
      ;;


    #-------------------------
    "maxinodedeallochistory" )
    #-------------------------
      # The range for maxInodeDeallocPrefetch is 0 to maxFilesToCache

      # Convert attribute value into a simple integer.
      if [[ $value != DEFAULT ]]
      then
        intValue=$(checkIntRange maxInodeDeallocHistory $value 1 100000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxInodeDeallocHistory"
      mmfscfgChange=yes
      ;;


    #--------------------------
    "maxinodedeallocprefetch" )
    #--------------------------
      # The range for maxInodeDeallocPrefetch is
      #   0 to min(maxInodeDeallocHistory, 16)

      # Convert attribute value into a simple integer.
      if [[ $value != DEFAULT ]]
      then
        intValue=$(checkIntRange maxInodeDeallocPrefetch $value 1 16)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 8 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxInodeDeallocPrefetch"
      mmfscfgChange=yes
      ;;


    #-------------
    "mmapkprocs" )
    #-------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange mmapKprocs $value 0 10000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 3 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="mmapKprocs"
      mmfscfgChange=yes
      ;;


    #------------------------
    "maxfcntlrangesperfile" )
    #------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxFcntlRangesPerFile $value 10 200000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 200 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxFcntlRangesPerFile"
      mmfscfgChange=yes
      ;;


    #-------------------------------
    "allowsynchronousfcntlretries" )
    #-------------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr yes "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="allowSynchronousFcntlRetries"
      mmfscfgChange=yes
      ;;


    #---------------------------
    "retryfcntltokenthreshold" )
    #---------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange retryFcntlTokenThreshold $value 0 1000)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 200 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="retryFcntlTokenThreshold"
      mmfscfgChange=yes
      ;;


    #---------------------
    "eewatchdoginterval" )
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange eeWatchDogInterval $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 90 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="eeWatchDogInterval"
      mmfscfgChange=yes
      ;;


    #-----------------------------
    "eewatchdoghungthreadcutoff" )
    #-----------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange eeWatchDogHungThreadCutoff $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 60 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="eeWatchDogHungThreadCutoff"
      mmfscfgChange=yes
      ;;


    #------------------
    "watchdogtimeout" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange watchdogtimeout $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 20 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="watchdogtimeout"
      mmfscfgChange=yes
      ;;


    #--------------
    "nsdbufspace" )
    #--------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdbufspace $value 10 70)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 30 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdbufspace"
      mmfscfgChange=yes
      ;;


    #--------------------
    "nsdthreadsperdisk" )
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdThreadsPerDisk $value 1 128)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdThreadsPerDisk"
      mmfscfgChange=yes
      ;;


    #----------------------
    "nsdminworkerthreads" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdMinWorkerThreads $value 1 128)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdMinWorkerThreads"
      mmfscfgChange=yes
      ;;


    #----------------------
    "nsdmaxworkerthreads" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdMaxWorkerThreads $value 1 128)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdMaxWorkerThreads"
      mmfscfgChange=yes
      ;;


    #------------------------------------
    "nsdservercheckingintervalformount" )
    #------------------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdServerCheckingIntervalForMount $value 1 60)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 10 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdServerCheckingIntervalForMount"
      mmfscfgChange=yes
      ;;


    #----------------------------
    "nsdserverwaitconfig" )
    #----------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdServerWaitConfig $value 0 2)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 2 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdServerWaitConfig"
      mmfscfgChange=yes
      ;;


    #----------------------------
    "nsdserverwaittimeformount" )
    #----------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdServerWaitTimeForMount $value 0 1200)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 300 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdServerWaitTimeForMount"
      mmfscfgChange=yes
      ;;


    #---------------------------------
    "nsdserverwaittimewindowonmount" )
    #---------------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nsdServerWaitTimeWindowOnMount $value 1 1200)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 600 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nsdServerWaitTimeWindowOnMount"
      mmfscfgChange=yes
      ;;


    #--------------------
    "readreplicapolicy" )
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        if [[ $value != "local" && $value != "fastest" && $value != "default" ]]
        then
          # Incorrect value for this option.
          printErrorMsg 153 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        tsctlParms="$tsctlParms $attr $value "
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="readReplicaPolicy"
      mmfscfgChange=yes
      ;;


    #---------------
    "addnodestate" )
    #---------------
      if [[ $value != "new" && $value != "old" ]]
      then
        # Invalid node designation specified
        printErrorMsg 293 $mmcmd $value
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change in the MEMBER_NODE lines.
      if [[ -z "$arglist" ]]
      then
        changeAddNodeState $value $newsdrfs
        rc=$?
      else
        changeAddNodeState $value $newsdrfs $nodefile $allnodes
        rc=$?
      fi
      [[ $rc -ne 0 ]] && cleanupAndExit
      mmsdrfsModified=yes
      synchronousNotify=yes
      [[ $propagateOptions != *rereadNodeList* ]] &&  \
        propagateOptions=rereadNodeList,${propagateOptions}

      # No other attributes can be processed after addNodeState
      break
      ;;


    #----------
    "release" )    # Documented attribute
    #----------
      [[ $value = DEFAULT ]] && value=LATEST
      if [[ $value != "LATEST" && $value != "latest" ]]
      then
        # An invalid value was specified.
        printErrorMsg 13 "$mmcmd" "$attributePair"
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the appropriate preliminary changes.
      convertMmsdrfsFile $newsdrfs
      rc=$?
      [[ $rc -ne 0 ]] && cleanupAndExit
      mmsdrfsModified=yes
      ;;


    #-------------------
    "release_disabled" )    # Disable the code that handles release level determination.
    #-------------------
      [[ $value = DEFAULT ]] && value=LATEST
      if [[ $value != "LATEST" && $value != "latest" &&
            $value != +([0-9]).+([0-9]).+([0-9]).+([0-9]) ]]
      then
        n=$(checkIntRange DaemonVersion $value)
        if [[ $? -ne 0 ]]
        then
          # Invalid value specified
          printErrorMsg 13 "$mmcmd" "$attributePair"
          cleanupAndExit
        fi
      fi

      # -I (immediate only) option not allowed
      if [[ $immediate = "-I" ]]
      then
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      if [[ $value = "LATEST" || $value = "latest" ]]
      then
        # Make the appropriate preliminary changes.
        convertMmsdrfsFile $newsdrfs
        rc=$?
        [[ $rc -ne 0 ]] && cleanupAndExit
        mmsdrfsModified=yes

      else
        # The request is to set the version to a specific level.
        # This requires the daemon to be stopped everywhere.
        if [[ -n "$arglist" ]]
        then
          # <nodelist> cannot be used.
          printErrorMsg 192 $mmcmd $attr
          cleanupAndExit
        fi

        # The daemon must be down on all nodes in the cluster.
        if [[ -z $daemonInactiveVerified ]]
        then
          printInfoMsg 339
          verifyDaemonInactive $allnodes $mmcmd
          [[ $? -ne 0 ]] && cleanupAndExit
          daemonInactiveVerified=yes
        fi
      fi  # end if [[ $value = "LATEST" || $value = "latest" ]]

      # Verify that the NODESET_HDR version fields are up-to-date.
      result=$(setNodesetVersionFields $value $nodefile $newsdrfs)
      IFS=':'
      set -f ; set -- $result ; set +f
      IFS="$IFS_sv"
      rc=$2
      status=$3
      maxFeatureLevelAllowed=$4

      # If the daemon version has changed, make the appropriate
      # changes to mmfs.cfg.
      if [[ $status = changed ]]
      then
        # If upgrading the version level, the immediate option is implied.
        [[ $value = "LATEST" || $value = "latest" ]] &&  \
          immediate="-i";

        # If needed, set parameters for the tsctl command.
        [[ -n $immediate ]] &&  \
          tsctlParms_onactive="$tsctlParms_onactive $attr $value "

        # Make the change to the work copy of the mmfs.cfg file.
        value=$maxFeatureLevelAllowed
        attr="maxFeatureLevelAllowed"
        mmfscfgChange=yes
        ignoreNodeList=yes
      fi
      ;;


    #-------------------------
    "maxfeaturelevelallowed" )
    #-------------------------
      n=$(checkIntRange maxFeatureLevelAllowed $value 0 100000)
      [[ $? -ne 0 ]] && cleanupAndExit

      # If needed, set parameters for the tsctl command.
      [[ -n $immediate ]] &&  \
        tsctlParms_onactive="$tsctlParms_onactive $attr $value "

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxFeatureLevelAllowed"
      mmfscfgChange=yes
      ;;


    #------------------------
    "writebehindthreshhold" )
    #------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange writebehindThreshhold $value 0 )
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 512K "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="writebehindThreshhold"
      mmfscfgChange=yes
      ;;


    #-----------------------
    "seqdiscardthreshhold" )
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange seqDiscardThreshhold $value 0 )
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 1M "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="seqDiscardThreshhold"
      mmfscfgChange=yes
      ;;


    #---------------
    "syncinterval" )
    #---------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange syncInterval $value 0 3600)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          if [[ $osName = Linux ]]
          then
            tsctlParms="$tsctlParms $attr 30 "
          else
            tsctlParms="$tsctlParms $attr 70 "
          fi
        else
          tsctlParms="$tsctlParms $attr $value "
        fi  # end if [[ $value = DEFAULT ]]
      fi  # end if [[ -n $immediate ]]

      # Make the change to the work copy of the mmfs.cfg file.
      attr="syncInterval"
      mmfscfgChange=yes
      ;;


    #----------------
    "iohistorysize" )
    #----------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange ioHistorySize $value 32 32768)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 512 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="ioHistorySize"
      mmfscfgChange=yes
      ;;


    #------------------
    "maxfilecleaners" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxfilecleaners $value 0 32)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 8 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxFileCleaners"
      mmfscfgChange=yes
      ;;


    #--------------------
    "flusheddatatarget" )
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange flushedDataTarget $value 0 256)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 32 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="flushedDataTarget"
      mmfscfgChange=yes
      ;;


    #---------------------
    "flushedinodetarget" )
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange flushedInodeTarget $value 0 256)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 32 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="flushedInodeTarget"
      mmfscfgChange=yes
      ;;


    #-----------------
    "sharedmemlimit" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange sharedMemLimit $value 0 2047M)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="sharedMemLimit"
      mmfscfgChange=yes
      ;;

    #-----------------
    "tokenmemlimit" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange tokenMemLimit $value 0 2047M)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="tokenMemLimit"
      mmfscfgChange=yes
      ;;

    #-------------------------------
    "maxbackgrounddeletionthreads" )
    #-------------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxBackgroundDeletionThreads $value 0 8)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 4 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxBackgroundDeletionThreads"
      mmfscfgChange=yes
      ;;


    #--------------------------
    "maxnfsdelegationtimeout" )
    #--------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxNFSDelegationTimeout $value 3 3600)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 60 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxNFSDelegationTimeout"
      mmfscfgChange=yes
      ;;

    #----------------------
    "nfsprefetchstrategy" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange nfsPrefetchStrategy $value 0 10)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 0 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nfsPrefetchStrategy"
      mmfscfgChange=yes
      ;;


    #-----------------
    "enablenfscluster" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="enableNFSCluster"
      mmfscfgChange=yes
      ;;

    #-----------------
    "enableuidremap" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="enableUIDremap"
      mmfscfgChange=yes
      ;;


    #---------------------
    "enablestatuidremap" )
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="enableStatUIDremap"
      mmfscfgChange=yes
      ;;

    #----------------
    "uidexpiration" )
    #----------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange uidExpiration $value)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="uidExpiration"
      mmfscfgChange=yes
      ;;

    #---------------------
    "maxallocpcttocache" )
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxAllocPctToCache $value 0 100)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 0 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxAllocPctToCache"
      mmfscfgChange=yes
      ;;


    #---------------------------
    "ignorereplicaspaceonstat" )
    #---------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr no "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="IgnoreReplicaSpaceOnStat"
      mmfscfgChange=yes
      ;;


    #------------------------
    "enabletreebasedquotas" )
    #------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # The daemon must be down on all nodes in the cluster.
      if [[ -z $daemonInactiveVerified ]]
      then
        printInfoMsg 339
        verifyDaemonInactive $allnodes $mmcmd
        [[ $? -ne 0 ]] && cleanupAndExit
        daemonInactiveVerified=yes
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="enableTreeBasedQuotas"
      mmfscfgChange=yes
      ;;


    #----------
    "license" )
    #----------
      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="LICENSE"
      mmfscfgChange=yes
      ;;


    #-------------------------
    "listenonallinterfaces"  )
    #-------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="listenOnAllInterfaces"
      mmfscfgChange=yes
      ;;


    #----------
    "subnets" )
    #----------
      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="subnets"
      mmfscfgChange=yes
      ;;


    #---------------------
    "maxsgdesciobufsize" )   # Undocumented attribute
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        # Convert attribute value into a simple integer.
        intValue=$(checkIntRange maxSGDescIOBufSize $value 262144 2097152)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxSGDescIOBufSize"
      mmfscfgChange=yes
      ;;


    #-------------------------
    "distributedtokenserver" )
    #-------------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr yes "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="distributedTokenServer"
      mmfscfgChange=yes
      ;;


    #------------------------
    "multitmmountthreshold" )
    #------------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange multiTMMountThreshold $value 1 4096)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 2 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="multiTMMountThreshold"
      mmfscfgChange=yes
      ;;


    #------------------
    "maxtokenservers" )
    #------------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange maxTokenServers $value 1 256)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 128 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxTokenServers"
      mmfscfgChange=yes
      ;;

    #----------------
    "healthcheckinterval" )
    #----------------
      if [[ $value != DEFAULT ]]
      then
        n=$(checkIntRange healthCheckInterval $value 10 7200)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n $immediate ]]
      then
        # -i cannot be used.
        printErrorMsg 375 $mmcmd $immediate $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="healthCheckInterval"
      mmfscfgChange=yes
      ;;

    #-----------------------
    "setctimeonattrchange" )
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr yes "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="setCtimeOnAttrChange"
      mmfscfgChange=yes
      ;;


    #-----------------
    "qrevokewatchthreshold" )
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        n=$(checkIntRange qRevokeWatchThreshold $value 0 600)
        [[ $? -ne 0 ]] && cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr 2 "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="qRevokeWatchThreshold"
      mmfscfgChange=yes
      ;;

    #----------------------
    "allowdeleteaclonchmod" )
    #----------------------
      if [[ $value != DEFAULT ]]
      then
        # Check the new attribute value.
        if [[ $value != yes && $value != no ]]
        then
          printErrorMsg 37 $mmcmd $attr
          cleanupAndExit
        fi
      fi

      # If needed, set parameters for the tsctl command.
      if [[ -n $immediate ]]
      then
        if [[ $value = DEFAULT ]]
        then
          tsctlParms="$tsctlParms $attr yes "
        else
          tsctlParms="$tsctlParms $attr $value "
        fi
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="allowDeleteAclOnChmod"
      mmfscfgChange=yes
      ;;


    ####################################################################
    # The following parameters are obsolete.  They can only be deleted.
    ####################################################################

    #-------------------------------------------
    "singlenodequorum" | "usesinglenodequorum" ) # Obsolete attribute
    #-------------------------------------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="useSingleNodeQuorum"
      mmfscfgChange=yes
      ;;

    #-------------
    "corequorum" )        # Obsolete parameter
    #-------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="coreQuorum"
      mmfscfgChange=yes
      ;;

    #-------------
    "diskquorum" )        # Obsolete parameter
    #-------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="diskQuorum"
      mmfscfgChange=yes
      ;;

    #----------------
    "comm_protocol" )  # Obsolete attribute
    #----------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="comm_protocol"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;

    #-------------
    "dynmemsize" )  # Obsolete attribute
    #-------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="dynMemSize"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;

    #--------------
    "maxpagepool" )  # Obsolete attribute
    #--------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="maxpagepool"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;

    #-------------
    "mallocsize" )  # Obsolete attribute
    #-------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="mallocsize"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;

    #-----------------------
    "memrebalanceinterval" )  # Obsolete attribute
    #-----------------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="memrebalanceinterval"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;

    #-------------------
    "importancefactor" )  # Obsolete attribute
    #-------------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="importancefactor"
      mmfscfgChange=yes
      mmsdrfsModified=yes
      ;;

    #-----------------
    "worker2threads" )      # Obsolete parameter
    #-----------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="worker2Threads"
      mmfscfgChange=yes
      ;;

    #----------------
    "usespsecurity" )          # Obsolete parameter
    #----------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="useSPSecurity"
      mmfscfgChange=yes
      ;;

    #--------------------
    "useauthentication" )      # Obsolete attribute
    #--------------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="useAuthentication"
      mmfscfgChange=yes
      ;;

    #---------------------
    "spsecworkerthreads" )     # Obsolete parameter
    #---------------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="spsecWorkerThreads"
      mmfscfgChange=yes
      ;;

    #---------
    "group"  )          # Obsolete parameter
    #---------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="group"
      mmfscfgChange=yes
      ;;

    #------------
    "recgroup"  )          # Obsolete parameter
    #------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="recgroup"
      mmfscfgChange=yes
      ;;

    #-----------
    "nodelist" )     # Obsolete parameter
    #-----------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nodelist"
      mmfscfgChange=yes
      ;;


    #------------
    "multinode" )     # Obsolete parameter
    #------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="multinode"
      mmfscfgChange=yes
      ;;


    #------------
    "nodeprefs" )     # Obsolete parameter
    #------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="nodeprefs"
      mmfscfgChange=yes
      ;;


    #-------------------
    "locktableversion" )     # Obsolete parameter
    #-------------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="lockTableVersion"
      mmfscfgChange=yes
      ;;


    #---------
    "logdir" )     # Obsolete parameter
    #---------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="logDir"
      mmfscfgChange=yes
      ;;


    #--------------
    "minpagepool" )     # Obsolete parameter
    #--------------
      if [[ $value != DEFAULT ]]
      then
        # Obsolete attribute.
        printErrorMsg 19 $mmcmd $attr
        cleanupAndExit
      fi

      if [[ -n "$arglist" ]]
      then
        # <nodelist> cannot be used.
        printErrorMsg 192 $mmcmd $attr
        cleanupAndExit
      fi

      # Make the change to the work copy of the mmfs.cfg file.
      attr="minpagepool"
      mmfscfgChange=yes
      ;;


    # End of obsolete attribute section.
    # Add new attributes above the obsolete section.

    #----
    *   )    # unknown attribute
    #----
      # Warning:  unknown attribute.  The user is asked to press the enter key
      # to bypass this argument.  If the user enters 999, we assume the guy
      # knows what he is doing and we'll put the attribute in the mmfs.cfg file.
      printErrorMsg 277 $mmcmd $attr
      read response
      [[ $response = "999" ]] && mmfscfgChange=yes
    ;;

  esac


  ###################################################################
  # If -I (Immediate ONLY) was specified, then do not
  # make any change to the work copy of the mmfs.cfg file.
  ###################################################################
  if [[ -n $immediateOnly ]]
  then
    mmfscfgChange=no
    mmsdrfsModified=no
    mmfscfgModified=no
    synchronousNotify=no
  fi

  ###################################################################
  # Make the change to the work copy of the mmfs.cfg file.
  ###################################################################
  if [[ $mmfscfgChange = yes ]]
  then
    if [[ -n $ignoreNodeList ]]
    then
      $mmfixcfg "$attr" "$value" <$tmpcfgFile >$newcfg
    else
      $mmfixcfg "$attr" "$value" $argcust <$tmpcfgFile >$newcfg
    fi
    checkForMmfixcfgErrors "$attr" $?
    mmfscfgModified=yes

    # Get ready for the next attribute.
    $cp $newcfg $tmpcfgFile
    checkForErrors "cp $newcfg $tmpcfgFile" $?
    mmfscfgChange=no
  fi   #  end of if [[ $mmfscfgChange = yes ]]

done  # end of main loop


# Remove any back-to-back or unnecessary occurrences of [common]
# and/or [node] headers that were created by mmfixcfg.
$rm -f $tmpfile
awk '                                                            \
  BEGIN {   # Initialize state variables.                        \
    { headerFound = 0 }                                          \
    { oldHeader = null }                                         \
  }                                                              \
  # Process any [common] or [node] header lines.                 \
  # If a header line is encountered, we save it until we         \
  # encounter an attribute line, since we may encounter          \
  # multiple headers before encountering an attribute.           \
  # If a header is immediately followed by a header,             \
  # the 1st header is dropped and the 2nd header is saved.       \
  # If a new header is encountered and it matches the            \
  # last header that was output, it is not printed.              \
  # When an attribute line is encountered immediately after      \
  # a header, the header and the attribute are printed,          \
  # provided the header is different than the header in effect.  \
  #                                                              \
  /^\[/ {   # A header line was encountered.  Remember it.       \
    { headerFound = 1 }                                          \
    { newHeader = $0 }                                           \
    { next }                                                     \
  }                                                              \
  {  # A non-header line was encountered.  Do the right thing.   \
    if ( headerFound == 1 ) {                                    \
      if ( newHeader != oldHeader ) {                            \
        { print newHeader >> "'$tmpfile'" }                      \
        { oldHeader = newHeader }                                \
      }                                                          \
      { print $0 >> "'$tmpfile'" }                               \
      { headerFound = 0 }                                        \
    } else {                                                     \
      { print $0 >> "'$tmpfile'" }                               \
    }                                                            \
  }                                                              \
  END { }                                                        \
 ' $newcfg
checkForErrors awk $?

# Use the modified version of the file as the new config file.
$mv $tmpfile $newcfg

# See if the config file changed as a result of the awk script above.
# Note that it is not necessary to do this if we know that the file
# has changed as a result of changing a mmfs.cfg attribute.
if [[ $mmfscfgModified = no ]]
then
  $diff $oldcfgFile $newcfg >/dev/null 2>/dev/null
  [[ $? -eq 1 ]] && mmfscfgModified=yes
fi


##########################################################
# Put the new mmfs.cfg information in the mmsdrfs file.
##########################################################
if [[ $mmfscfgModified = yes || $mmsdrfsModified = yes ]]
then
  # Add the new version of the mmfs.cfg file.  If there were no changes to
  # parameters that reside in mmfs.cfg, newcfg is the same as oldcfgFile.
  appendCfgFile $nodesetId $newcfg $newsdrfs
  checkForErrors "appendCfgFile" $?

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

  mmsdrfsModified=yes
  mmfscfgModified=no
fi


##########################################################
# Put the new mmsdrfs file into the sdr.
# This function also updates all local system files.
##########################################################
trap "" HUP INT QUIT KILL

if [[ $mmfscfgModified = yes || $mmsdrfsModified = yes ]]
then
  gpfsObjectInfo=$(commitChanges  \
     $nodesetId $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer $commitOption)
  rc=$?

else
  # Nothing changed.  The user entered an unknown attribute
  # and bailed out, or maybe it was an immediateOnly command.
  rc=0
fi

if [[ $rc -ne 0 ]]
then
  # The commit step failed.
  printErrorMsg 381 $mmcmd
  cleanupAndExit
else
  # Command was successful.
  if [[ $mmfscfgModified = yes || $mmsdrfsModified = yes ]]
  then
    # Generic success message
    printErrorMsg 272 $mmcmd

  elif [[ -n $immediateOnly ]]
  then
    : # Nothing done yet, left for immediate execution

  else
    # Nothing was changed.
    printErrorMsg 323 $mmcmd
    cleanupAndExit 0
  fi
fi

# If necessary, update the rest of the nodes while still holding
# the sdr lock.  This is needed for the changeNodeState request.
if [[ $synchronousNotify = yes ]]
then
  $mmTRACE "synchronous notify starts"
  if [[ -s $allnodes ]]
  then
    propagateSdrfsFile sync $allnodes $newsdrfs $newGenNumber $propagateOptions
    rc=$?
  elif [[ -s $nodefile ]]
  then
    propagateSdrfsFile sync $nodefile $newsdrfs $newGenNumber $propagateOptions
    rc=$?
  else
    : # nothing to update
  fi
  $mmTRACE "synchronous notify ends rc=$rc"
  checkForErrors "mmcommon propagateSdrfsFile" $rc
fi


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


###########################################################################
# If immediate changes requested, make them.  Screen out success messages.
###########################################################################
if [[ -n $immediate ]]
then
  if [[ -n $tschpoolParms ]]
  then
    $mmcommon onall $nodefile $unreachedNodes  \
                      tschpool "$tschpoolParms" > $tmpfile 2>&1
    rc=$?
    $cat $tmpfile 1>&2 |  \
    $grep -v -e "6027-749" -e "Pool size changed to"
  fi

  if [[ $rc -eq 0 && -n $tsctlParms ]]
  then
    $mmcommon onall $nodefile $unreachedNodes  \
                      tsctl "setCfgValue $tsctlParms"
    rc=$?
  fi

  if [[ $rc -eq 0 && -n $tsctlParms_onactive ]]
  then
    $mmcommon onactive $preferredNode $nodefile                     \
                       $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK  \
                       tsctl "setCfgValue $tsctlParms_onactive"
    rc=$?
  fi

  if [[ $rc -ne 0 ]]
  then
    # The -i step failed.
    printErrorMsg 309 $mmcmd
  fi
fi  # end of if [[ -n $immediate ]]


####################################################################
# If not already done, propagate the changes to all affected nodes.
####################################################################
[[ $synchronousNotify = yes || -n $immediateOnly ]] &&  \
  cleanupAndExit 0

if [[ -s $allnodes ]]
then
  propagateSdrfsFile async $allnodes $newsdrfs $newGenNumber $propagateOptions
elif [[ -s $nodefile ]]
then
  propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber $propagateOptions
else
  :  # nothing to update
fi

cleanupAndExit 0

