#!/bin/sh
#********************************************************
#
# Name: patchinstall
#
# $Id$
#
# (c) Copyright IBM Corp. 1992, 2016. All rights reserved. 
# US Government Users Restricted Rights - Use, duplication or disclosure 
# restricted by GSA ADP Schedule Contract with IBM Corp.
#
#********************************************************

#
# This script will install Patch binaries
#
_CMD=`basename "$0"`
_CMD_DIR=`dirname "$0"`
PRODUCT_INST="patch"
CURRENT_SCRIPT_NAME="patchinstall"
LSF_VERSION="10.1"
IS_SAS_BUILD="N"
export PRODUCT_INST CURRENT_SCRIPT_NAME LSF_VERSION IS_SAS_BUILD

# Here are the three configurable environment variables:
# CHOWN's default value is "chown",
# CHMOD'S default value is "chmod",
#
# If on the AFS, we suggest to set IGNORECHECKFILEOWNER to
# "Y" to avoid the errors caused by the file owner not being
# the same user who runs patchinstall.
# IGNORECHECKFILEOWNER's default value is "n".
env | grep "^CHOWN=" > /dev/null 2>&1
if [ $? -ne 0 ]; then
    CHOWN="chown"
    export CHOWN
fi
env | grep "^CHMOD=" > /dev/null 2>&1
if [ $? -ne 0 ]; then
    CHMOD="chmod"
    export CHMOD
fi
env | grep "IGNORECHECKFILEOWNER=" > /dev/null 2>&1
if [ $? -ne 0 ]; then
    IGNORECHECKFILEOWNER="n"
    export IGNORECHECKFILEOWNER
fi

#
# Make sure we're running a shell that understands functions
#

if test "$SH5" != "/bin/sh5" -a -r /bin/sh5
then
    SH5=/bin/sh5
    export SH5
    exec /bin/sh5 "$0" "$@"
fi

hosttype=`uname`
version=""
if [ "$hosttype" = "HP-UX" ] ; then
    version=`uname -a |awk '{split($3, a, "."); print a[2]}'`
    RSH=remsh
else
    RSH=rsh
fi
export RSH


# HP-UX 11 needn't this work around

if [ "$version" != "11" ] ; then

    # Work around weird HP-UX 10 POSIX shell problem
    if test "$SH5" != "/usr/old/bin/sh" -a -r /usr/old/bin/sh
    then
        SH5=/usr/old/bin/sh
        export SH5
        exec /usr/old/bin/sh "$0" "$@"
    fi
fi


patch_exit ()
{
trap '' 1 2 3 15 

patch_msg ""
patch_msg ""
patch_msg "`date`"
patch_msg "Signal received."
patch_msg "Patch script exiting ..."

if [ "$CREATE_TRANSACTION" = "Y" ] ; then
    rm -f $PATCH_TOP/lock/transaction
    binary_rollback
fi

patch_cleanup

exit 99
} #patch_exit


patchinstall_usage ()
{
if [ "$IS_SAS_BUILD" = "N" ]; then
    cat << PATCHINSTALL_HLP
Usage:  patchinstall [-f env_file] [--silent] package... 
        patchinstall -c [-f env_file] [--silent] package... 
        patchinstall -r [-f env_file] [--silent] package
        patchinstall -r [-f env_file] [--silent] build_number
        patchinstall -h

-c      Check. Perform checking as if to install, but do not proceed with 
        installation. Specify each package you want to check.
-r      Rollback. Specify the file name of the package you used to install the
        most recent patch, or specify the build number of the most recent patch.
-f env_file  
        This option should only be used if you cannot set your environment (for 
        example, you cannot source profile.platform or profile.lsf, or there is
        no symbolic link or configuration file named lsf.conf under /etc). Specify 
        the full path and file name of a file (such as your LSF install.config 
        file) that properly defines the parameters LSF_TOP and optionally EGO_TOP.
--silent  
        Silent mode. Install or roll back without any interactive prompts for
        confirmation.
-h      Outputs command usage and exits.


PATCHINSTALL_HLP

else
    cat << PATCHINSTALL_HLP_SAS
Usage:  patchinstall [--silent] package... 
        patchinstall -c [--silent] package... 
        patchinstall -r [--silent] package
        patchinstall -r [--silent] build_number
        patchinstall -h

-c      Check. Perform checking as if to install, but do not proceed with 
        installation. Specify each package you want to check.
-r      Rollback. Specify the file name of the package you used to install the
        most recent patch, or specify the build number of the most recent patch.
--silent  
        Silent mode. Install or roll back without any interactive prompts for
        confirmation.
-h      Outputs command usage and exits.


PATCHINSTALL_HLP_SAS

fi

} # patchinstall_usage

