#!/bin/sh
# Minimal init for raw QEMU boot path.
#
# Two modes, auto-detected:
#
#   9p mode (default):
#     Mounts host filesystem via 9p, chroots in, runs the test command.
#     Exit code propagated via writable 9p results share.
#     Expects: hostroot (9p share), results (9p share), /mnt/results/cmd
#
#   Rootfs mode (RHEL kernels without 9p):
#     Mounts a virtio-blk disk image containing all binaries, libs,
#     and test scripts. No 9p needed. Exit code printed to serial
#     as a marker line for the host to parse.
#     Expects: /dev/vda (ext4 disk image), /cmd (in initramfs overlay)
#
# Mode detection: /dev/vda present → rootfs mode, else 9p mode.

# Step 1: essential filesystems
echo "[init] starting"
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo "[init] filesystems mounted"

# Step 2: load modules if present
# The boot layer appends kernel-specific .ko files at /modules/ with
# a load_order file specifying dependency-first sequence.
if [ -d /modules ] && [ -f /modules/load_order ]; then
    echo "[init] loading modules..."
    while read -r mod; do
        if [ -f "/modules/${mod}.ko" ]; then
            insmod "/modules/${mod}.ko" 2>&1 || echo "[init] WARN: insmod ${mod}.ko failed"
        fi
    done < /modules/load_order
    echo "[init] modules loaded"
elif [ -d /modules ]; then
    # Fallback: try all .ko files (may fail on dep order)
    for mod in /modules/*.ko; do
        [ -f "$mod" ] && insmod "$mod" 2>/dev/null
    done
fi

# Step 3: detect mode
echo "[init] checking for /dev/vda..."
ls -la /dev/vd* 2>/dev/null || echo "[init] no /dev/vd* devices found"
if [ -b /dev/vda ]; then
    # ===== Rootfs disk mode (RHEL kernels without 9p) =====
    echo "[init] rootfs mode: mounting /dev/vda"

    mkdir -p /mnt/rootfs
    mount -o ro /dev/vda /mnt/rootfs
    if [ $? -ne 0 ]; then
        echo "FATAL: failed to mount rootfs disk /dev/vda" >&2
        poweroff -f
    fi

    # Writable overlays (tests write to /tmp for loop devices)
    mount -t tmpfs tmpfs /mnt/rootfs/tmp
    mount -t tmpfs tmpfs /mnt/rootfs/run
    mount -t tmpfs tmpfs /mnt/rootfs/var/tmp 2>/dev/null

    # Guest needs its own /dev, /proc, /sys inside the chroot
    mount -t devtmpfs devtmpfs /mnt/rootfs/dev
    mkdir -p /mnt/rootfs/dev/pts
    mount -t devpts devpts /mnt/rootfs/dev/pts
    mount -t proc proc /mnt/rootfs/proc
    mount -t sysfs sysfs /mnt/rootfs/sys

    # Read command (from initramfs overlay, or default)
    if [ -f /cmd ]; then
        CMD=$(cat /cmd)
    else
        CMD="/test/guest-run-all.sh"
    fi

    # Run it inside the chroot (output goes to serial console)
    if [ "$CMD" = "__INTERACTIVE__" ]; then
        chroot /mnt/rootfs /test/guest-interactive.sh 2>&1
        echo "===QUOTATOOL_EXIT:0==="
    else
        echo "[init] chroot: running $CMD"
        chroot /mnt/rootfs /bin/bash -c "export PATH=/bin:/sbin:/usr/bin:/usr/sbin; $CMD" 2>&1
        EXIT_CODE=$?
        echo "===QUOTATOOL_EXIT:${EXIT_CODE}==="
    fi

    poweroff -f
fi

# ===== 9p mode (default) =====

# Step 3b: mount host root via 9p
# Read-write to match vng behavior (CoW overlay). Tests only write to
# /tmp and loop devices, so host files are not modified in practice.
mkdir -p /mnt/host
mount -t 9p -o trans=virtio,version=9p2000.L,msize=524288 hostroot /mnt/host
if [ $? -ne 0 ]; then
    # Try without msize (older kernels may not support it)
    mount -t 9p -o trans=virtio,version=9p2000.L hostroot /mnt/host
    if [ $? -ne 0 ]; then
        echo "FATAL: 9p mount failed — check kernel has 9P_FS support" >&2
        poweroff -f
    fi
fi

# Step 4: mount results share (writable)
mkdir -p /mnt/results
mount -t 9p -o trans=virtio,version=9p2000.L,msize=524288 results /mnt/results 2>/dev/null \
    || mount -t 9p -o trans=virtio,version=9p2000.L results /mnt/results

# Step 5: overlay writable areas on top of the read-only host mount
mount -t tmpfs tmpfs /mnt/host/tmp
mount -t tmpfs tmpfs /mnt/host/run
mount -t tmpfs tmpfs /mnt/host/var/tmp 2>/dev/null

# Guest needs its own /dev, /proc, /sys inside the chroot
mount -t devtmpfs devtmpfs /mnt/host/dev
mkdir -p /mnt/host/dev/pts
mount -t devpts devpts /mnt/host/dev/pts
mount -t proc proc /mnt/host/proc
mount -t sysfs sysfs /mnt/host/sys

# Step 6: read the command
if [ ! -f /mnt/results/cmd ]; then
    echo "FATAL: no command file at /mnt/results/cmd" >&2
    echo "1" > /mnt/results/exit_code
    poweroff -f
fi
CMD=$(cat /mnt/results/cmd)

# Step 7: run it inside the chroot
if [ "$CMD" = "__INTERACTIVE__" ]; then
    # Interactive mode: run setup, then drop to shell on serial console
    SETUP_PATH=$(cat /mnt/results/setup_path 2>/dev/null || true)
    if [ -n "$SETUP_PATH" ]; then
        chroot /mnt/host "$SETUP_PATH" 2>&1
    else
        chroot /mnt/host /bin/bash --norc --noprofile -i 2>&1
    fi
    echo "0" > /mnt/results/exit_code
else
    # Normal mode: capture output to files
    chroot /mnt/host /bin/sh -c "$CMD" > /mnt/results/stdout 2>&1
    EXIT_CODE=$?
    echo "$EXIT_CODE" > /mnt/results/exit_code
fi

# Done
poweroff -f
