#!/bin/sh
# Phase-1 bootstrap init for the Nucleic Linux base build (docs/LINUX_VM.md §base build).
#
# macOS has no Linux filesystem tooling, so the ext4 root disk is assembled *inside the guest*: this
# runs as PID 1 from a tiny busybox initramfs, formats the raw block device, unpacks the narOS rootfs
# tarball handed in as a raw tar on a second virtio-blk disk, bakes in the first-boot provisioning
# hooks, then powers off. The host then boots phase 2 (the installed rootfs) to provision the desktop
# + toolchain. The guest agents themselves come from the rootfs (their debs), never from here.
#
# Payload delivery is a block device, not virtiofs: modern Ubuntu arm64 kernels ship `virtiofs` as a
# module (absent from this busybox initramfs), whereas `virtio_blk` is built-in.
#
# Everything here is a single static busybox — keep it POSIX sh and busybox-applet only.
set -e
export PATH=/bin:/sbin:/usr/bin:/usr/sbin

log() { echo "[nucleic-bootstrap] $*"; }

# busybox applet symlinks + core pseudo-filesystems.
/bin/busybox --install -s /bin 2>/dev/null || true
mkdir -p /proc /sys /dev /mnt/root /mnt/prov
mount -t proc proc /proc 2>/dev/null || true
mount -t sysfs sysfs /sys 2>/dev/null || true
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true

fail() { log "FATAL: $*"; log "dropping to a shell for diagnosis"; exec /bin/sh; }

# Identify the two virtio-blk disks by content (enumeration order isn't guaranteed): the provisioning
# payload is a raw tar (its first header carries a `ustar` magic at byte 257); the root disk is empty.
log "locating the payload + root disks"
PROV=""; ROOTDISK=""
for d in /dev/vda /dev/vdb /dev/vdc /dev/vdd; do
    [ -b "$d" ] || continue
    if dd if="$d" bs=1 skip=257 count=5 2>/dev/null | grep -q ustar; then
        PROV="$d"
    else
        ROOTDISK="$d"
    fi
done
[ -n "$PROV" ] || fail "no provisioning payload disk (ustar tar) found on any virtio-blk device"
[ -n "$ROOTDISK" ] || fail "no root disk found"
log "payload disk=$PROV root disk=$ROOTDISK"

log "extracting the provisioning payload from $PROV"
tar -x -f "$PROV" -C /mnt/prov || fail "extracting the provisioning payload from $PROV failed"

log "formatting the root disk ($ROOTDISK)"
# busybox provides the `mke2fs` applet (there is no `mkfs.ext2` alias); it makes an ext2 fs that the
# kernel's ext4 driver mounts read/write, which is fine for a disposable clone. Use 4 KiB blocks: at
# the default 1 KiB block size a ~96 GiB disk has tens of thousands of block groups, which is slow and
# fragile; 4 KiB quarters the block count. (A journalled ext4 via a static mke2fs is a documented
# upgrade — see docs/LINUX_VM.md.)
mke2fs -F -b 4096 "$ROOTDISK" || fail "mke2fs $ROOTDISK failed"
mount -t ext2 "$ROOTDISK" /mnt/root || fail "could not mount the new root filesystem"

log "unpacking the root filesystem"
cd /mnt/root
if [ -f /mnt/prov/rootfs.tar.xz ]; then
    unxz < /mnt/prov/rootfs.tar.xz | tar -x || fail "unpacking rootfs.tar.xz failed"
elif [ -f /mnt/prov/rootfs.tar.gz ]; then
    tar -xzf /mnt/prov/rootfs.tar.gz || fail "unpacking rootfs.tar.gz failed"
else
    fail "no rootfs tarball found in the provisioning share"
fi

# Bake the kernel modules matching our external kernel into the rootfs. The cloud rootfs ships none,
# and modern Ubuntu kernels modularize vsock/virtiofs/gpu — without these the agent can't bind vsock
# (the whole control plane) and the desktop has no virtio_gpu. The nucleic-modsetup unit (installed
# below) runs depmod + loads the drivers early on the first boot, before the agent.
if [ -f /mnt/prov/modules.tar.gz ]; then
    log "baking kernel modules into the rootfs"
    tar -xzf /mnt/prov/modules.tar.gz -C /mnt/root || fail "extracting kernel modules failed"
else
    log "WARN: no kernel modules payload — vsock/gpu drivers may be missing"
fi

# The guest agents are NOT installed here: they are baked into the rootfs by their debs from the
# narOS apt pool (os/mkimage/profiles/vm*.naros-pkgs), which is the single source of truth. This
# bootstrap used to overlay a separately-published GHCR build of nucleic-linux-agent (and the
# optional a11y agent) on top, which meant a rootfs could ship one build and boot another. The deb
# also ships the unit at /usr/lib/systemd/system + its own static multi-user.target.wants enable
# symlink, so there is nothing to enable here either.
log "installing the Nucleic provisioning hooks"
mkdir -p /mnt/root/usr/local/bin /mnt/root/usr/local/sbin \
         /mnt/root/etc/systemd/system/multi-user.target.wants \
         /mnt/root/etc/systemd/system/sysinit.target.wants \
         /mnt/root/etc/systemd/network /mnt/root/var/lib/nucleic
