auto flash

This commit is contained in:
Pat Nakajima 2026-05-24 13:02:41 -07:00
parent ede4100286
commit 9e48a99318

View File

@ -1,8 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMG="$HOME/Documents/toes-image-builder/toes-ubuntu-base.img"
USBBOOT="$HOME/apps/forks/usbboot"
PROVISION_SCRIPT="${PROVISION_SCRIPT:-$SCRIPT_DIR/scripts/provision-device.sh}"
PROVISION_DEVICE_ID="${PROVISION_DEVICE_ID:-${DEVICE_ID:-device-001}}"
DEFAULT_SERIAL_LOGIN="toes"
DEFAULT_SERIAL_PASSWORD="nicetrywiseguy"
REBOOT_SETTLE_SECS="${REBOOT_SETTLE_SECS:-45}"
SERIAL_BOOT_TIMEOUT_SECS="${SERIAL_BOOT_TIMEOUT_SECS:-180}"
list_external_disks() {
diskutil list external physical 2>/dev/null | awk '/^\/dev\/disk[0-9]+ / { sub("^/dev/", "", $1); print $1 }' | sort || true
@ -12,6 +19,145 @@ disk_bytes() {
diskutil info "/dev/$1" | awk -F'[()]' '/Disk Size:/ { sub(/ Bytes.*/, "", $2); print $2; exit }'
}
detect_serial_port() {
local pattern port
local -a matches
matches=()
for pattern in /dev/cu.usbserial\* /dev/cu.usbmodem\*; do
for port in $pattern; do
[[ -e "$port" ]] || continue
matches+=("$port")
done
done
if (( ${#matches[@]} == 1 )); then
printf '%s\n' "${matches[0]}"
return 0
fi
if (( ${#matches[@]} > 1 )); then
echo "multiple serial ports detected; set SERIAL_PORT to one of:" >&2
printf ' %s\n' "${matches[@]}" >&2
return 2
fi
matches=()
for pattern in /dev/tty.usbserial\* /dev/tty.usbmodem\*; do
for port in $pattern; do
[[ -e "$port" ]] || continue
matches+=("$port")
done
done
if (( ${#matches[@]} == 1 )); then
printf '%s\n' "${matches[0]}"
return 0
fi
if (( ${#matches[@]} > 1 )); then
echo "multiple serial ports detected; set SERIAL_PORT to one of:" >&2
printf ' %s\n' "${matches[@]}" >&2
return 2
fi
return 1
}
resolve_serial_port() {
local port status
if [[ -n "${SERIAL_PORT:-}" ]]; then
[[ -e "$SERIAL_PORT" ]] || { echo "serial port does not exist: $SERIAL_PORT" >&2; return 1; }
printf '%s\n' "$SERIAL_PORT"
return 0
fi
if port="$(detect_serial_port)"; then
printf '%s\n' "$port"
return 0
fi
status=$?
if (( status == 1 )); then
echo "no serial port detected; set SERIAL_PORT=/dev/cu.*" >&2
fi
return 1
}
wait_for_serial_port() {
local timeout="$1"
local deadline=$((SECONDS + timeout))
local port status
if [[ -n "${SERIAL_PORT:-}" ]]; then
while (( SECONDS < deadline )); do
[[ -e "$SERIAL_PORT" ]] && { printf '%s\n' "$SERIAL_PORT"; return 0; }
sleep 1
done
echo "timed out waiting for serial port: $SERIAL_PORT" >&2
return 1
fi
while (( SECONDS < deadline )); do
if port="$(detect_serial_port 2>/dev/null)"; then
printf '%s\n' "$port"
return 0
fi
status=$?
if (( status == 2 )); then
detect_serial_port >/dev/null || true
return 1
fi
sleep 1
done
echo "timed out waiting for serial port; set SERIAL_PORT=/dev/cu.*" >&2
return 1
}
stop_rpiboot_mass_storage() {
pkill -f 'rpiboot.*mass-storage-gadget' 2>/dev/null || true
}
reboot_target_over_serial() {
local port="$1"
echo "Requesting target reboot over $port"
stty -f "$port" 115200 raw -echo clocal 2>/dev/null || true
{
sleep 0.2
printf '\r'
sleep 0.5
printf 'root\r'
sleep 0.5
printf '\r'
sleep 0.5
printf 'sync\r'
sleep 0.5
printf 'reboot -f\r'
} >"$port"
}
provision_device() {
local port="$1"
local provision_login="${SERIAL_LOGIN:-$DEFAULT_SERIAL_LOGIN}"
local provision_password="${SERIAL_PASSWORD:-$DEFAULT_SERIAL_PASSWORD}"
local provision_prompt="${SERIAL_PROMPT:-${provision_login}@}"
[[ -x "$PROVISION_SCRIPT" ]] || { echo "provision script is not executable: $PROVISION_SCRIPT" >&2; return 1; }
echo "Provisioning $PROVISION_DEVICE_ID over $port"
SERIAL_PORT="$port" \
SERIAL_LOGIN="$provision_login" \
SERIAL_PASSWORD="$provision_password" \
SERIAL_PROMPT="$provision_prompt" \
SERIAL_LOGIN_TIMEOUT_SECS="${SERIAL_LOGIN_TIMEOUT_SECS:-$SERIAL_BOOT_TIMEOUT_SECS}" \
"$PROVISION_SCRIPT" "$PROVISION_DEVICE_ID"
}
if [[ "${SKIP_BUILD:-0}" != 1 ]]; then
ssh toes-image-builder 'cd toes-image-builder && ./build.sh && cp build/toes-ubuntu-base.img /mnt/utm/toes-image-builder/'
fi
@ -64,3 +210,20 @@ diskutil unmountDisk "/dev/$target"
sudo dd if="$IMG" of="/dev/r$target" bs=16m status=progress conv=fsync
sync
diskutil eject "/dev/$target"
if [[ "${SKIP_REBOOT:-0}" != 1 ]]; then
reboot_port="$(resolve_serial_port)"
stop_rpiboot_mass_storage
reboot_target_over_serial "$reboot_port"
echo "Waiting ${REBOOT_SETTLE_SECS}s for target to start booting..."
sleep "$REBOOT_SETTLE_SECS"
else
echo "Skipping target reboot because SKIP_REBOOT=1"
fi
if [[ "${SKIP_PROVISION:-0}" != 1 ]]; then
provision_port="$(wait_for_serial_port "$SERIAL_BOOT_TIMEOUT_SECS")"
provision_device "$provision_port"
else
echo "Skipping provisioning because SKIP_PROVISION=1"
fi