#!/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