#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2004,2007 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)46 1.55.1.2 src/avs/fs/mmfs/ts/admin/mmremotefs.sh, mmfs, avs_rgpfs24, rgpfs24s012a 5/2/07 15:29:30
###############################################################################
#
#  Usage:
#
#    mmremotefs add device -f remoteDevice -C remoteClusterName
#                     -T mountPoint [-o mountOptions] [-A yes|no|automount]
#
#    mmremotefs update device [-f remoteDevice] [-C remoteClusterName]
#                    [-T mountPoint] [-o mountOptions] [-A yes|no|automount]
#
#    mmremotefs delete {device | all | -C remoteClusterName}
#
#    mmremotefs show   [device | all | -C remoteClusterName]
#
#  where
#
#    device        is the local name for the remote file system.
#                  This name must be unique within the local cluster.
#                  The actual name of the file system within its home cluster
#                  may or may not be the same.  See the -f parameter.
#
#    -f remoteDevice   is the actual device name for the remote file system
#                      within the file system's home cluster.
#
#    -C remoteClusterName   is the fully-qualified name for the remote
#                           cluster that owns the file system.
#
#    -T mountPoint     is the mount point directory of the file system.
#
#    -o mountOptions   is a comma-separated list of mount options.
#                      The default set of options is:  rw,nomtime,atime
#
#    -A yes|no|automount  controls the automount option.  If yes is specified,
#                      the file system is mounted automatically when the GPFS
#                      daemon is started.  If no is specified, the file system
#                      can be mounted only with an explicit mount command.
#                      If automount is specified, the mounting of the file
#                      system is controlled by the system automount daemon.
#                      The default setting is no.
#
###############################################################################

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

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

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

LOCAL_FILES=" $mountCheckList "


# Local variables
usageMsg=385
contactNodesCount=0


# Local functions


