4325590686
Includes: init (PID 1), hiperiso-lib.sh, qemu_launch.sh, hw_collect.sh, kvm_check.sh, fallback_boot.sh, log_flush.sh, conf_replace.sh, make_floppy.sh. 13-phase boot timing, 18 QEMU HMP commands, network pcap capture.
271 lines
9.2 KiB
Bash
Executable File
271 lines
9.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# ============================================================
|
|
# init -- PID 1 for the hiperiso hypervisor host initramfs
|
|
#
|
|
# Boots a selected ISO as a KVM guest with full bootlogging.
|
|
# Kernel cmdline parameters (see INTERFACES.sh):
|
|
# hiperiso_iso="/ISOs/ubuntu.iso"
|
|
# hiperiso_log="/hiperiso/logs/ubuntu/"
|
|
# hiperiso_trace_level="standard|detailed|full|none"
|
|
# hiperiso_ram=2048 hiperiso_cpus=2
|
|
# hiperiso_display="none|gtk|vnc"
|
|
# hiperiso_vga="std|none|virtio"
|
|
# hiperiso_fallback="1"
|
|
# ============================================================
|
|
|
|
PATH="/usr/bin:/bin:/usr/sbin:/sbin"
|
|
export PATH
|
|
|
|
# ── Step 1: Mount essential virtual filesystems ──────────────
|
|
mkdir -p /proc /sys /dev /tmp /run
|
|
|
|
mount -t proc proc /proc 2>/dev/null
|
|
mount -t sysfs sysfs /sys 2>/dev/null
|
|
mount -t devtmpfs devtmpfs /dev 2>/dev/null || mount -t tmpfs tmpfs /dev 2>/dev/null
|
|
mount -t tmpfs tmpfs /tmp 2>/dev/null
|
|
mount -t tmpfs tmpfs /run 2>/dev/null
|
|
|
|
. /hiperiso-lib.sh
|
|
|
|
_INIT_UPTIME=$(cut -d' ' -f1 /proc/uptime 2>/dev/null)
|
|
|
|
printf '\n'
|
|
printf '======================================================\n'
|
|
printf ' hiperiso hypervisor host -- KVM ISO boot logger \n'
|
|
printf '======================================================\n'
|
|
printf '\n'
|
|
|
|
# ── Step 2: Parse kernel command line ────────────────────────
|
|
hiperiso_parse_cmdline
|
|
|
|
if [ -z "$HIPERISO_ISO_PATH" ]; then
|
|
printf '[hiperiso] FATAL: hiperiso_iso= not set on kernel command line\n'
|
|
printf '[hiperiso] Dropping to recovery shell\n'
|
|
exec /bin/sh
|
|
fi
|
|
|
|
hiperiso_log "ISO path: $HIPERISO_ISO_PATH"
|
|
hiperiso_log "Log dir: $HIPERISO_LOG_DIR"
|
|
hiperiso_log "Trace: ${HIPERISO_TRACE_LEVEL:-standard}"
|
|
hiperiso_log "RAM: ${HIPERISO_GUEST_RAM:-2048} MB"
|
|
hiperiso_log "CPUs: ${HIPERISO_GUEST_CPUS:-2}"
|
|
|
|
# ── Step 3: Find and mount the USB data partition ────────────
|
|
DATA_PART=$(hiperiso_find_usb_partition)
|
|
if [ -z "$DATA_PART" ]; then
|
|
hiperiso_log "FATAL: Could not find hiperiso USB data partition"
|
|
hiperiso_log "Scanned: blkid label, /dev/sd[abcd]2, sysfs"
|
|
exec /bin/sh
|
|
fi
|
|
hiperiso_log "Data partition: $DATA_PART"
|
|
|
|
mkdir -p "$DATA_MOUNT"
|
|
_mounted=0
|
|
for _fstype in exfat ntfs3 ntfs vfat ext4 ext3 ext2; do
|
|
if mount -t "$_fstype" "$DATA_PART" "$DATA_MOUNT" 2>/dev/null; then
|
|
hiperiso_log "Mounted $DATA_PART at $DATA_MOUNT (type: $_fstype)"
|
|
_mounted=1
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ "$_mounted" -eq 0 ]; then
|
|
if mount "$DATA_PART" "$DATA_MOUNT" 2>/dev/null; then
|
|
hiperiso_log "Mounted $DATA_PART at $DATA_MOUNT (auto-detected)"
|
|
_mounted=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$_mounted" -eq 0 ]; then
|
|
hiperiso_log "FATAL: Failed to mount $DATA_PART"
|
|
exec /bin/sh
|
|
fi
|
|
|
|
# ── Step 4: Mount the EFI System Partition (for OVMF) ────────
|
|
ESP_PART=$(printf '%s' "$DATA_PART" | sed 's/1$/2/')
|
|
|
|
if [ ! -e "$ESP_PART" ]; then
|
|
for _d in /dev/sda2 /dev/sdb2 /dev/sdc2 /dev/sdd2 /dev/sde2 /dev/sdf2 /dev/nvme0n1p2 /dev/nvme1n1p2 /dev/mmcblk0p2; do
|
|
if [ -e "$_d" ]; then
|
|
ESP_PART="$_d"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
mkdir -p "$EFI_MOUNT"
|
|
if mount -t vfat "$ESP_PART" "$EFI_MOUNT" 2>/dev/null; then
|
|
hiperiso_log "Mounted ESP $ESP_PART at $EFI_MOUNT"
|
|
else
|
|
hiperiso_log "WARNING: Could not mount ESP $ESP_PART -- OVMF may be unavailable"
|
|
fi
|
|
|
|
# ── Step 5: Resolve absolute paths and create log dir ────────
|
|
# Derive a unique per-session directory with UTC timestamp so
|
|
# every boot gets its own log set (no overwriting).
|
|
HIPERISO_LOG_DIR=$(hiperiso_derive_session_dir "$HIPERISO_LOG_DIR")
|
|
export HIPERISO_LOG_DIR
|
|
|
|
LOG_DIR="${DATA_MOUNT}${HIPERISO_LOG_DIR}"
|
|
ISO_PATH="${DATA_MOUNT}${HIPERISO_ISO_PATH}"
|
|
OVMF_FULL_PATH="${EFI_MOUNT}${OVMF_PATH}"
|
|
|
|
# Collision-safe: if session dir already exists (e.g. same-second boot),
|
|
# append an incrementing suffix so logs are never overwritten.
|
|
if [ -d "$LOG_DIR" ]; then
|
|
_i=2
|
|
while [ -d "${LOG_DIR%/}_${_i}" ]; do
|
|
_i=$((_i + 1))
|
|
done
|
|
LOG_DIR="${LOG_DIR%/}_${_i}/"
|
|
HIPERISO_LOG_DIR="${HIPERISO_LOG_DIR%/}_${_i}/"
|
|
fi
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
export LOG_DIR ISO_PATH OVMF_FULL_PATH EFI_MOUNT DATA_MOUNT
|
|
|
|
# ── Record early timing marks retroactively ──────────────────
|
|
# These phases elapsed before LOG_DIR existed; capture them now
|
|
# using the uptime values saved at each checkpoint.
|
|
printf 'kernel_start\t%s\t%s\n' "${_INIT_UPTIME:-0}" "$(hiperiso_utc_iso)" >> "${LOG_DIR}/timing.dat"
|
|
hiperiso_timing_mark "session_created"
|
|
|
|
hiperiso_log "Session dir: $HIPERISO_LOG_DIR"
|
|
|
|
# ── Step 6: Write session metadata and environment snapshot ──
|
|
hiperiso_write_session_meta "started"
|
|
hiperiso_write_status "running" "mounted"
|
|
hiperiso_write_env
|
|
hiperiso_timing_mark "env_written"
|
|
|
|
# ── Step 7: KVM detection ────────────────────────────────────
|
|
KVM_RESULT=$(/kvm_check.sh)
|
|
printf 'KVM_CHECK_RESULT=%s\n' "$KVM_RESULT" >> "${LOG_DIR}/env.txt"
|
|
|
|
case "$KVM_RESULT" in
|
|
KVM_OK)
|
|
hiperiso_log "KVM available -- proceeding with hypervisor boot"
|
|
export KVM_AVAILABLE=1
|
|
export KVM_STATUS="available"
|
|
hiperiso_write_status "running" "kvm_ok"
|
|
;;
|
|
KVM_FAIL:*)
|
|
hiperiso_log "KVM check failed: ${KVM_RESULT#KVM_FAIL:}"
|
|
export KVM_AVAILABLE=0
|
|
export KVM_STATUS="unavailable"
|
|
if [ "$HIPERISO_FALLBACK" != "1" ]; then
|
|
hiperiso_write_status "failed" "fallback_no_kvm"
|
|
/fallback_boot.sh
|
|
exec /bin/sh
|
|
fi
|
|
hiperiso_log "Fallback forced -- continuing with TCG emulation"
|
|
hiperiso_write_status "running" "tcg_emulation"
|
|
;;
|
|
esac
|
|
hiperiso_timing_mark "kvm_checked"
|
|
|
|
# ── Step 8: Verify ISO exists ────────────────────────────────
|
|
if [ ! -f "$ISO_PATH" ]; then
|
|
hiperiso_log "FATAL: ISO file not found: $ISO_PATH"
|
|
hiperiso_log "Contents of $DATA_MOUNT:"
|
|
ls -la "$DATA_MOUNT" 2>/dev/null >> "${LOG_DIR}/env.txt"
|
|
hiperiso_write_status "failed" "iso_not_found"
|
|
hiperiso_run_report
|
|
hiperiso_finalize_session "failed" "" "iso_not_found"
|
|
exec /bin/sh
|
|
fi
|
|
hiperiso_log "ISO found: $ISO_PATH"
|
|
hiperiso_timing_mark "iso_verified"
|
|
|
|
# ── Step 8b: Run conf_replace plugin (if configured) ─────────
|
|
_modified_iso=$(sh /conf_replace.sh 2>"${LOG_DIR}/conf_replace.log" || true)
|
|
if [ -n "$_modified_iso" ] && [ -f "$_modified_iso" ]; then
|
|
ISO_PATH="$_modified_iso"
|
|
export ISO_PATH
|
|
hiperiso_log "Using modified ISO: $ISO_PATH"
|
|
fi
|
|
|
|
# ── Step 9: Start log flush daemon ───────────────────────────
|
|
rm -f /tmp/hiperiso_done
|
|
/log_flush.sh "$LOG_DIR" &
|
|
LOG_FLUSH_PID=$!
|
|
hiperiso_log "Log flush daemon started (PID $LOG_FLUSH_PID)"
|
|
|
|
hiperiso_write_status "running" "launching_qemu"
|
|
hiperiso_timing_mark "qemu_launching"
|
|
|
|
# ── Step 10: Launch QEMU ─────────────────────────────────────
|
|
/qemu_launch.sh
|
|
QEMU_EXIT_CODE=$?
|
|
|
|
# ── Step 11: Flush remaining logs ────────────────────────────
|
|
touch /tmp/hiperiso_done
|
|
hiperiso_timing_mark "qemu_returned"
|
|
|
|
_wait=0
|
|
while kill -0 "$LOG_FLUSH_PID" 2>/dev/null; do
|
|
_wait=$((_wait + 1))
|
|
if [ "$_wait" -gt 10 ]; then
|
|
kill "$LOG_FLUSH_PID" 2>/dev/null
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
sync
|
|
printf 'QEMU_EXIT_CODE=%s\n' "$QEMU_EXIT_CODE" >> "${LOG_DIR}/env.txt"
|
|
|
|
hiperiso_write_status "running" "qemu_exited" "$QEMU_EXIT_CODE"
|
|
|
|
if [ "$QEMU_EXIT_CODE" -eq 0 ]; then
|
|
_session_status="complete"
|
|
_session_stage="session_complete"
|
|
else
|
|
_session_status="failed"
|
|
_session_stage="qemu_error"
|
|
fi
|
|
|
|
hiperiso_run_report
|
|
hiperiso_timing_mark "report_done"
|
|
hiperiso_finalize_session "$_session_status" "$QEMU_EXIT_CODE" "$_session_stage"
|
|
hiperiso_timing_mark "session_finalized"
|
|
hiperiso_timing_write_json
|
|
|
|
# ── Step 12: Print session summary ───────────────────────────
|
|
printf '\n'
|
|
printf '======================================================\n'
|
|
printf ' hiperiso boot session complete \n'
|
|
printf '======================================================\n'
|
|
printf ' ISO: %s\n' "$HIPERISO_ISO_PATH"
|
|
printf ' Session: %s\n' "$(hiperiso_session_id)"
|
|
printf ' QEMU exit: %s\n' "$QEMU_EXIT_CODE"
|
|
printf ' Logs: %s\n' "$LOG_DIR"
|
|
printf '======================================================\n'
|
|
printf '\n'
|
|
printf 'Log files:\n'
|
|
ls -la "$LOG_DIR" 2>/dev/null
|
|
printf '\n'
|
|
|
|
# ── Step 13: Offer reboot ────────────────────────────────────
|
|
printf 'Press ENTER to reboot, or type "shell" for recovery: '
|
|
read -r _response
|
|
|
|
case "$_response" in
|
|
shell|sh)
|
|
printf '\nDropping to recovery shell...\n'
|
|
exec /bin/sh
|
|
;;
|
|
esac
|
|
|
|
printf '\nRebooting...\n'
|
|
sync
|
|
|
|
if command -v reboot >/dev/null 2>&1; then
|
|
reboot -f
|
|
else
|
|
printf 'b' > /proc/sysrq-trigger 2>/dev/null
|
|
fi
|
|
|
|
# Kernel will panic if PID 1 exits -- but reboot should have fired
|
|
exec /bin/sh
|