#!/bin/sh
# livepatch-ctl load|unload|status — CVE-2026-99999 livepatch for the running kernel
set -eu
NAME=livepatch_cve_2026_99999
LIBDIR=/usr/lib/livepatch/cve-2026-99999
SYS=/sys/kernel/livepatch/$NAME
TIMEOUT=${TIMEOUT:-120}
KREL=$(uname -r)
# the Debian upload the RUNNING kernel was built from (dpkg may already hold a newer one)
DEBVER=$(uname -v | sed -n 's/.*Debian \([^ ]*\).*/\1/p')
KO=""
MISMATCH=""
if [ -d "$LIBDIR/$KREL" ]; then
    if [ -n "$DEBVER" ] && [ -f "$LIBDIR/$KREL/$DEBVER/livepatch-cve-2026-99999.ko" ]; then
        KO="$LIBDIR/$KREL/$DEBVER/livepatch-cve-2026-99999.ko"
    else
        MISMATCH="modules for $KREL exist (Debian linux$(for d in "$LIBDIR/$KREL"/*/; do printf ' %s' "$(basename "$d")"; done)) but none for '${DEBVER:-?}' (uname -v)"
    fi
fi

log() { echo "livepatch-ctl: $*"; }

wait_transition() {
    i=0
    while [ "$i" -lt "$TIMEOUT" ]; do
        [ "$(cat "$SYS/transition")" = 0 ] && return 0
        sleep 1; i=$((i + 1))
    done
    return 1
}

case ${1:-} in
load)
    [ -d /sys/kernel/livepatch ] || { log "kernel has no livepatch support"; exit 1; }
    if [ -n "$MISMATCH" ]; then
        log "$MISMATCH; refusing to load a module built for another upload"
        exit 1
    fi
    if [ -z "$KO" ]; then
        log "no module for kernel $KREL in $LIBDIR; nothing to do"
        exit 0
    fi
    if [ -d "$SYS" ]; then
        if [ "$(cat "$SYS/enabled")" = 0 ]; then
            log "re-enabling $NAME"; echo 1 > "$SYS/enabled"
        else
            log "$NAME already loaded on $(uname -r)"
        fi
    else
        log "loading $KO"
        insmod "$KO"
    fi
    if wait_transition; then
        log "active on $KREL (Debian linux $DEBVER), all tasks transitioned"
    else
        log "active on $KREL; transition still in progress after ${TIMEOUT}s (kernel keeps retrying; check $SYS/transition)"
        exit 2
    fi
    ;;
unload)
    if [ -d "$SYS" ]; then
        if [ "$(cat "$SYS/enabled")" = 1 ]; then
            log "disabling $NAME"; echo 0 > "$SYS/enabled"
            wait_transition || { log "transition back still in progress; retry later"; exit 2; }
        fi
        rmmod "$NAME"
        log "$NAME removed from the running kernel"
    else
        log "$NAME is not loaded"
    fi
    ;;
status)
    echo "kernel: $KREL (Debian linux ${DEBVER:-?})"
    if [ -n "$KO" ]; then echo "module: $KO"
    elif [ -n "$MISMATCH" ]; then echo "module: NONE: $MISMATCH"
    else echo "module: none for this kernel"; fi
    if [ -d "$SYS" ]; then
        echo "loaded: yes  enabled=$(cat "$SYS/enabled") transition=$(cat "$SYS/transition")"
        echo "patched objects:$(for o in "$SYS"/*/; do [ -d "$o" ] && printf ' %s' "$(basename "$o")"; done)"
    else
        echo "loaded: no"
    fi
    ;;
*)
    echo "usage: $0 load|unload|status" >&2; exit 1 ;;
esac
