#!/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