#!/bin/sh
# BastionGuard service-manager compatibility layer.
# Supports systemd, OpenRC, SysVinit and Dinit, plus per-user services when
# no native user service manager is available.

set -u

SELF=/usr/libexec/bastionguard/bastionguard-service
CONFIG=/usr/libexec/bastionguard/bastionguard-init-config
BG_DINIT_SYSTEM_DIR=/etc/dinit.d
BG_DINIT_USER_DIR=/usr/lib/dinit.d/user
BG_DINIT_ENABLE_DIR=/etc/dinit.d/bastionguard.d
if [ -r "$CONFIG" ]; then
    # Generated by CMake and installed as root-owned package data.
    . "$CONFIG"
fi
scope=system

usage() {
    cat >&2 <<USAGE
usage: bastionguard-service [--system|--user] ACTION [OPTIONS] [UNIT]

Actions:
  backend, daemon-reload, exists, is-active, is-enabled, status
  start, stop, restart, reload, try-restart, try-reload-or-restart
  enable [--now], disable [--now], logs [LINES]
  start-enabled   (user scope only)
USAGE
    exit 64
}

case "${1-}" in
    --system) scope=system; shift ;;
    --user)   scope=user; shift ;;
esac

[ "$#" -gt 0 ] || usage
action=$1
shift

valid_unit() {
    case "$1" in
        ""|*[!A-Za-z0-9_.@:-]*) return 1 ;;
        *) return 0 ;;
    esac
}

strip_unit_suffix() {
    value=$1
    case "$value" in
        *.timer)   value=${value%.timer}-timer ;;
        *.service) value=${value%.service} ;;
    esac
    printf '%s\n' "$value"
}

detect_backend() {
    if [ -d /run/openrc ] && command -v rc-service >/dev/null 2>&1; then
        printf '%s\n' openrc
        return
    fi
    if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then
        printf '%s\n' systemd
        return
    fi
    if { [ -S /dev/dinitctl ] || [ -S /run/dinitctl ]; } && command -v dinitctl >/dev/null 2>&1; then
        printf '%s\n' dinit
        return
    fi

    init_real=$(readlink -f /sbin/init 2>/dev/null || readlink -f /usr/sbin/init 2>/dev/null || true)
    case "$init_real" in
        *openrc*) printf '%s\n' openrc; return ;;
        *systemd*) printf '%s\n' systemd; return ;;
        */dinit|*/dinit-*) printf '%s\n' dinit; return ;;
        *sysvinit*) printf '%s\n' sysvinit; return ;;
    esac

    if command -v rc-service >/dev/null 2>&1 && command -v openrc-run >/dev/null 2>&1; then
        printf '%s\n' openrc
    elif command -v dinitctl >/dev/null 2>&1 && ! command -v systemctl >/dev/null 2>&1; then
        printf '%s\n' dinit
    elif command -v systemctl >/dev/null 2>&1; then
        printf '%s\n' systemd
    elif [ -d /etc/init.d ]; then
        printf '%s\n' sysvinit
    else
        printf '%s\n' unknown
    fi
}

backend=$(detect_backend)

systemd_user_available() {
    [ "$backend" = systemd ] || return 1
    command -v systemctl >/dev/null 2>&1 || return 1
    user_dirs >/dev/null 2>&1 || true
    systemctl --user show-environment >/dev/null 2>&1
}

dinit_user_available() {
    [ "$backend" = dinit ] || return 1
    command -v dinitctl >/dev/null 2>&1 || return 1
    user_dirs >/dev/null 2>&1 || true
    dinitctl --user list >/dev/null 2>&1
}

service_candidates() {
    original=$1
    base=$(strip_unit_suffix "$original")
    printf '%s\n' "$base"

    case "$base" in
        clamd@scan|clamd.scan)
            printf '%s\n' clamd
            printf '%s\n' clamav-daemon
            ;;
        clamd)
            printf '%s\n' clamav-daemon
            ;;
        clamav-daemon)
            printf '%s\n' clamd
            ;;
        clamav-freshclam)
            printf '%s\n' freshclam
            ;;
        clamav-clamonacc)
            printf '%s\n' clamonacc
            ;;
    esac
}

