fwt_software/scripts/fgc-setcap

83 lines
3.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Give fire_gimbal_control the one privilege the thermal camera needs.
#
# The InfraTec SDK talks to the TarisIR over a raw AF_PACKET socket, which
# takes CAP_NET_RAW. Rather than running the whole program - motors, MQTT
# remote control and all - as root, the binary gets that one capability and
# keeps running as the tower's user. A rebuild replaces the binary and with it
# the capability, so deploy.sh and install-tower run this after every build.
#
# scripts/fgc-setcap set it (asks for the sudo password)
# scripts/fgc-setcap --if-thermal ... only if a [Camera.*] has driver = taris;
# never fails, says what is missing
# scripts/fgc-setcap --check exit 0 if the binary has it
# scripts/fgc-setcap --install-sudoers allow exactly this setcap without a
# password, so deploy.sh can run it
#
# A binary with file capabilities runs in the loader's secure mode: LD_* is
# ignored and no core dumps are written. So the SDK (/usr/lib/infratec, in the
# ld cache) and Vimba X must be found without LD_LIBRARY_PATH - see
# docs/tower-installation.md, "Thermal camera", for the check.
set -euo pipefail
REPO=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
BIN="$REPO/build/fire_gimbal_control"
CAPS="cap_net_raw+ep"
SETCAP=/usr/sbin/setcap # fixed: the sudoers rule names this exact path
[[ -x $SETCAP ]] || SETCAP=$(command -v setcap 2>/dev/null || echo /usr/sbin/setcap)
SUDOERS=/etc/sudoers.d/fire-gimbal-control-setcap
HW=/etc/fire_gimbal_control/hardware.ini
thermal_configured() {
local f cfg
cfg=$("$REPO/scripts/tower-config" where 2>/dev/null || true)
for f in "$cfg" "$REPO/config.ini" "$HW"; do
[[ -r $f ]] && grep -Eqi '^[[:space:]]*driver[[:space:]]*=[[:space:]]*taris' "$f" && return 0
done
return 1
}
has_cap() { command -v getcap > /dev/null && getcap "$BIN" 2>/dev/null | grep -q cap_net_raw; }
set_cap() {
[[ -x $BIN ]] || { echo "fgc-setcap: $BIN not built yet" >&2; return 1; }
if sudo -n "$SETCAP" "$CAPS" "$BIN" 2>/dev/null; then :
elif [[ -t 0 ]]; then sudo "$SETCAP" "$CAPS" "$BIN"
else return 1
fi
has_cap
}
case "${1:-}" in
--check)
has_cap
;;
--install-sudoers)
rule="$(id -un) ALL=(root) NOPASSWD: $SETCAP $CAPS $BIN"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
printf '# fire_gimbal_control: the thermal camera needs cap_net_raw after every build\n%s\n' \
"$rule" > "$tmp"
/usr/sbin/visudo -cf "$tmp" > /dev/null || { echo "fgc-setcap: rule rejected by visudo" >&2; exit 1; }
sudo install -m 0440 -o root -g root "$tmp" "$SUDOERS"
echo "wrote $SUDOERS: $rule"
;;
--if-thermal)
thermal_configured || exit 0
if set_cap; then
echo "fgc-setcap: $BIN may open raw sockets (thermal camera)"
else
echo "!! fgc-setcap: could not give $BIN $CAPS - the thermal camera stays offline." >&2
echo "!! Once on the tower: scripts/fgc-setcap --install-sudoers (or run scripts/fgc-setcap)" >&2
fi
exit 0
;;
"")
set_cap && echo "fgc-setcap: $BIN may open raw sockets"
;;
*)
sed -n '2,20p' "$0" >&2
exit 2
;;
esac