#!/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 
# @(#)93 1.1.1.3 src/avs/fs/mmfs/ts/admin/mmsdrrestore.sh, mmfs, avs_rgpfs24, rgpfs240610b 2/17/06 16:51:07
##############################################################################
#
# Ensure that the GPFS system files on the specified nodes are at the
# most recent level.  If the local mmsdrfs file is missing, use the file
# specified with the -F option from the node specified with the -p option.
#
# Usage:
#   mmsdrrestore [-p NodeName] [-F mmsdrfsFile] [-R remoteFileCopyCommand]
#                [-a | -N {Node[,Node...] | NodeFile | NodeClass}]
#
# where:
#   -p NodeName        specifies the node from which to obtain a valid
#                      mmsdrfs file.  This should be either the primary
#                      configuration server or a node that contains a
#                      valid backup copy of the mmsdrfs file.
#                      If not specified, the local node is assumed.
#
#   -F mmsdrfsFile     specifies the pathname of the mmsdrfs file to use.
#                      If not specified, /var/mmfs/gen/mmsdrfs is assumed.
#
#   -R remoteFileCopyCommand  specifies the fully-qualified pathname for
#                      the remote file copy program to be used for staging
#                      the mmsdrfs file.  The default is /usr/bin/rcp.
#
# Future options:
#   -a                 Restore all nodes in the GPFS cluster.
#
#   -N Node,Node,...   specifies the affected nodes in a list or in a file.
#   -N NodeFile        NodeClass may be one of several possible node classes
#   -N NodeClass       (e.g., quorumnodes, managernodes, nsdnodes, etc.)
#
# Notes:
#   If not explicitly specified otherwise, only the local node is affected.
#
#   If the -p and/or -F parameters are specified, i.e., if the local mmsdrfs
#   file will be replaced, the command must be first run on the primary and
#   backup cluster configuration servers.
#
#   If the local mmsdrfs file is going to be replaced, the command saves
#   the original file as /var/mmfs/gen/mmsdrfs.mmsdrrestore.backup
#
#   The -R option has to be specified only if the mmsdrfs file needs to be
#   copied from a different node and the cluster was set to use ssh/scp.
#   Once the correct mmsdrfs file is staged, the rest of the code will use
#   the remote commands that have been defined for the cluster.  In other
#   words, you can not change the remote shell and file copy programs with
#   the mmsdrrestore command; use mmchcluster for this purpose once the
#   cluster has been restored.
#
##############################################################################

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

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


# Local variables

usageMsg=284
rc=0


# Local routines


