#!/bin/bash
#
# Nagios/Icinga2 plugin to check if the system requires a reboot.
#
# Supported distributions:
#   - Debian / Ubuntu : checks /run/reboot-required (written by unattended-upgrades
#     or update-notifier after kernel/libc upgrades), then falls back to comparing
#     the running kernel with the latest installed kernel package.
#
# Exit codes:
#   0 - OK       : No reboot required (or alert acknowledged).
#   1 - WARNING  : (not used)
#   2 - CRITICAL : System needs to be rebooted.
#   3 - UNKNOWN  : Cannot determine reboot status.
#
# Usage: check_reboot_required [-v] [-r] [-f <ack_file>]
#   -v  Verbose: also print the list of packages that triggered the requirement.
#   -r  Acknowledge: create the ack file to suppress the alert until next reboot.
#       The ack file is auto-removed once no reboot is needed anymore.
#   -f  Path to the acknowledgement file
#       (default: /var/lib/nagios/reboot_required_ack).
#

# --- Nagios exit codes ---
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3

VERBOSE=0
ACK=0
ACK_FILE="/var/lib/nagios/reboot_required_ack"

while getopts "vrf:" opt; do
    case $opt in
        v) VERBOSE=1 ;;
        r) ACK=1 ;;
        f) ACK_FILE="$OPTARG" ;;
        *) echo "Usage: $0 [-v] [-r] [-f <ack_file>]"; exit $STATE_UNKNOWN ;;
    esac
done

# -----------------------------------------------------------------------
# Acknowledge mode: create the ack file to suppress the alert
# -----------------------------------------------------------------------
if [ "$ACK" -eq 1 ]; then
    touch "$ACK_FILE" && chmod 640 "$ACK_FILE"
    if [ $? -eq 0 ]; then
        echo "OK: Reboot alert acknowledged. Alert suppressed until next reboot."
        exit $STATE_OK
    else
        echo "UNKNOWN: Failed to create acknowledgement file '${ACK_FILE}' (permission denied?)"
        exit $STATE_UNKNOWN
    fi
fi

# -----------------------------------------------------------------------
# Helper: build a human-readable package list from /run/reboot-required.pkgs
# -----------------------------------------------------------------------
_debian_pkg_list() {
    local pkgs_file="/run/reboot-required.pkgs"
    if [ -f "$pkgs_file" ] && [ -s "$pkgs_file" ]; then
        sort -u "$pkgs_file" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g'
    else
        echo "(package list unavailable)"
    fi
}

# -----------------------------------------------------------------------
# Detect if a reboot is needed
# -----------------------------------------------------------------------
running_kernel=$(uname -r)
reboot_needed=0
reboot_reason=""

# Primary: /run/reboot-required (set by unattended-upgrades / update-notifier)
if [ -f /run/reboot-required ]; then
    reboot_needed=1
    if [ "$VERBOSE" -eq 1 ]; then
        pkg_list=$(_debian_pkg_list)
        reboot_reason="Reboot required. Triggering packages: ${pkg_list}"
    else
        reboot_reason="Reboot required."
    fi
fi

# Fallback: compare running kernel with latest installed kernel package.
# Tries known naming conventions in order until one matches.
if [ "$reboot_needed" -eq 0 ]; then
    if ! command -v dpkg >/dev/null 2>&1; then
        echo "UNKNOWN: 'dpkg' not found. Cannot determine reboot status."
        exit $STATE_UNKNOWN
    fi

    installed_kernel=""

    # Standard Debian / Ubuntu: linux-image-<version>
    if [ -z "$installed_kernel" ]; then
        installed_kernel=$(dpkg -l "linux-image-*" 2>/dev/null \
            | awk '/^ii/{print $2}' \
            | sed 's/^linux-image-//' \
            | grep -E '^[0-9]' \
            | sort -V \
            | tail -1)
    fi

    # Proxmox: proxmox-kernel-<version>[-signed]
    if [ -z "$installed_kernel" ]; then
        installed_kernel=$(dpkg -l "proxmox-kernel-*" 2>/dev/null \
            | awk '/^ii/{print $2}' \
            | sed 's/^proxmox-kernel-//' \
            | grep -E '^[0-9]' \
            | sed 's/-signed$//' \
            | sort -V \
            | tail -1)
    fi

    # Raspberry Pi: raspberrypi-kernel (version not embedded in the package name;
    # the primary /run/reboot-required check is the reliable method here).
    if [ -z "$installed_kernel" ]; then
        if dpkg -l raspberrypi-kernel 2>/dev/null | grep -q '^ii'; then
            echo "OK: No reboot required. Running kernel: ${running_kernel}."
            exit $STATE_OK
        fi
    fi

    if [ -z "$installed_kernel" ]; then
        echo "UNKNOWN: No versioned kernel package found via dpkg."
        exit $STATE_UNKNOWN
    fi

    if [ "$installed_kernel" != "$running_kernel" ]; then
        reboot_needed=1
        reboot_reason="Reboot required. Running kernel: ${running_kernel}, latest installed: ${installed_kernel}."
    fi
fi

# -----------------------------------------------------------------------
# Evaluate result
# -----------------------------------------------------------------------
if [ "$reboot_needed" -eq 0 ]; then
    # Auto-clear the ack file once the system no longer needs a reboot
    rm -f "$ACK_FILE" 2>/dev/null
    echo "OK: No reboot required. Running kernel: ${running_kernel}."
    exit $STATE_OK
fi

# Reboot is needed: check if it has been acknowledged
if [ -f "$ACK_FILE" ]; then
    echo "OK: ${reboot_reason} (acknowledged - waiting for reboot)"
    exit $STATE_OK
fi

echo "CRITICAL: ${reboot_reason}"
exit $STATE_CRITICAL
