#!/usr/bin/env bash # When VERIFY fails: PCI reset (root) + doctor --fix (desktop user), then re-verify. # Run as your desktop user (same as kaisa-audio-doctor.sh). Reset step needs: # sudo -n /path/to/reset-sof-hdmi-pci.sh # (configure NOPASSWD for that absolute path). # # Typical: # ./scripts/kaisa-audio-hdmi-watchdog.sh # ./scripts/kaisa-audio-hdmi-watchdog.sh --loop --interval 300 # set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" RESET_SCRIPT="${KAISA_RESET_SCRIPT:-${REPO_ROOT}/scripts/reset-sof-hdmi-pci.sh}" DOCTOR="${REPO_ROOT}/scripts/kaisa-audio-doctor.sh" LOG_DIR="${KAISA_LOG_DIR:-${REPO_ROOT}/_logs}" CONNECTED_ARGS=(--only-connected) LOOPS=1 INTERVAL_SEC="${KAISA_WATCHDOG_INTERVAL:-120}" LOOP_FOREVER=0 log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*"; } usage() { sed -n '1,40p' "$0" | sed -n '/^# /s/^# //p' cat <&2 usage >&2 exit 2 ;; esac done if ! [[ "${LOOPS}" =~ ^[0-9]+$ ]] || [[ "${LOOPS}" -lt 1 ]]; then echo "ERROR: --loops must be a positive integer" >&2 exit 2 fi if [[ "${EUID}" -eq 0 ]]; then echo "ERROR: run as desktop user, not root (doctor --fix needs user session)." >&2 exit 1 fi if [[ ! -x "${DOCTOR}" ]]; then echo "ERROR: missing doctor: ${DOCTOR}" >&2 exit 1 fi if [[ ! -f "${RESET_SCRIPT}" ]]; then echo "ERROR: missing reset script: ${RESET_SCRIPT}" >&2 exit 1 fi mkdir -p "${LOG_DIR}" run_one_cycle() { local cycle="${1:?}" local ts ts="$(date +%Y%m%d_%H%M%S)" local v1 f1 v2 v1="${LOG_DIR}/kaisa-watchdog_${ts}_c${cycle}_verify.log" f1="${LOG_DIR}/kaisa-watchdog_${ts}_c${cycle}_fix.log" v2="${LOG_DIR}/kaisa-watchdog_${ts}_c${cycle}_reverify.log" log "cycle ${cycle}: verify -> ${v1}" if "${DOCTOR}" --verify "${CONNECTED_ARGS[@]}" --verify-strict -o "${v1}"; then log "cycle ${cycle}: verify OK" return 0 fi log "cycle ${cycle}: verify FAILED -> sudo -n reset (${RESET_SCRIPT})" if ! sudo -n "${RESET_SCRIPT}"; then log "ERROR: sudo -n reset failed (password / NOPASSWD path?)" return 1 fi log "cycle ${cycle}: doctor --fix -> ${f1}" "${DOCTOR}" --fix "${CONNECTED_ARGS[@]}" -o "${f1}" || true log "cycle ${cycle}: re-verify -> ${v2}" if "${DOCTOR}" --verify "${CONNECTED_ARGS[@]}" --verify-strict -o "${v2}"; then log "cycle ${cycle}: re-verify OK after reset+fix" return 0 fi log "cycle ${cycle}: re-verify still FAILED (see ${v2})" return 1 } cycle=0 while true; do cycle=$((cycle + 1)) if run_one_cycle "${cycle}"; then : else log "cycle ${cycle}: recovery did not achieve clean verify" fi if [[ "${LOOP_FOREVER}" -eq 0 ]]; then if [[ "${cycle}" -ge "${LOOPS}" ]]; then break fi fi if [[ "${LOOP_FOREVER}" -eq 1 ]] || [[ "${cycle}" -lt "${LOOPS}" ]]; then log "sleep ${INTERVAL_SEC}s before next cycle" sleep "${INTERVAL_SEC}" fi done log "watchdog finished (${cycle} cycle(s))"