#!/bin/bash 
# #################################################################################
# Exceed TurboX Connection Node
# © Rocket Software, Inc. or its affiliates. All Rights Reserved.
# ROCKET SOFTWARE, INC. CONFIDENTIAL
# #################################################################################
# prereqcheck
# #################################################################################

# script to check for minimum prerequisites for bin\sys components

read_yesno()
{
# accepts y, n, yes, no; converts input to lowercase
# by default null input is "no", $1 overrides yndefault (n, y, none, block)
# yes: returns 0 (useful for: if read_yesno ; then )
# no: returns 1; Enter: returns default: 0, 1, or 2

	# set default answer if null response
	yndefault=$1
	if [ -z "${yndefault}" ] ; then
		yndefault=n
	fi
	
	while true ; do
		
		read answer
		#convert to lowercase
		answer=`${ECHO} ${answer}| ${TR} [:upper:] [:lower:]`
		${ECHO}
		
		case "${answer}" in
			y|yes )
				return 0
				;;
			n|no )
				return 1
				;;
			"" )
				case "${yndefault}" in
					y ) return 0 ;;
					n ) return 1 ;;
					none ) return 2 ;;
					block )
						${ECHO} "Invalid input. Please try again: \c"
						;;
				esac
				;;
			* )
				${ECHO} "Invalid input '${answer}'. Please try again: \c"
				;;
		esac
	
	done
}

read_noyes()
{
# no: returns 0 (useful for: if read_noyes ; then )

	read_yesno $*
	resp=$?
	if [ $resp -eq 0 ] ; then
		return 1
	elif [ $resp -eq 1 ] ; then
		return 0
	else
		return $resp
	fi
}

cd_and_exit()
{
	resetCDir
	exit $1
}

exit_error_unless()
{
	resetCDir
	if [ -z "${ContinueInstallOnMissing}" ] ; then
		exit 0
	fi
	exit $1
}

usage()
{
	${ECHO} "Usage: $0 [-s reponsefile ]"
}


test_GREP()
{
	${ECHO} ${GREP} -e GREP "$0" > /dev/null 2>&1
	${GREP} -e GREP "$0" > /dev/null 2>&1
	if [ $? -gt 0 ] ; then
		return 1
	else
		return 0
	fi
}

find_good_grep()
{
	GREP=`which grep`
	test_GREP
	if [ $? -gt 0 ] ; then
		GREP=`which egrep`
		test_GREP
		if [ $? -gt 0 ] ; then
			GREP=/usr/xpg4/bin/grep
			test_GREP
			if [ $? -gt 0 ] ; then
				${ECHO} "FATAL ERROR: The grep version on this machine is too old.  It needs to be equivalent to GNU grep."
				cd_and_exit 1
			fi
		fi
	fi
	export GREP
	return
}

test_AWK()
{
	awk_result=`${ECHO} "Access: (0755/d)" | ${AWK} 'BEGIN{FS="[(/]"} {print $2}' 2>/dev/null`
	if [ "${awk_result}" = "0755" ] ; then
		return 0
	else
		return 1
	fi
}

find_good_AWK()
{
	AWK=`which awk`
	test_AWK
	if [ $? -gt 0 ] ; then
		AWK=/usr/xpg4/bin/awk
		test_AWK
		if [ $? -gt 0 ] ; then
			${ECHO} "FATAL ERROR: The awk version on this machine is too old.  It needs to be equivalent to GNU awk."
			cd_and_exit 1
		fi
	fi
	export AWK
	return
}



test_TR()
{
	echo "aaAA" | ${TR} [:upper:] [:lower:]  > /dev/null 2>&1
	if [ $? -gt 0 ] ; then
		return 1
	else
		return 0
	fi
}

find_good_TR()
{
	TR=`which tr`
	test_TR
	if [ $? -gt 0 ] ; then
		TR=/usr/ucb/tr
		test_TR
		if [ $? -gt 0 ] ; then
			${ECHO} "FATAL ERROR: The tr version on this machine is too old.  It needs to be equivalent to GNU tr."
			cd_and_exit 1
		fi
	fi
	export TR
	return
}

