From acc2d9330719ed8b4829693e659df696e214d59e Mon Sep 17 00:00:00 2001 From: vasilito Date: Tue, 30 Jun 2026 14:51:06 +0300 Subject: [PATCH] fix: PCI summary JSON parser to match real QEMU info pci output The awk patterns in hw_gen_pci_json() targeted a hypothetical output format that never matched QEMU's actual HMP 'info pci' response: - /^Bus / anchored to line start, but QEMU outputs ' Bus ' (2 leading spaces) - /vendor_id = / expected 'vendor_id = 0x8086', but QEMU prints 'PCI device 8086:2922' - /device_id = / expected separate line, but vendor:device are on the same line - /class = / expected 'class = 0x010601', but QEMU prints 'SATA controller:' or 'Class 0106:' - IRQ field expected 'IRQ 0.' but QEMU prints 'IRQ 5, pin A' Result: pci_summary.json was always invalid JSON with orphaned key-value pairs. Fix verified against QEMU source (pci-hmp-cmds.c:31-51) and tested with realistic 4-device output: all devices correctly parsed with bus/dev/fn, vendor_id, device_id, and IRQ fields. Found by: 5-agent parallel review (QA execution agent) --- host/initramfs/hw_collect.sh | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/host/initramfs/hw_collect.sh b/host/initramfs/hw_collect.sh index 7bd6580..d2689ca 100755 --- a/host/initramfs/hw_collect.sh +++ b/host/initramfs/hw_collect.sh @@ -444,29 +444,37 @@ hw_gen_pci_json() { printf ' "devices": [\n' awk ' - /^Bus / { + # Device header: " Bus 0, device 1, function 0:" + # (QEMU outputs 2 leading spaces — no ^ anchor) + /Bus .*device .*function/ { 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 + next } - /vendor_id = / { - gsub(/.*= /, "", $0) - printf ", \"vendor_id\": \"%s\"", $NF + # Vendor/device line: " SATA controller: PCI device 8086:2922" + # or: " Class 0106: PCI device 8086:2922" + /PCI device/ { + for (i = 1; i <= NF; i++) { + if (index($i, ":") > 0) { + split($i, vd, ":") + if (length(vd[1]) == 4 && length(vd[2]) == 4 && \ + vd[1] ~ /^[0-9a-fA-F]+$/ && vd[2] ~ /^[0-9a-fA-F]+$/) { + printf ", \"vendor_id\": \"0x%s\", \"device_id\": \"0x%s\"", vd[1], vd[2] + break + } + } + } + next } - /device_id = / { - gsub(/.*= /, "", $0) - printf ", \"device_id\": \"%s\"", $NF - } - /class = / { - gsub(/.*= /, "", $0) - printf ", \"class\": \"%s\"", $NF - } - /IRQ / { - _irq = $2; gsub(/\./, "", _irq) + # IRQ line: " IRQ 5, pin A" + /IRQ [0-9]/ { + _irq = $2; gsub(/,/, "", _irq) printf ", \"irq\": \"%s\"", _irq + next } END { if (found) printf " }"; printf "\n" } ' "$_pci" 2>/dev/null