#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1998,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 
# @(#)00 1.72 src/avs/fs/mmfs/ts/admin/mmlsfs.sh, mmfs, avs_rgpfs24, rgpfs24s003a 5/18/06 18:48:16
###############################################################################
#
#  List the attributes of a file system.
#
#  Usage:
#    mmlsfs Device [-a] [-A] [-B] [-d] [-D] [-E] [-f] [-F] [-i] [-I] [-j] [-k] [-K]
#                  [-m] [-M] [-n] [-o] [-P] [-Q] [-r] [-R] [-s] [-S] [-T] [-u] [-V]
#                  [-z]
#
#  If Device is "all", then the command displays information for
#  all file systems in the cluster.
#
###############################################################################

# Include global declarations and service routines.
. /usr/lpp/mmfs/bin/mmglobfuncs
if [[ $ourUid -eq 0 ]]
then
  . /usr/lpp/mmfs/bin/mmsdrfsdef
  . /usr/lpp/mmfs/bin/mmfsfuncs
fi

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

# Local work files.  Names should be of the form:
#   fn=${tmpDir}fn.${mmcmd}.$$
if [[ $ourUid -eq 0 ]]
then
  fsToDisplay=${tmpDir}fsToDisplay.${mmcmd}.$$   # file systems to list
else
  fsToDisplay=/tmp/fsToDisplay.${mmcmd}.$$       # use /tmp if not root
fi

LOCAL_FILES=" $fsToDisplay "


# Local variables
integer rc=0
integer nodeCount=0
usageMsg=334
call_tslsfs=no
underline="==================================================================="
underline="${underline}======================================================="


# Local routines

###############################################################
#
# Function:  Return all GPFS file system devices.
#
# Input:     None
#
# Output:    For each file system, print:
#              - the fully-qualified device name
#              - the short local device name
#              - the home cluster name
#              - the remote device name if remote,
#                  otherwise repeat the local device name
#
###############################################################
function getAllFileSystems
{
  typeset sourceFile="mmlsfs.sh"
  [[ -n $DEBUG || -n $DEBUGgetAllFileSystems ]] && set -x
  $mmTRACE_ENTER "$*"

  $awk -F: '                                    \
    /':$SG_HEADR:'/ {                           \
      if ($'$REMOTE_DEV_NAME_Field' == "") {    \
        { print "/dev/"$'$DEV_NAME_Field' " "   \
                $'$DEV_NAME_Field'        " "   \
                $'$NODESETID_Field'       " "   \
                $'$DEV_NAME_Field' }            \
      } else {                                  \
        { print "/dev/"$'$DEV_NAME_Field' " "   \
                $'$DEV_NAME_Field'        " "   \
                $'$NODESETID_Field'       " "   \
                $'$REMOTE_DEV_NAME_Field' }     \
      }                                         \
    }                                           \
  ' $mmsdrfsFile
  checkForErrors awk $?
  return 0

}  #------ end of function getAllFileSystems ----------------



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


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

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

device=$arg1     # Save the stripe group device (always the first parameter).
shift 1          # Drop the device name from the parameter list.


# The option flags can be divided into two categories:
# options handled by the daemon, and non-daemon options.
# If no options are specified, the command displays all options.
if [[ $argc -eq 1 ]]
then
  call_tslsfs=yes
  nonDaemonFlags="-A -o -T"
