#!/bin/bash
# Acronis agent install with token + cpanel plugin install
# Created by Curt Berry and Victor Sumin
# script name "acronis_install"
# created.08.20.2020
# modified.04.21.2026

TITLE="Acronis Agent Installation"
VERSION="6.0"

clear
csf_restart=0

# Vars
OS=""
MAJORVERSION=""
PKG_HANDLER=""
SCRIPTNAME=$(basename $BASH_SOURCE)
MEMORY_LIMIT=5000000
NOW=$(date +"%Y-%m-%d-%H-%M-%S")
TOKEN=""
NEEDSWAP=0
ARCLD_64=https://leaseweb-redirect.servint.net/acronis/Cyber_Protection_Agent_for_Linux_x86_64.bin
ARCLD_32=https://leaseweb-redirect.servint.net/acronis/Cyber_Protection_Agent_for_Linux_x86.bin
ARGNT=acronis.bin
ACRONIS_PLUGIN_DIR="/usr/local/cpanel/base/3rdparty/acronisbackup/python/site-packages/acronis_backup_srv/bash_scripts"
ARCH=$(uname -m | grep '64')
CSF="/usr/sbin/csf"

# Colorization
TS='\033[1;36m' # Color Light Cyan
LRED='\033[1;31m' # Color Light Red
LYELLOW='\033[1;33m' # Color Yellow
LGREEN='\033[1;32m' # Color Light Green
LGRAY='\033[0;37m' # Color Light Gray
WHITE='\033[1;37m' # Color White
NC='\033[0m' # No Color

function set_log_file() {
    if [[ "$LOG" -eq 1 ]]; then
        LOG_FILE="/root/${SCRIPTNAME}-${NOW}.log"
        rm -f $LOG_FILE
    else
        LOG_FILE=/dev/null
    fi
}

function disp() {
    if [[ "$LOG" -eq 1 ]]; then
        declare COLOR=$1
        echo -e "${!COLOR}$2${NC}"
        log "${!COLOR}$2${NC}"
    fi
}

function dispt() {
    if [[ "$LOG" -eq 1 ]]; then
        declare COLOR=$1
        echo -e "\n${!COLOR}{$((++i))} $2${NC}"
        log "${!COLOR}$2${NC}"
    fi
}

function dispn() {
    if [[ "$LOG" -eq 1 ]]; then
        declare COLOR=$1
        echo -en "${!COLOR}$2${NC}"
        log "${!COLOR}$2${NC}"
    fi
}

function log() {
    echo -e $1 >> $LOG_FILE;
}

function view_log() {
    if [[ "$LOG" -eq 1 ]]; then
        while true; do
            read -p "View the Log File? " yn
            case $yn in
                [Yy]* ) cat $LOG_FILE; break;;
                [Nn]* ) break;;
                    * ) disp 'LYELLOW' "Please answer (y)es or (n)o.";;
            esac
        done
    fi
}

function countdown() {
    local secs=$1
    shift
    local msg=$@
    while [ $secs -gt 0 ]
        do
            printf "\r\033[K${LGREEN}$msg${NC} ${LRED}%.d${NC} seconds" $((secs--))
            sleep 1
        done
    echo
}

function cdtempdir() {
    dispn 'WHITE' "+ Installing temp Directory ... "
    if [ ! -d "$TEMP_DIR" ]; then
        install -d $TEMP_DIR >> $LOG_FILE 2>&1
        disp 'LGREEN' 'done'
    else
        rm -rf $TEMP_DIR
        install -d $TEMP_DIR >> $LOG_FILE 2>&1
        disp 'LGREEN' 'done'
    fi
    dispn 'WHITE' "+ Changing to temp Directory  ... "
    cd $TEMP_DIR
    disp 'LGREEN' 'done'
}

function removetempdir() {
    dispn 'WHITE' '+ Removing temp dir ... '
    rm -rf $TEMP_DIR
    disp 'LGREEN' 'done'
}

