#!/bin/sh
#
# Bitdefender (c) 2021
#

set -e

LC_ALL=C
DEBIAN_FRONTEND=noninteractive
export LC_ALL
export DEBIAN_FRONTEND

umask 0077

#
# These variables are populated by GravityZone
#
CONFIG_URL="https://cloudgz-ecs.gravityzone.bitdefender.com/Packages/BSTNIX/0/nzDSvc"
LOGINPASSWD="{LOGINPASSWD}"
STATUS_LINK="https://cloudgz-ecs.gravityzone.bitdefender.com/tasks/state"

#
# The 'taskId' argument must be the very first one
#
TASK_ID=$(printf "%s" "$1" | grep taskId | sed -e 's/taskId=/''/g' | sed -e 's/[{}]/''/g')

#
# Known actions:
#  1 - install
#  2 - reconfigure
#  3 - repair
#  4 - uninstall
#
CURRENT_ACTION=${CURRENT_ACTION:-1}

INSTALLER_DATE="Fri, 24 Dec 2021 00:02:33 +0200"
INSTALLER_VERSION="7.0.3.1927"
VERIFY_CERT=1
SDIR=$(readlink -f "$(dirname "$0")")
SNAME=${0##*/}
INSTALLER="$SDIR/$SNAME"
BDCONFIGURE="$SDIR/bdconfigure"
HOSTNAME=$(hostname)

BRAND="Bitdefender"
BRAND_LOW="bitdefender"
DIR="/opt/${BRAND_LOW}-security-tools"
LOG_DIR="$DIR/var/log"
LOG_FILE="$LOG_DIR/installer.log"
SETUP_DIR=${SETUP_DIR:-"$DIR/var/tmp/setup"}
INSTALLER_CONFIG=${INSTALLER_CONFIG:-$SETUP_DIR/installer.xml}
ARRAKIS_PRODUCT_ID=25

#
# There are two globals indicating locations from which files can be downloaded:
#   CONFIG_URL   - this is from where the installer components can be retreived
#                  (the installer configuration XML and the bdconfigure tool)
#   DOWNLOAD_URL - this is from where the files to be installed can be retrieved
#                  (package, repository signing key etc.)
#
DOWNLOAD_URL=""

PKG_MAJOR=7
PKG_MINOR=0
PKG_RELEASE=0
PKG_BUILD=0
PKG_ARCH=""
PKG_REMOTE_DIR=""
PKG_FILE=""

OS_ID=""
OS_VERSION=""
OS_BITNESS=""
OS_SUPPORTED=1

DO_SIG_CHECK=0

LOCKFILE="/tmp/bdinstaller.lock"

VERSION_TXT=""

SCAN_TYPE=""
REMOTE_SCAN=0
USE_SCAN_SETTINGS=0
BEST_LEGACY_PRESENT=0
BEST_LEGACY_DIRECTORY=""

#
# Disk space requirements (in 1KiB blocks)
#
FILESCAN_DISK_SPACE_REMOTE=614400                #  600MiB
FILESCAN_DISK_SPACE_FULL=1638400                 # 1600MiB
FILESCAN_DISK_SPACE_LIGHT=1126400                # 1100MiB
FILESCAN_DISK_SPACE_REMOTE_FULL=1638400          # 1600MiB
FILESCAN_DISK_SPACE_REMOTE_LIGHT=1126400         # 1100MiB
UPDATESERVER_DISK_SPACE_LIMIT=10485760           #   10GiB
PATCHMANAGEMENTSERVER_DISK_SPACE_LIMIT=104857600 #  100GiB

#
# Credits to Michael Holmes Hodgin
# https://unix.stackexchange.com/a/218505
#
_log ()
(
	p=
	mkfifo "${p:=$(mktemp -u)}"  &&
	printf %s "$p"               &&
	exec <&- >&- <>/dev/null >&0 &&
	{
		rm "$p"
		"$BDCONFIGURE" --logger-ident installer --logger-priority "$1" --logger-pid "$2" --logger "$LOG_FILE"
	} <"$p" &
)

logsetup ()
{
	mkdir -p "$LOG_DIR"
	exec >"$(_log info $$)" 2>"$(_log error $$)"
}

start_product ()
{
	if [ -x /bin/systemctl ]; then
		systemctl start bdsec
	else
		$DIR/bin/bd start >/dev/null
	fi
}

stop_product ()
{
	if [ -x /bin/systemctl ]; then
		systemctl stop bdsec
	else
		$DIR/bin/bd stop >/dev/null
	fi
}

product_is_enabled ()
{
	if [ -x /bin/systemctl ]; then
		systemctl is-active bdsec && return 0 || return 1
	fi

	if [ -x /sbin/chkconfig ]; then
		chkconfig bdsec && return 0 || return 1
	fi

	[ -L /etc/rc3.d/S80bdsec ] && return 0

	return 1
}

stop_arrakis ()
{
	if [ -x /bin/systemctl ]; then
		systemctl stop bdsec-arrakis
	elif [ -x $DIR/bin/arrakis ]; then
		$DIR/bin/arrakis -k >/dev/null
	fi
}

enable_arrakis ()
{
	if [ -x /bin/systemctl ]; then
		systemctl enable bdsec-arrakis
	fi
}

disable_arrakis ()
{
	if [ -x /bin/systemctl ]; then
		systemctl disable bdsec-arrakis
	fi
}

fetch ()
{
	local src="$1"
	local dst="$2"
	local force_verify="$3"

	printf "fetching \"$src\" into \"$dst\"\n"

	[ $VERIFY_CERT -eq 1 ] && force_verify=1
	[ -z "$force_verify" ] && force_verify=0

	if [ -x "$BDCONFIGURE" ]; then
		local bdconfigure_opt=""
		[ $force_verify -ne 1 ] && bdconfigure_opt="-k"
		"$BDCONFIGURE" $bdconfigure_opt -f "$src" -o "$dst"
	elif [ -x /usr/bin/curl ]; then
		local curl_opt=""
		[ $force_verify -ne 1 ] && curl_opt="-k"
		/usr/bin/curl $curl_opt -L --retry 2 -f -m 300 -s -o "$dst" "$src"
	elif [ -x /usr/bin/wget ]; then
		local wget_opt=""
		[ $force_verify -ne 1 ] && wget_opt="--no-check-certificate"
		/usr/bin/wget $wget_opt --tries 2 -T 300 -q -O "$dst" "$src"
	else
		return 1
	fi
}

http_post ()
{
	local data="$1"
	local url="$2"

	printf "POST-ing \"$data\" to \"$url\"\n"

	if [ -x "$BDCONFIGURE" ]; then
		local bdconfigure_opt=""
		[ $VERIFY_CERT -ne 1 ] && bdconfigure_opt="-k"
		"$BDCONFIGURE" $bdconfigure_opt -d "$data" -p "$url"
	elif [ -x /usr/bin/curl ]; then
		local curl_opt=""
		[ $VERIFY_CERT -ne 1 ] && curl_opt="-k"
		/usr/bin/curl $curl_opt --retry 2 -f -m 300 -s -d "$data" "$url"
		printf "\n"
	elif [ -x /usr/bin/wget ]; then
		local wget_opt=""
		[ $VERIFY_CERT -ne 1 ] && wget_opt="--no-check-certificate"
		/usr/bin/wget $wget_opt --tries 2 -T 300 -q -O - --post-data "$data" "$url"
		printf "\n"
	else
		return 1
	fi
}

#
# Known states:
#   200 - begin download
#   201 - end downloading
#   202 - remove competitor
#   203 - done removing competitor
#   204 - begin remove old version
#   205 - end remove old version
#   210 - begin installation
#   211 - end installation
#
post_status ()
{
	local state="$1"
	local error="$2"
	local timestamp=$(date +%s)
	local json=""

	[ -z "$STATUS_LINK" ] && return 0
	[ "$STATUS_LINK" = "{STATUS""_LINK}" ] && return 0

	[ -z "$TASK_ID" ] && return 0
	[ -z "$error" ] && error=0

	read json <<EOF || true
{"version":1,"action":$CURRENT_ACTION,"stateId":$state,"stateInfo":null,"error":$error,"timestamp":$timestamp,"taskId":"$TASK_ID"}
EOF

	http_post "$json" "$STATUS_LINK" || true
}

#
# This this is the generic exit point configured with 'trap <action> EXIT'
#
script_exit ()
{
	local err=$?

	if [ $err -gt 0 ]; then
		printf "the installer has unexpectedly exit with error $err\n" >&2
		if [ -x "$SETUP_DIR/bdaur" ]; then
			case "$CURRENT_ACTION" in
				1)
					post_status 211 $err
					"$SETUP_DIR/bdaur" -i $err >/dev/null 2>&1 || true
				;;
				2|3)
					post_status 211 $err
				;;
				4)
					"$SETUP_DIR/bdaur" -u $err >/dev/null 2>&1 || true
				;;
				*)
				;;
			esac
		fi
	fi

	return $err
}

