#!/bin/sh
#-------------------------------------------------------------------------------
# restorehdr.sh
# 
# This shell script is invoked to perform a copy of a remote server's HMC critical
# backup archive file (HMCBackup*.tgz) to this HMC's /dump directory.
#
# Based on the arguements passed into this program, the program will attempt to
# either mount a remote system or ftp from that system.
# 
# Usage: restorehdr <type>         (0 = NFS/Samba, 1 = ftp)
#                   <archive name> (HMCBackup*.tgz)
#
#                   if type 0...
#                   <server>        (remote server name)
#                   <resource>      (remote server resource)
#                   <fstype>        (file system type)
#                   <options>       (other 'mount' command options)
#
#                   if type 1...
#                   <server>        (remote ftp server)
#                   <userID>        (userID for ftp access)
#                   <password>      (password for ftp access)
#
# Return Codes:
# 1 - error locating required backup log directory
# 2 - unable to start portmap
# 8 - invalid backup type (not 0, 1, or 2)
# 10 - NFS error mounting remote filesystem
# 11 - NFS error, file could not be written to mounted filesystem
# 12 - NFS error, could not switch to target directory for file copy
# 21 - ftp, not logged in
# 22 - ftp, generic login failed
# 23 - ftp, connection refused
# 24 - ftp, unknown remote host
# 25 - ftp, not connected
# 26 - ftp, permission denied
# 27 - ftp, other error(s)
# 28 - ftp, could not switch to target directory for file transfer

#-------------------------------------------------------------------------------
# directory and filename which records the backup actions.
#-------------------------------------------------------------------------------
LOGDIR=/var/hsc/log
LOG=$LOGDIR/restorehdr.log
   
LOG_ERROR_LOG=/tmp/restorehdr.log
MOUNT_OUTPUT=/tmp/mountInfo



# common exit point for script
exit_cleanup() {
    rm -f $MOUNT_OUTPUT
    
    # this temp working file may or may not exist. Ensure it is removed prior to exiting
    rm -f /var/hsc/log/ftp.log
    
    if [ $1 -eq 0 ]; then
        # set indicator flag file noting a restore should be done on next reboot
        mount -v /mnt/upgrade >> $LOG 2>&1
        if [ $? -ne 0 ]; then
	    echo "unable to mount upgrade partiton to set indicator file, rc = $?" >> $LOG
	    echo "Offload of critical system data completed (with errors) on `date`., exit_cleanup = $1, rc = 127" >> $LOG
            exit 127
        else
            # ensure this indicator file jives with what is in the main 'restore' script
            touch /mnt/upgrade/rmtbcrit.dat
            if [ $? -ne 0 ]; then
	        echo "unable to 'touch' remote restore indicator file, rc = $?" >> $LOG
	        echo "Offload of critical system data completed (with errors) on `date`., exit_cleanup = $1, rc = 126" >> $LOG
                exit 126
            else
	        echo "indicator file correctly set for restore script processing on next reboot." >> $LOG
	        echo "Offload of critical system data to this HMC completed successfully on `date`." >> $LOG
            fi
            umount /mnt/upgrade
        fi
    else
	echo "Offload of critical system data completed (with errors) on `date`., rc = $1" >> $LOG
    fi
    
    exit $1
}  

