#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2005,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 
# @(#)45 1.9.1.2 src/avs/fs/mmfs/ts/admin/mmlsfileset.sh, mmfs, avs_rgpfs24, rgpfs24s005a 6/14/06 14:40:28
################################################################################
#
# Usage:
#   mmlsfileset Device [[FilesetNameList] [-J JunctionPathList]] | -F FileName]
#                       [-L] [-d] [-i]
#
# where:
#   Device            is the device name of the file system.
#
#   FilesetNameList   is a comma-separated list of fileset names.
#
#   JunctionPathList  is a comma-separated list of junction path names.
#
#   FileName          is the name of a file containing either fileset
#                     names or junction path names.  Each line must contain
#                     a single entry.  All junction path names must be fully
#                     qualified path names.
#
#   -L                display extended information (fileset id, parent, etc.)
#
#   -d                display the number of blocks in use.
#
#   -i                display the number of i-nodes in use.
#
# Undocumented option:
#   -s                display a list of snapshots for this fileset.
#
################################################################################

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

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

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

LOCAL_FILES=" $filesetFile "


# Local variables
usageMsg=518


# Local functions



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


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

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

# The first argument is always the file system name.
device=$arg1
deviceName=${device##+(/)dev+(/)}  # name stripped of /dev/ prefix
fqDeviceName="/dev/$deviceName"    # fully-qualified name (with /dev/ prefix)

# The device name may be followed by a fileset name list
# and a -J junction name list, or -F and a file name.
if [[ -n $arg2 && $arg2 != "-"* ]]
then
  # A fileset list was specified which may or
  # may not be followed by a junction list.
  filesetNameList=$arg2
  if [[ $arg3 = "-J"* ]]
  then
    # The fileset list is followed by a junction list.
    junctionPathList=${arg3#-J}
    if [[ -z $junctionPathList ]]
    then
      [[ $argc -lt 4  ]] && syntaxError "missingArgs" $usageMsg
      junctionPathList=$arg4
      shift 4
    else
      shift 3
    fi
  else
    # The fileset list is not followed by a junction list.
    shift 2
  fi

elif [[ $arg2 = "-J"* ]]
then
  # Only a junction list is specified.
  junctionPathList=${arg2#-J}
  if [[ -z $junctionPathList ]]
  then
    [[ $argc -lt 3  ]] && syntaxError "missingArgs" $usageMsg
    junctionPathList=$arg3
    shift 3
  else
    shift 2
  fi

elif [[ $arg2 = "-F"* ]]
then
  # A file name is specified; fileset and/or junction lists are not allowed.
  userFilesetFile=${arg2#-F}
  if [[ -z $userFilesetFile ]]
  then
    [[ $argc -lt 3  ]] && syntaxError "missingArgs" $usageMsg
    userFilesetFile=$arg3
    shift 3
  else
    shift 2
  fi

else
  # No file name and no fileset and/or junction lists are specified.
  shift 1
fi


# Process the rest of the parameters.
while getopts :diLs OPT
do
  case $OPT in
    d) # Display number of blocks in use.
       [[ -n $dflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       dflag="-$OPT"
       ;;

    i) # Display number of inodes in use.
       [[ -n $iflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       iflag="-$OPT"
       ;;

    L) # Display extended information.
       [[ -n $Lflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Lflag="-$OPT"
       ;;

    s) # Display the snapshots of the fileset.
       [[ -n $sflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       sflag="-$OPT"
       ;;

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

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

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

  esac
done  # end of while getopts :diLs OPT do
shift OPTIND-1

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


# If a fileset list was specified, parse it and
# put the names in a file.
$rm -f $filesetFile
if [[ -n $filesetNameList ]]
then
  IFS=','
  set -f
  for filesetName in $filesetNameList
  do
    print -- "$filesetName" >> $filesetFile
    checkForErrors "writing to $filesetFile" $?
  done
  set +f
  IFS="$IFS_sv"
fi  # end of if [[ -n $filesetNameList ]]

# If a junction list was specified, parse it and
# put the fully-qualified path names in a file.
if [[ -n $junctionPathList ]]
then
  IFS=','
  set -f
  for junctionName in $junctionPathList
  do
    [[ $junctionName != /* ]] && junctionName="${PWD%/}/${junctionName}"
    print -- "$junctionName" >> $filesetFile
    checkForErrors "writing to $filesetFile" $?
  done
  set +f
  IFS="$IFS_sv"
  junctionsSpecified=yes
fi  # end of if [[ -n $junctionPathList ]]

# If a file was specified, ensure the file exists and create our own copy.
if [[ -n $userFilesetFile ]]
then
  checkUserFile $userFilesetFile $filesetFile
  [[ $? -ne 0 ]] && cleanupAndExit

  # See if this file contains junction path names.
  $grep -q "^/" $filesetFile > /dev/null 2>&1
  [[ $? -eq 0 ]] && junctionsSpecified=yes
fi  # end of if [[ -n $userFilesetFile ]]


#####################################################################
# Set up trap exception handling and ensure that the local copy of
# the mmsdrfs is up-to-date.  There is no need to lock the mmsdrfs.
#####################################################################
trap pretrap2 HUP INT QUIT KILL
gpfsInitOutput=$(gpfsInit nolock)
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 if the command was invoked for a remote file system.
if [[ $fsHomeCluster != $HOME_CLUSTER ]]
then
  # The command is not allowed for remote file systems.
  printErrorMsg 106 $mmcmd $device $fsHomeCluster
  cleanupAndExit
fi


#############################
# Verify the junction names.
#############################
if [[ -n $junctionsSpecified ]]
then
  # The file system must be mounted.
  mountPoint=$(findMountpoint $deviceName)
  if [[ -z $mountPoint ]]
  then
    # The file system is not mounted.
    printErrorMsg 552 $mmcmd $device
    cleanupAndExit
  fi

  # Find the device ID of the mounted GPFS file system.
  gpfsDeviceID=$($perl -e '($dev) = stat "'$mountPoint'"; printf "%u", $dev;')

  # Scan the entries in the file.  If a junction path name is found,
  # ensure the junction is within the mounted file system.
  exec 3< $filesetFile
  while read -u3 name
  do
    # Skip empty lines.
    [[ $name = *([$BLANKchar$TABchar]) ]] && continue

    if [[ $name = /* ]]
    then
      # This is a junction path name.

      # Find the device ID and inode number of the junction.
      # The result is a colon-separated device and inode numbers.
      junctionDevAndIno=$($perl -e ' ($dev,$ino) = stat "'$name'";
                                     if ($dev ne "") { printf "%u:%u", $dev,$ino }')

      # The junction must be within the mounted file system.
      if [[ $gpfsDeviceID != ${junctionDevAndIno%:*} ]]
      then
        printErrorMsg 550 $mmcmd $name $device
        fatalError=yes
      else
        # Things look OK.  Create the extended junction path name.
        name="/GPFS:${junctionDevAndIno#*:}${name}"
      fi
    fi  # end of if [[ $name = /* ]]

    # Put the verified name in a temp file.
    print -- "$name" >> $tmpfile
    checkForErrors "writing to $tmpfile" $?

  done  # end while read -u3 name

  # Give up if there are errors.
  [[ -n $fatalError ]] && cleanupAndExit

  $mv $tmpfile $filesetFile
  checkForErrors "mv $tmpfile $filesetFile" $?
fi  # end of if [[ -n $junctionsSpecified ]]


########################################################################
# Invoke the tslsfileset command on the local node.
# Display any error messages and exit if any of the following are true:
#   - the command completed successfully
#   - a junction path name is specified
#   - there is an unacceptable error
#       (anything other than daemon down or quorum wait)
#   - this is a single node cluster
########################################################################
if [[ -s $filesetFile ]]
then
  $tslsfileset $fqDeviceName -F $filesetFile $Lflag $dflag $iflag $sflag 2>$errMsg
  rc=$(remapRC $?)
else
  $tslsfileset $fqDeviceName $Lflag $dflag $iflag $sflag 2>$errMsg
  rc=$(remapRC $?)
fi

if [[ $rc -ne $MM_DaemonDown && $rc -ne $MM_QuorumWait ||
      -n $junctionsSpecified || $MMMODE = single ]]
then
  if [[ $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
#   [[ $rc -ne 0 ]] && printErrorMsg 113 "$mmcmd" "tslsfileset" $rc
  fi  # end of if [[ $rc -eq $MM_FsNotFound ]]
  cleanupAndExit $rc
fi  # end of if [[ ($rc -ne $MM_DaemonDown && ... ]]
$rm -f $errMsg


####################################################################
# We come here if the local GPFS daemon is not ready for commands.
# Find an active node and send the command there.
####################################################################

# Create a file with the reliable names of the nodes in the cluster.
getNodeList $REL_HOSTNAME_Field $GLOBAL_ID $mmsdrfsFile > $nodefile
preferredNode=$ourNodeName

# Try the nodes one by one until you find a node that can execute the command.

##################################
# Invoke the tslsfileset command.
##################################
if [[ -s $filesetFile ]]
then
  $mmcommon onactive $preferredNode $nodefile    \
     $filesetFile $NO_MOUNT_CHECK NULL $NO_LINK  \
     tslsfileset "$fqDeviceName -F $filesetFile $Lflag $dflag $iflag $sflag"
  rc=$?
else
  $mmcommon onactive $preferredNode $nodefile     \
     $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK  \
     tslsfileset "$fqDeviceName $Lflag $dflag $iflag $sflag"
  rc=$?
fi  # end of if [[ -s $filesetFile ]]

# if [[ $rc -ne 0 ]]
# then
#   # tslsfileset failed.
#   printErrorMsg 104 $mmcmd tslsfileset
#   cleanupAndExit $rc
# fi

cleanupAndExit $rc

