Hwprobe-Device Driver status tool and offline Report

New features which should be implemented in Porteus; suggestions are welcome. All questions or problems with testing releases (alpha, beta, or rc) should go in their relevant thread here, rather than the Bug Reports section.
Testuser
Samurai
Samurai
Posts: 170
Joined: 26 May 2021, 15:11
Distribution: Porteux-v2.6-LXDE

Hwprobe-Device Driver status tool and offline Report

Post#1 by Testuser » 31 Aug 2026, 18:43

This is regarding hwprobe tool

https://github.com/linuxhw/hw-probe, what it does it run and has to upload it to there website - https://linux-hardware.org/ to get a report on the drivers status of our linux pc.

Sample report - https://linux-hardware.org/?probe=0c82de2288

I have made a script to show the hardware report as html without uploading using YAD,

Yad also shows the driver details and help use to locate the driver file. You can also launch the HTML report from yad.

the script uses Appimage of hwprobe and yad.

I am uploading a module for this with all the scripts and desktop files.

https://www.mediafire.com/file/9vtjxfny ... 5.xzm/file

Hope this helps somebody. All modifications are welcome to make this better :)

Launch script

Code: Select all

#!/usr/bin/env bash
#
# Launcher script to run hardware probe as root and YAD viewer as normal user.

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo "=========================================="
echo " Starting Hardware Probe Data Collection "
echo "=========================================="
echo "Requesting authentication..."
echo

# 1. Run probe script as root via pkexec (Single Password Prompt)
if pkexec "$SCRIPT_DIR/HwProbe_offline.sh"; then
    echo
    echo "Data collection complete! Launching YAD..."
    
    # 2. Launch YAD completely detached from this terminal session
    nohup "$SCRIPT_DIR/hwprobe-yad" >/dev/null 2>&1 &
    
    # 3. Small pause then exit terminal
    sleep 0.5
    exit 0
else
    echo
    echo "Authentication failed or cancelled."
    read -rp "Press Enter to close..."
    exit 1
fi
Hwprobe offline

Code: Select all

#!/usr/bin/env bash
#
# Generates an offline HTML hardware report matching linux-hardware.org
# with syntax-highlighted log pages and deep kernel module path resolution.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT_PATH="${SCRIPT_DIR}/$(basename "${BASH_SOURCE[0]}")"

OUTPUT_DIR="${SCRIPT_DIR}/hw_probe_local"
REPORT_FILE="${SCRIPT_DIR}/hardware_report.html"
LOGS_HTML_DIR="${SCRIPT_DIR}/logs_html"

if [ "$EUID" -ne 0 ]; then
    echo "Notice: Root privileges required. Escalating with sudo..."
    exec sudo "$SCRIPT_PATH" "$@"
fi

HW_PROBE_BIN=""
APPIMAGE_PATH=$(find "$SCRIPT_DIR" -maxdepth 1 -type f -name "hw-probe-*.AppImage" | head -n1 || true)

if [ -x "/usr/bin/hw-probe" ]; then
    HW_PROBE_BIN="/usr/bin/hw-probe"
elif [ -n "$APPIMAGE_PATH" ] && [ -f "$APPIMAGE_PATH" ]; then
    chmod +x "$APPIMAGE_PATH" 2>/dev/null || true
    HW_PROBE_BIN="$APPIMAGE_PATH"
else
    echo "Error: Neither system hw-probe nor any hw-probe-*.AppImage was found in ${SCRIPT_DIR}!"
    exit 1
fi

echo "==> Using binary: ${HW_PROBE_BIN}"
echo "==> Gathering local hardware probe logs..."
rm -rf "$OUTPUT_DIR" "$LOGS_HTML_DIR"
mkdir -p "$OUTPUT_DIR" "$LOGS_HTML_DIR"

"$HW_PROBE_BIN" -all -save "$OUTPUT_DIR" > /dev/null 2>&1 || true

# Extract hw.info tarballs recursively if created
find "$OUTPUT_DIR" -type f \( -name "*.txz" -o -name "*.tar.gz" -o -name "*.tgz" \) | while read -r archive; do
    tar -xf "$archive" -C "$OUTPUT_DIR" 2>/dev/null || true
done