#
# Known error codes:
#   1 - download URL not found
#   2 - download error
#   3 - file could not be copied; the package is corrupted or run on the wrong architecture
#   4 - could not create setup directory
#  10 - cannot find Linux distribution
#  11 - operating system not supported
#  12 - another installation is in progress
#  13 - could not uninstall Bitdefender Tools
#  16 - this package is already installed
#  19 - could not find configuration file
#  22 - cURL error (HTTP 4xx; see the curl(1) manual page for more information)
#  31 - uninstalling competitor product failed
#  74 - not enough disk space
#  75 - there is a problem with the package manager
#  77 - the current scan type configuration is not permitted
#  78 - could not install plugins
#  79 - invalid settings
#  80 - feature failed to install
#
die ()
{
	local err="$1"
	local msg="$2"

	[ -n "$msg" ] && printf "%s\n" "$msg" >&2

	post_status 211 "$err"

	# Disable the exit trap
	trap - EXIT

	if [ -x "$SETUP_DIR/bdaur" ]; then
		case "$CURRENT_ACTION" in
			1)
				"$SETUP_DIR/bdaur" -i $err >/dev/null 2>&1 || true
			;;
			4)
				"$SETUP_DIR/bdaur" -u $err >/dev/null 2>&1 || true
			;;
			*)
			;;
		esac
	fi

	exit $err
}

get_distro ()
{
	local distro=""
	local distrover=""

	if [ ! -f /etc/os-release ]; then
		if [ -f /etc/centos-release ]; then
			distro="centos"
			distrover=$(cat /etc/centos-release | egrep -o '[0-9.]+' || true)
		elif [ -f /etc/redhat-release ]; then
			distro="rhel"
			distrover=$(cat /etc/redhat-release | egrep -o '[0-9.]+' || true)
		elif [ -f /etc/SuSE-release ]; then
			distro="sles"
			distrover=$(cat /etc/SuSE-release | egrep -o '[0-9.]+' || true)
		elif [ -f /etc/debian_version ]; then
			distro="debian"
			distrover=$(cat /etc/debian_version | egrep -o '[0-9.]+' || true)
		else
			die 10 "/etc/os-release is missing"
		fi
	else
		. /etc/os-release

		distro="$ID"
		distrover="$VERSION_ID"
	fi

	OS_ID="$distro"
	OS_VERSION="$distrover"
}

update_arch ()
{
	PKG_ARCH=$(uname -m)

	case "$OS_ID" in
		debian|ubuntu|pardus)
			case "$PKG_ARCH" in
				i*86)
					PKG_ARCH="i386"
					PKG_REMOTE_DIR="linux-i386"
					OS_BITNESS="32"
				;;
				x86_64)
					PKG_ARCH="amd64"
					PKG_REMOTE_DIR="linux-amd64"
					OS_BITNESS="64"
				;;
				*)
					die 11 "unsupported architecture $PKG_ARCH"
				;;
			esac
		;;
		*)
			case "$PKG_ARCH" in
				i*86)
					PKG_ARCH="i686"
					PKG_REMOTE_DIR="linux-i386"
					OS_BITNESS="32"
				;;
				x86_64)
					PKG_REMOTE_DIR="linux-amd64"
					OS_BITNESS="64"
				;;
				*)
					die 11 "unsupported architecture $PKG_ARCH"
				;;
			esac
		;;
	esac
}

update_globals ()
{
	PKG_MAJOR=$(cut -d. -f 1 "$VERSION_TXT" | tr -d '\n\r')
	PKG_MINOR=$(cut -d. -f 2 "$VERSION_TXT" | tr -d '\n\r')
	PKG_RELEASE=$(cut -d. -f 3 "$VERSION_TXT" | tr -d '\n\r')
	PKG_BUILD=$(cut -d. -f 4 "$VERSION_TXT" | tr -d '\n\r')

	case "$OS_ID" in
		debian|ubuntu|pardus)
			PKG_FILE="${BRAND_LOW}-security-tools_${PKG_MAJOR}.${PKG_MINOR}.${PKG_RELEASE}-${PKG_BUILD}_${PKG_ARCH}.deb"
		;;
		almalinux|cloudlinux|rocky|amzn|centos|fedora|ol|rhel)
			PKG_FILE="${BRAND_LOW}-security-tools-${PKG_MAJOR}.${PKG_MINOR}.${PKG_RELEASE}-${PKG_BUILD}.${PKG_ARCH}.rpm"
		;;
		opensuse-leap|sles)
			PKG_FILE="${BRAND_LOW}-security-tools-${PKG_MAJOR}.${PKG_MINOR}.${PKG_RELEASE}-${PKG_BUILD}.${PKG_ARCH}.rpm"
		;;
		*)
			die 11 "unsupported distribution $OS_ID"
		;;
	esac

	printf "OS: $OS_ID\n"
	printf "OS version: $OS_VERSION\n"
	printf "kernel: $(uname -r)\n"
}

installed_version ()
{
	local ver=""

	case "$OS_ID" in
		debian|ubuntu|pardus)
			# Handle the case where the package was removed with 'apt-get remove' instead of 'apt-get purge'
			local p="$(dpkg-query -f '${Status}' --show "${BRAND_LOW}-security-tools" 2>/dev/null | grep -v deinstall || true)"
			[ -n "$p" ] && ver=$(dpkg-query -f '${Version}' --show "${BRAND_LOW}-security-tools" 2>/dev/null || true)
		;;
		almalinux|cloudlinux|rocky|amzn|centos|fedora|ol|opensuse-leap|rhel|sles)
			ver=$(rpm -q --queryformat='%{VERSION}-%{RELEASE}' "${BRAND_LOW}-security-tools" 2>/dev/null | grep -v "not installed" || true)
		;;
		*)
			die 11 "unsupported distribution $OS_ID"
		;;
	esac

	printf "$ver\n"
}

copy_file ()
{
	local src="$1"
	local dst="$2"

	printf "copying \"$src\" into \"$dst\"\n"
	cp -f "$src" "$dst"
}

copy_or_download ()
{
	local src="$1"
	local dst="$2"
	[ -z "$dst" ] && dst="$src"

	if [ -f "$SDIR/$src" ]; then
		local d=$(dirname "$dst")
		[ "$d" = "." ] || mkdir -p "$SETUP_DIR/$d"
		printf "copying \"$SDIR/$src\" into \"$SETUP_DIR/$dst\"\n"
		copy_file "$SDIR/$src" "$SETUP_DIR/$dst"
	else
		local d=$(dirname $dst)
		[ "$d" = "." ] || mkdir -p "$SETUP_DIR/$d"
		if ! fetch "$DOWNLOAD_URL/$src" "$SETUP_DIR/$dst"; then
			die 2 "failed to download '$DOWNLOAD_URL/$src'"
		fi
		DO_SIG_CHECK=1
	fi
}

do_jq()
{
	local expr="$1"
	local json_file="$2"
	local jq="$DIR/bin/jq"

	$jq "$expr" "$json_file" > "${json_file}.tmp" && \
		mv -f "${json_file}.tmp" "$json_file" || rm -f "${json_file}.tmp"
}

configure_epag ()
{
	local server="$1"
	local custid="$2"
	local conntime="$3"
	local customfield="$4"
	local appid="$5"
	local token="$6"
	local userid="$7"

	local proxy_server="$8"
	local proxy_port="$9"
	local proxy_user="${10}"
	local proxy_password="${11}"

	local epagjso="$DIR/etc/epagng/epagng.jso"

	do_jq ".conn.srvaddrlist=[\"$server\"]" "$epagjso"

	[ -n "$custid" ] && \
		do_jq ".id.custid=\"$custid\"" "$epagjso" || \
		do_jq ".id.custid=\"\"" "$epagjso"

	[ -n "$conntime" ] && \
		do_jq ".conn.timesec=$conntime" "$epagjso" || \
		do_jq ".conn.timesec=1800" "$epagjso"

	[ -n "$customfield" ] && \
		do_jq ".id.customdata=$customfield" "$epagjso" || \
		do_jq ".id.customdata={}" "$epagjso"

	[ -n "$appid" ] && \
		do_jq ".id.appid=$appid" "$epagjso" || \
		do_jq ".id.appid=12" "$epagjso"

	[ -n "$token" ] && \
		do_jq ".id.token=\"$token\"" "$epagjso" || \
		do_jq ".id.token=\"\"" "$epagjso"

	[ -n "$userid" ] && \
		do_jq ".id.userid=\"$userid\"" "$epagjso" || \
		do_jq ".id.userid=\"\"" "$epagjso"

	if [ -n "$proxy_server" ]; then
		do_jq ".conn.proxy.server=\"$proxy_server\"" "$epagjso"
		do_jq ".conn.proxy.port=$proxy_port" "$epagjso"
		do_jq ".conn.proxy.username=\"$proxy_user\"" "$epagjso"
		do_jq ".conn.proxy.password=\"$proxy_password\"" "$epagjso"
	else
		do_jq ".conn.proxy.server=\"\"" "$epagjso"
		do_jq ".conn.proxy.port=0" "$epagjso"
		do_jq ".conn.proxy.username=\"\"" "$epagjso"
		do_jq ".conn.proxy.password=\"\"" "$epagjso"
	fi
}