dinit_system_service_dirs() {
    printf '%s\n' \
        "$BG_DINIT_SYSTEM_DIR" \
        /etc/dinit.d \
        /run/dinit.d \
        /usr/local/lib/dinit.d \
        /usr/lib/dinit.d \
        /lib/dinit.d
}

dinit_user_service_dirs() {
    config_home=${XDG_CONFIG_HOME:-${HOME:-/tmp}/.config}
    printf '%s\n' \
        "$config_home/dinit.d" \
        "${HOME:-/tmp}/.config/dinit.d" \
        "$BG_DINIT_USER_DIR" \
        /etc/dinit.d/user \
        /usr/lib/dinit.d/user \
        /usr/local/lib/dinit.d/user
}

dinit_service_file_exists() {
    service_name=$1
    for service_dir in $(dinit_system_service_dirs); do
        [ -f "$service_dir/$service_name" ] && return 0
    done
    return 1
}

dinit_user_service_file_exists() {
    service_name=$1
    for service_dir in $(dinit_user_service_dirs); do
        [ -f "$service_dir/$service_name" ] && return 0
    done
    return 1
}

dinit_system_enable_dir() {
    printf '%s\n' "$BG_DINIT_ENABLE_DIR"
}

dinit_system_managed_services() {
    printf '%s\n' \
        bastionguard \
        BastionGuard-phishing-scanner \
        BastionGuard-phishing-updater \
        BastionGuard-phishing-updater-timer \
        BastionGuard-ransomware-realtime \
        bastionguard-sanesecurity \
        bastionguard-sanesecurity-timer \
        BastionGuard-usbd \
        clamav-clamonacc \
        bsc-daemon
}

dinit_user_managed_services() {
    printf '%s\n' \
        BastionGuard-useragent \
        BastionGuard-privacyd \
        BastionGuard-ransomware-alert \
        BastionGuard-ransomware-realtime-alert \
        BastionGuard-ransomware-scanner \
        BastionGuard-pacd \
        BastionGuard-mailproxy \
        BastionGuard-user-session-watch \
        BastionGuard-cef
}

find_native_service() {
    unit=$1
    for candidate in $(service_candidates "$unit"); do
        case "$backend" in
            openrc|sysvinit)
                if [ -x "/etc/init.d/$candidate" ]; then
                    printf '%s\n' "$candidate"
                    return 0
                fi
                ;;
            dinit)
                if dinit_service_file_exists "$candidate" ||
                   dinitctl status "$candidate" >/dev/null 2>&1; then
                    printf '%s\n' "$candidate"
                    return 0
                fi
                ;;
            systemd)
                printf '%s\n' "$unit"
                return 0
                ;;
        esac
    done
    return 1
}

system_exists() {
    unit=$1
    case "$backend" in
        systemd)
            systemctl cat "$unit" >/dev/null 2>&1
            ;;
        openrc|sysvinit|dinit)
            find_native_service "$unit" >/dev/null 2>&1
            ;;
        *) return 1 ;;
    esac
}

system_active() {
    unit=$1
    case "$backend" in
        systemd)
            systemctl is-active --quiet "$unit"
            ;;
        openrc)
            native=$(find_native_service "$unit") || return 3
            rc-service "$native" status >/dev/null 2>&1
            ;;
        dinit)
            native=$(find_native_service "$unit") || return 3
            dinitctl is-started "$native" >/dev/null 2>&1
            ;;
        sysvinit)
            native=$(find_native_service "$unit") || return 3
            if command -v service >/dev/null 2>&1; then
                service "$native" status >/dev/null 2>&1
            else
                "/etc/init.d/$native" status >/dev/null 2>&1
            fi
            ;;
        *) return 3 ;;
    esac
}

system_enabled() {
    unit=$1
    case "$backend" in
        systemd)
            systemctl is-enabled --quiet "$unit"
            ;;
        openrc)
            native=$(find_native_service "$unit") || return 1
            rc-update show 2>/dev/null | awk -v svc="$native" '
                $1 == svc { found=1 }
                END { exit(found ? 0 : 1) }
            '
            ;;
        dinit)
            native=$(find_native_service "$unit") || return 1
            enable_dir=$(dinit_system_enable_dir)
            if [ -e "$enable_dir/$native" ] || [ -L "$enable_dir/$native" ]; then
                return 0
            fi
            for service_dir in $(dinit_system_service_dirs); do
                find "$service_dir" -mindepth 2 -maxdepth 2 -type l \
                    -name "$native" -print -quit 2>/dev/null | grep -q . &&
                    return 0
            done
            return 1
            ;;
        sysvinit)
            native=$(find_native_service "$unit") || return 1
            if command -v chkconfig >/dev/null 2>&1; then
                chkconfig --list "$native" 2>/dev/null | grep -Eq '(^|[[:space:]])[2-5]:on([[:space:]]|$)'
            else
                find /etc/rc?.d -maxdepth 1 -type l -name "S??$native" -print -quit 2>/dev/null | grep -q .
            fi
            ;;
        *) return 1 ;;
    esac
}