function check_status() {
    local status=$1
    if [[ "$status" -eq 0 ]]; then
        disp 'LGREEN' 'done'
        return $status
    else
        disp 'LRED' 'failed'
        return $status
    fi
}

function title() {
    dispt 'TS' "$TITLE"
    disp 'LYELLOW' "Version: $VERSION"
    disp 'WHITE' "Logging in file $LOG_FILE"
}

function completed() {
    dispt 'TS' "$TITLE Completed"
}

function install_swap() {
    dispt 'TS' "Swap Space"
    dispn 'WHITE' '+ Downloading swap space script ... '
    wget --no-check-certificate -O centos_swap_space https://leaseweb-redirect.servint.net/files/centos_swap_space >> $LOG_FILE 2>&1
    if [[ $? -eq 0 ]]; then
        dispn 'WHITE' "setting permissions ... "
        chmod 700 centos_swap_space >> $LOG_FILE 2>&1
        check_status $?
        bash centos_swap_space
    else
        disp 'LRED' 'failed'
    fi
}

function check_swap() {
    if [ "$NEEDSWAP" -eq 1 ]; then
        disp 'LRED' "\n\n**** IMPORTANT: Need to add Swap to this system ****"
        while true; do
            read -p "Would you like to install swap? " yn
            case $yn in
                [Yy]* ) install_swap; break;;
                [Nn]* ) disp 'LGREEN' "Oh well.  Good luck with that."; break;;
                    * ) disp 'LYELLOW' "Please answer (y)es or (n)o.";;
            esac
        done
    fi
}

check_disk_space() {
    local mountpoint="${1:-/}"
    local min_gb=3               # threshold in GiB
    local min_bytes=$((min_gb * 1024 * 1024 * 1024))

    # `df` with machine‑readable output:
    #   -B1  → sizes in bytes
    #   --output=avail → only the available‑bytes column
    #   2>/dev/null silences errors (e.g. non‑existent mount)
    local avail_bytes
    avail_bytes=$(df -B1 --output=avail "${mountpoint}" 2>/dev/null | tail -1 | tr -d ' ')

    # If df failed or gave no numeric output, treat as error
    if [[ -z "$avail_bytes" || ! "$avail_bytes" =~ ^[0-9]+$ ]]; then
        printf "ERROR: Could not determine free space for \"%s\".\n" "$mountpoint" >&2
        exit 1
    fi

    # Compare
    if (( avail_bytes < min_bytes )); then
        # Convert to a human‑readable GiB value for the message
        local avail_gb=$(awk "BEGIN {printf \"%.2f\", $avail_bytes/1024/1024/1024}")
        printf "${LRED}WARNING: Only %.2f GiB free on \"%s\" (needs ≥ %d GiB) for installation${NC}\n" \
               "$avail_gb" "$mountpoint" "$min_gb" >&2
        exit 1
    fi

    # Enough space – silent success
    return 0
}

function download_agent() {
    dispt 'TS' "Downloading Acronis"
    rm -f $ARGNT >> $LOG_FILE 2>&1
    if [ ! -f $ARGNT ]; then
        if [ "$ARCH" != "" ]; then
            dispn 'WHITE' "+ Downloading 64-bit version ... "
            wget --no-check-certificate $ARCLD_64 -O $ARGNT >> $LOG_FILE 2>&1
            check_status $?
        else
            dispn 'WHITE' "+ Downloading 32-bit version ... "
            wget --no-check-certificate $ARCLD_32 -O $ARGNT >> $LOG_FILE 2>&1
            check_status $?
        fi
        dispn 'WHITE' "+ Setting executable permission ... "
        chmod +x $ARGNT
        check_status $?
    else
        dispn 'WHITE' "+ Older install agent still present ... "
        disp 'LRED' "failed"
        completed
        exit 0
    fi
}