verify_signature ()
{
	local bst_url=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/downloadUrl" 2>/dev/null || true)
	local update_server=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/arrakisUpdateServer" 2>/dev/null || true)
	local sigcheck=0

	printf "verifying the digital signature (ecs)\n"
	if [ -n "$bst_url" ]; then
		for f in versions.dat versions.sig; do
			[ -f "$SDIR/$f" ] && cp -f "$SDIR/$f" "$SETUP_DIR/$f" || fetch "$bst_url/$f" "$SETUP_DIR/$f" || break
		done
		if [ -f "$SETUP_DIR/versions.dat" ] && [ -f "$SETUP_DIR/versions.sig" ]; then
			"$BDCONFIGURE" -C "$SETUP_DIR" || die 2
			printf "signature: OK\n"
			sigcheck=1
		fi
	fi

	[ $sigcheck -eq 1 ] && return 0

	printf "verifying the digital signature (update server)\n"
	local force_verify=0
	local upd_dns=$(printf "%s" "$update_server" | egrep -o '^[^\/:]+' | egrep -i -v '^.*\.bitdefender\.biz$' | sed 's#.*\.\(bitdefender\)\.[^.]\+#\1#' || true)
	if [ "$upd_dns" = "bitdefender" ]; then
		bst_url="https://download.bitdefender.com/SMB/Hydra/release/bst_nix7/$(cat "$SETUP_DIR/$PKG_REMOTE_DIR/version.txt" | head -n 1)"
		force_verify=1
	else
		[ -n "$update_server" ] && bst_url="$update_server/DownloadableKits/${ARRAKIS_PRODUCT_ID}_$(cat "$SETUP_DIR/$PKG_REMOTE_DIR/version.txt" | head -n 1)"
	fi

	if [ ! "$update_server" = "{ARRAKIS""_UPDATE_SERVER}" ] && [ -n "$bst_url" ]; then
		for f in versions.dat versions.sig; do
			[ -f "$SDIR/$f" ] && cp -f "$SDIR/$f" "$SETUP_DIR/$f" || fetch "$bst_url/$f" "$SETUP_DIR/$f" "$force_verify"
		done
		"$BDCONFIGURE" -C "$SETUP_DIR" || die 2
		printf "signature: OK\n"
	else
		printf "cannot verify the digital signature (no valid URL found)\n"
	fi
}

check_feature ()
{
	local action=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/features/feature[@name='$1']/@action" 2>/dev/null || true)
	[ "$action" = "1" ] && return 0
	return 1
}

install_antimalware_plugins ()
{
	local basedir="$DIR/var/lib/modules/antimalware"

	printf "installing the antimalware plugins \"$SETUP_DIR/$PKG_REMOTE_DIR/$PLUGINS_ARCHIVE\"\n"

	rm -rf "$basedir"
	mkdir -p "$basedir"
	tar -C "$basedir" -xzf "$SETUP_DIR/$PKG_REMOTE_DIR/$PLUGINS_ARCHIVE" "./etc" "./var/lib/scan/base-temp"

	# Use the installed bdconfigure to speed up the exception processing as the
	# one that's bundled with the installer is an SFX
	local bdc="$DIR/bin/bdconfigure"

	# Delete all update exceptions
	"$bdc" -s "/modules/update/scheduled/signatures/exceptions="

	# If present, load the new update exceptions
	if [ -f "$basedir/etc/updexc.xml" ]; then
		"$bdc" -I "$basedir/etc/updexc.xml" -r "/updexc/*" --xml-full-path | sed 's#.*\/\([^\/=]\+\).*#\1#' | while read updexc; do
			local x=0
			local y=1
			local v=$("$bdc" -I "$basedir/etc/updexc.xml" -r "/updexc/$updexc/item[$y]/@file" 2>/dev/null || true)
			( while [ -n "$v" ]; do
				printf "%s\n" "/modules/update/scheduled/signatures/exceptions/$updexc/$x=$v" && x=$((x + 1))
				y=$((y + 1))
				v=$("$bdc" -I "$basedir/etc/updexc.xml" -r "/updexc/$updexc/item[$y]/@file" 2>/dev/null || true)
			done ) | "$bdc" -s -
		done
	fi

	# Move the plugins to the right place, cleanup and adjust the permissions
	mv "$basedir/var/lib/scan/base-temp" "$basedir/base"
	rm -rf "$basedir/etc" "$basedir/var"
	chown -Rh root:root "$basedir"
	find "$basedir" -type d -exec chmod 0700 {} \;
	find "$basedir" -type f -exec chmod 0600 {} \;

	"$bdc" -s "/modules/antimalware/scanType=$SCAN_TYPE"
	[ $REMOTE_SCAN -eq 1 ] && \
		"$bdc" -s "/modules/remoteScan/enabled=true" || \
		"$bdc" -s "/modules/remoteScan/enabled=false"

	"$bdc" -s "/modules/remoteScan/serverOrder=0"
	"$bdc" -s "/modules/remoteScan/servers=" >/dev/null 2>&1 || true

	( si=0
	for s in $(seq 1 50); do
		local s_address=$("$bdc" -I "$INSTALLER_CONFIG" -r "/config/remoteScanSettings/servers/server[$s]/@address" 2>/dev/null || true)
		[ -z "$s_address" ] && break

		local s_ssl=$("$bdc" -I "$INSTALLER_CONFIG" -r "/config/remoteScanSettings/servers/server[$s]/@useSSL" 2>/dev/null || true)
		local s_id=$("$bdc" -I "$INSTALLER_CONFIG" -r "/config/remoteScanSettings/servers/server[$s]/@id" 2>/dev/null || true)
		local s_port=$("$bdc" -I "$INSTALLER_CONFIG" -r "/config/remoteScanSettings/servers/server[$s]/@port" 2>/dev/null || true)

		printf "%s\n" "/modules/remoteScan/servers/$si/address=$s_address"
		printf "%s\n" "/modules/remoteScan/servers/$si/port=$s_port"
		printf "%s\n" "/modules/remoteScan/servers/$si/useSSL=$s_ssl"
		printf "%s\n" "/modules/remoteScan/servers/$si/id=$s_id"

		si=$((si + 1))
	done ) | "$bdc" -s -
}

