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