#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1997,2006 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)18 1.109.1.5 src/avs/fs/mmfs/ts/admin/mmchfs.sh, mmfs, avs_rgpfs24, rgpfs24s006a 8/25/06 13:05:47
################################################################################
#
# Usage:
#
#   mmchfs Device [-A {yes | no | automount}] [-D {posix | nfs4}]
#                 [-E {yes | no}] [-F MaxNumInodes[:NumInodesToPreallocate]]
#                 [-k {posix | nfs4 | all}] [-m DefaultMetadataReplicas]
#                 [-o mountOptions] [-Q {yes | no}] [-r DefaultDataReplicas]
#                 [-K {no | whenpossible | always}]
#                 [-s {roundRobin | random | balancedRandom}]
#                 [-S {yes | no}] [-T Mountpoint] [-V] [-z {yes | no}]
# or
#   mmchfs Device [-W newDeviceName]
#
# where
#
#   Device           is the device name of the file system.
#
#   -A {yes|no|automount}  Set the automount option.
#
#   -D {posix|nfs4}  Indicates whether CIFS deny write locks block NFS writes
#                      (nfs4) or not (posix)
#
#   -E {yes|no}      Enable or disable exact mtime
#
#   -F MaxNumInodes[:NumInodesToPreallocate]
#                    Specify the maximum number of files in the file system.
#                    Optionally, specify how many inodes to preallocate.
#
#   -k {posix|nfs4|all}  Specify the ACL semantics (posix, nfs4, all)
#
#   -K {no|whenpossible|always} Replica allocation behavior
#
#   -m DefaultMetadataReplicas
#                    is the default for the current number of replicas
#                    for metadata.
#
#   -o mountOptions  is a comma-separated list of mount options.
#
#   -Q {yes|no}      Enable or disable the quota option.
#
#   -r DefaultDataReplicas
#                    is the default for the current number of replicas for data.
#
#   -s StripeMethod  is the stripe method.
#
#   -S {yes|no}      Enable or disable (suppress) atime.
#
#   -T {mountpoint}  Change the mount point to the specified value.
#
#   -V               Change the file system to the latest format version.
#
#   -W newDeviceName  is the desired new name of the file system.
#
#   -z {yes|no}      Enable or disable DMAPI.
#
#
#  Note:  The -s option is undocumented.
#
#  Note:  The -C option is obsolete; use mmexportfs/mmimportfs instead.
#
################################################################################

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

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


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

LOCAL_FILES=" "


# Local variables
integer n
usageMsg=421


# Local functions


###########################################################
# This function is called if there is an interrupt after
# mmsdrfs changes are committed but before ts changes are.
###########################################################
function localPosttrap
{
  if [[ -n $mmsdrfsParms ]]
  then
    # Interrupt received:  only -A, -Q, and -T changed.
    printErrorMsg 33 $mmcmd
  else
    # Interrupt received:  no changes made.
    printErrorMsg 20 $mmcmd
  fi
  $mmTRACE_EXIT "rc=2"
  cleanupAndExit 2
}