###########################################################################
#
# Function:  Process the specified mount options string.
#            Provide default values for missing options.
#
# 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="mmremotefs.sh"
  [[ -n $DEBUG || -n $DEBUGparseMountOptions ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset optionsString=$1

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

  # Clear the string if DELETE or DEFAULT is specified.
  [[ $optionsString = DEFAULT || $optionsString = DELETE ]] &&  \
    optionsString=""

  # 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* )
        :       # Do nothing; quotas should be controlled with mmchfs -Q.
        ;;

      *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"

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

  # Put out 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 line arguments.
#######################################
[[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] &&  \
  syntaxError "help" $usageMsg

action=$arg1

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

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

# Process the positional parameters.
case $action in
  add )
    [[ $argc -lt 5 ]] && syntaxError "missingArgs" $usageMsg
    device=$arg2
    ;;

  update )
    [[ $argc -lt 3 ]] && syntaxError "missingArgs" $usageMsg
    device=$arg2
    ;;

  delete )
    [[ $argc -lt 2 ]] && syntaxError "missingArgs" $usageMsg
    if [[ $arg2 = "-C"* ]]
    then
      remoteClusterName=${arg2#-C}
      if [[ -z $remoteClusterName ]]
      then
        remoteClusterName=$arg3
        [[ -n $arg4 ]] && syntaxError "extraArg" $usageMsg $arg4
      else
        [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3
      fi
      [[ -z $remoteClusterName ]] && syntaxError "missingValue" $usageMsg "-C"
    else
      device=$arg2
      [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3
    fi
    ;;

  show )
    if [[ -z $arg2 ]]
    then
      device=all
    elif [[ $arg2 = "-C"* ]]
    then
      remoteClusterName=${arg2#-C}
      if [[ -z $remoteClusterName ]]
      then
        remoteClusterName=$arg3
        [[ -n $arg4 ]] && syntaxError "extraArg" $usageMsg $arg4
      else
        [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3
      fi
      [[ -z $remoteClusterName ]] && syntaxError "missingValue" $usageMsg "-C"
    else
      device=$arg2
      [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3
    fi
    ;;

  *) # Invalid action specified.
    syntaxError "keyword" $usageMsg $action
    ;;
esac


# Verify the device name.
deviceName=${device##+(/)dev+(/)}  # name stripped of /dev/ prefix
fqDeviceName="/dev/$deviceName"    # fully-qualified name (with /dev/ prefix)
if [[ $deviceName = /* ]]
then
  printErrorMsg 169 $mmcmd $device
  cleanupAndExit
elif [[ $deviceName = */* ]]
then
  printErrorMsg 170 $mmcmd $device
  cleanupAndExit
else
  checkName deviceName 255 "$deviceName"
  [[ $? -ne 0 ]] && cleanupAndExit
fi

# If action is "add" or "update", there are more options to process.
if [[ $action = add || $action = update ]]
then
  shift 2    # Move past the fs name in the parameter list.

  # Process the individual arguments and the values associated with them.
  while getopts :A:C:f:k:n:o:T: 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
         ;;

      C) [[ -n $Cflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         Cflag="-$OPT"; Carg=$OPTARG;
         ;;

      f) [[ -n $fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         fflag="-$OPT"; farg=$OPTARG;
         ;;

      o) [[ -n $oflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         oflag="-$OPT"; oarg=$OPTARG;
         [[ -z $oarg ]] && oarg=DEFAULT
         ;;

      T) [[ -n $Tflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
         Tflag="-$OPT"; Targ=$OPTARG;
         checkName pathName 1023 "$Targ"
         [[ $? -ne 0 ]] && cleanupAndExit
         # Ensure the pathname starts with a slash.
         [[ $Targ = ${Targ#/} ]] &&  \
           syntaxError "absolutePath" $noUsageMsg $Targ
         ;;

      +[ACfknoT)  # 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

  # Verify input parameters and assign default values as needed.
  if [[ $action = add ]]
  then
    [[ -z $Carg ]] && syntaxError "missingArgs" $usageMsg
    [[ -z $Targ ]] && syntaxError "missingArgs" $usageMsg
    [[ -z $farg ]] && syntaxError "missingArgs" $usageMsg
    [[ -z $Aarg ]] && Aarg=false
    if [[ $device = all ]]
    then
      # The device name cannot be "all".
      printErrorMsg 196 $mmcmd
      cleanupAndExit
    fi
  else  # action = update
    if [[ -z $Aarg && -z $Carg && -z $farg && -z $oarg && -z $Targ ]]
    then
      # No changes made.
      printErrorMsg 323 $mmcmd
      cleanupAndExit
    fi
  fi  # end of if [[ $action = add ]]

  # Initialize local variables.
  remoteDevice=${farg##+(/)dev+(/)}  # name stripped of /dev/ prefix
  if [[ $remoteDevice = /* ]]
  then
    printErrorMsg 169 $mmcmd "$farg"
    cleanupAndExit
  elif [[ $remoteDevice = */* ]]
  then
    printErrorMsg 170 $mmcmd "$farg"
    cleanupAndExit
  else
    checkName deviceName 255 "$remoteDevice"
    [[ $? -ne 0 ]] && cleanupAndExit
  fi
  remoteClusterName=$Carg
  mountPoint=$Targ
  automountValue=$Aarg
  mountOptions=$oarg

  # Determine the values for the /etc/filesystems stanza lines.
  sgVFS_Line_Value="mmfs"
  sgTYPE_Line_Value="mmfs"
  sgNODENAME_Line_Value="-"
  sgACCOUNT_Line_Value="false"
  sgMOUNT_Line_Value=$automountValue

  # Parse the mount options.
  parseMountOptionsOutput=$(parseMountOptions $mountOptions)
  IFS=":"
  set -f ; set -- $parseMountOptionsOutput ; set +f
  sgRW_OPT_Value=$1
  sgMTIME_OPT_Value=$2
  sgATIME_OPT_Value=$3
  sgQUOTA_OPT_Value=$4
  sgOTHER_OPT_Value=$5
  IFS="$IFS_sv"

  # The mount point cannot be the same as the device name.
  if [[ $fqDeviceName = $mountPoint ]]
  then
    printErrorMsg 305 $mmcmd $mountPoint
    cleanupAndExit
  fi
fi  # end of if [[ $action = add || $action = update ]]


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

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


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

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

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

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

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

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

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

    $SG_HEADR )
      # Processing depends on the specified action:
      case $action in
        add )
          # Make sure that the file system that we want to create
          # does not already exist.
          if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
          then
            printErrorMsg 107 $mmcmd $device
            cleanupAndExit
          fi
          if [[ ${v[$REMOTE_DEV_NAME_Field]} = $remoteDevice &&
                 ${v[$NODESETID_Field]} = $remoteClusterName ]]
          then
            # The file system on the remote cluster is already defined.
            printErrorMsg 317 $mmcmd $remoteDevice $remoteClusterName
            cleanupAndExit
          fi

          # Make a list of the used minor numbers.
          existingMinorNumbers="$existingMinorNumbers ${v[$DEV_MINOR_Field]}"
          ;;

        update )
          if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
          then
            # We are making changes to this remote file system.
            fsFound=yes

            # Generate the fully-qualified name for the file system.
            fsFullName="${v[$NODESETID_Field]}:${v[$REMOTE_DEV_NAME_Field]}"

            # Verify that this is indeed a remote file system.
            if [[ ${v[$FS_TYPE_Field]} != $remotefs ]]
            then
              # The file system is not a remote file system known to GPFS.
              printErrorMsg 252 $mmcmd $device
              cleanupAndExit
            fi

            if [[ -n $remoteDevice ]]
            then
              # We are changing the actual name of the file system.
              v[$REMOTE_DEV_NAME_Field]=$remoteDevice
              fsMustNotBeMounted=yes
            fi

            if [[ -n $remoteClusterName ]]
            then
              # We are changing the home cluster name.
              v[$NODESETID_Field]=$remoteClusterName
              fsMustNotBeMounted=yes
            fi
          fi  # end of if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
          ;;

        delete )
          if [[ (${v[$DEV_NAME_Field]} = $deviceName || $device = all ||
                 ${v[$NODESETID_Field]} = $remoteClusterName) &&
                 ${v[$FS_TYPE_Field]} = $remotefs ]]
          then
            # This file system is going away.
            deleteThisFileSystem=yes
            fsFound=yes

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

          else
            # This file system will remain in place.
            deleteThisFileSystem=""
            if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
            then
              # The file system is not a remote file system known to GPFS.
              printErrorMsg 252 $mmcmd $device
              cleanupAndExit
            fi
          fi  # end of if [[ (${v[$DEV_NAME_Field]} = $deviceName ... ]]

          [[ -n $deleteThisFileSystem ]] &&  \
            printLine=false
          ;;

        show )
          if [[ (${v[$DEV_NAME_Field]}  = $deviceName || $device = all ||
                 ${v[$NODESETID_Field]} = $remoteClusterName) &&
                 ${v[$FS_TYPE_Field]} = $remotefs ]]
          then
            fsFound=yes
            displayThisFileSystem=yes
            if [[ -z $headerOut ]]
            then
              # Output the header line.
              header=$(printInfoMsg 490)
              printf "%s\n" "$header"
              headerOut=yes
            fi

            # Start outputting the individual fields.
            printf "%-11s %-12s %-22s" "${v[$DEV_NAME_Field]}"  \
                   "${v[$REMOTE_DEV_NAME_Field]}" "${v[$NODESETID_Field]}"
          else
            displayThisFileSystem=""
            if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]
            then
              # The file system is not a remote file system known to GPFS.
              printErrorMsg 252 $mmcmd $device
              cleanupAndExit
            fi
          fi  # end of if [[ (${v[$DEV_NAME_Field]}  = $deviceName ...
          ;;

        *) checkForErrors "unexpected action $action" 1
          ;;
      esac  # end case $action in
      ;;

    $SG_ETCFS )
      # Processing depends on the specified action:
      case $action in
        add )
          # Make sure that the new mount point is not already used
          # by some other file system in the nodeset.
          if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_POINT_Line &&
                ${v[$ETCFS_TEXT_Field]}  = $mountPoint ]]
          then
            printErrorMsg 107 $mmcmd $mountPoint
            cleanupAndExit
          fi

          # See if any of the existing file systems requires
          # the system automounter.
          if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_Line &&
                ${v[$ETCFS_TEXT_Field]}  = *automount* ]]
          then
            automountMounts=yes
          fi
          ;;

        update )
          if [[ -n $mountPoint ]]
          then
            # We are changing the mount point.
            if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_POINT_Line ]]
            then
              # 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]=$mountPoint
                fsMustNotBeMounted=yes
              else
                existingMountPoints="$existingMountPoints ${v[$ETCFS_TEXT_Field]}"
              fi
            fi
          fi  # end of if [[ -n $mountPoint ]]

          if [[ -n $automountValue ]]
          then
            # We are changing the automount option.
            if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_Line ]]
            then
              # This is a mount line for some file system, i.e.,
              # the ' mount = ... ' line in etc/filesystems.

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

              # 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.
                [[ $automountValue = automount ||
                   ${v[$ETCFS_TEXT_Field]} = *automount* ]] &&  \
                  fsMustNotBeMounted=yes

                # Set the new value for the mount option.
                v[$ETCFS_TEXT_Field]="$MOUNT_Line_Prefix$automountValue"
              fi  # end of if [[ ${v[$DEV_NAME_Field]} = $deviceName ]]

            fi  # end of if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_Line ]]
          fi  # end of if [[ -n $automountValue ]]

          if [[ -n $remoteClusterName && ${v[$DEV_NAME_Field]} = $deviceName ]]
          then
            # We are changing the home cluster name.
            v[$NODESETID_Field]=$remoteClusterName
          fi
          ;;

        delete )
          [[ -n $deleteThisFileSystem ]] &&  \
            printLine=false
          ;;

        show )
          if [[ -n $displayThisFileSystem ]]
          then
            # Output the mount point.
            [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_POINT_Line ]] &&  \
              printf " %-20s" "${v[$ETCFS_TEXT_Field]}"

            # Determine the automount value.  It will be displayed last.
            if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_Line ]]
            then
              automountSetting=${v[$ETCFS_TEXT_Field]#$MOUNT_Line_Prefix}
              if [[ $automountSetting = mmfs ]]
              then
                automountSetting=yes
              elif [[ $automountSetting = false ]]
              then
                automountSetting=no
              else
                :  # Leave the value as is.
              fi
            fi  # end of if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_Line ]]
          fi  # end of if [[ -n $displayThisFileSystem ]]
          ;;

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

      esac  # end case $action in
      ;;

    $SG_MOUNT )
      # Processing depends on the specified action:
      case $action in
        add )
          :  # There is nothing to do.
          ;;

        update )
          if [[ -n $mountOptions && ${v[$DEV_NAME_Field]} = $deviceName ]]
          then
            # We are changing the mount options for this remote file system.
            v[$RW_OPT_Field]=$sgRW_OPT_Value
            v[$MTIME_OPT_Field]=$sgMTIME_OPT_Value
            v[$ATIME_OPT_Field]=$sgATIME_OPT_Value
            v[$QUOTA_OPT_Field]=$sgQUOTA_OPT_Value
            v[$OTHER_OPT_Field]=$sgOTHER_OPT_Value
          fi

          if [[ -n $remoteClusterName && ${v[$DEV_NAME_Field]} = $deviceName ]]
          then
            # We are changing the home cluster name.
            v[$NODESETID_Field]=$remoteClusterName
          fi
          ;;

        delete )
          [[ -n $deleteThisFileSystem ]] &&  \
            printLine=false
          ;;

        show )
          if [[ -n $displayThisFileSystem ]]
          then
            # Generate the mount options string.
            optionsString="${v[$RW_OPT_Field]}"
            [[ -n ${v[$MTIME_OPT_Field]} ]] &&  \
              optionsString="${optionsString},${v[$MTIME_OPT_Field]}"
            [[ -n ${v[$ATIME_OPT_Field]} ]] &&  \
              optionsString="${optionsString},${v[$ATIME_OPT_Field]}"
            [[ -n ${v[$OTHER_OPT_Field]} ]] &&  \
              optionsString="${optionsString},${v[$OTHER_OPT_Field]}"
            [[ -n ${v[$QUOTA_OPT_Field]} ]] &&  \
              optionsString="${optionsString},quota=${v[$QUOTA_OPT_Field]}"

            # Put out the last two values and finish the line.
            printf " %-16s %s\n" "$optionsString" "$automountSetting"
          fi  # end of if [[ -n $displayThisFileSystem ]]
          ;;

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

      esac  # end case $action in
      ;;

    $REM_CLUSTER )
      [[ ${v[$NODESETID_Field]} = $remoteClusterName ]] &&  \
        remoteClusterFound=yes
      ;;

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

  esac  # end of Change some of the fields

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

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

