fingerprintd/packaging/deploy-dev.sh
Jorijn van der Graaf 48419f22f4 Add deploy-dev.sh: a reboot is one command away from a running daemon again
Nothing is packaged yet, so the binary, the scripts, the module load, the
persist mount and the transient unit all live in places a reboot wipes. That is
deliberate -- a reboot leaves a stock phone rather than a half-installed daemon
-- but its cost was a list of manual steps in a journal handoff, and the second
reboot of the day showed what that costs. The list is now a script.

Two things it gets right that a first draft did not. The readiness check is
scoped to the current systemd invocation: the journal persists across restarts
and reboots, so grepping the whole unit history matches the previous run's ready
line and reports the daemon up while the session is still coming up on the
worker thread. And the binary is copied under a new name and swapped in with mv
after the unit stops, because a running executable cannot be overwritten and
scp reports that only as "dest open: Failure" -- which a retry loop turns into
six identical failures instead of one clear one.

Verified from a freshly rebooted phone and again over a running daemon.
2026-09-04 22:41:55 +02:00

106 lines
5 KiB
Shell
Executable file

#!/bin/sh
# deploy-dev.sh -- bring the dev phone back to a running daemon, from nothing.
#
# packaging/deploy-dev.sh [host] default: fp6usb4
#
# Run from the repo root on the workstation, after a cross build. Everything the
# daemon needs on the phone that does NOT survive a reboot is put back by this:
#
# /tmp/fingerprintd the cross-built binary
# /tmp/fpenrol.sh fptrial.sh the enrolment and labelled-trial scripts
# /tmp/fplearn.sh the template-learning protocol
# qcomtee.ko loaded /dev/tee0 does not exist until it is
# /dev/sda6 on /mnt/persist the real persist partition, read-write --
# the daemon's SFS root symlinks into it
# fingerprintd-test the transient unit, learning on
#
# What survives a reboot and is therefore NOT touched: /usr/lib/firmware/
# qcomtee.ko, /lib/firmware/fingerprintd.json (regenerate with
# fp6fpcfg.py --daemon --verbose and pass --config to refresh it), the SFS
# symlinks under /var/lib/fingerprintd/sfs, and the finger name map.
#
# WHY /tmp. Nothing here is packaged yet; /tmp is deliberate so a reboot leaves
# a stock phone rather than a half-installed daemon. The cost is exactly this
# script, run once after each reboot.
set -eu
HOST=${1:-fp6usb4}
CONFIG=${CONFIG:-} # optional: a fingerprintd.json to install
SSH="ssh -o ConnectTimeout=8 -o BatchMode=yes $HOST"
cd "$(dirname "$0")/.."
BIN=$(ls -dt bin/fingerprintd-aarch64-alpine-linux-musl-*/ | head -1)fingerprintd
[ -x "$BIN" ] || { echo "no cross-built binary under bin/; build first" >&2; exit 1; }
echo ">> binary $BIN"
echo " $(sha256sum "$BIN" | cut -c1-16)"
# The binary goes in under a NEW name and is swapped into place on the phone
# after the unit stops: a running executable cannot be overwritten (ETXTBSY,
# which scp reports only as "dest open: Failure"), and a retry loop turns that
# into six identical failures instead of one clear one. mv replaces the inode,
# which is allowed while the old one is still executing.
#
# The phone also drops off the network transiently, which IS worth retrying.
cp "$BIN" /tmp/fingerprintd.new
i=0
until scp -o ConnectTimeout=8 -o BatchMode=yes -q \
/tmp/fingerprintd.new packaging/fpenrol.sh packaging/fptrial.sh packaging/fplearn.sh \
${CONFIG:+"$CONFIG"} "$HOST:/tmp/"; do
i=$((i+1)); [ $i -lt 6 ] || { echo "scp failed 6 times" >&2; rm -f /tmp/fingerprintd.new; exit 1; }
echo " scp retry $i"; sleep 5
done
rm -f /tmp/fingerprintd.new
echo ">> copied"
$SSH 'set -e
# Stop before the swap so the new binary is what starts, not the old inode.
sudo systemctl stop fingerprintd-test 2>/dev/null || true
sudo mv /tmp/fingerprintd.new /tmp/fingerprintd
sudo chmod +x /tmp/fingerprintd /tmp/fpenrol.sh /tmp/fptrial.sh /tmp/fplearn.sh
if [ -f /tmp/fingerprintd.json ]; then
sudo cp /tmp/fingerprintd.json /lib/firmware/fingerprintd.json
echo ">> config installed"
fi
if ! lsmod | grep -q "^qcomtee"; then
sudo insmod /usr/lib/firmware/qcomtee.ko qseeflow=0
fi
[ -c /dev/tee0 ] || { echo "no /dev/tee0 after insmod" >&2; exit 1; }
echo ">> qcomtee loaded, /dev/tee0 present"
sudo mkdir -p /mnt/persist
if ! mount | grep -q " /mnt/persist "; then
sudo mount -o rw /dev/sda6 /mnt/persist
fi
mount | grep " /mnt/persist " | grep -q "rw," || { echo "persist not rw" >&2; exit 1; }
echo ">> persist mounted rw"
sudo systemctl stop fingerprintd-test 2>/dev/null || true
sleep 1
sudo systemd-run --unit=fingerprintd-test --collect \
/tmp/fingerprintd --daemon --verbose --edge-wake \
--sfs-root=/var/lib/fingerprintd/sfs --sfs-writable --rpmb-write >/dev/null
printf ">> daemon starting"
# Scope the readiness check to THIS invocation. The journal persists across
# restarts and reboots, so grepping the whole unit history matches the ready
# line of the PREVIOUS run and reports the daemon up while the session is
# still coming up on the worker thread -- which is how a first version of this
# script ran fprintd-list into "device is still starting".
# (No apostrophes in this block: the whole remote script is single-quoted.)
INV=$(systemctl show -p InvocationID --value fingerprintd-test)
log() { sudo journalctl "_SYSTEMD_INVOCATION_ID=$INV" --no-pager -o cat 2>/dev/null; }
i=0
while [ $i -lt 40 ]; do
if log | grep -q "fingerprintd: ready"; then echo " ready"; break; fi
if log | grep -q "StartFailed\|must run as root\|sensor power-up failed\|cannot open config"; then
echo " FAILED"; log | tail -15; exit 1
fi
printf "."; sleep 1; i=$((i+1))
done
[ $i -lt 40 ] || { echo " TIMED OUT"; log | tail -15; exit 1; }
echo ">> $(systemctl is-active fingerprintd-test), owning: $(busctl --system list 2>/dev/null | grep -c net.reactivated.Fprint)"
fprintd-list user 2>&1 | tail -n +2
echo ">> binary $(sha256sum /tmp/fingerprintd | cut -c1-16) config $(sha256sum /lib/firmware/fingerprintd.json | cut -c1-16)"
'
echo
echo "measurement:"
echo " ssh $HOST 'sudo /tmp/fplearn.sh enrol right-middle-finger'"
echo " ssh $HOST 'sudo /tmp/fplearn.sh base'"
echo " ssh $HOST 'sudo /tmp/fplearn.sh trend'"