#!/bin/sh
# Apply Linux Lite's NVIDIA kernel-compatibility patch to the installed
# open-kernel NVIDIA DKMS source, so the proprietary module builds on Linux
# Lite's mainline 7.x+ kernels.
#
# Why this is needed: LL ships a mainline kernel that is newer than the kernel
# Ubuntu's packaged NVIDIA driver was written for. Mainline 7.2 removed strncpy()
# and renamed drm_atomic_state -> drm_atomic_commit (plus uvm/nvswitch changes);
# NVIDIA 610's source still uses the old APIs, so its DKMS build fails on 7.x.
# The patch (from CachyOS, path-adapted for Ubuntu's dkms tree) fixes the source.
#
# NVIDIA's own package builds the module in its postinst, BEFORE this can run, so
# this runs reactively (as a dpkg trigger on /usr/src, and on install), patches
# the source, and rebuilds the module for every installed 7.x+ kernel. It is
# idempotent and safe: it only patches sources that still need it and only when
# the patch applies cleanly, and never touches dpkg (trigger-reentrancy safe).
set -e

PATCH=/usr/share/linuxlite/nvidia-kernel-patches/0001-7.2-kernel-support.patch
LOG=/var/log/linuxlite-nvidia-kernel-patch.log
[ -f "$PATCH" ] || exit 0

# A kernel counts as "needs the patch" when its major version is >= 7 (LL's
# mainline kernels). Stock Ubuntu kernels (6.x) build NVIDIA fine and are skipped.
kver_needs_patch() {  # $1 = kernel version string
    maj=${1%%.*}
    case "$maj" in ''|*[!0-9]*) return 1;; esac
    [ "$maj" -ge 7 ] 2>/dev/null
}

# Is any 7.x+ kernel with headers installed? If not, nothing to do.
have_target=0
for kdir in /lib/modules/*/; do
    [ -e "$kdir/build" ] || continue
    kver_needs_patch "$(basename "$kdir")" && { have_target=1; break; }
done
[ "$have_target" = 1 ] || exit 0

patched_any=0
for src in /usr/src/nvidia-[0-9]*; do
    [ -d "$src" ] || continue
    [ -f "$src/nvidia/os-interface.c" ] || continue
    # Idempotent: skip if our change is already in place.
    grep -q 'copied = strnlen' "$src/nvidia-modeset/nvidia-modeset-linux.c" 2>/dev/null && continue
    # Apply only if it applies cleanly (guards a future NVIDIA source that no
    # longer needs it, or a version the patch doesn't fit).
    if patch -p1 -d "$src" --dry-run --fuzz=3 < "$PATCH" >/dev/null 2>&1; then
        patch -p1 -d "$src" --fuzz=3 < "$PATCH" >/dev/null 2>&1
        echo "$(date '+%F %T') patched $src" >> "$LOG"
        patched_any=1
    fi
done
[ "$patched_any" = 1 ] || exit 0

# Rebuild + install the NVIDIA DKMS module for every installed 7.x+ kernel, since
# NVIDIA's own postinst build ran against the UNpatched source and failed.
command -v dkms >/dev/null 2>&1 || exit 0
ver=$(ls -d /usr/src/nvidia-[0-9]*/ 2>/dev/null | sed -n 's|.*/nvidia-\([0-9][^/]*\)/$|\1|p' | head -1)
[ -n "$ver" ] || exit 0
for kdir in /lib/modules/*/; do
    [ -e "$kdir/build" ] || continue
    k=$(basename "$kdir")
    kver_needs_patch "$k" || continue
    dkms build   -m nvidia -v "$ver" -k "$k"          >>"$LOG" 2>&1 || true
    dkms install --force -m nvidia -v "$ver" -k "$k"  >>"$LOG" 2>&1 || true
done
exit 0