system_call() {
    op=$1
    unit=$2

    case "$backend" in
        systemd)
            systemctl "$op" "$unit"
            ;;
        openrc)
            native=$(find_native_service "$unit") || return 5
            rc-service "$native" "$op"
            ;;
        dinit)
            native=$(find_native_service "$unit") || return 5
            case "$op" in
                reload)
                    case "$native" in
                        bsc-daemon) return 3 ;;
                        BastionGuard-phishing-updater|bastionguard-sanesecurity)
                            return 3
                            ;;
                    esac
                    dinitctl signal HUP "$native"
                    ;;
                *) dinitctl "$op" "$native" ;;
            esac
            ;;
        sysvinit)
            native=$(find_native_service "$unit") || return 5
            if command -v service >/dev/null 2>&1; then
                service "$native" "$op"
            else
                "/etc/init.d/$native" "$op"
            fi
            ;;
        *) return 5 ;;
    esac
}

system_enable() {
    unit=$1
    native=$(find_native_service "$unit" 2>/dev/null || true)
    case "$backend" in
        systemd) systemctl enable "$unit" ;;
        openrc)
            [ -n "$native" ] || return 5
            rc-update add "$native" default
            ;;
        dinit)
            [ -n "$native" ] || return 5
            mkdir -p "$(dinit_system_enable_dir)" || return 73
            if dinit_service_file_exists bastionguard; then
                if ! dinitctl enable bastionguard >/dev/null 2>&1; then
                    system_enabled bastionguard || return 5
                fi
            fi
            dinitctl enable "$native"
            ;;
        sysvinit)
            [ -n "$native" ] || return 5
            if command -v update-rc.d >/dev/null 2>&1; then
                update-rc.d "$native" defaults >/dev/null
                update-rc.d "$native" enable >/dev/null 2>&1 || true
            elif command -v chkconfig >/dev/null 2>&1; then
                chkconfig --add "$native" >/dev/null 2>&1 || true
                chkconfig "$native" on
            else
                return 5
            fi
            ;;
        *) return 5 ;;
    esac
}

system_disable() {
    unit=$1
    native=$(find_native_service "$unit" 2>/dev/null || true)
    case "$backend" in
        systemd) systemctl disable "$unit" ;;
        openrc)
            [ -n "$native" ] || return 5
            rc-update del "$native" default
            ;;
        dinit)
            [ -n "$native" ] || return 5
            dinitctl disable "$native"
            ;;
        sysvinit)
            [ -n "$native" ] || return 5
            if command -v update-rc.d >/dev/null 2>&1; then
                update-rc.d "$native" disable >/dev/null 2>&1 || \
                update-rc.d -f "$native" remove >/dev/null
            elif command -v chkconfig >/dev/null 2>&1; then
                chkconfig "$native" off
            else
                return 5
            fi
            ;;
        *) return 5 ;;
    esac
}

system_logs() {
    unit=$1
    lines=${2:-100}
    case "$lines" in *[!0-9]*|"") lines=100 ;; esac

    if [ "$backend" = systemd ] && command -v journalctl >/dev/null 2>&1; then
        exec journalctl -u "$unit" -n "$lines" --no-pager
    fi
    if [ "$backend" = dinit ] && command -v dinitctl >/dev/null 2>&1; then
        native=$(find_native_service "$unit") || return 1
        dinitctl catlog "$native" 2>/dev/null | tail -n "$lines"
        return 0
    fi

    base=$(strip_unit_suffix "$unit")
    for logfile in \
        "/var/log/BastionGuard/$base.log" \
        "/var/log/bastionguard-secure-connectiond.log" \
        "/var/log/clamav/clamonacc.log" \
        "/var/log/clamav/clamav.log" \
        "/var/log/clamav/clamd.log" \
        "/var/log/clamav/freshclam.log" \
        /var/log/messages /var/log/syslog; do
        if [ -r "$logfile" ]; then
            tail -n "$lines" "$logfile"
            return $?
        fi
    done
    return 1
}