control_feature ()
{
	local feature="$1"
	local module="$2"
	local enabled=""
	local bdsecd_json="$DIR/etc/bdsecd.json"

	check_feature "$feature" && enabled="true" || enabled="false"
	printf "feature $feature -> $module -> $enabled\n"
	idx=$($DIR/bin/jq ".modules | map(.name == \"$module\") | index(true)" "$bdsecd_json" 2>/dev/null || true)
	if [ "$idx" = "null" ]; then
		"$DIR/bin/jq" ".modules[.modules | length] |= . + {\"name\":\"$module\",\"installed\":$enabled}" "$bdsecd_json" > "${bdsecd_json}.tmp"
		mv -f "${bdsecd_json}.tmp" "$bdsecd_json"
	elif [ -n "$idx" ]; then
		"$DIR/bin/jq" ".modules[$idx].installed=$enabled" "$bdsecd_json" > "${bdsecd_json}.tmp"
		mv -f "${bdsecd_json}.tmp" "$bdsecd_json"
	else
		printf "cannot control module \"$module\"\n" >&2
	fi

	case "$feature" in
		"FileScan")
			if [ $USE_SCAN_SETTINGS -ne 1 ]; then
				printf "not using the scan settings for module %s\n" "$module"
			elif [ "$module" = "onaccess" ]; then
				[ "$enabled" = "true" ] && \
					install_antimalware_plugins || \
					rm -rf "$DIR/var/lib/modules/antimalware"/*
			fi
		;;
		"UpdateServer" | "PatchManagementServer")
			check_feature "UpdateServer" && upds_enabled=1 || upds_enabled=0
			check_feature "PatchManagementServer" && pms_enabled=1 || pms_enabled=0

			if [ $upds_enabled -eq 1 ] || [ $pms_enabled -eq 1 ]; then
				enable_arrakis

				mkdir -p "$DIR/var/data" "$DIR/var/www" "$DIR/var/www2"

				printf "<?xml version=\"1.0\"?>\n<config version=\"1.0\">\t<features>\n" > "$DIR/etc/features.xml"

				[ $upds_enabled -eq 1 ] && \
					printf "\t\t<feature name=\"Relay\"/>\n" >> "$DIR/etc/features.xml"

				[ $pms_enabled -eq 1 ] && \
					printf "\t\t<feature name=\"PatchManagerServer\"/>\n" >> "$DIR/etc/features.xml"

				printf "\t</features>\n</config>\n" >> "$DIR/etc/features.xml"
			else
				disable_arrakis
				rm -rf "$DIR/var/data" "$DIR/var/www" "$DIR/var/www2"
				rm -f "$DIR/etc/features.xml"
			fi

			# Restore the default update server settings
			for cfg in allPlugins.xml generalSettings.xml http_proxy_server.xml kits.xml \
			           logsettings.xml patches.xml patchManager.xml products.xml relay.xml \
			           server.xml updatePlugin.xml; do
				cp -f "$DIR/etc/$cfg.dist" "$DIR/etc/$cfg"
			done
			rm -f "$DIR/etc/arrakis.xml"
		;;
		*)
		;;
	esac
}

control_features ()
{
	control_feature "FileScan" "ondemand"
	control_feature "FileScan" "onaccess"
	control_feature "FileScan" "malwaremonitor"
	control_feature "FileScan" "antimalware"
	control_feature "EventCorrelator" "edr"
	control_feature "EventCorrelator" "logmonitor"
	control_feature "EventCorrelator" "siem"
	control_feature "VulnerabilityAssessment" "vulnerabilityassessment"
	control_feature "AntiExploit" "antiexploit"
	control_feature "ContainerProtection" "container"
	control_feature "UpdateServer" "relay"
	control_feature "PatchManagement" "patchmanagement"
	control_feature "PatchManagementServer" "patchmanagementserver"
}

launch_best_legacy ()
{
	local tmpdir="$1"
	local update_server=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/arrakisUpdateServer" 2>/dev/null || true)
	local bst_nix="http://$update_server/bst_nix"
	local upd_dns=$(printf "%s\n" "$update_server" | egrep -o '^[^\/:]+' | egrep -i -v '^.*\.bitdefender\.biz$' | sed 's#.*\.\(bitdefender\)\.[^.]\+#\1#' || true)

	[ "$upd_dns" = "bitdefender" ] && \
		bst_nix="https://download.bitdefender.com/SMB/Hydra/release/bst_nix"

	local latest_dat="$bst_nix/latest.dat"

	rm -rf "$tmpdir"
	mkdir -p "$tmpdir"

	if [ -z "$update_server" ] || [ "$update_server" = "{ARRAKIS""_UPDATE_SERVER}" ]; then
		printf "cannot download BEST legacy (invalid update server)\n" >&2
		return 1
	fi

	if ! fetch "$latest_dat" "$tmpdir/bst_nix_latest.dat"; then
		printf "cannot download BEST legacy (failed to fetch latest.dat)\n" >&2
		return 1
	fi

	local version="$(cat "$tmpdir/bst_nix_latest.dat" | egrep -o '^25\s+6\.[0-9.]+' | awk '{ print $2 }')"
	if [ -z "$version" ]; then
		printf "cannot download BEST legacy (cannot determine the latest version)\n" >&2
		return 1
	fi

	# Prepare the installer files
	if ! fetch "$bst_nix/$version/downloader.sh" "$tmpdir/installer"; then
		printf "cannot download BEST legacy (cannot download downloader.sh)\n" >&2
		return 1
	fi
	if ! fetch "$bst_nix/$version/bdconfigure" "$tmpdir/bdconfigure"; then
		printf "cannot download BEST legacy (cannot download installer.xml)\n" >&2
		return 1
	fi
	cp -f "$INSTALLER_CONFIG" "$tmpdir/installer.xml"
	chmod u+x "$tmpdir/installer" "$tmpdir/bdconfigure"

	# Patch the installer (downloader.sh)
	sed -i "s#{URL""_CONFIG_NIX}#$bst_nix/$version#g" "$tmpdir/installer"
	[ "$LOGINPASSWD" = "{LOGIN""PASSWD}" ] || sed -i "s#{LOGIN""PASSWD}#$LOGINPASSWD#g" "$tmpdir/installer"
	sed -i "s#{STATUS""_LINK}#$STATUS_LINK#g" "$tmpdir/installer"

	# Patch installer.xml
	sed -i "s#^\s*<downloadUrl\s\+.*#\t<downloadUrl strVar=\"DownloadUrl\"><\![CDATA[$bst_nix/$version]]></downloadUrl>#" "$tmpdir/installer.xml"

	shift

	ERR=0
	"$tmpdir/installer" "$@" || ERR=$?
	printf "legacy installer exit code: $ERR\n"

	mv -f "$LOG_FILE" "$tmpdir"
	rm -rf "$DIR"

	exit $ERR
}

check_disk_space ()
{
	local check_dir="/"
	if [ -d "$DIR" ]; then
		check_dir="$DIR"
	elif [ -d "/opt" ]; then
		check_dir="/opt"
	fi

	local freespace=$(df -P "$check_dir" | tail -1 | tr -s ' \t\n\r' ' ' | cut -d' ' -f 4 || true)
	if [ -z "$freespace" ]; then
		die 74 "failed to determine the currently available disk space"
	fi

	printf "free disk space: ${freespace} KB\n"

	local stype=0
	if [ "$SCAN_TYPE" = "remote" ]; then
		[ $REMOTE_SCAN -eq 1 ] && stype=1 || stype=0
	elif [ "$SCAN_TYPE" = "light" ]; then
		[ $REMOTE_SCAN -eq 1 ] && stype=2 || stype=4
	else
		[ $REMOTE_SCAN -eq 1 ] && stype=3 || stype=5
	fi

	printf "scan type: $SCAN_TYPE ($stype)\n"
	[ $REMOTE_SCAN -eq 1 ] && printf "remote scan: enabled\n" || printf "remote scan: disabled\n"

	local requiredspace=0
	case "$stype" in
		1) requiredspace=$FILESCAN_DISK_SPACE_REMOTE ;;
		2) requiredspace=$FILESCAN_DISK_SPACE_REMOTE_LIGHT ;;
		3) requiredspace=$FILESCAN_DISK_SPACE_REMOTE_FULL ;;
		4) requiredspace=$FILESCAN_DISK_SPACE_LIGHT ;;
		5) requiredspace=$FILESCAN_DISK_SPACE_FULL ;;
	esac

	check_feature "UpdateServer" && \
		requiredspace=$((requiredspace + UPDATESERVER_DISK_SPACE_LIMIT)) || true

	check_feature "PatchManagementServer" && \
		requiredspace=$((requiredspace + PATCHMANAGEMENTSERVER_DISK_SPACE_LIMIT)) || true

	printf "required disk space: ${requiredspace} KB\n"

	[ $freespace -gt $requiredspace ] || \
		die 74 "not enough disk space (free: $freespace, required: $requiredspace)"
}

detect_vm ()
{
	local detect_vm=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectVM" 2>/dev/null || true)
	local stype=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectVM/@scanType" 2>/dev/null || true)
	local rscan=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectVM/@enableRemoteScan" 2>/dev/null || true)

	[ -z "$detect_vm" ] && return 1
	[ "$detect_vm" = "0" ] && return 1

	[ -z "$stype" ] && stype="light"
	[ -z "$rscan" ] && rscan=0

	#
	# We will resume to x86 hardware virtualization which, by standard, is required
	# to set the 'hypervisor' CPUID bit (see Intel SDM)
	#
	local is_vm=1
	grep hypervisor /proc/cpuinfo >/dev/null && is_vm=0 || is_vm=1

	if [ $is_vm -eq 0 ]; then
		printf "is VM: yes\n"
		"$BDCONFIGURE" -s "/global/systemInfo/isVM=true"

		SCAN_TYPE="$stype"
		REMOTE_SCAN="$rscan"
	else
		printf "is VM: no\n"
		"$BDCONFIGURE" -s "/global/systemInfo/isVM=false"
	fi
}

detect_server ()
{
	local chassis=$(dmidecode -s chassis-type 2>/dev/null || true)
	local is_server=0

	case "$chassis" in
		"Portable"|"Notebook"|"Laptop"|"Hand Held"|"Sub Notebook")
			is_server=1
		;;
		*)
		;;
	esac

	if [ $is_server -eq 0 ]; then
		printf "server system: yes\n"
		"$BDCONFIGURE" -s "/global/systemInfo/isServer=true"
	else
		printf "server system: no\n"
		"$BDCONFIGURE" -s "/global/systemInfo/isServer=false"
	fi

	return $is_server
}

detect_slow_machine ()
{
	local detect_sm=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectSlowMachine" 2>/dev/null || true)
	local stype=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectSlowMachine/@scanType" 2>/dev/null || true)
	local rscan=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectSlowMachine/@enableRemoteScan" 2>/dev/null || true)

	[ -z "$detect_sm" ] && return 1
	[ "$detect_sm" = "0" ] && return 1

	[ -z "$stype" ] && stype="light"
	[ -z "$rscan" ] && rscan=0

	local free_ram=$(free | grep Mem | tr -s ' ' | cut -d ' ' -f 2)
	local cpu_count=$(egrep -c 'processor\s*:' /proc/cpuinfo)
	local cpu_speeds=$(grep -i "cpu MHz" /proc/cpuinfo | tr -s ' ' | cut -d ' ' -f 3 | xargs printf "%s+")
	# cpu_speeds has a trailing '+', thus the need for a '0' in the expression below
	local cpu_avg_speed=$(awk -v "cpu_count=$cpu_count" "BEGIN{print int((${cpu_speeds}0) / cpu_count + 0.5)}")
	local is_slow=1

	printf "free RAM: $free_ram KiB\n"
	printf "CPU count: $cpu_count\n"
	printf "CPU average speed: $cpu_avg_speed MHz\n"

	[ $free_ram -lt 1048576 ] && is_slow=0
	[ $cpu_avg_speed -lt 1500 ] && is_slow=0

	if [ $is_slow -eq 0 ]; then
		printf "slow machine: yes\n"
		"$BDCONFIGURE" -s "/global/systemInfo/isSlowMachine=true"

		SCAN_TYPE="$stype"
		REMOTE_SCAN="$rscan"
	else
		printf "slow machine: no\n"
		"$BDCONFIGURE" -s "/global/systemInfo/isSlowMachine=false"
	fi

	return $is_slow
}

detect_amazon_ec2 ()
{
	local detect_ec2=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectEC2" 2>/dev/null || true)
	local stype=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectEC2/@scanType" 2>/dev/null || true)
	local rscan=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectEC2/@enableRemoteScan" 2>/dev/null || true)
	local ec2_url=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectEC2/@detectEC2Url" 2>/dev/null || true)
	local ec2_detected=1

	"$BDCONFIGURE" -s "/global/systemInfo/instanceIdEc2="

	[ -z "$detect_ec2" ] && return 1
	[ "$detect_ec2" = "0" ] && return 1

	[ -z "$stype" ] && stype="light"
	[ -z "$rscan" ] && rscan=0

	if fetch "$ec2_url" "$SETUP_DIR/ec2_data"; then
		read amzid < "$SETUP_DIR/ec2_data"
		if printf "$amzid" | egrep '(i|r|vol|snap|ami|aki|ari)-[0-9a-zA-Z]+' >/dev/null; then
			printf "EC2 instance ID: $amzid\n"

			"$BDCONFIGURE" -s "/global/systemInfo/instanceIdEc2=$amzid"

			SCAN_TYPE="$stype"
			REMOTE_SCAN="$rscan"

			ec2_detected=0
		fi
	fi

	rm -f "$SETUP_DIR/ec2_data"

	return $ec2_detected
}

detect_azure ()
{
	local detect_azure=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectAzure" 2>/dev/null || true)
	local stype=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectAzure/@scanType" 2>/dev/null || true)
	local rscan=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectAzure/@enableRemoteScan" 2>/dev/null || true)
	local azure_url=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanTypeDetection/detectAzure/@detectAzureUrl" 2>/dev/null || true)
	local azure_detected=1

	"$BDCONFIGURE" -s "/global/systemInfo/instanceIdAzure="

	[ -z "$detect_azure" ] && return 1
	[ "$detect_azure" = "0" ] && return 1

	[ -z "$stype" ] && stype="light"
	[ -z "$rscan" ] && rscan=0

	if fetch "$azure_url" "$SETUP_DIR/azure_data"; then
		read azureid < "$SETUP_DIR/azure_data"

		local char_count=$(printf "$azureid" | tr -d '\r\n' | sed 's#-##g' | wc -c)
		if [ $char_count -eq 32 ]; then
			printf "Azure instance ID: $azureid\n"

			"$BDCONFIGURE" -s "/global/systemInfo/instanceIdAzure=$azureid"

			SCAN_TYPE="$stype"
			REMOTE_SCAN="$rscan"

			azure_detected=0
		fi
	fi

	rm -f "$SETUP_DIR/azure_data"

	return $azure_detected
}

detect_scan_type ()
{
	#
	# Known scan types: remote, light, full
	#
	SCAN_TYPE=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/scanType" 2>/dev/null || true)
	if [ -z "$SCAN_TYPE" ]; then
		die 77 "cannot determine the scan type"
	fi

	case "$SCAN_TYPE" in
		full|light|remote)
			printf "scan type: $SCAN_TYPE\n"
		;;
		*)
			die 77 "unsupported scan type '$SCAN_TYPE'"
		;;
	esac

	REMOTE_SCAN=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/remoteScanSettings/enableRemoteScan" 2>/dev/null || true)
	if [ -z "$REMOTE_SCAN" ] || [ ! "$REMOTE_SCAN" = "1" ]; then
		REMOTE_SCAN=0
		[ "$SCAN_TYPE" = "remote" ] && SCAN_TYPE="light"
	else
		REMOTE_SCAN=1
	fi

	#
	# Basic check of the servers
	#
	if ! "$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/remoteScanSettings/servers/server[1]/@address" >/dev/null 2>&1; then
		REMOTE_SCAN=0
		[ "$SCAN_TYPE" = "remote" ] && SCAN_TYPE="light"
	fi

	#
	# Configure the scan settings
	#
	if ! detect_amazon_ec2 && ! detect_azure && ! detect_vm; then
		printf "nothing detected; proceeding with the default scan settings\n"
	fi

	#
	# Update the scan settings if the system is too slow
	#
	detect_slow_machine || true
}

fetch_antimalware_plugins ()
{
	[ "$SCAN_TYPE" = "light" ] && PLUGINS_ARCHIVE="plugins_lightav${OS_BITNESS}.tar.gz" || \
		PLUGINS_ARCHIVE="plugins_${SCAN_TYPE}${OS_BITNESS}.tar.gz"
	copy_or_download "$PKG_REMOTE_DIR/$PLUGINS_ARCHIVE"
}

uninstall_competitor ()
{
	local remove_competitor=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/competitorRemoval/execute/@mode" 2>/dev/null || true)

	[ -z "$remove_competitor" ] && return 1
	[ "$remove_competitor" = "never" ] && return 1

	local savscan=""
	local uninstaller="/opt/sophos-av/uninstall.sh"
	[ -L /usr/local/bin/savscan ] && savsan=$(readlink /usr/local/bin/savscan)
	[ -n "$savscan" ] && [ -x "$savscan" ] && uninstaller=${savscan%/*/*}/uninstall.sh

	if [ -x "$uninstaller" ]; then
		printf "removing Sophos\n"

		post_status 202

		$uninstaller --automatic --force >/dev/null 2>&1 || true
		pkill -9 savscand >/dev/null 2>&1 || true

		post_status 203
	else
		printf "no competitor detected\n"
	fi

	return 0
}