# The agent is the host's only way in — fail loudly here rather than 5 minutes later as an opaque
# "guest unreachable" timeout if a rootfs is ever built without it.
[ -x /mnt/root/usr/local/bin/nucleic-linux-agent ] \
    || fail "the rootfs has no /usr/local/bin/nucleic-linux-agent — it must be baked in by the nucleic-linux-agent deb"
# busybox has no `install` applet — use cp + chmod. (0755 for executables, 0644 for units.)
cp /mnt/prov/provision-linux-guest.sh     /mnt/root/usr/local/sbin/provision-linux-guest.sh
chmod 0755                                /mnt/root/usr/local/sbin/provision-linux-guest.sh
cp /mnt/prov/nucleic-firstboot.service    /mnt/root/etc/systemd/system/nucleic-firstboot.service
chmod 0644                                /mnt/root/etc/systemd/system/nucleic-firstboot.service
cp /mnt/prov/nucleic-modsetup.service     /mnt/root/etc/systemd/system/nucleic-modsetup.service
chmod 0644                                /mnt/root/etc/systemd/system/nucleic-modsetup.service
cp /mnt/prov/nucleic-modsetup.sh          /mnt/root/usr/local/sbin/nucleic-modsetup.sh
chmod 0755                                /mnt/root/usr/local/sbin/nucleic-modsetup.sh
cp /mnt/prov/nucleic-bootdebug.service    /mnt/root/etc/systemd/system/nucleic-bootdebug.service
chmod 0644                                /mnt/root/etc/systemd/system/nucleic-bootdebug.service
cp /mnt/prov/nucleic-bootdebug.sh         /mnt/root/usr/local/sbin/nucleic-bootdebug.sh
chmod 0755                                /mnt/root/usr/local/sbin/nucleic-bootdebug.sh
# Host-requested verbose boot diagnostics (docs/LINUX_VM.md §Debugging a failed base build): the
# marker makes nucleic-bootdebug emit its full snapshot (+ journal tail) even on healthy boots.
if [ -f /mnt/prov/nucleic-debug ]; then
    touch /mnt/root/etc/nucleic-debug
fi
if [ -f /mnt/prov/nucleic-provision.env ]; then
    cp /mnt/prov/nucleic-provision.env /mnt/root/etc/nucleic-provision.env
    chmod 0644 /mnt/root/etc/nucleic-provision.env
fi
# The AT-SPI semantic agent (vsock 2036) and the Mutter geometry helper GNOME Shell extension are
# likewise rootfs-baked, not overlaid: the desktop flavor pulls them in via nucleic-a11y-agent and
# naros-desktop-config (os/mkimage/profiles/vm-desktop.naros-pkgs). The headless flavor has no
# graphical session, so it ships without them and the host falls back to screenshot + pixels.

# Enable: module setup EARLY (sysinit, before the agent), then first-boot provisioning (removes
# itself when done) + the boot-health snapshot (serial-console diagnostics). The agent enables
# itself — its deb ships a static multi-user.target.wants symlink.
ln -sf ../nucleic-modsetup.service    /mnt/root/etc/systemd/system/sysinit.target.wants/nucleic-modsetup.service
ln -sf ../nucleic-firstboot.service   /mnt/root/etc/systemd/system/multi-user.target.wants/nucleic-firstboot.service
ln -sf ../nucleic-bootdebug.service   /mnt/root/etc/systemd/system/multi-user.target.wants/nucleic-bootdebug.service

# Root fstab (the ext4 driver mounts the ext2 image); the session workspace share is mounted lazily by
# the provisioner/agent, not here.
cat > /mnt/root/etc/fstab <<EOF
/dev/vda / ext4 defaults 0 1
EOF

# NAT DHCP so phase-2 apt has network (the cloud rootfs uses systemd-networkd).
cat > /mnt/root/etc/systemd/network/10-nucleic-nat.network <<EOF
[Match]
Name=en* eth*
[Network]
DHCP=yes
EOF
mkdir -p /mnt/root/etc/systemd/system/multi-user.target.wants
ln -sf /lib/systemd/system/systemd-networkd.service \
       /mnt/root/etc/systemd/system/multi-user.target.wants/systemd-networkd.service 2>/dev/null || true

log "syncing"
cd /
sync
# /mnt/prov is a tar we untarred, not a mount (the payload rides a block device now) — nothing to
# unmount there; only the root fs needs unmounting before poweroff.
umount /mnt/root || true
log "done — powering off"
poweroff -f
