#!/bin/bash

EXIT_CODE=-1
EC_SUCCESS=0
EC_CLIENT_LOG_FILE_NOT_FOUND=209
EC_CLIENT_REGISTRATION_FAILED=210
EC_CLIENT_SERVICE_NOT_FOUND=211
EC_CLIENT_ALREADY_INSTALLED=212
EC_MISSING_SCRIPT_PARAM=213
EC_WRONG_SCRIPT_PARAM=214
EC_WGET_AND_CURL_NOT_FOUND=216
EC_WRONG_OS=217
EC_MISSING_OS_INFO=218
EC_INSTALLER_NOT_FOUND=220
EC_MASTHEAD_NOT_FOUND=221

command_exists() {
	type "$1" &> /dev/null;
}

RED_HAT_MATCHES=("red hat linux release " "red hat enterprise linux ws release " "red hat enterprise linux es release "
"red hat enterprise linux as release " "red hat enterprise linux server release "
"red hat enterprise linux server release " "red hat enterprise linux client release "
"red hat enterprise linux workstation release " "red hat enterprise linux release")
CENTOS_MATCHES=("centos release " "centos linux release ")
ROCKY_MATCHES=("rocky linux release")
OEL_MATCHES=("oracle linux server release " "oracle linux workstation release " "enterprise linux enterprise linux ")
SUSE_MATCHES=("suse linux enterprise server " "suse linux enterprise desktop " "suse linux" "suse sles-")
OS=""
OS_VER=""
OS_AND_VER=""
EXT=""
INSTALL_COMMAND=""
CHECK_COMMAND=""
ARCH=$(uname -m)

