83 lines
3.3 KiB
Bash
Executable File
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
|