#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2002,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 
# @(#)65 1.25.1.2 src/avs/fs/mmfs/ts/admin/mmbackup.sh, mmfs, avs_rgpfs24, rgpfs24s005a 6/14/06 14:39:45
##############################################################################
#
# Usage:
#
#   mmbackup Device -n ControlFile [-t {full | incremental}] [-r IOrate]
#                     [-s sortDir] [-T]
#
#     or
#
#   mmbackup Device -R [-r IOrate] [-s sortDir] [-T]
#
# where:
#
#   -n ControlFile         is a file containing information for controlling
#                          the backup; this parameter is optional if mmbackup
#                          was run previously, in which case the values from
#                          the prior control file remain in effect if -n
#                          is not specified
#
#   -r IOrate              an integer between 1 and 100 specifying how much
#                          I/O bandwidth to allocate to the backup process
#                          (the larger the number, the larger the allocated
#                          bandwidth; default is 100)
#
#   -t full | incremental  type of backup; default is incremental
#
#   -R                     resume backing up files which failed to be
#                          backed up on the previous invocation of mmbackup
#
#   -T                     enable tracing
#
#   -s sortDir             sort temporary directory name (default /tmp)
#
##############################################################################

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

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


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

tmpCtrlFile=${tmpDir}tmpCtrlFile.mmbackup.$$
LOCAL_FILES=" $tmpCtrlFile "


# Local variables

usageMsg=458
integer rc=0
integer nodeCount=0
integer n
backupControlFile=".mmbuControl"

typeset -i freeSpace


# Local routines


