Add recorder: raw CAN and GNSS sessions with failsafes and a storage bound

Reads SocketCAN and gpsd directly. Sessions start on the first frame or on
'ctl start', end after 15 s of bus idle or on 'ctl stop'; blips under 3 s are
discarded. candump -L chunks fdatasync'd every second and zstd'd once closed;
oldest sessions deleted to stay under 50 GB / above 20 GB free. Kernel and
queue drops, link changes and clock steps are recorded as events.

Bench-tested on vcan with the first car capture (byte-identical) and installed
on the car Orin as yukart-recorder.service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
This commit is contained in:
2026-10-09 20:15:13 +09:00
commit 1f678fe87f
19 changed files with 1784 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Fail if a binary references a glibc symbol version newer than the car unit has.
#
# Detects drift between the development Orin and the car Orin. It does not fix
# it: the fix is building on a unit whose release matches the target's.
#
# usage: scripts/check-glibc.sh <binary> [ceiling]
set -euo pipefail
CEILING="${GLIBC_CEILING:-2.35}"
BIN="${1:?usage: check-glibc.sh <binary> [ceiling]}"
[ $# -ge 2 ] && CEILING="$2"
# A check that cannot check must not report success.
command -v objdump >/dev/null 2>&1 || { echo "BROKEN: objdump unavailable, nothing was checked"; exit 2; }
[ -f "$BIN" ] || { echo "BROKEN: no such binary: $BIN"; exit 2; }
mapfile -t versions < <(objdump -T "$BIN" 2>/dev/null | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu)
if [ "${#versions[@]}" -eq 0 ]; then
echo "BROKEN: no glibc symbol versions found in $BIN — statically linked, or objdump read nothing"
exit 2
fi
max="${versions[-1]#GLIBC_}"
echo "$(basename "$BIN"): ${#versions[@]} glibc versions referenced, highest GLIBC_$max, ceiling GLIBC_$CEILING"
if [ "$(printf '%s\n%s\n' "$max" "$CEILING" | sort -V | tail -1)" != "$CEILING" ]; then
echo "FAIL: GLIBC_$max exceeds the ceiling. Symbols responsible:"
objdump -T "$BIN" 2>/dev/null | grep -F "GLIBC_$max" | awk '{print " " $(NF-1), $NF}' | sort -u
echo
echo "Build on a unit matching the car Orin's release, or raise the ceiling if"
echo "the car unit was upgraded too."
exit 1
fi
echo "OK"
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Build the recorder for aarch64, check it against the car's glibc, and install it
# on an Orin as the yukart-recorder service.
#
# usage: scripts/deploy-recorder.sh [host] (default: mikkeli-orin-nano)
#
# Cross-compiles from the workstation (the documented fallback): the development
# Orin is the preferred native build host. Either way check-glibc.sh gates it.
set -euo pipefail
HOST="${1:-mikkeli-orin-nano}"
cd "$(dirname "$0")/.."
TARGET=aarch64-unknown-linux-gnu
BIN="target/$TARGET/release/recorder"
cargo build --release --target "$TARGET"
scripts/check-glibc.sh "$BIN"
# Binary lives under ~/infra per the host repo's guidelines; /usr/local/bin gets a symlink.
ssh "$HOST" 'mkdir -p ~/infra/svc-core'
scp -q "$BIN" "$HOST:infra/svc-core/recorder.new"
scp -q deploy/yukart-recorder.service "$HOST:infra/svc-core/yukart-recorder.service"
ssh "$HOST" 'set -e
mv ~/infra/svc-core/recorder.new ~/infra/svc-core/recorder
sudo ln -sfn "$HOME/infra/svc-core/recorder" /usr/local/bin/yukart-recorder
sudo install -m 0644 ~/infra/svc-core/yukart-recorder.service /etc/systemd/system/yukart-recorder.service
sudo systemctl daemon-reload
sudo systemctl enable yukart-recorder.service >/dev/null
sudo systemctl restart yukart-recorder.service
sleep 1
systemctl --no-pager --lines=5 status yukart-recorder.service'