#!/bin/bash set -Eeuo pipefail if [ "$(id -u)" -ne 0 ]; then printf '%s\n' 'install_image_bootstrap.sh must run as root.' >&2 exit 1 fi if [ "$#" -ne 5 ]; then printf '%s\n' 'usage: install_image_bootstrap.sh IMAGE SERVICE_UNIT SSH_CONFIG KERNEL_DEPENDENCY APP_BUNDLE' >&2 exit 2 fi IMAGE=$(readlink -f -- "$1") UNIT=$(readlink -f -- "$2") SSH_CONFIG=$(readlink -f -- "$3") KERNEL_DEPENDENCY=$(readlink -f -- "$4") APP_BUNDLE=$(readlink -f -- "$5") SCRIPT_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) [ -f "$IMAGE" ] [ -f "$UNIT" ] [ -f "$SSH_CONFIG" ] [ -d "$KERNEL_DEPENDENCY" ] [ -f "$APP_BUNDLE" ] KERNEL_ARCHIVE=axp313a-kernel-6.1.31-matrix-axp313a1.tar.gz [ -f "$KERNEL_DEPENDENCY/$KERNEL_ARCHIVE" ] [ -f "$KERNEL_DEPENDENCY/SHA256SUMS" ] [ -f "$KERNEL_DEPENDENCY/METADATA.json" ] PYTHONPATH="$SCRIPT_ROOT" python3 "$SCRIPT_ROOT/scripts/kernel_artifact.py" \ --kernel "$KERNEL_DEPENDENCY" >/dev/null LOOP= MOUNT_DIR=$(mktemp -d /var/tmp/matrix-image-root.XXXXXX) cleanup() { if mountpoint -q "$MOUNT_DIR"; then umount "$MOUNT_DIR" fi if [ -n "$LOOP" ]; then losetup -d "$LOOP" fi rmdir "$MOUNT_DIR" 2>/dev/null || true } trap cleanup EXIT LOOP=$(losetup --find --show --partscan "$IMAGE") ROOT_PARTITION="${LOOP}p2" for _attempt in $(seq 1 20); do [ -b "$ROOT_PARTITION" ] && break sleep 0.25 done [ -b "$ROOT_PARTITION" ] mount -o rw "$ROOT_PARTITION" "$MOUNT_DIR" [ -x "$MOUNT_DIR/usr/sbin/sshd" ] [ -x "$MOUNT_DIR/usr/bin/sudo" ] [ -x "$MOUNT_DIR/usr/sbin/visudo" ] [ -f "$MOUNT_DIR/lib/systemd/system/ssh.service" ] install -D -m 0644 "$UNIT" "$MOUNT_DIR/etc/systemd/system/matrix-image-firstboot.service" install -D -m 0644 "$SSH_CONFIG" "$MOUNT_DIR/etc/ssh/sshd_config.d/10-walnutpi-screen-hardening.conf" install -d -m 0755 "$MOUNT_DIR/etc/systemd/system/multi-user.target.wants" ln -sfn ../matrix-image-firstboot.service \ "$MOUNT_DIR/etc/systemd/system/multi-user.target.wants/matrix-image-firstboot.service" systemctl --root="$MOUNT_DIR" unmask ssh.service systemctl --root="$MOUNT_DIR" enable ssh.service # The exported image must not clone identity or network state from the baseline. find "$MOUNT_DIR/etc/NetworkManager/system-connections" -mindepth 1 -maxdepth 1 -type f -delete 2>/dev/null || true find "$MOUNT_DIR/var/lib/NetworkManager" -mindepth 1 -maxdepth 1 -type f -delete 2>/dev/null || true rm -f -- "$MOUNT_DIR"/etc/ssh/ssh_host_* "$MOUNT_DIR/etc/machine-id" : > "$MOUNT_DIR/etc/machine-id" rm -f -- "$MOUNT_DIR/var/lib/dbus/machine-id" ln -sfn /etc/machine-id "$MOUNT_DIR/var/lib/dbus/machine-id" PYTHONPATH="$SCRIPT_ROOT" python3 "$SCRIPT_ROOT/scripts/image_bootstrap_payload.py" stage \ --root "$MOUNT_DIR" --bundle "$APP_BUNDLE" --dependency "$KERNEL_DEPENDENCY" >/dev/null sync umount "$MOUNT_DIR" losetup -d "$LOOP" LOOP= printf '%s\n' 'rootfs bootstrap installed'