###########################################################################
#
# Function:  Process the specified mount options string.
#            Provide default values for missing options.
#            This function is called if the -o flag is specified.
#
# Input:     $1 - A comma-separated list of mount options.
#
# Output:    Colon-separated string containing the fields:
#              rwOption:mtimeOption:atimeOption:quotaOptions:otherOptions:
#
# Returns:   0 - success
#            1 - error encountered
#
###########################################################################
function parseMountOptions   # <optionsString>
{
  typeset sourceFile="mmchfs.sh"
  [[ -n $DEBUG || -n $DEBUGparseMountOptions ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset optionsString=$1

  typeset rc=0
  typeset rwOption=""
  typeset mtimeOption=""
  typeset atimeOption=""
  typeset quotaOptions=""
  typeset otherOptions=""


  # Parse the options string looking for certain options.
  # All other options are simply passed through.
  IFS=","
  for option in $optionsString
  do
    case $option in

      rw | ro | rs )
        [[ $option = rs ]] && option=ro
        rwOption=$option
        ;;

      atime* | noatime )
        if [[ $option = atime || $option = "atime=1" || $option = "atime=yes" ]]
        then
          atimeOption=atime
        elif [[ $option = noatime || $option = "atime=0" || $option = "atime=no" ]]
        then
          atimeOption=noatime
        else
          print -u2 "$mmcmd:  Invalid mount option specified: $option."
          return 1
        fi
        ;;

      mtime* | nomtime )
        if [[ $option = mtime || $option = "mtime=1" || $option = "mtime=yes" ]]
        then
          mtimeOption=mtime
        elif [[ $option = nomtime || $option = "mtime=0" || $option = "mtime=no" ]]
        then
          mtimeOption=nomtime
        else
          print -u2 "$mmcmd:  Invalid mount option specified: $option."
          return 1
        fi
        ;;

      syncnfs* | nosyncnfs )
        if [[ $option = syncnfs || $option = "syncnfs=1" || $option = "syncnfs=yes" ]]
        then
          otherOptions="${otherOptions},syncnfs"
        elif [[ $option = nosyncnfs || $option = "syncnfs=0" || $option = "syncnfs=no" ]]
        then
          otherOptions="${otherOptions},nosyncnfs"
        else
          print -u2 "$mmcmd:  Invalid mount option specified: $option."
          return 1
        fi
        ;;

      *quota* )
        quotaOptions="${quotaOptions};$option"
        ;;

      *rootSquash* )
        :       # Do nothing; root squash is controlled with mmauth grant.
        ;;

      * )
        otherOptions="${otherOptions},$option"
        ;;

    esac  # end of case $option in
  done  # end of for option in $optionsString do
  IFS="$IFS_sv"

  quotaOptions="${quotaOptions##+(;)}"   # Strip leading  semicolons, if any.
  quotaOptions="${quotaOptions%%+(;)}"   # Strip trailing semicolons, if any.
  otherOptions="${otherOptions##+(,)}"   # Strip leading  commas, if any.
  otherOptions="${otherOptions%%+(,)}"   # Strip trailing commas, if any.

  # Output the results and return.
  print -- "$rwOption:$mtimeOption:$atimeOption:$quotaOptions:$otherOptions:"

  $mmTRACE_EXIT "rc=$rc"
  return $rc

}  #------ end of function parseMountOptions -----------------



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


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

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

# The first argument is always the file system name.
device=$arg1
shift 1          # Drop the device name from the parameter list.

