Boil iso-boot down to its essence
This commit is contained in:
1 parent
84dec181e1
commit
9d0faa4c58
1 file changed
+25
-324
+25
-324
@@ -2,331 +2,32 @@
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: omarchy-iso-boot [release/omarchy.iso]"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Function to print colored messages
|
||||
print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
||||
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
print_info() { echo -e "[INFO] $1"; }
|
||||
if ! pacman -Q qemu-full >/dev/null || ! pacman -Q edk2-ovmf >/dev/null; then
|
||||
sudo pacman -Sy --noconfirm --needed --quiet qemu-full edk2-ovmf
|
||||
fi
|
||||
|
||||
# Function to find OVMF firmware files on Arch Linux
|
||||
find_ovmf_firmware() {
|
||||
local firmware_type="$1" # CODE or VARS
|
||||
DISK="/tmp/omarchy-iso-boot.qcow2"
|
||||
[ -f "$DISK" ] || qemu-img create -f qcow2 "$DISK" 20G
|
||||
|
||||
# Arch Linux OVMF paths (from edk2-ovmf package)
|
||||
local ovmf_paths=(
|
||||
"/usr/share/edk2/x64/OVMF_${firmware_type}.4m.fd"
|
||||
"/usr/share/edk2-ovmf/x64/OVMF_${firmware_type}.fd"
|
||||
"/usr/share/ovmf/x64/OVMF_${firmware_type}.4m.fd"
|
||||
)
|
||||
cp /usr/share/edk2/x64/OVMF_VARS.4m.fd /tmp/OVMF_VARS.4m.fd
|
||||
|
||||
for path in "${ovmf_paths[@]}"; do
|
||||
if [ -f "$path" ]; then
|
||||
echo "$path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to check and install Arch Linux dependencies
|
||||
check_requirements() {
|
||||
local errors=0
|
||||
local packages_to_install=()
|
||||
|
||||
# Check for QEMU
|
||||
if ! pacman -Qi qemu-full &>/dev/null && ! pacman -Qi qemu-system-x86 &>/dev/null; then
|
||||
print_warning "QEMU is not installed"
|
||||
packages_to_install+=("qemu-full")
|
||||
else
|
||||
print_success "QEMU is installed"
|
||||
fi
|
||||
|
||||
# Check for OVMF firmware
|
||||
if ! pacman -Qi edk2-ovmf &>/dev/null; then
|
||||
print_warning "OVMF UEFI firmware is not installed"
|
||||
packages_to_install+=("edk2-ovmf")
|
||||
else
|
||||
print_success "OVMF firmware is installed"
|
||||
fi
|
||||
|
||||
# Install missing packages
|
||||
if [ ${#packages_to_install[@]} -gt 0 ]; then
|
||||
print_info "Installing missing packages: ${packages_to_install[*]}"
|
||||
sudo pacman -S --noconfirm --needed "${packages_to_install[@]}"
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to install required packages"
|
||||
((errors++))
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for KVM support
|
||||
if [ ! -e /dev/kvm ]; then
|
||||
print_warning "KVM is not available. VM will run without hardware acceleration (slower)"
|
||||
print_info "To enable KVM:"
|
||||
print_info " 1. Ensure virtualization is enabled in BIOS"
|
||||
print_info " 2. Load KVM modules: sudo modprobe kvm kvm_intel (or kvm_amd)"
|
||||
KVM_AVAILABLE=false
|
||||
else
|
||||
if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
|
||||
print_warning "KVM permissions issue. Add user to kvm group: sudo usermod -a -G kvm $USER"
|
||||
KVM_AVAILABLE=false
|
||||
else
|
||||
KVM_AVAILABLE=true
|
||||
print_success "KVM hardware acceleration is available"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find OVMF firmware files
|
||||
OVMF_CODE=$(find_ovmf_firmware "CODE")
|
||||
if [ -z "$OVMF_CODE" ]; then
|
||||
print_error "Could not find OVMF CODE firmware"
|
||||
print_info "Install with: sudo pacman -S edk2-ovmf"
|
||||
((errors++))
|
||||
else
|
||||
print_success "Found OVMF CODE at: $OVMF_CODE"
|
||||
fi
|
||||
|
||||
OVMF_VARS=$(find_ovmf_firmware "VARS")
|
||||
if [ -z "$OVMF_VARS" ]; then
|
||||
# On Arch, VARS might not exist separately, use CODE
|
||||
OVMF_VARS="$OVMF_CODE"
|
||||
print_info "Using OVMF CODE for VARS"
|
||||
else
|
||||
print_success "Found OVMF VARS at: $OVMF_VARS"
|
||||
fi
|
||||
|
||||
return $errors
|
||||
}
|
||||
|
||||
# Function to setup storage
|
||||
setup_storage() {
|
||||
local storage_dir="${STORAGE_DIR:-/tmp}"
|
||||
|
||||
if [ ! -d "$storage_dir" ]; then
|
||||
print_error "Storage directory does not exist: $storage_dir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$storage_dir/test.qcow2" ]; then
|
||||
print_info "Creating virtual disk at $storage_dir/test.qcow2..."
|
||||
qemu-img create -f qcow2 "$storage_dir/test.qcow2" 20G
|
||||
else
|
||||
print_info "Using existing disk at $storage_dir/test.qcow2"
|
||||
fi
|
||||
|
||||
if [ ! -f "$storage_dir/test_large.qcow2" ]; then
|
||||
print_info "Creating second virtual disk at $storage_dir/test_large.qcow2..."
|
||||
qemu-img create -f qcow2 "$storage_dir/test_large.qcow2" 20G
|
||||
else
|
||||
print_info "Using existing disk at $storage_dir/test_large.qcow2"
|
||||
fi
|
||||
|
||||
DISK1="$storage_dir/test.qcow2"
|
||||
DISK2="$storage_dir/test_large.qcow2"
|
||||
}
|
||||
|
||||
# Function to build QEMU command
|
||||
build_qemu_command() {
|
||||
local iso_file="$1"
|
||||
local qemu_args=()
|
||||
|
||||
# Basic configuration
|
||||
qemu_args+=("qemu-system-x86_64")
|
||||
|
||||
# CPU and acceleration
|
||||
if [ "$KVM_AVAILABLE" = true ]; then
|
||||
qemu_args+=("-cpu" "host")
|
||||
qemu_args+=("-enable-kvm")
|
||||
qemu_args+=("-machine" "q35,accel=kvm")
|
||||
else
|
||||
qemu_args+=("-cpu" "qemu64")
|
||||
qemu_args+=("-machine" "q35")
|
||||
fi
|
||||
|
||||
# Memory
|
||||
local total_mem=$(free -m | awk '/^Mem:/{print $2}')
|
||||
local vm_mem="${MEMORY:-8192}"
|
||||
if [ "$total_mem" -lt 10240 ] && [ "$vm_mem" -gt 4096 ]; then
|
||||
vm_mem=4096
|
||||
print_warning "Limited system memory. Using ${vm_mem}MB for VM"
|
||||
fi
|
||||
qemu_args+=("-m" "$vm_mem")
|
||||
|
||||
# UEFI firmware (unless BIOS mode requested)
|
||||
if [ -n "$OVMF_CODE" ] && [ "$BOOT_MODE" != "bios" ]; then
|
||||
# Persist firmaware as well if $STORAGE_DIR is specified
|
||||
if [ -z "$STORAGE_DIR" ]; then
|
||||
# Create writable VARS file from the correct template
|
||||
OVMF_VARS_COPY="/tmp/OVMF_VARS_$$.fd"
|
||||
if [ -f "$OVMF_VARS" ]; then
|
||||
cp "$OVMF_VARS" "$OVMF_VARS_COPY"
|
||||
else
|
||||
# Fallback: create empty VARS file if template not found
|
||||
dd if=/dev/zero of="$OVMF_VARS_COPY" bs=1M count=4 2>/dev/null
|
||||
fi
|
||||
else
|
||||
OVMF_VARS_COPY="$STORAGE_DIR/OVMF_VARS.fd"
|
||||
|
||||
# Only create firmaware file if it doesn't exist to allow persistence
|
||||
if [ ! -f "$OVMF_VARS_COPY" ]; then
|
||||
if [ -f "$OVMF_VARS" ]; then
|
||||
cp "$OVMF_VARS" "$OVMF_VARS_COPY"
|
||||
else
|
||||
# Fallback: create empty VARS file if template not found
|
||||
dd if=/dev/zero of="$OVMF_VARS_COPY" bs=1M count=4 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
qemu_args+=("-drive" "if=pflash,format=raw,readonly=on,file=$OVMF_CODE")
|
||||
qemu_args+=("-drive" "if=pflash,format=raw,file=$OVMF_VARS_COPY")
|
||||
fi
|
||||
|
||||
# Storage devices - Smart boot order that handles both installation and post-install
|
||||
# Credits to Ryan Hughes for this elegant solution:
|
||||
# - Empty disk (bootindex=1) fails to boot -> falls back to ISO (bootindex=2)
|
||||
# - After installation, disk is bootable -> boots from disk automatically
|
||||
# This achieves David's goal without any complex monitoring!
|
||||
qemu_args+=("-drive" "file=$DISK1,format=qcow2,if=none,id=drive0")
|
||||
qemu_args+=("-device" "virtio-blk-pci,drive=drive0,bootindex=1")
|
||||
|
||||
qemu_args+=("-drive" "file=$DISK2,format=qcow2,if=none,id=drive1")
|
||||
qemu_args+=("-device" "virtio-blk-pci,drive=drive1,bootindex=3")
|
||||
|
||||
# CD-ROM with ISO - set as second boot device (fallback)
|
||||
qemu_args+=("-drive" "file=$iso_file,media=cdrom,if=none,format=raw,id=cdrom0")
|
||||
qemu_args+=("-device" "ide-cd,drive=cdrom0,bootindex=2")
|
||||
|
||||
qemu_args+=("-device" "virtio-vga-gl")
|
||||
qemu_args+=("-display" "gtk,gl=on")
|
||||
|
||||
# Input devices
|
||||
qemu_args+=("-usb" "-device" "usb-tablet")
|
||||
|
||||
# Network
|
||||
qemu_args+=("-netdev" "user,id=net0")
|
||||
qemu_args+=("-device" "virtio-net-pci,netdev=net0")
|
||||
|
||||
echo "${qemu_args[@]}"
|
||||
}
|
||||
|
||||
# Function to show usage
|
||||
show_usage() {
|
||||
echo "Omarchy ISO Boot Tool - Arch Linux"
|
||||
echo ""
|
||||
echo "Usage: $0 <image.iso> [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --bios Force BIOS boot mode (default: UEFI)"
|
||||
echo " --storage DIR Directory for VM storage (default: /tmp)"
|
||||
echo " --memory MB Memory allocation in MB (default: 8192)"
|
||||
echo " --no-kvm Disable KVM acceleration"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 omarchy.iso"
|
||||
echo " $0 omarchy.iso --memory 4096"
|
||||
echo " $0 omarchy.iso --bios --storage ~/vms"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
print_info "Omarchy ISO Boot Tool for Arch Linux"
|
||||
echo "======================================"
|
||||
|
||||
# Parse arguments
|
||||
if [ $# -eq 0 ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
|
||||
show_usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ISO_FILE="$1"
|
||||
shift
|
||||
|
||||
# Check if ISO exists
|
||||
if [ ! -f "$ISO_FILE" ]; then
|
||||
print_error "ISO file not found: $ISO_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "ISO file: $ISO_FILE ($(du -h "$ISO_FILE" | cut -f1))"
|
||||
|
||||
# Parse additional options
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--bios)
|
||||
BOOT_MODE="bios"
|
||||
print_info "Using BIOS boot mode"
|
||||
;;
|
||||
--storage)
|
||||
STORAGE_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
--memory)
|
||||
MEMORY="$2"
|
||||
shift
|
||||
;;
|
||||
--no-kvm)
|
||||
KVM_AVAILABLE=false
|
||||
print_info "KVM acceleration disabled by user"
|
||||
;;
|
||||
*)
|
||||
print_warning "Unknown option: $1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Check system requirements
|
||||
print_info "Checking system requirements..."
|
||||
if ! check_requirements; then
|
||||
print_error "System requirements not met"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setup storage
|
||||
print_info "Setting up storage..."
|
||||
setup_storage
|
||||
|
||||
print_info "Boot order: Disk (if bootable) -> ISO (fallback)"
|
||||
print_info "After installation, system will automatically boot from disk"
|
||||
|
||||
# Build QEMU command
|
||||
QEMU_CMD=$(build_qemu_command "$ISO_FILE")
|
||||
|
||||
# Show command for debugging
|
||||
print_info "QEMU command:"
|
||||
echo " $QEMU_CMD" | fold -s -w 80 | sed '2,$s/^/ /'
|
||||
echo ""
|
||||
|
||||
print_success "Starting VM... (Press Ctrl-A X to exit)"
|
||||
echo "======================================"
|
||||
|
||||
# Execute QEMU
|
||||
eval $QEMU_CMD
|
||||
|
||||
# Cleanup
|
||||
if [ -f "$OVMF_VARS_COPY" ]; then
|
||||
rm -f "$OVMF_VARS_COPY"
|
||||
fi
|
||||
}
|
||||
|
||||
# Cleanup on exit
|
||||
cleanup() {
|
||||
if [ -f "$OVMF_VARS_COPY" ]; then
|
||||
rm -f "$OVMF_VARS_COPY"
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
qemu-system-x86_64 \
|
||||
-cpu host -enable-kvm -machine q35,accel=kvm \
|
||||
-smp "$(nproc)" \
|
||||
-m "$(free -m | awk '/^Mem:/{print $4}')" \
|
||||
-drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
|
||||
-drive if=pflash,format=raw,file=/tmp/OVMF_VARS.4m.fd \
|
||||
-drive file="$DISK",format=qcow2,if=none,id=drive0 \
|
||||
-device virtio-blk-pci,drive=drive0,bootindex=1 \
|
||||
-drive file="$1",media=cdrom,if=none,format=raw,id=cdrom0 \
|
||||
-device ide-cd,drive=cdrom0,bootindex=2 \
|
||||
-device virtio-vga-gl \
|
||||
-display gtk,gl=on \
|
||||
-usb -device usb-tablet \
|
||||
-netdev user,id=net0 \
|
||||
-device virtio-net-pci,netdev=net0
|
||||
Reference in new issue
Block a user