# Locate target log files
HW_INFO_DIR=$(find "$OUTPUT_DIR" -type d -name "hw.info" | head -n1 || true)
if [ -z "$HW_INFO_DIR" ]; then
    HW_INFO_DIR="$OUTPUT_DIR"
fi

# System Metadata Retrieval
HOSTNAME_VAL=$(cat "$HW_INFO_DIR/hostname" 2>/dev/null || hostname)
OS_VAL=$(cat "$HW_INFO_DIR/os" 2>/dev/null || echo "Linux")
ARCH_VAL=$(uname -m 2>/dev/null || echo "x86_64")
KERNEL_VAL=$(cat "$HW_INFO_DIR/kernel" 2>/dev/null || uname -r)
VENDOR_VAL=$(cat "$HW_INFO_DIR/sys_vendor" 2>/dev/null || cat "$HW_INFO_DIR/dmi/sys_vendor" 2>/dev/null || echo "Generic")
MODEL_VAL=$(cat "$HW_INFO_DIR/product_name" 2>/dev/null || cat "$HW_INFO_DIR/dmi/product_name" 2>/dev/null || echo "System")
YEAR_VAL=$(cat "$HW_INFO_DIR/product_year" 2>/dev/null || echo "N/A")
HWID_VAL=$(cat "$HW_INFO_DIR/probe.id" 2>/dev/null || echo "Offline")
TYPE_VAL=$(cat "$HW_INFO_DIR/chassis_type" 2>/dev/null || echo "Desktop/Laptop")
DE_VAL=$(cat "$HW_INFO_DIR/desktop" 2>/dev/null || echo "${DESKTOP_SESSION:-${XDG_CURRENT_DESKTOP:-Unknown}}")

# Log Categorization
get_log_category() {
    local fname
    fname=$(echo "$1" | tr '[:upper:]' '[:lower:]')
    case "$fname" in
        *hwinfo*|*devices*|*lspci*|*lsusb*|*lshw*|*lscpu*|*lsblk*|*lsscsi*|*dmidecode*|*dmi*|*pci*|*usb*|*cpu*|*bios*|*edid*|*input*)
            echo "Hardware & Devices" ;;
        *nmcli*|*iwconfig*|*ifconfig*|*ip*|*route*|*net*|*wpa*|*fstab*|*mount*|*smartctl*|*hdparm*|*disk*|*nvme*)
            echo "Network & Storage" ;;
        *dmesg*|*uname*|*uptime*|*modules*|*lsmod*|*sysctl*|*cmdline*|*hostname*|*os*|*kernel*|*systemd*)
            echo "System & Kernel" ;;
        *xorg*|*wayland*|*glxinfo*|*vulkan*|*drm*|*display*|*gpu*)
            echo "Graphics & Display" ;;
        *alsa*|*sound*|*audio*|*pulse*|*pipewire*|*amixer*|*aplay*)
            echo "Audio & Sound" ;;
        *)
            echo "Other Logs" ;;
    esac
}

# Deep Driver Module Resolution
resolve_driver_path() {
    local drv="$1"
    if [ -z "$drv" ] || [ "$drv" = "-" ]; then
        echo "-"
        return
    fi

    local mod_path=""
    
    mod_path=$(modinfo -n "$drv" 2>/dev/null || true)
    if [ -n "$mod_path" ] && [[ "$mod_path" != "(builtin)" ]] && [ -f "$mod_path" ]; then
        echo "$mod_path"
        return
    fi

    mod_path=$(modprobe --show-depends "$drv" 2>/dev/null | awk '/insmod/ {print $2}' | tail -n1 || true)
    if [ -n "$mod_path" ] && [ -f "$mod_path" ]; then
        echo "$mod_path"
        return
    fi

    local kver
    kver=$(uname -r)
    mod_path=$(find "/lib/modules/$kver" -type f \( -name "${drv}.ko" -o -name "${drv}.ko.xz" -o -name "${drv}.ko.zst" -o -name "${drv}.ko.gz" \) 2>/dev/null | head -n1 || true)
    if [ -n "$mod_path" ]; then
        echo "$mod_path"
        return
    fi

    if [ -d "/sys/module/$drv" ]; then
        echo "/sys/module/$drv"
        return
    fi

    echo "builtin / $drv"
}