user_dirs() {
    uid=$(id -u)
    runtime=${XDG_RUNTIME_DIR:-/run/user/$uid}
    if [ ! -d "$runtime" ] || [ ! -w "$runtime" ]; then
        runtime=${TMPDIR:-/tmp}/bastionguard-runtime-$uid
        mkdir -p "$runtime" 2>/dev/null || return 73
        chmod 0700 "$runtime" 2>/dev/null || true
    fi

    XDG_RUNTIME_DIR=$runtime
    export XDG_RUNTIME_DIR
    if [ -S "$runtime/bus" ] && [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
        DBUS_SESSION_BUS_ADDRESS=unix:path=$runtime/bus
        export DBUS_SESSION_BUS_ADDRESS
    fi

    config_home=${XDG_CONFIG_HOME:-${HOME:-/tmp}/.config}
    state_home=${XDG_STATE_HOME:-${HOME:-/tmp}/.local/state}
    user_enable_dir=$config_home/BastionGuard/services
    user_state_dir=$state_home/BastionGuard/services
    user_runtime_dir=$runtime/BastionGuard/services
    mkdir -p "$user_enable_dir" "$user_state_dir" "$user_runtime_dir" 2>/dev/null || return 73
}

user_name() {
    strip_unit_suffix "$1"
}

user_command() {
    name=$(user_name "$1")
    USER_WORKDIR=${HOME:-/}
    USER_RESTART=always
    USER_RESTART_DELAY=3

    case "$name" in
        BastionGuard-useragent)
            set -- /usr/bin/BastionGuard-ransomware-alert
            ;;
        BastionGuard-ransomware-alert)
            USER_RESTART=on-failure
            set -- /usr/bin/BastionGuard-ransomware-alert
            ;;
        BastionGuard-privacyd)
            set -- /usr/bin/BastionGuard-privacyd
            ;;
        BastionGuard-ransomware-realtime-alert)
            set -- /usr/bin/BastionGuard-ransomware-realtime-alert
            ;;
        BastionGuard-ransomware-scanner)
            USER_WORKDIR=${HOME:-/tmp}/.local/share/BastionGuard
            set -- /usr/bin/BastionGuard-ransomware-scanner \
                --0day-protection \
                /usr/share/BastionGuard/data/0day_ransomware_protection/ZeroDay.yara
            ;;
        BastionGuard-pacd|bastionguard-pacd)
            set -- /usr/bin/bastionguard-pacd \
                --listen 127.0.0.1 --port 8765 \
                --stub-host 127.0.0.1 --stub-port 3129 \
                --backend-host 127.0.0.1 --backend-port 3130 \
                --trigger-cmd "$SELF --user start BastionGuard-cef.service" \
                --backend-wait-ms 4000
            ;;
        BastionGuard-mailproxy)
            set -- /usr/bin/BastionGuard-mailproxy
            ;;
        BastionGuard-user-session-watch)
            set -- /usr/share/BastionGuard/data/scripts/BastionGuard-user-session-watch.sh
            ;;
        BastionGuard-cef)
            set -- /usr/bin/bastionguard-cef --listen 127.0.0.1 --port 3130
            ;;
        *) return 5 ;;
    esac

    [ -x "$1" ] || return 5
    USER_DAEMON=$1
    shift
    # Store the positional parameters as quoted shell text used only inside this
    # process. Values above are constants, not user-provided strings.
    USER_ARGS=""
    for arg in "$@"; do
        escaped=$(printf '%s' "$arg" | sed "s/'/'\\\\''/g")
        USER_ARGS="$USER_ARGS '$escaped'"
    done
    return 0
}

user_pidfile() {
    user_dirs || return $?
    name=$(user_name "$1")
    printf '%s/%s.pid\n' "$user_runtime_dir" "$name"
}

user_logfile() {
    user_dirs || return $?
    name=$(user_name "$1")
    printf '%s/%s.log\n' "$user_state_dir" "$name"
}

