diff --git a/install_station/create_cfg.py b/install_station/create_cfg.py index 71391ac..6220be9 100644 --- a/install_station/create_cfg.py +++ b/install_station/create_cfg.py @@ -156,5 +156,11 @@ def create_cfg(cls): f.write("runCommand=pw userdel -n ghostbsd -r\n") f.write("runCommand=sed -i '' 's/ghostbsd/root/g' /etc/gettytab\n") f.write("runCommand=sed -i '' 's/ghostbsd/root/g' /etc/ttys\n") + f.write("runCommand=echo '# WARNING: Do NOT set initial_setup_enable=YES manually!' >> /etc/rc.conf\n") + f.write("runCommand=echo '# This service is ONLY for first boot after installation.' >> /etc/rc.conf\n") + f.write("runCommand=echo '# It will automatically disable itself after running.' >> /etc/rc.conf\n") + f.write("runCommand=sysrc initial_setup_enable=YES\n") + f.write("runCommand=sed -i '' '/^autologin-user=/d' /usr/local/etc/lightdm/lightdm.conf\n") + f.write("runCommand=sed -i '' '/^autologin-session=/d' /usr/local/etc/lightdm/lightdm.conf\n") except IOError as e: raise IOError(f"Failed to write configuration file: {e}") from e diff --git a/install_station/interface_controller.py b/install_station/interface_controller.py index 9e3e788..e4004ad 100644 --- a/install_station/interface_controller.py +++ b/install_station/interface_controller.py @@ -298,4 +298,4 @@ def back_page(cls, _widget: Gtk.Button) -> None: current_page_widget = cls.page.get_nth_page(cls.page.get_current_page()) title_text = cls.page.get_tab_label_text(current_page_widget) Window.set_title(title_text) - # Button.next_button.set_sensitive(True) + Button.next_button.set_sensitive(True) diff --git a/install_station/partition.py b/install_station/partition.py index 63a578d..7e9f1bb 100644 --- a/install_station/partition.py +++ b/install_station/partition.py @@ -7,6 +7,7 @@ from time import sleep from subprocess import Popen, PIPE, STDOUT, call from install_station.data import query, zfs_datasets, InstallationData +from install_station.system_calls import get_ram_size_mb # Define required file paths @@ -779,7 +780,7 @@ def create_mbr_partiton(self, drive, size, path, fs): InstallationData.slice = main_slice.replace(drive, "") root_size = int(main_size) - swap_size = 2048 + swap_size = get_ram_size_mb() root_size -= swap_size part_list = disk_db[drive]['partitions'][main_slice]['partition-list'] @@ -861,7 +862,7 @@ def create_gpt_partiton(self, drive, size, path, fs, efi_exist): InstallationData.disk = drive InstallationData.scheme = 'partscheme=GPT' root_size = int(main_size) - swap_size = 2048 + swap_size = get_ram_size_mb() root_size -= int(swap_size) if self.bios_type == "UEFI" and efi_exist is False: boot_size = 256 diff --git a/install_station/system_calls.py b/install_station/system_calls.py index 93343a6..fac2b0d 100644 --- a/install_station/system_calls.py +++ b/install_station/system_calls.py @@ -258,6 +258,21 @@ def timezone_dictionary() -> dict[str, list[str]]: return dictionary +def get_ram_size_mb() -> int: + """Query the system RAM size in megabytes using sysctl. + + Returns: + System RAM size in MB + """ + output = Popen( + 'sysctl -n hw.realmem', + shell=True, + stdout=PIPE, + universal_newlines=True + ).stdout.read().strip() + return int(output) // 1048576 + + def zfs_disk_query() -> list[str]: """Query available disks for ZFS installation. diff --git a/install_station/use_zfs.py b/install_station/use_zfs.py index 1e0441b..ccdcd90 100644 --- a/install_station/use_zfs.py +++ b/install_station/use_zfs.py @@ -3,6 +3,7 @@ from install_station.data import InstallationData, zfs_datasets, be_name, logo, get_text from install_station.partition import bios_or_uefi from install_station.system_calls import ( + get_ram_size_mb, zfs_disk_query, zfs_disk_size_query, ) @@ -38,13 +39,13 @@ class ZFS: zfs_disk_list = [] pool_type = 'stripe' scheme = 'GPT' - zpool = False disk_encrypt = False - mirror = 'single disk' + mirror = 'stripe' vbox1 = None - + # UI elements as class variables pool = None + swap_entry = None password = None repassword = None mirrorTips = None @@ -69,28 +70,19 @@ def save_selection(cls): # Validate required fields are populated if not cls.zfs_disk_list: raise ValueError("No disks selected for ZFS configuration") - - if cls.zpool and not cls.pool.get_text().strip(): - raise ValueError("Pool name cannot be empty when zpool is enabled") - + if cls.disk_encrypt and not cls.password.get_text().strip(): raise ValueError("Password cannot be empty when disk encryption is enabled") - + size = int(cls.zfs_disk_list[0].partition('-')[2].rstrip()) - 512 - swap = 0 - zfs_num = size - swap - if cls.disk_encrypt is True: - dgeli = '.eli' - else: - dgeli = '' + swap_size = cls.swap_entry.get_value_as_int() + zfs_num = size - swap_size + dgeli = '.eli' if cls.disk_encrypt else '' # Store configuration data in InstallationData instead of writing to file InstallationData.zfs_config_data = [] - - if cls.zpool is True: - InstallationData.zfs_config_data.append(f"zpoolName={cls.pool.get_text()}\n") - else: - InstallationData.zfs_config_data.append("#zpoolName=None\n") + + InstallationData.zfs_config_data.append(f"zpoolName={cls.pool.get_text()}\n") InstallationData.zfs_config_data.append(f"beName={be_name}\n") InstallationData.zfs_config_data.append('ashift=12\n\n') disk = cls.zfs_disk_list[0].partition('-')[0].rstrip() @@ -98,18 +90,13 @@ def save_selection(cls): InstallationData.zfs_config_data.append('partition=ALL\n') InstallationData.zfs_config_data.append(f'partscheme={cls.scheme}\n') InstallationData.zfs_config_data.append('commitDiskPart\n\n') - if cls.pool_type == 'none': + if len(cls.zfs_disk_list) <= 1: pool_disk = '\n' else: zfs_disk = cls.zfs_disk_list - disk_len = len(zfs_disk) - 1 - num = 1 mirror_dsk = '' - while disk_len != 0: - mirror_dsk += ' ' + zfs_disk[num].partition('-')[0].rstrip() - print(mirror_dsk) - num += 1 - disk_len -= 1 + for i in range(1, len(zfs_disk)): + mirror_dsk += ' ' + zfs_disk[i].partition('-')[0].rstrip() pool_disk = f' ({cls.pool_type}:{mirror_dsk})\n' if bios_or_uefi() == "UEFI": zfs_num = zfs_num - 100 @@ -118,19 +105,51 @@ def save_selection(cls): # adding zero to use remaining space zfs_part = f'disk0-part=ZFS{dgeli} {zfs_num} {zfs_datasets}{pool_disk}' InstallationData.zfs_config_data.append(zfs_part) - if swap != 0: - InstallationData.zfs_config_data.append('disk0-part=swap 0 none\n') - if cls.disk_encrypt is True: + # encpass must be on the line immediately after the .eli partition + if cls.disk_encrypt: InstallationData.zfs_config_data.append(f'encpass={cls.password.get_text()}\n') else: InstallationData.zfs_config_data.append('#encpass=None\n') + if swap_size != 0: + if cls.disk_encrypt: + InstallationData.zfs_config_data.append('disk0-part=SWAP.eli 0 none\n') + else: + InstallationData.zfs_config_data.append('disk0-part=SWAP 0 none\n') InstallationData.zfs_config_data.append('commitDiskLabel\n') + @classmethod + def _is_ready(cls): + """ + Check if all conditions are met to proceed to the next page. + + Returns: + bool: True if disk count, swap entry, and encryption requirements are all satisfied. + """ + count = len(cls.zfs_disk_list) + if cls.mirror == "stripe": + disks_ok = count >= 1 + elif cls.mirror == "mirror": + disks_ok = count >= 2 + elif cls.mirror == "raidz1": + disks_ok = count == 3 + elif cls.mirror == "raidz2": + disks_ok = count == 4 + elif cls.mirror == "raidz3": + disks_ok = count == 5 + else: + disks_ok = False + if cls.disk_encrypt: + encrypt_ok = (cls.password.get_text() == cls.repassword.get_text() + and len(cls.password.get_text()) > 0) + else: + encrypt_ok = True + return disks_ok and encrypt_ok + @classmethod def scheme_selection(cls, combobox): """ Handle partition scheme selection from combo box. - + Args: combobox: ComboBox widget containing scheme options (GPT/MBR) """ @@ -143,80 +162,48 @@ def scheme_selection(cls, combobox): def mirror_selection(cls, combobox): """ Handle pool type selection and update UI accordingly. - + Sets the pool type (stripe, mirror, RAIDZ1/2/3) and updates the tip text and next button sensitivity based on the number of selected disks. - + Args: combobox: ComboBox widget containing pool type options """ model = combobox.get_model() index = combobox.get_active() - data = model[index][0] # Get the internal value (English) + data = model[index][0] cls.mirror = data - if cls.mirror == "1+ disks Stripe": + smallest_msg = get_text("(select the smallest disk first)") + if cls.mirror == "stripe": cls.pool_type = 'stripe' cls.mirrorTips.set_text( - get_text("Please select 1 or more drive for stripe (select the smallest disk first)")) - if len(cls.zfs_disk_list) >= 1: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "2+ disks Mirror": + get_text("Select 1 or more drives, no redundancy") + " " + smallest_msg) + elif cls.mirror == "mirror": cls.pool_type = 'mirror' - mir_msg1 = get_text("Please select 2 drive for mirroring (select the smallest disk first)") - cls.mirrorTips.set_text(mir_msg1) - if len(cls.zfs_disk_list) >= 2: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "3 disks RAIDZ1": + cls.mirrorTips.set_text( + get_text("Select 2 or more drives for mirroring") + " " + smallest_msg) + elif cls.mirror == "raidz1": cls.pool_type = 'raidz1' - cls.mirrorTips.set_text(get_text("Please select 3 drive for RAIDZ1 (select the smallest disk first)")) - if len(cls.zfs_disk_list) == 3: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "4 disks RAIDZ2": + cls.mirrorTips.set_text( + get_text("Select 3 drives for RAIDZ1") + " " + smallest_msg) + elif cls.mirror == "raidz2": cls.pool_type = 'raidz2' - cls.mirrorTips.set_text(get_text("Please select 4 drive for RAIDZ2 (select the smallest disk first)")) - if len(cls.zfs_disk_list) == 4: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "5 disks RAIDZ3": + cls.mirrorTips.set_text( + get_text("Select 4 drives for RAIDZ2") + " " + smallest_msg) + elif cls.mirror == "raidz3": cls.pool_type = 'raidz3' - cls.mirrorTips.set_text(get_text("Please select 5 drive for RAIDZ3 (select the smallest disk first)")) - if len(cls.zfs_disk_list) == 5: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - - @classmethod - def on_check_poll(cls, widget): - """ - Handle custom pool name checkbox toggle. - - Enables or disables the pool name entry field based on checkbox state. - - Args: - widget: CheckButton widget for pool name enable/disable - """ - if widget.get_active(): - cls.pool.set_sensitive(True) - cls.zpool = True - else: - cls.pool.set_sensitive(False) - cls.zpool = False + cls.mirrorTips.set_text( + get_text("Select 5 drives for RAIDZ3") + " " + smallest_msg) + Button.next_button.set_sensitive(cls._is_ready()) @classmethod def on_check_encrypt(cls, widget): """ Handle disk encryption checkbox toggle. - + Enables or disables password fields and updates next button sensitivity based on encryption state and current disk selection. - + Args: widget: CheckButton widget for disk encryption enable/disable """ @@ -229,31 +216,21 @@ def on_check_encrypt(cls, widget): cls.password.set_sensitive(False) cls.repassword.set_sensitive(False) cls.disk_encrypt = False - if cls.mirror == "1+ disks Stripe": - if len(cls.zfs_disk_list) >= 1: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "2+ disks Mirror": - if len(cls.zfs_disk_list) >= 2: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "3 disks RAIDZ1": - if len(cls.zfs_disk_list) == 3: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "4 disks RAIDZ2": - if len(cls.zfs_disk_list) == 4: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "5 disks RAIDZ3": - if len(cls.zfs_disk_list) == 5: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) + Button.next_button.set_sensitive(cls._is_ready()) + + @classmethod + def on_password_changed(cls, _widget): + """ + Handle password entry changes and update strength display. + + Wraps the common password_strength function to extract the text + from the Entry widget and pass it with the strength label. + + Args: + _widget: Entry widget that triggered the change (unused) + """ + password_strength(cls.password.get_text(), cls.strenght_label) + Button.next_button.set_sensitive(cls._is_ready()) @classmethod def initialize(cls): @@ -271,7 +248,8 @@ def initialize(cls): """ cls.vbox1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=0) cls.vbox1.show() - # Chose disk + + # Disk list in a scrolled window sw = Gtk.ScrolledWindow(hexpand=True, vexpand=True) sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) @@ -319,37 +297,39 @@ def initialize(cls): tree_selection.set_mode(Gtk.SelectionMode.SINGLE) sw.add(treeview) sw.show() + cls.mirrorTips = Gtk.Label(label=get_text('Please select one drive')) cls.mirrorTips.set_justify(Gtk.Justification.LEFT) cls.mirrorTips.set_alignment(0.01, 0.5) - # Mirror, raidz and stripe - cls.mirror = 'none' - mirror_label = Gtk.Label(label=get_text('Pool Type')) + + # Pool Layout + cls.mirror = 'stripe' + mirror_label = Gtk.Label(label=get_text('Pool Layout')) mirror_label.set_use_markup(True) - mirror_box = Gtk.ComboBox() - mirror_store = Gtk.ListStore(str, str) # value, display_text - mirror_store.append(["1+ disks Stripe", get_text("1+ disks Stripe")]) - mirror_store.append(["2+ disks Mirror", get_text("2+ disks Mirror")]) - mirror_store.append(["3 disks RAIDZ1", get_text("3 disks RAIDZ1")]) - mirror_store.append(["4 disks RAIDZ2", get_text("4 disks RAIDZ2")]) - mirror_store.append(["5 disks RAIDZ3", get_text("5 disks RAIDZ3")]) - mirror_box.set_model(mirror_store) - renderer = Gtk.CellRendererText() - mirror_box.pack_start(renderer, True) - mirror_box.add_attribute(renderer, "text", 1) # Display column 1 (translated text) - mirror_box.connect('changed', cls.mirror_selection) + mirror_box = Gtk.ComboBoxText() + mirror_box.append_text("stripe") + mirror_box.append_text("mirror") + mirror_box.append_text("raidz1") + mirror_box.append_text("raidz2") + mirror_box.append_text("raidz3") mirror_box.set_active(0) + mirror_box.connect('changed', cls.mirror_selection) - # Pool Name - cls.zpool = False - pool_name_label = Gtk.Label(label=get_text('Pool Name')) - pool_name_label.set_use_markup(True) + # Pool Name (always editable) + pool_label = Gtk.Label(label=get_text('Pool Name')) + pool_label.set_use_markup(True) cls.pool = Gtk.Entry() cls.pool.set_text('zroot') + + # Swap Size + swap_label = Gtk.Label(label=get_text('Swap Size(MB)')) + swap_label.set_use_markup(True) + ram_mb = get_ram_size_mb() + adj = Gtk.Adjustment(ram_mb, 0, ram_mb, 1, 100, 0) + cls.swap_entry = Gtk.SpinButton(adjustment=adj, numeric=True) + cls.swap_entry.set_editable(True) + # Creating MBR or GPT drive - scheme_label = Gtk.Label(label='Partition Scheme') - scheme_label.set_use_markup(True) - # Adding a combo box to selecting MBR or GPT sheme. cls.scheme = 'GPT' shemebox = Gtk.ComboBoxText() shemebox.append_text("GPT") @@ -360,52 +340,85 @@ def initialize(cls): shemebox.set_sensitive(False) else: shemebox.set_sensitive(True) + # GELI Disk encryption cls.disk_encrypt = False - encrypt_check = Gtk.CheckButton(label=get_text("Encrypt Disk")) + encrypt_check = Gtk.CheckButton(label=get_text("Encrypt Disk (GELI)")) encrypt_check.connect("toggled", cls.on_check_encrypt) encrypt_check.set_sensitive(True) - # password + + # Password cls.passwd_label = Gtk.Label(label=get_text("Password")) cls.password = Gtk.Entry() cls.password.set_sensitive(False) cls.password.set_visibility(False) - cls.password.connect("changed", password_strength) + cls.password.connect("changed", cls.on_password_changed) cls.strenght_label = Gtk.Label() cls.strenght_label.set_alignment(0.1, 0.5) - cls.vpasswd_label = Gtk.Label(label=get_text("Verify it")) + cls.strenght_label.set_size_request(-1, 20) + + # Verify password + cls.vpasswd_label = Gtk.Label(label=get_text("Confirm")) cls.repassword = Gtk.Entry() cls.repassword.set_sensitive(False) cls.repassword.set_visibility(False) cls.repassword.connect("changed", cls.password_verification) - # set image for password matching + + # Password match image cls.img = Gtk.Image() - cls.img.set_alignment(0.2, 0.5) - # table = Gtk.Table(12, 12, True) - grid = Gtk.Grid() - grid.set_row_spacing(10) - # grid.set_column_homogeneous(True) - # grid.set_row_homogeneous(True) - # grid.attach(Title, 1, 1, 10, 1) - grid.attach(mirror_label, 1, 2, 1, 1) - grid.attach(mirror_box, 2, 2, 1, 1) - grid.attach(pool_name_label, 7, 2, 2, 1) - grid.attach(cls.pool, 9, 2, 2, 1) - grid.attach(cls.mirrorTips, 1, 3, 8, 1) - # grid.attach(zfs4kcheck, 9, 3, 2, 1) - grid.attach(sw, 1, 4, 10, 3) - # grid.attach(scheme_label, 1, 9, 1, 1) - # grid.attach(shemebox, 2, 9, 1, 1) - # grid.attach(cls.swap_encrypt_check, 9, 15, 11, 12) - # grid.attach(swap_mirror_check, 9, 15, 11, 12) - # grid.attach(encrypt_check, 2, 8, 2, 1) - # grid.attach(cls.passwd_label, 1, 9, 1, 1) - # grid.attach(cls.password, 2, 9, 2, 1) - # grid.attach(cls.strenght_label, 4, 9, 2, 1) - # grid.attach(cls.vpasswd_label, 1, 10, 1, 1) - # grid.attach(cls.repassword, 2, 10, 2, 1) - # grid.attach(cls.img, 4, 10, 2, 1) - cls.vbox1.pack_start(grid, True, True, 10) + cls.img.set_size_request(20, 20) + + # Two-column layout: left settings, right disk list + hbox_main = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, homogeneous=False, spacing=10) + + # Left panel: settings grid + left_grid = Gtk.Grid() + left_grid.set_row_spacing(4) + left_grid.set_column_spacing(6) + left_grid.set_hexpand(False) + + mirror_label.set_alignment(0, 0.5) + pool_label.set_alignment(0, 0.5) + swap_label.set_alignment(0, 0.5) + cls.passwd_label.set_alignment(0, 0.5) + cls.vpasswd_label.set_alignment(0, 0.5) + + # Row 0-1: Pool Layout + left_grid.attach(mirror_label, 0, 0, 2, 1) + left_grid.attach(mirror_box, 0, 1, 2, 1) + # Row 2-3: Pool Name + left_grid.attach(pool_label, 0, 2, 2, 1) + left_grid.attach(cls.pool, 0, 3, 2, 1) + # Row 4-5: Swap Size + left_grid.attach(swap_label, 0, 4, 2, 1) + left_grid.attach(cls.swap_entry, 0, 5, 2, 1) + # Row 6: Separator + sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) + left_grid.attach(sep, 0, 6, 2, 1) + # Row 7: Encrypt Disk checkbox + left_grid.attach(encrypt_check, 0, 7, 2, 1) + # Row 8: Password label + strength indicator + left_grid.attach(cls.passwd_label, 0, 8, 1, 1) + left_grid.attach(cls.strenght_label, 1, 8, 1, 1) + # Row 9: Password input + left_grid.attach(cls.password, 0, 9, 2, 1) + # Row 10: Confirm label + match icon + left_grid.attach(cls.vpasswd_label, 0, 10, 1, 1) + left_grid.attach(cls.img, 1, 10, 1, 1) + # Row 11: Confirm input + left_grid.attach(cls.repassword, 0, 11, 2, 1) + + hbox_main.pack_start(left_grid, False, False, 10) + + # Right panel: tips + disk list + right_panel = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=0) + cls.mirrorTips.set_alignment(0, 0.5) + right_panel.pack_start(cls.mirrorTips, False, False, 0) + right_panel.pack_start(sw, True, True, 0) + + hbox_main.pack_start(right_panel, True, True, 10) + + cls.vbox1.pack_start(hbox_main, True, True, 10) return @classmethod @@ -465,62 +478,21 @@ def col1_toggled_cb(cls, _cell, path, model): model[path][3] = not model[path][3] if model[path][3] is False: cls.zfs_disk_list.remove(model[path][0] + "-" + model[path][1]) - if cls.mirror == "1+ disks Stripe": - if len(cls.zfs_disk_list) >= 1: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "2+ disks Mirror": - if len(cls.zfs_disk_list) >= 2: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "3 disks RAIDZ1": - if len(cls.zfs_disk_list) == 3: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "4 disks RAIDZ2": - if len(cls.zfs_disk_list) == 4: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "5 disks RAIDZ3": - if len(cls.zfs_disk_list) == 5: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) else: if cls.check_if_small_disk(model[path][1]) is False: cls.zfs_disk_list.extend([model[path][0] + "-" + model[path][1]]) - if cls.mirror == "1+ disks Stripe": - if len(cls.zfs_disk_list) >= 1: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "2+ disks Mirror": - if len(cls.zfs_disk_list) >= 2: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "3 disks RAIDZ1": - if len(cls.zfs_disk_list) == 3: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "4 disks RAIDZ2": - if len(cls.zfs_disk_list) == 4: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "5 disks RAIDZ3": - if len(cls.zfs_disk_list) == 5: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) else: cls.check_cell.set_sensitive(False) cls.small_disk_warning() + return True + + # Update swap SpinButton upper limit based on first selected disk + if cls.zfs_disk_list: + disk_size = int(cls.zfs_disk_list[0].partition('-')[2].rstrip()) - 512 + cls.swap_entry.get_adjustment().set_upper(disk_size) + else: + cls.swap_entry.get_adjustment().set_upper(get_ram_size_mb()) + Button.next_button.set_sensitive(cls._is_ready()) print(cls.zfs_disk_list) return True @@ -589,32 +561,8 @@ def password_verification(cls, _widget): _widget: Entry widget that triggered the verification (unused) """ if cls.password.get_text() == cls.repassword.get_text(): - cls.img.set_from_stock(Gtk.STOCK_YES, 5) - if cls.mirror == "1+ disks Stripe": - if len(cls.zfs_disk_list) >= 1: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "2+ disks Mirror": - if len(cls.zfs_disk_list) >= 2: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "3 disks RAIDZ1": - if len(cls.zfs_disk_list) == 3: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "4 disks RAIDZ2": - if len(cls.zfs_disk_list) == 4: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) - elif cls.mirror == "5 disks RAIDZ3": - if len(cls.zfs_disk_list) == 5: - Button.next_button.set_sensitive(True) - else: - Button.next_button.set_sensitive(False) + cls.img.set_from_icon_name("gtk-yes", Gtk.IconSize.MENU) + Button.next_button.set_sensitive(cls._is_ready()) else: - cls.img.set_from_stock(Gtk.STOCK_NO, 5) + cls.img.set_from_icon_name("gtk-no", Gtk.IconSize.MENU) Button.next_button.set_sensitive(False) diff --git a/setup.py b/setup.py index d5340c2..2c66d60 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from DistUtilsExtra.command.clean_i18n import clean_i18n prefix = sys.prefix -__VERSION__ = '0.1' +__VERSION__ = '0.4' PROGRAM_VERSION = __VERSION__ @@ -157,7 +157,8 @@ def run(self): data_files = [ (f'{prefix}/lib/install-station', ['src/ghostbsd-style.css']), (f'{prefix}/lib/install-station/backend-query', lib_install_station_backend_query), - (f'{prefix}/lib/install-station/image', lib_install_station_image) + (f'{prefix}/lib/install-station/image', lib_install_station_image), + (f'{prefix}/etc/rc.d', ['src/install_station']) ] data_files.extend(data_file_list(f'{prefix}/share/locale', 'build/mo')) diff --git a/src/install_station b/src/install_station new file mode 100755 index 0000000..c92e336 --- /dev/null +++ b/src/install_station @@ -0,0 +1,36 @@ +#!/bin/sh +# +# PROVIDE: install_station +# REQUIRE: LOGIN FILESYSTEMS +# BEFORE: lightdm +# KEYWORD: shutdown + +. /etc/rc.subr + +name="install_station" +rcvar="${name}_enable" +start_cmd="${name}_start" +stop_cmd=":" + +install_station_start() +{ + # Create .xinitrc for root to run installer + cat > /root/.xinitrc <<'EOF' +exec marco & +exec feh --bg-fill /usr/local/share/backgrounds/ghostbsd/blue-layered-stripes.jpg & +exec install-station +EOF + chmod 755 /root/.xinitrc + + # Start X as root - this will block until install-station exits + su -l root -c "startx -- :0 vt09" + + # Cleanup + rm -f /root/.xinitrc + + # Disable this service for future boots + sysrc install_station_enable=NO +} + +load_rc_config $name +run_rc_command "$1" \ No newline at end of file