else
  while getopts :aABdDEfFiIjkKmMnoPQrRsSTuVz OPT
  do
    case $OPT in
      A) # display the automount option
         nonDaemonFlags="$nonDaemonFlags -$OPT"
         ;;
      o) # display the additional mount options
         nonDaemonFlags="$nonDaemonFlags -$OPT"
         ;;
      T) # display the additional mount options
         nonDaemonFlags="$nonDaemonFlags -$OPT"
         ;;
      [aBdDEfFkKiIjmMnPQrRsSVuz])  # Some other valid option was specified.
         call_tslsfs=yes
         daemonFlags="$daemonFlags -$OPT"
         ;;
      +[aABdDEfFiIjkKmMnoPQrRsSTVuz])
         syntaxError "invalidOption" $usageMsg $OPT
         ;;
      *) # invalid option specified
         syntaxError "invalidOption" $usageMsg $OPTARG
         ;;
    esac
  done
  shift OPTIND-1
  [[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1
fi


###################################
# Set up trap exception handling.
###################################
trap pretrap2 HUP INT QUIT KILL


####################################################################
# If invoked by a root user, call the gpfsInit function to ensure
# that the local copy of the mmsdrfs file and the rest of the GPFS
# system files are up-to-date.  There is no need to lock the sdr.
# Non-root users are not allowed to invoke commands on other nodes.
####################################################################
if [[ $ourUid -eq 0 ]]
then
  gpfsInitOutput=$(gpfsInit nolock)
  setGlobalVar $? $gpfsInitOutput
fi


#########################################################################
# If device is the keyword all, create a list of all known file systems.
# Otherwise, ensure the specified file system exists.
#########################################################################
if [[ $device = all ]]
then
  getAllFileSystems > $fsToDisplay
  if [[ ! -s $fsToDisplay ]]
  then
    # No file systems were found.
    printErrorMsg 200 $mmcmd
    cleanupAndExit
  fi
  displayName=yes
else
  # If the invocation is not for an explicitly-remote device, obtain the
  # needed information about the filesystem from the mmsdrfs file.
  if [[ $device != *:* ]]
  then
    findFSoutput=$(findFS "$device" $mmsdrfsFile)
    [[ -z $findFSoutput ]] && cleanupAndExit
    print -- $findFSoutput > $fsToDisplay
    displayName=no
  else
    IFS=":"            # Change the field separator to ':'.
    set -f ; set -- $device ; set +f
    IFS="$IFS_sv"      # Restore the default IFS settings.
    fsHomeCluster=$1
    remoteDevice=$2
    deviceName=${remoteDevice##+(/)dev+(/)}  # name stripped of /dev/ prefix
    fqDeviceName="/dev/$deviceName"    # fully-qualified name with /dev/ prefix
    print -- "$fqDeviceName $deviceName $fsHomeCluster $remoteDevice" > $fsToDisplay
  fi
fi


######################################################
# Process the individual file systems one at a time.
######################################################
exec 3<&-
exec 3< $fsToDisplay
while read -u3 inLine
do
  rc=0
  set -f ; set -- $inLine ; set +f
  fqDeviceName=$1
  deviceName=$2
  fsHomeCluster=$3
  remoteDevice=$4

  # If this is a remote file system, set fqDeviceName appropriately.
  [[ $fsHomeCluster != $HOME_CLUSTER ]] &&  \
    fqDeviceName="$fsHomeCluster:/dev/$remoteDevice"

  ###################################################
  # If more than one file system, display its name.
  ###################################################
  if [[ $displayName = yes ]]
  then
    header=$(printInfoMsg 406 $fqDeviceName)
    printf "\n%s\n%.${#header}s\n" "$header" "$underline"
  fi

  ##################################################################
  # Call tslsfs to handle all options other than -A and -o.
  ##################################################################
  if [[ $call_tslsfs = yes ]]
  then

    # Invoke the command on the local node.
    ${mmcmdDir}/${links}/mmlsfs $fqDeviceName $daemonFlags 2>$errMsg
    rc=$(remapRC $?)

    # If we get an unacceptable error, or if the file system is remote,
    # display any error messages and move to the next file system.
    if [[ ($rc -ne 0 && $rc -ne $MM_DaemonDown && $rc -ne $MM_QuorumWait) ||
          $fsHomeCluster != $HOME_CLUSTER ||
          $ourUid -ne 0  || $MMMODE = single ]]
    then
      if [[ $rc -eq $MM_FsNotFound ]]
      then
        if [[ $fsHomeCluster != $HOME_CLUSTER ]]
        then
          # The remote cluster does not know anything about this file system.
          printErrorMsg 108 $mmcmd $remoteDevice $fsHomeCluster
        else
          # Unexpected error.
          printErrorMsg 171 $mmcmd "file system $deviceName not found" $rc
        fi
      elif [[ $rc -eq $MM_Remotefs && $fsHomeCluster != $HOME_CLUSTER ]]
      then
        # The file system is not owned by the remote cluster.
        [[ $device != *:* && $device != all ]] &&  \
          printErrorMsg 111 $mmcmd $device $remoteDevice $fsHomeCluster
        printErrorMsg 112 $mmcmd $remoteDevice $fsHomeCluster
      elif [[ ($rc -eq $MM_HostDown    ||
               $rc -eq $MM_TimedOut    ||
               $rc -eq $MM_SecurityCfg ||
               $rc -eq $MM_AuthorizationFailed ||
               $rc -eq $MM_UnknownCluster)    &&
              $fsHomeCluster != $HOME_CLUSTER ]]
      then
        # Failed to connect to the remote cluster.
        [[ $rc -eq $MM_SecurityCfg ]] &&  \
          printErrorMsg 150 $mmcmd
        [[ $rc -eq $MM_AuthorizationFailed ]] &&  \
          printErrorMsg 151 $mmcmd
        printErrorMsg 105 $mmcmd $fsHomeCluster
      elif [[ $rc -eq $MM_DaemonDown ]]
      then
        # GPFS is down on this node.
        printErrorMsg 109 $mmcmd
      elif [[ $rc -eq $MM_QuorumWait ]]
      then
        # GPFS is not ready for commands.
        printErrorMsg 110 $mmcmd
      elif [[ $rc -eq $MM_ConnectionReset ]]
      then
        # An internode connection was reset.
        printErrorMsg 257 $mmcmd
      else
        # Either the command worked, or it is an unexpected error.
        [[ -s $errMsg ]] && $cat $errMsg 1>&2
      fi  # end of if [[ $rc -eq $MM_FsNotFound ]]
      $rm -f $errMsg

      # If we failed for some reason, move to the next file system.
      [[ $rc -ne 0 ]] && continue

    fi  # end of if [[ ($rc -ne 0 && $rc -ne $MM_DaemonDown && ... ]]
    $rm -f $errMsg

    #------------------------------------------------------------
    # If we come here, either (1) the mmlsfs command succeeded
    # or (2) the mmlsfs command failed for a local file system
    # when the local daemon is down or is waiting for quorum.
    #
    # If (1), the command succeeded, skip the rest of this if
    # statement and continue processing the non-daemon flags.
    #
    # If (2), the command failed, try running it on some other
    # node.  Note that we will never get here with a non-zero
    # return code if we do not have root priviledges, or if this
    # is not a local file system, or if cluster type is single.
    #------------------------------------------------------------

    if [[ $rc -ne 0 ]]
    then
      # The command failed due to daemon down or lack of quorum.
      # Find an active node and send the command there.

      # Create a file with the reliable names that form the local cluster
      # to which the file system belongs.
      nodeCount=$(getNodeFile $REL_HOSTNAME_Field $fsHomeCluster $mmsdrfsFile $nodefile)
      if [[ $nodeCount -eq 0 ]]
      then
        # The local cluster is empty; there is nobody to run the command.
        printErrorMsg 171 $mmcmd "getNodeFile (nodeCount=0)" 1
        continue
      fi

      # Try the nodes one by one until you find a node
      # that can execute the command.
      preferredNode=0     # No idea where to go first; let mmcommon decide.
      $mmcommon linkCommand  \
        $preferredNode $nodefile mmlsfs $fqDeviceName $daemonFlags
      rc=$?
      if [[ $rc -eq $MM_ConnectionReset ]]
      then
        # An internode connection was reset.
        printErrorMsg 257 $mmcmd
      fi

      # If we failed for some reason, move to the next file system.
      [[ $rc -ne 0 ]] && continue

    fi  # end of if [[ $rc -ne 0 ]]
  fi  # end of if [[ $call_tslsfs = yes ]]

  # If no non-daemon options requested, we are done.
  [[ -z $nonDaemonFlags ]] && continue

  # If tslsfs was not invoked, print the header for the mmlsfs output.
  [[ $call_tslsfs = no ]] && printInfoMsg 179

  # Get the values for the requested non-daemon options from the mmsdrfs file.
  for flag in $(print -- $nonDaemonFlags)
  do
    case $flag in

      -A ) # Find the value of the automount option.
         mountOpt=$($grep -e  \
           "$fsHomeCluster:$SG_ETCFS:$deviceName:$MOUNT_Line:" $mmsdrfsFile |  \
           $GETVALUE $ETCFS_TEXT_Field)
         set -f ; set -- $mountOpt ; set +f
         automountOption=$3
         if [[ $automountOption = mmfs ]]
         then
           flagValue=yes
         elif [[ $automountOption = false ]]
         then
           flagValue=no
         else
           # must be "automount"
           flagValue=$automountOption
         fi
         printf " %s  %-14s " $flag $flagValue
         printInfoMsg 331   # "Automatic mount option"
         ;;

      -o ) # Find the additional mount options, if any.
         otherOptions=$($grep -e  \
           "$fsHomeCluster:$SG_MOUNT:$deviceName:" $mmsdrfsFile |  \
           $GETVALUE $OTHER_OPT_Field)
         [[ $otherOptions = "" ]] && \
           otherOptions="none"

         printf " %s  %-14s " $flag $otherOptions
         printInfoMsg 519   # "Additional mount options"
         ;;

      -T ) # Find the mount point pathname.
         mountPoint=$($grep -e  \
           "$fsHomeCluster:$SG_ETCFS:$deviceName:$MOUNT_POINT_Line:" $mmsdrfsFile |  \
           $GETVALUE $ETCFS_TEXT_Field)
         printf " %s  %-14s " $flag $mountPoint
         printInfoMsg 559   # "Default mount point"
         ;;

      * )  # Unknown flag; this should never happen.
        printErrorMsg 13 "$mmcmd" $flag
        checkForErrors "bad nonDaemonFlags value" 1
        ;;
    esac
  done   # end of for flag in $(print -- $nonDaemonFlags)

done  # end of while read -u3 inLine

cleanupAndExit $rc

