diff --git a/AGENTS.md b/AGENTS.md index d4f5454..3ac81e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,6 +14,10 @@ This repository manages the infrastructure, configuration, and maintenance for M |------|---------| | Apply Configuration | `ansible-playbook ansible/workstation.yml` | | System Maintenance | `bash scripts/maintenance.sh` | +| Package Cleanup (dry-run) | `bash scripts/cleanup.sh --check` | +| Package Cleanup (apply) | `bash scripts/cleanup.sh --apply` | +| NVIDIA Recovery (broken GUI) | `bash scripts/nvidia-recovery.sh --apply` | +| **Post-recovery** | **Reboot required to restore GUI login** | | Verify Ansible | `ansible-playbook ansible/workstation.yml --check` | ## Standards diff --git a/config/bashrc.j2 b/config/bashrc.j2 index 3d56e35..59f750e 100644 --- a/config/bashrc.j2 +++ b/config/bashrc.j2 @@ -14,7 +14,7 @@ alias k='kubectl' alias main='bash {{ workspace_root }}/scripts/maintenance.sh' # Environment -export EDITOR='vim' +export EDITOR='nvim' export PATH="$HOME/.local/bin:$PATH" # saTway indicators diff --git a/scripts/cleanup.sh b/scripts/cleanup.sh new file mode 100755 index 0000000..2ff709f --- /dev/null +++ b/scripts/cleanup.sh @@ -0,0 +1,372 @@ +#!/bin/bash +set -euo pipefail + +# Workstation Package Cleanup Script +# Version: 1.0.0 +# Target: mw-pfeddersheim-workstation +# Purpose: Remove identified cleanup candidates and log for verification + +MODE="apply" +if [[ "${1:-}" == "--check" ]]; then + MODE="check" + echo "=== Running in CHECK mode (dry-run, no packages removed) ===" +elif [[ "${1:-}" == "--help" ]]; then + echo "Usage: $0 [--check | --apply | --help]" + echo " --check Dry-run: show what would be removed (default)" + echo " --apply Actually remove packages" + echo " --help Show this help" + exit 0 +fi + +# Ensure log directory exists +mkdir -p "$HOME/logs" 2>/dev/null || true +LOCAL_LOG="$HOME/logs/cleanup-$(date +%Y%m%d-%H%M%S).log" +BOLD=$(tput bold 2>/dev/null || true) +RED=$(tput setaf 1 2>/dev/null || true) +GREEN=$(tput setaf 2 2>/dev/null || true) +RESET=$(tput sgr0 2>/dev/null || true) + +log() { echo -e "$*" | tee -a "$LOCAL_LOG"; } +section() { log ""; log "${BOLD}--- $1 ---${RESET}"; } + +echo "" | tee -a "$LOCAL_LOG" +log "=============================================" +log " Workstation Package Cleanup" +log " Mode: $MODE | Date: $(date)" +log " Log: $LOCAL_LOG" +log "=============================================" + +# Track totals +TOTAL_CANDIDATES=0 +TOTAL_REMOVED=0 +TOTAL_ERRORS=0 +SKIPPED=0 + +# Helper: add package to candidate list file +add_candidates() { + local category="$1" + shift + echo "$@" >> "$HOME/logs/.cleanup-candidates-${category}.txt" +} + +# ============================================================ +# 1. PRE-FLIGHT CHECKS +# ============================================================ +section "Pre-flight Checks" + +# Verify pacman is available +if ! command -v pacman &> /dev/null; then + log "${RED}ERROR: pacman not found. This script must be run on Arch/Manjaro.${RESET}" + exit 1 +fi + +# Check disk space (need room for transaction) +DISK_PCT=$(df / | awk 'NR==2 {gsub(/%/,"",$5); print $5}') +if [[ "$DISK_PCT" -gt 95 ]]; then + log "${RED}WARNING: Disk usage at ${DISK_PCT}%. Consider freeing space first.${RESET}" +fi +DISK_AVAIL=$(df -h / | awk 'NR==2 {print $4}') +log "Disk available: $DISK_AVAIL" + +# Check for existing packages (only list ones that are installed) +log "Scanning for installed cleanup candidates..." + +# ============================================================ +# 2. OLD MULTIMEDIA PACKAGES +# ============================================================ +section "[1/7] Old Multimedia Packages" + +CANDIDATES=() +# Old ffmpeg version +if pacman -Qe ffmpeg4.4 &>/dev/null || pacman -Q ffmpeg4.4 &>/dev/null; then + CANDIDATES+=(ffmpeg4.4) +fi + +# VLC plugins (keep base vlc) +while IFS= read -r pkg; do + [[ "$pkg" == "vlc" ]] && continue # skip base vlc + CANDIDATES+=("$pkg") +done < <(pacman -Qq 2>/dev/null | grep -E '^vlc-' || true) + +TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) +log "Found ${#CANDIDATES[@]} multimedia candidates: ${CANDIDATES[*]:0:5}..." + +if [[ ${#CANDIDATES[@]} -gt 0 ]]; then + log "Candidates: ${CANDIDATES[*]}" + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm ${CANDIDATES[*]}" + else + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + fi +fi + +# ============================================================ +# 3. INACTIVE NVIDIA/MHWHD DRIVERS +# ============================================================ +section "[2/7] Inactive NVIDIA Drivers (mhwd-nvidia-*)" + +CANDIDATES=() +while IFS= read -r pkg; do + [[ -n "$pkg" ]] && CANDIDATES+=("$pkg") +done < <(pacman -Qq 2>/dev/null | grep -E '^mhwd-nvidia-' || true) + +TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) +if [[ ${#CANDIDATES[@]} -gt 0 ]]; then + log "Found ${#CANDIDATES[@]} mhwd-nvidia candidates: ${CANDIDATES[*]}" + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm ${CANDIDATES[*]}" + else + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + fi +else + log "No mhwd-nvidia packages found." +fi + +# ============================================================ +# 4. OLD KERNELS +# ============================================================ +section "[3/7] Old Kernel Packages" + +CANDIDATES=() +# linux618 and linux70 (keep current running kernel and its modules) +CURRENT_KERNEL=$(uname -r) +KMVR="${CURRENT_KERNEL%-MANJARO}" # 6.18.33-1 +KMJ="${KMVR%%.*}" # 6 +KMREST="${KMVR#*.}" # 18.33-1 +KMN="${KMREST%%.*}" # 18 +CURRENT_KERNEL_PKG="linux${KMJ}${KMN}" # linux618 +log "Current running kernel: $CURRENT_KERNEL (package: $CURRENT_KERNEL_PKG)" + +for kernel in linux618 linux70; do + # Skip if this is the running kernel package + if [[ "$kernel" == "linux${CURRENT_KERNEL_PKG}" ]]; then + log "Skipping $kernel — this is the running kernel." + continue + fi + if pacman -Q "$kernel" &>/dev/null; then + CANDIDATES+=("$kernel") + # Also remove its modules/headers/etc (but not nvidia/r8168 for running kernel — already skipped above) + while IFS= read -r pkg; do + [[ -n "$pkg" ]] && CANDIDATES+=("$pkg") + done < <(pacman -Qq 2>/dev/null | grep -E "^${kernel}-" || true) + fi +done + +TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) +if [[ ${#CANDIDATES[@]} -gt 0 ]]; then + log "Found ${#CANDIDATES[@]} kernel candidates: ${CANDIDATES[*]}" + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm ${CANDIDATES[*]}" + else + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + fi +else + log "No old kernel packages found." +fi + +# ============================================================ +# 5. lib32 PACKAGES +# ============================================================ +section "[4/7] lib32 Packages" + +CANDIDATES=() +while IFS= read -r pkg; do + [[ -n "$pkg" ]] && CANDIDATES+=("$pkg") +done < <(pacman -Qq 2>/dev/null | grep -E '^lib32-' || true) + +TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) +log "Found ${#CANDIDATES[@]} lib32 packages" + +if [[ ${#CANDIDATES[@]} -gt 0 ]]; then + # List first 10, then total + log "First 10 candidates: ${CANDIDATES[*]:0:10}..." + log "Total: ${#CANDIDATES[@]} lib32 packages" + + # Interactive: ask user if they want to remove lib32 packages + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm ${CANDIDATES[*]}" + else + log "${BOLD}This will remove ALL ${#CANDIDATES[@]} lib32 packages.${RESET}" + log "Only remove if you don't run 32-bit applications (games, wine, etc.)" + read -rp "Remove all lib32 packages? [y/N] " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + else + log "SKIPPED lib32 removal." + SKIPPED=$((SKIPPED + ${#CANDIDATES[@]})) + fi + fi +fi + +# ============================================================ +# 6. REDUNDANT FONTS (Nerd Font variants) +# ============================================================ +section "[5/7] Redundant Font Packages" + +CANDIDATES=() +# Nerd Font packages (keep the one in active use) +while IFS= read -r pkg; do + [[ -n "$pkg" ]] && CANDIDATES+=("$pkg") +done < <(pacman -Qq 2>/dev/null | grep -iE 'nerd-font' || true) + +# Also check for duplicate font collections +while IFS= read -r pkg; do + [[ -n "$pkg" ]] && CANDIDATES+=("$pkg") +done < <(pacman -Qq 2>/dev/null | grep -iE 'ttf-(jetbrains|iosevka|fira|hack|noto)' || true) + +TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) +if [[ ${#CANDIDATES[@]} -gt 0 ]]; then + log "Found ${#CANDIDATES[@]} font candidates:" + for pkg in "${CANDIDATES[@]}"; do + log " - $pkg" + done + + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would show above packages for manual review" + else + log "${RED}CRITICAL: Review font packages carefully - removing wrong fonts can break UI.${RESET}" + read -rp "Remove these ${#CANDIDATES[@]} font packages? [y/N] " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + else + log "SKIPPED font removal." + SKIPPED=$((SKIPPED + ${#CANDIDATES[@]})) + fi + fi +else + log "No redundant font packages found." +fi + +# ============================================================ +# 7. BROWSERS (keep current active, remove extras) +# ============================================================ +section "[6/7] Browser Packages" + +CANDIDATES=() +# Check which browsers are installed +BROWSERS=() +for browser in firefox chromium google-chrome firefox-developer-edition brave-bin microsoft-edge; do + if pacman -Q "$browser" &>/dev/null; then + BROWSERS+=("$browser") + fi +done + +log "Installed browsers: ${BROWSERS[*]}" +log "${BOLD}Recommended: Keep firefox-developer-edition + one other${RESET}" + +if [[ ${#BROWSERS[@]} -gt 2 ]]; then + # Suggest removal of non-essential browsers + SUGGESTED_REMOVAL=() + for b in "${BROWSERS[@]}"; do + # Keep firefox-developer-edition and chromium/google-chrome + if [[ "$b" != "firefox-developer-edition" && "$b" != "chromium" && "$b" != "google-chrome" ]]; then + SUGGESTED_REMOVAL+=("$b") + fi + done + + if [[ ${#SUGGESTED_REMOVAL[@]} -gt 0 ]]; then + CANDIDATES=("${SUGGESTED_REMOVAL[@]}") + TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) + log "Suggested removal: ${CANDIDATES[*]}" + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm ${CANDIDATES[*]}" + else + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + fi + fi +else + log "Browser count is manageable (${#BROWSERS[@]}). No action needed." +fi + +# ============================================================ +# 8. UNUSED PYTHON PACKAGES +# ============================================================ +section "[7/7] Unused Python GUI Packages" + +CANDIDATES=() +PYTHON_CANDIDATES=( + wxpython + wxpython-gtk3 + pyqt5 + pyqt5-sip + pyqt6 + pyqt6-sip + fluidity + tk + tkinter + python-tk +) + +for pkg in "${PYTHON_CANDIDATES[@]}"; do + if pacman -Q "$pkg" &>/dev/null; then + CANDIDATES+=("$pkg") + fi +done + +TOTAL_CANDIDATES=$((TOTAL_CANDIDATES + ${#CANDIDATES[@]})) +if [[ ${#CANDIDATES[@]} -gt 0 ]]; then + log "Found ${#CANDIDATES[@]} Python GUI candidates: ${CANDIDATES[*]}" + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm ${CANDIDATES[*]}" + else + sudo pacman -Rns --noconfirm "${CANDIDATES[@]}" 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ${#CANDIDATES[@]})) + fi +else + log "No unused Python GUI packages found." +fi + +# ============================================================ +# CLEANUP ORPHANS & CACHE +# ============================================================ +section "Post-Cleanup: Orphans & Cache" + +log "Finding orphaned dependencies..." +ORPHANS=$(pacman -Qtdq 2>/dev/null || true) +if [[ -n "$ORPHANS" ]]; then + ORPHAN_COUNT=$(echo "$ORPHANS" | wc -l) + log "Found $ORPHAN_COUNT orphaned packages" + if [[ "$MODE" == "check" ]]; then + log "DRY-RUN: Would run: sudo pacman -Rns --noconfirm $(echo $ORPHANS)" + else + sudo pacman -Rns --noconfirm $ORPHANS 2>&1 | tee -a "$LOCAL_LOG" || true + TOTAL_REMOVED=$((TOTAL_REMOVED + ORPHAN_COUNT)) + fi +else + log "No orphaned packages found." +fi + +log "Cleaning pacman cache (keep last 2 versions)..." +if [[ "$MODE" == "check" ]]; then + CACHE_SIZE=$(du -sh /var/cache/pacman/pkg/ 2>/dev/null | cut -f1) + log "Cache size: $CACHE_SIZE" + log "DRY-RUN: Would run: sudo paccache -rk2" +else + sudo paccache -rk2 2>&1 | tee -a "$LOCAL_LOG" || true +fi + +# ============================================================ +# SUMMARY +# ============================================================ +section "Cleanup Summary" + +FINAL_DISK=$(df -h / | awk 'NR==2 {print $4}') +log "Disk space available after cleanup: $FINAL_DISK" +log "Total candidates identified: $TOTAL_CANDIDATES" +log "Packages removed: $TOTAL_REMOVED" +log "Packages skipped: $SKIPPED" +log "Log saved to: $LOCAL_LOG" + +log "" +log "=============================================" +log " Cleanup Complete" +log "=============================================" + +# Cleanup temp files +rm -f "$HOME/logs/.cleanup-candidates-"*.txt 2>/dev/null || true diff --git a/scripts/nvidia-recovery.sh b/scripts/nvidia-recovery.sh new file mode 100755 index 0000000..29cf6e2 --- /dev/null +++ b/scripts/nvidia-recovery.sh @@ -0,0 +1,230 @@ +#!/bin/bash +set -euo pipefail + +# NVIDIA Kernel Module Recovery Script +# Purpose: Reinstall nvidia-580xx-dkms and rebuild kernel module after package cleanup removed it +# Target: mw-pfeddersheim-workstation (Manjaro, NVIDIA GPU) + +MODE="apply" +if [[ "${1:-}" == "--check" ]]; then + MODE="check" + echo "=== Running in CHECK mode (diagnostic only, no changes) ===" +elif [[ "${1:-}" == "--help" ]]; then + echo "Usage: $0 [--check | --apply | --help]" + echo " --check Diagnose and show what would be done" + echo " --apply Reinstall nvidia-580xx-dkms and rebuild module (requires sudo)" + echo " --help Show this help" + exit 0 +fi + +mkdir -p "$HOME/logs" 2>/dev/null || true +LOCAL_LOG="$HOME/logs/nvidia-recovery-$(date +%Y%m%d-%H%M%S).log" +BOLD=$(tput bold 2>/dev/null || true) +RED=$(tput setaf 1 2>/dev/null || true) +GREEN=$(tput setaf 2 2>/dev/null || true) +YELLOW=$(tput setaf 3 2>/dev/null || true) +RESET=$(tput sgr0 2>/dev/null || true) + +log() { echo -e "$*" | tee -a "$LOCAL_LOG"; } +section() { log ""; log "${BOLD}--- $1 ---${RESET}"; } + +echo "" | tee -a "$LOCAL_LOG" +log "=============================================" +log " NVIDIA Kernel Module Recovery" +log " Date: $(date)" +log " Log: $LOCAL_LOG" +log "=============================================" + +# ============================================================ +# 1. DIAGNOSTICS +# ============================================================ +section "Diagnostic" + +# Get current kernel +RUNNING_KERNEL=$(uname -r) +log "Running kernel: $RED$RUNNING_KERNEL$RESET" + +KERNEL_VERSION="${RUNNING_KERNEL%-MANJARO}" # 6.18.33-1 +KERNEL_MAJOR="${KERNEL_VERSION%%.*}" # 6 +KERNEL_MINOR="${KERNEL_VERSION#*.}" # 18.33-1 +KERNEL_MINOR="${KERNEL_MINOR%%.*}" # 18 +KERNEL_PKG="linux${KERNEL_MAJOR}${KERNEL_MINOR}" # linux618 +log "Kernel package: $KERNEL_PKG" + +# Check if nvidia module exists +MODULE_PATH="/usr/lib/modules/$RUNNING_KERNEL/extra/modules/nvidia.ko.zst" +MODULE_PATH2="/usr/lib/modules/$RUNNING_KERNEL/extra/nvidia.ko.zst" +MODULE_PATH3="/usr/lib/modules/$RUNNING_KERNEL/updates/dkms/nvidia.ko.zst" +MODULE_PATH4="/usr/lib/modules/$RUNNING_KERNEL/updates/nvidia.ko.zst" +MODULE_PATH5="/usr/lib/modules/$RUNNING_KERNEL/kernel/drivers/gpu/drm/nvidia/nvidia.ko.zst" + +MODULE_FOUND=false +if [[ -f "$MODULE_PATH" ]] || [[ -f "$MODULE_PATH2" ]] || [[ -f "$MODULE_PATH3" ]] || [[ -f "$MODULE_PATH4" ]] || [[ -f "$MODULE_PATH5" ]]; then + MODULE_FOUND=true + log "${GREEN}NVIDIA module found at $MODULE_PATH3$RESET" +else + log "${RED}NVIDIA module MISSING for kernel $RUNNING_KERNEL$RESET" +fi + +# Check nvidia-utils +if command -v nvidia-smi &>/dev/null; then + log "${GREEN}nvidia-smi: available$RESET" +else + log "${RED}nvidia-smi: not found$RESET" +fi + +# Check DKMS +if command -v dkms &>/dev/null; then + log "${GREEN}dkms: available$RESET" +else + log "${RED}dkms: not found$RESET" +fi + +# Check if nvidia-580xx-dkms is installed +if pacman -Q nvidia-580xx-dkms &>/dev/null; then + DKMS_INSTALLED=true + log "${GREEN}nvidia-580xx-dkms: installed$(pacman -Qi nvidia-580xx-dkms 2>/dev/null | grep Version)" +else + DKMS_INSTALLED=false + log "${RED}nvidia-580xx-dkms: NOT installed$RESET" +fi + +# Check if nvidia-utils is installed +if pacman -Q nvidia-utils &>/dev/null; then + log "${GREEN}nvidia-utils: installed" +else + log "${RED}nvidia-utils: NOT installed$RESET" +fi + +# Check modules-load config +if [[ -f /etc/modules-load.d/mhwd-gpu.conf ]]; then + log "modules-load config: /etc/modules-load.d/mhwd-gpu.conf exists" + log " Entries: $(grep -v '^#\|^$' /etc/modules-load.d/mhwd-gpu.conf | tr '\n' ' ')" +else + log "${RED}No mhwd-gpu.conf found$RESET" +fi + +# ============================================================ +# 2. CHECK DEPENDENCIES +# ============================================================ +section "Dependency Check" + +MISSING=() +if ! command -v dkms &>/dev/null; then + MISSING+=(dkms) +fi +if ! command -v mkinitcpio &>/dev/null; then + MISSING+=(mkinitcpio) +fi + +if [[ ${#MISSING[@]} -gt 0 ]]; then + log "${RED}Missing base tools: ${MISSING[*]}$RESET" + log "These will be installed as part of the fix." +fi + +# Check available disk space +DISK_AVAIL=$(df -h / | awk 'NR==2 {print $4}') +log "Disk available: $DISK_AVAIL" + +# ============================================================ +# 3. APPLY FIX +# ============================================================ +section "Applying Fix" + +if [[ "$MODE" == "check" ]]; then + log "${BOLD}DRY-RUN MODE${RESET}" + log "Would execute:" + log " sudo pacman -Rns --noconfirm nvidia-utils # remove conflicting non-580xx driver" + log " sudo pacman -S --needed nvidia-580xx-dkms nvidia-580xx-utils" + log " sudo pacman -S --needed linux618-headers # kernel headers for DKMS" + log " sudo dkms autoinstall" + log " sudo mkinitcpio -P" + log " sudo reboot" + exit 0 +fi + +# Confirm before destructive action +log "${BOLD}This will reinstall the NVIDIA kernel module driver.$RESET" +log "The system will reboot automatically." +read -rp "Continue? [y/N] " confirm +if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + log "ABORTED by user." + exit 0 +fi + +# Step 1: Resolve driver conflict, install 580xx suite +log "[1/5] Resolving NVIDIA driver conflict and installing 580xx suite..." +# Check if newer nvidia-utils conflicts with 580xx-dkms +if pacman -Q nvidia-utils &>/dev/null && ! pacman -Q nvidia-580xx-utils &>/dev/null; then + log "Conflict: nvidia-utils (non-580xx) installed alongside nvidia-580xx-dkms." + log "Removing conflicting nvidia-utils, installing nvidia-580xx-utils..." + sudo pacman -Rns --noconfirm nvidia-utils 2>&1 | tee -a "$LOCAL_LOG" + sudo pacman -S --needed --noconfirm nvidia-580xx-dkms nvidia-580xx-utils 2>&1 | tee -a "$LOCAL_LOG" +else + sudo pacman -S --needed --noconfirm nvidia-580xx-dkms nvidia-580xx-utils 2>&1 | tee -a "$LOCAL_LOG" +fi + +# Step 2: Ensure kernel headers are available for DKMS +log "[1b/4] Checking kernel headers for DKMS..." +KERNEL_HEADERS="${KERNEL_PKG}-headers" +if pacman -Q "$KERNEL_HEADERS" &>/dev/null; then + log "${GREEN}Kernel headers ($KERNEL_HEADERS) already installed.$RESET" +else + log "Installing $KERNEL_HEADERS for DKMS..." + sudo pacman -S --needed --noconfirm "$KERNEL_HEADERS" 2>&1 | tee -a "$LOCAL_LOG" +fi + +# Step 3: Rebuild DKMS module for current kernel +log "[2/5] Rebuilding DKMS module for kernel $RUNNING_KERNEL..." +sudo dkms autoinstall 2>&1 | tee -a "$LOCAL_LOG" + +# Step 3: Verify module was created +log "[3/5] Verifying module..." +if [[ -f "$MODULE_PATH" ]] || [[ -f "$MODULE_PATH2" ]] || [[ -f "$MODULE_PATH3" ]] || [[ -f "$MODULE_PATH4" ]] || [[ -f "$MODULE_PATH5" ]]; then + log "${GREEN}Module verified!$RESET" + # Show module details + modinfo_output=$(modinfo nvidia 2>/dev/null || echo "modinfo failed") + log " $modinfo_output" +else + log "${RED}WARNING: Module file not found after DKMS build.$RESET" + # Detect version for manual build + DKMS_VERSION=$(pacman -Qi nvidia-580xx-dkms 2>/dev/null | grep Version | awk '{print $2}' | cut -d- -f1) + [[ -z "$DKMS_VERSION" ]] && DKMS_VERSION="580.159.04" + log "Attempting manual build (version: $DKMS_VERSION)..." + sudo dkms build -m nvidia -v "$DKMS_VERSION" -k "$RUNNING_KERNEL" 2>&1 | tee -a "$LOCAL_LOG" + sudo dkms install -m nvidia -v "$DKMS_VERSION" -k "$RUNNING_KERNEL" 2>&1 | tee -a "$LOCAL_LOG" +fi + +# Step 4: Rebuild initramfs +log "[4/5] Rebuilding initramfs..." +sudo mkinitcpio -P 2>&1 | tee -a "$LOCAL_LOG" + +# ============================================================ +# 4. VERIFICATION +# ============================================================ +section "Post-Recovery Verification" + +log "Checking module loading..." +if sudo modprobe nvidia 2>&1; then + log "${GREEN}nvidia module loaded successfully$RESET" +else + log "${YELLOW}modprobe nvidia failed - module will be loaded at next boot$RESET" +fi + +# Detect 580xx version for manual DKMS fallback +DKMS_VERSION=$(pacman -Qi nvidia-580xx-dkms 2>/dev/null | grep Version | awk '{print $2}' | cut -d- -f1 || echo "580.159.04") + +# Manual DKMS fallback uses DKMS_VERSION variable + +log "" +log "${BOLD}Recovery complete!${RESET}" +log "" +log "Before rebooting, verify:" +log " 1. Module exists: ls /usr/lib/modules/$(uname -r)/extra/nvidia*" +log " 2. nvidia-smi works: sudo nvidia-smi" +log "" +log "Then reboot:" +log " sudo reboot" +log "" +log "Log saved to: $LOCAL_LOG" +log "============================================="