#-------------------------------------------------------------------------------
# check contents of ftp log file when sending data
#-------------------------------------------------------------------------------
function checkForFtpDataTransferErrors {

    FTP_LOG=$1
    funcRC=0

    # First, test if the file transfer succeeded, then if not, check for
    # any specific errors (login, etc)
    #
    # Look for "Transfer complete", "Successful transfer" or equivalent msg
    # code. Careful on grep'ing for this value - note the space
    grep -i "^226 " $FTP_LOG 2>&1 >/dev/null
    if [ $? -eq 0 ]; then
        # successful file transfer, remove the log
        rm -f $FTP_LOG
    else
        # special case for i5 OS FTP
        grep -i "^250 " $FTP_LOG 2>&1 >/dev/null
        if [ $? -eq 0 ]; then
            funcRC=0
        else
            # If no file transfer, look for (known) errors
            grep -i "not logged in" $FTP_LOG > /dev/null 2>&1
            if [ $? -eq 0 ]; then
                # Oops - error logging in
                funcRC=21
            else
                grep -i "Connection refused" $FTP_LOG > /dev/null 2>&1
                if [ $? -eq 0 ]; then
                    # Oops - error accessing server
                    funcRC=23
                else
                    grep -i "unknown host" $FTP_LOG > /dev/null 2>&1
                    if [ $? -eq 0 ]; then
                        # Oops - error accessing server
                        funcRC=24
                    else
                        grep -i "Not connected" $FTP_LOG > /dev/null 2>&1
                        if [ $? -eq 0 ]; then
                            # Oops - error accessing server
                            funcRC=25
                        else
                            # one more login check...
                            grep -i "Login failed" $FTP_LOG > /dev/null 2>&1
                            if [ $? -eq 0 ]; then
                                # Oops - error logging in
                                funcRC=22
                            else
                                # assuming past these login checks, now check for successful file xfer
                                grep -i "Permission denied" $FTP_LOG > /dev/null 2>&1
                                if [ $? -eq 0 ]; then
                                    # permission issues
                                    funcRC=26
                                else
                                    # All other errors here
                                    funcRC=27
                                fi
                            fi 
                        fi 
                    fi
                fi
            fi   
        fi
    fi
    
    echo "Exiting checkForFtpDataTransferErrors, funcRC = $funcRC." >> $LOG
    return $funcRC
}  


#-------------------------------------------------------------------------------
# check contents of ftp log file when changing directories
#-------------------------------------------------------------------------------
function checkForFtpChdirError {

    FTP_LOG=$1
    funcRC=0

    # First check for the '550' error code indicating the 'cd' comamnd failed.
    # Then check for the connection/login errors
    grep -i "^250 " $FTP_LOG 2>&1 >/dev/null
    if [ $? -eq 0 ]; then
        # Directory change ok
        funcRC=0
    else
        # Look for (known) errors
        grep -i "not logged in" $FTP_LOG > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            # Oops - error logging in
            funcRC=21
        else
            grep -i "Connection refused" $FTP_LOG > /dev/null 2>&1
            if [ $? -eq 0 ]; then
                # Oops - error accessing server
                funcRC=23
            else
                grep -i "unknown host" $FTP_LOG > /dev/null 2>&1
                if [ $? -eq 0 ]; then
                    # Oops - error accessing server
                    funcRC=24
                else
                    grep -i "Not connected" $FTP_LOG > /dev/null 2>&1
                    if [ $? -eq 0 ]; then
                        # Oops - error accessing server
                        funcRC=25
                    else
                        # one more login check...
                        grep -i "Login failed" $FTP_LOG > /dev/null 2>&1
                        if [ $? -eq 0 ]; then
                            # Oops - error logging in
                            funcRC=22
                        else
                            # assuming past these login checks, now check for successful file xfer
                            grep -i "Permission denied" $FTP_LOG > /dev/null 2>&1
                            if [ $? -eq 0 ]; then
                                # permission issues
                                funcRC=26
                            else
                                # last check is for the 'cd' error
                                grep -i "^550 " $FTP_LOG 2>&1 >/dev/null
                                if [ $? -eq 0 ]; then
                                    funcRC=28
                                else
                                    # All other errors here
                                    funcRC=27
                                fi
                            fi
                        fi 
                    fi 
                fi
            fi
        fi   
    fi
    
    echo "Exiting checkForFtpChdirError, funcRC = $funcRC." >> $LOG
    return $funcRC
}  