product_uninstall ()
{
	get_distro

	case "$OS_ID" in
		debian|ubuntu|pardus)
			apt-get purge -qq -y bitdefender-security-tools || true
		;;
		almalinux|cloudlinux|rocky|amzn|centos|fedora|ol|rhel)
			yum erase -q -y bitdefender-security-tools || true
		;;
		opensuse-leap|sles)
			zypper -q remove -y bitdefender-security-tools || true
		;;
		*)
			printf "unsupported distribution $OS_ID" >&2
			exit 11
		;;
	esac
}

check_update_server ()
{
	local server="$1"
	local use_ssl="$2"
	local use_proxy="$3"
	local upd_dns="$4"
	local url=""

	[ "$use_proxy" = "true" ] && \
		http_proxy=$("$BDCONFIGURE" --proxy-string 2>/dev/null || true) && \
		https_proxy=""

	export http_proxy
	export https_proxy

	if [ "$upd_dns" = "bitdefender" ]; then
		url="https://$server/bst_nix7"

		VERIFY_CERT=1

		fetch "$url/latest.dat" "$SETUP_DIR/latest.dat" >/dev/null || return 1
		local ver="$(cat "$SETUP_DIR/latest.dat" | awk '{ print $2 }')"

		fetch "$url/$ver/versions.dat" "$SETUP_DIR/versions.dat" >/dev/null || return 1
		fetch "$url/$ver/versions.sig" "$SETUP_DIR/versions.sig" >/dev/null || return 1

		printf "%s" "$url/$ver"
	else
		server=$(printf "%s" "$server" | sed 's#^[a-z]\+:\/\/##g')

		[ "$use_ssl" = "true" ] && \
			url="https://$server/DownloadableKits" || \
			url="http://$server/DownloadableKits"

		VERIFY_CERT=0

		fetch "$url/${ARRAKIS_PRODUCT_ID}_latest_downloaded_version.dat" \
			"$SETUP_DIR/${ARRAKIS_PRODUCT_ID}_latest_downloaded_version.dat" >/dev/null || return 1

		local ver="$(cat "$SETUP_DIR/${ARRAKIS_PRODUCT_ID}_latest_downloaded_version.dat")"

		fetch "$url/${ARRAKIS_PRODUCT_ID}_$ver/versions.dat" "$SETUP_DIR/versions.dat" >/dev/null || return 1
		fetch "$url/${ARRAKIS_PRODUCT_ID}_$ver/versions.sig" "$SETUP_DIR/versions.sig" >/dev/null || return 1

		printf "%s" "$url/${ARRAKIS_PRODUCT_ID}_$ver"
	fi

	return 0
}