_cmd_opt_str="$@"
_n_opts=$#

if [ "$_n_opts" = "0" ]; then
    patchinstall_usage
    exit 0
fi

ACTION=""
SLIENT=""
CONFIG_FILE=""
PACKAGE_LIST=""

CONFIG_FILE=""
_next_type=""
for _opt in $_cmd_opt_str
do
    case $_opt in 
        -c )
            if [ "$ACTION" != "" ] ; then
                patchinstall_usage
                exit 1
            else
                ACTION="precheck"
                _next_type="p"
            fi
            ;;
        -r )
            if [ "$ACTION" != "" ] ; then
                patchinstall_usage
                exit 1
            else
                ACTION="rollback"
                _next_type="p"
            fi
            ;;
        -d )
            if [ "$ACTION" != "" ] ; then
                patchinstall_usage
                exit 1
            else
                ACTION="check_db"
            fi
            ;;
        -f )
            _next_type="f"
            ;;
        --silent )
            SLIENT="Y"
            ;;
        --backup )
            _next_type="backup_dir"
            ;;
        -h )
            patchinstall_usage
            exit 0 
            ;;
        --createdb )
            if [ "$ACTION" != "" ] ; then
                patchinstall_usage
                exit 1
            else
                ACTION="createdb"
                _next_type="p"
            fi
            ;;

        -*)
            echo "    Command line option $_opt is not valid."
            patchinstall_usage
            exit 0 
            ;;
        *)
            if [ "$_next_type" = "p" -o "$_next_type" = "f"  -o "$_next_type" = "backup_dir" ] ; then
                if [ "$_next_type" = "p" ] ; then
                    PACKAGE_LIST=`echo $PACKAGE_LIST $_opt`
                elif [ "$_next_type" = "f" ] ; then
                    if [ "$CONFIG_FILE" != "" ] ; then
                        echo "You can only specify one file with the command line option -f."
                        patchinstall_usage
                        exit 1
                    else
                        CONFIG_FILE="$_opt"
                        _next_type=""
                    fi
                else
                    if [ "$BACKUP_DIR" != "" ] ; then
                        echo "You can only specify one directory with the command line option --backup."
                        patchinstall_usage
                        exit 1
                    else
                        _defined_backup_dir="Y"
                        BACKUP_DIR="$_opt"
                        _next_type=""
                    fi
                fi
            else
                if [ "$ACTION" = "" ] ; then
                    ACTION="apply"
                fi
                PACKAGE_LIST=`echo $PACKAGE_LIST $_opt`
            fi
            ;;
    esac
done

if [ "$ACTION" = "" ] ; then
    ACTION="apply"
fi

if [ "$ACTION" = "apply" -a "$PACKAGE_LIST" = "" ] ; then
    echo "You must specify the packages you want to install. Specify the full path including package name."
    patchinstall_usage
    exit 1
fi

if [ "$ACTION" = "precheck" -a "$PACKAGE_LIST" = "" ] ; then
    echo "You must specify the packages you want to check. Specify the full path including package name."
    patchinstall_usage
    exit 1
fi

if [ "$ACTION" = "apply" -o "$ACTION" = "precheck" -a "$PACKAGE_LIST" != "" ] ; then
        for _package in $PACKAGE_LIST 
        do           
            if [ ! -r "$_package" -o ! -f "$_package" ]; then
                echo "The package file \"$_package\" does not exist or is not readable." 1>&2
                exit 1
            fi
        done
fi