done  # end while read -u3 mmsdrfsFile

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


if [[ -z $fsFound && $action != add ]]
then
  if [[ (-z $device || $device = all) && ($action = show || $action = delete) ]]
  then
    # There are no remote file systems.
    printErrorMsg 193 $mmcmd
  else
    # Remote file system not found.
    printErrorMsg 194 $mmcmd $device
  fi
  cleanupAndExit
fi  # end of if [[ -z $clusterFound ]]


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

###############################
# If action is "show", return.
###############################
if [[ $action = show ]]
then
  # Return; we are done.
  cleanupAndExit $rc
fi  # end of if [[ $action = show ]]


#######################################################
# If action is "update", perform final error checking.
#######################################################
if [[ $action = update ]]
then
  # If the mount point for a file system is being changed,
  # ensure that the new mount point is not already in use.
  if [[ -n $mountPoint ]]
  then
    for mpnt in $existingMountPoints
    do
      if [[ $mpnt = $mountPoint ]]
      then
        # There is already an existing filesystem using this mountpoint.
        printErrorMsg 107 $mmcmd $mountPoint
        cleanupAndExit
      fi
    done
  fi  # end of if [[ -n $mountPoint ]]

  # If the home cluster for a file system is being changed,
  # ensure that the new cluster is already defined.
  if [[ -n $remoteClusterName && -z $remoteClusterFound ]]
  then
    # The remote cluster is not defined.
    printErrorMsg 263 $mmcmd $remoteClusterName
    cleanupAndExit
  fi

  # If appropriate, put the file system on the list
  # of file systems that should not be mounted.
  if [[ -n $fsMustNotBeMounted ]]
  then
    print -- "$fsFullName $deviceName" >> $mountCheckList
    checkForErrors "writing to file $mountCheckList" $?
  fi