##########################################################################
#
# Function:  Get the amount of unused space in the specified file system.
#
# Input:     $1 - file system dev name or name of a file or directory
#
# Output:    the number of unused 1K blocks in the filesystem
#
# Returns:   0
#
##########################################################################
function getFreeSpace  # { <fileSytem> | <fileName> }
{
  typeset sourceFile="mmbackup.sh"
  [[ -n $DEBUG || -n $DEBUGgetFreeSpace ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset fileSystem=$1

  typeset dfInfo
  typeset -i freeBlocks

  [[ -z $fileSystem ]] && \
    checkForErrors "getFreeSpace: missing file system parameter" 1

  # Issue the df command, requesting info in Posix format and 1K blocks.
  LC_ALL=C $df -P -k $fileSystem > $tmpfile

  # Read and discard the first line (the header).
  exec 3<&-
  exec 3< $tmpfile
  $rm -f $tmpfile
  read -u3 dfInfo

  # Read and extract the desired info from the second line.
  read -u3 dfInfo
  set -f ; set -- $dfInfo ; set +f
  freeBlocks=$4

  # Return the result.
  print -- "$freeBlocks"
  return 0

}  #--------- end of function getFreeSpace ------------------



######################
# 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 file system name (always the first parameter).
shift 1          # Drop the device name from the parameter list.

while getopts :n:r:RTt:s: OPT
do
  case $OPT in

    n) # input control file
       [[ -n $nflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       nflag="-$OPT"; narg=$OPTARG;
       [[ -n $Rflag ]] && \
         syntaxError "invalidCombination" $usageMsg "-n" "-R"
       ;;

    r) [[ -n $rflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       rflag="-$OPT"; rarg=$OPTARG;
       # Ensure that rarg is an integer, and that its value is from 1 to 100.
       n=$(checkIntRange $rflag $rarg 1 100)
       [[ $? -ne 0 ]] && cleanupAndExit
       ;;

    s) [[ -n $sflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       sflag="-$OPT"; sarg=$OPTARG;
       ;;

    R) [[ -n $Rflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Rflag="-$OPT";
       [[ -n $nflag ]] && \
         syntaxError "invalidCombination" $usageMsg "-n" "-R"
       [[ -n $tflag ]] && \
         syntaxError "invalidCombination" $usageMsg "-t" "-R"
       ;;

    t) [[ -n $tflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       tflag="-$OPT"; targ=$OPTARG;
       [[ $targ != full && $targ != incremental ]] && \
         syntaxError "invalidOption" $usageMsg "-$OPT $OPTARG"
       [[ -n $Rflag ]] && \
         syntaxError "invalidCombination" $usageMsg "-t" "-R"
       ;;

    T) Tflag="-T";
       ;;

    +[n,r,s,R,t]) # 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

# Complete the parameter checking and set defaults.
[[ -z $nflag && -z $Rflag ]] && \
  syntaxError "missingArgs" $usageMsg

[[ -z $rarg ]] && rarg=100
rOption="-r $rarg"

if [[ -z $targ ]]
then
  if [[ -z $Rflag ]]
  then
    tOption="-t incremental"
  else
    tOption=""
  fi
else
  tOption="-t $targ"
fi

sOption=""
if [[ -n $sarg ]]
then
  if [[ ! -d  $sarg ]]
  then
    # The sort temp dir does not exist.  Issue an error and quit.
    printErrorMsg 574 $mmcmd $sarg
    cleanupAndExit
  fi
  sOption="-s $sarg"
fi


#######################################################
# Make sure there is a reasonable amount of free space
# in the /var/mmfs filesystem.  This is needed so that
# TSM can create error logs in /var/mmfs/mmbackup.
#######################################################
freeSpace=$(getFreeSpace $mmbackupDir)
if [[ $freeSpace -lt 100 ]]
then
  # The filesystem is not mounted.  Issue an error and quit.
  printErrorMsg 572 $mmcmd $mmbackupDir "100K"
  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.  There is no need to lock the sdr.
########################################################################
trap pretrap2 HUP INT QUIT KILL
gpfsInitOutput=$(gpfsInit nolock)
setGlobalVar $? $gpfsInitOutput

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


#######################################################
# Make sure the file system exists, that it is part of
# this node's cluster, and that it is mounted.
#######################################################
findFSoutput=$(findFS "$device" $mmsdrfsFile)
[[ -z $findFSoutput ]] && cleanupAndExit

# Parse the output from the findFS function.
set -f ; set -- $findFSoutput ; set +f
fqDeviceName=$1
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 1
fi

# Obtain the name of the file system (i.e., the mount point).
mountPoint=$(findMountpoint $fqDeviceName)
if [[ $mountPoint = "" ]]
then
  # The filesystem is not mounted.  Issue an error and quit.
  printErrorMsg 563 $mmcmd $device $ourNodeName
  cleanupAndExit
fi


##########################################################
# Check that the control file, if specified, makes sense.
##########################################################
if [[ -z $narg ]]
then
  nOption=""
else
  # Verify the existence of the user specified control file
  # and create our own copy.
  checkUserFile $narg $tmpCtrlFile
  [[ $? -ne 0 ]] && cleanupAndExit

  # Set nOption to pass the control file to tsbackup.
  nOption="-n $tmpCtrlFile"

  # Check whether the backup clients specified in the control file
  # belong to the cluster.
  foundError=false
  IFS_sv="$IFS"  # Save the IFS variable.
  exec 3<&-
  exec 3< $tmpCtrlFile
  while read -u3 inputLine
  do
    IFS="="
    set -f ; set -- $inputLine ; set +f
    lineType=$1
    lineValue=$2
    IFS="$IFS_sv"  # Restore the IFS variable.
    if [[ $lineType = clientName ]]
    then
      # Find the IP address that corresponds to this node name.
      hostResult=$($host $lineValue)
      set -f ; set -- $hostResult ; set +f
      ipa=${3%%,*}           # Exclude everything after the first comma.
      if [[ -z $ipa ]]
      then
        # An invalid node name was specified as a client.
        printErrorMsg 54 $mmcmd $lineValue
        foundError=true
      fi
      nodeName=$(getNodeInfo  \
                   $REL_HOSTNAME_Field $IPA_Field $ipa $nsId $mmsdrfsFile)
      if [[ -z $nodeName ]]
      then
        # The specified client node is not a member of the GPFS cluster.
        printErrorMsg 290 $mmcmd $lineValue
        foundError=true
      fi
    fi
  done  # end while read -u3 fileName

  # If an error was found, print a "command failed" message and exit.
  if [[ $foundError = true ]]
  then
    printErrorMsg 389 $mmcmd
    cleanupAndExit
  fi
fi


################################################################
# If an incremental or a resume backup was specified, make sure
# there is a readable backup control file from a prior backup.
################################################################
if [[ $targ = incremental || -n $Rflag ]]
then
  myBackupCtrlFile="$mountPoint/$backupControlFile"
  if [[ ! -f $myBackupCtrlFile || ! -r $myBackupCtrlFile ]]
  then
    # Can't find or read the backup control file from a prior backup.
    printErrorMsg 565 $mmcmd $myBackupCtrlFile
    cleanupAndExit
  fi
fi


####################################
# Invoke tsbackup to do the backup.
####################################
$tsbackup $fqDeviceName $mountPoint $nOption $rOption $tOption $Rflag $Tflag $sOption
rc=$?
if [[ $rc -ne 0 ]]
then
  # The command failed.
  printErrorMsg 389 $mmcmd
else
  # The command completed successfully.
  printInfoMsg 272 $mmcmd
fi

cleanupAndExit $rc

