4325590686
Includes: init (PID 1), hiperiso-lib.sh, qemu_launch.sh, hw_collect.sh, kvm_check.sh, fallback_boot.sh, log_flush.sh, conf_replace.sh, make_floppy.sh. 13-phase boot timing, 18 QEMU HMP commands, network pcap capture.
507 lines
22 KiB
Bash
Executable File
507 lines
22 KiB
Bash
Executable File
#!/bin/sh
|
|
# ============================================================
|
|
# hw_collect.sh -- Hardware inventory collector for hiperiso
|
|
#
|
|
# Collects comprehensive hardware data across three phases:
|
|
#
|
|
# hw_collect.sh pre Before QEMU: host /proc, /sys, ACPI,
|
|
# SMBIOS, KVM params, USB, EFI
|
|
# hw_collect.sh monitor Background: send HMP commands to QEMU
|
|
# via FIFO pipe chardev (18 commands)
|
|
# hw_collect.sh post After QEMU: parse raw dump, generate
|
|
# JSON summaries, extract crash data
|
|
#
|
|
# Output directory: ${LOG_DIR}/hw/
|
|
#
|
|
# Host files (always present if pre-phase ran):
|
|
# host_cpuinfo.txt /proc/cpuinfo
|
|
# host_meminfo.txt /proc/meminfo
|
|
# host_interrupts.txt /proc/interrupts
|
|
# host_iomem.txt /proc/iomem (physical memory map)
|
|
# host_ioports.txt /proc/ioports
|
|
# host_cmdline.txt /proc/cmdline
|
|
# host_pci_devices.txt /proc/bus/pci/devices
|
|
# host_cpu_cache.txt CPU cache topology from sysfs
|
|
# host_numa.txt NUMA node topology
|
|
# host_iommu.txt IOMMU groups (VT-d/AMD-Vi)
|
|
# host_kvm.txt /dev/kvm presence
|
|
# host_block.txt Block device info
|
|
# host_dmesg.txt Host kernel boot messages
|
|
# host_version.txt /proc/version
|
|
# host_diskstats.txt /proc/diskstats
|
|
# host_usb.txt USB device tree from sysfs
|
|
# host_dmi.txt DMI/SMBIOS identifiers from sysfs
|
|
# acpi/ Host ACPI tables (binary .aml files)
|
|
# smbios/ Host DMI/SMBIOS raw tables
|
|
# kvm_caps.json KVM capabilities (module params)
|
|
#
|
|
# QEMU files (present if QEMU launched and ran >= 3 seconds):
|
|
# qemu_version.txt QEMU version string
|
|
# qemu_qtree.txt Full QEMU device tree
|
|
# qemu_pci.txt PCI device list as seen by guest
|
|
# qemu_memmap.txt Guest memory map (mtree)
|
|
# qemu_memmap_flat.txt Flat memory map (mtree -f)
|
|
# qemu_cpuid.txt CPUID leaves exposed to guest
|
|
# qemu_chardev.txt QEMU character devices
|
|
# qemu_block.txt QEMU block devices
|
|
# qemu_net.txt QEMU network devices
|
|
# qemu_ioapic.txt IO-APIC interrupt routing
|
|
# qemu_lapic.txt Local APIC state
|
|
# qemu_registers.txt CPU register snapshot
|
|
# qemu_tlb.txt TLB state (TCG only)
|
|
# qemu_numa.txt Guest NUMA topology
|
|
# qemu_hpet.txt HPET timer state
|
|
# qemu_irq.txt IRQ statistics
|
|
# qemu_qomtree.txt QOM object hierarchy
|
|
# qemu_smbios.txt SMBIOS table (if QEMU supports it)
|
|
# pci_summary.json Structured PCI device list
|
|
# ============================================================
|
|
|
|
. /hiperiso-lib.sh
|
|
|
|
LOG_DIR="${LOG_DIR:?hw_collect: LOG_DIR not set}"
|
|
HW_DIR="${LOG_DIR}/hw"
|
|
MON_IN="/tmp/hw_mon.in"
|
|
MON_OUT="/tmp/hw_mon.out"
|
|
|
|
mkdir -p "$HW_DIR"
|
|
|
|
# ── Mode: pre ────────────────────────────────────────────────
|
|
hw_collect_pre() {
|
|
hiperiso_log "hw_collect: collecting host hardware inventory..."
|
|
|
|
# ── /proc snapshots ──────────────────────────────────────
|
|
cat /proc/cpuinfo > "$HW_DIR/host_cpuinfo.txt" 2>/dev/null
|
|
cat /proc/meminfo > "$HW_DIR/host_meminfo.txt" 2>/dev/null
|
|
cat /proc/version > "$HW_DIR/host_version.txt" 2>/dev/null
|
|
cat /proc/diskstats > "$HW_DIR/host_diskstats.txt" 2>/dev/null
|
|
|
|
[ -f /proc/interrupts ] && cat /proc/interrupts > "$HW_DIR/host_interrupts.txt" 2>/dev/null
|
|
[ -f /proc/iomem ] && cat /proc/iomem > "$HW_DIR/host_iomem.txt" 2>/dev/null
|
|
[ -f /proc/ioports ] && cat /proc/ioports > "$HW_DIR/host_ioports.txt" 2>/dev/null
|
|
[ -f /proc/cmdline ] && cat /proc/cmdline > "$HW_DIR/host_cmdline.txt" 2>/dev/null
|
|
[ -f /proc/bus/pci/devices ] && cat /proc/bus/pci/devices > "$HW_DIR/host_pci_devices.txt" 2>/dev/null
|
|
|
|
# ── CPU cache topology ───────────────────────────────────
|
|
{
|
|
printf '=== CPU Cache Topology ===\n'
|
|
for _idx in /sys/devices/system/cpu/cpu*/cache/index*/; do
|
|
[ -d "$_idx" ] || continue
|
|
_level=$(cat "${_idx}level" 2>/dev/null)
|
|
_type=$(cat "${_idx}type" 2>/dev/null)
|
|
_size=$(cat "${_idx}size" 2>/dev/null)
|
|
_shared=$(cat "${_idx}shared_cpu_list" 2>/dev/null)
|
|
printf 'cpu=%s level=%s type=%s size=%s shared=%s\n' \
|
|
"$(printf '%s' "$_idx" | sed 's|.*/cpu\(cpu[0-9]*\)/.*|\1|')" \
|
|
"$_level" "$_type" "$_size" "$_shared"
|
|
done
|
|
} > "$HW_DIR/host_cpu_cache.txt" 2>/dev/null
|
|
|
|
# ── CPU topology (thread/core/socket IDs) ────────────────
|
|
{
|
|
printf '=== CPU Topology ===\n'
|
|
for _cpu in /sys/devices/system/cpu/cpu[0-9]*; do
|
|
[ -d "$_cpu" ] || continue
|
|
_name=$(basename "$_cpu")
|
|
_core=$(cat "${_cpu}/topology/core_id" 2>/dev/null)
|
|
_sock=$(cat "${_cpu}/topology/physical_package_id" 2>/dev/null)
|
|
_threads=$(cat "${_cpu}/topology/thread_siblings_list" 2>/dev/null)
|
|
printf '%s: core=%s socket=%s siblings=%s\n' \
|
|
"$_name" "${_core:-?}" "${_sock:-?}" "${_threads:-?}"
|
|
done
|
|
} > "$HW_DIR/host_cpu_topology.txt" 2>/dev/null
|
|
|
|
# ── NUMA topology ────────────────────────────────────────
|
|
if [ -d /sys/devices/system/node ]; then
|
|
{
|
|
printf '=== NUMA Topology ===\n'
|
|
for _node in /sys/devices/system/node/node[0-9]*; do
|
|
[ -d "$_node" ] || continue
|
|
_name=$(basename "$_node")
|
|
_cpus=$(cat "${_node}/cpulist" 2>/dev/null)
|
|
printf '%s: cpus=%s\n' "$_name" "$_cpus"
|
|
done
|
|
} > "$HW_DIR/host_numa.txt" 2>/dev/null
|
|
fi
|
|
|
|
# ── IOMMU groups (VT-d / AMD-Vi) ─────────────────────────
|
|
if [ -d /sys/kernel/iommu_groups ]; then
|
|
{
|
|
printf '=== IOMMU Groups ===\n'
|
|
for _grp in /sys/kernel/iommu_groups/[0-9]*; do
|
|
[ -d "$_grp" ] || continue
|
|
_gid=$(basename "$_grp")
|
|
printf 'group %s:\n' "$_gid"
|
|
for _dev in "$_grp"/devices/*; do
|
|
[ -e "$_dev" ] || continue
|
|
printf ' %s\n' "$(basename "$_dev")"
|
|
done
|
|
done
|
|
} > "$HW_DIR/host_iommu.txt" 2>/dev/null
|
|
fi
|
|
|
|
# ── KVM presence ─────────────────────────────────────────
|
|
if [ -e /dev/kvm ]; then
|
|
{
|
|
printf '=== KVM Device ===\n'
|
|
ls -la /dev/kvm 2>/dev/null
|
|
} > "$HW_DIR/host_kvm.txt" 2>/dev/null
|
|
fi
|
|
|
|
# ── KVM capabilities (module parameters) ─────────────────
|
|
_kvm_json="$HW_DIR/kvm_caps.json"
|
|
{
|
|
printf '{\n'
|
|
printf ' "kvm_present": %s,\n' $([ -e /dev/kvm ] && echo true || echo false)
|
|
|
|
# Core KVM parameters
|
|
_first=1
|
|
printf ' "kvm_core": {'
|
|
if [ -d /sys/module/kvm/parameters ]; then
|
|
for _p in /sys/module/kvm/parameters/*; do
|
|
[ -f "$_p" ] || continue
|
|
_pname=$(basename "$_p")
|
|
_pval=$(cat "$_p" 2>/dev/null)
|
|
if [ "$_first" -eq 1 ]; then _first=0; else printf ','; fi
|
|
printf '\n "%s": "%s"' "$_pname" "$_pval"
|
|
done
|
|
fi
|
|
[ "$_first" -eq 0 ] && printf '\n '
|
|
printf '},\n'
|
|
|
|
# Intel VT-x parameters
|
|
_first=1
|
|
printf ' "kvm_intel": {'
|
|
if [ -d /sys/module/kvm_intel/parameters ]; then
|
|
for _p in /sys/module/kvm_intel/parameters/*; do
|
|
[ -f "$_p" ] || continue
|
|
_pname=$(basename "$_p")
|
|
_pval=$(cat "$_p" 2>/dev/null)
|
|
if [ "$_first" -eq 1 ]; then _first=0; else printf ','; fi
|
|
printf '\n "%s": "%s"' "$_pname" "$_pval"
|
|
done
|
|
fi
|
|
[ "$_first" -eq 0 ] && printf '\n '
|
|
printf '},\n'
|
|
|
|
# AMD-V parameters
|
|
_first=1
|
|
printf ' "kvm_amd": {'
|
|
if [ -d /sys/module/kvm_amd/parameters ]; then
|
|
for _p in /sys/module/kvm_amd/parameters/*; do
|
|
[ -f "$_p" ] || continue
|
|
_pname=$(basename "$_p")
|
|
_pval=$(cat "$_p" 2>/dev/null)
|
|
if [ "$_first" -eq 1 ]; then _first=0; else printf ','; fi
|
|
printf '\n "%s": "%s"' "$_pname" "$_pval"
|
|
done
|
|
fi
|
|
[ "$_first" -eq 0 ] && printf '\n '
|
|
printf '}\n'
|
|
printf '}\n'
|
|
} > "$_kvm_json" 2>/dev/null
|
|
|
|
# ── Block devices ────────────────────────────────────────
|
|
{
|
|
printf '=== Block Devices ===\n'
|
|
for _blk in /sys/block/sd* /sys/block/nvme* /sys/block/sr* /sys/block/mmcblk*; do
|
|
[ -d "$_blk" ] || continue
|
|
_name=$(basename "$_blk")
|
|
_size=$(cat "${_blk}/size" 2>/dev/null)
|
|
_rm=$(cat "${_blk}/removable" 2>/dev/null)
|
|
_ro=$(cat "${_blk}/readonly" 2>/dev/null)
|
|
_model=$(cat "${_blk}/device/model" 2>/dev/null)
|
|
_vendor=$(cat "${_blk}/device/vendor" 2>/dev/null)
|
|
printf '%s: sectors=%s removable=%s readonly=%s model=%s vendor=%s\n' \
|
|
"$_name" "${_size:-?}" "${_rm:-?}" "${_ro:-?}" \
|
|
"$(printf '%s' "$_model" | tr -d ' ')" \
|
|
"$(printf '%s' "$_vendor" | tr -d ' ')"
|
|
done
|
|
} > "$HW_DIR/host_block.txt" 2>/dev/null
|
|
|
|
# ── USB device tree ──────────────────────────────────────
|
|
{
|
|
printf '=== USB Devices ===\n'
|
|
for _dev in /sys/bus/usb/devices/*; do
|
|
[ -d "$_dev" ] || continue
|
|
_name=$(basename "$_dev")
|
|
_vid=$(cat "${_dev}/idVendor" 2>/dev/null)
|
|
_pid=$(cat "${_dev}/idProduct" 2>/dev/null)
|
|
_mfr=$(cat "${_dev}/manufacturer" 2>/dev/null)
|
|
_prod=$(cat "${_dev}/product" 2>/dev/null)
|
|
_speed=$(cat "${_dev}/speed" 2>/dev/null)
|
|
[ -n "$_vid" ] || continue
|
|
printf '%s: %s:%s speed=%s mfr=%s product=%s\n' \
|
|
"$_name" "$_vid" "$_pid" "${_speed:-?}" \
|
|
"$(printf '%s' "$_mfr" | tr -d '\n')" \
|
|
"$(printf '%s' "$_prod" | tr -d '\n')"
|
|
done
|
|
} > "$HW_DIR/host_usb.txt" 2>/dev/null
|
|
|
|
# ── ACPI tables (host firmware) ──────────────────────────
|
|
if [ -d /sys/firmware/acpi/tables ]; then
|
|
mkdir -p "$HW_DIR/acpi"
|
|
cp -r /sys/firmware/acpi/tables/* "$HW_DIR/acpi/" 2>/dev/null
|
|
{
|
|
printf '=== ACPI Tables ===\n'
|
|
for _t in /sys/firmware/acpi/tables/[A-Z]*; do
|
|
[ -f "$_t" ] || continue
|
|
_sig=$(basename "$_t")
|
|
_size=$(wc -c < "$_t" 2>/dev/null)
|
|
printf '%s: %s bytes\n' "$_sig" "${_size:-?}"
|
|
done
|
|
} > "$HW_DIR/acpi/_summary.txt" 2>/dev/null
|
|
fi
|
|
|
|
# ── DMI / SMBIOS (host firmware) ─────────────────────────
|
|
if [ -d /sys/firmware/dmi/tables ]; then
|
|
mkdir -p "$HW_DIR/smbios"
|
|
cp /sys/firmware/dmi/tables/* "$HW_DIR/smbios/" 2>/dev/null
|
|
fi
|
|
if [ -d /sys/class/dmi/id ]; then
|
|
{
|
|
printf '=== DMI Identifiers ===\n'
|
|
for _f in /sys/class/dmi/id/*; do
|
|
[ -f "$_f" ] || continue
|
|
_key=$(basename "$_f")
|
|
_val=$(cat "$_f" 2>/dev/null)
|
|
[ -n "$_val" ] && printf '%s: %s\n' "$_key" "$_val"
|
|
done
|
|
} > "$HW_DIR/host_dmi.txt" 2>/dev/null
|
|
fi
|
|
|
|
# ── EFI firmware info (if UEFI boot) ─────────────────────
|
|
if [ -d /sys/firmware/efi ]; then
|
|
{
|
|
printf '=== EFI Firmware ===\n'
|
|
cat /sys/firmware/efi/fw_platform_size 2>/dev/null
|
|
printf 'Runtime services: '
|
|
ls /sys/firmware/efi/runtime 2>/dev/null || printf '(not exported)\n'
|
|
printf 'EFI variables:\n'
|
|
ls /sys/firmware/efi/efivars/ 2>/dev/null | head -20
|
|
} > "$HW_DIR/host_efi.txt" 2>/dev/null
|
|
fi
|
|
|
|
# ── Kernel config (if available) ─────────────────────────
|
|
if [ -f /proc/config.gz ]; then
|
|
cp /proc/config.gz "$HW_DIR/host_kernel_config.gz" 2>/dev/null
|
|
fi
|
|
|
|
# ── DMESG (host kernel messages) ─────────────────────────
|
|
if command -v dmesg >/dev/null 2>&1; then
|
|
dmesg > "$HW_DIR/host_dmesg.txt" 2>/dev/null
|
|
fi
|
|
|
|
_count=$(ls "$HW_DIR"/host_*.txt "$HW_DIR"/*.json 2>/dev/null | wc -l)
|
|
hiperiso_log "hw_collect: host inventory complete ($_count files)"
|
|
}
|
|
|
|
# ── Mode: monitor ────────────────────────────────────────────
|
|
hw_setup_monitor_fifo() {
|
|
mkfifo "$MON_IN" "$MON_OUT" 2>/dev/null
|
|
|
|
cat "$MON_OUT" > "${HW_DIR}/qemu_monitor_raw.txt" 2>/dev/null &
|
|
MON_READER_PID=$!
|
|
printf '%s\n' "$MON_READER_PID" > /tmp/hw_mon_reader.pid
|
|
|
|
# Writer: sends HMP commands via echo-delimited markers.
|
|
# QEMU pipe mode does not echo input, so we inject markers
|
|
# using QEMU's HMP 'echo' command to enable section splitting.
|
|
(
|
|
sleep 3
|
|
|
|
# ── P0: Core inventory ───────────────────────────────
|
|
printf 'echo ===SECTION===version\n'; sleep 0.1
|
|
printf 'info version\n'; sleep 0.3
|
|
printf 'echo ===SECTION===qtree\n'; sleep 0.1
|
|
printf 'info qtree\n'; sleep 0.5
|
|
printf 'echo ===SECTION===pci\n'; sleep 0.1
|
|
printf 'info pci\n'; sleep 0.3
|
|
|
|
# ── P1: CPU + memory map ─────────────────────────────
|
|
printf 'echo ===SECTION===cpuid\n'; sleep 0.1
|
|
printf 'info cpuid\n'; sleep 0.3
|
|
printf 'echo ===SECTION===memmap\n'; sleep 0.1
|
|
printf 'info mtree\n'; sleep 0.3
|
|
printf 'echo ===SECTION===memmap_flat\n'; sleep 0.1
|
|
printf 'info mtree -f\n'; sleep 0.3
|
|
|
|
# ── P2: SMBIOS + registers + TLB ─────────────────────
|
|
printf 'echo ===SECTION===smbios\n'; sleep 0.1
|
|
printf 'info smbios\n'; sleep 0.3
|
|
printf 'echo ===SECTION===registers\n'; sleep 0.1
|
|
printf 'info registers\n'; sleep 0.3
|
|
printf 'echo ===SECTION===tlb\n'; sleep 0.1
|
|
printf 'info tlb\n'; sleep 0.3
|
|
|
|
# ── P3: Interrupt routing + KVM caps ─────────────────
|
|
printf 'echo ===SECTION===ioapic\n'; sleep 0.1
|
|
printf 'info ioapic\n'; sleep 0.3
|
|
printf 'echo ===SECTION===lapic\n'; sleep 0.1
|
|
printf 'info lapic\n'; sleep 0.3
|
|
printf 'echo ===SECTION===irq\n'; sleep 0.1
|
|
printf 'info irq\n'; sleep 0.3
|
|
|
|
# ── Additional: topology + timers ────────────────────
|
|
printf 'echo ===SECTION===numa\n'; sleep 0.1
|
|
printf 'info numa\n'; sleep 0.3
|
|
printf 'echo ===SECTION===hpet\n'; sleep 0.1
|
|
printf 'info hpet\n'; sleep 0.3
|
|
printf 'echo ===SECTION===qomtree\n'; sleep 0.1
|
|
printf 'info qom-tree\n'; sleep 0.3
|
|
|
|
# ── Device summaries ─────────────────────────────────
|
|
printf 'echo ===SECTION===chardev\n'; sleep 0.1
|
|
printf 'info chardev\n'; sleep 0.3
|
|
printf 'echo ===SECTION===block\n'; sleep 0.1
|
|
printf 'info block\n'; sleep 0.3
|
|
printf 'echo ===SECTION===net\n'; sleep 0.1
|
|
printf 'info networking\n'; sleep 0.3
|
|
) > "$MON_IN" 2>/dev/null &
|
|
MON_WRITER_PID=$!
|
|
printf '%s\n' "$MON_WRITER_PID" > /tmp/hw_mon_writer.pid
|
|
|
|
hiperiso_log "hw_collect: monitor FIFO reader (PID $MON_READER_PID)"
|
|
hiperiso_log "hw_collect: monitor FIFO writer (PID $MON_WRITER_PID)"
|
|
}
|
|
|
|
# ── Mode: post ───────────────────────────────────────────────
|
|
hw_collect_post() {
|
|
_raw="${HW_DIR}/qemu_monitor_raw.txt"
|
|
|
|
if [ ! -f "$_raw" ] || [ ! -s "$_raw" ]; then
|
|
hiperiso_log "hw_collect: no QEMU monitor data (raw file missing or empty)"
|
|
hw_cleanup_procs
|
|
return 1
|
|
fi
|
|
|
|
hiperiso_log "hw_collect: parsing QEMU monitor output..."
|
|
|
|
# Split raw dump into per-section files using echo markers
|
|
# injected by the writer. Each ===SECTION===xxx line triggers
|
|
# a section change; subsequent output goes to that file.
|
|
_awk_script='
|
|
BEGIN { section = "header"; }
|
|
/===SECTION===version/ { section = "version"; next; }
|
|
/===SECTION===qtree/ { section = "qtree"; next; }
|
|
/===SECTION===pci/ { section = "pci"; next; }
|
|
/===SECTION===cpuid/ { section = "cpuid"; next; }
|
|
/===SECTION===memmap_flat/ { section = "memmap_flat"; next; }
|
|
/===SECTION===memmap/ { section = "memmap"; next; }
|
|
/===SECTION===smbios/ { section = "smbios"; next; }
|
|
/===SECTION===registers/ { section = "registers"; next; }
|
|
/===SECTION===tlb/ { section = "tlb"; next; }
|
|
/===SECTION===ioapic/ { section = "ioapic"; next; }
|
|
/===SECTION===lapic/ { section = "lapic"; next; }
|
|
/===SECTION===irq/ { section = "irq"; next; }
|
|
/===SECTION===numa/ { section = "numa"; next; }
|
|
/===SECTION===hpet/ { section = "hpet"; next; }
|
|
/===SECTION===qomtree/ { section = "qomtree"; next; }
|
|
/===SECTION===chardev/ { section = "chardev"; next; }
|
|
/===SECTION===block/ { section = "block"; next; }
|
|
/===SECTION===net/ { section = "net"; next; }
|
|
{
|
|
if (section != "header")
|
|
print > "'"$HW_DIR"'/qemu_" section ".txt";
|
|
}
|
|
'
|
|
|
|
awk "$_awk_script" "$_raw" 2>/dev/null
|
|
|
|
for _f in \
|
|
qemu_version qemu_qtree qemu_pci qemu_cpuid \
|
|
qemu_memmap qemu_memmap_flat qemu_smbios \
|
|
qemu_registers qemu_tlb qemu_ioapic qemu_lapic \
|
|
qemu_irq qemu_numa qemu_hpet qemu_qomtree \
|
|
qemu_chardev qemu_block qemu_net; do
|
|
_fp="${HW_DIR}/${_f}.txt"
|
|
if [ -f "$_fp" ] && [ ! -s "$_fp" ]; then
|
|
rm -f "$_fp"
|
|
fi
|
|
done
|
|
|
|
# Generate PCI summary JSON from qemu_pci.txt
|
|
hw_gen_pci_json
|
|
|
|
_count=$(ls "$HW_DIR"/qemu_*.txt "$HW_DIR"/*.json 2>/dev/null | wc -l)
|
|
hiperiso_log "hw_collect: parsed $_count QEMU + JSON files"
|
|
|
|
hw_cleanup_procs
|
|
|
|
hiperiso_log "hw_collect: inventory files:"
|
|
ls -la "$HW_DIR"/ 2>/dev/null >> "${LOG_DIR}/env.txt"
|
|
}
|
|
|
|
# ── PCI summary JSON ─────────────────────────────────────────
|
|
# Parse qemu_pci.txt to extract structured PCI device data.
|
|
hw_gen_pci_json() {
|
|
_pci="${HW_DIR}/qemu_pci.txt"
|
|
_out="${HW_DIR}/pci_summary.json"
|
|
[ -f "$_pci" ] || return 0
|
|
|
|
{
|
|
printf '{\n'
|
|
printf ' "devices": [\n'
|
|
|
|
awk '
|
|
/^Bus / {
|
|
if (found) printf " },\n"
|
|
found = 1
|
|
bus = $2; gsub(/,/, "", bus)
|
|
dev = $4; gsub(/,/, "", dev)
|
|
fn = $6; gsub(/:/, "", fn)
|
|
printf " {\"bus\": %s, \"device\": %s, \"function\": %s", bus, dev, fn
|
|
}
|
|
/vendor_id = / {
|
|
gsub(/.*= /, "", $0)
|
|
printf ", \"vendor_id\": \"%s\"", $NF
|
|
}
|
|
/device_id = / {
|
|
gsub(/.*= /, "", $0)
|
|
printf ", \"device_id\": \"%s\"", $NF
|
|
}
|
|
/class = / {
|
|
gsub(/.*= /, "", $0)
|
|
printf ", \"class\": \"%s\"", $NF
|
|
}
|
|
/IRQ / {
|
|
_irq = $2; gsub(/\./, "", _irq)
|
|
printf ", \"irq\": \"%s\"", _irq
|
|
}
|
|
END { if (found) printf " }"; printf "\n" }
|
|
' "$_pci" 2>/dev/null
|
|
|
|
printf ' ]\n'
|
|
printf '}\n'
|
|
} > "$_out" 2>/dev/null
|
|
|
|
if [ ! -s "$_out" ]; then
|
|
rm -f "$_out"
|
|
fi
|
|
}
|
|
|
|
# ── Process cleanup ──────────────────────────────────────────
|
|
hw_cleanup_procs() {
|
|
rm -f "$MON_IN" "$MON_OUT" 2>/dev/null
|
|
for _pidfile in /tmp/hw_mon_reader.pid /tmp/hw_mon_writer.pid; do
|
|
if [ -f "$_pidfile" ]; then
|
|
_pid=$(cat "$_pidfile" 2>/dev/null)
|
|
if [ -n "$_pid" ] && kill -0 "$_pid" 2>/dev/null; then
|
|
kill "$_pid" 2>/dev/null
|
|
fi
|
|
rm -f "$_pidfile"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# ── Main ─────────────────────────────────────────────────────
|
|
case "${1:-}" in
|
|
pre) hw_collect_pre ;;
|
|
monitor) hw_setup_monitor_fifo ;;
|
|
post) hw_collect_post ;;
|
|
*)
|
|
printf 'Usage: hw_collect.sh {pre|monitor|post}\n' >&2
|
|
exit 1
|
|
;;
|
|
esac
|