# Process the individual arguments and the values associated with them.
while getopts :A:C:D:E:F:k:K:m:o:Q:r:s:S:T:W:z:V OPT
do
  case $OPT in

    A) [[ -n $Aflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Aflag="-$OPT"; Aarg=$OPTARG;
       [[ $Aarg != yes && $Aarg != no && $Aarg != automount ]] &&  \
         syntaxError "invalidOption" $usageMsg "-$OPT $OPTARG"
       if [[ $Aarg = yes ]]
       then
         Aarg=mmfs
       elif [[ $Aarg = no ]]
       then
         Aarg=false
       else
         :  # It must be "automount".
       fi
       # Add -A to the list of parameters not handled by the daemon.
       if [[ -z $mmsdrfsParms ]]
       then
         mmsdrfsParms="-$OPT"
       else
         mmsdrfsParms="${mmsdrfsParms}, -$OPT"
       fi
       ;;

    C) syntaxError "obsoleteOption" $usageMsg "-$OPT"
       ;;

    D) [[ -n $Dflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Dflag="-$OPT"; Darg=$OPTARG;
       [[ $Darg != nfs4 && $Darg != posix ]] &&  \
         syntaxError "invalidOption" $usageMsg "-$OPT $OPTARG"
       # Add -D to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $Dflag $Darg"
       ;;

    E) [[ -n $Eflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Eflag="-$OPT"; Earg=$OPTARG;
       [[ $Earg != yes && $Earg != no ]] &&  \
         syntaxError "YesNoValue" $noUsageMsg "-$OPT"
       # Add -E to the list of parameters not handled by the daemon.
       if [[ -z $mmsdrfsParms ]]
       then
         mmsdrfsParms="-$OPT"
       else
         mmsdrfsParms="${mmsdrfsParms}, -$OPT"
       fi
       if [[ $Earg = yes ]]
       then
         Earg="mtime"
       else
         Earg="nomtime"
       fi
       callResetEFOptions=yes
       ;;

    F) [[ -n $Fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Fflag="-$OPT"; Farg=$OPTARG;
       ;;

    k) [[ -n $kflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       kflag="-$OPT"; karg=$OPTARG;
       [[ $karg != posix && $karg != nfs4 && $karg != all ]] &&  \
         syntaxError "invalidOption" $usageMsg "-$OPT $OPTARG"
       # Add -k to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $kflag $karg"
       ;;

    K) [[ -n $Kflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Kflag="-$OPT"; Karg=$OPTARG;
       [[ $Karg != no && $Karg != whenpossible && $Karg != always ]] &&  \
         syntaxError "invalidOption" $usageMsg "-$OPT $OPTARG"
       # Add -K to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $Kflag $Karg"
       ;;

    m) [[ -n $mflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       mflag="-$OPT"; marg=$OPTARG;
       # Ensure that marg is an integer, and that its value is 1 or 2.
       n=$(checkIntRange $mflag $marg 1 2)
       [[ $? -ne 0 ]] && cleanupAndExit
       # Add -m to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $mflag $marg"
       ;;

    o) [[ -n $oflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       oflag="-$OPT"; oarg=$OPTARG;
       [[ -z $oarg ]] && oarg=DELETE
       # Add -o to the list of parameters not handled by the daemon.
       if [[ -z $mmsdrfsParms ]]
       then
         mmsdrfsParms="-$OPT"
       else
         mmsdrfsParms="${mmsdrfsParms}, -$OPT"
       fi
       callResetEFOptions=yes
       ;;

    Q) [[ -n $Qflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Qflag="-$OPT"; Qarg=$OPTARG;
       [[ $Qarg != yes && $Qarg != no ]] &&  \
         syntaxError "YesNoValue" $noUsageMsg "-$OPT"
       # Add -Q to the list of parameters not handled by the daemon.
       if [[ -z $mmsdrfsParms ]]
       then
         mmsdrfsParms="-$OPT"
       else
         mmsdrfsParms="${mmsdrfsParms}, -$OPT"
       fi
       if [[ $Qarg = yes ]]
       then
         Qarg=$QUOTA_ACTIVATED
       else
         Qarg=DELETE
       fi
       callResetEFOptions=yes
       ;;

    r) [[ -n $rflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       rflag="-$OPT"; rarg=$OPTARG;
       # Ensure that rarg is an integer, and that its value is 1 or 2.
       n=$(checkIntRange $rflag $rarg 1 2)
       [[ $? -ne 0 ]] && cleanupAndExit
       # Add -r to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $rflag $rarg"
       ;;

    s) [[ -n $sflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       sflag="-$OPT"; sarg=$OPTARG;
       # Let tschfs validate the argument.
       # Add -s to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $sflag $sarg"
       ;;

    S) [[ -n $Sflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Sflag="-$OPT"; Sarg=$OPTARG;
       [[ $Sarg != yes && $Sarg != no ]] &&  \
         syntaxError "YesNoValue" $noUsageMsg "-$OPT"
       # Add -S to the list of parameters not handled by the daemon.
       if [[ -z $mmsdrfsParms ]]
       then
         mmsdrfsParms="-$OPT"
       else
         mmsdrfsParms="${mmsdrfsParms}, -$OPT"
       fi
       if [[ $Sarg = yes ]]
       then
         Sarg="noatime"
       else
         Sarg="atime"
       fi
       callResetEFOptions=yes
       ;;

    T) [[ -n $Tflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Tflag="-$OPT"; Targ=$OPTARG;
       # Ensure the pathname starts with a slash.
       [[ $Targ = ${Targ#/} ]] &&  \
         syntaxError "absolutePath" $noUsageMsg $Targ
       # Add -T to the list of parameters not handled by the daemon.
       if [[ -z $mmsdrfsParms ]]
       then
         mmsdrfsParms="-$OPT"
       else
         mmsdrfsParms="${mmsdrfsParms}, -$OPT"
       fi
       callResetEFOptions=yes
       ;;

    V) [[ -n $Vflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Vflag="-$OPT";
       # Add -V to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $Vflag"
       ;;

    W) # If specified, W must be the only option.
       [[ $argc -gt 3 ]] && syntaxError "help" $usageMsg
       Wflag="-$OPT"; Warg=$OPTARG;
       checkName deviceName 255 "$Warg"
       [[ $? -ne 0 ]] && cleanupAndExit
       ;;

    z) [[ -n $zflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       zflag="-$OPT"; zarg=$OPTARG;
       [[ $zarg != yes && $zarg != no ]] &&  \
         syntaxError "YesNoValue" $noUsageMsg "-$OPT"
       # Add -z to the list of parameters handled by tschfs.
       tschfsParms="${tschfsParms} $zflag $zarg"
       ;;

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

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

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

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

# Parse and process the -o value if it was specified.
# This can result in prior values for Earg, Qarg, and Sarg
# being overridden.
if [[ $oarg = DEFAULT || $oarg = DELETE ]]
then
  # Set the default mount options; leave the quota setting alone.
  sgRW_OPT_Value="rw"
  Earg="mtime"
  Sarg="atime"
  oarg=DELETE
elif [[ -n $oarg ]]
then
  # Parse the mount options and set variables to be used later.
  parseMountOptionsOutput=$(parseMountOptions $oarg)
  [[ $? -ne 0 ]] && cleanupAndExit
  IFS=":"
  set -f ; set -- $parseMountOptionsOutput ; set +f
  [[ -n $1 ]] && sgRW_OPT_Value=$1
  [[ -n $2 ]] && Earg=$2
  [[ -n $3 ]] && Sarg=$3
  [[ -n $4 ]] && Qarg=$4
  oarg=$5
  IFS="$IFS_sv"
fi  # end of if [[ $oarg = DEFAULT || $oarg = DELETE ]]

# Process the -F value.  Verify it is of the form NumInodes[:NumInodesToPreallocate]
if [[ -n $Farg ]]
then
  IFS=":"
  set -f ; set -- $Farg ; set +f
  numInodes=$1
  numInodesToPreallocate=$2
  IFS="$IFS_sv"

  [[ -z $numInodes ]] &&  \
    syntaxError "invalidOption" $usageMsg "$Fflag $Farg"

  n=$(checkIntRange $Fflag $numInodes)
  [[ $? -ne 0 ]] && cleanupAndExit
  Farg=$n

  if [[ -n $numInodesToPreallocate && $numInodesToPreallocate != 0 ]]
  then
    n=$(checkIntRange $Fflag $numInodesToPreallocate)
    [[ $? -ne 0 ]] && cleanupAndExit
    Farg="${Farg}:$n"
  fi

  # Add -F to the list of parameters handled by tschfs.
  tschfsParms="${tschfsParms} $Fflag $Farg"
fi  # end of if [[ -n $Farg ]]


###########################################################
# If the request is to rename the file system (-W option),
# invoke the mmmvfs script.
###########################################################
if [[ -n $Wflag ]]
then
  $mmmvfs $device $Wflag $Warg
  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


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

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

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


###############################################################################
# Go through the mmsdrfs file.  If changing parameters that are kept in the file,
# create a new version of the file.  It will have a new generation number and
# the appropriate parameters in the SG_ETCFS and/or SG_MOUNT lines will be
# set to their new values.  Simultaneously, create a file with the names of
# the nodes that belong to the cluster.  This file will be used later for
# propagating the changes to the individual nodes and for finding a node
# on which to execute the tschfs command if needed.
###############################################################################
$rm -f $newsdrfs $nodefile $allQuorumNodes
existingMountPoints=""
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.

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

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

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

    $NODESET_HDR )  # This is the header line for some cluster.
       # If this is our cluster, save the release level information.
       if [[ ${v[$NODESETID_Field]} = $fsHomeCluster ]]
       then
         lowestVersion=${v[$MIN_DAEMON_VERSION_Field]}
         highestVersion=${v[$MAX_DAEMON_VERSION_Field]}
       fi
       ;;

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

       # Create a list of the quorum nodes.
       if [[ ${v[$CORE_QUORUM_Field]} = $quorumNode ]]
       then
         print -- "${v[$REL_HOSTNAME_Field]}" >> $allQuorumNodes
         checkForErrors "writing to file $allQuorumNodes" $?
       fi

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

    $SG_ETCFS )  # This is an /etc/filesystem line.
       # The processing of the SG_ETCFS lines will depend
       # on the options that were specified on the mmchfs command.

       if [[ -n $Targ && ${v[$LINE_NUMBER_Field]} = $MOUNT_POINT_Line ]]
       then
         # We are changing the mount point and this
         # is a mount point line for some file system.
         # If this is the mount point for our file system,
         # set it to the new value.  Otherwise, add it to
         # the list of existing mount points.
         if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
         then
           oldMountPoint=${v[$ETCFS_TEXT_Field]}
           v[$ETCFS_TEXT_Field]=$Targ
           fsMustNotBeMounted=yes
           [[ $mountCheckScope != $CHECK_ALL ]] &&  \
              mountCheckScope=$ourClusterName
         else
           existingMountPoints="$existingMountPoints ${v[$ETCFS_TEXT_Field]}"
         fi
       fi  # end if [[ -n $Targ && ${v[$LINE_NUMBER_Field]} = $MOUNT_POINT_Line ]]

       if [[ -n $Aarg && ${v[$LINE_NUMBER_Field]} = $MOUNT_Line ]]
       then
         # We are changing the automount option and
         # this is a mount line for some file system.

         # See if any file system requires the system automounter.
         [[ ${v[$ETCFS_TEXT_Field]}  = *automount* ]] &&  \
           automountMounts=true

         # If this is the mount line for our file system,
         # set the new value for the mount option.
         if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
         then
           # If switching to or from automount the file system must be unmounted.
           if [[ $Aarg = automount || ${v[$ETCFS_TEXT_Field]} = *automount* ]]
           then
             fsMustNotBeMounted=yes
             [[ $mountCheckScope != $CHECK_ALL ]] &&  \
                mountCheckScope=$ourClusterName
           fi

           # Set the new value for the mount option.
           v[$ETCFS_TEXT_Field]="$MOUNT_Line_Prefix$Aarg"
         fi  # end of if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
       fi  # end if [[ -n $Aarg && ${v[$LINE_NUMBER_Field]} = $MOUNT_Line ]]
       ;;

    $SG_MOUNT )  # This line describes stripe group mount options.

       if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
       then
         # Change mount options for our file system.

         [[ -n $Earg ]] && v[$MTIME_OPT_Field]=$Earg

         if [[ -n $Qarg ]]
         then
           fsMustNotBeMounted=yes
           mountCheckScope=$CHECK_ALL
           if [[ $Qarg = DELETE ]]
           then
             v[$QUOTA_OPT_Field]=$QUOTA_DISACTIVATED
           else
             v[$QUOTA_OPT_Field]=$Qarg
           fi
         fi

         [[ -n $Sarg ]] && v[$ATIME_OPT_Field]=$Sarg

         if [[ -n $oarg ]]
         then
           if [[ $oarg = DELETE ]]
           then
             v[$OTHER_OPT_Field]=""
           else
             v[$OTHER_OPT_Field]=$oarg
           fi
         fi

         [[ -n $sgRW_OPT_Value ]] && v[$RW_OPT_Field]=$sgRW_OPT_Value

       fi  # end of if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
       ;;

    * )  # 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 >> $newsdrfs
  checkForErrors "writing to file $newsdrfs" $?

  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 the mount point was changed, make sure that the new mount point
# is not already used by some other file system and that the file system
# is not mounted anywhere.
if [[ -n $Targ ]]
then
  for mpnt in $existingMountPoints
  do
    if [[ $mpnt = $Targ ]]
    then
      # There is already an existing filesystem using this mountpoint.
      printErrorMsg 107 $mmcmd $Targ
      cleanupAndExit
    fi
  done
fi  # end if [[ -n $Targ ]]

# If necessary, ensure that the file system is not mounted.
if [[ -n $fsMustNotBeMounted ]]
then
  $mmcommon onactive $preferredNode $nodefile $NO_FILE_COPY  \
     $fqDeviceName $mountCheckScope $NO_LINK $MOUNT_CHECK_ONLY 2>$errMsg
  rc=$?
  if [[ $rc -eq $MM_FsMounted ]]
  then
    # File system is still mounted (messages were issued by mmcommon).
    cleanupAndExit $rc
  elif [[ $rc -eq $MM_DaemonDown ]]
  then
    # GPFS is down on all nodes that we care about.
    rc=0
  elif [[ $rc -eq $MM_ConnectionReset ]]
  then
    # An internode connection was reset.
    printErrorMsg 257 $mmcmd
    cleanupAndExit $rc
  elif [[ $rc -ne 0 ]]
  then
    # An unexpected error occurred during the mount check.
    if [[ -s $errMsg ]]
    then
      # Show the error messages from the daemon.
      $cat $errMsg 1>&2
    else
      # The mount check failed and there were no messages from the daemon.
      printErrorMsg 171 $mmcmd "mount check for $fqDeviceName" $rc
    fi
    # The command was unable to determine whether the file system is mounted.
    printErrorMsg 564 $mmcmd $fqDeviceName
    cleanupAndExit $rc
  fi  # end if [[ $rc -eq $MM_FsMounted ]]
  $rm -f $errMsg
fi  # end if [[ -n $fsMustNotBeMounted ]]

# If this is the first automountable GPFS file system,
# run the automount command on the nodes in the cluster.
if [[ $Aarg = "automount" && -z $automountMounts ]]
then
  # Determine the value of the automountDir parameter.
  automountDir=$(showCfgValue automountDir)
  [[ -z $automountDir ]] && automountDir=$defaultAutomountDir

  # Run the automount command on the nodes on which GPFS is active.
  # On nodes that do not have GPFS running right now, this will be
  # done by the mmchecksubsys processing when the daemon is started.
  $mmcommon onactive $preferredNode $nodefile        \
      $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK    \
      tsdsh $mmremote startAutomounter $automountDir >$tmpfile 2>&1
  rc=$?

  # Ignore errors but show messages from the nodes, if any.
  if [[ $rc -ne 0 && $rc -ne $MM_DaemonDown && -s $tmpfile ]]
  then
    $awk '                             \
      # Skip the lines with rc values. \
      $2 == "rc" { next }              \
      # Print everything else.         \
      { print $0 }                     \
    ' $tmpfile
  fi  # end of if [[ -s $tmpfile ]]
fi  # end of if [[ $Aarg = "automount" && -z $automountMounts ]]

# If changing the file system to the latest format version (-V),
# verify that all nodes are running the same level of code.
# if [[ -n $Vflag ]]
# then
#   VflagAllowed=no  # Assume the worst.
#
#   # First look at the current information in the mmsdrfs file.
#   if [[ $lowestVersion -ne $highestVersion ]]
#   then
#     # -V requires all nodes to be at the same level.
#     printErrorMsg 583 $mmcmd
#     cleanupAndExit
#   fi  # end if [[ $lowestVersion -ne $highestVersion ]]
#
#   # According to the mmsdrfs file, all nodes are at the same level.
#   # Verify that this is indeed the case at least on the nodes
#   # on which the GPFS daemon is currently running.
#   getCodeRangeOutput=$($mmcommon onactive $preferredNode $nodefile  \
#     $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK mmremote getCodeRange)
#   rc=$?
#   if [[ -z $getCodeRangeOutput || $rc -ne 0 ]]
#   then
#     # Something went wrong with the mmcommon call.
#     [[ $rc -eq 0 ]] && rc=1
#     if [[ -n $getCodeRangeOutput ]]
#     then
#       # If there was some output, assume it is an error message.
#       # Filter out the standard output strings, if any.
#       print -- "$getCodeRangeOutput" | $grep -v "getCodeRange:" 1>&2
#     else
#       # Otherwise, output the generic unexpected error message.
#       printErrorMsg 171 "$mmcmd" "mmcommon onactive mmremote getCodeRange" $rc
#     fi
#
#   else
#     # The mmcommon call seems to have worked.  Parse the results.
#     IFS=":"
#     set -f ; set -- $getCodeRangeOutput ; set +f
#     kword=$1
#     rc=$2
#     status=$3
#     maxDaemonVersion=$4
#     minDaemonVersion=$5
#     IFS="$IFS_sv"
#
#     if [[ $kword = getCodeRange && $status = complete ]]
#     then
#       if [[ $minDaemonVersion = $maxDaemonVersion ]]
#       then
#         VflagAllowed=yes
#       else
#         # -V requires all nodes to be at the same level.
#         printErrorMsg 583 $mmcmd
#       fi
#     else
#       # Otherwise, output the generic unexpected error message.
#       printErrorMsg 171 "$mmcmd" "mmcommon onactive mmremote getCodeRange" $rc
#     fi  # end if [[ $kword = getCodeRange && $status = complete ]]
#   fi  # end if [[ -z $getCodeRangeOutput || $rc -ne 0 ]]
#
#   # If we were not able to convince ourselves that it is OK
#   # to procede with the -V call, give up.
#   [[ $VflagAllowed = no ]] && cleanupAndExit
#
# fi  # end if [[ -n $Vflag ]]


#######################################################
# Change parameters that are kept in the mmsdrfs file.
#######################################################
if [[ -n $mmsdrfsParms ]]
then
  # Put the mmsdrfs file into the sdr.
  trap "" HUP INT QUIT KILL
  gpfsObjectInfo=$(commitChanges $fsHomeCluster $nsId  \
                      $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer)
  rc=$?
  if [[ $rc -ne 0 ]]
  then
    # Cannot replace file in the sdr.
    printErrorMsg 381 $mmcmd
    cleanupAndExit
  fi

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

  # If necessary, tell the daemon to invalidate its currently-cached
  # mount options.
  if [[ -n $callResetEFOptions ]]
  then
    $mmcommon onactive $preferredNode $allQuorumNodes  \
                       $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK  \
                       tsctl resetEFOptions $fqDeviceName > $errMsg 2>&1
    rc=$?
    [[ $rc = $MM_DaemonDown ]] && rc=0
    [[ $rc -ne 0 && -s $errMsg ]] && cat $errMsg 2>&1
    $rm -f $errMsg
  fi

  # If the mount point changed, remove the old mount point.
  [[ -n $oldMountPoint && $Targ != $oldMountPoint ]] &&  \
    propagateOptions="rmdir$oldMountPoint"

  # Make the changes visible to the affected nodes.  Note that when
  # changing the mount point or mount options, there is a window during
  # which different nodes may see different mount points and/or options.
  propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber $propagateOptions

fi  # end if [[ -n $mmsdrfsParms ]]


############################################################
# If changes are requested that need to be handled by GPFS,
# run the tschfs command on an active daemon.
############################################################
if [[ -n $tschfsParms && $tschfsParms != +( ) ]]
then
  $mmcommon onactive $preferredNode $nodefile  \
                     $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK  \
                     tschfs $fqDeviceName $tschfsParms
  rc=$?
  if [[ $rc -ne 0 ]]
  then
    if [[ -n $mmsdrfsParms ]]
    then
      # The tschfs step failed.  Some parameters changed.
      printErrorMsg 318 $mmcmd tschfs "$mmsdrfsParms"
    else
      # The tschfs step failed.
      printErrorMsg 104 $mmcmd tschfs
    fi
    cleanupAndExit
  fi
fi  # end of if [[ -n $tschfsParms && $tschfsParms != +( ) ]]


###################################################
# If installed, invoke the syncfsconfig user exit.
###################################################
if [[ -x $syncfsconfig && -n $mmsdrfsParms ]]
then
   print -- "$mmcmd:  Starting $syncfsconfig ..."
   $syncfsconfig
   print -- "$mmcmd:  $syncfsconfig finished."
fi

$mmTRACE_EXIT "rc=0"
cleanupAndExit 0