function check_system {
    dispt 'TS' "Checking System"

    dispn 'WHITE' "+ Checking for swap ... "
    MEMORY=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    SWAP=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
    if [ "$MEMORY" -lt "$MEMORY_LIMIT" ] && [ "$SWAP" -lt 500000 ]; then
        NEEDSWAP=1
        disp 'LRED' "needed"
    else
        disp 'LGREEN' "good"
    fi

    if test -f /etc/csf/csf.conf; then
        dispt 'TS' "Checking CSF Configuration"

        dispn 'WHITE' "+ Checking Acronis Ports ... "
        if grep 44445 /etc/csf/csf.conf >> $LOG_FILE 2>&1; then
            disp 'LGREEN' "correct"
        else
            dispn 'WHITE' "adding ... "
            sed -i '/^TCP_OUT/ s/^\(.*\)\("\)/\1,8443,25001,445,44445,55556,5060,6109,5905,7770:7800,49152:65534"/' /etc/csf/csf.conf
            check_status $?
            csf_restart=1
        fi

        dispn 'WHITE' "+ Adding Acronis IP Ranges ... "
        $CSF -a 185.151.160.0/24 Acronis Backups >> $LOG_FILE 2>&1;
        $CSF -a 185.151.161.0/24 Acronis Backups >> $LOG_FILE 2>&1;
        $CSF -a 62.138.210.0/24  Acronis Backups >> $LOG_FILE 2>&1;
        $CSF -a 162.244.6.0/24   Acronis Backups >> $LOG_FILE 2>&1;
        $CSF -a 162.244.7.0/24   Acronis Backups >> $LOG_FILE 2>&1;
        $CSF -a 45.11.129.61     Acronis Backups >> $LOG_FILE 2>&1;
        $CSF -a 45.11.129.62     Acronis Backups >> $LOG_FILE 2>&1;


        disp 'LGREEN' "done"

        dispn 'WHITE' "+ Checking MaxMind configuration ... "
        if grep 'MM_LICENSE_KEY = ""' /etc/csf/csf.conf >> $LOG_FILE 2>&1 && grep '^CC_SRC = "1"' /etc/csf/csf.conf >> $LOG_FILE 2>&1; then
            dispn 'WHITE' "setting CC_SRC to 2 ... "
            sed -i '/^CC_SRC =/ c CC_SRC = "2"' /etc/csf/csf.conf
            disp 'LGREEN' "done"
            csf_restart=1
        else
            disp 'LGREEN' "correct"
        fi

        dispn 'WHITE' "+ Checking Leaseweb Blocklist ... "
        if grep "LWEXIMEXP" /etc/csf/csf.blocklists >> $LOG_FILE 2>&1; then
            disp 'LGREEN' "installed"
        else
            dispn 'WHITE' "installing ... "
            echo -e "\n# Leaseweb Support DOS BlockList\nLWEXIMEXP|3600|0|https://leaseweb-redirect.servint.net/blocklist/blocklist.txt" >> /etc/csf/csf.blocklists
            check_status $?
            csf_restart=1
        fi

        if [ $csf_restart -eq 1 ]; then
            dispn 'WHITE' "+ Restarting CSF ... "
            if [[ "$MAJORVERSION" -le 7 ]]; then
                service csf restart >> $LOG_FILE 2>&1
                check_status $?
            else
                systemctl restart csf >> $LOG_FILE 2>&1
                check_status $?
            fi
            dispn 'WHITE' "+ Restarting LFD ... "
            if [[ "$MAJORVERSION" -le 7 ]]; then
                service lfd restart >> $LOG_FILE 2>&1
                check_status $?
            else
                systemctl restart lfd >> $LOG_FILE 2>&1
                check_status $?
            fi
        fi
    fi

}