if [ "$ACTION" = "rollback"  ] ; then
    _pack_num=`echo $PACKAGE_LIST | wc -w`
    _pack_num=`expr $_pack_num`
    if [ "$_pack_num" -ne "1" ] ; then
        echo "For rollback, you must specify the most recently installed package name or build number. "
        patchinstall_usage
        exit 1
    fi
fi

PATCHLIB=`cd $_CMD_DIR;pwd`/patchlib
INSTLIB=`cd $_CMD_DIR;pwd`/instlib

#
# Checking patch installer package
#
if [ -d "$PATCHLIB" ] ; then
    for _file in "error.tbl" "commonlib.sh" "dblib.sh"  "applyfuncs.sh" "queryfuncs.sh" "rollbackfuncs.sh"
    do
        if [ ! -f "$PATCHLIB/$_file" ] ; then
            echo "The package is not complete." 1>&2
            echo "The file \"$_file\" is missing from the package." 1>&2
            echo "Patch installation cannot continue. Exiting ..." 1>&2
            exit 1
        fi
    done
else
    echo "The package is not complete." 1>&2
    echo "The directory \"$PATCHLIB\" is missing from the package." 1>&2
    echo "Patch installation cannot continue. Exiting ..." 1>&2
    exit 1

fi

. $INSTLIB/lsflib.sh
. $PATCHLIB/error.tbl
. $PATCHLIB/commonlib.sh
. $PATCHLIB/dblib.sh
. $PATCHLIB/applyfuncs.sh
. $PATCHLIB/queryfuncs.sh
. $PATCHLIB/rollbackfuncs.sh

export PATCHLIB 
if [ "$CONFIG_FILE" != "" -a "$ACTION" != "createdb"  ] ; then
    if [ ! -f "$CONFIG_FILE" -o ! -r "$CONFIG_FILE" ]; then
        echo "The file \"$CONFIG_FILE\" does not exist or is not readable." 1>&2
        echo "Check the file and its permissions." 1>&2
        patchinstall_usage
        exit 1
    else
        LSF_TOP=`get_opt_value "$CONFIG_FILE" "LSF_TOP" "="`
        PATCH_BACKUP_DIR=`get_opt_value "$CONFIG_FILE" "PATCH_BACKUP_DIR" "="`
        PATCH_HISTORY_DIR=`get_opt_value "$CONFIG_FILE" "PATCH_HISTORY_DIR" "="`
        EP_BACKUP=`get_opt_value "$CONFIG_FILE" "EP_BACKUP" "="`
        if [ "$LSF_TOP" = "" ] ; then
            echo "    You must specify LSF_TOP in the file \"$CONFIG_FILE\"." 1>&2
            echo "    Exiting ..." 1>&2
            exit 1
        else
            if [ ! -d "$LSF_TOP" ] ; then
                echo "Your specified LSF installation directory \"$LSF_TOP\"" 1>&2
                echo "does not exist. Exiting ..." 1>&2
                exit 1
            elif [ ! -d "$LSF_TOP/conf" ] ; then
                echo "    Cannot find \"$LSF_TOP/conf\"." 1>&2
                echo "    Your cluster must already exist and your configuration file must specify" 1>&2
                echo "    the current LSF installation directory as LSF_TOP." 1>&2
                echo "    Exiting ..." 1>&2
                exit 1
            fi
        fi
        
        EGO_TOP=$LSF_TOP
    fi
