#!/usr/bin/env bash # ============================================================================ # qcrows-inspect — Read QCrows image metadata without full extraction # ============================================================================ set -euo pipefail CYAN='\033[0;36m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' FILE="${1:-}" [[ -z "$FILE" ]] && { echo "Usage: qcrows-inspect "; exit 1; } [[ ! -f "$FILE" ]] && { echo "File not found: $FILE" >&2; exit 1; } # ─── Archive extraction helpers (single dispatch point) ────────────────────── # Extract a file from the archive to stdout tar_extract() { local archive="$1"; shift if [[ "$archive" == *.gz ]]; then tar xzf "$archive" "$@" 2>/dev/null else tar xf "$archive" "$@" 2>/dev/null fi } # List archive contents to stdout tar_list() { local archive="$1" if [[ "$archive" == *.gz ]]; then tar tzf "$archive" 2>/dev/null else tar tf "$archive" 2>/dev/null fi } # ─── Read values from TOML content ────────────────────────────────────────── get_val() { echo "$META" | grep -E "^${1}" | head -1 | sed 's/.*= *//' | tr -d '"' | tr -d ' ' } get_array() { echo "$META" | grep -E "^${1}" | head -1 | sed 's/.*= *//' | tr -d '[]"' | sed 's/, */, /g' } get_section_val() { local section="$1" key="$2" echo "$META" | awk "/\[.*${section}.*\]/{found=1} found && /^${key}/{print; exit}" } # ─── Read metadata.toml ──────────────────────────────────────────────────── META="$(tar_extract "$FILE" -O ./metadata.toml 2>/dev/null || tar_extract "$FILE" -O metadata.toml 2>/dev/null || echo "")" if [[ -z "$META" ]]; then echo "Error: Could not read metadata.toml from archive" >&2 exit 1 fi # ─── Format output ───────────────────────────────────────────────────────── FMT=" %-16s ${CYAN}%s${NC}\n" echo "" echo -e "${GREEN}QCrows Image Inspection${NC}" echo -e "${YELLOW}──────────────────────────────────────────────────────${NC}" printf "$FMT" "Name:" "$(get_val 'name')" printf "$FMT" "Version:" "$(get_val 'version')" printf "$FMT" "Description:" "$(echo "$META" | grep '^description' | head -1 | sed "s/.*= *//;s/^\"//;s/\"$//")" printf "$FMT" "Arch:" "$(get_val 'arch')" printf "$FMT" "Created:" "$(get_val 'created_at')" echo "" echo -e "${YELLOW}Compatibility:${NC}" printf "$FMT" "Hypervisors:" "$(get_array 'hypervisors')" printf "$FMT" "Kata min:" "$(get_val 'kata_runtime_min')" echo "" # ─── Component details ───────────────────────────────────────────────────── echo -e "${YELLOW}Components:${NC}" k_included=$(get_section_val kernel included | sed 's/.*= *//' | tr -d ' ' || echo "false") k_version=$(get_section_val kernel version | sed 's/.*= *//' | tr -d '"' || echo "unknown") k_format=$(get_section_val kernel format | sed 's/.*= *//' | tr -d '"' || echo "vmlinuz") k_size=$(get_section_val kernel size_mb | sed 's/.*= *//' | tr -d ' ' || echo "0") printf "$FMT" "Kernel:" "${k_version} (${k_format})" printf "$FMT" "Kernel size:" "${k_size} MiB" printf "$FMT" "Kernel config:" "$(get_section_val kernel config_path | sed 's/.*= *//' | tr -d '"' || echo "missing")" printf "$FMT" "Initrd:" "$(get_val 'type') (included=$(get_val 'included'))" printf "$FMT" "Rootfs:" "$(get_val 'type')" printf "$FMT" "Rootfs size:" "$(get_val 'size_mb') MiB" boot_included=$(get_section_val boot_params included | sed 's/.*= *//' | tr -d ' ' || echo "false") printf "$FMT" "Boot params:" "${boot_included}" echo "" # ─── Build info ───────────────────────────────────────────────────────────── BUILD_SYS=$(get_section_val build system | sed 's/.*= *//' | tr -d '"' || true) if [[ -n "$BUILD_SYS" ]]; then echo -e "${YELLOW}Build:${NC}" printf "$FMT" "System:" "$BUILD_SYS" printf "$FMT" "Timestamp:" "$(get_section_val build timestamp | sed 's/.*= *//' | tr -d '"' || echo 'N/A')" echo "" fi # ─── Menu entry ───────────────────────────────────────────────────────────── MENU="$(tar_extract "$FILE" -O ./menu.toml 2>/dev/null || tar_extract "$FILE" -O menu.toml 2>/dev/null || echo "")" if [[ -n "$MENU" ]]; then menu_label=$(echo "$MENU" | grep '^label' | head -1 | sed 's/.*= *//' | tr -d '"' || echo "N/A") menu_cat=$(echo "$MENU" | grep '^category' | head -1 | sed 's/.*= *//' | tr -d '"' || echo "N/A") echo -e "${YELLOW}Menu Entry:${NC}" printf "$FMT" "Label:" "$menu_label" printf "$FMT" "Category:" "$menu_cat" echo "" fi # ─── Archive contents (direct pipeline — no subshell loop) ────────────────── echo -e "${YELLOW}Archive Contents:${NC}" tar_list "$FILE" | sort | sed "s/^/ ${CYAN}/;s/$/${NC}/" echo ""