product_reconfigure ()
{
	local is_active=0
	local use_ss=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/useScanSettings")

	product_is_enabled && is_active=1 || true

	# change the current directory to a known safe one
	cd "$(dirname "$INSTALLER_CONFIG")"

	printf "reconfiguring ...\n"

	# allow a bit of time for epag to process the response event to the
	# add/remove/modify task
	printf "sleeping for a bit\n"
	sleep 10

	update_arch

	detect_scan_type

	check_disk_space

	if [ "$use_ss" = "1" ]; then
		printf "searching for an appropriate update server\n"

		for i in $(seq 0 9); do
			upd_host=$("$BDCONFIGURE" -g "/modules/update/scheduled/product/locations/$i/host" 2>/dev/null || true)
			[ -z "$upd_host" ] && break

			upd_use_ssl=$("$BDCONFIGURE" -g "/modules/update/scheduled/product/locations/$i/useSSL" 2>/dev/null || true)
			upd_use_proxy=$("$BDCONFIGURE" -g "/modules/update/scheduled/product/locations/$i/useProxy" 2>/dev/null || true)

			upd_dns=$(printf "%s\n" "$upd_host" | egrep -o '^[^\/:]+' | egrep -i -v '^.*\.bitdefender\.biz$' | sed 's#.*\.\(bitdefender\)\.[^.]\+#\1#' || true)
			[ "$upd_dns" = "bitdefender" ] && \
				upd_host="download.bitdefender.com/SMB/Hydra/release" && \
				upd_use_ssl="true"

			printf "checking: %s (useSSL: %s, useProxy: %s)\n" "$upd_host" "$upd_use_ssl" "$upd_use_proxy"

			DOWNLOAD_URL=$(check_update_server "$upd_host" "$upd_use_ssl" "$upd_use_proxy" "$upd_dns" || true)
			[ -z "$DOWNLOAD_URL" ] && continue
			printf "%s" "$DOWNLOAD_URL" >"$SETUP_DIR/update-server"
			break
		done

		if [ ! -f "$SETUP_DIR/update-server" ]; then
			[ $is_active -eq 1 ] && start_product
			die 1 "no suitable update server found"
		fi

		printf "stopping the product (is active: $is_active)\n"
		stop_product

		DOWNLOAD_URL=$(cat "$SETUP_DIR/update-server")

		# Backup relevant configuration files
		[ -f "$DIR/etc/bdsecd.json" ] && \
			cp -f "$DIR/etc/bdsecd.json" "$SETUP_DIR/bdsecd.json.backup"
		[ -f "$DIR/var/cache/settings.bdsecd.enc" ] && \
			cp -f "$DIR/var/cache/settings.bdsecd.enc" "$SETUP_DIR/settings.bdsecd.enc.backup"

		fetch_antimalware_plugins

		if [ "$DO_SIG_CHECK" -eq 1 ]; then
			if ! "$BDCONFIGURE" -C "$SETUP_DIR"; then
				# Restore backups and bail
				[ -f "$SETUP_DIR/bdsecd.json.backup" ] && \
					mv -f "$SETUP_DIR/bdsecd.json.backup" "$DIR/etc/bdsecd.json"
				[ -f "$SETUP_DIR/settings.bdsecd.enc.backup" ] && \
					mv -f "$SETUP_DIR/settings.bdsecd.enc.backup" "$DIR/var/cache/settings.bdsecd.enc"
				[ $is_active -eq 1 ] && start_product
				die 2 "aborting"
			fi
		else
			printf "no files have been downloaded; not verifying the digital signature\n"
		fi

		USE_SCAN_SETTINGS=1
	else
		printf "stopping the product (is active: $is_active)\n"
		stop_product
	fi

	printf "controlling the features\n"
	control_features

	[ $is_active -eq 1 ] && printf "starting the product\n" && start_product

	printf "done\n"
}

configure_tls ()
{
	local gz_host=$(printf "%s" "$1" | egrep -i -o "^https:\/\/[^\/]+\.bitdefender\.[a-z]+\/" | sed 's#https:\/\/\([^\/]\+\).*#\1#' | egrep -i -v '^.*\.bitdefender\.biz$' || true)
	if [ -n "$gz_host" ]; then
		VERIFY_CERT=1
		printf "TLS certificate verification: enabled\n"
	else
		VERIFY_CERT=0
		printf "TLS certificate verification: disabled\n"
	fi
}

#
# This function targets Debian 8 in particular which has a version of apt
# that is unable to handle installing packages by path, eg:
#
#     apt-get install /opt/bitdefender-security-tools/var/tmp/setup/bitdefender-security-tools_7.0.0-0_amd64.deb
#
# In this case we do a two stage installation:
#
#     dpkg -i /opt/bitdefender-security-tools/var/tmp/setup/bitdefender-security-tools_7.0.0-0_amd64.deb ||
#         apt-get -q install -y -f
#
apt_too_old ()
{
	local ver=$(apt-get --version | egrep -o 'apt[[:blank:]]+[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+' | cut -d' ' -f 2 | awk -F. '{ print $1 * 10000 + $2 * 100 + $3 }')

	[ -z "$ver" ] && return 0

	# versions older than 1.2.0 are considered as being unable to install
	# packages by using a filesystem path
	[ $ver -lt 10200 ] && return 0

	return 1
}

detect_best_legacy_by_init_script ()
{
	local bd_script=""

	[ -L "/usr/bin/bd" ] && bd_script="$(readlink "/usr/bin/bd")"
	[ -n "$bd_script" ] && bd_script="$(basename "$bd_script")"

	[ "$bd_script" = "bd-sve-client" ] || return 1

	BEST_LEGACY_PRESENT=1

	local bd_sve_client="$(readlink "/usr/bin/bd")"
	local bd_bin_dir="$(dirname "$bd_sve_client")"

	BEST_LEGACY_DIRECTORY="$(cd "$bd_bin_dir/../" && pwd)"
}

detect_best_legacy_by_update_script ()
{
	local bdupdate=""
	local bd_bin_dir=""

	[ -L "/etc/cron.hourly/BitdefenderUpdateRecovery" ] && bdupdate="$(readlink "/etc/cron.hourly/BitdefenderUpdateRecovery")"
	[ -n "$bdupdate" ] && bd_bin_dir="$(dirname "$bdupdate")"

	[ -x "$bd_bin_dir/bd-sve-client" ] || return 1

	BEST_LEGACY_PRESENT=1

	BEST_LEGACY_DIRECTORY="$(cd "$bd_bin_dir/../" && pwd)"
}

detect_best_legacy ()
{
	detect_best_legacy_by_init_script || detect_best_legacy_by_update_script || true
}

upgrade_from_best_legacy ()
{
	local bd_dir="$BEST_LEGACY_DIRECTORY"

	printf "BEST legacy detected; upgrading ...\n"

	printf "stopping BEST legacy\n"
	if ! /usr/bin/bd stop; then
		printf "forcefully stopping all daemons\n"
		for b in bdmond bdepsecd bdsrvscand.bin bdupdated bdlogd bdregd epagd arrakis; do
			[ -x "$bd_dir/bin/$b" ] && printf "killing %s\n" "$b" && pkill -9 "$b" || true
		done
	fi

	printf "migrating the legacy epag database\n"
	"$SDIR/bdconfigure" --epag-migrate --epag-directory "$bd_dir/bin" --epag-logs "$bd_dir/var/epag"

	[ -d "$bd_dir/etc/epagng" ] && rm -rf "$DIR/etc/epagng" && cp -rf "$bd_dir/etc/epagng" "$DIR/etc/"
	[ -d "$bd_dir/var/epagng" ] && rm -rf "$DIR/var/epagng" && cp -rf "$bd_dir/var/epagng" "$DIR/var/"

	[ -d "$DIR/etc/epagng" ] && chown -Rh root:root "$DIR/etc/epagng"
	[ -d "$DIR/var/epagng" ] && chown -Rh root:root "$DIR/var/epagng"

	printf "migrating the quarantine\n"
	if [ -d "$bd_dir/var/quarantine" ]; then
		rm -rf "$DIR/var/quarantine"
		cp -rf "$bd_dir/var/quarantine" "$DIR/var/"
		chown -Rh root:root "$DIR/var/quarantine"
	fi

	if [ -x "$bd_dir/bin/arrakis" ] && check_feature "UpdateServer"; then
		printf "migrating the relay data\n"
		if [ -d "$bd_dir/var/data" ]; then
			rm -rf "$DIR/var/data"
			mv "$bd_dir/var/data" "$DIR/var/"
			chown -Rh root:root "$DIR/var/data"
			find "$DIR/var/data" -type d -exec chmod 0755 {} \;
			find "$DIR/var/data" -type f -exec chmod 0644 {} \;
		fi
		if [ -d "$bd_dir/var/www" ]; then
			rm -rf "$DIR/var/www"
			mv "$bd_dir/var/www" "$DIR/var/"
			chown -Rh root:root "$DIR/var/www"
			find "$DIR/var/www" -type d -exec chmod 0755 {} \;
			find "$DIR/var/www" -type f -exec chmod 0644 {} \;
		fi
		if [ -d "$bd_dir/var/www2" ]; then
			rm -rf "$DIR/var/www2"
			mv "$bd_dir/var/www2" "$DIR/var/"
			chown -Rh root:root "$DIR/var/www2"
			find "$DIR/var/www2" -type d -exec chmod 0755 {} \;
			find "$DIR/var/www2" -type f -exec chmod 0644 {} \;
		fi

		# Fix all symlinks
		if [ -d "$DIR/var/www" ]; then
			find "$DIR/var/www" -type l | while read lnk; do
				local old_target="$(readlink "$lnk")"
				local new_target="$(printf "$old_target" | sed "s#$bd_dir#$DIR#")"
				ln -sf "$new_target" "$lnk"
			done
		fi
		if [ -d "$DIR/var/www2" ]; then
			find "$DIR/var/www2" -type l | while read lnk; do
				local old_target="$(readlink "$lnk")"
				local new_target="$(printf "$old_target" | sed "s#$bd_dir#$DIR#")"
				ln -sf "$new_target" "$lnk"
			done
		fi
	fi

	printf "creating a backup of the BEST legacy installation\n"
	mkdir -p "$DIR/var/backup"
	tar \
		--exclude "$bd_dir/var/lib/scan/*/Plugins" \
		--exclude "$bd_dir/var/data" \
		--exclude "$bd_dir/var/www" \
		--exclude "$bd_dir/var/www2" \
		-czf "$DIR/var/backup/best_legacy.tar.gz" "$bd_dir"

	printf "removing BEST legacy\n"
	sed -i "s#UNINSTALLLINK=\$\+.*#UNINSTALLLINK=\"\"#g" "$bd_dir/bin/remove-sve-client"
	"$bd_dir/bin/remove-sve-client" isConsoleOrdered=true

	# Redo the symlink that the BEST legacy uninstaller most certainly removed
	ln -s "$DIR/bin/bd" /usr/bin/bd

	printf "upgrade complete\n"
}