#-------------------------------------------------------------------------------
# copy backup archive file from remotely mounted server resource to the HMC
#-------------------------------------------------------------------------------
function copyBackupArchiveFromMount {

    DIR=$1
    FILE=$2
    SERVER=$3
    RESOURCE=$4
    FSTYPE=$5
    OPTIONS=$6
    DIRECTORY=$7
    funcRC=0
    
    # set local mount point - this directory on the HMC should be established by now
    MTPT=/mnt/remote
    
    # attempt to mount
    # NFS example:
    #   mount -o vers=2 -o proto=udp <server>:<resource> <mount point>
    # Samba example:
    #   mount -t smbfs -o username=xxx,password=yyy //<server>/<resource> <mount point>
    mount $OPTIONS $SERVER:$RESOURCE $MTPT >> $LOG 2>&1
    mountRC=$?
    
    if [ $mountRC -eq 0 ]; then
    
        # Good mount. Check on directory change again
        if [[ "$DIRECTORY" == "" || "$DIRECTORY" == "." ]]; then
            echo "actual copy of data does NOT requires a directory change." >> $LOG
            cd $MTPT
        else
            echo "actual copy of data requires a directory change to $DIRECTORY." >> $LOG
            cd $MTPT/$DIRECTORY
            cdRC=$?
            if [ $cdRC != 0 ]; then
                funcRC=12
            fi
        fi
              
        if [ $funcRC == 0 ]; then
            cp -v $FILE $DIR >> $LOG 2>&1
            if [ $? -eq 0 ]; then
                funcRC=0
            else
                # pretty vague/generic copy error here. Should refine ASAP. Diskspace? Or more likely,
                # permission issues
                funcRC=11
            fi
        fi
        
        # Switch to a different directory so we can unmount (otherwise, umount fails due to "resource busy")
        cd /
        umount $MTPT
    
    else
        # unable to mount
        echo "an error occurred while attempting to mount the remote system, rc=$mountRC." >> $LOG
        funcRC=10
    fi
    
    echo "exiting copyBackupArchiveFromMount, funcRC = $funcRC." >> $LOG
    return $funcRC
}  



#-------------------------------------------------------------------------------
# offload dump to ftp
#-------------------------------------------------------------------------------
function copyBackupArchiveFromFtp {

    DIR=$1
    FILE=$2
    SERVER=$3
    USER=$4
    PASSWORD=$5
    DIRECTORY=$6
    funcRC=0
    
    FTP_LOG=/var/hsc/log/ftp.log
    
    # We'll need 2 separate ftp attempts here if offloading the data to a 
    # directory other than user's home dir.  First attempt is just to see
    # if we can 'cd' to the target dirctory.  If successful, then ftp the
    # actual data.
    #
    # The theory is we'll never encounter any errors here since we just logged into
    # this same server to do a 'ls' command
    if [[ "$DIRECTORY" == "" || "$DIRECTORY" == "." ]]; then
        echo "ftp of the backup archive file does not require a directory change." >> $LOG
        
        /usr/kerberos/bin/ftp -n -u -v $SERVER <<EOF 2>&1 > $FTP_LOG
user $USER $PASSWORD
bin
lcd $DIR
get $FILE
quit
EOF
        # Check for errors during the transfer
        checkForFtpDataTransferErrors $FTP_LOG
        funcRC=$?
    
    else
        # case here where remote target is not in user's home dir...
        echo "ftp of the backup archive file requires a change to $DIRECTORY." >> $LOG
        
        /usr/kerberos/bin/ftp -n -u -v $SERVER <<EOF 2>&1 > $FTP_LOG
user $USER $PASSWORD
cd $DIRECTORY
quit
EOF
        # First check for 'cd' errors (and the usual connection/login errors...)
        checkForFtpChdirError $FTP_LOG
        funcRC=$?
        
        if [ $funcRC == 0 ]; then
            # repeat ftp with actual data transfer
            /usr/kerberos/bin/ftp -n -u -v $SERVER <<EOF 2>&1 > $FTP_LOG
user $USER $PASSWORD
bin
lcd $DIR
cd $DIRECTORY
get $FILE
quit
EOF
            # now check for data transfer errors
            checkForFtpDataTransferErrors $FTP_LOG
            funcRC=$?
        fi
    fi
   
    echo "exiting copyBackupArchiveFromFtp, funcRC = $funcRC." >> $LOG
    return $funcRC
}  
# --------------  End Subroutines ---------------------------------------------