function install_a3_cache {
    if [[ "$MAJORVERSION" -le 7 ]]; then
        dispt 'TS' "Acronis A3_CACHE_SIZE Check Script"

        countdown 60 "+ Waiting 60 seconds for registration to take effect ... "
        disp 'LGREEN' " ... done"

        dispn 'WHITE' "+ Downloading acronis_a3_cache ... "
        wget --no-check-certificate -O /etc/cron.daily/acronis_a3_cache https://leaseweb-redirect.servint.net/files/acronis_a3_cache >> $LOG_FILE 2>&1
        if [[ $? -eq 0 ]]; then
            dispn 'WHITE' "setting permissions ... "
            chmod 700 /etc/cron.daily/acronis_a3_cache >> $LOG_FILE 2>&1
            dispn 'WHITE' "running ... "
            /etc/cron.daily/acronis_a3_cache >> $LOG_FILE 2>&1
            check_status $?
        else
            disp 'LRED' 'failed'
        fi
    fi
}

function log_check_acronis_plugin_call() {
    local texttoshow=$1
    local preliminary=0
    local secs=0
    local regex="[-:]\s+(.+)$"
    local regex_error="E?e?rror"
    tail $LOG_FILE -n0 -F --retry | while read line; do
        if [[ "$line" =~ $regex_error ]]; then
            printf "\r\033[K${WHITE}${texttoshow}${NC}${LRED}%s${NC}" "$line"
            pkill -9 -P $$ tail >> $LOG_FILE 2>&1
            echo
            sleep 2
            break
        fi
        if [[ "$line" =~ $regex ]]; then
            found=${BASH_REMATCH[1]}
            if [[ "$found" =~ 'Cleaning up' ]]; then
                printf "\r\033[K${WHITE}${texttoshow}${NC}${LGREEN}%s${NC}" "Cleaning Up"
            elif [[ "$found" =~ 'Closing this script' ]]; then
                printf "\r\033[K${WHITE}${texttoshow}${NC}${LGREEN}%s${NC}" "Launching Backup"
                pkill -9 -P $$ tail >> $LOG_FILE 2>&1
                echo
                sleep 2
                break
            else
                printf "\r\033[K${WHITE}${texttoshow}${NC}${LGREEN}%s${NC}" "$found"
            fi
      fi
    done
}

function set_acronis_plugin_plan() {
    # This will set the configuration for the Acronis Backup Plugin
    # and auto run the backup.
    local hour
    local minute
    hour=$((20 + $RANDOM % 10))
    if [[ "$hour" -gt 23 ]]; then
        hour=$(($hour - 24))
    fi
    minute=$((0 + $RANDOM % 59))

    dispn 'WHITE' "+ Setting Acronis Plan to start at hour $hour and minute $minute ... "

    # NOTE: Acronis keeps flipflopping directory structures
    if [ -d /usr/local/cpanel/base/3rdparty/acronisbackup/python/lib/python3.8/site-packages/acronis_backup_srv/bash_scripts ]; then
        ACRONIS_PLUGIN_DIR="/usr/local/cpanel/base/3rdparty/acronisbackup/python/lib/python3.8/site-packages/acronis_backup_srv/bash_scripts"
    fi

    echo "[configurator]

acronis_cyber_cloud_url = cloud.acronis.com
acronis_cyber_cloud_login =
acronis_cyber_cloud_password =
acronis_cyber_cloud_client_id =
acronis_cyber_cloud_client_secret =
encryption_password =
encryption_type = aes256
# Next options accept integer values, e.g. retention_weeks = 5
retention_days = 7
retention_weeks = 4
retention_months = 2
backup_start_hours = $hour
backup_start_minutes = $minute
retention_number_of_backups =
reattempts =
reattempt_period =
alert_period =
# This option accepts single pair of integer and suffix \"m\" or \"h\", e.g. 30m or 5h
# Available only for initial backup configuration
backup_start_delay_window = 1h
# These two options accept binary integer values, 0 or 1
enable_backup = 1
run_backup = 1" > $ACRONIS_PLUGIN_DIR/configurator.ini
    disp 'LGREEN' "done"

    dispn 'WHITE' "+ Configuring ... "
    dispn 'LGREEN' "waiting 15 seconds for Plugin to start"
    sleep 15
    sh $ACRONIS_PLUGIN_DIR/configurator.sh >> $LOG_FILE 2>&1 &
    log_check_acronis_plugin_call "+ Configuring ... "
}