elif [ "$ACTION" != "createdb" ] ; then
    # need to more think about how to get LSF_TOP by environment variable
    if [ "$LSF_ENVDIR" = "" ] ; then
		if [ "$LSF_TOP" = "" ] ; then
			CONFIG_FILE="/etc/lsf.conf"
			if [ -f "$CONFIG_FILE" ] ; then
				LSF_TOP=`get_opt_value "$CONFIG_FILE" "LSF_TOP" "="`	
			fi
			if [ "$LSF_TOP" = "" ] ; then
				echo "    The path to the installation directory is not defined in the environment." 1>&2
				echo "    To set your environment, use profile.platform or cshrc.platform." 1>&2
				if [ "$IS_SAS_BUILD" = "N" ]; then
					echo "    To get the installation directory from a file, use the command line option -f." 1>&2
					patchinstall_usage
				fi
				exit 1
			else
				EGO_TOP=$LSF_TOP
			fi
		fi
    else
        if [ ! -f $LSF_ENVDIR/lsf.conf ] ; then
            echo "    Cannot get lsf.conf under your $LSF_ENVDIR." 1>&2
            exit 1
        else
            LSF_TOP=`get_opt_value "$LSF_ENVDIR/lsf.conf" "LSF_TOP" "="`
            if [ "$LSF_TOP" = "" ] ; then
                echo "    Cannot get LSF_TOP from lsf.conf." 1>&2
                exit 1
            fi                
        fi
        
        EGO_TOP=$LSF_TOP
    fi
fi

if [ -f "$LSF_TOP/conf/lsf.conf" -a "$ACTION" != "createdb" ] ; then
    _current_lsf_version=`get_opt_value "$LSF_TOP/conf/lsf.conf" "LSF_VERSION" "="`
    if [ "$_current_lsf_version" != "" ] ; then
        _ret=`version_cmp "$_current_lsf_version" "7.0"`
        if [ "$_ret" = "-1" ] ; then
            echo "    This installer is only compatible with LSF 7.0 or later." 1>&2
            echo "    Your cluster runs LSF $_current_lsf_version." 1>&2
            echo "    Exiting ..." 1>&2
            exit 1
        fi
    fi
fi

#check existing patch.conf
PATCH_CONF=""
if [ -f $EGO_TOP/patch.conf ] ; then
    PATCH_CONF=$EGO_TOP/patch.conf
fi    
if [ -f $LSF_TOP/ego/patch.conf ] ; then
    PATCH_CONF=$LSF_TOP/ego/patch.conf
fi    

if [ "$PATCH_HISTORY_DIR" = "" ] ; then
    if [ "$PATCH_CONF" = "" ] ; then
        PATCH_TOP=$EGO_TOP/patch
    else    
        PATCH_TOP=`get_opt_value "$PATCH_CONF" "PATCH_HISTORY_DIR" "="` 
    fi
else
    PATCH_TOP=$PATCH_HISTORY_DIR
fi

if [ "$PATCH_BACKUP_DIR" = "" ] ; then
    if [ "$PATCH_CONF" = "" ] ; then
        BACKUP_DIR=$PATCH_TOP/backup
    else
        BACKUP_DIR=`get_opt_value "$PATCH_CONF" "PATCH_BACKUP_DIR" "="`
    fi
else
    BACKUP_DIR=$PATCH_BACKUP_DIR
fi

PACKAGEDB_TOP=$PATCH_TOP/patchdb
export LSF_TOP EGO_TOP PATCH_TOP PACKAGEDB_TOP BACKUP_DIR
ROLLBACK_FILE=$PATCH_TOP/lock/rollback.log    
export ROLLBACK_FILE

CREATE_TRANSACTION="N" 
export CREATE_TRANSACTION

if [ "$ACTION" = "precheck" ] ; then
	_head_name="C H E C K"
else
	_head_name="I N S T A L L A T I O N"
fi

enable_patch_logs

trap patch_exit 1 2 3 15 

if [ "$ACTION" != "createdb" ] ; then
cat  >> $PREFIX_PATCH_LOG/${LOG_FILE} << START

-----------------------------------------------------------------
P A T C H    $_head_name    E N V I R O N M E N T    
-----------------------------------------------------------------
Logger: ${CURRENT_SCRIPT_NAME}

Started: `date`
    
User ID: `id`

Command: 
    $0 $_cmd_opt_str

Installing from host: 
    `hostname` ( `uname -a`)

Current working directory: 
    `pwd`

Contents of current working directory:(`pwd`)
    `ls -l .`

-----------------------------------------------------------------

START
fi

if [ "$ACTION" = "apply" ] ; then
     #show_copyright
     case $? in
        1 ) echo "   Installation exiting ..." ; exit 0 ;;
        2 ) echo "   JRE is not installed on the system. Installation exiting ..." ; exit 0 ;;
        3 ) echo "   JRE must be version 1.4 or higher. Installation exiting ..." ; exit 0 ;;
     esac