init_system_details() {
	if [[ -e "/etc/redhat-release" ]];
	then
		EXT="rpm"
		INSTALL_COMMAND="rpm -ivh"
		CHECK_COMMAND="rpm -qa"
		OUT=$(cat /etc/redhat-release)
		for match in "${RED_HAT_MATCHES[@]}"
		do
			if [[ $OUT == $match* ]];
			then
				OS_VER=$(echo ${OUT:${#match}} | cut -d ' ' -f 1)
				OS="Redhat"
				if [[ $ARCH == *"x86_64"* ]];
				then
					OS_AND_VER="rhe6"
					ARCH="x86_64"
				elif [[ $ARCH == *"ppc64"* ]];
				then
					OS_AND_VER="rhe7"
					ARCH="ppc64le"
				elif [[ $ARCH == *"s390x"* ]];
				then
					OS_AND_VER="rhe5"
					ARCH="s390x"
				fi
				break
			fi
		done

		if [[ "$OS" == "" ]];
		then
			for match in "${CENTOS_MATCHES[@]}"
			do
				if [[ $OUT == $match* ]];
				then
					OS_VER=$(echo ${OUT:${#match}} | cut -d ' ' -f 1)
					OS="CentOS"
					OS_AND_VER="rhe6"
					ARCH="x86_64"
					break
				fi
			done
		fi

		if [[ "$OS" == "" ]];
		then
			for match in "${ROCKY_MATCHES[@]}"
			do
				if [[ $OUT == $match* ]];
				then
					OS_VER=$(echo ${OUT:${#match}} | cut -d ' ' -f 1)
					OS="RockyLinux"
					OS_AND_VER="rhe6"
					ARCH="x86_64"
					break
				fi
			done
		fi

	elif [[ -e "/etc/oracle-release" ]];
	then
		EXT="rpm"
		INSTALL_COMMAND="rpm -ivh"
		CHECK_COMMAND="rpm -qa"
		OS_AND_VER="rhe6"
		ARCH="x86_64"
		OUT=$(cat /etc/oracle-release)
		for match in "${OEL_MATCHES[@]}"
		do
			if [[ $OUT == $match* ]]
			then
				OS_VER=$(echo ${OUT:${#match}} | cut -d ' ' -f 1)
				OS="OracleLinux"
				break
			fi
		done
	elif [[ -e "/etc/enterprise-release" ]];
	then
		EXT="rpm"
		INSTALL_COMMAND="rpm -ivh"
		CHECK_COMMAND="rpm -qa"
		OS_AND_VER="rhe6"
		ARCH="x86_64"
		OUT=$(cat /etc/enterprise-release)
		for match in "${OEL_MATCHES[@]}"
		do
			if [[ $OUT == $match* ]]
			then
				OS_VER=$(echo ${OUT:${#match}} | cut -d ' ' -f 1)
				OS="OracleLinux"
				break
			fi
		done
	elif [[ -e "/etc/SuSE-release" ]];
	then
		EXT="rpm"
		INSTALL_COMMAND="rpm -ivh"
		CHECK_COMMAND="rpm -qa"
		OUT=$(cat /etc/SuSE-release)
		for match in "${SUSE_MATCHES[@]}"
		do
			if [[ $OUT == $match* ]];
			then
				OS_VER=$(cat /etc/SuSE-release | sed -n 2p | cut -d ' ' -f 3)
				OS="Suse"
				if [[ $ARCH == *"x86_64"* ]];
				then
					OS_AND_VER="sle11"
					ARCH="x86_64"
				elif [[ $ARCH == *"ppc64"* ]];
				then
					OS_AND_VER="sle12"
					ARCH="ppc64le"
				elif [[ $ARCH == *"s390x"* ]];
				then
					OS_AND_VER="sle10"
					ARCH="s390x"
				fi
				break
			fi
		done
	elif [[ $(cat /proc/version) == *"Debian"* ]];
	then
		EXT="deb"
		INSTALL_COMMAND="dpkg -i"
		CHECK_COMMAND="dpkg -l"
		OS_AND_VER="debian6"
		ARCH="amd64"
		OUT=$(cat /etc/debian_version)
		OS="Debian"
		if [[ $OUT == *"/"* ]];
		then
			OUT=$(cat /etc/debian_version | cut -d '/' -f 1)
		fi
		RE='^[0-9]+([.][0-9]+)?$'
		if [[ $OUT =~ $RE ]];
		then
			OS_VER=$OUT
		else
			case "$OUT" in
				"jessie" ) 
					OS_VER="8.0" ;;
				"wheezy" ) 
					OS_VER="7.0" ;;
				"squeeze" )
					OS_VER="6.0" ;;
				"lenny" )
					OS_VER="5.0" ;;
				"etch" )
					OS_VER="4.0" ;;
				"sarge" )
					OS_VER="3.1" ;;
				"woody" )
					OS_VER="3.0" ;;
				"potato" )
					OS_VER="2.2" ;;
				"slink" )
					OS_VER="2.1" ;;
				"hamm" )
					OS_VER="2.0" ;;
			esac
		fi
	elif [[ $(cat /proc/version) == *"Ubuntu"* ]];
	then
		EXT="deb"
		INSTALL_COMMAND="dpkg -i"
		CHECK_COMMAND="dpkg -l"
		OS="Ubuntu"
		OS_VER=$(cat /etc/lsb-release | sed -n 2p | cut -d "=" -f 2)
		if [[ $ARCH == *"x86_64"* ]] || [[ $ARCH == *"amd64"* ]];
		then
			ARCH="amd64"
			OS_AND_VER="ubuntu10"
		elif [[ $ARCH == *"ppc64"* ]];
		then
			ARCH="ppc64el"
			OS_AND_VER="ubuntu144"
		fi
	elif [[ -e "/etc/os-release" ]];
	then
		RNAME=$(cat /etc/os-release | head -n 1 | sed 's/.$//' | sed 's/NAME="//')
		if [[ "$RNAME" == "SLES" ]] || [[ "$RNAME" == "openSUSE Leap" ]];
		then
			EXT="rpm"
			INSTALL_COMMAND="rpm -ivh"
			CHECK_COMMAND="rpm -qa"
			if [[ $ARCH == *"x86_64"* ]];
			then
				OS_AND_VER="sle11"
				ARCH="x86_64"
			elif [[ $ARCH == *"ppc64"* ]];
			then
				OS_AND_VER="sle12"
				ARCH="ppc64le"
			elif [[ $ARCH == *"s390x"* ]];
			then
				OS_AND_VER="sle10"
				ARCH="s390x"
			fi
			OS="Suse"
			if [[ "$RNAME" == "openSUSE Leap" ]];
			then
				OS="OpenSuseLeap"
			fi
			OS_VER=$(cat /etc/os-release | sed -n 2p | sed 's/.$//' | sed 's/VERSION="//')
		elif [[ $(cat /etc/os-release | head -n 1 | sed 's/.$//' | sed 's/NAME="//') == "Amazon Linux" ]];
		then
			EXT="rpm"
			INSTALL_COMMAND="rpm -ivh"
			CHECK_COMMAND="rpm -qa"
			OS_AND_VER="rhe6"
			ARCH="x86_64"
			OS="AmazonLinux"
			OS_VER=$(cat /etc/os-release | sed -n 2p | sed 's/.$//' | sed 's/VERSION="//')
			if [[ $(uname -m) == "aarch64" ]];
			then
				OS_AND_VER="al2"
				ARCH="aarch64"
			fi
		fi
	fi
}

download_file() {
	local SRC=$1
	local DST=$2
	local NAME=$3
	local NO_CHECK=$4
	local DOWNLOAD_CMD=""
	write_log "Downloading $NAME from: $SRC"
	if command_exists curl;
	then
		if $NO_CHECK;
		then
			DOWNLOAD_CMD="curl --insecure -fo $DST $SRC"
		else
			DOWNLOAD_CMD="curl -fo $DST $SRC"
		fi
		$DOWNLOAD_CMD
		EXIT_CODE=$?
		if [[ $EXIT_CODE -ne $EC_SUCCESS ]];
		then
			write_log "Error: $NAME download operation failed. Exit code: $EXIT_CODE"
			exit $EXIT_CODE
		fi
		write_log "$NAME download operation complete. Exit code: $EXIT_CODE"
	elif command_exists wget;
	then
		if $NO_CHECK;
		then
			DOWNLOAD_CMD="wget $SRC -O $DST --no-check-certificate --content-on-error=on"
		else
			DOWNLOAD_CMD="wget $SRC -O $DST --content-on-error=on"
		fi
		$DOWNLOAD_CMD
		EXIT_CODE=$?
		if [[ $EXIT_CODE -ne $EC_SUCCESS ]];
		then
			write_log "Error: $NAME download operation failed. Exit code: $EXIT_CODE"
			exit $EXIT_CODE
		fi
		write_log "$NAME download operation complete. Exit code: $EXIT_CODE"
	else
		write_log "Error: curl and wget commands not found, cannot start download. Exit code: $EC_WGET_AND_CURL_NOT_FOUND"
		exit $EC_WGET_AND_CURL_NOT_FOUND
	fi
}

start_service_and_check() {
	START_CMD="$1 start"
	STATUS_CMD="$1 status"
	$START_CMD
	EXIT_CODE=$?
	write_log "Checking if the $2 service is running"
	TIMER=0
	while [[ -z $($STATUS_CMD | grep -iE 'is running|active \(running\)') ]] && [[ $TIMER -lt 10 ]]
	do
		((TIMER++))
		sleep 1
	done

	test -z "$($STATUS_CMD | grep -iE 'is running|active \(running\)')"
}

wait_file() {
	local TIMER=0
	while [[ ! -f "$1" ]] && [[ $TIMER -lt $2 ]]
	do
		((TIMER++))
		sleep 1
	done

	test -f "$1"
}

# Creating a folder inside tmp to store files
TEMP_FOLDER_PATH="/tmp/BigFix"
mkdir -p $TEMP_FOLDER_PATH

# Creating the installation script log file
SCRIPT_LOG_FILE_PATH="$TEMP_FOLDER_PATH/BESAgentInstallScriptLog.txt"
if [[ -f $SCRIPT_LOG_FILE_PATH ]];
then
	>$SCRIPT_LOG_FILE_PATH
else
	touch $SCRIPT_LOG_FILE_PATH
fi

write_log() {
	echo $1 >> "$SCRIPT_LOG_FILE_PATH"
	echo $1
}

write_usage() {
	write_log "The syntax to run this script is: ./BESClientInstallScript.sh --besVersion <besVersion> 
	--relayName <relayName>"
	write_log "where besVersion is in the following format: <majorVersion>.<minorVersion>.<patch>.<buildNumber>"
}

# Logging script version
write_log "Agent installation script version 2 for BES V11"

# Logging command line arguments
write_log "Command line input: $*"

# Input parameters definition
BES_VERSION=""
RELAY_NAME=""
while [[ $# -gt 0 ]]
do
	case "$1" in
		--besVersion)
		shift
		BES_VERSION=$1
		shift
		;;
		--relayName)
		shift
		RELAY_NAME=$1
		shift
		;;
		*)
		write_log "Error: Wrong input paramter. Exit code: $EC_WRONG_SCRIPT_PARAM"
		write_usage
		exit $EC_WRONG_SCRIPT_PARAM
	esac
done

if [[ -z $BES_VERSION ]];
then
	write_log "Error: Missing input parameter besVersion. Exit code: $EC_MISSING_SCRIPT_PARAM"
	write_usage
	exit $EC_MISSING_SCRIPT_PARAM
elif [[ -z $RELAY_NAME ]];
then
	write_log "Error: Missing input parameter relayName. Exit code: $EC_MISSING_SCRIPT_PARAM"
	write_usage
	exit $EC_MISSING_SCRIPT_PARAM
fi

if [[ $(uname -s) != "Linux" ]];
then
	write_log "Error: operating system type not recognized as Linux. Exit code: $EC_WRONG_OS"
	exit $EC_WRONG_OS
fi

# Find OS, OS version, architecture to derive OS-based variables such as commands and extensions
write_log "Searching for operating system data..."
shopt -s nocasematch
init_system_details

write_log "The following information have been retrieved. OS: $OS, Version: $OS_VER, Architecture: $ARCH"
# Check if we found sufficient data for starting the installation
if [[ -z $OS_AND_VER ]] || [[ -z $ARCH ]] || [[ -z $EXT ]] || [[ -z $INSTALL_COMMAND ]] || [[ -z $CHECK_COMMAND ]];
then
	write_log "Error: Cannot retrieve enough data about the operating system. Exit code: $EC_MISSING_OS_INFO"
	exit $EC_MISSING_OS_INFO
fi

# Check if BigFix Client is already installed
INSTALLED_PACKAGES=$CHECK_COMMAND
if [[ -n $($INSTALLED_PACKAGES | grep -i BESAgent) ]];
then
	write_log "Error: BESAgent is already installed. Exit code: $EC_CLIENT_ALREADY_INSTALLED"
	exit $EC_CLIENT_ALREADY_INSTALLED
fi

write_log "BESAgent is not installed. Beginning installation..."

if ! [[ "$RELAY_NAME" == *":"* ]];
then
	write_log "Relay port not specified: assuming 52311"
	RELAY_NAME="$RELAY_NAME:52311"
fi

INSTALLER_SUFFIX="$OS_AND_VER.$ARCH.$EXT"
INSTALLER_NAME="BESAgent-$BES_VERSION-$INSTALLER_SUFFIX"
MASTHEAD_URL="https://$RELAY_NAME/masthead/masthead.afxm"
REL_VER=`echo $BES_VERSION | awk '/./ {gsub(/\./, " "); print $1 $2}'`
SOFTWARE_BIGFIX="https://software.bigfix.com/download/bes"
ACTIONSITE_DIR="/etc/opt/BESClient"
DOWNLOAD_URL="$SOFTWARE_BIGFIX/$REL_VER/$INSTALLER_NAME"
INSTALLER="$TEMP_FOLDER_PATH/$INSTALLER_NAME"
ACTIONSITE_PATH="$TEMP_FOLDER_PATH/actionsite.afxm"

# Download BigFix Agent installer and masthead
download_file "$DOWNLOAD_URL" "$INSTALLER" "BigFix Agent Installer" false
if [[ ! -s $INSTALLER ]];
then
	write_log "Error: installer file not found. Exit code: $EC_INSTALLER_NOT_FOUND"
	exit $EC_INSTALLER_NOT_FOUND
fi
write_log "Relay to download masthead from: $RELAY_NAME"
download_file "$MASTHEAD_URL" "$ACTIONSITE_PATH" "BigFix masthead" true
if [[ ! -s $ACTIONSITE_PATH ]];
then
	write_log "Error: masthead file not found. Exit code: $EC_MASTHEAD_NOT_FOUND"
	exit $EC_MASTHEAD_NOT_FOUND
fi


# Installing BigFix Client
write_log "Starting silent installation of BigFix Client..."
$INSTALL_COMMAND $INSTALLER
EXIT_CODE=$?
if [[ $EXIT_CODE -eq 0 ]] || [[ $EXIT_CODE -eq 3010 ]];
then
	write_log "BigFix Client installation complete. Exit code: $EXIT_CODE"
else
	write_log "Error: BigFix Client installation failed. Exit code: $EXIT_CODE"
	exit $EXIT_CODE
fi

# Copying the actionsite in the new actionsite directory
write_log "Creating actionsite directory: \"$ACTIONSITE_DIR\""
mkdir -p $ACTIONSITE_DIR
write_log "Copying the actionsite from \"$TEMP_FOLDER_PATH\" to \"$ACTIONSITE_DIR\""
cp $ACTIONSITE_PATH $ACTIONSITE_DIR

# Creating the clientsettings.cfg file
BESCONFIG_FILE="/var/opt/BESClient/besclient.config"
if [[ ! -f $BESCONFIG_FILE ]];
then
	touch $BESCONFIG_FILE
fi
CURR_DATE=$(date '+%a, %d %b %Y %T %z')
echo "[Software\BigFix\EnterpriseClient]
EnterpriseClientFolder = /opt/BESClient

[Software\BigFix\EnterpriseClient\GlobalOptions]
StoragePath = /var/opt/BESClient
LibPath = /opt/BESClient/BESLib

[Software\BigFix\EnterpriseClient\Settings\Client\__RelayServer1]
effective date = $CURR_DATE
value = http://$RELAY_NAME/bfmirror/downloads/

[Software\BigFix\EnterpriseClient\Settings\Client\__RelaySelect_Automatic]
effective date = $CURR_DATE
value = 0" >> $BESCONFIG_FILE

# Start BESAgent service and check whether is running
write_log "Starting BESClient service..."
BESCLIENT_INITD="/etc/init.d/besclient"
if start_service_and_check $BESCLIENT_INITD "BESClient";
then
	echo "Error: BESClient service starting operation failed. Exit code: $EXIT_CODE"
	exit $EXIT_CODE
fi

# Check whether the BigFix Client has registered
write_log "Checking the BigFix Client registration..."
BESCLIENT_LOG_FOLDER="/var/opt/BESClient/__BESData/__Global/Logs"
CURR_DATE=$(date '+%Y%m%d')
LOG_NAME="$CURR_DATE.log"
BESCLIENT_LOG="$BESCLIENT_LOG_FOLDER/$LOG_NAME"

if ! wait_file "$BESCLIENT_LOG" 10
then
	write_log "Error: Client log file \"$BESCLIENT_LOG\" could not be found. Exit code: $EC_CLIENT_LOG_FILE_NOT_FOUND"
	exit $EC_CLIENT_LOG_FILE_NOT_FOUND
fi

sleep 5
REGIST=$(head -128 $BESCLIENT_LOG | grep -i "\bRegistered with url\b")
if [[ -z $REGIST ]];
then
	write_log "Error: BigFix Client registration failed. Exit code: $EC_CLIENT_REGISTRATION_FAILED"
	exit $EC_CLIENT_REGISTRATION_FAILED
else
	write_log "BigFix Client registration completed. Exit code: $EC_SUCCESS"
	exit $EC_SUCCESS
fi

