Redo backend installer logic to support BIOS/MBR boot on older devices and switch to GRUB2
This commit is contained in:
@@ -128,123 +128,97 @@ def ensure_unmounted(disk_device):
|
|||||||
logger.warning(f"Error during pre-partition unmount: {e}")
|
logger.warning(f"Error during pre-partition unmount: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def is_uefi():
|
||||||
|
"""Checks if the system is booted in UEFI mode."""
|
||||||
|
return os.path.exists("/sys/firmware/efi")
|
||||||
|
|
||||||
|
|
||||||
def auto_partition_disk(disk_device):
|
def auto_partition_disk(disk_device):
|
||||||
"""
|
"""
|
||||||
Automatically partitions the disk:
|
Automatically partitions the disk based on boot mode:
|
||||||
1. EFI System Partition (2GB standard, 1GB small)
|
UEFI (GPT): ESP (1GB), Root (Remaining), Swap (RAM+2GB)
|
||||||
2. Root (Remaining)
|
BIOS (MBR): Root (Remaining, Bootable), Swap (RAM+2GB)
|
||||||
3. Swap (RAM + 2GB, or 0 if small)
|
|
||||||
|
|
||||||
Layout: P1=EFI, P3=Swap (End), P2=Root (Middle)
|
|
||||||
"""
|
"""
|
||||||
logger.info(f"Starting auto-partitioning on {disk_device}")
|
uefi = is_uefi()
|
||||||
log_disk_operation("PARTITION", "start", f"Disk: {disk_device}")
|
logger.info(f"Starting auto-partitioning on {disk_device} (UEFI: {uefi})")
|
||||||
|
log_disk_operation("PARTITION", "start", f"Disk: {disk_device}, UEFI: {uefi}")
|
||||||
|
|
||||||
# 0. Ensure unmounted
|
|
||||||
ensure_unmounted(disk_device)
|
ensure_unmounted(disk_device)
|
||||||
|
|
||||||
# Calculate sizes
|
|
||||||
disk_size = get_disk_size(disk_device)
|
disk_size = get_disk_size(disk_device)
|
||||||
ram_size = get_total_memory()
|
ram_size = get_total_memory()
|
||||||
|
|
||||||
# Defaults
|
# Calculate sizes
|
||||||
efi_mb = 2048
|
|
||||||
swap_mb = int((ram_size / (1024 * 1024)) + 2048)
|
swap_mb = int((ram_size / (1024 * 1024)) + 2048)
|
||||||
min_root_mb = 10240 # 10GB
|
# Cap swap at 16GB for sanity on large RAM systems unless disk is huge
|
||||||
|
if disk_size < 100 * 1024**3: # < 100GB
|
||||||
|
swap_mb = min(swap_mb, 4096)
|
||||||
|
|
||||||
total_required_mb = efi_mb + swap_mb + min_root_mb
|
|
||||||
disk_mb = disk_size / (1024 * 1024)
|
disk_mb = disk_size / (1024 * 1024)
|
||||||
|
use_swap = disk_mb > (10240 + swap_mb) # Only use swap if we have at least 10GB for root
|
||||||
|
|
||||||
use_swap = True
|
if uefi:
|
||||||
|
# GPT Layout
|
||||||
if disk_mb < total_required_mb:
|
logger.info("Using GPT layout for UEFI")
|
||||||
logger.warning("Disk too small for standard layout. Adjusting...")
|
|
||||||
efi_mb = 1024
|
|
||||||
use_swap = False
|
|
||||||
|
|
||||||
# Check minimal viability
|
|
||||||
if disk_mb < (efi_mb + min_root_mb):
|
|
||||||
raise Exception("Disk too small for installation (Need ~11GB)")
|
|
||||||
|
|
||||||
# 1. Zap the disk (destroy all data)
|
|
||||||
run_command(["sgdisk", "-Z", disk_device])
|
run_command(["sgdisk", "-Z", disk_device])
|
||||||
|
|
||||||
# 2. Create new GPT table
|
|
||||||
run_command(["sgdisk", "-o", disk_device])
|
run_command(["sgdisk", "-o", disk_device])
|
||||||
|
|
||||||
# 3. Create EFI Partition (Part 1, Start)
|
# 1. ESP (1GB)
|
||||||
run_command(
|
run_command(["sgdisk", "-n", "1:0:+1024M", "-t", "1:ef00", "-c", "1:EFI System", disk_device])
|
||||||
[
|
|
||||||
"sgdisk",
|
|
||||||
"-n",
|
|
||||||
f"1:0:+{efi_mb}M",
|
|
||||||
"-t",
|
|
||||||
"1:ef00",
|
|
||||||
"-c",
|
|
||||||
"1:EFI System",
|
|
||||||
disk_device,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# 4. Create Swap Partition (Part 3, End) - If enabled
|
# 2. Swap (if enabled)
|
||||||
if use_swap:
|
if use_swap:
|
||||||
# sgdisk negative start is from end of disk
|
run_command(["sgdisk", "-n", f"3:-{swap_mb}M:0", "-t", "3:8200", "-c", "3:Swap", disk_device])
|
||||||
# We use partition 3 for Swap
|
|
||||||
run_command(
|
|
||||||
[
|
|
||||||
"sgdisk",
|
|
||||||
"-n",
|
|
||||||
f"3:-{swap_mb}M:0",
|
|
||||||
"-t",
|
|
||||||
"3:8200",
|
|
||||||
"-c",
|
|
||||||
"3:Swap",
|
|
||||||
disk_device,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# 5. Create Root Partition (Part 2, Fill Gap)
|
# 3. Root
|
||||||
# This fills the space between P1 and P3 (or end if no swap)
|
|
||||||
run_command(["sgdisk", "-n", "2:0:0", "-t", "2:8300", "-c", "2:Root", disk_device])
|
run_command(["sgdisk", "-n", "2:0:0", "-t", "2:8300", "-c", "2:Root", disk_device])
|
||||||
|
else:
|
||||||
|
# MBR Layout for BIOS
|
||||||
|
logger.info("Using MBR layout for BIOS")
|
||||||
|
# Wipe disk using dd to be sure MBR is cleared
|
||||||
|
run_command(["dd", "if=/dev/zero", f"of={disk_device}", "bs=512", "count=100"])
|
||||||
|
|
||||||
|
# Use parted for MBR
|
||||||
|
run_command(["parted", "-s", disk_device, "mklabel", "msdos"])
|
||||||
|
|
||||||
|
if use_swap:
|
||||||
|
# Root first, then swap at end
|
||||||
|
root_end = int(disk_mb - swap_mb)
|
||||||
|
run_command(["parted", "-s", disk_device, "mkpart", "primary", "ext4", "1MiB", f"{root_end}MiB"])
|
||||||
|
run_command(["parted", "-s", disk_device, "mkpart", "primary", "linux-swap", f"{root_end}MiB", "100%"])
|
||||||
|
run_command(["parted", "-s", disk_device, "set", "1", "boot", "on"])
|
||||||
|
else:
|
||||||
|
run_command(["parted", "-s", disk_device, "mkpart", "primary", "ext4", "1MiB", "100%"])
|
||||||
|
run_command(["parted", "-s", disk_device, "set", "1", "boot", "on"])
|
||||||
|
|
||||||
# Inform kernel of changes
|
|
||||||
run_command(["partprobe", disk_device])
|
run_command(["partprobe", disk_device])
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
time.sleep(1)
|
# Identify partitions
|
||||||
|
if uefi:
|
||||||
# 6. Format Partitions
|
|
||||||
efi_part = get_partition_device(disk_device, 1)
|
efi_part = get_partition_device(disk_device, 1)
|
||||||
root_part = get_partition_device(disk_device, 2)
|
root_part = get_partition_device(disk_device, 2)
|
||||||
swap_part = get_partition_device(disk_device, 3) if use_swap else None
|
swap_part = get_partition_device(disk_device, 3) if use_swap else None
|
||||||
|
else:
|
||||||
|
efi_part = None # BIOS doesn't use ESP
|
||||||
|
root_part = get_partition_device(disk_device, 1)
|
||||||
|
swap_part = get_partition_device(disk_device, 2) if use_swap else None
|
||||||
|
|
||||||
logger.info("Formatting EFI partition...")
|
# Format
|
||||||
|
if uefi:
|
||||||
|
logger.info(f"Formatting EFI partition {efi_part}...")
|
||||||
run_command(["mkfs.vfat", "-F32", efi_part])
|
run_command(["mkfs.vfat", "-F32", efi_part])
|
||||||
|
|
||||||
if use_swap:
|
if use_swap:
|
||||||
logger.info("Formatting Swap partition...")
|
logger.info(f"Formatting Swap partition {swap_part}...")
|
||||||
run_command(["mkswap", swap_part])
|
run_command(["mkswap", swap_part])
|
||||||
|
|
||||||
logger.info("Formatting Root partition...")
|
logger.info(f"Formatting Root partition {root_part}...")
|
||||||
run_command(["mkfs.ext4", "-F", root_part])
|
run_command(["mkfs.ext4", "-F", root_part])
|
||||||
|
|
||||||
logger.info("Partitioning and formatting complete.")
|
result = {"efi": efi_part, "root": root_part, "swap": swap_part}
|
||||||
log_disk_operation(
|
log_disk_operation("PARTITION", "complete", str(result))
|
||||||
"PARTITION",
|
|
||||||
"complete",
|
|
||||||
f"EFI: {efi_part}, Root: {root_part}, Swap: {swap_part or 'none'}",
|
|
||||||
)
|
|
||||||
|
|
||||||
result = {"efi": efi_part, "root": root_part}
|
|
||||||
if use_swap:
|
|
||||||
result["swap"] = swap_part
|
|
||||||
else:
|
|
||||||
# If no swap, we should probably return None or handle it in fstab generation
|
|
||||||
# backend/os_install.py expects "swap" key for UUID.
|
|
||||||
# We should probably pass a dummy or None, and update os_install to handle it.
|
|
||||||
result["swap"] = None
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -253,32 +227,29 @@ def mount_partitions(partition_info, mount_root="/mnt"):
|
|||||||
Mounts the partitions into mount_root.
|
Mounts the partitions into mount_root.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
log_disk_operation("MOUNT", "start", f"Mounting to {mount_root}")
|
log_disk_operation("MOUNT", "start", f"Mounting to {mount_root}")
|
||||||
|
|
||||||
# 1. Mount Root
|
# 1. Mount Root
|
||||||
if not os.path.exists(mount_root):
|
if not os.path.exists(mount_root):
|
||||||
os.makedirs(mount_root)
|
os.makedirs(mount_root)
|
||||||
|
|
||||||
run_command(["mount", partition_info["root"], mount_root])
|
run_command(["mount", partition_info["root"], mount_root])
|
||||||
|
|
||||||
# 2. Mount EFI
|
# 2. Mount EFI (if exists)
|
||||||
efi_mount = os.path.join(mount_root, "boot")
|
if partition_info.get("efi"):
|
||||||
if not os.path.exists(efi_mount):
|
efi_mount = os.path.join(mount_root, "boot/efi")
|
||||||
os.makedirs(efi_mount, exist_ok=True)
|
os.makedirs(efi_mount, exist_ok=True)
|
||||||
|
|
||||||
run_command(["mount", partition_info["efi"], efi_mount])
|
run_command(["mount", partition_info["efi"], efi_mount])
|
||||||
|
else:
|
||||||
|
# For BIOS, /boot is just a directory on root or we could make a separate /boot
|
||||||
|
# Current logic keeps it on root.
|
||||||
|
pass
|
||||||
|
|
||||||
# 3. Enable Swap
|
# 3. Enable Swap
|
||||||
if partition_info.get("swap"):
|
if partition_info.get("swap"):
|
||||||
run_command(["swapon", partition_info["swap"]])
|
run_command(["swapon", partition_info["swap"]])
|
||||||
|
|
||||||
logger.info(f"Partitions mounted at {mount_root}")
|
logger.info(f"Partitions mounted at {mount_root}")
|
||||||
log_disk_operation(
|
log_disk_operation("MOUNT", "complete", f"Root: {partition_info['root']}")
|
||||||
"MOUNT",
|
|
||||||
"complete",
|
|
||||||
f"Root: {partition_info['root']}, EFI: {partition_info['efi']}",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def create_partition(
|
def create_partition(
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ def mount_pseudo_fs(mount_root):
|
|||||||
logger.warning(f"Failed to unmount {path}: {e}")
|
logger.warning(f"Failed to unmount {path}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def is_uefi():
|
||||||
|
return os.path.exists("/sys/firmware/efi")
|
||||||
|
|
||||||
|
|
||||||
def install_minimal_os(mount_root, releasever="43"):
|
def install_minimal_os(mount_root, releasever="43"):
|
||||||
"""
|
"""
|
||||||
Installs minimal Fedora packages to mount_root.
|
Installs minimal Fedora packages to mount_root.
|
||||||
@@ -117,22 +121,29 @@ def install_minimal_os(mount_root, releasever="43"):
|
|||||||
logger.info(f"Installing minimal Fedora {releasever} to {mount_root}...")
|
logger.info(f"Installing minimal Fedora {releasever} to {mount_root}...")
|
||||||
log_os_install("INSTALL", "start", f"Target: {mount_root}, Release: {releasever}")
|
log_os_install("INSTALL", "start", f"Target: {mount_root}, Release: {releasever}")
|
||||||
|
|
||||||
|
uefi = is_uefi()
|
||||||
|
|
||||||
packages = [
|
packages = [
|
||||||
"basesystem",
|
"basesystem",
|
||||||
"bash",
|
"bash",
|
||||||
"coreutils",
|
"coreutils",
|
||||||
"kernel",
|
"kernel",
|
||||||
"systemd",
|
"systemd",
|
||||||
"systemd-boot-unsigned",
|
|
||||||
"dnf",
|
"dnf",
|
||||||
"shadow-utils",
|
"shadow-utils",
|
||||||
"util-linux",
|
"util-linux",
|
||||||
"efibootmgr",
|
|
||||||
"passwd",
|
"passwd",
|
||||||
"rootfiles",
|
"rootfiles",
|
||||||
"vim-minimal",
|
"vim-minimal",
|
||||||
|
"grub2-tools",
|
||||||
|
"grubby",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if uefi:
|
||||||
|
packages += ["grub2-efi-x64", "shim-x64", "efibootmgr"]
|
||||||
|
else:
|
||||||
|
packages += ["grub2-pc"]
|
||||||
|
|
||||||
# Offline installation logic
|
# Offline installation logic
|
||||||
possible_repos = [
|
possible_repos = [
|
||||||
"/run/install/repo",
|
"/run/install/repo",
|
||||||
@@ -175,7 +186,7 @@ def install_minimal_os(mount_root, releasever="43"):
|
|||||||
"--cacheonly",
|
"--cacheonly",
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
logger.warning("ISO repository not found in common locations. DNF might try to use network.")
|
logger.warning("ISO repository not found. DNF might try to use network.")
|
||||||
dnf_args = []
|
dnf_args = []
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
@@ -200,56 +211,48 @@ def install_minimal_os(mount_root, releasever="43"):
|
|||||||
log_os_install("INSTALL", "complete", f"Installed to {mount_root}")
|
log_os_install("INSTALL", "complete", f"Installed to {mount_root}")
|
||||||
|
|
||||||
|
|
||||||
def configure_system(mount_root, partition_info, user_info=None):
|
def configure_system(mount_root, partition_info, user_info=None, disk_device=None):
|
||||||
"""
|
"""
|
||||||
Basic configuration: fstab, systemd-boot, and user creation.
|
Basic configuration: fstab, grub2, and user creation.
|
||||||
"""
|
"""
|
||||||
logger.info("Configuring system...")
|
logger.info("Configuring system...")
|
||||||
log_os_install("CONFIGURE", "start", f"Configuring system in {mount_root}")
|
log_os_install("CONFIGURE", "start", f"Configuring system in {mount_root}")
|
||||||
|
|
||||||
|
uefi = is_uefi()
|
||||||
|
|
||||||
# 1. Generate fstab
|
# 1. Generate fstab
|
||||||
def get_uuid(dev):
|
def get_uuid(dev):
|
||||||
res = run_command(["blkid", "-s", "UUID", "-o", "value", dev])
|
res = run_command(["blkid", "-s", "UUID", "-o", "value", dev])
|
||||||
return res.stdout.strip()
|
return res.stdout.strip()
|
||||||
|
|
||||||
root_uuid = get_uuid(partition_info["root"])
|
root_uuid = get_uuid(partition_info["root"])
|
||||||
efi_uuid = get_uuid(partition_info["efi"])
|
|
||||||
|
|
||||||
swap_entry = ""
|
fstab_lines = [f"UUID={root_uuid} / ext4 defaults 1 1"]
|
||||||
|
|
||||||
|
if uefi and partition_info.get("efi"):
|
||||||
|
efi_uuid = get_uuid(partition_info["efi"])
|
||||||
|
fstab_lines.append(f"UUID={efi_uuid} /boot/efi vfat defaults 0 2")
|
||||||
|
|
||||||
if partition_info.get("swap"):
|
if partition_info.get("swap"):
|
||||||
swap_uuid = get_uuid(partition_info["swap"])
|
swap_uuid = get_uuid(partition_info["swap"])
|
||||||
swap_entry = f"UUID={swap_uuid} none swap defaults 0 0\n"
|
fstab_lines.append(f"UUID={swap_uuid} none swap defaults 0 0")
|
||||||
|
|
||||||
fstab_content = f"""
|
|
||||||
UUID={root_uuid} / ext4 defaults 1 1
|
|
||||||
UUID={efi_uuid} /boot vfat defaults 0 2
|
|
||||||
{swap_entry}
|
|
||||||
"""
|
|
||||||
os.makedirs(os.path.join(mount_root, "etc"), exist_ok=True)
|
os.makedirs(os.path.join(mount_root, "etc"), exist_ok=True)
|
||||||
with open(os.path.join(mount_root, "etc/fstab"), "w") as f:
|
with open(os.path.join(mount_root, "etc/fstab"), "w") as f:
|
||||||
f.write(fstab_content)
|
f.write("\n".join(fstab_lines) + "\n")
|
||||||
|
|
||||||
with mount_pseudo_fs(mount_root):
|
with mount_pseudo_fs(mount_root):
|
||||||
# 2. Configure User
|
# 2. Configure User
|
||||||
if user_info:
|
if user_info:
|
||||||
logger.info(f"Creating user {user_info['username']}...")
|
logger.info(f"Creating user {user_info['username']}...")
|
||||||
# Create user and add to wheel group (sudoer)
|
|
||||||
run_command(["chroot", mount_root, "useradd", "-m", "-G", "wheel", user_info["username"]])
|
run_command(["chroot", mount_root, "useradd", "-m", "-G", "wheel", user_info["username"]])
|
||||||
|
|
||||||
# Ensure changes to /etc/passwd and /etc/shadow are flushed
|
# Set hostname
|
||||||
run_command(["sync"])
|
with open(os.path.join(mount_root, "etc/hostname"), "w") as f:
|
||||||
|
f.write(user_info["hostname"] + "\n")
|
||||||
|
|
||||||
# Ensure wheel group has sudo privileges
|
# Set passwords
|
||||||
sudoers_dir = os.path.join(mount_root, "etc/sudoers.d")
|
|
||||||
os.makedirs(sudoers_dir, exist_ok=True)
|
|
||||||
with open(os.path.join(sudoers_dir, "wheel"), "w") as f:
|
|
||||||
f.write("%wheel ALL=(ALL) ALL\n")
|
|
||||||
os.chmod(os.path.join(sudoers_dir, "wheel"), 0o440)
|
|
||||||
|
|
||||||
# Set user and root password using hashed passwords and usermod
|
|
||||||
try:
|
try:
|
||||||
logger.info(f"Setting hashed passwords for {user_info['username']} and root...")
|
|
||||||
# Generate SHA512 hash using openssl on the host
|
|
||||||
res = subprocess.run(
|
res = subprocess.run(
|
||||||
["openssl", "passwd", "-6", user_info["password"]],
|
["openssl", "passwd", "-6", user_info["password"]],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
@@ -257,64 +260,38 @@ UUID={efi_uuid} /boot vfat defaults 0 2
|
|||||||
check=True
|
check=True
|
||||||
)
|
)
|
||||||
hashed_pass = res.stdout.strip()
|
hashed_pass = res.stdout.strip()
|
||||||
|
|
||||||
# Apply hash to user and root using usermod -p (takes encrypted password)
|
|
||||||
run_command(["chroot", mount_root, "usermod", "-p", hashed_pass, user_info["username"]])
|
run_command(["chroot", mount_root, "usermod", "-p", hashed_pass, user_info["username"]])
|
||||||
run_command(["chroot", mount_root, "usermod", "-p", hashed_pass, "root"])
|
run_command(["chroot", mount_root, "usermod", "-p", hashed_pass, "root"])
|
||||||
|
|
||||||
run_command(["sync"])
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to set passwords: {e}")
|
logger.error(f"Failed to set passwords: {e}")
|
||||||
raise e
|
|
||||||
|
|
||||||
# Set hostname
|
# 3. Configure GRUB2
|
||||||
with open(os.path.join(mount_root, "etc/hostname"), "w") as f:
|
logger.info("Configuring GRUB2...")
|
||||||
f.write(user_info["hostname"] + "\n")
|
|
||||||
|
|
||||||
# 3. Configure systemd-boot
|
# Ensure /etc/default/grub exists
|
||||||
# Ensure machine-id exists for kernel-install
|
grub_default = os.path.join(mount_root, "etc/default/grub")
|
||||||
if not os.path.exists(os.path.join(mount_root, "etc/machine-id")):
|
if not os.path.exists(grub_default):
|
||||||
run_command(["chroot", mount_root, "systemd-machine-id-setup"])
|
with open(grub_default, "w") as f:
|
||||||
|
f.write('GRUB_TIMEOUT=5\nGRUB_DISTRIBUTOR="$(sed \'s, release .*$,,g\' /etc/system-release)"\nGRUB_DEFAULT=saved\nGRUB_DISABLE_SUBMENU=true\nGRUB_TERMINAL_OUTPUT="console"\nGRUB_CMDLINE_LINUX="rhgb quiet"\nGRUB_DISABLE_RECOVERY="true"\nGRUB_ENABLE_BLSCFG=true\n')
|
||||||
|
|
||||||
# Set kernel command line
|
if uefi:
|
||||||
os.makedirs(os.path.join(mount_root, "etc/kernel"), exist_ok=True)
|
run_command(["chroot", mount_root, "grub2-install", "--target=x86_64-efi", "--efi-directory=/boot/efi", "--bootloader-id=iridium", "--recheck"])
|
||||||
with open(os.path.join(mount_root, "etc/kernel/cmdline"), "w") as f:
|
run_command(["chroot", mount_root, "grub2-mkconfig", "-o", "/boot/efi/EFI/iridium/grub.cfg"])
|
||||||
f.write(f"root=UUID={root_uuid} rw quiet\n")
|
# Fedora compatibility link
|
||||||
|
fedora_dir = os.path.join(mount_root, "boot/efi/EFI/fedora")
|
||||||
|
os.makedirs(fedora_dir, exist_ok=True)
|
||||||
|
with open(os.path.join(fedora_dir, "grub.cfg"), "w") as f:
|
||||||
|
f.write(f"configfile /EFI/iridium/grub.cfg\n")
|
||||||
|
else:
|
||||||
|
if not disk_device:
|
||||||
|
# Try to guess disk device from root partition
|
||||||
|
disk_device = partition_info["root"].rstrip("0123456789")
|
||||||
|
if disk_device.endswith("p"): disk_device = disk_device[:-1]
|
||||||
|
|
||||||
# Set kernel layout to BLS for systemd-boot
|
logger.info(f"Installing GRUB to {disk_device} (BIOS)")
|
||||||
with open(os.path.join(mount_root, "etc/kernel/layout"), "w") as f:
|
run_command(["chroot", mount_root, "grub2-install", "--target=i386-pc", disk_device])
|
||||||
f.write("bls\n")
|
run_command(["chroot", mount_root, "grub2-mkconfig", "-o", "/boot/grub2/grub.cfg"])
|
||||||
|
|
||||||
# Install systemd-boot to the ESP (mounted at /boot)
|
|
||||||
# Note: removed --force as it's not supported by all bootctl versions
|
|
||||||
run_command(["chroot", mount_root, "bootctl", "install", "--path=/boot"])
|
|
||||||
|
|
||||||
# Add kernel entries
|
|
||||||
modules_dir = os.path.join(mount_root, "lib/modules")
|
|
||||||
if os.path.exists(modules_dir):
|
|
||||||
kvers = [d for d in os.listdir(modules_dir) if os.path.isdir(os.path.join(modules_dir, d))]
|
|
||||||
for kver in kvers:
|
|
||||||
logger.info(f"Adding kernel entry for {kver}...")
|
|
||||||
|
|
||||||
# Ensure initramfs exists. If not, generate it.
|
|
||||||
initrd_path_rel = f"boot/initramfs-{kver}.img"
|
|
||||||
initrd_full_path = os.path.join(mount_root, initrd_path_rel)
|
|
||||||
|
|
||||||
if not os.path.exists(initrd_full_path):
|
|
||||||
logger.info(f"Generating initramfs for {kver}...")
|
|
||||||
run_command(["chroot", mount_root, "dracut", "--force", f"/boot/initramfs-{kver}.img", kver])
|
|
||||||
|
|
||||||
kernel_image = f"/lib/modules/{kver}/vmlinuz"
|
|
||||||
initrd_arg = f"/boot/initramfs-{kver}.img"
|
|
||||||
|
|
||||||
# kernel-install add <version> <image> [initrd]
|
|
||||||
cmd = ["chroot", mount_root, "kernel-install", "add", kver, kernel_image]
|
|
||||||
if os.path.exists(os.path.join(mount_root, initrd_arg.lstrip("/"))):
|
|
||||||
cmd.append(initrd_arg)
|
|
||||||
|
|
||||||
run_command(cmd)
|
|
||||||
|
|
||||||
# Ensure all data is synced to disk
|
|
||||||
run_command(["sync"])
|
run_command(["sync"])
|
||||||
|
|
||||||
logger.info("System configuration complete.")
|
logger.info("System configuration complete.")
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ def main():
|
|||||||
"password": "password", # Insecure default for CLI dev testing
|
"password": "password", # Insecure default for CLI dev testing
|
||||||
"hostname": "iridium-cli"
|
"hostname": "iridium-cli"
|
||||||
}
|
}
|
||||||
configure_system(mount_root, parts, user_info)
|
configure_system(mount_root, parts, user_info, disk_device=target)
|
||||||
logger.info("INSTALLER_BOOTLOADER_COMPLETE: Bootloader configured")
|
logger.info("INSTALLER_BOOTLOADER_COMPLETE: Bootloader configured")
|
||||||
|
|
||||||
print("Installation complete! You can now reboot.")
|
print("Installation complete! You can now reboot.")
|
||||||
|
|||||||
@@ -54,8 +54,13 @@ def get_total_memory() -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def is_uefi():
|
||||||
|
return os.path.exists("/sys/firmware/efi")
|
||||||
|
|
||||||
|
|
||||||
def calculate_auto_partitions(disk_device):
|
def calculate_auto_partitions(disk_device):
|
||||||
disk_size = 0
|
disk_size = 0
|
||||||
|
uefi = is_uefi()
|
||||||
try:
|
try:
|
||||||
# Get disk size in bytes
|
# Get disk size in bytes
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
@@ -83,16 +88,21 @@ def calculate_auto_partitions(disk_device):
|
|||||||
disk_mb = disk_size / (1024 * 1024)
|
disk_mb = disk_size / (1024 * 1024)
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
efi_size = 2 * 1024 * 1024 * 1024
|
efi_size = 1024 * 1024 * 1024 if uefi else 0
|
||||||
swap_size = ram_size + (2 * 1024 * 1024 * 1024)
|
swap_size = ram_size + (2 * 1024 * 1024 * 1024)
|
||||||
min_root_size = 10 * 1024 * 1024 * 1024 # 10GB
|
min_root_size = 10 * 1024 * 1024 * 1024 # 10GB
|
||||||
|
|
||||||
|
# Cap swap for auto-calc if disk is small
|
||||||
|
if disk_size < 100 * 1024**3:
|
||||||
|
swap_size = min(swap_size, 4 * 1024**3)
|
||||||
|
|
||||||
total_required = efi_size + swap_size + min_root_size
|
total_required = efi_size + swap_size + min_root_size
|
||||||
|
|
||||||
use_swap = True
|
use_swap = True
|
||||||
|
|
||||||
if disk_size < total_required:
|
if disk_size < total_required:
|
||||||
efi_size = 1 * 1024 * 1024 * 1024
|
if uefi:
|
||||||
|
efi_size = 512 * 1024 * 1024
|
||||||
use_swap = False
|
use_swap = False
|
||||||
swap_size = 0
|
swap_size = 0
|
||||||
if disk_size < (efi_size + min_root_size):
|
if disk_size < (efi_size + min_root_size):
|
||||||
@@ -101,17 +111,20 @@ def calculate_auto_partitions(disk_device):
|
|||||||
|
|
||||||
root_size = disk_size - efi_size - swap_size
|
root_size = disk_size - efi_size - swap_size
|
||||||
|
|
||||||
partitions = [
|
partitions = []
|
||||||
{
|
|
||||||
|
if uefi:
|
||||||
|
partitions.append({
|
||||||
"type": "partition",
|
"type": "partition",
|
||||||
"name": "EFI System",
|
"name": "EFI System",
|
||||||
"filesystem": "vfat",
|
"filesystem": "vfat",
|
||||||
"mount_point": "/boot",
|
"mount_point": "/boot/efi",
|
||||||
"size": f"{efi_size / (1024**3):.1f} GB",
|
"size": f"{efi_size / (1024**3):.1f} GB",
|
||||||
"bytes": efi_size,
|
"bytes": efi_size,
|
||||||
"style_class": "part-efi",
|
"style_class": "part-efi",
|
||||||
},
|
})
|
||||||
{
|
|
||||||
|
partitions.append({
|
||||||
"type": "partition",
|
"type": "partition",
|
||||||
"name": "Root",
|
"name": "Root",
|
||||||
"filesystem": "ext4",
|
"filesystem": "ext4",
|
||||||
@@ -119,8 +132,7 @@ def calculate_auto_partitions(disk_device):
|
|||||||
"size": f"{root_size / (1024**3):.1f} GB",
|
"size": f"{root_size / (1024**3):.1f} GB",
|
||||||
"bytes": root_size,
|
"bytes": root_size,
|
||||||
"style_class": "part-root",
|
"style_class": "part-root",
|
||||||
},
|
})
|
||||||
]
|
|
||||||
|
|
||||||
if use_swap:
|
if use_swap:
|
||||||
partitions.append(
|
partitions.append(
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ class InstallerWindow(Adw.ApplicationWindow):
|
|||||||
f"Session: {self.session_id} - Configuring bootloader and user",
|
f"Session: {self.session_id} - Configuring bootloader and user",
|
||||||
"installer",
|
"installer",
|
||||||
)
|
)
|
||||||
configure_system(mount_root, parts, user_info)
|
configure_system(mount_root, parts, user_info, disk_device=disk)
|
||||||
nlog(
|
nlog(
|
||||||
"INSTALL_PROGRESS",
|
"INSTALL_PROGRESS",
|
||||||
f"Session: {self.session_id} - Configuration complete",
|
f"Session: {self.session_id} - Configuration complete",
|
||||||
|
|||||||
2
run.sh
2
run.sh
@@ -29,7 +29,7 @@ fi
|
|||||||
|
|
||||||
# Check and install dependencies (Fedora/DNF)
|
# Check and install dependencies (Fedora/DNF)
|
||||||
if command -v dnf &> /dev/null; then
|
if command -v dnf &> /dev/null; then
|
||||||
DEPENDENCIES="python3-gobject gtk4 libadwaita python3-requests gdisk dosfstools e2fsprogs"
|
DEPENDENCIES="python3-gobject gtk4 libadwaita python3-requests gdisk dosfstools e2fsprogs parted grub2-tools openssl"
|
||||||
MISSING_DEPS=""
|
MISSING_DEPS=""
|
||||||
|
|
||||||
for dep in $DEPENDENCIES; do
|
for dep in $DEPENDENCIES; do
|
||||||
|
|||||||
25
run_vm_bios.sh
Executable file
25
run_vm_bios.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
ISO_PATH="${1:-/home/n0va/.local/share/iridium-installer-vm/Fedora.iso}"
|
||||||
|
DISK_PATH="${2:-/home/n0va/.local/share/iridium-installer-vm/test-disk.qcow2}"
|
||||||
|
|
||||||
|
echo "Starting Iridium VM with BIOS (Legacy) support..."
|
||||||
|
echo "ISO: $ISO_PATH"
|
||||||
|
echo "Disk: $DISK_PATH"
|
||||||
|
|
||||||
|
# QEMU Command with BIOS (Standard QEMU behavior)
|
||||||
|
qemu-system-x86_64
|
||||||
|
-enable-kvm
|
||||||
|
-m 8G
|
||||||
|
-smp 2
|
||||||
|
-cpu host
|
||||||
|
-drive file="$DISK_PATH",format=qcow2,if=virtio
|
||||||
|
-cdrom "$ISO_PATH"
|
||||||
|
-boot once=d
|
||||||
|
-netdev user,id=net0
|
||||||
|
-device virtio-net-pci,netdev=net0
|
||||||
|
-vga virtio
|
||||||
|
-display gtk,gl=on
|
||||||
|
-monitor unix:$HOME/.local/share/iridium-installer-vm/monitor.sock,server,nowait
|
||||||
|
-name "Iridium Installer Test VM (BIOS)"
|
||||||
Reference in New Issue
Block a user