From f0cea296d76342d1a819f476e7fa0c441ad89460 Mon Sep 17 00:00:00 2001 From: stornic56 <71296607+stornic56@users.noreply.github.com> Date: Sun, 26 Jul 2026 01:15:57 -0500 Subject: [PATCH] fix harden hardware detection D3cold freezes Fixes a critical startup crash on hybrid graphics laptops (e.g., Intel + Nvidia) running fresh Debian installs without proprietary drivers. When the secondary GPU enters D3cold power state, kernel-level I/O operations (like `lspci` or reading `/sys/block/`) hang in Uninterruptible Sleep (State D), ignoring standard kill signals and freezing the terminal. Combined with `set -euo pipefail`, these hangs made the script silently fail or enter infinite loops. Changes: - Timeout Wrappers: Wrapped all hardware probing commands (`lspci`, `lsblk`, `cat /sys/...`, `ip`, `iwgetid`, `pw-cli`) with `timeout 2` to force-continue if the kernel blocks. - Pipeline Safety: Added `|| true` to `nvidia-smi` and `dpkg` fallback queries to prevent `pipefail` from killing the script when drivers are missing. - Loop Hardening: Fixed an infinite loop in `detect_gpu()` where empty `lspci` outputs caused by timeouts would loop forever by adding `[[ -z "$line" ]] && continue`. - TUI Fallbacks: Added default values for `${LINES:-24}` and `${COLUMNS:-80}` to prevent `set -u` from crashing the `whiptail` menu in restricted shell environments. --- debianito.sh | 4 ++-- modules/extras/system/system.sh | 4 ++-- modules/sysinfo.sh | 8 ++++---- modules/utils.sh | 14 +++++++------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/debianito.sh b/debianito.sh index 2f96dba..d25ec6f 100644 --- a/debianito.sh +++ b/debianito.sh @@ -46,8 +46,8 @@ DEBIAN_CODENAME="" main_menu() { # Auto-adjust TUI dimensions for small terminals if [ "${LINES:-24}" -lt $((TUI_ALTO + 6)) ] || [ "${COLUMNS:-80}" -lt $((TUI_ANCHO + 6)) ]; then - TUI_ALTO=$((LINES - 4 > 8 ? LINES - 4 : 8)) - TUI_ANCHO=$((COLUMNS - 4 > 50 ? COLUMNS - 4 : 50)) + TUI_ALTO=$(( ${LINES:-24} - 4 > 8 ? ${LINES:-24} - 4 : 8)) + TUI_ANCHO=$(( ${COLUMNS:-80} - 4 > 50 ? ${COLUMNS:-80} - 4 : 50)) TUI_ALTO_LISTA=$((TUI_ALTO - 10 > 4 ? TUI_ALTO - 10 : 4)) fi diff --git a/modules/extras/system/system.sh b/modules/extras/system/system.sh index 8bf7988..e3491a6 100644 --- a/modules/extras/system/system.sh +++ b/modules/extras/system/system.sh @@ -225,7 +225,7 @@ _cat_general() { fi ;; nvme-cli) - if ! lsblk -d -o TRAN 2>/dev/null | grep -q "^nvme$"; then + if ! timeout 2 lsblk -d -o TRAN 2>/dev/null | grep -q "^nvme$"; then echo "No NVMe controller detected. Skipping." continue fi @@ -235,7 +235,7 @@ _cat_general() { local nvme_devs=() while read -r dev; do nvme_devs+=("$dev") - done < <(lsblk -d -o NAME,TRAN 2>/dev/null | awk '$2 == "nvme" {print $1}') + done < <(timeout 2 lsblk -d -o NAME,TRAN 2>/dev/null | awk '$2 == "nvme" {print $1}') if [ ${#nvme_devs[@]} -eq 0 ]; then echo "No NVMe block devices found for health check." continue diff --git a/modules/sysinfo.sh b/modules/sysinfo.sh index 021b9ae..e88fb91 100644 --- a/modules/sysinfo.sh +++ b/modules/sysinfo.sh @@ -112,7 +112,7 @@ _show_sysinfo() { lo|docker*|veth*|br-*|virbr*|tun*|tap*|bond*) continue ;; esac - ip4=$(ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}') + ip4=$(timeout 2 ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}') # Determine type by PCI class (most reliable) local pci_class="" @@ -129,7 +129,7 @@ _show_sysinfo() { desc="${wifi_descs[0]:-Unknown WiFi chipset}" shown_wifi_descs+=("${wifi_descs[0]}") ssid="" - [ "$state" = "UP" ] && ssid=$(iwgetid -r "$iface" 2>/dev/null || true) + [ "$state" = "UP" ] && ssid=$(timeout 2 iwgetid -r "$iface" 2>/dev/null || true) ;; *) # Fallback: classify by interface name pattern @@ -139,7 +139,7 @@ _show_sysinfo() { desc="${wifi_descs[0]:-Unknown WiFi chipset}" shown_wifi_descs+=("${wifi_descs[0]}") ssid="" - [ "$state" = "UP" ] && ssid=$(iwgetid -r "$iface" 2>/dev/null || true) + [ "$state" = "UP" ] && ssid=$(timeout 2 iwgetid -r "$iface" 2>/dev/null || true) ;; eth*|enp*|ens*|enx*|eno*) has_eth=true @@ -163,7 +163,7 @@ _show_sysinfo() { else msg+="${iface}: ${desc}\n ↓\n" fi - done < <(ip -o link show 2>/dev/null) + done < <(timeout 2 ip -o link show 2>/dev/null) fi # ── 5. Show chipsets without an active interface ── diff --git a/modules/utils.sh b/modules/utils.sh index 3af1bee..110b651 100644 --- a/modules/utils.sh +++ b/modules/utils.sh @@ -243,7 +243,7 @@ detect_gpu() { local nv_ver nv_ver=$(timeout 3 nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -1) || true if [ -z "$nv_ver" ]; then - nv_ver=$(dpkg -l nvidia-driver 2>/dev/null | awk '/^ii/ {print $3}' | sed 's/-.*//') + nv_ver=$(dpkg -l nvidia-driver 2>/dev/null | awk '/^ii/ {print $3}' | sed 's/-.*//') || true fi [ -n "$nv_ver" ] && GPU_VERSION="NVIDIA $nv_ver" fi @@ -325,16 +325,16 @@ detect_network() { state=$(echo "$line" | awk '{print $9}') case "$iface" in eth*|enp*|ens*|enx*|eno*) - ip4=$(ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}') + ip4=$(timeout 2 ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}') ETH_NAMES+=("$iface") ETH_STATES+=("$state") ETH_IPS+=("${ip4:-}") ETH_DESCS+=("${ETH_DESC:-}") ;; wl*|wlp*|wlo*|wlan*) - ip4=$(ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}') + ip4=$(timeout 2 ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}') ssid="" - [ "$state" = "UP" ] && ssid=$(iwgetid -r "$iface" 2>/dev/null || true) + [ "$state" = "UP" ] && ssid=$(timeout 2 iwgetid -r "$iface" 2>/dev/null || true) WIFI_NAMES+=("$iface") WIFI_STATES+=("$state") WIFI_IPS+=("${ip4:-}") @@ -342,7 +342,7 @@ detect_network() { WIFI_DESCS+=("${WIFI_DESC:-}") ;; esac - done < <(ip -o link show 2>/dev/null) + done < <(timeout 2 ip -o link show 2>/dev/null) } # --------------------------------------- @@ -391,7 +391,7 @@ detect_storage() { fi fi parts+=("${size} ${type}") - done < <(lsblk -d -o NAME,SIZE,ROTA,TYPE -e 7,11 2>/dev/null || true) + done < <(timeout 2 lsblk -d -o NAME,SIZE,ROTA,TYPE -e 7,11 2>/dev/null || true) if [ ${#parts[@]} -eq 0 ]; then STORAGE_SUMMARY="No disks detected" @@ -423,7 +423,7 @@ detect_desktop_environment() { # Audio server detection (PipeWire / PulseAudio) # --------------------------------------- detect_audio_server() { - if command -v pw-cli &>/dev/null && pw-cli info &>/dev/null 2>&1; then + if command -v pw-cli &>/dev/null && timeout 2 pw-cli info &>/dev/null 2>&1; then AUDIO_SERVER="pipewire" elif command -v pactl &>/dev/null; then AUDIO_SERVER="pulseaudio"