test_ECHO()
{
	${ECHO} -e "test\c" | grep "\-e" > /dev/null
	if [ $? -gt 0 ] ; then
		# -e is supported so add it
		ECHO="${ECHO} -e"
	fi
}

find_good_ECHO()
{
	ECHO=`which echo`
	test_ECHO
	export ECHO
	SILENT_ECHO=${ECHO}
	if [ ! -z "${DEBUG_INSTALL}" ] ; then
		DEBUG_ECHO=${ECHO}
	else
		DEBUG_ECHO=:
	fi
	export SILENT_ECHO
	export DEBUG_ECHO
}


find_good_LDCONFIG()
{
	LDCONFIG=`which ldconfig 2> /dev/null`
	test_LDCONFIG
	if [ $? -gt 0 ] ; then
		LDCONFIG=/sbin/ldconfig
		test_LDCONFIG
		if [ $? -gt 0 ] ; then
			return
		fi
	fi
	export LDCONFIG 
	return
}

test_LDCONFIG()
{
	if [ -z "${LDCONFIG}" ] ; then
		return 1
	fi
	if [ -f "${LDCONFIG}" -o -h "${LDCONFIG}" ] ; then
		${LDCONFIG} -p | grep "libs" > /dev/null 2>&1
		return $?
	else
		return 1
	fi
}


resolveDir()
{
	# resolve links - $0 may be a softlink
	thisPRG="${1}"
	
	while [ -h "$thisPRG" ]; do
		ls_ld=`ls -ld "$thisPRG"`
		this_link=`expr "${ls_ld}" : '.*-> \(.*\)$'`
		
		if expr "${this_link}" : '/.*' > /dev/null; then
			thisPRG="${this_link}"
		else
			thisPRG=`dirname "${thisPRG}"`/"${this_link}"
		fi
	done

	# -- we only want to check fully resolved path
	if [ "${3}" = "CD" ] ; then
		eval ${2}="${thisPRG}"
		return
	fi
	
	CDir=`pwd`
	
	thisPrgDirName="`dirname ${thisPRG}`"
	
	cd "${thisPrgDirName}" > /dev/null 2>&1
	cd .. > /dev/null 2>&1 
	
	Here=`pwd`
	eval ${2}="${Here}"

	cd ${CDir}

}

getInstallDir()
{
	resolveDir $0 InstallDir
}

resetCDir()
{
	cd "${CDir}" > /dev/null 2>&1
}


initialize()
{
	init_variables $*
	get_params $*
}

isItSUSELinux()
{
	if [ -d "/etc/init.d" ] ; then
		isSUSE=1
	fi
}

isItAarch64()
{
    local thisAarch64=`uname -m`
    if [ "${thisAarch64}" == "aarch64" ]; then
	thisArch="aarch64"
    fi
}

getSolarisVersion()
{
    local thisUname=$(uname)
    if [ "$thisUname" = "SunOS" ]; then
	solVersion=""
	local thisVersion=$(uname -v)
	if [[ $thisVersion =~ ^[0-9]+\.[0-9]+ ]]; then
	    local matchString=${BASH_REMATCH[0]}
	    solVersion=$matchString
	    return 0
	fi
    fi
    return 1
}