product_repair ()
{
	KEEPQUAR=1
	export KEEPQUAR

	printf "starting repair\n"

	local tmpdir=$(mktemp -d "/tmp/bitdefender.XXXXXX")

	printf "setting up the installer configuration\n"
	cp -f "$SETUP_DIR/installer.xml" "$tmpdir/installer.xml"
	cp -f "$INSTALLER_CONFIG" "$tmpdir/installer.template.xml"

	printf "configuring the product features\n"
        for f in FileScan UserControl Antiphishing Firewall UpdateServer BehavioralScan \
		TrafficScan MailServers DataLossPrevention ApplicationControl PowerUser \
		MailServersForSandboxAnalyser EventCorrelator VolumeEncryption \
		PatchManagement PatchManagementServer VulnerabilityAssessment AntiExploit \
		NetworkMonitor; do
		local action=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/features/feature[@name='$f']/@action" 2>/dev/null || printf "0\n")
		printf "feature %s -> %s\n" "$f" "$action"
		"$BDCONFIGURE" -I "$tmpdir/installer.xml" -r "/config/features/feature[@name='$f']/@action" >/dev/null 2>&1 && \
			"$BDCONFIGURE" -I "$tmpdir/installer.xml" -w "/config/features/feature[@name\\='$f']/@action=$action"
	done

	local server=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/downloadUrl" 2>/dev/null || true)
	[ -z "$server" ] && die 1
	[ "$server" = "{DOWNLOAD""_URL}" ] && die 1

	printf "server: %s\n" "$server"

	configure_tls "$server"

	printf "downloading the installer components\n"

	fetch "$server/downloader.sh" "$tmpdir/installer"
	chmod +x "$tmpdir/installer"

	fetch "$server/bdconfigure" "$tmpdir/bdconfigure"

	printf "setting the download URL to: %s\n" "$server"
	"$BDCONFIGURE" -I "$tmpdir/installer.xml" -w "/config/downloadUrl=$server"

	printf "copying the proxy settings\n"
	for s in proxyServer proxyPort proxyUser proxyPass; do
		local value=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/$s" 2>/dev/null || true)
		printf "setting %s -> %s\n" "$s" "$value"
		"$BDCONFIGURE" -I "$tmpdir/installer.xml" -w "/config/$s=$value" 2>/dev/null || true
	done

	sed -i "s#{STATUS""_LINK}#$STATUS_LINK#" "$tmpdir/installer"

	local upds_feature=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/features/feature[@name='UpdateServer']/@action" || true)
	local pms_feature=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/features/feature[@name='PatchManagementServer']/@action" || true)
	if [ "$upds_feature" = "1" ] || [ "$pms_feature" = "1" ]; then
		printf "moving away the arrakis data\n"

		rm -rf "${DIR}.tmp/var"
		mkdir -p "${DIR}.tmp/var"

		stop_arrakis

		mv "$DIR/var/data" "${DIR}.tmp/var/"
		mv "$DIR/var/www" "${DIR}.tmp/var/"
		mv "$DIR/var/www2" "${DIR}.tmp/var/"
	else
		rm -rf "${DIR}.tmp/var"
		rmdir "${DIR}.tmp" >/dev/null 2>&1 || true
	fi

	cp -f "$LOG_FILE" "$tmpdir/installer.log"

	product_uninstall

	if [ -d "${DIR}.tmp/var" ]; then
		printf "restoring the arrakis data\n"
		mkdir -p "$DIR/var"
		[ -d "${DIR}.tmp/var/data" ] && rm -rf "$DIR/var/data" && mv "${DIR}.tmp/var/data" "$DIR/var/"
		[ -d "${DIR}.tmp/var/www" ] && rm -rf "$DIR/var/www" && mv "${DIR}.tmp/var/www" "$DIR/var/"
		[ -d "${DIR}.tmp/var/www2" ] && rm -rf "$DIR/var/www2" && mv "${DIR}.tmp/var/www2" "$DIR/var/"
		rm -rf "${DIR}.tmp/var"
		rmdir "${DIR}.tmp" >/dev/null 2>&1 || true
	fi

	unset INSTALLER_CONFIG
	unset CURRENT_ACTION

	ERR=0

	/bin/sh "$tmpdir/installer" "taskId=$TASK_ID" || ERR=$?

	CURRENT_ACTION=3 post_status 211

	rm -rf "$tmpdir"

	exit $ERR
}

configure_submissions ()
{
	local submit_dumps=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/submitDumps" 2>/dev/null || true)
	local submit_quar=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/submitQuar" 2>/dev/null || true)
	local submit_quar_interval=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/submitQuarInterval" 2>/dev/null || true)
	local submit_suspicious=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/submitSuspicious" 2>/dev/null || true)

	[ "$submit_dumps" = "1" ] && submit_dumps="true" || submit_dumps="false"
	[ "$submit_quar" = "1" ] && submit_quar="true" || submit_quar="false"

	[ "$submit_quar_interval" = "{SUBMIT""_QUARANTINE_SECONDS}" ] && submit_quar_interval=""
	[ -z "$submit_quar_interval" ] && submit_quar_interval="3600"

	[ "$submit_suspicious" = "1" ] && submit_suspicious="true" || submit_suspicious="false"

	"$BDCONFIGURE" -s "/global/submitDumps=$submit_dumps"
	"$BDCONFIGURE" -s "/global/submitQuar=$submit_quar"
	"$BDCONFIGURE" -s "/global/submitQuarInterval=$submit_quar_interval"
	"$BDCONFIGURE" -s "/global/cloud/allowFilesSubmission=$submit_suspicious"
}

check_download_url ()
{
	[ -f "$SDIR/installer.xml" ] && \
		DOWNLOAD_URL=$("$BDCONFIGURE" -I "$SDIR/installer.xml" -r "/config/downloadUrl" 2>/dev/null || true)
	[ -f "$INSTALLER_CONFIG" ] && [ -z "$DOWNLOAD_URL" ] && \
		DOWNLOAD_URL=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/downloadUrl" 2>/dev/null || true)
	if [ -z "$DOWNLOAD_URL" ] || [ "$DOWNLOAD_URL" = "{DOWNLOAD""_URL}" ]; then
		die 1 "cannot find the download URL"
	fi
	printf "download URL: $DOWNLOAD_URL\n"
}

trap script_exit EXIT

if [ "$SNAME" = "uninstall" ]; then
	BDUID=`id -u`
	if [ $BDUID -ne 0 ]; then
		printf "this script must be run as 'root'\n" >&2
		exit 79
	fi

	CURRENT_ACTION=4
	product_uninstall
	exit 0
fi

#
# If running as a regular user, then elevate the privileges to root
#
# NOTE: The privilege elevation must happen before trying to acquire the lock file.
#       Otherwise, we will run into a quagmire because of /proc/sys/fs/protected_regular
#       (see proc(5) for more information)
#
BDUID=`id -u`
if [ $BDUID -ne 0 ]; then
	if [ "$LOGINPASSWD" = "{LOGIN""PASSWD}" ]; then
		die 79 "missing login password"
	fi
	# The -E option is important in order to pass the FLOCKER environment variable
	# used to ensure only one instance of the script is run. 'Cg==' is an extra
	# encoded newline. Some versions of sudo require it.
	printf "%sCg==" "$LOGINPASSWD" | base64 -d | sudo -S -E "$INSTALLER" "$@"
	die $?
fi

#
# Do not allow multiple instances of the installer
#
[ "${FLOCKER}" != "$LOCKFILE" ] && exec env FLOCKER="$LOCKFILE" flock -en "$LOCKFILE" "$0" "$@" || :

#
# Not all installer files are readily available. Some need to be downloaded
#
# NOTE: This is a special case that prepares the usual install process, hence
#       the copy and move between $SETUP_DIR and $SDIR
#
if [ $CURRENT_ACTION -eq 1 ] && [ ! -f "$BDCONFIGURE" ]; then
	[ "$CONFIG_URL" = "{URL_CONFIG""_NIX}" ] && die 1 "cannot use CONFIG_URL to download bdconfigure"
	configure_tls "$CONFIG_URL"
	mkdir -p "$SETUP_DIR"

	DOWNLOAD_URL="$CONFIG_URL"
	copy_or_download "bdconfigure"
	mv -f "$SETUP_DIR/bdconfigure" "$BDCONFIGURE"
	DOWNLOAD_URL=""
fi

if [ $CURRENT_ACTION -eq 1 ] && [ ! -f "$SDIR/installer.xml" ]; then
	[ "$CONFIG_URL" = "{URL_CONFIG""_NIX}" ] && die 1 "cannot use CONFIG_URL to download installer.xml"
	configure_tls "$CONFIG_URL"
	mkdir -p "$SETUP_DIR"

	DOWNLOAD_URL="$CONFIG_URL"
	copy_or_download "installer.xml"
	mv -f "$SETUP_DIR/installer.xml" "$SDIR/installer.xml"
	DOWNLOAD_URL=""
fi

#
# Enable a script-wide logger
#
printf "Redirecting all output to "$LOG_FILE" ...\n"
chmod u+x "$BDCONFIGURE"
logsetup

