#!/bin/sh
# sg-bugreport-info [FILE]: the "System" part of a Report a problem report --
# what a tester's machine is, in plain text, for sg-bugreport.exe. Nothing is
# sent anywhere: the tester sees all of it in the report window first.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2026 David Hamner and the Stained Glass OS contributors
LC_ALL=C; export LC_ALL
# sg-bugreport-info [FILE]: to FILE instead of standard output
[ $# -ge 1 ] && exec >"$1"

line() { printf '%-14s %s\n' "$1:" "$2"; }
first() { head -n1 "$1" 2>/dev/null | tr -d '\n'; }
# firmware's placeholders say nothing
dmi() { v=$(first "/sys/class/dmi/id/$1"); case "$v" in "Default string"|"To be filled by O.E.M."|"System Product Name"|"Not Specified"|"None") v= ;; esac; printf %s "$v"; }

# shellcheck disable=SC1091  # the running system's, read where it is
. /etc/os-release 2>/dev/null
line "System" "${PRETTY_NAME:-unknown}${IMAGE_VERSION:+ (image $IMAGE_VERSION)}"
[ -r /etc/stained-glass/build-id ] && line "Build" "$(first /etc/stained-glass/build-id)"
if grep -qs 'boot=live\|sg.live' /proc/cmdline || [ -d /run/live ]; then line "Running" "live medium"; else line "Running" "installed"; fi
line "Kernel" "$(uname -r) $(uname -m)"
vendor=$(dmi sys_vendor); product=$(dmi product_name); version=$(dmi product_version)
[ -n "$product" ] || product=$(dmi board_name)
line "Machine" "$vendor $product${version:+ ($version)}"
line "CPU" "$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//') x$(grep -c '^processor' /proc/cpuinfo)"
line "Memory" "$(awk '/MemTotal/ {t=$2} /MemAvailable/ {a=$2} END {printf "%.1f GB, %.1f GB free", t/1048576, a/1048576}' /proc/meminfo)"
line "Disk" "$(df -h / 2>/dev/null | awk 'NR==2 {print $4 " free of " $2}')"
if command -v lspci >/dev/null 2>&1; then
    lspci -nn 2>/dev/null | grep -Ei 'vga|3d controller|display controller' | cut -d' ' -f2- | while read -r g; do line "Graphics" "$g"; done
    lspci -nn 2>/dev/null | grep -Ei 'audio' | cut -d' ' -f2- | head -2 | while read -r g; do line "Audio" "$g"; done
    lspci -nn 2>/dev/null | grep -Ei 'network|ethernet' | cut -d' ' -f2- | head -3 | while read -r g; do line "Network" "$g"; done
fi
for c in /sys/class/drm/card*-*/status; do
    [ "$(cat "$c" 2>/dev/null)" = connected ] || continue
    d=${c%/status}; line "Display" "${d##*/card?-} $(head -n1 "$d/modes" 2>/dev/null) preferred"
done
if command -v wlr-randr >/dev/null 2>&1 && [ -n "${WAYLAND_DISPLAY:-}" ]; then
    wlr-randr 2>/dev/null | awk '/^[^ ]/ {o=$1} /current/ {print o " " $1 " @ " $3 " Hz (current)"}' | while read -r m; do line "Mode" "$m"; done