getThisPlatform()
{
	osAix=aix
	osLinux=linux
	osSolaris=solaris
	osHPUX=hpux
	
	archPpc=ppc
	archPpc64=ppc64
	archi586=i586
	archx86_64=x86_64
	archSparc=sparc
	archParisc=parisc
	
	unknown=unknown
	
	thisOS=${unknown}
	thisArch=${unknown}
	
	thisUname=`uname`
	
	fgrepOptions="-c -i"
	optionL="-L"
	
	hasi86=`uname -a | grep ${fgrepOptions} i386`
	
	if [ ${hasi86} = "0" ] ; then
		hasi86=`uname -a | grep ${fgrepOptions} i686`
	fi
	
	isx86_64=`uname -a | grep ${fgrepOptions} x86_64`

	if [ ${isx86_64} != "0" ]; then
	    thisArch=${archx86_64}
	elif [ ${hasi86} = "0" ] ; then
	    thisArch=${archi586}
	fi
	
	case ${thisUname} in
		AIX )
			thisOS=${osAix}
			thisArch=${archPpc}
			;;
		Linux )
			thisOS=${osLinux}
			isItSUSELinux
			isItAarch64
			;;
		SunOS )
			thisOS=${osSolaris}
			if [ ${hasi86} = 1 ] ; then
			    thisArch=${archx86_64}
			else
				thisArch=${archSparc}
				optionL="-h"
			fi
			solarisVersion=`uname -r|cut -d "." -f2`
			export solarisVersion
			getSolarisVersion
			if [ -n "$solVersion" ] && (( $(echo "$solVersion 11.4" | awk '{print ($1 < $2)}') )); then
			    ${ECHO} "Cannot install on Solaris version less that 11.4. This version is ${solVersion}."
			    cd_and_exit 1
			fi
			;;
		HP-UX )
			thisOS=${osHPUX}
			thisArch=${archParisc}
			;;
		* )
			;;
	esac
}


init_variables()
{
	binDir=${InstallDir}/bin
	sysDir=${binDir}/sys

	thisUname=`uname`
	isSparc=`uname -a | ${GREP} -c sparc`
}


set_platform_opts()
{

	find_good_ECHO
	find_good_grep
	find_good_AWK
	find_good_TR
	find_good_LDCONFIG

	if [ "${thisOS}" = "${osLinux}" ] ; then
		USERADDOPTS="-M"
		USERADDOPTS_WITHSHELL="-m"
	elif [ "${thisOS}" = "${osAix}" ] ; then
		USERADDOPTS=
		USERADDOPTS_WITHSHELL="-m"
	elif [ "${thisOS}" = "${osSolaris}" ] ; then
		USERADDOPTS=
		USERADDOPTS_WITHSHELL="-m"
	else
		USERADDOPTS=
	fi
	
	export USERADDOPTS
	export USERADDOPTS_WITHSHELL
}


readThisSectionKeyValueForThisVariable()
{
	thisPropFile=$1
	thisSection=$2
	thisKey=$3
	thisKeyFullName=${thisSection}.${thisKey}
	
	tmp_value=`${GREP} "${thisKeyFullName}=" "${thisPropFile}" 2> /dev/null | cut -f2- -d=`
	ret_value=`echo ${tmp_value}|${TR} -d '\011\012\015'`
	eval ${thisKey}="${ret_value}"
	
}

readThisSectionKeys()
{
	thisPropFile="$1"
	thisSection="$2"
	theseKeys="$3"
	
	for thisKey in ${theseKeys}
	do
		readThisSectionKeyValueForThisVariable "${thisPropFile}" "${thisSection}" ${thisKey}
	done
}



readResponseFile()
{
	thisResponseFile="$1"
	PWD=`pwd`
	checkthisResponseFile=`echo ${thisResponseFile}|awk '{print substr($0,1,1)}'`
	
	if [ ! -f "${thisResponseFile}" ] ; then
		${ECHO} "FATAL ERROR: Silent mode response file '${thisResponseFile}' does not exist!"
		cd_and_exit 1
	fi
	
	if [ "${PWD}" != "${InstallDir}/bin"  -a "${checkthisResponseFile}" != "/" ] ; then
		${ECHO} "FATAL ERROR: Full path to response file is required to run silent install!"
		cd_and_exit 1
	fi
	
	theseKeys="ContinueInstallOnMissing"
	readThisSectionKeys "${thisResponseFile}" "prerequisites.etxcn" "${theseKeys}"
}