fi

#load daemons list from daemonlists.tbl
_daemon_lists=""
if [ -f "$PATCHLIB/daemonlists.tbl" ] ; then 
    exec 3<&0 < $PATCHLIB/daemonlists.tbl
    while read LINE
    do    		
        _daemon_lists="$_daemon_lists $LINE" 
    done
    exec 0<&3 3<&-
fi
export _daemon_lists

if [ "$ACTION" = "apply" -o "$ACTION" = "precheck" ] ; then

    #check file type and unpack command
    commonprechk 
    if [ "$?" != "0" ] ; then
        exit 1
    fi

    if [ "$PACKAGE_LIST" != "" ] ; then 
        for _package in $PACKAGE_LIST
        do
            set_unpack_cmd "$_package"  
            if [ "$?" != "0" ] ; then
                if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                    rm -f $PATCH_TOP/lock/transaction
                fi 
                exit 1
            fi

            if [ "$isTAR" != "y" ] ; then
                patch_error "ERROR_5003" "patchinstall" $_package
                if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                    rm -f $PATCH_TOP/lock/transaction
                fi 
                exit 1
            fi
            if [ "$UNPACK" = "" ] ; then
                patch_error "ERROR_2001" "patchinstall" $UNPACK_CMD
                if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                    rm -f $PATCH_TOP/lock/transaction
                fi 
                exit 1
            fi
        done
    fi   
		
	_summary_file=$PREFIX_PATCH_LOG/summary.log.$$
    if [ "$ACTION" = "precheck" ] ; then
	    cat > $_summary_file << SUMMARY 

PATCH CHECK SUMMARY
-------------------