fi
line "Session" "${SG_DISPLAY_PATH:-${XDG_SESSION_TYPE:-unknown}} display, user $(id -un)$(id -Gn | grep -qw sudo && echo " (administrator)")"
line "Language" "${LANG:-unset}"
# USB devices: hardware problems (a label printer not found, a scanner) are
# often a missing udev rule or driver (David 2026-10-05, the DYMO 550). Each
# device's ids and names, the drivers its interfaces have, and its device
# node's mode and group -- which decide whether the session may open it. No
# serial numbers: they identify the machine. SG_SYSFS: another sysfs (the gate).
SYS=${SG_SYSFS:-/sys}
usb=""
for d in "$SYS"/bus/usb/devices/*; do
    [ -r "$d/idVendor" ] || continue
    case "${d##*/}" in usb*) continue ;; esac   # the root hubs
    vid=$(first "$d/idVendor"); pid=$(first "$d/idProduct")
    name=$(printf '%s %s' "$(first "$d/manufacturer")" "$(first "$d/product")" | tr -s ' ' | sed 's/^ *//; s/ *$//')
    drivers=$(for i in "$d"/"${d##*/}":*; do [ -e "$i/driver" ] && basename "$(readlink "$i/driver")"; done | sort -u | tr '\n' ' ' | sed 's/ $//')
    node=""
    bus=$(first "$d/busnum"); dev=$(first "$d/devnum")
    if [ -n "$bus" ] && [ -n "$dev" ]; then
        n=$(printf '%s/bus/usb/%03d/%03d' "${SG_DEVFS:-/dev}" "$bus" "$dev")
        # the mode says nothing of the session's own access (logind's uaccess
        # ACL): whether this user may open it, asked directly
        [ -e "$n" ] && node="$(stat -c '%A %U:%G' "$n" 2>/dev/null), $( [ -r "$n" ] && [ -w "$n" ] && echo "this user can open it" || echo "this user cannot open it")"
    fi
    usb="$usb$(printf '  %s:%s %s [%s]%s' "$vid" "$pid" "${name:-?}" "${drivers:-no driver}" "${node:+ $node}")
"
done
if [ -n "$usb" ]; then
    echo
    echo "USB devices (id, name, drivers, device node):"
    printf '%s' "$usb"
fi
for lp in "${SG_DEVFS:-/dev}"/usb/lp*; do
    [ -e "$lp" ] && line "USB printer" "${lp##*/} $(stat -c '%A %U:%G' "$lp" 2>/dev/null)"
done
if command -v lpstat >/dev/null 2>&1; then
    # the queues and their devices, a USB one's serial left out
    lpstat -v 2>/dev/null | sed 's/[?&]serial=[^ &]*//' | while read -r q; do line "Printer" "$q"; done
fi
# Sound devices (David 2026-10-07: a microphone that works but is not in
# Settings, dictation microphones -- a Nuance PowerMic, a SpeechMike -- not
# found): what the kernel's sound cards are, and what PipeWire offers
if [ -r "${SG_PROCFS:-/proc}/asound/cards" ]; then
    echo
    echo "Sound cards (ALSA):"
    sed 's/^/  /' "${SG_PROCFS:-/proc}/asound/cards"
fi
if command -v pactl >/dev/null 2>&1; then
    echo
    echo "Sound devices (PipeWire: outputs, inputs, cards):"
    # descriptions, not names: a USB device's name carries its serial number
    for k in sinks sources cards; do
        timeout 5 pactl --format=json list "$k" 2>/dev/null | python3 -c '
import json, sys
kind = sys.argv[1]
try:
    devs = json.load(sys.stdin)
except ValueError:
    devs = []
for d in devs:
    p = d.get("properties") or {}
    if kind == "sources" and (p.get("device.class") == "monitor" or str(d.get("name", "")).endswith(".monitor")):
        continue
    desc = d.get("description") or p.get("device.description") or p.get("device.product.name") or "?"
    bus = p.get("device.bus") or ""
    print("  %s: %s%s" % (kind[:-1], desc, " (" + bus + ")" if bus else ""))
' "$k" 2>/dev/null
    done
fi
# Input devices: a dictation microphone's buttons, a pen, a touch screen --
# their names and handlers (the kernel's list; no serials)
if [ -r "${SG_PROCFS:-/proc}/bus/input/devices" ]; then
    echo
    echo "Input devices:"
    awk -F'"' '/^N: Name=/ { name = $2 } /^H: Handlers=/ { sub(/^H: Handlers=/, ""); printf "  %s [%s]\n", name, $0 }' \
        "${SG_PROCFS:-/proc}/bus/input/devices"
fi
echo
echo "Packages:"
dpkg-query -W -f '  ${Package} ${Version}\n' wine-sg sg-shell sg-session sg-compositor sg-image \
    'sg-wordpad' 'sg-notepad' mesa-vulkan-drivers libgl1-mesa-dri firmware-sof-signed linux-image-amd64 2>/dev/null | sort -u
command -v vulkaninfo >/dev/null 2>&1 && vulkaninfo --summary 2>/dev/null | grep -m3 'deviceName\|driverInfo' | sed 's/^ */  vulkan: /'
exit 0