function tokeninstall {
    dispt 'TS' "Token Install"
    check_system

    dispn 'WHITE' "+ Checking for agent ... "
    if [ -f /usr/sbin/acronis_mms ] ; then
        disp 'LRED' "installed"
    else
        disp 'LGREEN' "not installed"
        download_agent
        dispt 'TS' "Installing Acronis Agent"
        sh $ARGNT -a --token $TOKEN
        install_a3_cache
    fi
}

function reinstall {
    dispt 'TS' "Acronis Reinstall"
    check_system
    download_agent
    dispt 'TS' "Installing Acronis Agent"
    sh $ARGNT -a --skip-registration
    install_a3_cache
}

function reregister {
    dispt 'TS' "Acronis Re-Register"
    check_system
    dispt 'TS' "Registering with token $TOKEN"
    dispn 'WHITE' "+ Registering ... "
    /usr/lib/Acronis/RegisterAgentTool/RegisterAgent -o register -t cloud -a https://us-cloud.acronis.com --token $TOKEN
    check_status $?
    install_a3_cache
}

function install_acronis_backup_plugin_call() {
    dispt 'TS' "Acronis Backup Plugin"
    dispn 'WHITE' "+ Checking for Acronis Agent ... "
    if [ -f /usr/sbin/acronis_mms ] ; then
        disp 'LGREEN' 'found'
        dispn 'WHITE' "+ Checking for Acronis Backup Plugin ... "
        if rpm -q acronis-backup-cpanel | grep 'not installed' >> $LOG_FILE 2>&1 ; then
            disp 'LGREEN' "not installed"
            cdtempdir
            dispn 'WHITE' "+ Downloading ... "
            wget --no-check-certificate -O install_acronis_cpanel.sh https://download.acronis.com/ci/cpanel/stable/install_acronis_cpanel.sh >> $LOG_FILE 2>&1
            if [ $? -ne 0 ]; then
                disp 'LRED' 'failed'
            else
                disp 'LGREEN' "done";
                dispn 'WHITE' "+ Installing ... ";
                sh install_acronis_cpanel.sh >> $LOG_FILE 2>&1
                if [ $? -eq 0 ]; then
                    disp 'LGREEN' "done"
                    set_acronis_plugin_plan
                else
                    disp 'LRED' 'failed'
                fi
            fi
            removetempdir
        else
            disp 'LGREEN' 'installed'
        fi
    else
        disp 'LRED' 'not installed'
    fi
}


function pluginreinstall {
    dispt 'TS' "Re-Install cPanel Acronis Plugin"
    dispn 'WHITE' "+ Removing Plugin ... "
    export UNINSTALL_BACKUP_AGENT=0
    $PKG_HANDLER -y remove acronis-backup-cpanel >> $LOG_FILE 2>&1
    check_status $?
    ps aux | grep acronis_backup_srv | awk '{print $2}' | xargs kill -9 >> $LOG_FILE 2>&1
    dispn 'WHITE' "+ Installing Plugin ... "
    $PKG_HANDLER -y install acronis-backup-cpanel >> $LOG_FILE 2>&1
    check_status $?
}

function pluginuninstall {
    dispt 'TS' "Uninstall cPanel Acronis Plugin"
    dispn 'WHITE' "+ Checking for plugin ... "
    if rpm -q acronis-backup-cpanel | grep 'not installed' >> $LOG_FILE 2>&1 ; then
        disp 'LRED' "not installed"
    else
        disp 'LGREEN' "found"
        dispn 'WHITE' "+ Removing plugin ... "
        $PKG_HANDLER -y remove acronis-backup-cpanel >> $LOG_FILE 2>&1
        check_status $?
    fi
}