#####################################################################
#
# Function:  Verifies that a command executed successfully.  If the
#            return code from the command is not zero, the function
#            issues a message, restores the original mmsdrfs file,
#            and exits.
#
# Input:     $1 - text to be printed in the message
#            $2 - return code from the execution of the command
#
#####################################################################
function checkForErrorsAndRestoreOldFile
{
  sourceFile="mmsdrrestore.sh"
  [[ -n $DEBUG || -n $DEBUGcheckForErrorsAndRestoreOldFile ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset msgSub=$1
  typeset rc=$2

  if [ $rc != "0" ]
  then
    # If asked, issue an "unexpected error" message.
    [[ $msgSub != NOMSG ]] &&  \
      printErrorMsg 171 "$mmcmd" "$msgSub" $rc

    # Remove the mmsdrfs file if it was copied from another place.
    [[ -n $userProvidedFile ]] &&  \
      $rm -f $mmsdrfsFile

    # Restore the original mmsdrfs file.
    [[ -f ${mmsdrfsFile}.${mmcmd}.backup ]] &&  \
      $mv -f ${mmsdrfsFile}.${mmcmd}.backup $mmsdrfsFile

    cleanupAndExit $2
  fi

}  #------ end of function checkForErrorsAndRestoreOldFile -------



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


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

while getopts :aF:N:p:R: OPT
do
  case $OPT in
    a) [[ -n $aflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       aflag="-$OPT"
       [[ -n $Nflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg $aflag $Nflag
       syntaxError "invalidOption" $usageMsg $OPT  #esjx option not allowed yet
       ;;

    F) # source mmsdrfs file
       [[ -n $Farg ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Farg=$OPTARG
       ;;

    N) [[ -n $Nflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Nflag="-$OPT"
       nodenames="$OPTARG"
       [[ -n $aflag ]] &&  \
         syntaxError "invalidCombination" $usageMsg $Nflag $aflag
       syntaxError "invalidOption" $usageMsg $OPT  #esjx option not allowed yet
       ;;

    p) # primary server
       [[ -n $parg ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       parg=$OPTARG
       ;;

    R) # remote file copy command
       [[ -n $Rarg ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
       Rarg=$OPTARG
       [[ $Rarg != /* ]] &&  \
         syntaxError "absolutePath_2" $noUsageMsg "-$OPT" "$OPTARG"
       ;;

    :) syntaxError "missingValue" $usageMsg $OPTARG
       ;;

    +[aFNpR])
       syntaxError "invalidOption" $usageMsg "$OPT"
       ;;

    *) syntaxError "invalidOption" $usageMsg $OPTARG
       ;;

  esac
done  # end of while getopts :afF:N:p:r:R: OPT do

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


###########################################################
# Process the optional remote file copy command parameter.
###########################################################
if [[ -n $Rarg ]]
then
  if [[ ! -x $Rarg ]]
  then
    # The specified remote file copy command is incorrect
    # (it is not an executable).
    printErrorMsg 423 $mmcmd ${Rarg%% *}
    cleanupAndExit
  fi
  rcp="$Rarg"
  export GPFS_rcpPath="$rcp"
fi


###################################################################
# If an mmsdrfs file exists and we are told not to use it, create
# a backup of the local mmsdrfs file before proceding any further.
###################################################################
if [[ ( -n $parg || -n $Farg && $Farg != $mmsdrfsFile ) && -f $mmsdrfsFile ]]
then
  $cp $mmsdrfsFile ${mmsdrfsFile}.${mmcmd}.backup
  checkForErrors "cp $mmsdrfsFile ${mmsdrfsFile}.${mmcmd}.backup" $?
fi


##############################################################
# If we are told where to find the good mmsdrfs file, get it.
##############################################################
sourceNode=$parg
sourceFile=$Farg
[[ -z $sourceFile ]] && sourceFile=$mmsdrfsFile

if [[ -n $parg ]]
then
  # The file must be copied from a remote node.
  isNodeReachable $sourceNode
  if [[ $? -ne 0 ]]
  then
    # The node is not reachable.
    printErrorMsg 340 $mmcmd $sourceNode
    checkForErrorsAndRestoreOldFile NOMSG 1
  fi

  rcpResult=$(LC_ALL=C $rcp ${sourceNode}:${sourceFile} $mmsdrfsFile 2>&1)
  rc=$?
  if [[ $rc -ne 0 ]]
  then
    # If there was no need to copy the file, that's fine.
    print -- "$rcpResult" | $grep -e "refer to the same file" >/dev/null
    if [[ $? -ne 0 ]]
    then
      # Show the error from the rcp command and give up.
      print -u2 "$rcpResult"
      checkForErrorsAndRestoreOldFile  \
        "$rcp ${sourceNode}:${sourceFile} $mmsdrfsFile" $rc
    fi
  fi  # end of if [[ $rc -ne 0 ]]
  userProvidedFile=yes

elif [[ $sourceFile != $mmsdrfsFile ]]
then
  # The file must be copied from some other place within the local node.
  $cp $sourceFile $mmsdrfsFile
  checkForErrorsAndRestoreOldFile "cp $sourceFile $mmsdrfsFile" $?
  userProvidedFile=yes

else
  : # The local mmsdrfs file is supposed to be good.
fi  # end of if [[ -n $parg ]]

# At this point we must have an mmsdrfs file to work with.
if [[ ! -f $mmsdrfsFile ]]
then
  # Either the node does not belong to a cluster
  # or the config information is lost/corrupted.
  printErrorMsg 282 $mmcmd
  checkForErrors "$mmcmd: Missing /var/mmfs/gen/mmsdrfs" 1
fi

# If this is a user-specified mmsdrfs file, perform a quick sanity check.
if [[ -n $userProvidedFile ]]
then
  checkSdrfsFile $mmsdrfsFile
  checkForErrorsAndRestoreOldFile "$mmcmd: Invalid input file" $?
fi


########################################################################
# See if this node belongs to the cluster defined by this mmsdrfs file.
########################################################################
# Remove the local mmfsNodeData file.  We will derive the information
# based on the currently active IP addresses of the node.
$rm -f $mmfsNodeData

# Determine the node's GPFS node number by checking all local addresses.
nodeData=$(guessLocalNodeNumber)
rc=$?
set -f ; set -- $nodeData ; set +f
ourNodeNumber=$1
ourNodeName=$3

if [[ -z $ourNodeNumber ]]
then
  # The node does not appear to belong to the cluster rpresented
  # by this mmsdrfs file.  Either the file is from a different
  # cluster, or not all adapter interfaces have been activated.
  # Or the node indeed is not part of the cluster.

  # Determine the name of the source file for the message.
  sdrfs="$sourceFile"
  [[ -n $sourceNode ]] && sdrfs="${sourceNode}:${sourceFile}"

  # There is no record for this node in the file.
  printErrorMsg 283 $mmcmd $sdrfs
  checkForErrorsAndRestoreOldFile NOMSG 1
fi


#############################################################################
# At this point, the current mmsdrfs file is assumed to be the correct one.
# The code continues with the standard gpfsInit processing.  This means
# that the primary or backup servers, as per the current mmsdrfs file,
# will be consulted to ensure this is indeed the latest version of the file.
#############################################################################
# Remove the current versions of the system files to force the environment
# to be rebuilt based on the information in the new mmsdrfs file.
$rm -f $mmfscfgFile $mmfsNodeData ${mmfsEnvLevel}+([0-9])  \
       ${mmfsNewKeyLevel}+([0-9]) ${mmfsCommittedKeyLevel}+([0-9])  \
       $nsdpvol


########################################################################
# 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


###########################################################
# Ensure the sdrserv daemon is running on this node only
# if the node is a primary or backup configuration server.
###########################################################
killSdrServ >/dev/null 2>&1
[[ $ourNodeName = $primaryServer || $ourNodeName = $backupServer ]] &&  \
  startSdrServ CURRENT

# The node was successfully restored.
printErrorMsg 285 $mmcmd $ourNodeName

# Done for now.  The -a and -N options are not implemented yet.
cleanupAndExit 0


#######################################################
# Create a file containing all of the affected nodes.
#######################################################
if [[ -n $aflag ]]
then
  # Get a list of all nodes in the cluster.
  getNodeList $REL_HOSTNAME_Field $GLOBAL_ID $mmsdrfsFile > $nodefile

elif [[ -n $Nflag ]]
then
  # Convert the passed data into a file containing admin node names.
  createVerifiedNodefile $nodenames $REL_HOSTNAME_Field no $nodefile
  [[ $? -ne 0 ]] && cleanupAndExit

else
  : # Only the local node is affected.
fi  # end of if [[ -n $aflag ]]


# Ensure we have the proper credentials.
[[ $getCredCalled = no ]] && getCred


#esjxx - If more than one node is involved AND a new mmsdrfs file was copied,
#esjxx   push the file to the rest of the affected nodes.  This will be done
#esjxx   with a new mmremote call that will take care of mmsdrserv as well.
#esjxx   We will need to pass the names of the primary and backup servers
#esjxx   and clusterID to ensure that the individual nodes will go to the
#esjxx   right place for the correct version of the mmsdrfs file.
#esjxx   If the individual nodes have different information, they should go
#esjxx   to the correct primary only and specify current gen number 0 or 1.
#esjxx   This should apply to the backup too ???


##########################
# Restore the GPFS nodes.
##########################
if [[ ! -s $nodefile ]]
then
  : # This is a request to restore only the local node.  We are done.
else
  # This is a request to restore other nodes as well.
  $mmcommon onall $nodefile $unreachedNodes cfg -f
  rc=$?
fi  # end of if [[ ! -s $nodefile ]]

# If any nodes could not be reached, tell the user which ones.
if [[ -s $unreachedNodes ]]
then
  # The following nodes could not be reached: . . .
  printErrorMsg 270 $mmcmd
  $cat $unreachedNodes 1>&2
fi

cleanupAndExit $rc

