#!/usr/bin/env bash
set -euo pipefail
set -o errtrace
IFS=$'\n\t'
trap 'echo "Error on or near line ${LINENO}; command exited with status $?" >&2' ERR
# rk3588_audit.sh
#
# Purpose:
# - Create a timestamped audit directory under ~/rk3588_audit_<timestamp>/
# - Collect system/display/GPU/VPU/network/storage snapshots
# - Install diagnostic packages idempotently (skips missing packages)
# - Avoid destructive actions; optional actions require explicit confirmation
START_TS="$(date +%Y%m%d_%H%M%S)"
AUDIT_DIR="$HOME/rk3588_audit_${START_TS}"
LOG_DIR="$AUDIT_DIR/logs"
OUT_DIR="$AUDIT_DIR/out"
REPORT_MD="$AUDIT_DIR/REPORT.md"
LOG_FILE="$LOG_DIR/audit.log"
ENV_FILE="$LOG_DIR/env.txt"
DMESG_FILE="$LOG_DIR/dmesg.txt"
CMD_FAIL_HINT="Check ${LOG_FILE} and ${REPORT_MD} for details."
: "${NET_TIMEOUT:=5}"
: "${FIO_SIZE_MB:=512}"
: "${FIO_BS:=1M}"
: "${FIO_IODEPTH:=16}"
: "${RUN_COLORS:=1}"
TMPDIR_CREATED=""
cleanup() {
if [[ -n "${TMPDIR_CREATED:-}" && -d "$TMPDIR_CREATED" ]]; then
rm -rf "$TMPDIR_CREATED" || true
fi
}
trap cleanup EXIT SIGINT SIGTERM
if [[ -t 1 && "$RUN_COLORS" -eq 1 ]] && command -v tput >/dev/null 2>&1; then
GREEN="$(tput setaf 2)"; YELLOW="$(tput setaf 3)"; RED="$(tput setaf 1)"; BLUE="$(tput setaf 4)"; BOLD="$(tput bold)"; RESET="$(tput sgr0)"
else
GREEN=""; YELLOW=""; RED=""; BLUE=""; BOLD=""; RESET=""
fi
log() { echo -e "$*" | tee -a "$LOG_FILE"; }
section() { log "\n${BOLD}${BLUE}==> $1${RESET}"; }
ensure_dir() { [[ -d "$1" ]] || mkdir -p "$1"; }
ask_yes() {
local prompt="$1" ans
echo
read -r -p "${YELLOW}${prompt}${RESET} (type 'yes' to continue, anything else to cancel): " ans
[[ "$ans" == "yes" ]] || { echo "Cancelled by user."; return 1; }
}
need_sudo() {
command -v sudo >/dev/null 2>&1 || { echo "Error: sudo required." >&2; exit 1; }
sudo -v || { echo "Error: sudo auth failed." >&2; exit 1; }
}
package_available() {
local pkg="$1"
apt-cache policy "$pkg" 2>/dev/null | awk '/Candidate:/ {print $2}' | grep -vq "(none)"
}
is_installed() { dpkg -s "$1" >/dev/null 2>&1; }
ensure_package() {
local pkg="$1"
if is_installed "$pkg"; then
log "Package already installed: ${GREEN}${pkg}${RESET}"
return 0
fi
if ! package_available "$pkg"; then
log "Package not available (skipping): ${YELLOW}${pkg}${RESET}"
return 0
fi
log "Installing package: ${GREEN}${pkg}${RESET}"
sudo apt-get install -y --no-install-recommends "$pkg" >>"$LOG_FILE" 2>&1 || {
echo "Error: Failed to install '$pkg'. ${CMD_FAIL_HINT}" >&2
exit 1
}
}
ensure_packages() { for pkg in "$@"; do ensure_package "$pkg"; done; }
run_continue() {
local title="$1"; shift
log "\n--- $title ---"
"$@" >>"$LOG_FILE" 2>&1 || log " (Command failed but continuing): $*"
}
run_fail() {
local title="$1"; shift
log "\n>>> $title"
"$@" >>"$LOG_FILE" 2>&1 || { echo "Error: $title failed. ${CMD_FAIL_HINT}" >&2; exit 1; }
}
quick_net_check() {
section "Quick network check"
if command -v ping >/dev/null 2>&1 && ping -c1 -W "$NET_TIMEOUT" deb.debian.org >/dev/null 2>&1; then
log "Network reachable."
return 0
fi
log "Network check failed; installs/downloads may be limited."
return 1
}
check_platform() {
section "Platform checks"
local debver arch
debver="$(cut -d'.' -f1 < /etc/debian_version 2>/dev/null || echo unknown)"
arch="$(uname -m 2>/dev/null || echo unknown)"
log "Debian major: $debver"
log "Arch : $arch"
[[ "$debver" == "11" ]] || log "WARNING: tuned for Debian 11 (Bullseye)."
[[ "$arch" == "aarch64" || "$arch" == "arm64" ]] || log "WARNING: tuned for ARM64."
}
enable_nonfree_optional() {
section "Optional: Enable contrib/non-free (Bullseye)"
if ! ask_yes "Enable 'contrib non-free' in /etc/apt/sources.list (backup + apt update)?"; then
log "Skipped enabling contrib/non-free."
return 0
fi
local src="/etc/apt/sources.list"
if [[ ! -f "$src" ]]; then
log "No $src found; skipping."
return 0
fi
sudo cp -a "$src" "${src}.bak.${START_TS}"
TMPDIR_CREATED="$(mktemp -d)"
local tmp="$TMPDIR_CREATED/sources.list"
sudo awk '{
if ($1=="deb" || $1=="deb-src") {
line=$0
has_contrib=match(line,/(^| )contrib( |$)/)
has_nonfree=match(line,/(^| )non-free( |$)/)
if (!has_contrib) line=line" contrib"
if (!has_nonfree) line=line" non-free"
print line
} else {
print
}
}' "$src" | sudo tee "$tmp" >/dev/null
sudo mv "$tmp" "$src"
run_fail "apt-get update (after enabling contrib/non-free)" sudo apt-get update
rm -rf "$TMPDIR_CREATED" || true
TMPDIR_CREATED=""
}
main() {
ensure_dir "$AUDIT_DIR"; ensure_dir "$LOG_DIR"; ensure_dir "$OUT_DIR"
: >"$LOG_FILE"
section "Start"
log "Audit directory: $AUDIT_DIR"
log "Log file : $LOG_FILE"
need_sudo
{
echo "===== ENVIRONMENT ====="
echo "Timestamp: $START_TS"
uname -a || true
echo
echo "----- /etc/os-release -----"
cat /etc/os-release 2>/dev/null || true
echo
echo "----- /proc/cmdline -----"
cat /proc/cmdline 2>/dev/null || true
echo
echo "----- CPU -----"
lscpu 2>/dev/null || true
echo
echo "----- Memory/CMA -----"
grep -E 'CmaTotal|CmaFree|MemTotal|MemFree|HugePages' /proc/meminfo 2>/dev/null || true
} >"$ENV_FILE"
run_continue "Collect dmesg" bash -lc "sudo dmesg -T > '$DMESG_FILE'"
check_platform
quick_net_check || true
section "APT update"
run_fail "apt-get update" sudo apt-get update
enable_nonfree_optional || true
section "Install baseline diagnostic tools (idempotent; skips unavailable)"
ensure_packages \
curl wget ca-certificates \
pciutils usbutils lshw hwinfo inxi \
ethtool iproute2 net-tools jq \
i2c-tools lm-sensors \
v4l-utils \
gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
ffmpeg alsa-utils \
vulkan-tools mesa-utils kmscube \
xrandr x11-xserver-utils autorandr \
edid-decode read-edid ddcutil \
fio hdparm nvme-cli smartmontools \
iw wireless-tools bluez can-utils
section "System overview"
run_continue "lshw (short)" sudo lshw -short
run_continue "lsblk -O" lsblk -O
run_continue "df -hT" df -hT
run_continue "lsusb -t" lsusb -t
run_continue "lspci -nnk" lspci -nnk
run_continue "Kernel warnings/errors (last 200)" bash -lc 'dmesg -T --level=err,warn | tail -n 200'
section "GPU & Display"
run_continue "GPU modules loaded" bash -lc "lsmod | egrep -i 'panthor|panfrost|mali|kbase' || true"
run_continue "GPU-related dmesg" bash -lc "dmesg -T | egrep -i 'mali|panthor|panfrost|csf|gpu' || true"
run_continue "DRM connectors (modetest -c)" modetest -c
run_continue "kmscube smoke test" bash -lc "kmscube -i 100 >/dev/null 2>&1 || true"
run_continue "Vulkan summary" vulkaninfo --summary
run_continue "xrandr --props (if X running)" bash -lc "DISPLAY=\${DISPLAY:-:0} xrandr --props 2>/dev/null || true"
section "Video / V4L2 / Codecs"
run_continue "List V4L2 devices" v4l2-ctl --list-devices
run_continue "FFmpeg hwaccels" ffmpeg -hide_banner -hwaccels
run_continue "GStreamer rockchip-ish plugins" bash -lc "gst-inspect-1.0 | egrep -i 'v4l2|rkv|hantro|rockchip' || true"
section "Audio"
run_continue "ALSA playback" aplay -l
run_continue "ALSA capture" arecord -l
section "Network"
run_continue "ip -details addr" ip -details address
run_continue "iw dev" iw dev
section "Storage"
run_continue "lsblk (model/serial)" lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS,MODEL,SERIAL,TRAN
run_continue "SATA/NVMe/PCIe dmesg" bash -lc "dmesg -T | egrep -i 'sata|ahci|nvme|pcie' || true"
run_continue "nvme list (if any)" bash -lc "ls /dev/nvme*n1 >/dev/null 2>&1 && sudo nvme list || true"
section "Optional actions"
if ask_yes "Run powertop --auto-tune (changes power tunables until reboot)?"; then
run_fail "powertop --auto-tune" sudo powertop --auto-tune
fi
if ask_yes "Run sensors-detect (interactive; may load modules)?"; then
run_fail "sensors-detect" sudo sensors-detect
fi
if ask_yes "Run quick fio seq read/write in $HOME (~${FIO_SIZE_MB}MB temp file, then removed)?"; then
TMPDIR_CREATED="$(mktemp -d)"
local fiofile="$TMPDIR_CREATED/fio_test.dat"
run_fail "dd create file" dd if=/dev/zero of="$fiofile" bs=1M count="$FIO_SIZE_MB" status=none
run_fail "fio seq rw" fio --name=seqrw --filename="$fiofile" --rw=readwrite --bs="$FIO_BS" --direct=1 --numjobs=1 --iodepth="$FIO_IODEPTH" --size="${FIO_SIZE_MB}M" --group_reporting
rm -rf "$TMPDIR_CREATED" || true
TMPDIR_CREATED=""
fi
section "REPORT.md"
{
echo "# RK3588 Capability Audit — $START_TS"
echo
echo "Audit directory: $AUDIT_DIR"
echo "Log file: $LOG_FILE"
echo "Env snapshot: $ENV_FILE"
echo "dmesg: $DMESG_FILE"
} >"$REPORT_MD"
( cd "$HOME" && tar czf "${AUDIT_DIR}.tar.gz" "$(basename "$AUDIT_DIR")" )
section "Done"
log "Report : $REPORT_MD"
log "Archive: ${AUDIT_DIR}.tar.gz"
}
main "$@"
URL: https://ib.bsb.br/rk3588-scan