user_fallback_active() {
    pidfile=$(user_pidfile "$1")
    [ -r "$pidfile" ] || return 3
    pid=$(cat "$pidfile" 2>/dev/null || true)
    case "$pid" in *[!0-9]*|"") return 3 ;; esac
    kill -0 "$pid" 2>/dev/null
}

user_fallback_start() {
    unit=$1
    user_fallback_active "$unit" && return 0
    user_command "$unit" || return $?

    pidfile=$(user_pidfile "$unit") || return $?
    logfile=$(user_logfile "$unit") || return $?
    rm -f "$pidfile"

    # USER_ARGS is assembled exclusively from the constant command table.
    eval "set -- '$USER_DAEMON' $USER_ARGS"
    mkdir -p "$USER_WORKDIR" 2>/dev/null || return 73
    nohup /usr/libexec/bastionguard/bastionguard-supervise \
        --restart "$USER_RESTART" \
        --delay "$USER_RESTART_DELAY" \
        --chdir "$USER_WORKDIR" -- "$@" >>"$logfile" 2>&1 &
    pid=$!
    printf '%s\n' "$pid" > "$pidfile"
    sleep 1
    if kill -0 "$pid" 2>/dev/null; then
        return 0
    fi
    rm -f "$pidfile"
    return 1
}

user_fallback_stop() {
    unit=$1
    pidfile=$(user_pidfile "$unit") || return $?
    [ -r "$pidfile" ] || return 0
    pid=$(cat "$pidfile" 2>/dev/null || true)
    case "$pid" in *[!0-9]*|"") rm -f "$pidfile"; return 0 ;; esac

    kill "$pid" 2>/dev/null || true
    count=0
    while kill -0 "$pid" 2>/dev/null && [ "$count" -lt 50 ]; do
        sleep 0.1
        count=$((count + 1))
    done
    if kill -0 "$pid" 2>/dev/null; then
        kill -KILL "$pid" 2>/dev/null || true
    fi
    rm -f "$pidfile"
    return 0
}

user_fallback_enabled() {
    user_dirs || return $?
    name=$(user_name "$1")
    [ -f "$user_enable_dir/$name.enabled" ]
}

user_fallback_enable() {
    user_dirs || return $?
    name=$(user_name "$1")
    user_command "$1" || return $?
    : > "$user_enable_dir/$name.enabled"
}

user_fallback_disable() {
    user_dirs || return $?
    name=$(user_name "$1")
    rm -f "$user_enable_dir/$name.enabled"
}