Package Name                                      Results
------------                                      -------
SUMMARY
    fi

    if [ "$PACKAGE_LIST" != "" ] ; then
        for _package in $PACKAGE_LIST 
        do           
    		#convert package path to absolution path
    		_basename=`basename "$_package"`
    		_dirname=`dirname "$_package"`
    		if [ "$_dirname" != "" ]; then
        		_absolute_path=`cd "$_dirname";pwd`
        		_package_fullname="${_absolute_path}/${_basename}"	
    		fi

    		if [ ! -f "$_package_fullname" ] ; then
        		patch_error "ERROR_2002" "patchinstall" "$_package" 
                if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                    rm -f $PATCH_TOP/lock/transaction
                fi 
				rm -f $_summary_file
        		exit 1
    		fi

            set_unpack_cmd $_package_fullname
            if [ "$?" != "0" ] ; then
                if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                    rm -f $PATCH_TOP/lock/transaction
                fi 
                exit 1
            fi

            applypatch $_package_fullname
			_ret=$?
            if [ "$_ret" = "0" -a "$ACTION" = "apply" ] ; then
                Package_read

                ls $LSF_TOP/$_db_ProductVersion/misc/inventory_tag/*$_db_ProductVersion.$_db_EPVersion.*.fxtag >/dev/null 2>&1
                if [ "$?" = "0" ] ; then
                    $CHMOD 664 $LSF_TOP/$_db_ProductVersion/misc/inventory_tag/*.fxtag
                    $CP $LSF_TOP/$_db_ProductVersion/misc/inventory_tag/*$_db_ProductVersion.$_db_EPVersion.*.fxtag $LSF_TOP/properties/version
                    FUSER=`stat -c %U $LSF_TOP/properties/version`
                    FGROUP=`stat -c %G $LSF_TOP/properties/version`
                    $CHMOD 644 $LSF_TOP/properties/version/*.fxtag
                    $CHOWN $FUSER:$FGROUP $LSF_TOP/properties/version/*.fxtag
                fi
            fi
            if [ "$_ret" = "1" -a "$ACTION" = "apply" ] ; then
                cat << APPLYPATCH | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}

${CURRENT_SCRIPT_NAME} found unrecoverable errors during patch installation.
Check $PREFIX_PATCH_LOG/patch.err 
to correct these errors and run again.

APPLYPATCH

                if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                    rm -f $PATCH_TOP/lock/transaction
                fi 
				rm -f $_summary_file
                exit 1
            elif [ "$_ret" = "2" -a "$ACTION" = "apply" ] ; then
                continue
			elif [ "$_ret" = "1" -a "$ACTION" = "precheck" ] ; then
				echo "" | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}
				echo "Checking package $_basename is complete. This package CANNOT be installed in the cluster." | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}
				echo "`basename $_package`:FAILED" | awk -F':' '{printf$1;for(x=1;x<=50-length($1);x++){printf" "};print$2}' >> $_summary_file 
			else
				if [ "$ACTION" = "precheck" ] ; then
					echo "" | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}
					echo "Checking package $_basename is complete. This package CAN be installed in the cluster." | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}
					echo "`basename $_package`:PASSED" | awk -F':' '{printf$1;for(x=1;x<=50-length($1);x++){printf" "};print$2}' >> $_summary_file 
				fi
            fi
        done

        if [ "$CREATE_TRANSACTION" = "Y" ] ; then
            rm -f $PATCH_TOP/lock/transaction
        fi
        if [ -x ${PATCHLIB}/showsecurity.sh ]; then
            ${PATCHLIB}/showsecurity.sh $PREFIX_PATCH_LOG/${LOG_FILE}
        fi

	if [ "$ACTION" = "precheck" ] ; then
	    cat $_summary_file | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}
	    echo ""
	fi
        patch_msg ""
        patch_msg "Exiting..."
    fi

    rm -f $_summary_file
        
fi

if [ "$ACTION" = "createdb" ] ; then
    createdb_for_ep $PACKAGE_LIST 
    if [ "$?" = "1" ] ; then
        if [ "$CREATE_TRANSACTION" = "Y" ] ; then
            rm -f $PATCH_TOP/lock/transaction
        fi 
        exit 1
    fi
fi

if [ "$ACTION" = "rollback" ] ; then

    if chk_shell ; then
        :
    else
        return 1
    fi

    if [ "$PACKAGE_LIST" != "" ] ; then
        set_unpack_cmd $PACKAGE_LIST
        if [ "$?" != "0" ] ; then
            exit 1
        fi

        if [ "$isTAR" != "y" ] ; then
            _tmp_build_number=`echo $PACKAGE_LIST | tr -d [0-9]`
            if [ "$_tmp_build_number" != "" ] ; then
                patch_error "ERROR_5003" "patchinstall" "$PACKAGE_LIST"
                exit 1
            fi
        else
            if [  -f "$PACKAGE_LIST" -a -r "$PACKAGE_LIST" ] ; then
                :
            else
                patch_error "ERROR_5004" "patchinstall" "$PACKAGE_LIST"
                exit 1
            fi
            if [ "$UNPACK" = "" ] ; then
                patch_error "ERROR_2001" "patchinstall" $UNPACK_CMD
                exit 1
            fi
        fi
    fi

    commonprechk 
    if [ "$?" != "0" ] ; then
        if [ "$CREATE_TRANSACTION" = "Y" ] ; then
            rm -f $PATCH_TOP/lock/transaction
        fi 
        exit 1
    fi

    if [ "$PACKAGE_LIST" != "" ] ; then
        insert_event_log "$PACKAGE_LIST" "start"
        rollbackpatch
        if [ "$?" != "0" ] ; then
            cat << ROLLBACKPATCH | tee -a $PREFIX_PATCH_LOG/${LOG_FILE}

${CURRENT_SCRIPT_NAME} found unrecoverable errors during patch installation.
Check $PREFIX_PATCH_LOG/patch.err
to correct these errors and run again.

ROLLBACKPATCH
            if [ "$CREATE_TRANSACTION" = "Y" ] ; then
                rm -f $PATCH_TOP/lock/transaction
            fi 
            exit 1
        fi
        insert_event_log "$PACKAGE_LIST" "complete"

    fi
    if [ "$CREATE_TRANSACTION" = "Y" ] ; then
        rm -f $PATCH_TOP/lock/transaction
    fi 
fi

if [ "$ACTION" = "check_db" ] ; then
  check_db
fi