# --------------- BEGIN MAIN PROGRAM  -----------------------------------------

#
# Just in case we have NLS troubles reading system information...
#
LANG=en_US
export LANG

#------------------------------------------------------------------------------
# the restore type and the HMC backup archive filename
#------------------------------------------------------------------------------
RESTORE_TYPE=$1

IN_FILE=$2
ARCHIVE=`basename $IN_FILE`
DIRECTORY=`dirname $IN_FILE`

HMC_DIRECTORY=/dump

# Check if the directory for the log file exists.
if [ ! -d $LOGDIR ]; then
	echo "=================================================================" > $LOG_ERROR_LOG
	echo -e "Restore task log for `date`." >> $LOG_ERROR_LOG
	echo "Restore task log directory, <$LOGDIR>, does not exist. Program exiting" >> $LOG_ERROR_LOG
	exit 1
fi

# Start log to record backup actions.
echo -e "Remote restore log for `date`, archive name is $ARCHIVE.\n" > $LOG


#
# Now move this backup file to the appropriate location (/dump)
#
   
if [ $RESTORE_TYPE -eq 0 ]; then

    echo -e "Remote restore type is 0 (NFS mount)." >> $LOG
    echo "input args are: <$1> <$2> <$3> <$4> <$5> <$6> <$DIRECTORY>" >> $LOG
    # to remote (NFS/Samba) mount. Grab remaining program args from input
    SERVER=$3
    RESOURCE=$4
    FSTYPE=$5
    OPTIONS=$6
    
    # First determine if portmap is running - it should not be.
    # Then start that service for the duration of this script
    PORTMAP=/sbin/portmap
    PORTMAP_SHORT=portmap
    PID=`ps -ef | grep $PORTMAP_SHORT | grep -v grep | awk '{print $2}'`
    
    if test -n "$PID" ; then
        echo "portmap is currently executing, PID is $PID." >> $LOG
    else
        # echo No PID, so start the service.
	echo "about to start the portmap service..." >> $LOG
        /etc/init.d/portmap start
        RC=$?
        sleep 1
     
        # save away this PID for later process termination    
        NEW_PID=`ps -ef | grep $PORTMAP_SHORT | grep -v grep | awk '{print $2}'`
        
        if test -n "$NEW_PID" ; then
            echo "portmap started successfully, pid is $NEW_PID" >> $LOG
        else
            echo "unable to start the portmap daemon, rc = $RC" >> $LOG
            exit_cleanup 2
        fi
    fi
    
    copyBackupArchiveFromMount $HMC_DIRECTORY $ARCHIVE $SERVER $RESOURCE $FSTYPE "$OPTIONS" $DIRECTORY
    copyRC=$?
    
    # whether the restore worked or not, we should kill the portmap service if
    # we started it.
    echo "attempt to stop the portmap service..." >> $LOG
    if test -n "$PID" ; then
        echo "portmap was running prior to script execution - not terminating the service." >> $LOG
    else
        echo "now terminating the portmap service..." >> $LOG
        kill -9 $NEW_PID
    fi
    
    if [ $copyRC -ne 0 ]; then
        exit_cleanup $copyRC
    fi
   
elif [ $RESTORE_TYPE -eq 1 ]; then

    echo -e "Remote restore type is 1 (remote FTP server)." >> $LOG
    echo "input args are: <$1> <$2> <$3> <$4> <password> <$DIRECTORY>" >> $LOG
    # to ftp server. Grab remaining program args from input
    SERVER=$3
    USERID=$4
    PASSWORD=$5
    copyBackupArchiveFromFtp $HMC_DIRECTORY $ARCHIVE $SERVER $USERID $PASSWORD $DIRECTORY
    ftpRC=$?
    if [ $ftpRC -ne 0 ]; then
        exit_cleanup $ftpRC
    fi
    
fi


#
# That's all folks!
#
exit_cleanup 0
