From d43e49aacfb1c8c688f252afde06fef0c0844fd7 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 14:56:14 +0100 Subject: [PATCH 01/17] DBusStructures: Add new file system enum and partition usage struct --- common/DBusStructures.vala | 43 +++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 388e2b9ed..22c5e9a43 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -31,14 +31,41 @@ public struct InstallerDaemon.Disk { Partition[] partitions; } +public enum InstallerDaemon.FileSystem { + NONE, + BTRFS, + EXT2, + EXT3, + EXT4, + F2FS, + FAT16, + FAT32, + NTFS, + SWAP, + XFS, + LVM, + LUKS, +} + +public struct InstallerDaemon.PartitionUsage { + /** + * None = 0; Some(usage) = 1; + */ + public uint8 tag; + /** + * The size, in sectors, that a partition is used. + */ + public uint64 value; +} + public struct InstallerDaemon.Partition { string device_path; - Distinst.FileSystem filesystem; + FileSystem filesystem; uint64 start_sector; uint64 end_sector; - Distinst.PartitionUsage sectors_used; + PartitionUsage sectors_used; string? current_lvm_volume_group; } @@ -62,18 +89,18 @@ public struct InstallerDaemon.Mount { string parent_disk; string mount_point; uint64 sectors; - Distinst.FileSystem filesystem; + FileSystem filesystem; MountFlags flags; public bool is_valid_boot_mount () { - return filesystem == Distinst.FileSystem.FAT16 - || filesystem == Distinst.FileSystem.FAT32; + return filesystem == FileSystem.FAT16 + || filesystem == FileSystem.FAT32; } public bool is_valid_root_mount () { - return filesystem != Distinst.FileSystem.FAT16 - && filesystem != Distinst.FileSystem.FAT32 - && filesystem != Distinst.FileSystem.NTFS; + return filesystem != FileSystem.FAT16 + && filesystem != FileSystem.FAT32 + && filesystem != FileSystem.NTFS; } public bool is_lvm () { From ff2b6d044e6f17491dca0bb6f898a3be095dea07 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 15:02:20 +0100 Subject: [PATCH 02/17] DBusStructures: Add to_string method to FileSystem enum --- common/DBusStructures.vala | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 22c5e9a43..8d441bd6c 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -44,7 +44,40 @@ public enum InstallerDaemon.FileSystem { SWAP, XFS, LVM, - LUKS, + LUKS; + + public string to_string () { + switch (this) { + case BTRFS: + return "btrfs"; + case EXT2: + return "ext2"; + case EXT3: + return "ext3"; + case EXT4: + return "ext4"; + case F2FS: + return "f2fs"; + case FAT16: + return "fat16"; + case FAT32: + return "fat32"; + case NONE: + return "none"; + case NTFS: + return "ntfs"; + case SWAP: + return "swap"; + case XFS: + return "xfs"; + case LVM: + return "lvm"; + case LUKS: + return "luks"; + } + + return "none"; + } } public struct InstallerDaemon.PartitionUsage { From 5853498e370d5779358a70470deb8e3916410a8e Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 15:02:36 +0100 Subject: [PATCH 03/17] Update file system types to use InstallerDaemon instead of Distinst --- src/Objects/Mount.vala | 14 +++++++------- src/Views/PartitioningView.vala | 2 +- src/Widgets/DiskBar.vala | 2 +- src/Widgets/PartitionBar.vala | 8 ++++---- src/Widgets/PartitionMenu.vala | 26 +++++++++++++------------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Objects/Mount.vala b/src/Objects/Mount.vala index 6896f0ac6..7fca8c30e 100644 --- a/src/Objects/Mount.vala +++ b/src/Objects/Mount.vala @@ -23,12 +23,12 @@ public class Installer.Mount { public string parent_disk; public string mount_point; public uint64 sectors; - public Distinst.FileSystem filesystem; + public InstallerDaemon.FileSystem filesystem; public InstallerDaemon.MountFlags flags; public PartitionMenu menu; public Mount (string partition, string parent_disk, string mount, - uint64 sectors, InstallerDaemon.MountFlags flags, Distinst.FileSystem fs, + uint64 sectors, InstallerDaemon.MountFlags flags, InstallerDaemon.FileSystem fs, PartitionMenu menu) { filesystem = fs; mount_point = mount; @@ -40,14 +40,14 @@ public class Installer.Mount { } public bool is_valid_boot_mount () { - return filesystem == Distinst.FileSystem.FAT16 - || filesystem == Distinst.FileSystem.FAT32; + return filesystem == InstallerDaemon.FileSystem.FAT16 + || filesystem == InstallerDaemon.FileSystem.FAT32; } public bool is_valid_root_mount () { - return filesystem != Distinst.FileSystem.FAT16 - && filesystem != Distinst.FileSystem.FAT32 - && filesystem != Distinst.FileSystem.NTFS; + return filesystem != InstallerDaemon.FileSystem.FAT16 + && filesystem != InstallerDaemon.FileSystem.FAT32 + && filesystem != InstallerDaemon.FileSystem.NTFS; } public bool is_lvm () { diff --git a/src/Views/PartitioningView.vala b/src/Views/PartitioningView.vala index 90e4cee1e..4751713e5 100644 --- a/src/Views/PartitioningView.vala +++ b/src/Views/PartitioningView.vala @@ -236,7 +236,7 @@ public class Installer.PartitioningView : AbstractInstallerView { m.parent_disk, m.partition_path, m.mount_point, - Distinst.strfilesys (m.filesystem), + m.filesystem.to_string (), m.should_format () ? "true" : "false" ); diff --git a/src/Widgets/DiskBar.vala b/src/Widgets/DiskBar.vala index aa606d506..afe6ee2ba 100644 --- a/src/Widgets/DiskBar.vala +++ b/src/Widgets/DiskBar.vala @@ -89,7 +89,7 @@ public class Installer.DiskBar: Gtk.Grid { legend.add (legend_container); foreach (PartitionBar p in partitions) { - add_legend (p.path, p.get_size () * 512, Distinst.strfilesys (p.filesystem), p.vg, p.menu); + add_legend (p.path, p.get_size () * 512, p.filesystem.to_string (), p.vg, p.menu); } uint64 used = 0; diff --git a/src/Widgets/PartitionBar.vala b/src/Widgets/PartitionBar.vala index df44cc955..719ac3c8f 100644 --- a/src/Widgets/PartitionBar.vala +++ b/src/Widgets/PartitionBar.vala @@ -29,7 +29,7 @@ public class Installer.PartitionBar : Gtk.EventBox { public Gtk.Label label; public Gtk.Popover menu; - public Distinst.FileSystem filesystem; + public InstallerDaemon.FileSystem filesystem; public signal void decrypted (InstallerDaemon.LuksCredentials credential); @@ -48,17 +48,17 @@ public class Installer.PartitionBar : Gtk.EventBox { path = part.device_path; filesystem = part.filesystem; - vg = (Distinst.FileSystem.LVM == filesystem) + vg = (InstallerDaemon.FileSystem.LVM == filesystem) ? part.current_lvm_volume_group : null; tooltip_text = path; var style_context = get_style_context (); - style_context.add_class (Distinst.strfilesys (filesystem)); + style_context.add_class (filesystem.to_string ()); container = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - if (filesystem == Distinst.FileSystem.LUKS) { + if (filesystem == InstallerDaemon.FileSystem.LUKS) { menu = new DecryptMenu (path); ((DecryptMenu)menu).decrypted.connect ((creds) => decrypted (creds)); } else { diff --git a/src/Widgets/PartitionMenu.vala b/src/Widgets/PartitionMenu.vala index 51007cf49..5e1750f77 100644 --- a/src/Widgets/PartitionMenu.vala +++ b/src/Widgets/PartitionMenu.vala @@ -28,7 +28,7 @@ public class Installer.PartitionMenu : Gtk.Popover { private bool is_lvm; private string parent_disk; private string partition_path; - private Distinst.FileSystem original_filesystem; + private InstallerDaemon.FileSystem original_filesystem; private Granite.SwitchModelButton format_partition; private Granite.SwitchModelButton use_partition; @@ -40,7 +40,7 @@ public class Installer.PartitionMenu : Gtk.Popover { // A reference to the parent which owns this menu. private PartitionBar partition_bar; - public PartitionMenu (string path, string parent, Distinst.FileSystem fs, + public PartitionMenu (string path, string parent, InstallerDaemon.FileSystem fs, bool lvm, SetMount set_mount, UnsetMount unset_mount, MountSetFn mount_set, PartitionBar partition_bar) { this.partition_bar = partition_bar; @@ -203,13 +203,13 @@ public class Installer.PartitionMenu : Gtk.Popover { disable_signals = false; int select = 0; - if (fs == Distinst.FileSystem.FAT16 || fs == Distinst.FileSystem.FAT32) { + if (fs == InstallerDaemon.FileSystem.FAT16 || fs == InstallerDaemon.FileSystem.FAT32) { if (mount_set (boot_partition)) { select = 4; } else { select = 2; } - } else if (fs == Distinst.FileSystem.SWAP) { + } else if (fs == InstallerDaemon.FileSystem.SWAP) { select = 3; } else if (mount_set ("/")) { if (mount_set ("/home" )) { @@ -256,7 +256,7 @@ public class Installer.PartitionMenu : Gtk.Popover { private void update_values (SetMount set_mount) { var mount = get_mount (); var filesystem = mount == "swap" - ? Distinst.FileSystem.SWAP + ? InstallerDaemon.FileSystem.SWAP : get_file_system (); string? error = null; @@ -297,22 +297,22 @@ public class Installer.PartitionMenu : Gtk.Popover { return original_filesystem == get_file_system (); } - private Distinst.FileSystem get_file_system () { + private InstallerDaemon.FileSystem get_file_system () { switch (type.active) { case 0: - return Distinst.FileSystem.EXT4; + return InstallerDaemon.FileSystem.EXT4; case 1: - return Distinst.FileSystem.FAT16; + return InstallerDaemon.FileSystem.FAT16; case 2: - return Distinst.FileSystem.FAT32; + return InstallerDaemon.FileSystem.FAT32; case 3: - return Distinst.FileSystem.BTRFS; + return InstallerDaemon.FileSystem.BTRFS; case 4: - return Distinst.FileSystem.XFS; + return InstallerDaemon.FileSystem.XFS; case 5: - return Distinst.FileSystem.NTFS; + return InstallerDaemon.FileSystem.NTFS; default: - return Distinst.FileSystem.NONE; + return InstallerDaemon.FileSystem.NONE; } } From 8c137fe387608331fdb0561918b45df3b2419be4 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 16:18:50 +0100 Subject: [PATCH 04/17] Daemon: Convert file system and partition usage to common format --- daemon/Daemon.vala | 95 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index 2a93ea6c0..bed269b47 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -69,10 +69,10 @@ public class InstallerDaemon.Daemon : GLib.Object { partitions += Partition () { device_path = string_from_utf8 (part.get_device_path ()), - filesystem = part.get_file_system (), + filesystem = to_common_fs (part.get_file_system ()), start_sector = part.get_start_sector (), end_sector = part.get_end_sector (), - sectors_used = part.sectors_used (disk.get_sector_size ()), + sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), current_lvm_volume_group = lvm_vg }; } @@ -103,10 +103,10 @@ public class InstallerDaemon.Daemon : GLib.Object { partitions += Partition () { device_path = string_from_utf8 (part.get_device_path ()), - filesystem = part.get_file_system (), + filesystem = to_common_fs (part.get_file_system ()), start_sector = part.get_start_sector (), end_sector = part.get_end_sector (), - sectors_used = part.sectors_used (disk.get_sector_size ()), + sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), current_lvm_volume_group = lvm_vg }; } @@ -149,10 +149,10 @@ public class InstallerDaemon.Daemon : GLib.Object { partitions += Partition () { device_path = string_from_utf8 (part.get_device_path ()), - filesystem = part.get_file_system (), + filesystem = to_common_fs (part.get_file_system ()), start_sector = part.get_start_sector (), end_sector = part.get_end_sector (), - sectors_used = part.sectors_used (disk.get_sector_size ()), + sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), current_lvm_volume_group = lvm_vg }; } @@ -451,7 +451,7 @@ public class InstallerDaemon.Daemon : GLib.Object { if (m.mount_point == "/boot/efi") { if (m.is_valid_boot_mount ()) { if (m.should_format ()) { - partition.format_with (m.filesystem); + partition.format_with (to_distinst_fs (m.filesystem)); } partition.set_mount (m.mount_point); @@ -460,7 +460,7 @@ public class InstallerDaemon.Daemon : GLib.Object { throw new GLib.IOError.FAILED ("Unreachable code path -- EFI partition is invalid"); } } else { - if (m.filesystem != Distinst.FileSystem.SWAP) { + if (m.filesystem != InstallerDaemon.FileSystem.SWAP) { partition.set_mount (m.mount_point); } @@ -469,7 +469,7 @@ public class InstallerDaemon.Daemon : GLib.Object { } if (m.should_format ()) { - partition.format_with (m.filesystem); + partition.format_with (to_distinst_fs (m.filesystem)); } } } @@ -498,12 +498,12 @@ public class InstallerDaemon.Daemon : GLib.Object { throw new GLib.IOError.FAILED ("could not find %s", m.partition_path); } - if (m.filesystem != Distinst.FileSystem.SWAP) { + if (m.filesystem != InstallerDaemon.FileSystem.SWAP) { partition.set_mount (m.mount_point); } if (m.should_format ()) { - partition.format_and_keep_name (m.filesystem); + partition.format_and_keep_name (to_distinst_fs (m.filesystem)); } } } @@ -513,6 +513,79 @@ public class InstallerDaemon.Daemon : GLib.Object { builder.append_len ((string) input, input.length); return (owned) builder.str; } + + private InstallerDaemon.FileSystem to_common_fs (Distinst.FileSystem fs) { + switch (fs) { + case BTRFS: + return InstallerDaemon.FileSystem.BTRFS; + case EXT2: + return InstallerDaemon.FileSystem.EXT2; + case EXT3: + return InstallerDaemon.FileSystem.EXT3; + case EXT4: + return InstallerDaemon.FileSystem.EXT4; + case F2FS: + return InstallerDaemon.FileSystem.F2FS; + case FAT16: + return InstallerDaemon.FileSystem.FAT16; + case FAT32: + return InstallerDaemon.FileSystem.FAT32; + case NONE: + return InstallerDaemon.FileSystem.NONE; + case NTFS: + return InstallerDaemon.FileSystem.NTFS; + case SWAP: + return InstallerDaemon.FileSystem.SWAP; + case XFS: + return InstallerDaemon.FileSystem.XFS; + case LVM: + return InstallerDaemon.FileSystem.LVM; + case LUKS: + return InstallerDaemon.FileSystem.LUKS; + default: + return InstallerDaemon.FileSystem.NONE; + } + } + + private InstallerDaemon.PartitionUsage to_common_usage (Distinst.PartitionUsage usage) { + return InstallerDaemon.PartitionUsage () { + tag = usage.tag, + value = usage.value + }; + } + + private Distinst.FileSystem to_distinst_fs (InstallerDaemon.FileSystem fs) { + switch (fs) { + case BTRFS: + return Distinst.FileSystem.BTRFS; + case EXT2: + return Distinst.FileSystem.EXT2; + case EXT3: + return Distinst.FileSystem.EXT3; + case EXT4: + return Distinst.FileSystem.EXT4; + case F2FS: + return Distinst.FileSystem.F2FS; + case FAT16: + return Distinst.FileSystem.FAT16; + case FAT32: + return Distinst.FileSystem.FAT32; + case NONE: + return Distinst.FileSystem.NONE; + case NTFS: + return Distinst.FileSystem.NTFS; + case SWAP: + return Distinst.FileSystem.SWAP; + case XFS: + return Distinst.FileSystem.XFS; + case LVM: + return Distinst.FileSystem.LVM; + case LUKS: + return Distinst.FileSystem.LUKS; + default: + return Distinst.FileSystem.NONE; + } + } } private void on_bus_acquired (GLib.DBusConnection connection, string name) { From 3e041ce19659e26ac4f861a6dd7040e9650fa034 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 16:27:01 +0100 Subject: [PATCH 05/17] Add PartitionTable enum and update bootloader_detect method --- common/DBusStructures.vala | 6 ++++++ daemon/Daemon.vala | 17 +++++++++++++++-- src/Helpers/InstallerDaemon.vala | 10 +++++----- src/Views/PartitioningView.vala | 8 ++++---- src/Widgets/PartitionMenu.vala | 6 +++--- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 8d441bd6c..2b1308464 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -91,6 +91,12 @@ public struct InstallerDaemon.PartitionUsage { public uint64 value; } +public enum InstallerDaemon.PartitionTable { + NONE, + GPT, + MSDOS; +} + public struct InstallerDaemon.Partition { string device_path; diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index bed269b47..e458528ae 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -33,8 +33,8 @@ public class InstallerDaemon.Daemon : GLib.Object { }); } - public Distinst.PartitionTable bootloader_detect () throws GLib.Error { - return Distinst.bootloader_detect (); + public InstallerDaemon.PartitionTable bootloader_detect () throws GLib.Error { + return to_common_usage_bootloader (Distinst.bootloader_detect ()); } public DiskInfo get_disks (bool get_partitions = false) throws GLib.Error { @@ -586,6 +586,19 @@ public class InstallerDaemon.Daemon : GLib.Object { return Distinst.FileSystem.NONE; } } + + public InstallerDaemon.PartitionTable to_common_usage_bootloader (Distinst.PartitionTable bootloader) { + switch (bootloader) { + case GPT: + return InstallerDaemon.PartitionTable.GPT; + case MSDOS: + return InstallerDaemon.PartitionTable.MSDOS; + case NONE: + return InstallerDaemon.PartitionTable.NONE; + default: + return InstallerDaemon.PartitionTable.NONE; + } + } } private void on_bus_acquired (GLib.DBusConnection connection, string name) { diff --git a/src/Helpers/InstallerDaemon.vala b/src/Helpers/InstallerDaemon.vala index 254bb8f90..1d523c258 100644 --- a/src/Helpers/InstallerDaemon.vala +++ b/src/Helpers/InstallerDaemon.vala @@ -27,7 +27,7 @@ public class Installer.Daemon { public signal void on_status (Distinst.Status status); public signal void on_log_message (Distinst.LogLevel level, string message); - public abstract Distinst.PartitionTable bootloader_detect () throws GLib.Error; + public abstract InstallerDaemon.PartitionTable bootloader_detect () throws GLib.Error; public async abstract InstallerDaemon.DiskInfo get_disks (bool get_partitions = false) throws GLib.Error; public async abstract int decrypt_partition (string path, string pv, string password) throws GLib.Error; @@ -59,7 +59,7 @@ public class Installer.Daemon { daemon.on_log_message.connect ((level, message) => on_log_message (level, message)); } - public Distinst.PartitionTable bootloader_detect () { + public InstallerDaemon.PartitionTable bootloader_detect () { if (daemon == null) { return fallback_bootloader_detect (); } @@ -71,12 +71,12 @@ public class Installer.Daemon { } } - private Distinst.PartitionTable fallback_bootloader_detect () { + private InstallerDaemon.PartitionTable fallback_bootloader_detect () { var efi_file = GLib.File.new_for_path ("/sys/firmware/efi"); if (efi_file.query_exists ()) { - return Distinst.PartitionTable.GPT; + return InstallerDaemon.PartitionTable.GPT; } else { - return Distinst.PartitionTable.MSDOS; + return InstallerDaemon.PartitionTable.MSDOS; } } diff --git a/src/Views/PartitioningView.vala b/src/Views/PartitioningView.vala index 4751713e5..ada7412a4 100644 --- a/src/Views/PartitioningView.vala +++ b/src/Views/PartitioningView.vala @@ -53,11 +53,11 @@ public class Installer.PartitioningView : AbstractInstallerView { var bootloader = Daemon.get_default ().bootloader_detect (); switch (bootloader) { - case Distinst.PartitionTable.MSDOS: + case MSDOS: // Device is in BIOS mode, so we just require a root partition required_description = _("You must at least select a Root (/) partition."); break; - case Distinst.PartitionTable.GPT: + case GPT: // Device is in EFI mode, so we also require a boot partition required_description = _("You must at least select a Root (/) partition and a Boot (/boot/efi) partition."); break; @@ -222,9 +222,9 @@ public class Installer.PartitioningView : AbstractInstallerView { var bootloader = Daemon.get_default ().bootloader_detect (); switch (bootloader) { - case Distinst.PartitionTable.MSDOS: + case MSDOS: break; - case Distinst.PartitionTable.GPT: + case GPT: required |= Defined.EFI; break; } diff --git a/src/Widgets/PartitionMenu.vala b/src/Widgets/PartitionMenu.vala index 5e1750f77..3fde1af5c 100644 --- a/src/Widgets/PartitionMenu.vala +++ b/src/Widgets/PartitionMenu.vala @@ -49,7 +49,7 @@ public class Installer.PartitionMenu : Gtk.Popover { partition_path = path; parent_disk = parent; - string boot_partition = (Daemon.get_default ().bootloader_detect () == Distinst.PartitionTable.GPT) + string boot_partition = (Daemon.get_default ().bootloader_detect () == InstallerDaemon.PartitionTable.GPT) ? "/boot/efi" : "/boot"; @@ -156,7 +156,7 @@ public class Installer.PartitionMenu : Gtk.Popover { custom.visible = visible; if (active == 2) { - if (Daemon.get_default ().bootloader_detect () == Distinst.PartitionTable.GPT) { + if (Daemon.get_default ().bootloader_detect () == InstallerDaemon.PartitionTable.GPT) { type.active = 2; } else { type.active = 0; @@ -323,7 +323,7 @@ public class Installer.PartitionMenu : Gtk.Popover { case 1: return "/home"; case 2: - if (Daemon.get_default ().bootloader_detect () == Distinst.PartitionTable.GPT) { + if (Daemon.get_default ().bootloader_detect () == InstallerDaemon.PartitionTable.GPT) { return "/boot/efi"; } else { return "/boot"; From 3a2ed8dab8d502f95da83cd62b39ec600d9d54ee Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 20:35:15 +0100 Subject: [PATCH 06/17] Add new enums and struct for InstallerDaemon and update flags in Daemon and ProgressView --- common/DBusStructures.vala | 17 ++++++++++++++++- daemon/Daemon.vala | 11 ++++++++++- src/Views/ProgressView.vala | 28 ++++++++++++++-------------- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 2b1308464..59ea1aa8d 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -97,6 +97,20 @@ public enum InstallerDaemon.PartitionTable { MSDOS; } +public enum InstallerDaemon.Step { + BACKUP, + INIT, + PARTITION, + EXTRACT, + CONFIGURE, + BOOTLOADER; +} + +public struct InstallerDaemon.Status { + Step step; + int percent; +} + public struct InstallerDaemon.Partition { string device_path; @@ -113,7 +127,8 @@ public struct InstallerDaemon.InstallConfig { string keyboard_layout; string keyboard_variant; string lang; - uint8 flags; + bool modify_boot_order; + bool install_drivers; } [Flags] diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index e458528ae..a3cdb46af 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -186,7 +186,16 @@ public class InstallerDaemon.Daemon : GLib.Object { installer.on_status ((status) => on_status (status)); var distinst_config = Distinst.Config (); - distinst_config.flags = config.flags; + uint8 flags = 0; + if (config.modify_boot_order) { + flags = Distinst.MODIFY_BOOT_ORDER; + } + + if (config.install_drivers) { + flags |= Distinst.RUN_UBUNTU_DRIVERS; + } + + distinst_config.flags = flags; distinst_config.hostname = config.hostname; var casper = casper_dir (); diff --git a/src/Views/ProgressView.vala b/src/Views/ProgressView.vala index d0e7f105f..5943e991e 100644 --- a/src/Views/ProgressView.vala +++ b/src/Views/ProgressView.vala @@ -112,10 +112,10 @@ public class ProgressView : AbstractInstallerView { public void start_installation () { if (Installer.App.test_mode) { new Thread (null, () => { - fake_status (Distinst.Step.PARTITION); - fake_status (Distinst.Step.EXTRACT); - fake_status (Distinst.Step.CONFIGURE); - fake_status (Distinst.Step.BOOTLOADER); + fake_status (InstallerDaemon.Step.PARTITION); + fake_status (InstallerDaemon.Step.EXTRACT); + fake_status (InstallerDaemon.Step.CONFIGURE); + fake_status (InstallerDaemon.Step.BOOTLOADER); return null; }); } else { @@ -133,9 +133,9 @@ public class ProgressView : AbstractInstallerView { unowned Configuration current_config = Configuration.get_default (); var config = InstallerDaemon.InstallConfig (); - config.flags = Distinst.MODIFY_BOOT_ORDER; + config.modify_boot_order = true; if (current_config.install_drivers) { - config.flags |= Distinst.RUN_UBUNTU_DRIVERS; + config.install_drivers = true; } config.hostname = Utils.get_hostname (); config.lang = "en_US.UTF-8"; @@ -199,9 +199,9 @@ public class ProgressView : AbstractInstallerView { } } - private void fake_status (Distinst.Step step) { + private void fake_status (InstallerDaemon.Step step) { for (var percent = 0; percent <= 100; percent++) { - Distinst.Status status = Distinst.Status () { + InstallerDaemon.Status status = InstallerDaemon.Status () { step = step, percent = percent }; @@ -210,9 +210,9 @@ public class ProgressView : AbstractInstallerView { } } - private void installation_status_callback (Distinst.Status status) { + private void installation_status_callback (InstallerDaemon.Status status) { Idle.add (() => { - if (status.percent == 100 && status.step == Distinst.Step.BOOTLOADER) { + if (status.percent == 100 && status.step == InstallerDaemon.Step.BOOTLOADER) { on_success (); return GLib.Source.REMOVE; } @@ -220,21 +220,21 @@ public class ProgressView : AbstractInstallerView { string step_string = ""; double fraction = ((double) status.percent) / (100.0 * NUM_STEP); switch (status.step) { - case Distinst.Step.PARTITION: + case PARTITION: ///TRANSLATORS: The current step of the installer back-end step_string = _("Partitioning Drive"); break; - case Distinst.Step.EXTRACT: + case EXTRACT: fraction += 2 * (1.0 / NUM_STEP); ///TRANSLATORS: The current step of the installer back-end step_string = _("Extracting Files"); break; - case Distinst.Step.CONFIGURE: + case CONFIGURE: fraction += 3 * (1.0 / NUM_STEP); ///TRANSLATORS: The current step of the installer back-end step_string = _("Configuring the System"); break; - case Distinst.Step.BOOTLOADER: + case BOOTLOADER: fraction += 4 * (1.0 / NUM_STEP); ///TRANSLATORS: The current step of the installer back-end step_string = _("Finishing the Installation"); From c1e4fa95982aa81c30ace6c9edd53ce879703a08 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 20:44:17 +0100 Subject: [PATCH 07/17] Refactor to_common_usage_bootloader method in Daemon class --- daemon/Daemon.vala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index a3cdb46af..ab9c4a2b2 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -596,14 +596,13 @@ public class InstallerDaemon.Daemon : GLib.Object { } } - public InstallerDaemon.PartitionTable to_common_usage_bootloader (Distinst.PartitionTable bootloader) { + private InstallerDaemon.PartitionTable to_common_usage_bootloader (Distinst.PartitionTable bootloader) { switch (bootloader) { case GPT: return InstallerDaemon.PartitionTable.GPT; case MSDOS: return InstallerDaemon.PartitionTable.MSDOS; case NONE: - return InstallerDaemon.PartitionTable.NONE; default: return InstallerDaemon.PartitionTable.NONE; } From 7cdde6a836a307542341a906ddf6e9460616cfd7 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:05:44 +0100 Subject: [PATCH 08/17] Add InstallerDaemon.LogLevel and InstallerDaemon.Error to InstallerDaemon.Daemon signals --- common/DBusStructures.vala | 13 +++++++ daemon/Daemon.vala | 64 ++++++++++++++++++++++++++++---- src/Helpers/InstallerDaemon.vala | 12 +++--- src/Helpers/LogHelper.vala | 14 +++---- src/Views/ProgressView.vala | 6 +-- 5 files changed, 85 insertions(+), 24 deletions(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 59ea1aa8d..7f83735dc 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -111,6 +111,19 @@ public struct InstallerDaemon.Status { int percent; } +public enum InstallerDaemon.LogLevel { + TRACE, + DEBUG, + INFO, + WARN, + ERROR; +} + +public struct InstallerDaemon.Error { + Step step; + int err; +} + public struct InstallerDaemon.Partition { string device_path; diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index ab9c4a2b2..9711a964f 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -19,16 +19,16 @@ private static GLib.MainLoop loop; [DBus (name = "io.elementary.InstallerDaemon")] public class InstallerDaemon.Daemon : GLib.Object { - public signal void on_log_message (Distinst.LogLevel level, string message); - public signal void on_status (Distinst.Status status); - public signal void on_error (Distinst.Error error); + public signal void on_log_message (InstallerDaemon.LogLevel level, string message); + public signal void on_status (InstallerDaemon.Status status); + public signal void on_error (InstallerDaemon.Error error); private Distinst.Disks disks; construct { Distinst.log ((level, message) => { Idle.add (() => { - on_log_message (level, message); + on_log_message (to_common_log_level (level), message); }); }); } @@ -182,8 +182,8 @@ public class InstallerDaemon.Daemon : GLib.Object { private void install (InstallConfig config, owned Distinst.Disks disks) { var installer = new Distinst.Installer (); - installer.on_error ((error) => on_error (error)); - installer.on_status ((status) => on_status (status)); + installer.on_error ((error) => on_error (to_common_error (error))); + installer.on_status ((status) => on_status (to_common_status (status))); var distinst_config = Distinst.Config (); uint8 flags = 0; @@ -212,7 +212,7 @@ public class InstallerDaemon.Daemon : GLib.Object { new Thread (null, () => { if (installer.install ((owned) disks, distinst_config) != 0) { Idle.add (() => { - on_error (Distinst.Error ()); + on_error (InstallerDaemon.Error ()); return GLib.Source.REMOVE; }); } @@ -229,7 +229,7 @@ public class InstallerDaemon.Daemon : GLib.Object { var demo_mode_file = GLib.File.new_for_path ("/var/lib/lightdm/demo-mode"); try { demo_mode_file.create (GLib.FileCreateFlags.NONE); - } catch (Error e) { + } catch (GLib.Error e) { if (!(e is GLib.IOError.EXISTS)) { throw e; } @@ -607,6 +607,54 @@ public class InstallerDaemon.Daemon : GLib.Object { return InstallerDaemon.PartitionTable.NONE; } } + + private InstallerDaemon.LogLevel to_common_log_level (Distinst.LogLevel level) { + switch (level) { + case DEBUG: + return InstallerDaemon.LogLevel.DEBUG; + case INFO: + return InstallerDaemon.LogLevel.INFO; + case WARN: + return InstallerDaemon.LogLevel.WARN; + case ERROR: + return InstallerDaemon.LogLevel.ERROR; + case TRACE: + default: + return InstallerDaemon.LogLevel.TRACE; + } + } + + private InstallerDaemon.Error to_common_error (Distinst.Error error) { + return InstallerDaemon.Error () { + step = to_common_step (error.step), + err = error.err + }; + } + + private InstallerDaemon.Step to_common_step (Distinst.Step step) { + switch (step) { + case BACKUP: + return InstallerDaemon.Step.BACKUP; + case PARTITION: + return InstallerDaemon.Step.PARTITION; + case EXTRACT: + return InstallerDaemon.Step.EXTRACT; + case CONFIGURE: + return InstallerDaemon.Step.CONFIGURE; + case BOOTLOADER: + return InstallerDaemon.Step.BOOTLOADER; + case INIT: + default: + return InstallerDaemon.Step.INIT; + } + } + + private InstallerDaemon.Status to_common_status (Distinst.Status status) { + return InstallerDaemon.Status () { + step = to_common_step (status.step), + percent = status.percent + }; + } } private void on_bus_acquired (GLib.DBusConnection connection, string name) { diff --git a/src/Helpers/InstallerDaemon.vala b/src/Helpers/InstallerDaemon.vala index 1d523c258..25cdbec16 100644 --- a/src/Helpers/InstallerDaemon.vala +++ b/src/Helpers/InstallerDaemon.vala @@ -23,9 +23,9 @@ public class Installer.Daemon { [DBus (name = "io.elementary.InstallerDaemon")] private interface InstallerInterface : GLib.DBusProxy { - public signal void on_error (Distinst.Error error); - public signal void on_status (Distinst.Status status); - public signal void on_log_message (Distinst.LogLevel level, string message); + public signal void on_error (InstallerDaemon.Error error); + public signal void on_status (InstallerDaemon.Status status); + public signal void on_log_message (InstallerDaemon.LogLevel level, string message); public abstract InstallerDaemon.PartitionTable bootloader_detect () throws GLib.Error; @@ -38,9 +38,9 @@ public class Installer.Daemon { public async abstract void trigger_demo_mode () throws GLib.Error; } - public signal void on_error (Distinst.Error error); - public signal void on_status (Distinst.Status status); - public signal void on_log_message (Distinst.LogLevel level, string message); + public signal void on_error (InstallerDaemon.Error error); + public signal void on_status (InstallerDaemon.Status status); + public signal void on_log_message (InstallerDaemon.LogLevel level, string message); private InstallerInterface daemon; diff --git a/src/Helpers/LogHelper.vala b/src/Helpers/LogHelper.vala index 00677e1db..0bbb1e72f 100644 --- a/src/Helpers/LogHelper.vala +++ b/src/Helpers/LogHelper.vala @@ -16,17 +16,17 @@ * along with this program. If not, see . */ -static string level_name (Distinst.LogLevel level) { +static string level_name (InstallerDaemon.LogLevel level) { switch (level) { - case Distinst.LogLevel.TRACE: + case TRACE: return "TRACE"; - case Distinst.LogLevel.DEBUG: + case DEBUG: return "DEBUG"; - case Distinst.LogLevel.INFO: + case INFO: return "INFO"; - case Distinst.LogLevel.WARN: + case WARN: return "WARN"; - case Distinst.LogLevel.ERROR: + case ERROR: return "ERROR"; default: return "UNKNOWN"; @@ -50,7 +50,7 @@ public class LogHelper : GLib.Object { buffer.text = ""; } - public void log_func (Distinst.LogLevel level, string message) { + public void log_func (InstallerDaemon.LogLevel level, string message) { stdout.printf ("log: %s: %s\n", level_name (level), message); Gtk.TextIter end_iter; buffer.get_end_iter (out end_iter); diff --git a/src/Views/ProgressView.vala b/src/Views/ProgressView.vala index 5943e991e..9759d4289 100644 --- a/src/Views/ProgressView.vala +++ b/src/Views/ProgressView.vala @@ -167,7 +167,7 @@ public class ProgressView : AbstractInstallerView { current_config.encryption_password ?? "" ); } catch (Error e) { - log_helper.log_func (Distinst.LogLevel.ERROR, e.message); + log_helper.log_func (InstallerDaemon.LogLevel.ERROR, e.message); on_error (); } } else { @@ -193,7 +193,7 @@ public class ProgressView : AbstractInstallerView { try { yield daemon.install_with_custom_disk_layout (config, mounts, creds); } catch (Error e) { - log_helper.log_func (Distinst.LogLevel.ERROR, e.message); + log_helper.log_func (InstallerDaemon.LogLevel.ERROR, e.message); on_error (); } } @@ -247,7 +247,7 @@ public class ProgressView : AbstractInstallerView { }); } - private void installation_error_callback (Distinst.Error error) { + private void installation_error_callback (InstallerDaemon.Error error) { Idle.add (() => { on_error (); return GLib.Source.REMOVE; From 08a0147ff786e3003a30cea310478613cade46ec Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:07:33 +0100 Subject: [PATCH 09/17] Utils: Remove distinst specific code --- src/Utils.vala | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Utils.vala b/src/Utils.vala index 8368ab2cf..8c7afcc34 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -264,13 +264,6 @@ namespace Utils { string hostname = get_ubiquity_compatible_hostname () ?? ("elementary-os" + "-" + get_chassis ()); hostname += "-" + get_machine_id ().substring (0, 8); - // If the automatic hostname logic fails in some way, it's possible we may generate an invalid - // hostname. We could fix this by trimming traling/leading hyphens or other invalid characters. - // But it's probably a bad hostname anyway, so just fallback - if (!Distinst.validate_hostname (hostname)) { - hostname = "elementary-os"; - } - return hostname; } } From dd09a4b0ecd79dff324c297f22ac9a85a016c235 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:08:46 +0100 Subject: [PATCH 10/17] Refactor file common/DBusStructures.vala to handle FileSystem.NONE case in a default statement. --- common/DBusStructures.vala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 7f83735dc..8a5ec8b18 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -62,8 +62,6 @@ public enum InstallerDaemon.FileSystem { return "fat16"; case FAT32: return "fat32"; - case NONE: - return "none"; case NTFS: return "ntfs"; case SWAP: @@ -74,9 +72,10 @@ public enum InstallerDaemon.FileSystem { return "lvm"; case LUKS: return "luks"; + case NONE: + default: + return "none"; } - - return "none"; } } From 82c20cd20c329e4673f38bfe160428256746ac8f Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:10:40 +0100 Subject: [PATCH 11/17] Remove distinst_dep from gui_dependencies --- src/meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index 39dbd5913..1c3a007e1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -54,7 +54,6 @@ config_file = configure_file( ) gui_dependencies = [ - distinst_dep, gee_dep, glib_dep, gnome_keyboard_dep, From 2d382d2b8e074d4f6f5d9043dbe42860af017207 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:19:10 +0100 Subject: [PATCH 12/17] Add support for Distinst installer backend in daemon --- daemon/Daemon.vala | 644 +---------------------------------- daemon/DistinstBackend.vala | 656 ++++++++++++++++++++++++++++++++++++ daemon/meson.build | 12 +- meson.build | 8 +- meson_options.txt | 1 + 5 files changed, 678 insertions(+), 643 deletions(-) create mode 100644 daemon/DistinstBackend.vala diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index 9711a964f..0fd716099 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -17,649 +17,11 @@ private static GLib.MainLoop loop; -[DBus (name = "io.elementary.InstallerDaemon")] -public class InstallerDaemon.Daemon : GLib.Object { - public signal void on_log_message (InstallerDaemon.LogLevel level, string message); - public signal void on_status (InstallerDaemon.Status status); - public signal void on_error (InstallerDaemon.Error error); - - private Distinst.Disks disks; - - construct { - Distinst.log ((level, message) => { - Idle.add (() => { - on_log_message (to_common_log_level (level), message); - }); - }); - } - - public InstallerDaemon.PartitionTable bootloader_detect () throws GLib.Error { - return to_common_usage_bootloader (Distinst.bootloader_detect ()); - } - - public DiskInfo get_disks (bool get_partitions = false) throws GLib.Error { - disks = Distinst.Disks.probe (); - - if (get_partitions) { - disks.initialize_volume_groups (); - } - - DiskInfo result = DiskInfo (); - - Disk[] physical_disks = {}; - Disk[] logical_disks = {}; - - foreach (unowned Distinst.Disk disk in disks.list ()) { - if (disk.is_read_only ()) { - continue; - } - - // Skip root disk or live disk - if (disk.contains_mount ("/", disks) || disk.contains_mount ("/cdrom", disks)) { - continue; - } - - Partition[] partitions = {}; - - if (get_partitions) { - foreach (unowned Distinst.Partition part in disk.list_partitions ()) { - string lvm_vg = (part.get_file_system () == Distinst.FileSystem.LVM) - ? string_from_utf8 (part.get_current_lvm_volume_group ()) - : ""; - - partitions += Partition () { - device_path = string_from_utf8 (part.get_device_path ()), - filesystem = to_common_fs (part.get_file_system ()), - start_sector = part.get_start_sector (), - end_sector = part.get_end_sector (), - sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), - current_lvm_volume_group = lvm_vg - }; - } - } - - string model = string_from_utf8 (disk.get_model ()); - string name = model.length == 0 ? string_from_utf8 (disk.get_serial ()).replace ("_", " ") : model; - - physical_disks += Disk () { - name = name, - device_path = string_from_utf8 (disk.get_device_path ()), - sectors = disk.get_sectors (), - sector_size = disk.get_sector_size (), - rotational = disk.is_rotational (), - removable = disk.is_removable (), - partitions = partitions - }; - } - - if (get_partitions) { - foreach (unowned Distinst.LvmDevice disk in disks.list_logical ()) { - Partition[] partitions = {}; - - foreach (unowned Distinst.Partition part in disk.list_partitions ()) { - string lvm_vg = (part.get_file_system () == Distinst.FileSystem.LVM) - ? string_from_utf8 (part.get_current_lvm_volume_group ()) - : ""; - - partitions += Partition () { - device_path = string_from_utf8 (part.get_device_path ()), - filesystem = to_common_fs (part.get_file_system ()), - start_sector = part.get_start_sector (), - end_sector = part.get_end_sector (), - sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), - current_lvm_volume_group = lvm_vg - }; - } - - logical_disks += Disk () { - name = string_from_utf8 (disk.get_model ()), - device_path = string_from_utf8 (disk.get_device_path ()), - sectors = disk.get_sectors (), - sector_size = disk.get_sector_size (), - partitions = partitions - }; - } - } - - result.physical_disks = physical_disks; - result.logical_disks = logical_disks; - return result; - } - - public int decrypt_partition (string path, string pv, string password) throws GLib.Error { - return disks.decrypt_partition (path, Distinst.LvmEncryption () { - physical_volume = pv, - password = password, - keydata = null - }); - } - - public Disk get_logical_device (string pv) throws GLib.Error { - unowned Distinst.LvmDevice disk = disks.get_logical_device (pv); - if (disk == null) { - throw new GLib.IOError.NOT_FOUND ("Couldn't find a logical device with that name"); - } - - Partition[] partitions = {}; - - foreach (unowned Distinst.Partition part in disk.list_partitions ()) { - string lvm_vg = (part.get_file_system () == Distinst.FileSystem.LVM) - ? string_from_utf8 (part.get_current_lvm_volume_group ()) - : ""; - - partitions += Partition () { - device_path = string_from_utf8 (part.get_device_path ()), - filesystem = to_common_fs (part.get_file_system ()), - start_sector = part.get_start_sector (), - end_sector = part.get_end_sector (), - sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), - current_lvm_volume_group = lvm_vg - }; - } - - return Disk () { - name = string_from_utf8 (disk.get_model ()), - device_path = string_from_utf8 (disk.get_device_path ()), - sectors = disk.get_sectors (), - sector_size = disk.get_sector_size (), - partitions = partitions - }; - } - - public void install_with_default_disk_layout (InstallConfig config, string disk, bool encrypt, string encryption_password) throws GLib.Error { - var disks = new Distinst.Disks (); - default_disk_configuration (disks, disk, encrypt ? encryption_password : null); - - install (config, (owned) disks); - } - - public void install_with_custom_disk_layout (InstallConfig config, Mount[] disk_config, LuksCredentials[] credentials) throws GLib.Error { - var disks = new Distinst.Disks (); - custom_disk_configuration (disks, disk_config, credentials); - - install (config, (owned) disks); - } - - private void install (InstallConfig config, owned Distinst.Disks disks) { - var installer = new Distinst.Installer (); - installer.on_error ((error) => on_error (to_common_error (error))); - installer.on_status ((status) => on_status (to_common_status (status))); - - var distinst_config = Distinst.Config (); - uint8 flags = 0; - if (config.modify_boot_order) { - flags = Distinst.MODIFY_BOOT_ORDER; - } - - if (config.install_drivers) { - flags |= Distinst.RUN_UBUNTU_DRIVERS; - } - - distinst_config.flags = flags; - distinst_config.hostname = config.hostname; - - var casper = casper_dir (); - distinst_config.remove = GLib.Path.build_filename (casper, "filesystem.manifest-remove"); - distinst_config.squashfs = GLib.Path.build_filename (casper, "filesystem.squashfs"); - - debug ("language: %s\n", config.lang); - distinst_config.lang = config.lang; - - distinst_config.keyboard_layout = config.keyboard_layout; - distinst_config.keyboard_model = null; - distinst_config.keyboard_variant = config.keyboard_variant == "" ? null : config.keyboard_variant; - - new Thread (null, () => { - if (installer.install ((owned) disks, distinst_config) != 0) { - Idle.add (() => { - on_error (InstallerDaemon.Error ()); - return GLib.Source.REMOVE; - }); - } - - return null; - }); - } - - public void set_demo_mode_locale (string locale) throws GLib.Error { - GLib.FileUtils.set_contents ("/etc/default/locale", "LANG=" + locale); - } - - public void trigger_demo_mode () throws GLib.Error { - var demo_mode_file = GLib.File.new_for_path ("/var/lib/lightdm/demo-mode"); - try { - demo_mode_file.create (GLib.FileCreateFlags.NONE); - } catch (GLib.Error e) { - if (!(e is GLib.IOError.EXISTS)) { - throw e; - } - } - } - - private string casper_dir () { - const string CDROM = "/cdrom"; - - try { - var cdrom_dir = File.new_for_path (CDROM); - var iter = cdrom_dir.enumerate_children (FileAttribute.STANDARD_NAME, 0); - - FileInfo info; - while ((info = iter.next_file ()) != null) { - unowned string name = info.get_name (); - if (name.has_prefix ("casper")) { - return GLib.Path.build_filename (CDROM, name); - } - } - } catch (GLib.Error e) { - critical ("failed to find casper dir automatically: %s\n", e.message); - } - - return GLib.Path.build_filename (CDROM, "casper"); - } - - private void default_disk_configuration (Distinst.Disks disks, string disk_path, string? encryption_password) throws GLib.IOError { - var encrypted_vg = Distinst.generate_unique_id ("cryptdata"); - var root_vg = Distinst.generate_unique_id ("data"); - if (encrypted_vg == null || root_vg == null) { - throw new GLib.IOError.FAILED ("Unable to generate unique volume group IDs"); - } - - Distinst.LvmEncryption? encryption; - if (encryption_password != null) { - debug ("encrypting"); - encryption = Distinst.LvmEncryption () { - physical_volume = encrypted_vg, - password = encryption_password, - keydata = null - }; - } else { - debug ("not encrypting"); - encryption = null; - } - - debug ("disk: %s\n", disk_path); - var disk = new Distinst.Disk (disk_path); - if (disk == null) { - throw new GLib.IOError.FAILED ("Could not find %s", disk_path); - } - - var bootloader = Distinst.bootloader_detect (); - - var start_sector = Distinst.Sector () { - flag = Distinst.SectorKind.START, - value = 0 - }; - - // 256 MiB is the minimum distinst ESP partition size, so this is 256 MiB in MB plus a bit - // extra for safety - var efi_sector = Distinst.Sector () { - flag = Distinst.SectorKind.MEGABYTE, - value = 278 - }; - - // 1024MB /boot partition that's created if we're doing encryption - var boot_sector = Distinst.Sector () { - flag = Distinst.SectorKind.MEGABYTE, - value = efi_sector.value + 1024 - }; - - // 4GB swap partition at the end - var swap_sector = Distinst.Sector () { - flag = Distinst.SectorKind.MEGABYTE_FROM_END, - value = 4096 - }; - - var end_sector = Distinst.Sector () { - flag = Distinst.SectorKind.END, - value = 0 - }; - - // Prepares a new partition table. - int result = disk.mklabel (bootloader); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to write partition table to %s", disk_path); - } - - var start = disk.get_sector (ref start_sector); - var end = disk.get_sector (ref boot_sector); - - switch (bootloader) { - case Distinst.PartitionTable.MSDOS: - // This is used to ensure LVM installs will work with BIOS - result = disk.add_partition ( - new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.EXT4) - .partition_type (Distinst.PartitionType.PRIMARY) - .flag (Distinst.PartitionFlag.BOOT) - .mount ("/boot") - ); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to add boot partition to %s", disk_path); - } - - // Start the LVM from the end of our /boot partition - start = disk.get_sector (ref boot_sector); - break; - case Distinst.PartitionTable.GPT: - end = disk.get_sector (ref efi_sector); - - // A FAT32 partition is required for EFI installs - result = disk.add_partition ( - new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.FAT32) - .partition_type (Distinst.PartitionType.PRIMARY) - .flag (Distinst.PartitionFlag.ESP) - .mount ("/boot/efi") - ); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to add EFI partition to %s", disk_path); - } - - // If we're encrypting, we need an unencrypted partition to store kernels and initramfs images - if (encryption != null) { - start = disk.get_sector (ref efi_sector); - end = disk.get_sector (ref boot_sector); - - result = disk.add_partition ( - new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.EXT4) - .partition_type (Distinst.PartitionType.PRIMARY) - .mount ("/boot") - ); - - if (result != 0) { - throw new GLib.IOError.FAILED ("unable to add /boot partition to %s", disk_path); - } - - // Start the LVM from the end of our /boot/efi and /boot partitions - start = disk.get_sector (ref boot_sector); - } else { - // No encryption, we only have a /boot/efi partition, start the LVM from there - start = disk.get_sector (ref efi_sector); - } - - break; - } - - end = disk.get_sector (ref end_sector); - - result = disk.add_partition ( - new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.LVM) - .partition_type (Distinst.PartitionType.PRIMARY) - .logical_volume (root_vg, encryption) - ); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to add LVM partition to %s", disk_path); - } - - disks.push ((owned) disk); - - result = disks.initialize_volume_groups (); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to initialize volume groups on %s", disk_path); - } - - unowned Distinst.LvmDevice lvm_device = disks.get_logical_device (root_vg); - - if (lvm_device == null) { - throw new GLib.IOError.FAILED ("Unable to find '%s' volume group on %s", root_vg, disk_path); - } - - start = lvm_device.get_sector (ref start_sector); - end = lvm_device.get_sector (ref swap_sector); - - result = lvm_device.add_partition ( - new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.EXT4) - .name ("root") - .mount ("/") - ); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to add / partition to LVM on %s", disk_path); - } - - start = lvm_device.get_sector (ref swap_sector); - end = lvm_device.get_sector (ref end_sector); - - result = lvm_device.add_partition ( - new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.SWAP) - .name ("swap") - ); - - if (result != 0) { - throw new GLib.IOError.FAILED ("Unable to add swap partition to LVM on %s", disk_path); - } - } - - private void custom_disk_configuration (Distinst.Disks disks, Mount[] mounts, LuksCredentials[] credentials) throws GLib.IOError { - Mount[] lvm_devices = {}; - - foreach (Mount m in mounts) { - if (m.is_lvm ()) { - lvm_devices += m; - } else { - unowned Distinst.Disk disk = disks.get_physical_device (m.parent_disk); - if (disk == null) { - var new_disk = new Distinst.Disk (m.parent_disk); - if (new_disk == null) { - throw new GLib.IOError.FAILED ("Could not find physical device: '%s'", m.parent_disk); - } - - disks.push ((owned) new_disk); - disk = disks.get_physical_device (m.parent_disk); - } - - unowned Distinst.Partition partition = disk.get_partition_by_path (m.partition_path); - - if (partition == null) { - throw new GLib.IOError.FAILED ("Could not find %s", m.partition_path); - } - - if (m.mount_point == "/boot/efi") { - if (m.is_valid_boot_mount ()) { - if (m.should_format ()) { - partition.format_with (to_distinst_fs (m.filesystem)); - } - - partition.set_mount (m.mount_point); - partition.set_flags ({ Distinst.PartitionFlag.ESP }); - } else { - throw new GLib.IOError.FAILED ("Unreachable code path -- EFI partition is invalid"); - } - } else { - if (m.filesystem != InstallerDaemon.FileSystem.SWAP) { - partition.set_mount (m.mount_point); - } - - if (m.mount_point == "/boot") { - partition.set_flags ({ Distinst.PartitionFlag.BOOT }); - } - - if (m.should_format ()) { - partition.format_with (to_distinst_fs (m.filesystem)); - } - } - } - } - - disks.initialize_volume_groups (); - - foreach (LuksCredentials cred in credentials) { - disks.decrypt_partition (cred.device, Distinst.LvmEncryption () { - physical_volume = cred.pv, - password = cred.password, - keydata = null - }); - } - - foreach (Mount m in lvm_devices) { - var vg = m.parent_disk.offset (12); - unowned Distinst.LvmDevice disk = disks.get_logical_device (vg); - if (disk == null) { - throw new GLib.IOError.FAILED ("Could not find %s", vg); - } - - unowned Distinst.Partition partition = disk.get_partition_by_path (m.partition_path); - - if (partition == null) { - throw new GLib.IOError.FAILED ("could not find %s", m.partition_path); - } - - if (m.filesystem != InstallerDaemon.FileSystem.SWAP) { - partition.set_mount (m.mount_point); - } - - if (m.should_format ()) { - partition.format_and_keep_name (to_distinst_fs (m.filesystem)); - } - } - } - - private static string string_from_utf8 (uint8[] input) { - var builder = new GLib.StringBuilder.sized (input.length); - builder.append_len ((string) input, input.length); - return (owned) builder.str; - } - - private InstallerDaemon.FileSystem to_common_fs (Distinst.FileSystem fs) { - switch (fs) { - case BTRFS: - return InstallerDaemon.FileSystem.BTRFS; - case EXT2: - return InstallerDaemon.FileSystem.EXT2; - case EXT3: - return InstallerDaemon.FileSystem.EXT3; - case EXT4: - return InstallerDaemon.FileSystem.EXT4; - case F2FS: - return InstallerDaemon.FileSystem.F2FS; - case FAT16: - return InstallerDaemon.FileSystem.FAT16; - case FAT32: - return InstallerDaemon.FileSystem.FAT32; - case NONE: - return InstallerDaemon.FileSystem.NONE; - case NTFS: - return InstallerDaemon.FileSystem.NTFS; - case SWAP: - return InstallerDaemon.FileSystem.SWAP; - case XFS: - return InstallerDaemon.FileSystem.XFS; - case LVM: - return InstallerDaemon.FileSystem.LVM; - case LUKS: - return InstallerDaemon.FileSystem.LUKS; - default: - return InstallerDaemon.FileSystem.NONE; - } - } - - private InstallerDaemon.PartitionUsage to_common_usage (Distinst.PartitionUsage usage) { - return InstallerDaemon.PartitionUsage () { - tag = usage.tag, - value = usage.value - }; - } - - private Distinst.FileSystem to_distinst_fs (InstallerDaemon.FileSystem fs) { - switch (fs) { - case BTRFS: - return Distinst.FileSystem.BTRFS; - case EXT2: - return Distinst.FileSystem.EXT2; - case EXT3: - return Distinst.FileSystem.EXT3; - case EXT4: - return Distinst.FileSystem.EXT4; - case F2FS: - return Distinst.FileSystem.F2FS; - case FAT16: - return Distinst.FileSystem.FAT16; - case FAT32: - return Distinst.FileSystem.FAT32; - case NONE: - return Distinst.FileSystem.NONE; - case NTFS: - return Distinst.FileSystem.NTFS; - case SWAP: - return Distinst.FileSystem.SWAP; - case XFS: - return Distinst.FileSystem.XFS; - case LVM: - return Distinst.FileSystem.LVM; - case LUKS: - return Distinst.FileSystem.LUKS; - default: - return Distinst.FileSystem.NONE; - } - } - - private InstallerDaemon.PartitionTable to_common_usage_bootloader (Distinst.PartitionTable bootloader) { - switch (bootloader) { - case GPT: - return InstallerDaemon.PartitionTable.GPT; - case MSDOS: - return InstallerDaemon.PartitionTable.MSDOS; - case NONE: - default: - return InstallerDaemon.PartitionTable.NONE; - } - } - - private InstallerDaemon.LogLevel to_common_log_level (Distinst.LogLevel level) { - switch (level) { - case DEBUG: - return InstallerDaemon.LogLevel.DEBUG; - case INFO: - return InstallerDaemon.LogLevel.INFO; - case WARN: - return InstallerDaemon.LogLevel.WARN; - case ERROR: - return InstallerDaemon.LogLevel.ERROR; - case TRACE: - default: - return InstallerDaemon.LogLevel.TRACE; - } - } - - private InstallerDaemon.Error to_common_error (Distinst.Error error) { - return InstallerDaemon.Error () { - step = to_common_step (error.step), - err = error.err - }; - } - - private InstallerDaemon.Step to_common_step (Distinst.Step step) { - switch (step) { - case BACKUP: - return InstallerDaemon.Step.BACKUP; - case PARTITION: - return InstallerDaemon.Step.PARTITION; - case EXTRACT: - return InstallerDaemon.Step.EXTRACT; - case CONFIGURE: - return InstallerDaemon.Step.CONFIGURE; - case BOOTLOADER: - return InstallerDaemon.Step.BOOTLOADER; - case INIT: - default: - return InstallerDaemon.Step.INIT; - } - } - - private InstallerDaemon.Status to_common_status (Distinst.Status status) { - return InstallerDaemon.Status () { - step = to_common_step (status.step), - percent = status.percent - }; - } -} - private void on_bus_acquired (GLib.DBusConnection connection, string name) { try { - connection.register_object ("/io/elementary/InstallerDaemon", new InstallerDaemon.Daemon ()); +#if DISTINST_BACKEND + connection.register_object ("/io/elementary/InstallerDaemon", new InstallerDaemon.DistinstBackend ()); +#endif } catch (GLib.Error e) { critical ("Unable to register the object: %s", e.message); } diff --git a/daemon/DistinstBackend.vala b/daemon/DistinstBackend.vala new file mode 100644 index 000000000..b356ba868 --- /dev/null +++ b/daemon/DistinstBackend.vala @@ -0,0 +1,656 @@ +/* + * Copyright 2021 elementary, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +[DBus (name = "io.elementary.InstallerDaemon")] +public class InstallerDaemon.DistinstBackend : GLib.Object { + public signal void on_log_message (InstallerDaemon.LogLevel level, string message); + public signal void on_status (InstallerDaemon.Status status); + public signal void on_error (InstallerDaemon.Error error); + + private Distinst.Disks disks; + + construct { + Distinst.log ((level, message) => { + Idle.add (() => { + on_log_message (to_common_log_level (level), message); + }); + }); + } + + public InstallerDaemon.PartitionTable bootloader_detect () throws GLib.Error { + return to_common_usage_bootloader (Distinst.bootloader_detect ()); + } + + public DiskInfo get_disks (bool get_partitions = false) throws GLib.Error { + disks = Distinst.Disks.probe (); + + if (get_partitions) { + disks.initialize_volume_groups (); + } + + DiskInfo result = DiskInfo (); + + Disk[] physical_disks = {}; + Disk[] logical_disks = {}; + + foreach (unowned Distinst.Disk disk in disks.list ()) { + if (disk.is_read_only ()) { + continue; + } + + // Skip root disk or live disk + if (disk.contains_mount ("/", disks) || disk.contains_mount ("/cdrom", disks)) { + continue; + } + + Partition[] partitions = {}; + + if (get_partitions) { + foreach (unowned Distinst.Partition part in disk.list_partitions ()) { + string lvm_vg = (part.get_file_system () == Distinst.FileSystem.LVM) + ? string_from_utf8 (part.get_current_lvm_volume_group ()) + : ""; + + partitions += Partition () { + device_path = string_from_utf8 (part.get_device_path ()), + filesystem = to_common_fs (part.get_file_system ()), + start_sector = part.get_start_sector (), + end_sector = part.get_end_sector (), + sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), + current_lvm_volume_group = lvm_vg + }; + } + } + + string model = string_from_utf8 (disk.get_model ()); + string name = model.length == 0 ? string_from_utf8 (disk.get_serial ()).replace ("_", " ") : model; + + physical_disks += Disk () { + name = name, + device_path = string_from_utf8 (disk.get_device_path ()), + sectors = disk.get_sectors (), + sector_size = disk.get_sector_size (), + rotational = disk.is_rotational (), + removable = disk.is_removable (), + partitions = partitions + }; + } + + if (get_partitions) { + foreach (unowned Distinst.LvmDevice disk in disks.list_logical ()) { + Partition[] partitions = {}; + + foreach (unowned Distinst.Partition part in disk.list_partitions ()) { + string lvm_vg = (part.get_file_system () == Distinst.FileSystem.LVM) + ? string_from_utf8 (part.get_current_lvm_volume_group ()) + : ""; + + partitions += Partition () { + device_path = string_from_utf8 (part.get_device_path ()), + filesystem = to_common_fs (part.get_file_system ()), + start_sector = part.get_start_sector (), + end_sector = part.get_end_sector (), + sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), + current_lvm_volume_group = lvm_vg + }; + } + + logical_disks += Disk () { + name = string_from_utf8 (disk.get_model ()), + device_path = string_from_utf8 (disk.get_device_path ()), + sectors = disk.get_sectors (), + sector_size = disk.get_sector_size (), + partitions = partitions + }; + } + } + + result.physical_disks = physical_disks; + result.logical_disks = logical_disks; + return result; + } + + public int decrypt_partition (string path, string pv, string password) throws GLib.Error { + return disks.decrypt_partition (path, Distinst.LvmEncryption () { + physical_volume = pv, + password = password, + keydata = null + }); + } + + public Disk get_logical_device (string pv) throws GLib.Error { + unowned Distinst.LvmDevice disk = disks.get_logical_device (pv); + if (disk == null) { + throw new GLib.IOError.NOT_FOUND ("Couldn't find a logical device with that name"); + } + + Partition[] partitions = {}; + + foreach (unowned Distinst.Partition part in disk.list_partitions ()) { + string lvm_vg = (part.get_file_system () == Distinst.FileSystem.LVM) + ? string_from_utf8 (part.get_current_lvm_volume_group ()) + : ""; + + partitions += Partition () { + device_path = string_from_utf8 (part.get_device_path ()), + filesystem = to_common_fs (part.get_file_system ()), + start_sector = part.get_start_sector (), + end_sector = part.get_end_sector (), + sectors_used = to_common_usage (part.sectors_used (disk.get_sector_size ())), + current_lvm_volume_group = lvm_vg + }; + } + + return Disk () { + name = string_from_utf8 (disk.get_model ()), + device_path = string_from_utf8 (disk.get_device_path ()), + sectors = disk.get_sectors (), + sector_size = disk.get_sector_size (), + partitions = partitions + }; + } + + public void install_with_default_disk_layout (InstallConfig config, string disk, bool encrypt, string encryption_password) throws GLib.Error { + var disks = new Distinst.Disks (); + default_disk_configuration (disks, disk, encrypt ? encryption_password : null); + + install (config, (owned) disks); + } + + public void install_with_custom_disk_layout (InstallConfig config, Mount[] disk_config, LuksCredentials[] credentials) throws GLib.Error { + var disks = new Distinst.Disks (); + custom_disk_configuration (disks, disk_config, credentials); + + install (config, (owned) disks); + } + + private void install (InstallConfig config, owned Distinst.Disks disks) { + var installer = new Distinst.Installer (); + installer.on_error ((error) => on_error (to_common_error (error))); + installer.on_status ((status) => on_status (to_common_status (status))); + + var distinst_config = Distinst.Config (); + uint8 flags = 0; + if (config.modify_boot_order) { + flags = Distinst.MODIFY_BOOT_ORDER; + } + + if (config.install_drivers) { + flags |= Distinst.RUN_UBUNTU_DRIVERS; + } + + distinst_config.flags = flags; + distinst_config.hostname = config.hostname; + + var casper = casper_dir (); + distinst_config.remove = GLib.Path.build_filename (casper, "filesystem.manifest-remove"); + distinst_config.squashfs = GLib.Path.build_filename (casper, "filesystem.squashfs"); + + debug ("language: %s\n", config.lang); + distinst_config.lang = config.lang; + + distinst_config.keyboard_layout = config.keyboard_layout; + distinst_config.keyboard_model = null; + distinst_config.keyboard_variant = config.keyboard_variant == "" ? null : config.keyboard_variant; + + new Thread (null, () => { + if (installer.install ((owned) disks, distinst_config) != 0) { + Idle.add (() => { + on_error (InstallerDaemon.Error ()); + return GLib.Source.REMOVE; + }); + } + + return null; + }); + } + + public void set_demo_mode_locale (string locale) throws GLib.Error { + GLib.FileUtils.set_contents ("/etc/default/locale", "LANG=" + locale); + } + + public void trigger_demo_mode () throws GLib.Error { + var demo_mode_file = GLib.File.new_for_path ("/var/lib/lightdm/demo-mode"); + try { + demo_mode_file.create (GLib.FileCreateFlags.NONE); + } catch (GLib.Error e) { + if (!(e is GLib.IOError.EXISTS)) { + throw e; + } + } + } + + private string casper_dir () { + const string CDROM = "/cdrom"; + + try { + var cdrom_dir = File.new_for_path (CDROM); + var iter = cdrom_dir.enumerate_children (FileAttribute.STANDARD_NAME, 0); + + FileInfo info; + while ((info = iter.next_file ()) != null) { + unowned string name = info.get_name (); + if (name.has_prefix ("casper")) { + return GLib.Path.build_filename (CDROM, name); + } + } + } catch (GLib.Error e) { + critical ("failed to find casper dir automatically: %s\n", e.message); + } + + return GLib.Path.build_filename (CDROM, "casper"); + } + + private void default_disk_configuration (Distinst.Disks disks, string disk_path, string? encryption_password) throws GLib.IOError { + var encrypted_vg = Distinst.generate_unique_id ("cryptdata"); + var root_vg = Distinst.generate_unique_id ("data"); + if (encrypted_vg == null || root_vg == null) { + throw new GLib.IOError.FAILED ("Unable to generate unique volume group IDs"); + } + + Distinst.LvmEncryption? encryption; + if (encryption_password != null) { + debug ("encrypting"); + encryption = Distinst.LvmEncryption () { + physical_volume = encrypted_vg, + password = encryption_password, + keydata = null + }; + } else { + debug ("not encrypting"); + encryption = null; + } + + debug ("disk: %s\n", disk_path); + var disk = new Distinst.Disk (disk_path); + if (disk == null) { + throw new GLib.IOError.FAILED ("Could not find %s", disk_path); + } + + var bootloader = Distinst.bootloader_detect (); + + var start_sector = Distinst.Sector () { + flag = Distinst.SectorKind.START, + value = 0 + }; + + // 256 MiB is the minimum distinst ESP partition size, so this is 256 MiB in MB plus a bit + // extra for safety + var efi_sector = Distinst.Sector () { + flag = Distinst.SectorKind.MEGABYTE, + value = 278 + }; + + // 1024MB /boot partition that's created if we're doing encryption + var boot_sector = Distinst.Sector () { + flag = Distinst.SectorKind.MEGABYTE, + value = efi_sector.value + 1024 + }; + + // 4GB swap partition at the end + var swap_sector = Distinst.Sector () { + flag = Distinst.SectorKind.MEGABYTE_FROM_END, + value = 4096 + }; + + var end_sector = Distinst.Sector () { + flag = Distinst.SectorKind.END, + value = 0 + }; + + // Prepares a new partition table. + int result = disk.mklabel (bootloader); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to write partition table to %s", disk_path); + } + + var start = disk.get_sector (ref start_sector); + var end = disk.get_sector (ref boot_sector); + + switch (bootloader) { + case Distinst.PartitionTable.MSDOS: + // This is used to ensure LVM installs will work with BIOS + result = disk.add_partition ( + new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.EXT4) + .partition_type (Distinst.PartitionType.PRIMARY) + .flag (Distinst.PartitionFlag.BOOT) + .mount ("/boot") + ); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to add boot partition to %s", disk_path); + } + + // Start the LVM from the end of our /boot partition + start = disk.get_sector (ref boot_sector); + break; + case Distinst.PartitionTable.GPT: + end = disk.get_sector (ref efi_sector); + + // A FAT32 partition is required for EFI installs + result = disk.add_partition ( + new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.FAT32) + .partition_type (Distinst.PartitionType.PRIMARY) + .flag (Distinst.PartitionFlag.ESP) + .mount ("/boot/efi") + ); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to add EFI partition to %s", disk_path); + } + + // If we're encrypting, we need an unencrypted partition to store kernels and initramfs images + if (encryption != null) { + start = disk.get_sector (ref efi_sector); + end = disk.get_sector (ref boot_sector); + + result = disk.add_partition ( + new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.EXT4) + .partition_type (Distinst.PartitionType.PRIMARY) + .mount ("/boot") + ); + + if (result != 0) { + throw new GLib.IOError.FAILED ("unable to add /boot partition to %s", disk_path); + } + + // Start the LVM from the end of our /boot/efi and /boot partitions + start = disk.get_sector (ref boot_sector); + } else { + // No encryption, we only have a /boot/efi partition, start the LVM from there + start = disk.get_sector (ref efi_sector); + } + + break; + } + + end = disk.get_sector (ref end_sector); + + result = disk.add_partition ( + new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.LVM) + .partition_type (Distinst.PartitionType.PRIMARY) + .logical_volume (root_vg, encryption) + ); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to add LVM partition to %s", disk_path); + } + + disks.push ((owned) disk); + + result = disks.initialize_volume_groups (); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to initialize volume groups on %s", disk_path); + } + + unowned Distinst.LvmDevice lvm_device = disks.get_logical_device (root_vg); + + if (lvm_device == null) { + throw new GLib.IOError.FAILED ("Unable to find '%s' volume group on %s", root_vg, disk_path); + } + + start = lvm_device.get_sector (ref start_sector); + end = lvm_device.get_sector (ref swap_sector); + + result = lvm_device.add_partition ( + new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.EXT4) + .name ("root") + .mount ("/") + ); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to add / partition to LVM on %s", disk_path); + } + + start = lvm_device.get_sector (ref swap_sector); + end = lvm_device.get_sector (ref end_sector); + + result = lvm_device.add_partition ( + new Distinst.PartitionBuilder (start, end, Distinst.FileSystem.SWAP) + .name ("swap") + ); + + if (result != 0) { + throw new GLib.IOError.FAILED ("Unable to add swap partition to LVM on %s", disk_path); + } + } + + private void custom_disk_configuration (Distinst.Disks disks, Mount[] mounts, LuksCredentials[] credentials) throws GLib.IOError { + Mount[] lvm_devices = {}; + + foreach (Mount m in mounts) { + if (m.is_lvm ()) { + lvm_devices += m; + } else { + unowned Distinst.Disk disk = disks.get_physical_device (m.parent_disk); + if (disk == null) { + var new_disk = new Distinst.Disk (m.parent_disk); + if (new_disk == null) { + throw new GLib.IOError.FAILED ("Could not find physical device: '%s'", m.parent_disk); + } + + disks.push ((owned) new_disk); + disk = disks.get_physical_device (m.parent_disk); + } + + unowned Distinst.Partition partition = disk.get_partition_by_path (m.partition_path); + + if (partition == null) { + throw new GLib.IOError.FAILED ("Could not find %s", m.partition_path); + } + + if (m.mount_point == "/boot/efi") { + if (m.is_valid_boot_mount ()) { + if (m.should_format ()) { + partition.format_with (to_distinst_fs (m.filesystem)); + } + + partition.set_mount (m.mount_point); + partition.set_flags ({ Distinst.PartitionFlag.ESP }); + } else { + throw new GLib.IOError.FAILED ("Unreachable code path -- EFI partition is invalid"); + } + } else { + if (m.filesystem != InstallerDaemon.FileSystem.SWAP) { + partition.set_mount (m.mount_point); + } + + if (m.mount_point == "/boot") { + partition.set_flags ({ Distinst.PartitionFlag.BOOT }); + } + + if (m.should_format ()) { + partition.format_with (to_distinst_fs (m.filesystem)); + } + } + } + } + + disks.initialize_volume_groups (); + + foreach (LuksCredentials cred in credentials) { + disks.decrypt_partition (cred.device, Distinst.LvmEncryption () { + physical_volume = cred.pv, + password = cred.password, + keydata = null + }); + } + + foreach (Mount m in lvm_devices) { + var vg = m.parent_disk.offset (12); + unowned Distinst.LvmDevice disk = disks.get_logical_device (vg); + if (disk == null) { + throw new GLib.IOError.FAILED ("Could not find %s", vg); + } + + unowned Distinst.Partition partition = disk.get_partition_by_path (m.partition_path); + + if (partition == null) { + throw new GLib.IOError.FAILED ("could not find %s", m.partition_path); + } + + if (m.filesystem != InstallerDaemon.FileSystem.SWAP) { + partition.set_mount (m.mount_point); + } + + if (m.should_format ()) { + partition.format_and_keep_name (to_distinst_fs (m.filesystem)); + } + } + } + + private static string string_from_utf8 (uint8[] input) { + var builder = new GLib.StringBuilder.sized (input.length); + builder.append_len ((string) input, input.length); + return (owned) builder.str; + } + + private InstallerDaemon.FileSystem to_common_fs (Distinst.FileSystem fs) { + switch (fs) { + case BTRFS: + return InstallerDaemon.FileSystem.BTRFS; + case EXT2: + return InstallerDaemon.FileSystem.EXT2; + case EXT3: + return InstallerDaemon.FileSystem.EXT3; + case EXT4: + return InstallerDaemon.FileSystem.EXT4; + case F2FS: + return InstallerDaemon.FileSystem.F2FS; + case FAT16: + return InstallerDaemon.FileSystem.FAT16; + case FAT32: + return InstallerDaemon.FileSystem.FAT32; + case NONE: + return InstallerDaemon.FileSystem.NONE; + case NTFS: + return InstallerDaemon.FileSystem.NTFS; + case SWAP: + return InstallerDaemon.FileSystem.SWAP; + case XFS: + return InstallerDaemon.FileSystem.XFS; + case LVM: + return InstallerDaemon.FileSystem.LVM; + case LUKS: + return InstallerDaemon.FileSystem.LUKS; + default: + return InstallerDaemon.FileSystem.NONE; + } + } + + private InstallerDaemon.PartitionUsage to_common_usage (Distinst.PartitionUsage usage) { + return InstallerDaemon.PartitionUsage () { + tag = usage.tag, + value = usage.value + }; + } + + private Distinst.FileSystem to_distinst_fs (InstallerDaemon.FileSystem fs) { + switch (fs) { + case BTRFS: + return Distinst.FileSystem.BTRFS; + case EXT2: + return Distinst.FileSystem.EXT2; + case EXT3: + return Distinst.FileSystem.EXT3; + case EXT4: + return Distinst.FileSystem.EXT4; + case F2FS: + return Distinst.FileSystem.F2FS; + case FAT16: + return Distinst.FileSystem.FAT16; + case FAT32: + return Distinst.FileSystem.FAT32; + case NONE: + return Distinst.FileSystem.NONE; + case NTFS: + return Distinst.FileSystem.NTFS; + case SWAP: + return Distinst.FileSystem.SWAP; + case XFS: + return Distinst.FileSystem.XFS; + case LVM: + return Distinst.FileSystem.LVM; + case LUKS: + return Distinst.FileSystem.LUKS; + default: + return Distinst.FileSystem.NONE; + } + } + + private InstallerDaemon.PartitionTable to_common_usage_bootloader (Distinst.PartitionTable bootloader) { + switch (bootloader) { + case GPT: + return InstallerDaemon.PartitionTable.GPT; + case MSDOS: + return InstallerDaemon.PartitionTable.MSDOS; + case NONE: + default: + return InstallerDaemon.PartitionTable.NONE; + } + } + + private InstallerDaemon.LogLevel to_common_log_level (Distinst.LogLevel level) { + switch (level) { + case DEBUG: + return InstallerDaemon.LogLevel.DEBUG; + case INFO: + return InstallerDaemon.LogLevel.INFO; + case WARN: + return InstallerDaemon.LogLevel.WARN; + case ERROR: + return InstallerDaemon.LogLevel.ERROR; + case TRACE: + default: + return InstallerDaemon.LogLevel.TRACE; + } + } + + private InstallerDaemon.Error to_common_error (Distinst.Error error) { + return InstallerDaemon.Error () { + step = to_common_step (error.step), + err = error.err + }; + } + + private InstallerDaemon.Step to_common_step (Distinst.Step step) { + switch (step) { + case BACKUP: + return InstallerDaemon.Step.BACKUP; + case PARTITION: + return InstallerDaemon.Step.PARTITION; + case EXTRACT: + return InstallerDaemon.Step.EXTRACT; + case CONFIGURE: + return InstallerDaemon.Step.CONFIGURE; + case BOOTLOADER: + return InstallerDaemon.Step.BOOTLOADER; + case INIT: + default: + return InstallerDaemon.Step.INIT; + } + } + + private InstallerDaemon.Status to_common_status (Distinst.Status status) { + return InstallerDaemon.Status () { + step = to_common_step (status.step), + percent = status.percent + }; + } +} diff --git a/daemon/meson.build b/daemon/meson.build index f041264cc..f4a07ee25 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -4,13 +4,22 @@ vala_files = [ ] daemon_dependencies = [ - distinst_dep, gee_dep, glib_dep, gio_dep, gobject_dep, ] +args = '' + +if installer_backend == 'distinst' + vala_files += ['DistinstBackend.vala'] + daemon_dependencies += [distinst_dep] + args += '--define=DISTINST_BACKEND' +else + error('No supported installer backend provided') +endif + systemdunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir') install_data( @@ -22,4 +31,5 @@ install_data('io.elementary.InstallerDaemon.conf', install_dir : get_option('dat executable(meson.project_name() + '-daemon', vala_files, dependencies : daemon_dependencies, + vala_args : args, install: true) diff --git a/meson.build b/meson.build index a89a27857..ecd03a888 100644 --- a/meson.build +++ b/meson.build @@ -12,7 +12,6 @@ add_project_arguments(['--vapidir', join_paths(meson.current_source_dir(), 'vapi gnome = import('gnome') i18n = import('i18n') -distinst_dep = dependency('distinst') glib_dep = dependency('glib-2.0') gobject_dep = dependency('gobject-2.0') gtk_dep = dependency('gtk+-3.0') @@ -27,6 +26,13 @@ gnome_keyboard_ui_dep = meson.get_compiler('c').find_library('gnomekbdui') pwquality_dep = dependency('pwquality') systemd_dep = dependency('systemd') +installer_backend = get_option('installer_backend') +if installer_backend == 'distinst' + distinst_dep = dependency('distinst') +else + error('No supported installer backend provided') +endif + asresources = gnome.compile_resources( 'as-resources', 'data/' + meson.project_name() + '.gresource.xml', source_dir: 'data', diff --git a/meson_options.txt b/meson_options.txt index fefae3b5e..7973bb2a5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,3 @@ option('supported_languages', type : 'string', value : 'aa;ab;ae;af;ak;am;an;ar;as;ast;av;ay;az;ba;be;bg;bh;bi;bm;bn;bo;br;bs;ca;ce;ch;ckb;co;cr;cs;cu;cv;cy;da;de;de_CH;de_DE;dv;dz;ee;el;en;en_US;en_AU;en_CA;en_GB;eo;es;et;eu;fa;ff;fi;fj;fo;fr;fr_BE;fr_CA;fr_FR;fy;ga;gd;gl;gn;gu;gv;ha;he;hi;ho;hr;ht;hu;hy;hz;ia;id;ie;ig;ii;ik;io;is;it;iu;ja;jv;ka;kab;kg;ki;kj;kk;kl;km;kn;ko;kr;ks;ku;kv;kw;ky;la;lb;lg;li;ln;lo;lt;lu;lv;mg;mh;mi;mk;ml;mn;mo;mr;ms;mt;my;na;nb;nd;ne;ng;nl;nn;no;nr;nv;ny;oc;oj;om;or;os;pa;pi;pl;ps;pt;pt_PT;pt_BR;qu;rm;rn;ro;ru;rue;rw;sa;sc;sd;se;sg;si;sk;sl;sm;sma;sn;so;sq;sr;ss;st;su;sv;sw;szl;ta;te;tg;th;ti;tk;tl;tn;to;tr;ts;tt;tw;ty;udm;ug;uk;ur;uz;ve;vi;vo;wa;wo;xh;yi;yo;za;zh;zh_CN;zh_HK;zh_TW;zu', description : 'The list of supported languages') option('preferred_languages', type : 'string', value : 'en;zh;es;fr;pt;ru;de', description : 'A prioritized list of languages') +option('installer_backend', type : 'combo', choices : ['distinst'], value : 'distinst') From 400d56773ec59f7ed84cdbf631ef1e28024a1e3d Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:23:18 +0100 Subject: [PATCH 13/17] Satisfy linter --- src/Views/ProgressView.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/ProgressView.vala b/src/Views/ProgressView.vala index 9759d4289..fb3e20a8e 100644 --- a/src/Views/ProgressView.vala +++ b/src/Views/ProgressView.vala @@ -135,7 +135,7 @@ public class ProgressView : AbstractInstallerView { var config = InstallerDaemon.InstallConfig (); config.modify_boot_order = true; if (current_config.install_drivers) { - config.install_drivers = true; + config.install_drivers = true; } config.hostname = Utils.get_hostname (); config.lang = "en_US.UTF-8"; From bd4c3e80dbacffdf8b57fba44982f997c8bc842f Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:40:10 +0100 Subject: [PATCH 14/17] Add AnacondaBackend for installer backend option --- daemon/AnacondaBackend.vala | 47 +++++++++++++++++++++++++++++++++++++ daemon/Daemon.vala | 2 ++ daemon/meson.build | 3 +++ meson.build | 1 + meson_options.txt | 2 +- 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 daemon/AnacondaBackend.vala diff --git a/daemon/AnacondaBackend.vala b/daemon/AnacondaBackend.vala new file mode 100644 index 000000000..9aac110bc --- /dev/null +++ b/daemon/AnacondaBackend.vala @@ -0,0 +1,47 @@ +/* + * Copyright 2023 elementary, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +[DBus (name = "io.elementary.InstallerDaemon")] +public class InstallerDaemon.AnacondaBackend : GLib.Object { + public signal void on_log_message (InstallerDaemon.LogLevel level, string message); + public signal void on_status (InstallerDaemon.Status status); + public signal void on_error (InstallerDaemon.Error error); + + public InstallerDaemon.PartitionTable bootloader_detect () throws GLib.Error { + return InstallerDaemon.PartitionTable.NONE; + } + + public DiskInfo get_disks (bool get_partitions = false) throws GLib.Error { + return DiskInfo (); + } + + public int decrypt_partition (string path, string pv, string password) throws GLib.Error { + return 0; + } + + public Disk get_logical_device (string pv) throws GLib.Error { + return Disk (); + } + + public void install_with_default_disk_layout (InstallConfig config, string disk, bool encrypt, string encryption_password) throws GLib.Error {} + + public void install_with_custom_disk_layout (InstallConfig config, Mount[] disk_config, LuksCredentials[] credentials) throws GLib.Error {} + + public void set_demo_mode_locale (string locale) throws GLib.Error {} + + public void trigger_demo_mode () throws GLib.Error {} +} diff --git a/daemon/Daemon.vala b/daemon/Daemon.vala index 0fd716099..cfd3b3452 100644 --- a/daemon/Daemon.vala +++ b/daemon/Daemon.vala @@ -21,6 +21,8 @@ private void on_bus_acquired (GLib.DBusConnection connection, string name) { try { #if DISTINST_BACKEND connection.register_object ("/io/elementary/InstallerDaemon", new InstallerDaemon.DistinstBackend ()); +#elif ANACONDA_BACKEND + connection.register_object ("/io/elementary/InstallerDaemon", new InstallerDaemon.AnacondaBackend ()); #endif } catch (GLib.Error e) { critical ("Unable to register the object: %s", e.message); diff --git a/daemon/meson.build b/daemon/meson.build index f4a07ee25..0c787778a 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -16,6 +16,9 @@ if installer_backend == 'distinst' vala_files += ['DistinstBackend.vala'] daemon_dependencies += [distinst_dep] args += '--define=DISTINST_BACKEND' +elif installer_backend == 'anaconda' + vala_files += ['AnacondaBackend.vala'] + args += '--define=ANACONDA_BACKEND' else error('No supported installer backend provided') endif diff --git a/meson.build b/meson.build index ecd03a888..50cbf799b 100644 --- a/meson.build +++ b/meson.build @@ -29,6 +29,7 @@ systemd_dep = dependency('systemd') installer_backend = get_option('installer_backend') if installer_backend == 'distinst' distinst_dep = dependency('distinst') +elif installer_backend == 'anaconda' else error('No supported installer backend provided') endif diff --git a/meson_options.txt b/meson_options.txt index 7973bb2a5..a00724b37 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,3 @@ option('supported_languages', type : 'string', value : 'aa;ab;ae;af;ak;am;an;ar;as;ast;av;ay;az;ba;be;bg;bh;bi;bm;bn;bo;br;bs;ca;ce;ch;ckb;co;cr;cs;cu;cv;cy;da;de;de_CH;de_DE;dv;dz;ee;el;en;en_US;en_AU;en_CA;en_GB;eo;es;et;eu;fa;ff;fi;fj;fo;fr;fr_BE;fr_CA;fr_FR;fy;ga;gd;gl;gn;gu;gv;ha;he;hi;ho;hr;ht;hu;hy;hz;ia;id;ie;ig;ii;ik;io;is;it;iu;ja;jv;ka;kab;kg;ki;kj;kk;kl;km;kn;ko;kr;ks;ku;kv;kw;ky;la;lb;lg;li;ln;lo;lt;lu;lv;mg;mh;mi;mk;ml;mn;mo;mr;ms;mt;my;na;nb;nd;ne;ng;nl;nn;no;nr;nv;ny;oc;oj;om;or;os;pa;pi;pl;ps;pt;pt_PT;pt_BR;qu;rm;rn;ro;ru;rue;rw;sa;sc;sd;se;sg;si;sk;sl;sm;sma;sn;so;sq;sr;ss;st;su;sv;sw;szl;ta;te;tg;th;ti;tk;tl;tn;to;tr;ts;tt;tw;ty;udm;ug;uk;ur;uz;ve;vi;vo;wa;wo;xh;yi;yo;za;zh;zh_CN;zh_HK;zh_TW;zu', description : 'The list of supported languages') option('preferred_languages', type : 'string', value : 'en;zh;es;fr;pt;ru;de', description : 'A prioritized list of languages') -option('installer_backend', type : 'combo', choices : ['distinst'], value : 'distinst') +option('installer_backend', type : 'combo', choices : ['distinst', 'anaconda'], value : 'anaconda') From f7b989f116d0ecb4db26799b0ccdd865add8866d Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 9 Nov 2023 21:41:33 +0100 Subject: [PATCH 15/17] GitHub CI: Build anaconda backend --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc95b7e3e..0f6da0dd7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,10 @@ jobs: run: | meson build ninja -C build + - name: Build (Anaconda Backend) + run: | + meson configure -Dinstaller_backend=anaconda build + ninja -C build lint: runs-on: ubuntu-latest From a27bda796ff3c30b2f79fd60c4d2b68bdf921495 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Sat, 11 Nov 2023 06:17:15 +0100 Subject: [PATCH 16/17] DBusStructures: Refactor to unowned reference --- common/DBusStructures.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/DBusStructures.vala b/common/DBusStructures.vala index 8a5ec8b18..eaa64cecd 100644 --- a/common/DBusStructures.vala +++ b/common/DBusStructures.vala @@ -46,7 +46,7 @@ public enum InstallerDaemon.FileSystem { LVM, LUKS; - public string to_string () { + public unowned string to_string () { switch (this) { case BTRFS: return "btrfs"; From 94135fa3804318248912cae7df1cd2b1ad84e129 Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Wed, 9 Oct 2024 11:16:20 +0200 Subject: [PATCH 17/17] ProgressView: Output config --- src/Views/ProgressView.vala | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Views/ProgressView.vala b/src/Views/ProgressView.vala index 3c7450574..ae55b434e 100644 --- a/src/Views/ProgressView.vala +++ b/src/Views/ProgressView.vala @@ -107,6 +107,35 @@ public class ProgressView : Adw.NavigationPage { } public void start_installation () { + unowned Configuration current_config = Configuration.get_default (); + + stdout.printf ("###################################\n"); + stdout.printf ("lang: %s\n", current_config.lang); + stdout.printf ("country: %s\n", current_config.country); + stdout.printf ("keyboard_layout: %s\n", current_config.keyboard_layout); + stdout.printf ("keyboard_variant: %s\n", current_config.keyboard_variant); + stdout.printf ("encryption_password: %s\n", current_config.encryption_password); + stdout.printf ("disk: %s\n", current_config.disk); + stdout.printf ("mounts:\n"); + foreach (var mount in current_config.mounts) { + stdout.printf ("- partition_path: %s\n", mount.partition_path); + stdout.printf (" parent_disk: %s\n", mount.parent_disk); + stdout.printf (" mount_point: %s\n", mount.mount_point); + stdout.printf (" sectors: %llu\n", mount.sectors); + stdout.printf (" filesystem: %s\n", mount.filesystem.to_string ()); + stdout.printf (" flags: %u\n", mount.flags); + } + stdout.printf ("luks:\n"); + foreach (var luks in current_config.luks) { + if (luks != null) { + stdout.printf ("- device: %s\n", luks.device); + stdout.printf (" pv: %s\n", luks.pv); + stdout.printf (" password: %s\n", luks.password); + } + } + stdout.printf ("install_drivers: %s\n", current_config.install_drivers ? "true" : "false"); + stdout.printf ("###################################\n"); + if (Installer.App.test_mode) { new Thread (null, () => { fake_status (InstallerDaemon.Step.PARTITION);