user_fallback_start_enabled() {
    user_dirs || return $?
    found=0
    for marker in "$user_enable_dir"/*.enabled; do
        [ -e "$marker" ] || continue
        found=1
        name=$(basename "$marker" .enabled)
        user_fallback_start "$name.service" || true
    done
    [ "$found" -eq 1 ] || return 0
}

user_fallback_logs() {
    logfile=$(user_logfile "$1") || return $?
    lines=${2:-100}
    case "$lines" in *[!0-9]*|"") lines=100 ;; esac
    [ -r "$logfile" ] || return 1
    tail -n "$lines" "$logfile"
}

user_dinit_enabled() {
    user_dirs || return $?
    name=$(user_name "$1")
    [ -f "$user_enable_dir/$name.dinit-enabled" ]
}

user_dinit_enable() {
    user_dirs || return $?
    name=$(user_name "$1")
    dinit_user_service_file_exists "$name" || return 5
    # Use Dinit's native boot dependency when the user manager provides one.
    # The marker remains as a portable fallback started by XDG Autostart.
    dinitctl --user enable "$name" >/dev/null 2>&1 || true
    : > "$user_enable_dir/$name.dinit-enabled"
}

user_dinit_disable() {
    user_dirs || return $?
    name=$(user_name "$1")
    dinitctl --user disable "$name" >/dev/null 2>&1 || true
    rm -f "$user_enable_dir/$name.dinit-enabled"
}

user_dinit_start_enabled() {
    user_dirs || return $?
    for marker in "$user_enable_dir"/*.dinit-enabled; do
        [ -e "$marker" ] || continue
        name=$(basename "$marker" .dinit-enabled)
        dinitctl --user start "$name" >/dev/null 2>&1 || true
    done
}

user_systemd() {
    exec systemctl --user "$@"
}

if [ "$action" = backend ]; then
    if [ "$scope" = user ]; then
        if systemd_user_available; then
            printf '%s\n' systemd
        elif dinit_user_available; then
            printf '%s\n' dinit
        else
            printf '%s\n' user-supervisor
        fi
    else
        printf '%s\n' "$backend"
    fi
    exit 0
fi

if [ "$scope" = user ]; then
    if systemd_user_available; then
        case "$action" in
            start-enabled)
                # Enabled systemd user units are started by the user manager.
                exit 0
                ;;
            logs)
                [ "$#" -ge 1 ] || usage
                unit=$1; lines=${2:-100}
                valid_unit "$unit" || exit 64
                exec journalctl --user -u "$unit" -n "$lines" --no-pager
                ;;
            exists)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                systemctl --user cat "$1" >/dev/null 2>&1
                exit $?
                ;;
            daemon-reload)
                user_systemd daemon-reload
                ;;
            enable|disable)
                now=0
                if [ "${1-}" = --now ]; then now=1; shift; fi
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                if [ "$now" -eq 1 ]; then
                    user_systemd "$action" --now "$1"
                else
                    user_systemd "$action" "$1"
                fi
                ;;
            is-active)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                if systemctl --user is-active --quiet "$1"; then
                    printf '%s\n' active
                    exit 0
                else
                    rc=$?
                    printf '%s\n' inactive
                    exit "$rc"
                fi
                ;;
            is-enabled)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                if systemctl --user is-enabled --quiet "$1"; then
                    printf '%s\n' enabled
                    exit 0
                else
                    rc=$?
                    printf '%s\n' disabled
                    exit "$rc"
                fi
                ;;
            try-restart)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                systemctl --user try-restart "$1"
                exit $?
                ;;
            try-reload-or-restart)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                systemctl --user try-reload-or-restart "$1"
                exit $?
                ;;
            start|stop|restart|reload|status)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                user_systemd "$action" "$1"
                ;;
            *) usage ;;
        esac
    fi

    if dinit_user_available; then
        case "$action" in
            start-enabled)
                [ "$#" -eq 0 ] || usage
                user_dinit_start_enabled
                ;;
            logs)
                [ "$#" -ge 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                lines=${2:-100}
                case "$lines" in *[!0-9]*|"") lines=100 ;; esac
                dinitctl --user catlog "$name" 2>/dev/null | tail -n "$lines"
                ;;
            exists)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                dinit_user_service_file_exists "$name"
                ;;
            daemon-reload)
                for name in $(dinit_user_managed_services); do
                    dinit_user_service_file_exists "$name" || continue
                    dinitctl --user reload "$name" >/dev/null 2>&1 || true
                done
                exit 0
                ;;
            enable|disable)
                now=0
                if [ "${1-}" = --now ]; then now=1; shift; fi
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                if [ "$action" = enable ]; then
                    user_dinit_enable "$1" || exit $?
                    [ "$now" -eq 0 ] || dinitctl --user start "$name"
                else
                    [ "$now" -eq 0 ] || dinitctl --user stop --ignore-unstarted "$name" || true
                    user_dinit_disable "$1"
                fi
                ;;
            is-active|status)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                if dinitctl --user is-started "$name" >/dev/null 2>&1; then
                    printf '%s\n' active
                    exit 0
                else
                    rc=$?
                    printf '%s\n' inactive
                    exit "$rc"
                fi
                ;;
            is-enabled)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                if user_dinit_enabled "$1"; then
                    printf '%s\n' enabled
                    exit 0
                else
                    rc=$?
                    printf '%s\n' disabled
                    exit "$rc"
                fi
                ;;
            start|stop|restart)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                dinitctl --user "$action" "$name"
                ;;
            reload)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                dinitctl --user signal HUP "$name"
                ;;
            try-restart)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                if dinitctl --user is-started "$name" >/dev/null 2>&1; then
                    dinitctl --user restart "$name"
                fi
                ;;
            try-reload-or-restart)
                [ "$#" -eq 1 ] || usage
                valid_unit "$1" || exit 64
                name=$(user_name "$1")
                if dinitctl --user is-started "$name" >/dev/null 2>&1; then
                    dinitctl --user signal HUP "$name" 2>/dev/null ||
                        dinitctl --user restart "$name"
                fi
                ;;
            *) usage ;;
        esac
        exit $?
    fi

    case "$action" in
        start-enabled)
            [ "$#" -eq 0 ] || usage
            user_fallback_start_enabled
            ;;
        daemon-reload)
            exit 0
            ;;
        exists)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            user_command "$1" >/dev/null 2>&1
            ;;
        is-active|status)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            if user_fallback_active "$1"; then
                printf '%s\n' active
                exit 0
            else
                rc=$?
                printf '%s\n' inactive
                exit "$rc"
            fi
            ;;
        is-enabled)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            if user_fallback_enabled "$1"; then
                printf '%s\n' enabled
                exit 0
            else
                rc=$?
                printf '%s\n' disabled
                exit "$rc"
            fi
            ;;
        start)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            user_fallback_start "$1"
            ;;
        stop)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            user_fallback_stop "$1"
            ;;
        restart)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            user_fallback_stop "$1"
            user_fallback_start "$1"
            ;;
        reload)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            pidfile=$(user_pidfile "$1") || exit $?
            pid=$(cat "$pidfile" 2>/dev/null || true)
            case "$pid" in *[!0-9]*|"") exit 3 ;; esac
            kill -HUP "$pid"
            ;;
        try-restart)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            if user_fallback_active "$1"; then
                user_fallback_stop "$1"
                user_fallback_start "$1"
            fi
            ;;
        try-reload-or-restart)
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            if user_fallback_active "$1"; then
                pidfile=$(user_pidfile "$1") || exit $?
                pid=$(cat "$pidfile")
                kill -HUP "$pid" 2>/dev/null || {
                    user_fallback_stop "$1"
                    user_fallback_start "$1"
                }
            fi
            ;;
        enable|disable)
            now=0
            if [ "${1-}" = --now ]; then now=1; shift; fi
            [ "$#" -eq 1 ] || usage
            valid_unit "$1" || exit 64
            if [ "$action" = enable ]; then
                user_fallback_enable "$1" || exit $?
                [ "$now" -eq 0 ] || user_fallback_start "$1"
            else
                [ "$now" -eq 0 ] || user_fallback_stop "$1"
                user_fallback_disable "$1"
            fi
            ;;
        logs)
            [ "$#" -ge 1 ] || usage
            valid_unit "$1" || exit 64
            user_fallback_logs "$1" "${2:-100}"
            ;;
        *) usage ;;
    esac
    exit $?
fi

# System scope.
case "$action" in
    daemon-reload)
        if [ "$backend" = systemd ]; then
            exec systemctl daemon-reload
        fi
        if [ "$backend" = dinit ]; then
            for name in $(dinit_system_managed_services); do
                dinit_service_file_exists "$name" || continue
                dinitctl reload "$name" >/dev/null 2>&1 || true
            done
        fi
        exit 0
        ;;
    exists)
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        system_exists "$1"
        ;;
    is-active|status)
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        if system_active "$1"; then
            printf '%s\n' active
            exit 0
        else
            rc=$?
            printf '%s\n' inactive
            exit "$rc"
        fi
        ;;
    is-enabled)
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        if system_enabled "$1"; then
            printf '%s\n' enabled
            exit 0
        else
            rc=$?
            printf '%s\n' disabled
            exit "$rc"
        fi
        ;;
    start|stop|restart|reload)
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        system_call "$action" "$1"
        ;;
    try-restart)
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        if system_active "$1"; then system_call restart "$1"; fi
        ;;
    try-reload-or-restart)
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        if system_active "$1"; then
            system_call reload "$1" 2>/dev/null || system_call restart "$1"
        fi
        ;;
    enable|disable)
        now=0
        if [ "${1-}" = --now ]; then now=1; shift; fi
        [ "$#" -eq 1 ] || usage
        valid_unit "$1" || exit 64
        if [ "$action" = enable ]; then
            system_enable "$1" || exit $?
            [ "$now" -eq 0 ] || system_call start "$1"
        else
            [ "$now" -eq 0 ] || system_call stop "$1" || true
            system_disable "$1"
        fi
        ;;
    logs)
        [ "$#" -ge 1 ] || usage
        valid_unit "$1" || exit 64
        system_logs "$1" "${2:-100}"
        ;;
    *) usage ;;
esac
