109 lines
2.7 KiB
Bash
109 lines
2.7 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck disable=SC1091
|
|
source "${SCRIPT_DIR}/load-env.sh"
|
|
|
|
camera_device="${OMNI_CAMERA_DEVICE}"
|
|
occupancy_policy="${OMNI_CAMERA_OCCUPANCY_POLICY:-check}"
|
|
release_service="${OMNI_CAMERA_RELEASE_SERVICE:-}"
|
|
|
|
die() {
|
|
echo "[camera-preflight] $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
camera_pids() {
|
|
fuser "${camera_device}" 2>/dev/null \
|
|
| tr ' ' '\n' \
|
|
| grep -E '^[0-9]+$' \
|
|
| sort -nu \
|
|
|| true
|
|
}
|
|
|
|
pid_service() {
|
|
local pid="$1"
|
|
local service
|
|
|
|
service="$(sed -nE 's#.*[/:]([^/:]+\.service)$#\1#p' "/proc/${pid}/cgroup" 2>/dev/null | head -1)"
|
|
printf '%s' "${service:-unknown}"
|
|
}
|
|
|
|
report_owners() {
|
|
local pid
|
|
local comm
|
|
local service
|
|
local found=0
|
|
|
|
while read -r pid; do
|
|
[[ -n "${pid}" ]] || continue
|
|
found=1
|
|
comm="$(cat "/proc/${pid}/comm" 2>/dev/null || printf 'unknown')"
|
|
service="$(pid_service "${pid}")"
|
|
echo "[camera-preflight] owner pid=${pid} command=${comm} service=${service}" >&2
|
|
done < <(camera_pids)
|
|
|
|
if [[ "${found}" == "1" ]]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
has_proc_manager_owner() {
|
|
local pid
|
|
|
|
while read -r pid; do
|
|
[[ -n "${pid}" ]] || continue
|
|
if [[ "$(pid_service "${pid}")" == "proc_manager.service" ]]; then
|
|
return 0
|
|
fi
|
|
done < <(camera_pids)
|
|
|
|
return 1
|
|
}
|
|
|
|
if [[ ! -e "${camera_device}" ]]; then
|
|
die "camera device does not exist: ${camera_device}"
|
|
fi
|
|
|
|
if ! command -v fuser >/dev/null 2>&1; then
|
|
die "missing required command: fuser (install the psmisc package)"
|
|
fi
|
|
|
|
resolved_device="$(readlink -f "${camera_device}" 2>/dev/null || printf '%s' "${camera_device}")"
|
|
echo "[camera-preflight] checking ${camera_device} (${resolved_device}) policy=${occupancy_policy}" >&2
|
|
|
|
if ! report_owners; then
|
|
echo "[camera-preflight] ${camera_device} is free" >&2
|
|
exit 0
|
|
fi
|
|
|
|
case "${occupancy_policy}" in
|
|
check)
|
|
die "${camera_device} is busy; no process was stopped"
|
|
;;
|
|
release-known)
|
|
if [[ -z "${release_service}" ]]; then
|
|
die "OMNI_CAMERA_RELEASE_SERVICE is required when policy=release-known"
|
|
fi
|
|
|
|
echo "[camera-preflight] stopping known camera service ${release_service}" >&2
|
|
systemctl stop "${release_service}"
|
|
|
|
if ! report_owners; then
|
|
echo "[camera-preflight] ${camera_device} was released by ${release_service}" >&2
|
|
exit 0
|
|
fi
|
|
|
|
if has_proc_manager_owner; then
|
|
die "${camera_device} is still owned by proc_manager.service; refusing to stop the whole process manager. Unload the owning ROS component explicitly."
|
|
fi
|
|
|
|
die "${camera_device} remains busy after stopping ${release_service}"
|
|
;;
|
|
*)
|
|
die "unsupported OMNI_CAMERA_OCCUPANCY_POLICY=${occupancy_policy}; expected check or release-known"
|
|
;;
|
|
esac
|