printf "starting the installation ...\n"
printf "command line: %s\n" "$*"
printf "version: $INSTALLER_VERSION ($INSTALLER_DATE)\n"

# Uncomment the following two lines to enable debugging
# set -x
# set

# Prefetch the OS information
get_distro

for p in $*; do
	if [ "$p" = "--reconfigure" ]; then
		STATUS_LINK=$("$DIR/bin/jq" -r ".conn.srvaddr" "$DIR/etc/epagng/epagng.jso" 2>/dev/null | sed 's#\/hydra.*$#\/tasks/state#' || true)
		[ -n "$STATUS_LINK" ] && configure_tls "$STATUS_LINK"

		CURRENT_ACTION=2

		post_status 210
		product_reconfigure
		post_status 211
		exit 0
	elif [ "$p" = "--repair" ]; then
		STATUS_LINK=$("$DIR/bin/jq" -r ".conn.srvaddr" "$DIR/etc/epagng/epagng.jso" 2>/dev/null | sed 's#\/hydra.*$#\/tasks/state#' || true)
		[ -n "$STATUS_LINK" ] && configure_tls "$STATUS_LINK"

		CURRENT_ACTION=3

		post_status 210
		product_repair
		post_status 211
		exit 0
	fi
done

# copy_or_download uses DOWNLOAD_URL, so make sure it's set
check_download_url

#
# Sanity checks
#
printf "sanity checks\n"

INSTALL_PATH=$("$BDCONFIGURE" -I "$SDIR/installer.xml" -r "/config/installPath" 2>/dev/null || true)
[ -n "$INSTALL_PATH" ] && [ ! "$INSTALL_PATH" = "%PROGRAMFILES%" ] && die 79 "installations in custom directories are no longer supported ($INSTALL_PATH)"

if [ "$CONFIG_URL" = "{URL_CONFIG""_NIX}" ]; then
	printf "CONFIG_URL is unset. Using $DOWNLOAD_URL\n"
	CONFIG_URL="$DOWNLOAD_URL"
fi

[ -f "$BDCONFIGURE" ] || \
	die 1 "cannot find the executable bdconfigure"

[ -f "$SDIR/installer.xml" ] || \
	die 19 "cannot find the installer configuration file (installer.xml)"

#
# Determine if TLS certificate verification should be enabled or not
#
configure_tls "$DOWNLOAD_URL"

#
# Check if the product is already installed
#
INSTALLED_VERSION=$(installed_version)
[ -n "$INSTALLED_VERSION" ] && \
	printf "already installed version: $INSTALLED_VERSION\n"

#
# Place all files into $SETUP_DIR
#
printf "preparing to copy files\n"

rm -rf "$SETUP_DIR" && mkdir -p "$SETUP_DIR" || die 4
chmod 0755 "$DIR" \
	"$DIR/var" \
	"$DIR/var/tmp"

printf "copying all files into \"$SETUP_DIR\"\n"

copy_file "$INSTALLER" "$SETUP_DIR/installer"
chmod 0700 "$SETUP_DIR/installer"

copy_file "$BDCONFIGURE" "$SETUP_DIR/bdconfigure"
chmod 0700 "$BDCONFIGURE"

#
# Extract the telemetry tool (just in case)
#
"$SETUP_DIR/bdconfigure" extractbdaur

copy_file "$SDIR/installer.xml" "$INSTALLER_CONFIG"
chmod 0600 "$SDIR/installer.xml"

#
# Get the CPU architecture information
#
update_arch
printf "CPU: $(uname -m)\n"
printf "Package architecture: $PKG_ARCH\n"

if [ $OS_SUPPORTED -eq 0 ]; then
	launch_best_legacy "/tmp/bitdefender_legacy" "$@"
	die 11
fi

#
# Get the proxy configuration
#
PROXY_SERVER=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/proxyServer" 2>/dev/null || true)
if [ ! -z "$PROXY_SERVER" ]; then
	printf "setting up the proxy environment variables ($PROXY_SERVER)\n"

	PROXY_PORT=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/proxyPort" 2>/dev/null || true)
	PROXY_USER=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/proxyUser" 2>/dev/null || true)
	PROXY_PASS=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/proxyPass" 2>/dev/null || true)

	http_proxy=$("$BDCONFIGURE" --proxy-server "$PROXY_SERVER:$PROXY_PORT" --proxy-user "$PROXY_USER" --proxy-password "$PROXY_PASS" --proxy-string)
	https_proxy=""
	export http_proxy
	export https_proxy
else
	printf "no proxy configured\n"
fi

#
# Fetch the GravityZone status link (used mainly during automatic deployments)
#
[ "$STATUS_LINK" = "{STATUS""_LINK}" ] && \
	STATUS_LINK=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/statusLink" 2>/dev/null || true)
printf "status link: $STATUS_LINK\n"

# Begin download
post_status 200

copy_or_download "$PKG_REMOTE_DIR/version.txt"
VERSION_TXT="$SETUP_DIR/$PKG_REMOTE_DIR/version.txt"

update_globals

copy_or_download "$PKG_REMOTE_DIR/$PKG_FILE"

detect_scan_type
fetch_antimalware_plugins
USE_SCAN_SETTINGS=1

copy_or_download "$PKG_REMOTE_DIR/repo-key.gpg"
copy_or_download "$PKG_REMOTE_DIR/repo-key.asc"

# End download
post_status 201

#
# If a download has taken place, then proceed with the signature vertification
#
[ "$DO_SIG_CHECK" -eq 1 ] && verify_signature || printf "no files have been downloaded; not verifying the digital signature\n"

uninstall_competitor

check_disk_space

#
# The new product package will overwrite the '/usr/bin/bd' symlink, so we need
# to do the BEST legacy detection before proceeding with the installation
#
detect_best_legacy

# Begin installation
post_status 210

#
# Install the product package
#
printf "installing the product package \"$SETUP_DIR/$PKG_REMOTE_DIR/$PKG_FILE\"\n"
case "$OS_ID" in
	debian|ubuntu|pardus)
		mkdir -p /etc/apt/trusted.gpg.d
		cp -f "$SETUP_DIR/$PKG_REMOTE_DIR/repo-key.gpg" /etc/apt/trusted.gpg.d/bitdefender.gpg
		chmod 0644 /etc/apt/trusted.gpg.d/bitdefender.gpg
		if apt_too_old; then
			dpkg -i --refuse-downgrade "$SETUP_DIR/$PKG_REMOTE_DIR/$PKG_FILE" || \
				apt-get -q install -y -f || die 75
		else
			apt-get -q install -y "$SETUP_DIR/$PKG_REMOTE_DIR/$PKG_FILE" || die 75
		fi
	;;
	almalinux|cloudlinux|rocky|amzn|centos|fedora|ol|rhel)
		[ -z "$INSTALLED_VERSION" ] && YUM_OPTS="install" || YUM_OPTS="update"
		rpm --import "$SETUP_DIR/$PKG_REMOTE_DIR/repo-key.asc"
		if ! yum -q $YUM_OPTS -y "$SETUP_DIR/$PKG_REMOTE_DIR/$PKG_FILE"; then
			# Fail directly if this is not a full kit (ie. components were downloaded)
			[ $DO_SIG_CHECK -eq 0 ] || die 75

			# Attempt an offline install in case the environment is air gapped
			yum -q $YUM_OPTS -y "--disablerepo=*" "$SETUP_DIR/$PKG_REMOTE_DIR/$PKG_FILE" || die 75
		fi
	;;
	opensuse-leap|sles)
		rpm --import "$SETUP_DIR/$PKG_REMOTE_DIR/repo-key.asc"
		zypper -q install -y --no-recommends "$SETUP_DIR/$PKG_REMOTE_DIR/$PKG_FILE" || die 75
	;;
	*)
		die 11 "unsupported distribution $OS_ID"
	;;
esac

if [ $BEST_LEGACY_PRESENT -eq 1 ]; then
	upgrade_from_best_legacy || die 13
fi

if [ -z "$INSTALLED_VERSION" ]; then
	printf "configuring epagng\n"
	EPAG_SERVER=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/serverAddress" 2>/dev/null || true)
	if [ -z "$EPAG_SERVER" ]; then
		die 79 "cannot get the ECS server"
	fi

	EPAG_CUSTID=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/customerId" 2>/dev/null || true)
	EPAG_CONNTIME=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/connTime" 2>/dev/null || true)
	EPAG_CUSTOM_FIELD=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/epagCustomField" 2>/dev/null || true)
	EPAG_APPID=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/appId" 2>/dev/null || true)
	EPAG_TOKEN=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/epagConfig/authToken" 2>/dev/null || true)
	EPAG_USERID=$("$BDCONFIGURE" -I "$INSTALLER_CONFIG" -r "/config/userId" 2>/dev/null || true)

	configure_epag "$EPAG_SERVER" "$EPAG_CUSTID" "$EPAG_CONNTIME" "$EPAG_CUSTOM_FIELD" "$EPAG_APPID" "$EPAG_TOKEN" "$EPAG_USERID" \
		"$PROXY_SERVER" "$PROXY_PORT" "$PROXY_USER" "$PROXY_PASS"

	control_features

	configure_submissions

	printf "starting the product\n"
	start_product
else
	printf "skipping the product configuration (an upgrade was performed)\n"
fi

# End installation
post_status 211

printf "installation complete"