get_params()
{
	builtinResponseFile="${InstallDir}/conf/builtin.resp"
	
	while [ ! -z "${1}" ] 
	do
		
		case "${1}" in
		--help )
			${ECHO} "Usage: $0 [-s reponsefile ]"
			${ECHO} "Option: -s fullpath/responsefile : Silent install of ETX Node."
			cd_and_exit
			;;
		-e )
			# we will prompt if required but generally don't print anything out
			SILENT_ECHO=:
			;;
		-s )
			if [ -z "$2" ] ; then
				usage
				cd_and_exit
			fi
			shift
			bSilent="1"
			SILENT_ECHO=:
			readResponseFile "$1"
			;;
		* )
			${ECHO} "Invalid option: ${1}"
			cd_and_exit 1
			;;
		esac
		
		shift
	done
	
}

prerequisites_prep()
{
	global_result=0
	export global_result
	prereq_failed_list=
	export prereq_failed_list
	
	if [ "${thisOS}" = "${osSolaris}" ] ; then
		if [ ! -z "${DEBUG_INSTALL}" ] ; then
			#  On solaris we will use crle + find to locate a grand list of .so files similar to ldconfig
			crle -64 | grep ELF | cut -f2- -d:|sed 's/[\(].*//g' > t
			rm -f tt 2>&1 >/dev/null
			while read line
			do
				xx=`echo $line | tr ':' '\t'`
				allines="${xx} ${allines}"
			done < t
			rm -f t 2>&1 >/dev/null
			# now space delimited list of folders
			alllibs="`pwd`/alllibs"
			# echo "$allines"
			for x in ${allines} ; do
				if [ -d "$x" ] ; then
					pushd "$x"
					for ll in *.so* ; do
						echo "$ll => $x/$ll"  >> ${alllibs}
					done
					popd
				fi
			done
		fi
	else
		if [ -z "${LDCONFIG}" ] ; then
			${ECHO} "Fatal error: We cannot locate ldconfig in path."
			cd_and_exit  1
		fi
	fi
}

find_glibc()
{
	glibc_version=$1

	${ECHO} "Locating libc.so with GLIBC_$glibc_version version"
	glibc_found=0

	${ECHO} "`${LDCONFIG} -p | grep libc.so`" | sed 's/ //g'|sed 's/=>/ /g' > tmp_glibc
	while read line
	do
			# echo "line: " $line
			glib_details=`echo $line |${AWK} '{print $1}'`
			glib_path=`echo $line | ${AWK} '{print $2}'`

			if [ "${DEBUGINSTALL}" = "1" ] ; then
				${ECHO} "Details:   $glib_details"
				${ECHO} "   Path:   $glib_path"
			fi

			supported=`strings $glib_path | grep "GLIBC_$glibc_version"`
			strlen $supported
			glibc_found=$?
			if [ $glibc_found -gt 0 ] ; then
					break
			fi
	done < tmp_glibc
	rm -f tmp_glibc > /dev/null 2>&1
	return $glibc_found
}


check_GLIBC_prerequisites()
{
	${DEBUG_ECHO} "check_GLIBC_prerequisites - $3"

	thisFolder=$1
	thisCritical=$2
	thisBinary=$3
	if [ "${thisOS}" = "${osLinux}" ] ; then
		pushd "${thisFolder}" > /dev/null
		# format is    GLIBC  not found (stderr)
		#      or     library   =>  not found  (stdout)
		rm -f tmp_results2 >/dev/null 2>&1
		rm -f tmp_results3 >/dev/null 2>&1
		ldd ${thisBinary} 2>&1 | ${GREP} "GLIBC" | ${GREP} "not found" > tmp_results2
		result=$?
		if [ ${result} -eq 0 ] ; then
			rm -f tmp_results3 >/dev/null 2>&1
			while read line
			do
				thisLib=`${ECHO} ${line} |  cut -f3 -d:| sed 's/.*\`//g' | sed "s/'.*//g"`
				echo ${thisLib} >> tmp_results3
			done < tmp_results2
			this_library_failurelist=`sort tmp_results3 | ${AWK} 'NR==1 {print;exit}'`
			result=1
		else
			result=0
		fi
		rm -f tmp_results3 >/dev/null 2>&1
		rm -f tmp_results2 >/dev/null 2>&1
		popd > /dev/null
	else
		# nothing to do on this platform
		result=0
	fi
	export result
	return $result
}


