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.
This commit is contained in:
stornic56
2026-07-26 01:15:57 -05:00
committed by GitHub
parent 762285f993
commit f0cea296d7
4 changed files with 15 additions and 15 deletions
+2 -2
View File
@@ -46,8 +46,8 @@ DEBIAN_CODENAME=""
main_menu() { main_menu() {
# Auto-adjust TUI dimensions for small terminals # Auto-adjust TUI dimensions for small terminals
if [ "${LINES:-24}" -lt $((TUI_ALTO + 6)) ] || [ "${COLUMNS:-80}" -lt $((TUI_ANCHO + 6)) ]; then if [ "${LINES:-24}" -lt $((TUI_ALTO + 6)) ] || [ "${COLUMNS:-80}" -lt $((TUI_ANCHO + 6)) ]; then
TUI_ALTO=$((LINES - 4 > 8 ? LINES - 4 : 8)) TUI_ALTO=$(( ${LINES:-24} - 4 > 8 ? ${LINES:-24} - 4 : 8))
TUI_ANCHO=$((COLUMNS - 4 > 50 ? COLUMNS - 4 : 50)) TUI_ANCHO=$(( ${COLUMNS:-80} - 4 > 50 ? ${COLUMNS:-80} - 4 : 50))
TUI_ALTO_LISTA=$((TUI_ALTO - 10 > 4 ? TUI_ALTO - 10 : 4)) TUI_ALTO_LISTA=$((TUI_ALTO - 10 > 4 ? TUI_ALTO - 10 : 4))
fi fi
+2 -2
View File
@@ -225,7 +225,7 @@ _cat_general() {
fi fi
;; ;;
nvme-cli) 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." echo "No NVMe controller detected. Skipping."
continue continue
fi fi
@@ -235,7 +235,7 @@ _cat_general() {
local nvme_devs=() local nvme_devs=()
while read -r dev; do while read -r dev; do
nvme_devs+=("$dev") 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 if [ ${#nvme_devs[@]} -eq 0 ]; then
echo "No NVMe block devices found for health check." echo "No NVMe block devices found for health check."
continue continue
+4 -4
View File
@@ -112,7 +112,7 @@ _show_sysinfo() {
lo|docker*|veth*|br-*|virbr*|tun*|tap*|bond*) continue ;; lo|docker*|veth*|br-*|virbr*|tun*|tap*|bond*) continue ;;
esac 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) # Determine type by PCI class (most reliable)
local pci_class="" local pci_class=""
@@ -129,7 +129,7 @@ _show_sysinfo() {
desc="${wifi_descs[0]:-Unknown WiFi chipset}" desc="${wifi_descs[0]:-Unknown WiFi chipset}"
shown_wifi_descs+=("${wifi_descs[0]}") shown_wifi_descs+=("${wifi_descs[0]}")
ssid="" 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 # Fallback: classify by interface name pattern
@@ -139,7 +139,7 @@ _show_sysinfo() {
desc="${wifi_descs[0]:-Unknown WiFi chipset}" desc="${wifi_descs[0]:-Unknown WiFi chipset}"
shown_wifi_descs+=("${wifi_descs[0]}") shown_wifi_descs+=("${wifi_descs[0]}")
ssid="" 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*) eth*|enp*|ens*|enx*|eno*)
has_eth=true has_eth=true
@@ -163,7 +163,7 @@ _show_sysinfo() {
else else
msg+="${iface}: ${desc}\n ↓\n" msg+="${iface}: ${desc}\n ↓\n"
fi fi
done < <(ip -o link show 2>/dev/null) done < <(timeout 2 ip -o link show 2>/dev/null)
fi fi
# ── 5. Show chipsets without an active interface ── # ── 5. Show chipsets without an active interface ──
+7 -7
View File
@@ -243,7 +243,7 @@ detect_gpu() {
local nv_ver local nv_ver
nv_ver=$(timeout 3 nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -1) || true nv_ver=$(timeout 3 nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -1) || true
if [ -z "$nv_ver" ]; then 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 fi
[ -n "$nv_ver" ] && GPU_VERSION="NVIDIA $nv_ver" [ -n "$nv_ver" ] && GPU_VERSION="NVIDIA $nv_ver"
fi fi
@@ -325,16 +325,16 @@ detect_network() {
state=$(echo "$line" | awk '{print $9}') state=$(echo "$line" | awk '{print $9}')
case "$iface" in case "$iface" in
eth*|enp*|ens*|enx*|eno*) 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_NAMES+=("$iface")
ETH_STATES+=("$state") ETH_STATES+=("$state")
ETH_IPS+=("${ip4:-}") ETH_IPS+=("${ip4:-}")
ETH_DESCS+=("${ETH_DESC:-}") ETH_DESCS+=("${ETH_DESC:-}")
;; ;;
wl*|wlp*|wlo*|wlan*) 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="" 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_NAMES+=("$iface")
WIFI_STATES+=("$state") WIFI_STATES+=("$state")
WIFI_IPS+=("${ip4:-}") WIFI_IPS+=("${ip4:-}")
@@ -342,7 +342,7 @@ detect_network() {
WIFI_DESCS+=("${WIFI_DESC:-}") WIFI_DESCS+=("${WIFI_DESC:-}")
;; ;;
esac 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
fi fi
parts+=("${size} ${type}") 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 if [ ${#parts[@]} -eq 0 ]; then
STORAGE_SUMMARY="No disks detected" STORAGE_SUMMARY="No disks detected"
@@ -423,7 +423,7 @@ detect_desktop_environment() {
# Audio server detection (PipeWire / PulseAudio) # Audio server detection (PipeWire / PulseAudio)
# --------------------------------------- # ---------------------------------------
detect_audio_server() { 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" AUDIO_SERVER="pipewire"
elif command -v pactl &>/dev/null; then elif command -v pactl &>/dev/null; then
AUDIO_SERVER="pulseaudio" AUDIO_SERVER="pulseaudio"