Skip to content

Instantly share code, notes, and snippets.

@AustinSaintAubin
Forked from r15ch13/iommu.sh
Last active May 17, 2025 21:55
Show Gist options
  • Select an option

  • Save AustinSaintAubin/16f930da0abd7cf1c6e1536e5eebb898 to your computer and use it in GitHub Desktop.

Select an option

Save AustinSaintAubin/16f930da0abd7cf1c6e1536e5eebb898 to your computer and use it in GitHub Desktop.

Revisions

  1. AustinSaintAubin revised this gist May 17, 2025. 1 changed file with 69 additions and 16 deletions.
    85 changes: 69 additions & 16 deletions iommu.sh
    Original file line number Diff line number Diff line change
    @@ -1,24 +1,77 @@
    #!/usr/bin/env bash
    # https://chatgpt.com/c/6828dc89-e524-800e-b978-05b3f27626c9

    # IOMMU and Device Enumeration Script
    # Description: Enumerates IOMMU groups and lists associated PCI and USB devices
    # in a neatly formatted, column-aligned table.
    # Usage: Run as root or with permissions to read /sys/kernel/iommu_groups,
    # and have lspci and lsusb available.
    # Output: Columns: IOMMU group, Device ID (vendor:device), Flags (e.g., reset support or USB),
    # Address or bus:device, Type (PCI/USB), Description.

    # Enable nullglob so patterns that match no files expand to empty
    shopt -s nullglob
    lastgroup=""
    for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    for d in $g/devices/*; do
    if [ "${g##*/}" != "$lastgroup" ]; then
    echo -en "Group ${g##*/}:\t"

    # Array to collect all output rows
    declare -a rows

    # Function to queue a row for later formatted output
    # queue_row() { rows+=("$1"); }
    queue_row() { rows+=("$(printf '%s\t[%s]\t%s\t%s\t%s' "${1}" "${2}" "${3}" "${4}" "${5}")"); }

    # Function queue_rowto print all queued rows with column alignment
    # print_all_rows() { printf '%s\n' "${rows[@]}" | column -ts $'\t'; }

    # Header
    rows+=("$(printf '%s\t%s\t%s\t%s\t%s\t%s' "IOMMU" "Device ID" "Flags" "Address" "Type" "Description")");
    rows+=("$(printf '%s\t%s\t%s\t%s\t%s\t%s' "--------" "-----------" "-----" "-------" "------------" "--------------------------------------------")");

    # Track the last processed IOMMU group ID to control header formatting
    last_group_id=""

    # Iterate over each IOMMU group directory, sorted numerically
    for iommu_group_dir in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do
    # Iterate over each PCI device in this IOMMU group
    for device_dir in "${iommu_group_dir}/devices/"*; do
    # Extract the current group ID from the directory name
    current_group_id="${iommu_group_dir##*/}"

    # Determine group column header for first device in the group
    if [[ "$current_group_id" != "$last_group_id" ]]; then
    group_col="Group ${current_group_id}"
    else
    echo -en "\t\t"
    group_col=" L $current_group_id"
    fi
    lastgroup=${g##*/}
    lspci -nms ${d##*/} | awk -F'"' '{printf "[%s:%s]", $4, $6}'
    if [[ -e "$d"/reset ]]; then echo -en " [R] "; else echo -en " "; fi

    lspci -mms ${d##*/} | awk -F'"' '{printf "%s %-40s %s\n", $1, $2, $6}'
    for u in ${d}/usb*/; do
    bus=$(cat "${u}/busnum")
    lsusb -s $bus: | \
    awk '{gsub(/:/,"",$4); printf "%s|%s %s %s %s|", $6, $1, $2, $3, $4; for(i=7;i<=NF;i++){printf "%s ", $i}; printf "\n"}' | \
    awk -F'|' '{printf "USB:\t\t[%s]\t\t %-40s %s\n", $1, $2, $3}'
    last_group_id="$current_group_id"

    # Gather PCI information
    vendor_device_id=$(lspci -nms "${device_dir##*/}" | awk -F'"' '{printf "%s:%s", $4, $6}')
    reset_flag=""
    [[ -e "${device_dir}/reset" ]] && reset_flag="[R]"
    pci_details=$(lspci -mms "${device_dir##*/}" | awk -F'"' '{printf "%s\t%s\t%s", $1, $2, $6}')

    # Queue the PCI row (tab-separated)
    # rows+=("${group_col} [${vendor_device_id}] ${reset_flag} ${pci_details}")
    # rows+=("$(printf '%s\t[%s]\t[%s]\t%s\t%s' "${group_col}" "${vendor_device_id}" "${reset_flag}" "${pci_details}")")
    queue_row "${group_col}" "${vendor_device_id}" "${reset_flag}" "${pci_details}"

    # Process any USB interfaces for this device
    for usb_dir in "${device_dir}/usb"*/; do
    bus_number=$(<"${usb_dir}/busnum")
    dev_number=$(<"${usb_dir}/devnum")
    group_col=" L $current_group_id"

    # Get the lsusb line and parse vendor:product ID and description
    usb_line=$(lsusb -s "${bus_number}:${dev_number}")
    usb_id=$(awk '{print $6}' <<< "$usb_line")
    usb_desc=${usb_line#* $usb_id }

    # Queue the USB row using printf to embed tabs correctly
    # rows+=("$(printf '\t[%s]\t[%s]\t%s\t%s' "$usb_id" "${bus_number}:${dev_number}" "U" "$usb_desc")")
    queue_row "$group_col" "$usb_id" "USB" "${bus_number}:${dev_number}" "$usb_desc"
    done
    done
    done

    # Print all collected rows with aligned columns
    printf '%s\n' "${rows[@]}" | column -ts $'\t';
  2. @r15ch13 r15ch13 revised this gist Jul 25, 2021. No changes.
  3. @r15ch13 r15ch13 revised this gist Jul 25, 2021. No changes.
  4. @r15ch13 r15ch13 revised this gist Jul 25, 2021. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions iommu.sh
    Original file line number Diff line number Diff line change
    @@ -4,12 +4,12 @@ shopt -s nullglob
    lastgroup=""
    for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    for d in $g/devices/*; do
    if [ "${g##*/}" != "$lastgroup" ]; then
    echo -en "Group ${g##*/}:\t"
    else
    echo -en "\t\t"
    fi
    lastgroup=${g##*/}
    if [ "${g##*/}" != "$lastgroup" ]; then
    echo -en "Group ${g##*/}:\t"
    else
    echo -en "\t\t"
    fi
    lastgroup=${g##*/}
    lspci -nms ${d##*/} | awk -F'"' '{printf "[%s:%s]", $4, $6}'
    if [[ -e "$d"/reset ]]; then echo -en " [R] "; else echo -en " "; fi

  5. @r15ch13 r15ch13 revised this gist Jul 24, 2021. 1 changed file with 14 additions and 4 deletions.
    18 changes: 14 additions & 4 deletions iommu.sh
    Original file line number Diff line number Diff line change
    @@ -1,14 +1,24 @@
    #!/usr/bin/env bash

    shopt -s nullglob
    lastgroup=""
    for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    for d in $g/devices/*; do
    if [ "${g##*/}" != "$lastgroup" ]; then
    echo -en "Group ${g##*/}:\t"
    if [[ -e "$d"/reset ]]; then echo -en "[RESET]"; fi
    echo -e "\t$(lspci -nns ${d##*/})"
    else
    echo -en "\t\t"
    fi
    lastgroup=${g##*/}
    lspci -nms ${d##*/} | awk -F'"' '{printf "[%s:%s]", $4, $6}'
    if [[ -e "$d"/reset ]]; then echo -en " [R] "; else echo -en " "; fi

    lspci -mms ${d##*/} | awk -F'"' '{printf "%s %-40s %s\n", $1, $2, $6}'
    for u in ${d}/usb*/; do
    lsusb -s $(cat "${u}/busnum"): | awk '{printf "\t\t\t\t%s\n", $0}'
    echo
    bus=$(cat "${u}/busnum")
    lsusb -s $bus: | \
    awk '{gsub(/:/,"",$4); printf "%s|%s %s %s %s|", $6, $1, $2, $3, $4; for(i=7;i<=NF;i++){printf "%s ", $i}; printf "\n"}' | \
    awk -F'|' '{printf "USB:\t\t[%s]\t\t %-40s %s\n", $1, $2, $3}'
    done
    done
    done
  6. @r15ch13 r15ch13 revised this gist Jul 24, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion iommu.sh
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    if [[ -e "$d"/reset ]]; then echo -en "[RESET]"; fi
    echo -e "\t$(lspci -nns ${d##*/})"
    for u in ${d}/usb*/; do
    lsusb -s $(cat "${u}/busnum"): | awk '{printf "\t\t\t%s\n", $0}'
    lsusb -s $(cat "${u}/busnum"): | awk '{printf "\t\t\t\t%s\n", $0}'
    echo
    done
    done
  7. @r15ch13 r15ch13 revised this gist Jul 24, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion iommu.sh
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,9 @@
    shopt -s nullglob
    for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    for d in $g/devices/*; do
    echo -e "Group ${g##*/}:\t$(lspci -nns ${d##*/})"
    echo -en "Group ${g##*/}:\t"
    if [[ -e "$d"/reset ]]; then echo -en "[RESET]"; fi
    echo -e "\t$(lspci -nns ${d##*/})"
    for u in ${d}/usb*/; do
    lsusb -s $(cat "${u}/busnum"): | awk '{printf "\t\t\t%s\n", $0}'
    echo
  8. @r15ch13 r15ch13 created this gist Jul 24, 2021.
    12 changes: 12 additions & 0 deletions iommu.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    #!/usr/bin/env bash

    shopt -s nullglob
    for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    for d in $g/devices/*; do
    echo -e "Group ${g##*/}:\t$(lspci -nns ${d##*/})"
    for u in ${d}/usb*/; do
    lsusb -s $(cat "${u}/busnum"): | awk '{printf "\t\t\t%s\n", $0}'
    echo
    done
    done
    done