#!/bin/sh
set -eu

TOOLSUFFIX="${TOOLSUFFIX:-}"

setup_config() {
    rm -f /etc/ferm/ferm.conf
    if [ -n "${TOOLSUFFIX:-}" ]; then
        cat > /etc/ferm/ferm.conf <<EOF
@def \$path_iptables= "/usr/sbin/iptables$TOOLSUFFIX";
@def \$path_iptables_save="/usr/sbin/iptables$TOOLSUFFIX-save";
@def \$path_iptables_restore="/usr/sbin/iptables$TOOLSUFFIX-restore";
@def \$path_ip6tables= "/usr/sbin/ip6tables$TOOLSUFFIX";
@def \$path_ip6tables_save="/usr/sbin/ip6tables$TOOLSUFFIX-save";
@def \$path_ip6tables_restore="/usr/sbin/ip6tables$TOOLSUFFIX-restore";
EOF
    fi
    cat >> /etc/ferm/ferm.conf <<'EOF'
domain (ip ip6) {
    table filter {
        chain INPUT {
            policy ACCEPT;
            mod state state INVALID DROP;
        }
    }
}
EOF
}

flush() {
    ferm --flush /etc/ferm/ferm.conf 2>/dev/null || true
    iptables-legacy --flush 2>/dev/null || true
    ip6tables-legacy --flush 2>/dev/null || true
    iptables-nft --flush 2>/dev/null || true
    ip6tables-nft --flush 2>/dev/null || true
    nft flush ruleset 2>/dev/null || true
    modprobe -r iptable_filter 2>/dev/null || true
}

check_present() {
    if iptables${TOOLSUFFIX:-}-save 2>/dev/null | grep -q "state INVALID"; then
        if ip6tables${TOOLSUFFIX:-}-save 2>/dev/null | grep -q "state INVALID"; then
            return 0
        fi
    fi

    if nft list ruleset 2>/dev/null | grep -qi "invalid"; then
        return 0
    fi

    echo >&2 "ERROR (check_present): firewall rule not present"
    systemctl status ferm.service --no-pager || true
    iptables${TOOLSUFFIX:-}-save
    ip6tables${TOOLSUFFIX:-}-save
    nft list ruleset 2>/dev/null
    exit 1
}

show() {
    echo "---- show ${1:-} ----"
    echo "iptables-nft -nvL"
    iptables-nft -nvL 2>/dev/null || true
    ip6tables-nft -nvL 2>/dev/null || true
    echo "iptables-legacy -nvL"
    iptables-legacy -nvL 2>/dev/null || true
    ip6tables-legacy -nvL 2>/dev/null || true
    echo "nft list ruleset"
    nft list ruleset 2>/dev/null || true
    echo "---- end show ${1:-} ----"
}


check_absent() {
    if iptables${TOOLSUFFIX:-}-save 2>/dev/null | grep -q "state INVALID"; then
        echo >&2 "ERROR (check_absent): firewall rule still present (iptables${TOOLSUFFIX:-})"
        iptables${TOOLSUFFIX:-}-save
        systemctl status ferm.service --no-pager || true
        exit 1
    fi

    if ip6tables${TOOLSUFFIX:-}-save 2>/dev/null | grep -q "state INVALID"; then
        echo >&2 "ERROR (check_absent): firewall rule still present (ip6tables${TOOLSUFFIX:-})"
        ip6tables${TOOLSUFFIX:-}-save
        systemctl status ferm.service --no-pager || true
            exit 1
    fi

    if nft list ruleset 2>/dev/null | grep -qi "invalid"; then
        echo >&2 "ERROR (check_absent): firewall rule still present (nft)"
        nft list ruleset 2>/dev/null
        systemctl status ferm.service --no-pager || true
        exit 1
    fi
}

# --- shared post-reboot / teardown helpers ---

# wait_for_service_active SERVICE_NAME
# Polls `systemctl is-active` for up to 10s (50 * 0.2s). On timeout, dumps
# status + boot journal for the unit and returns 1.
wait_for_service_active() {
    unit="$1"
    i=0
    echo "while ! systemctl is-active --quiet ${unit}"
    while ! systemctl is-active --quiet "${unit}"; do
        sleep 0.2
        i=$((i+1))
        if [ "$i" -gt 50 ]; then
            echo >&2 "ERROR: ${unit} did not start after boot"
            systemctl status "${unit}" --no-pager || true
            journalctl --boot --unit="${unit}"
            return 1
        fi
    done
}

# wait_after_reboot
# Waits for systemd to settle, then for ferm-early.service and ferm.service
# to be active. Relies on `set -e` in the caller to abort on timeout.
wait_after_reboot() {
    echo "=== POST-REBOOT PHASE, WAIT FOR INIT TO FINISH ==="
    systemctl is-system-running --wait --quiet || true
    wait_for_service_active ferm-early.service
    wait_for_service_active ferm.service
}

# maybe_reboot_or_flush REBOOT_MARK
# If not already past a reboot and MODE=reboot, triggers autopkgtest-reboot
# with REBOOT_MARK and exits 0. Otherwise flushes and exits 0. Only fits
# tests whose sole non-reboot tail action is "flush; exit 0" -- tests with
# extra teardown (e.g. disabling a service override) should not use this.
maybe_reboot_or_flush() {
    reboot_mark="$1"
    if [ -z "${AUTOPKGTEST_REBOOT_MARK:-}" ] && [ "${MODE:-basic}" = "reboot" ]; then
        echo "=== autopkgtest-reboot ${reboot_mark} ==="
        autopkgtest-reboot "${reboot_mark}"
        exit 0
    fi
    flush
    exit 0
}