check_library_prerequisites()
{
	${DEBUG_ECHO} "check_library_prerequisites - $3"
	thisFolder=$1
	thisCritical=$2
	thisBinary=$3

	if [ "${thisOS}" = "${osSolaris}" ] ; then
		pushd "${thisFolder}" > /dev/null
		# format   library   =>  not found
		resultlist=`ldd ${thisBinary} 2>/dev/null| ${GREP} "not found"`
		result=$?
		if [ ${result} -eq 0 ] ; then
			this_library_failurelist=
			${ECHO} $resultlist > tmp_results
			while read line
			do
				thisLib=`${ECHO} ${line} |  cut -f1 -d=|tr -d ' \t'`
				this_library_failurelist="${thisLib}\n${this_library_failurelist}"
			done < tmp_results
			result=1
			export this_library_failurelist
			rm -f tmp_results
		else
			result=0
		fi
		popd > /dev/null
	elif [ "${thisOS}" = "${osLinux}" ] ; then
		pushd "${thisFolder}" > /dev/null
		# format is    GLIBC  not found
		#      or     library   =>  not found
		resultlist=`ldd ${thisBinary} 2>/dev/null| ${GREP} "not found"`
		result=$?
		if [ ${result} -eq 0 ] ; then
			this_library_failurelist=
			${ECHO} $resultlist > tmp_results
			while read line
			do
				thisLib=`${ECHO} ${line} |  cut -f1 -d=|tr -d ' \t'`
				this_library_failurelist="${thisLib}\n${this_library_failurelist}"
			done < tmp_results
			result=1
			export this_library_failurelist
			rm -f tmp_results
		else
			result=0
		fi
		popd > /dev/null
	else
		result=0
	fi
}


check_prerequisites()
{
	thisFolder=$1
	thisCritical=$2
	thisBinary=$3

	if [ "${thisOS}" = "${osSolaris}" ] ; then
		${SILENT_ECHO} "Checking solaris binary $thisFolder/$thisBinary ...\c"
		check_library_prerequisites ${thisFolder} ${thisCritical} ${thisBinary}
		if [ ${result} -eq 0 ] ; then
			check_GLIBC_prerequisites ${thisFolder} ${thisCritical} ${thisBinary}
			if [ ${result} -gt 0 ] ; then
				${SILENT_ECHO} " Failed: ${this_library_failurelist} is not available on this system"
			else
				${SILENT_ECHO} " Ok"
			fi
		else
			${SILENT_ECHO} "\nFailed: ${thisBinary} is missing the following libraries:"
			${SILENT_ECHO} "${this_library_failurelist}"
			if [ "${thisCritical}" = "stopinstall" ] ; then
				dump_this_error="${thisBinary} failed prequisite.  It is missing the following libraries:\n${this_library_failurelist}"
			fi
		fi
	elif [ "${thisOS}" = "${osLinux}" ] ; then
		${SILENT_ECHO} "Checking linux binary $thisFolder/$thisBinary ...\c"
		check_library_prerequisites ${thisFolder} ${thisCritical} ${thisBinary}
		if [ ${result} -eq 0 ] ; then
			check_GLIBC_prerequisites ${thisFolder} ${thisCritical} ${thisBinary}
			if [ ${result} -gt 0 ] ; then
				${SILENT_ECHO} "\nFailed: ${this_library_failurelist} is not available on this system"
				if [ "${thisCritical}" = "stopinstall" ] ; then
					dump_this_error="${thisBinary} failed prequisite.  ${this_library_failurelist} is not available on this system"
				fi
			else
				${SILENT_ECHO} " Ok"
			fi
		else
			${SILENT_ECHO} "\nFailed: ${thisBinary} is missing the following libraries:"
			${SILENT_ECHO} "${this_library_failurelist}"
			if [ "${thisCritical}" = "stopinstall" ] ; then
				dump_this_error="${thisBinary} failed prequisite.  It is missing the following libraries:\n${this_library_failurelist}"
			fi
		fi
	else
		${SILENT_ECHO} "Skipping check of binary $thisFolder/$thisBinary on ${thisOS}"
		result=0
	fi
	# Update global error count and failed list
	global_result=`expr ${global_result} + ${result}`
	if [ ${result} -gt 0 ] ; then
		if [ ! -z "${prereq_failed_list}" ] ; then
			prereq_failed_list="${prereq_failed_list}, "
		fi
		prereq_failed_list="${prereq_failed_list}${thisBinary}"
		
		if [ "${thisCritical}" = "stopinstall" ] ; then
			if [ ! -f ${InstallDir}/installlogs/prereqs-failed ] ; then
				${ECHO} "Failed prerequisites:" > ${InstallDir}/installlogs/prereqs-failed
				${ECHO} "=====================" >> ${InstallDir}/installlogs/prereqs-failed
				${ECHO} >> ${InstallDir}/installlogs/prereqs-failed
			fi
			${ECHO} ${dump_this_error} >> ${InstallDir}/installlogs/prereqs-failed
			
			
		fi
	fi
}