echo "==> Rendering separate HTML pages for logs..."
find "$HW_INFO_DIR" -type f ! -name "*.txz" ! -name "*.gz" | sort | while read -r logfile; do
    REL_PATH="${logfile#$HW_INFO_DIR/}"
    SAFE_NAME=$(echo "$REL_PATH" | tr '/' '_').html
    TARGET_HTML="${LOGS_HTML_DIR}/${SAFE_NAME}"
    
    if file "$logfile" | grep -q "text"; then
        HIGHLIGHTED_LOG=$(sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g' "$logfile" | awk '
        {
            gsub(/(Intel|AMD|NVIDIA|Realtek|Broadcom|Qualcomm|Samsung|Lenovo|Dell|HP|Asus|Acer|Gigabyte|MSI|Crucial|Kingston|Western Digital|Seagate|Logitech|Apple|Atheros)/, "<span class=\"hl-vendor\">&</span>")
            gsub(/(driver|Driver|module|Module|kernel|Kernel|sysfs|pci|usb|i2c|nvme|ahci|snd_[a-z0-9_]+|iwlwifi|ath9k|amdgpu|i915|nouveau|nvidia)[ :=]/, "<span class=\"hl-driver\">&</span>")
            gsub(/([0-9]+(\.[0-9]+)?\s*(GHz|MHz|GiB|MiB|KiB|GB|MB|KB|TB|%|Core|Cores|Threads|bits|bit))/, "<span class=\"hl-val\">&</span>")
            gsub(/([0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9]|[0-9a-fA-F]{4}:[0-9a-fA-F]{4})/, "<span class=\"hl-id\">&</span>")
            gsub(/(\/dev\/|\/sys\/|\/lib\/|\/etc\/|\/proc\/)[a-zA-Z0-9_\/\.\-]+/, "<span class=\"hl-path\">&</span>")
            print $0
        }')

        cat <<EOF > "$TARGET_HTML"
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Log: ${REL_PATH}</title>
    <style>
        body { background: #18191a; color: #e4e6eb; font-family: monospace; font-size: 15px; padding: 25px; line-height: 1.5; }
        h2 { color: #4599df; font-family: sans-serif; font-size: 1.5em; }
        a { color: #61afef; text-decoration: none; font-family: sans-serif; font-size: 1.1em; font-weight: bold; }
        a:hover { text-decoration: underline; }
        pre { background: #242526; padding: 18px; border-radius: 6px; overflow-x: auto; border: 1px solid #3a3b3c; font-size: 0.95em; color: #e4e6eb; line-height: 1.5; }
        
        .hl-vendor { color: #e5c07b; font-weight: bold; }
        .hl-driver { color: #ce9178; font-weight: bold; }
        .hl-val    { color: #98c379; font-weight: bold; }
        .hl-id     { color: #e06c75; font-weight: bold; }
        .hl-path   { color: #61afef; }
    </style>
</head>
<body>
    <p><a href="../hardware_report.html">&larr; Back to Main Report</a></p>
    <h2>Log File: ${REL_PATH}</h2>
    <pre>${HIGHLIGHTED_LOG}</pre>
</body>
</html>
EOF
    fi
done

echo "==> Rendering primary hardware report..."

cat <<EOF > "$REPORT_FILE"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hardware Probe - ${HOSTNAME_VAL}</title>
    <style>
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #18191a; color: #e4e6eb; margin: 0; padding: 25px; font-size: 15px; }
        h2 { font-size: 1.4em; color: #ffffff; margin-top: 30px; margin-bottom: 15px; }
        h3.cat-title { color: #4599df; font-size: 1.2em; border-bottom: 1px solid #3a3b3c; padding-bottom: 6px; margin-top: 20px; margin-bottom: 12px; }
        
        .sys-card { background: #242526; padding: 20px; border-radius: 8px; margin-bottom: 25px; border: 1px solid #3a3b3c; }
        .sys-title { font-size: 1.3em; font-weight: bold; color: #4599df; margin-bottom: 15px; }
        .sys-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; font-size: 1em; }
        .sys-item { background: #1c1e21; padding: 10px 14px; border-radius: 6px; border: 1px solid #3a3b3c; }
        .sys-label { color: #b0b3b8; font-weight: bold; }
        .sys-val { color: #ffffff; font-weight: 500; }

        table.hw-table { width: 100%; border-collapse: collapse; background: #242526; border-radius: 8px; overflow: hidden; border: 1px solid #3a3b3c; margin-bottom: 30px; }
        table.hw-table th { background: #1c1e21; color: #4599df; text-align: left; padding: 12px 14px; font-size: 0.95em; text-transform: uppercase; border-bottom: 2px solid #3a3b3c; }
        table.hw-table td { padding: 11px 14px; border-bottom: 1px solid #3a3b3c; font-size: 0.95em; line-height: 1.4; }
        table.hw-table tr:hover { background: #3a3b3c; }

        .bus-id { font-family: monospace; color: #61afef; font-weight: bold; font-size: 1.05em; }
        .vendor { font-weight: bold; color: #ffffff; }
        .driver { font-family: monospace; color: #ce9178; font-size: 0.95em; }
        .drv-path { font-family: monospace; color: #98c379; font-size: 0.85em; word-break: break-all; }
        
        .status-works { background: #1b4721; color: #4caf50; padding: 3px 8px; border-radius: 4px; font-size: 0.88em; font-weight: bold; }
        .status-detected { background: #4a2c00; color: #ff9800; padding: 3px 8px; border-radius: 4px; font-size: 0.88em; font-weight: bold; }
        .status-nodriver { background: #4a0000; color: #f44336; padding: 3px 8px; border-radius: 4px; font-size: 0.88em; font-weight: bold; }
        
        .logs-container { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 15px; }
        .log-link { background: #242526; border: 1px solid #3a3b3c; padding: 8px 14px; border-radius: 5px; color: #61afef; text-decoration: none; font-size: 0.98em; font-family: monospace; font-weight: bold; }
        .log-link:hover { background: #3a3b3c; color: #ffffff; }
    </style>
</head>
<body>

    <div class="sys-card">
        <div class="sys-title">System Overview</div>
        <div class="sys-grid">
            <div class="sys-item"><span class="sys-label">System:</span> <span class="sys-val">${OS_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">Arch:</span> <span class="sys-val">${ARCH_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">Kernel:</span> <span class="sys-val">${KERNEL_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">Vendor:</span> <span class="sys-val">${VENDOR_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">Model:</span> <span class="sys-val">${MODEL_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">Year:</span> <span class="sys-val">${YEAR_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">HWid:</span> <span class="sys-val">${HWID_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">Type:</span> <span class="sys-val">${TYPE_VAL}</span></div>
            <div class="sys-item"><span class="sys-label">DE:</span> <span class="sys-val">${DE_VAL}</span></div>
        </div>
    </div>

    <h2>Devices Table</h2>
    <table class="hw-table">
        <thead>
            <tr>
                <th>BUS ID/Class</th>
                <th>Status</th>
                <th>Type</th>
                <th>Driver</th>
                <th>Vendor</th>
                <th>Device</th>
                <th>Driver Module (.ko) Path</th>
            </tr>
        </thead>
        <tbody>
EOF

DEVICES_FILE=$(find "$OUTPUT_DIR" -type f -name "devices" 2>/dev/null | head -n1 || true)

if [ -n "$DEVICES_FILE" ] && [ -s "$DEVICES_FILE" ]; then
    while IFS=';' read -r bus_id_class vendor_id status_val type_val driver_val vendor_val device_val company_val rest || [ -n "$bus_id_class" ]; do
        [[ "$bus_id_class" =~ ^# ]] && continue
        [ -z "$bus_id_class" ] && continue

        status_val=${status_val:-detected}
        type_val=${type_val:--}
        driver_val=${driver_val:--}
        vendor_val=${vendor_val:--}
        device_val=${device_val:--}

        if [ "$status_val" = "works" ]; then
            st_html="<span class=\"status-works\">works</span>"
        elif [ "$status_val" = "detected" ]; then
            st_html="<span class=\"status-detected\">detected</span>"
        else
            st_html="<span class=\"status-nodriver\">${status_val}</span>"
        fi

        drv_path=$(resolve_driver_path "$driver_val")

        cat <<TR >> "$REPORT_FILE"
            <tr>
                <td class="bus-id">${bus_id_class}</td>
                <td>${st_html}</td>
                <td>${type_val}</td>
                <td class="driver">${driver_val}</td>
                <td class="vendor">${vendor_val}</td>
                <td>${device_val}</td>
                <td class="drv-path">${drv_path}</td>
            </tr>
TR
    done < "$DEVICES_FILE"
fi

cat <<EOF >> "$REPORT_FILE"
        </tbody>
    </table>

    <h2>Hardware Probe Logs</h2>
EOF

CATEGORIES=("Audio & Sound" "Graphics & Display" "Hardware & Devices" "Network & Storage" "System & Kernel" "Other Logs")

for cat_name in "${CATEGORIES[@]}"; do
    FOUND_LOGS=()
    while IFS= read -r html_page; do
        [ -z "$html_page" ] && continue
        REL_NAME=$(basename "$html_page")
        DISPLAY_NAME=$(echo "$REL_NAME" | sed 's/\.html$//; s/_/\//g')
        
        LOG_CAT=$(get_log_category "$DISPLAY_NAME")
        if [ "$LOG_CAT" = "$cat_name" ]; then
            FOUND_LOGS+=("<a class=\"log-link\" href=\"logs_html/${REL_NAME}\" target=\"_blank\">${DISPLAY_NAME}</a>")
        fi
    done < <(find "$LOGS_HTML_DIR" -name "*.html" | sort)

    if [ ${#FOUND_LOGS[@]} -gt 0 ]; then
        echo "    <h3 class=\"cat-title\">${cat_name}</h3>" >> "$REPORT_FILE"
        echo "    <div class=\"logs-container\">" >> "$REPORT_FILE"
        for log_btn in "${FOUND_LOGS[@]}"; do
            echo "      ${log_btn}" >> "$REPORT_FILE"
        done
        echo "    </div>" >> "$REPORT_FILE"
    fi
done

cat <<EOF >> "$REPORT_FILE"
</body>
</html>
EOF

# Hand file ownership back to the user who invoked pkexec/sudo
if [ -n "${PKEXEC_UID:-}" ]; then
    REAL_USER=$(id -nu "$PKEXEC_UID")
    REAL_GROUP=$(id -ng "$PKEXEC_UID")
    chown -R "$REAL_USER:$REAL_GROUP" "$OUTPUT_DIR"
elif [ -n "${SUDO_USER:-}" ]; then
    chown -R "$SUDO_USER:$SUDO_USER" "$OUTPUT_DIR"
fi

echo "==> Report successfully generated at: ${REPORT_FILE}"
Hwprobe Yad

Code: Select all

#!/usr/bin/env bash
#
# YAD GUI Viewer with Inline Positional Column Action Handlers

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUTPUT_DIR="${SCRIPT_DIR}/hw_probe_local"

if [ ! -d "$OUTPUT_DIR" ]; then
    echo "Error: Directory ${OUTPUT_DIR} does not exist. Run Hw-Probe_offline.sh first."
    exit 1
fi

HW_INFO_DIR=$(find "$OUTPUT_DIR" -type d -name "hw.info" | head -n1 || true)
[ -z "$HW_INFO_DIR" ] && HW_INFO_DIR="$OUTPUT_DIR"

OS_VAL=$(cat "$HW_INFO_DIR/os" 2>/dev/null || echo "Linux")
ARCH_VAL=$(uname -m 2>/dev/null || echo "x86_64")
KERNEL_VAL=$(cat "$HW_INFO_DIR/kernel" 2>/dev/null || uname -r)
VENDOR_VAL=$(cat "$HW_INFO_DIR/sys_vendor" 2>/dev/null || cat "$HW_INFO_DIR/dmi/sys_vendor" 2>/dev/null || echo "Generic")
MODEL_VAL=$(cat "$HW_INFO_DIR/product_name" 2>/dev/null || cat "$HW_INFO_DIR/dmi/product_name" 2>/dev/null || echo "System")
YEAR_VAL=$(cat "$HW_INFO_DIR/product_year" 2>/dev/null || echo "N/A")
HWID_VAL=$(cat "$HW_INFO_DIR/probe.id" 2>/dev/null || echo "Offline")
TYPE_VAL=$(cat "$HW_INFO_DIR/chassis_type" 2>/dev/null || echo "Desktop/Laptop")
DE_VAL=$(cat "$HW_INFO_DIR/desktop" 2>/dev/null || echo "${DESKTOP_SESSION:-${XDG_CURRENT_DESKTOP:-Unknown}}")

# XML Escaping for Pango
xml_escape() {
    sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g; s/"/\&quot;/g; s/'\''/\&apos;/g' <<< "$1"
}

# Log Categorization
get_log_category() {
    local fname
    fname=$(echo "$1" | tr '[:upper:]' '[:lower:]')
    case "$fname" in
        *hwinfo*|*devices*|*lspci*|*lsusb*|*lshw*|*lscpu*|*lsblk*|*lsscsi*|*dmidecode*|*dmi*|*pci*|*usb*|*cpu*|*bios*|*edid*|*input*)
            echo "Hardware & Devices" ;;
        *nmcli*|*iwconfig*|*ifconfig*|*ip*|*route*|*net*|*wpa*|*fstab*|*mount*|*smartctl*|*hdparm*|*disk*|*nvme*)
            echo "Network & Storage" ;;
        *dmesg*|*uname*|*uptime*|*modules*|*lsmod*|*sysctl*|*cmdline*|*hostname*|*os*|*kernel*|*systemd*)
            echo "System & Kernel" ;;
        *xorg*|*wayland*|*glxinfo*|*vulkan*|*drm*|*display*|*gpu*)
            echo "Graphics & Display" ;;
        *alsa*|*sound*|*audio*|*pulse*|*pipewire*|*amixer*|*aplay*)
            echo "Audio & Sound" ;;
        *)
            echo "Other Logs" ;;
    esac
}

# Driver Module Path Resolver
resolve_driver_path() {
    local drv="$1"
    if [ -z "$drv" ] || [ "$drv" = "-" ]; then
        echo "-"
        return
    fi
    
    local mod_path=""
    mod_path=$(modinfo -n "$drv" 2>/dev/null || true)
    if [ -n "$mod_path" ] && [[ "$mod_path" != "(builtin)" ]] && [ -f "$mod_path" ]; then
        echo "$mod_path"
        return
    fi

    mod_path=$(modprobe --show-depends "$drv" 2>/dev/null | awk '/insmod/ {print $2}' | tail -n1 || true)
    if [ -n "$mod_path" ] && [ -f "$mod_path" ]; then
        echo "$mod_path"
        return
    fi

    local kver
    kver=$(uname -r)
    mod_path=$(find "/lib/modules/$kver" -type f \( -name "${drv}.ko" -o -name "${drv}.ko.xz" -o -name "${drv}.ko.zst" -o -name "${drv}.ko.gz" \) 2>/dev/null | head -n1 || true)
    if [ -n "$mod_path" ]; then
        echo "$mod_path"
        return
    fi

    if [ -d "/sys/module/$drv" ]; then
        echo "/sys/module/$drv"
        return
    fi

    echo "builtin / $drv"
}

GRID_DATA=$(mktemp)
LOG_TEMP=$(mktemp)
LOG_DATA=$(mktemp)

trap 'rm -f "$GRID_DATA" "$LOG_TEMP" "$LOG_DATA"' EXIT

DEVICES_FILE=$(find "$OUTPUT_DIR" -type f -name "devices" | head -n 1 || true)

# Process Devices
if [ -n "$DEVICES_FILE" ] && [ -f "$DEVICES_FILE" ]; then
    while IFS=';' read -r bus_id_class vendor_id status_val type_val driver_val vendor_val device_val company_val rest || [ -n "$bus_id_class" ]; do
        [[ "$bus_id_class" =~ ^# ]] && continue
        [ -z "$bus_id_class" ] && continue

        status_val=${status_val:-detected}
        type_val=${type_val:--}
        driver_val=${driver_val:--}
        vendor_val=${vendor_val:--}
        device_val=${device_val:--}

        bus_esc=$(xml_escape "$bus_id_class")
        type_esc=$(xml_escape "$type_val")
        driver_esc=$(xml_escape "$driver_val")
        vendor_esc=$(xml_escape "$vendor_val")
        device_esc=$(xml_escape "$device_val")

        bus_id="<span foreground=\"#61afef\" font_family=\"monospace\"><b>${bus_esc}</b></span>"
        
        if [ "$status_val" = "works" ]; then
            st="<span foreground=\"#4caf50\"><b>works</b></span>"
        elif [ "$status_val" = "detected" ]; then
            st="<span foreground=\"#ff9800\"><b>detected</b></span>"
        else
            st="<span foreground=\"#f44336\"><b>$(xml_escape "$status_val")</b></span>"
        fi

        drv_f="<span foreground=\"#ce9178\" font_family=\"monospace\">${driver_esc}</span>"
        v_f="<span foreground=\"#ffffff\"><b>${vendor_esc}</b></span>"
        
        drv_path=$(resolve_driver_path "$driver_val")
        path_esc=$(xml_escape "$drv_path")
        path_f="<span foreground=\"#98c379\" font_family=\"monospace\">${path_esc}</span>"

        printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n" "$bus_id" "$st" "$type_esc" "$drv_f" "$v_f" "$device_esc" "$path_f" "$drv_path" >> "$GRID_DATA"
    done < "$DEVICES_FILE"
fi

# Process Logs
find "$HW_INFO_DIR" -type f ! -name "*.txz" ! -name "*.gz" | while read -r f; do
    if file "$f" | grep -q "text"; then
        REL_NAME="${f#$HW_INFO_DIR/}"
        CAT=$(get_log_category "$REL_NAME")
        printf "%s|%s|%s\n" "$CAT" "$REL_NAME" "$f" >> "$LOG_TEMP"
    fi
done

sort -t'|' -k1,1 -k2,2 "$LOG_TEMP" | while IFS='|' read -r CAT REL_NAME f; do
    CAT_ESC=$(xml_escape "$CAT")
    REL_ESC=$(xml_escape "$REL_NAME")

    CAT_FMT="<span foreground=\"#4599df\"><b>${CAT_ESC}</b></span>"
    LOG_FMT="<span foreground=\"#61afef\" font_family=\"monospace\"><b>${REL_ESC}</b></span>"
    
    printf "%s\n%s\n%s\n" "$CAT_FMT" "$LOG_FMT" "$f" >> "$LOG_DATA"
done

KEY=$RANDOM

# Tab 1: System Info
yad --plug=$KEY --tabnum=1 --form \
    --field="System:":RO "$OS_VAL" \
    --field="Arch:":RO "$ARCH_VAL" \
    --field="Kernel:":RO "$KERNEL_VAL" \
    --field="Vendor:":RO "$VENDOR_VAL" \
    --field="Model:":RO "$MODEL_VAL" \
    --field="Year:":RO "$YEAR_VAL" \
    --field="HWid:":RO "$HWID_VAL" \
    --field="Type:":RO "$TYPE_VAL" \
    --field="DE:":RO "$DE_VAL" --columns=3 &

# Tab 2: Devices Table (Checks nemo first, falls back to xdg-open/thunar)
yad --plug=$KEY --tabnum=2 --list \
    --markup \
    --column="BUS ID/Class" \
    --column="Status" \
    --column="Type" \
    --column="Driver" \
    --column="Vendor" \
    --column="Device" \
    --column="Driver Path (.ko)" \
    --column="Raw Path":HD \
    --dclick-action='bash -c '\''
        target="${8#builtin / }"
        if [ -f "$target" ]; then target=$(dirname "$target"); fi
        if [ -d "$target" ]; then
            nemo "$target" 2>/dev/null || xdg-open "$target" 2>/dev/null || thunar "$target" 2>/dev/null || pcmanfm "$target" 2>/dev/null
        fi
    '\'' _ %s' \
    --grid-lines=both < "$GRID_DATA" &

# Tab 3: Sorted Categorized Logs ($3 maps to 3rd column: Full File Path)
yad --plug=$KEY --tabnum=3 --list \
    --markup \
    --column="Category" \
    --column="Log File" \
    --column="Full Path":HD \
    --dclick-action='bash -c '\''
        file="$3"
        if [ -f "$file" ]; then
            yad --text-info --title="Log View: $(basename "$file")" --filename="$file" --width=1000 --height=680 --fontname="Monospace 11" --button="Close:0"
        fi
    '\'' _ %s' \
    --grid-lines=both < "$LOG_DATA" &

# Master Notebook Window
yad --notebook --key=$KEY \
    --tab="System Overview" \
    --tab="Devices Table" \
    --tab="Logs" \
    --title="Offline Hardware Probe - ${VENDOR_VAL} ${MODEL_VAL}" \
    --width=1200 --height=720 \
    --button="Open HTML Report:bash -c 'xdg-open \"${SCRIPT_DIR}/hardware_report.html\"'" \
    --button="Close:0"