Files
monok8s/macos/flashusb.sh

175 lines
4.1 KiB
Bash
Executable File

#!/bin/sh
set -eu
### User-configurable vars
IMG="./out/monok8s-dev.img.gz"
DEFAULT_DISK="/dev/disk7" # whole disk, not a partition
CONFIG_PART_SUFFIX="s1" # config partition after flashing
ENV_SEARCH_DIR="./out" # optional; leave empty to use image dir
MNT="/tmp/monok8s-usb-config.$$"
cleanup() {
if mount | grep -q "on ${MNT} "; then
diskutil unmount "$MNT" >/dev/null 2>&1 || true
fi
rmdir "$MNT" >/dev/null 2>&1 || true
}
log() {
echo "[*] $*"
}
warn() {
echo "[!] $*" >&2
}
die() {
echo "[!] ERROR: $*" >&2
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
}
wait_for_disk() {
dev="$1"
timeout="${2:-15}"
i=0
while [ "$i" -lt "$timeout" ]; do
[ -e "$dev" ] && return 0
i=$((i + 1))
sleep 1
done
return 1
}
wait_for_mountable_partition() {
dev="$1"
timeout="${2:-20}"
i=0
while [ "$i" -lt "$timeout" ]; do
if [ -e "$dev" ] && diskutil info "$dev" >/dev/null 2>&1; then
return 0
fi
i=$((i + 1))
sleep 1
done
return 1
}
### Sanity checks
require_cmd diskutil
require_cmd gunzip
require_cmd dd
require_cmd sync
require_cmd mount
require_cmd find
require_cmd cp
require_cmd sed
require_cmd stat
require_cmd pv
printf "disk ($DEFAULT_DISK): "
read -r TARGET_DISK
if [ -z "$TARGET_DISK" ]; then
TARGET_DISK="$DEFAULT_DISK"
fi
TARGET_RAW_DISK="/dev/r$(basename "$TARGET_DISK")"
TARGET_BASENAME="$(basename "$TARGET_DISK")"
### Derived vars
TARGET_CONFIG_PART="/dev/${TARGET_BASENAME}${CONFIG_PART_SUFFIX}"
IMG_DIR="$(cd "$(dirname "$IMG")" && pwd)"
SEARCH_DIR="${ENV_SEARCH_DIR:-$IMG_DIR}"
IMG_SIZE_BYTES="$(stat -f%z "$IMG")"
[ -f "$IMG" ] || die "Image not found: $IMG"
[ -b "$TARGET_DISK" ] || die "Target disk not found: $TARGET_DISK"
[ "$(id -u)" -eq 0 ] || die "Run this script with sudo"
case "$TARGET_DISK" in
/dev/disk[0-9]*)
;;
*)
die "TARGET_DISK must look like /dev/diskN"
;;
esac
mkdir -p "$MNT"
trap cleanup EXIT
log "Image: $IMG"
log "Compressed image size: $IMG_SIZE_BYTES bytes"
log "Target disk: $TARGET_DISK"
log "Raw target disk: $TARGET_RAW_DISK"
log "Expected config partition after flash: $TARGET_CONFIG_PART"
log "Target disk info:"
diskutil info "$TARGET_DISK" || die "Unable to inspect target disk"
echo
printf "Type 'YES' to continue: "
read -r CONFIRM
[ "$CONFIRM" = "YES" ] || die "Aborted."
log "Unmounting target disk..."
diskutil unmountDisk force "$TARGET_DISK" || die "Failed to unmount $TARGET_DISK"
log "Flashing image with progress..."
pv -s "$IMG_SIZE_BYTES" "$IMG" \
| gunzip \
| dd of="$TARGET_RAW_DISK" bs=1m
log "Syncing writes..."
sync
log "Ejecting and re-reading disk..."
diskutil eject "$TARGET_DISK" >/dev/null 2>&1 || true
sleep 2
log "Waiting for disk to come back..."
if ! wait_for_disk "$TARGET_DISK" 15; then
warn "Disk node did not reappear quickly. You may need to replug the drive."
fi
log "Disk layout after flashing:"
diskutil list "$TARGET_DISK" || warn "Could not list flashed disk yet"
ENV_FILES="$(find "$SEARCH_DIR" -maxdepth 1 -type f -name '*.env' | sort || true)"
if [ -n "$ENV_FILES" ]; then
log "Found env files:"
echo "$ENV_FILES" | sed 's/^/ /'
log "Waiting for config partition..."
wait_for_mountable_partition "$TARGET_CONFIG_PART" 20 || die "Config partition not ready: $TARGET_CONFIG_PART"
log "Mounting flashed config partition..."
diskutil mount -mountPoint "$MNT" "$TARGET_CONFIG_PART" >/dev/null || die "Failed to mount $TARGET_CONFIG_PART"
log "Copying env files to config partition..."
echo "$ENV_FILES" | while IFS= read -r f; do
[ -n "$f" ] || continue
base="$(basename "$f")"
cp "$f" "$MNT/$base"
echo " copied: $base"
done
log "Syncing copied config..."
sync
log "Config partition contents:"
ls -la "$MNT" || true
log "Unmounting config partition..."
diskutil unmount "$MNT" >/dev/null || warn "Unmount failed for $MNT"
else
log "No .env files found in $SEARCH_DIR"
fi
log "Done."