fi  # end of if [[ $action = update ]]


#############################################################################
# If action is "add",  generate the needed information for the mmsdrfs file.
#############################################################################
if [[ $action = add ]]
then
  # Ensure the remote cluster that we need is already defined.
  if [[ -z $remoteClusterFound ]]
  then
    # The remote cluster was not found.
    printErrorMsg 188 $mmcmd $remoteClusterName
    cleanupAndExit
  fi  # end of if [[ -z $remoteClusterFound ]]

  # Determine what the major number should be.
  if [[ $osName = Linux ]]
  then
    checkVfsNumber
    devMajor=$currentMajorNumber
  fi
  [[ -z $devMajor ]] && devMajor=$defaultMajorNumber

  # Assign a minor number to the file system.
  # Keep trying until we get a minor number that is not used by anybody.
  rc=0
  minor=""
  while [[ -z $minor && $rc -eq 0 ]]
  do
    # Assign a minor number to the file system.
    devMinor=$(assignDevMinor "$existingMinorNumbers")
    rc=$?
    if [[ $rc -eq 0 ]]
    then
      # Check whether the new device number is being used by somebody.
      inuse=$($ls -lL /dev 2>/dev/null | $grep "^${fsDeviceType}.* $devMajor, *$devMinor ")
      if [[ -z $inuse ]]
      then
        # The number seems to be free.
        minor=$devMinor
      fi

      # Add the number to the list of existing minor numbers.
      existingMinorNumbers="$existingMinorNumbers $devMinor"

    fi  # end of if [[ $rc -eq 0 ]]
  done  # end of while [[ -z $minor && $rc -eq 0 ]]

  if [[ -z $minor ]]
  then
    print -u2 "$mmcmd:  Cannot assign a minor number for the file system."
    cleanupAndExit
  fi

  # Build the SG-related lines for the new file system.
  # Note: In order to preserve the tab characters in the /etc/filesystems lines,
  #       we temporarily reset the value of the IFS variable to exclude the tab.
  IFS=' '

  newLine="$remoteClusterName:$SG_HEADR:$deviceName::$minor::$remotefs:$remoteDevice"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$MOUNT_POINT_Line:$mountPoint:"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$DEV_Line"
  newLine="$newLine:$DEV_Line_Prefix$fqDeviceName"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$VFS_Line"
  newLine="$newLine:$VFS_Line_Prefix$sgVFS_Line_Value"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$NODENAME_Line"
  newLine="$newLine:$NODENAME_Line_Prefix$sgNODENAME_Line_Value"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$MOUNT_Line"
  newLine="$newLine:$MOUNT_Line_Prefix$sgMOUNT_Line_Value"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$TYPE_Line"
  newLine="$newLine:$TYPE_Line_Prefix$sgTYPE_Line_Value"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_ETCFS:$deviceName:$ACCOUNT_Line"
  newLine="$newLine:$ACCOUNT_Line_Prefix$sgACCOUNT_Line_Value"
  print -- "$newLine" >> $newsdrfs

  newLine="$remoteClusterName:$SG_MOUNT:$deviceName::$sgRW_OPT_Value"
  newLine="$newLine:$sgMTIME_OPT_Value:$sgATIME_OPT_Value"
  newLine="$newLine:$sgQUOTA_OPT_Value:$sgOTHER_OPT_Value:"
  print -- "$newLine" >> $newsdrfs
  checkForErrors "writing to file $newsdrfs" $?

  IFS="$IFS_sv"

fi  # end of if [[ $action = add ]]


#########################################################
# If this is the first automountable GPFS file system,
# run the automount command on the nodes in the cluster.
#########################################################
if [[ $automountValue = "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 [[ $automountValue = "automount" && -z $automountMounts ]]


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


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


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

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


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


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


#########################################################################
# Make the new file system visible to the nodes.  This includes adding
# a stanza to /etc/filesystems and creating the mount point directory.
# If the mount point changed, remove the old mount point.
# This process is asynchronous.
#########################################################################
[[ -n $oldMountPoint && $mountPoint != $oldMountPoint ]] &&  \
  propagateOptions="rmdir$oldMountPoint"

propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber $propagateOptions

cleanupAndExit 0

