From 48419f22f48b67386ff6b0fee756da292d40e4c2 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Fri, 4 Sep 2026 22:41:55 +0200 Subject: [PATCH] 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. --- packaging/deploy-dev.sh | 106 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 packaging/deploy-dev.sh diff --git a/packaging/deploy-dev.sh b/packaging/deploy-dev.sh new file mode 100755 index 0000000..2cab772 --- /dev/null +++ b/packaging/deploy-dev.sh @@ -0,0 +1,106 @@ +#!/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'"