function pluginfix {
    dispt 'TS' "Fix cPanel Acronis Plugin"
    dispn 'WHITE' "+ Downloading Plugin Fix ... "
    install -d /usr/local/cpanel/base/frontend/paper_lantern
    cd /usr/local/cpanel/base/frontend/paper_lantern
    wget --no-check-certificate -O acronisbackup.tar https://leaseweb-redirect.servint.net/files/acronisbackup.tar >> $LOG_FILE 2>&1
    if [[ $? -eq 0 ]]; then
        disp 'LGREEN' 'done'
        dispn 'WHITE' "Untarring fix ... "
        tar xvf acronisbackup.tar >> $LOG_FILE 2>&1
        check_status $?
	rm -f acronisbackup.tar
    else
        disp 'LRED' 'failed'
    fi
    cd /root
}

function mmsuninstall {
    dispt 'TS' "Uninstall Acronis"
    dispn 'WHITE' "+ Removing Acronis ... "
    sh /usr/lib/Acronis/BackupAndRecovery/uninstall/uninstall -u -a >> $LOG_FILE 2>&1
    check_status $?
}

function os_major_version {
    if test -f /etc/lsb-release; then
        OS=$(cat /etc/lsb-release | grep DISTRIB_ID | awk -F '=' '{print $2}' | tr -d '\n')
        MAJORVERSION=$(cat /etc/lsb-release | grep DISTRIB_RELEASE | tr -dc '0-9.'|cut -d \. -f1 | tr -d '\n')
        PKG_HANDLER="dnf"
    else
        OS=$(cat /etc/redhat-release | awk '{print $1}' | tr -d '\n');
        MAJORVERSION=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1 | tr -d '\n')
        PKG_HANDLER="yum"
    fi
}

# Set OS and Major Version vars
os_major_version

function help {
    echo -e "\n${TS}OS:${NC} $OS $MAJORVERSION"
    echo -e "\n${TS}Fresh install via token${NC}\n$0 --acronis-token xxxx-xxxx-xxxx\n"
    echo -e "${TS}Reinstall or Update the Acronis Agent${NC}\n$0 --acronis-reinstall\n"
    echo -e "${TS}Re-Register via token${NC}\n$0 --register xxxx-xxxx-xxxx\n"
    echo -e "${TS}Install cPanel Plugin${NC}\n$0 --install-plugin\n"
    echo -e "${TS}Reinstall cPanel Plugin${NC}\n$0 --reinstall-plugin\n"
    echo -e "${TS}Fix cPanel Plugin${NC}\n$0 --fix-plugin\n"
    echo -e "${TS}Uninstall cPanel Plugin - CentOS 7.x or above with WHM Plugin installed${NC}\n   ${LRED}(side effect - completely uninstalls Acronis)${NC}\n$0 --uninstall-plugin\n"
    echo -e "${TS}Uninstall Acronis${NC} - CentOS 7.x or below without WHM Plugin installed\n$0 --uninstall-mms\n"
    rm -f $LOG_FILE
}

if [ -z $1 ]; then
    LOG=0
    set_log_file
    title
    help
    exit 0
fi

case "$1" in
--help|-h)
    LOG=0
    set_log_file
    title
    help
    exit 0
    ;;
esac

case "$1" in
--install-plugin)
    LOG=1
    set_log_file
    title
    install_acronis_backup_plugin_call
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--reinstall-plugin)
    LOG=1
    set_log_file
    title
    pluginreinstall
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--uninstall-plugin)
    LOG=1
    set_log_file
    title
    pluginuninstall
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--fix-plugin)
    LOG=1
    set_log_file
    title
    pluginfix
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--uninstall-mms)
    LOG=1
    set_log_file
    title
    mmsuninstall
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--acronis-token)
    shift
    TOKEN=$1
    LOG=1
    set_log_file
    title
    check_disk_space
    tokeninstall
#    check_swap
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--acronis-reinstall)
    LOG=1
    set_log_file
    title
    check_disk_space
    reinstall
#    check_swap
    completed
    view_log
    exit 0
    ;;
esac

case "$1" in
--register)
    shift
    TOKEN=$1
    LOG=1
    set_log_file
    title
    reregister
#    check_swap
    completed
    view_log
    exit 0
    ;;
esac