check_platform()
{
    packageplatformfile="${InstallDir}/installlogs/.runtimeplat"
    if [ ! -f "${packageplatformfile}" ]; then
	return 0
    fi
    packageplatform=`cat ${packageplatformfile}`
    packageOS=`${ECHO} ${packageplatform} | cut -f1 -d-`
    packageArch=`${ECHO} ${packageplatform} | cut -f2 -d-`

    case "${packageArch}" in
	x64 )
	    packageArch=${archx86_64}
	    ;;
	ppc64 )
	    packageArch=${archPpc}
	    ;;
	sparc64 )
	    packageArch=${archSparc}
	    ;;
    esac

    if [ "${thisOS}" != "${packageOS}" ] && [ "${thisOS}" != "${unknown}" ] && [ "${thisOS}" != "${osLinux}" ]; then
	local errMsg="FATAL ERROR: ${thisOS} OS is not compatible with ${packageOS} package OS"
	${ECHO} "${errMsg}"
	${ECHO} "${errMsg}" >> "${InstallDir}/installlogs/prereqs-failed"
	cd_and_exit 1
    fi

    if [ "${thisArch}" != "${packageArch}" ]; then
	local errMsg="FATAL ERROR: ${thisArch} architecture is not compatible with ${packageArch} package architecture"
	${ECHO} "${errMsg}"
	${ECHO} "${errMsg}" >> "${InstallDir}/installlogs/prereqs-failed"
	cd_and_exit 1
    fi
}

doIt()
{
	getThisPlatform
	set_platform_opts
	getInstallDir
	initialize $*
	prerequisites_prep
	${SILENT_ECHO} "Checking if package is compatible with platform"
	check_platform
	${SILENT_ECHO} "Checking to see if binaries will run on this platform"
	check_prerequisites ${InstallDir}/bin/sys stopinstall etxpm
	check_prerequisites ${InstallDir}/bin/sys stopinstall nodemaint
	check_prerequisites ${InstallDir}/bin/sys stopinstall openssl
	check_prerequisites ${InstallDir}/bin/sys continue etxauth
	check_prerequisites ${InstallDir}/bin/sys continue etxscan
	check_prerequisites ${InstallDir}/bin/sys continue etxstart
	
	# provide result
	case ${global_result} in
		0 )
			${SILENT_ECHO}
			${SILENT_ECHO} "All core binaries have passed prerequisite tests."
			;;
		1 )
			${SILENT_ECHO}
			${SILENT_ECHO} "One core binary has failed prerequisite tests:\n${prereq_failed_list}."
			;;
		*)
			${SILENT_ECHO}
			${SILENT_ECHO} "${global_result} core binaries have failed prerequisite tests:\n${prereq_failed_list}."
			;;
	esac
	export prereq_failed_list
	exit ${global_result}
}

doIt $*
