#!/bin/sh
# BastionGuard RootGuard multi-init service controller.
# SPDX-License-Identifier: GPL-3.0-or-later
set -eu

SERVICE="bastionguard-rootguard"
DAEMON="${ROOTGUARD_DAEMON:-/usr/libexec/bastionguard/bastionguard-rootguard}"
POLICY="${ROOTGUARD_POLICY:-/etc/bastionguard/rootguard.conf}"
STATUS_FILE="${ROOTGUARD_STATUS_FILE:-/run/bastionguard-rootguard.status}"

usage() {
    echo "Usage: $0 {status|start|stop|restart|reload}" >&2
    exit 2
}

need_root() {
    [ "$(id -u)" -eq 0 ] || {
        echo "Administrative privileges are required for this action." >&2
        exit 77
    }
}

detect_init() {
    if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then
        echo systemd
    elif command -v rc-service >/dev/null 2>&1 && command -v openrc-run >/dev/null 2>&1; then
        echo openrc
    elif command -v dinitctl >/dev/null 2>&1 && dinitctl --quiet list >/dev/null 2>&1; then
        echo dinit
    elif [ -x "/etc/init.d/$SERVICE" ]; then
        echo sysvinit
    else
        echo none
    fi
}

read_engine_value() {
    key=$1
    if [ -r "$POLICY" ]; then
        awk -v wanted="$key" '
            /^\[engine\][[:space:]]*$/ { in_engine=1; next }
            /^\[/ { in_engine=0 }
            in_engine {
                line=$0
                sub(/^[[:space:]]*/, "", line)
                split(line, parts, "=")
                k=parts[1]
                gsub(/[[:space:]]/, "", k)
                if (k == wanted) {
                    sub(/^[^=]*=[[:space:]]*/, "", line)
                    sub(/[[:space:]#;].*$/, "", line)
                    print line
                    exit
                }
            }
        ' "$POLICY"
    fi
}

read_runtime_value() {
    key=$1
    if [ -r "$STATUS_FILE" ]; then
        awk -F= -v wanted="$key" '
            $1 == wanted {
                sub(/^[^=]*=/, "")
                print
                exit
            }
        ' "$STATUS_FILE"
    fi
}

find_pid() {
    if command -v pgrep >/dev/null 2>&1; then
        pgrep -o -f "^${DAEMON}([[:space:]]|$)" 2>/dev/null || true
    fi
}

status_output() {
    init_system=$(detect_init)
    active=false
    state=inactive

    case "$init_system" in
        systemd)
            if systemctl is-active --quiet "$SERVICE.service"; then
                active=true
                state=active
            else
                state=$(systemctl is-active "$SERVICE.service" 2>/dev/null || true)
                [ -n "$state" ] || state=inactive
            fi
            ;;
        openrc)
            if rc-service "$SERVICE" status >/dev/null 2>&1; then
                active=true
                state=active
            fi
            ;;
        dinit)
            if dinitctl --quiet is-started "$SERVICE" >/dev/null 2>&1; then
                active=true
                state=active
            else
                state=inactive
            fi
            ;;
        sysvinit)
            if "/etc/init.d/$SERVICE" status >/dev/null 2>&1; then
                active=true
                state=active
            fi
            ;;
        none)
            pid=$(find_pid)
            if [ -n "$pid" ]; then
                active=true
                state=active
            else
                state=unavailable
            fi
            ;;
    esac

    pid=$(find_pid)
    mode=
    metadata_action=
    global_metadata_action=
    auto_block_services=
    block_user_home=
    if [ "$active" = true ]; then
        mode=$(read_runtime_value mode)
        metadata_action=$(read_runtime_value metadata_action)
        global_metadata_action=$(read_runtime_value global_metadata_action)
        auto_block_services=$(read_runtime_value auto_block_services)
        block_user_home=$(read_runtime_value block_user_home)
    fi
    [ -n "$mode" ] || mode=$(read_engine_value mode)
    [ -n "$metadata_action" ] || metadata_action=$(read_engine_value metadata_action)
    [ -n "$global_metadata_action" ] || global_metadata_action=$(read_engine_value global_metadata_action)
    [ -n "$auto_block_services" ] || auto_block_services=$(read_engine_value auto_block_system_services)
    [ -n "$block_user_home" ] || block_user_home=$(read_engine_value block_user_home)
    [ -n "$mode" ] || mode=unknown
    [ -n "$metadata_action" ] || metadata_action=unknown
    [ -n "$global_metadata_action" ] || global_metadata_action=unknown
    [ -n "$auto_block_services" ] || auto_block_services=unknown
    [ -n "$block_user_home" ] || block_user_home=false

    printf 'init=%s\n' "$init_system"
    printf 'active=%s\n' "$active"
    printf 'state=%s\n' "$state"
    printf 'mode=%s\n' "$mode"
    printf 'metadata_action=%s\n' "$metadata_action"
    printf 'global_metadata_action=%s\n' "$global_metadata_action"
    printf 'auto_block_services=%s\n' "$auto_block_services"
    printf 'block_user_home=%s\n' "$block_user_home"
    printf 'pid=%s\n' "$pid"
}

control() {
    action=$1
    init_system=$(detect_init)

    case "$init_system" in
        systemd)
            case "$action" in
                reload) systemctl reload "$SERVICE.service" ;;
                *) systemctl "$action" "$SERVICE.service" ;;
            esac
            ;;
        openrc)
            rc-service "$SERVICE" "$action"
            ;;
        dinit)
            case "$action" in
                reload) dinitctl signal HUP "$SERVICE" ;;
                *) dinitctl "$action" "$SERVICE" ;;
            esac
            ;;
        sysvinit)
            "/etc/init.d/$SERVICE" "$action"
            ;;
        none)
            echo "No supported init system was detected." >&2
            exit 69
            ;;
    esac
}

[ "$#" -eq 1 ] || usage
case "$1" in
    status)
        status_output
        ;;
    start|stop|restart|reload)
        need_root
        control "$1"
        echo "RootGuard $1 completed."
        ;;
    *)
        usage
        ;;
esac
