#!/bin/bash
################################################################################
# Script Name: version/3.9.6/UPDATE.sh
# Description: Apply version 3.9.6. Everything 3.9.6 changes in code ships in
#              the binaries and templates the update already installs; this
#              script only repairs what earlier releases left on disk:
#
#              1. the stock cron file. Before 3.9.6 it ran
#                 `files-malware_scan --all`, an option the CLI refuses, so on
#                 servers without the malware-scan timer no weekly sweep ever
#                 ran; and it called `waf-update`, which is not a command. The
#                 install merge only adds missing lines, so the old ones stay
#                 until something rewrites them - this does, line by line,
#                 leaving every other line (an operator's edits included) alone.
#              2. a half-written Caddy repository. A Caddy install whose key
#                 download failed could leave
#                 /etc/apt/sources.list.d/caddy-stable.list behind with no
#                 keyring, and every later `apt-get update` on the server
#                 complained about it. Removed when its keyring is missing or
#                 empty; a working repository is left as it is.
#              3. failed install tasks. The App Store kept showing the bare
#                 "exit-code (exit 1)" of an install that failed before 3.9.6;
#                 those units are reset so the page starts clean and a retry
#                 runs 3.9.6's installer with its real error messages.
#
#              Nothing here fails the update without saying what to run.
# Company/Brand: HiTechCloud by Pho Tue SoftWare Solutions JSC
# Copyright (c) HiTechCloud by Pho Tue SoftWare Solutions JSC
################################################################################

set -uo pipefail
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
ok()   { echo -e "[3.9.6] ${GREEN}✓${NC} $*"; }
warn() { echo -e "[3.9.6] ${YELLOW}!${NC} $*" >&2; }
FAILURES=0
bad()  { echo -e "[3.9.6] ${RED}✗${NC} $*" >&2; FAILURES=$((FAILURES + 1)); }

VERSION="3.9.6"
# Every path and command can be pointed elsewhere, so each step can be run
# against a throwaway tree.
CRON_FILE="${HITECHCLOUD_CRON_FILE:-/etc/cron.d/hitechcloud}"
APT_LIST="${HITECHCLOUD_CADDY_LIST:-/etc/apt/sources.list.d/caddy-stable.list}"
APT_KEYRING="${HITECHCLOUD_CADDY_KEYRING:-/usr/share/keyrings/caddy-stable-archive-keyring.gpg}"
SYSTEMCTL="${HITECHCLOUD_SYSTEMCTL:-systemctl}"

if [[ -z "${HITECHCLOUD_CRON_FILE:-}" && $EUID -ne 0 ]]; then
    echo "[3.9.6] This update must run as root." >&2
    exit 1
fi

################################################################################
# 1. The stock cron file (see the header).
################################################################################
cron_step() {
    if [[ ! -f "$CRON_FILE" ]]; then
        ok "no ${CRON_FILE}; nothing to repair."
        return 0
    fi
    local tmp="${CRON_FILE%/*}/.${CRON_FILE##*/}.3.9.6.$$"
    # Only the two stock lines: the scan line loses its refused option, the
    # waf-update line becomes a comment. Comments and every other line are
    # copied as they are.
    if ! awk '
        /^[[:space:]]*#/ { print; next }
        /hitechcloudcli files-malware_scan --all/ { sub(/ files-malware_scan --all/, " files-malware_scan"); print; next }
        /hitechcloudcli waf-update/ { print "# removed by 3.9.6: waf-update is not a hitechcloudcli command"; next }
        { print }
    ' "$CRON_FILE" > "$tmp"; then
        rm -f "$tmp"
        bad "could not rewrite ${CRON_FILE}. Edit it by hand: drop '--all' after files-malware_scan and remove the waf-update line."
        return 0
    fi
    if cmp -s "$tmp" "$CRON_FILE"; then
        rm -f "$tmp"
        ok "${CRON_FILE} needs no repair."
        return 0
    fi
    chmod 0644 "$tmp" && mv -f "$tmp" "$CRON_FILE" \
        && ok "${CRON_FILE}: the weekly malware sweep runs again; the non-existent waf-update job is gone." \
        || { rm -f "$tmp"; bad "could not replace ${CRON_FILE}."; }
    return 0
}

################################################################################
# 2. A half-written Caddy repository (see the header).
################################################################################
caddy_repo_step() {
    if [[ ! -e "$APT_LIST" ]]; then
        return 0
    fi
    if [[ -s "$APT_LIST" && -s "$APT_KEYRING" ]]; then
        ok "Caddy's repository is complete; left as it is."
        return 0
    fi
    if rm -f "$APT_LIST"; then
        ok "removed ${APT_LIST}, which had no keyring and broke apt-get update."
    else
        warn "remove ${APT_LIST} by hand: it has no keyring and breaks apt-get update."
    fi
    return 0
}

################################################################################
# 3. Failed install tasks (see the header).
################################################################################
install_units_step() {
    command -v "$SYSTEMCTL" >/dev/null 2>&1 || return 0
    local units
    units=$("$SYSTEMCTL" list-units --all --state=failed --type=service --no-legend --plain 'hitechcloud-install-*' 2>/dev/null | awk '{print $1}')
    if [[ -z "$units" ]]; then
        ok "no failed install tasks to clear."
        return 0
    fi
    local u
    for u in $units; do
        "$SYSTEMCTL" reset-failed "$u" >/dev/null 2>&1 || warn "could not clear ${u}: systemctl reset-failed ${u}"
    done
    ok "cleared $(wc -w <<<"$units") failed install task(s); a retry runs 3.9.6's installer."
    return 0
}

cron_step
caddy_repo_step
install_units_step

if [[ "$FAILURES" -gt 0 ]]; then
    echo -e "[3.9.6] ${RED}$FAILURES check(s) left something undone - see above.${NC}" >&2
    exit 1
fi
ok "version ${VERSION} applied."
exit 0
