added functionality to delete existing partitions before reinstall
Some checks failed
Build / build (push) Failing after 4m53s

This commit is contained in:
tumillanino
2025-11-12 15:55:15 +11:00
parent adab84e8ff
commit f05bd8b929
575 changed files with 187 additions and 160911 deletions

View File

@@ -145,28 +145,71 @@ func (m InstallModel) saveConfigurationFiles() error {
func (m InstallModel) partitionDisk() error {
disk := m.config.Disk
m.updateProgress(m.currentStep, "Clearing existing partition table...")
// Ensure the disk device exists
if _, err := os.Stat(disk); os.IsNotExist(err) {
return fmt.Errorf("disk device %s does not exist", disk)
}
// Kill all processes using the disk
killCmd := exec.Command("fuser", "-k", disk)
killCmd.Run() // Ignore errors as the device might not be in use
// Wait a moment for processes to terminate
time.Sleep(500 * time.Millisecond)
// Wipe filesystem signatures
wipeDisk := exec.Command("wipefs", "-af", disk)
if err := wipeDisk.Run(); err != nil {
return err
if output, err := wipeDisk.CombinedOutput(); err != nil {
return fmt.Errorf("failed to wipe filesystem signatures: %w\nOutput: %s", err, string(output))
}
sgdisk := exec.Command("sgdisk", "-Z", disk)
if err := sgdisk.Run(); err != nil {
return err
// Zap (clear) the GPT and MBR partition table
sgdiskZap := exec.Command("sgdisk", "--zap-all", disk)
if output, err := sgdiskZap.CombinedOutput(); err != nil {
return fmt.Errorf("failed to zap partition table: %w\nOutput: %s", err, string(output))
}
createEFI := exec.Command("sgdisk", "-n", "1:0:+512M", "-t", "1:ef00", disk)
if err := createEFI.Run(); err != nil {
return err
// Clear with dd for additional safety
ddClear := exec.Command("dd", "if=/dev/zero", "of="+disk, "bs=1M", "count=100", "status=none")
if output, err := ddClear.CombinedOutput(); err != nil {
return fmt.Errorf("failed to clear disk header: %w\nOutput: %s", err, string(output))
}
createRoot := exec.Command("sgdisk", "-n", "2:0:0", "-t", "2:8300", disk)
if err := createRoot.Run(); err != nil {
return err
}
// Ensure the kernel re-reads the partition table
partprobe := exec.Command("partprobe", disk)
partprobe.Run()
// Wait for the system to recognize the changes
time.Sleep(1 * time.Second)
m.updateProgress(m.currentStep, "Creating new partition table...")
// Create new GPT partition table
sgdiskNew := exec.Command("sgdisk", "--clear", disk)
if output, err := sgdiskNew.CombinedOutput(); err != nil {
return fmt.Errorf("failed to create new partition table: %w\nOutput: %s", err, string(output))
}
// Create EFI System Partition (512MB, FAT32)
createEFI := exec.Command("sgdisk", "--new=1:0:+512M", "--typecode=1:EF00", "--change-name=1:EFI System Partition", disk)
if output, err := createEFI.CombinedOutput(); err != nil {
return fmt.Errorf("failed to create EFI partition: %w\nOutput: %s", err, string(output))
}
// Create root partition (remaining space, Linux filesystem)
createRoot := exec.Command("sgdisk", "--new=2:0:0", "--typecode=2:8300", "--change-name=2:Linux Root", disk)
if output, err := createRoot.CombinedOutput(); err != nil {
return fmt.Errorf("failed to create root partition: %w\nOutput: %s", err, string(output))
}
// Notify the kernel of partition table changes
partprobe2 := exec.Command("partprobe", disk)
partprobe2.Run()
// Wait for the system to recognize the new partitions
time.Sleep(1 * time.Second)
exec.Command("partprobe", disk).Run()
return nil
}
@@ -176,35 +219,55 @@ func (m InstallModel) formatPartitions() error {
efiPart := disk + "1"
rootPart := disk + "2"
if strings.Contains(disk, "nvme") || strings.Contains(disk, "mmcblk") {
efiPart = disk + "p1"
rootPart = disk + "p2"
// Wait a bit more to ensure partitions are recognized
time.Sleep(2 * time.Second)
// Re-probe the partition table to ensure kernel recognizes the new partitions
exec.Command("partprobe", disk).Run()
time.Sleep(500 * time.Millisecond)
// Verify partitions exist
if _, err := os.Stat(efiPart); os.IsNotExist(err) {
if strings.Contains(disk, "nvme") || strings.Contains(disk, "mmcblk") {
efiPart = disk + "p1"
rootPart = disk + "p2"
}
}
// Double-check that the partitions exist with the correct naming
if _, err := os.Stat(efiPart); os.IsNotExist(err) {
// Try to list available partitions to help with debugging
lsblk := exec.Command("lsblk", "-f", disk)
if output, err := lsblk.CombinedOutput(); err == nil {
return fmt.Errorf("EFI partition %s not found after partitioning. Available partitions:\n%s", efiPart, string(output))
}
return fmt.Errorf("EFI partition %s not found after partitioning", efiPart)
}
mkfsEFI := exec.Command("mkfs.fat", "-F32", efiPart)
if err := mkfsEFI.Run(); err != nil {
return err
if output, err := mkfsEFI.CombinedOutput(); err != nil {
return fmt.Errorf("failed to format EFI partition: %w\nOutput: %s", err, string(output))
}
if m.config.EnableLUKS {
cryptsetup := exec.Command("cryptsetup", "luksFormat", "--type", "luks2", rootPart)
cryptsetup.Stdin = strings.NewReader(m.config.RootPassword + "\n")
if err := cryptsetup.Run(); err != nil {
return err
if output, err := cryptsetup.CombinedOutput(); err != nil {
return fmt.Errorf("failed to format LUKS partition: %w\nOutput: %s", err, string(output))
}
cryptOpen := exec.Command("cryptsetup", "open", rootPart, "cryptroot")
cryptOpen.Stdin = strings.NewReader(m.config.RootPassword + "\n")
if err := cryptOpen.Run(); err != nil {
return err
if output, err := cryptOpen.CombinedOutput(); err != nil {
return fmt.Errorf("failed to open LUKS partition: %w\nOutput: %s", err, string(output))
}
rootPart = "/dev/mapper/cryptroot"
}
mkfsBtrfs := exec.Command("mkfs.btrfs", "-f", rootPart)
if err := mkfsBtrfs.Run(); err != nil {
return err
if output, err := mkfsBtrfs.CombinedOutput(); err != nil {
return fmt.Errorf("failed to format root partition: %w\nOutput: %s", err, string(output))
}
return nil
@@ -215,32 +278,58 @@ func (m InstallModel) mountFilesystems() error {
rootPart := disk + "2"
efiPart := disk + "1"
// Wait for partitions to be fully recognized
time.Sleep(1 * time.Second)
exec.Command("partprobe", disk).Run()
time.Sleep(500 * time.Millisecond)
// Handle NVMe and mmcblk device naming
if strings.Contains(disk, "nvme") || strings.Contains(disk, "mmcblk") {
efiPart = disk + "p1"
rootPart = disk + "p2"
}
// Verify partitions exist before mounting
if _, err := os.Stat(efiPart); os.IsNotExist(err) {
return fmt.Errorf("EFI partition %s not found", efiPart)
}
if _, err := os.Stat(rootPart); os.IsNotExist(err) {
return fmt.Errorf("root partition %s not found", rootPart)
}
if m.config.EnableLUKS {
// Check if cryptroot is already open
if _, err := os.Stat("/dev/mapper/cryptroot"); os.IsNotExist(err) {
cryptOpen := exec.Command("cryptsetup", "open", rootPart, "cryptroot")
cryptOpen.Stdin = strings.NewReader(m.config.RootPassword + "\n")
if output, err := cryptOpen.CombinedOutput(); err != nil {
return fmt.Errorf("failed to open LUKS partition: %w\nOutput: %s", err, string(output))
}
}
rootPart = "/dev/mapper/cryptroot"
}
os.MkdirAll("/mnt", 0755)
mount := exec.Command("mount", rootPart, "/mnt")
if err := mount.Run(); err != nil {
return err
if output, err := mount.CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount root partition: %w\nOutput: %s", err, string(output))
}
// Create btrfs subvolumes
btrfsOpts := "subvol=@,compress=zstd,noatime"
for _, subvol := range []string{"@", "@home", "@var", "@snapshots"} {
create := exec.Command("btrfs", "subvolume", "create", "/mnt/"+subvol)
create.Run()
if output, err := create.CombinedOutput(); err != nil {
return fmt.Errorf("failed to create subvolume %s: %w\nOutput: %s", subvol, err, string(output))
}
}
exec.Command("umount", "/mnt").Run()
// Mount root with subvolume
mount = exec.Command("mount", "-o", btrfsOpts, rootPart, "/mnt")
if err := mount.Run(); err != nil {
return err
if output, err := mount.CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount root with subvolumes: %w\nOutput: %s", err, string(output))
}
os.MkdirAll("/mnt/home", 0755)
@@ -249,17 +338,23 @@ func (m InstallModel) mountFilesystems() error {
os.MkdirAll("/mnt/boot", 0755)
mountHome := exec.Command("mount", "-o", "subvol=@home,compress=zstd,noatime", rootPart, "/mnt/home")
mountHome.Run()
if output, err := mountHome.CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount home subvolume: %w\nOutput: %s", err, string(output))
}
mountVar := exec.Command("mount", "-o", "subvol=@var,compress=zstd,noatime", rootPart, "/mnt/var")
mountVar.Run()
if output, err := mountVar.CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount var subvolume: %w\nOutput: %s", err, string(output))
}
mountSnap := exec.Command("mount", "-o", "subvol=@snapshots,compress=zstd,noatime", rootPart, "/mnt/.snapshots")
mountSnap.Run()
if output, err := mountSnap.CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount snapshots subvolume: %w\nOutput: %s", err, string(output))
}
mountEFI := exec.Command("mount", efiPart, "/mnt/boot")
if err := mountEFI.Run(); err != nil {
return err
if output, err := mountEFI.CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount EFI partition: %w\nOutput: %s", err, string(output))
}
return nil
@@ -511,20 +606,34 @@ editor no
disk := m.config.Disk
rootPart := disk + "2"
// Handle NVMe and mmcblk device naming
if strings.Contains(disk, "nvme") || strings.Contains(disk, "mmcblk") {
rootPart = disk + "p2"
}
// For LUKS, we need to reference the encrypted device, not the decrypted one
// The bootloader needs to unlock the device first
var options string
if m.config.EnableLUKS {
cryptUUID := ""
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", rootPart)
output, _ := blkid.Output()
cryptUUID = strings.TrimSpace(string(output))
// Get UUID of the encrypted partition (not the mapped device)
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", disk+"2")
if strings.Contains(disk, "nvme") || strings.Contains(disk, "mmcblk") {
blkid = exec.Command("blkid", "-s", "UUID", "-o", "value", disk+"p2")
}
output, err := blkid.Output()
if err != nil {
return fmt.Errorf("failed to get encrypted partition UUID: %w", err)
}
cryptUUID := strings.TrimSpace(string(output))
options = fmt.Sprintf("cryptdevice=UUID=%s:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw quiet splash", cryptUUID)
} else {
// Get UUID of the root partition
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", rootPart)
output, _ := blkid.Output()
output, err := blkid.Output()
if err != nil {
return fmt.Errorf("failed to get root partition UUID: %w", err)
}
rootUUID := strings.TrimSpace(string(output))
options = fmt.Sprintf("root=UUID=%s rootflags=subvol=@ rw quiet splash", rootUUID)
}