Skip to content

Commit dda96d3

Browse files
author
MochiOS Team
committed
fix: ext4 support, snapper config, selfupdate sha256, sddm resolution, nightly branding, desktop consistency
- installer: dispatch format/setup/mount/fstab/bootloader based on filesystem choice (btrfs/ext4) - installer: add format_ext4() and setup_ext4() for ext4 installs - installer: only install btrfs-progs/snapper when btrfs selected - installer: generate correct ext4 fstab (no subvol flags, no abroot.conf for ext4) - installer: pass filesystem to all bootloader installers (rootflags conditional) - installer: configure snapper (create-config, timeline, cleanup timers) after btrfs setup - installer: add PID lock file to prevent concurrent installs - installer: fix file handle leak in pacman.conf append - mochiinstall_app: save filesystem choice from step 2 (was never collected) - mochiinstall_app: add ext4 option to filesystem selection step - selfupdate: platform-conditional URL (mochi.exe on windows, mochi on linux) - selfupdate: SHA256 checksum verification with graceful fallback - selfupdate: fix temp file extension per platform - sddm themes: use Screen.width/height instead of hardcoded 1920x1080 - nightly mochiboot.conf: fix variable names (INTERFACE_BRANDING), add recovery entry - desktop entries: all use sudo -E consistently, remove duplicate non-sudo autostart - KDE packages: add systemsettings, powerdevil, plasma-pa, polkit-kde-agent, xdg-desktop-portal-kde, bluedevil - archiso installer.py: sync pre-flight _unmount_all() from root copy
1 parent c47ed9a commit dda96d3

13 files changed

Lines changed: 325 additions & 117 deletions

File tree

‎archiso-mochios/airootfs/home/mochi/.config/autostart/mochiinstall.desktop‎

Lines changed: 0 additions & 10 deletions
This file was deleted.

‎archiso-mochios/airootfs/home/mochi/Desktop/mochiinstall.desktop‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
Type=Application
33
Name=MochiOS Installer
44
Comment=Install MochiOS to your system
5-
Exec=mochiinstall
5+
Exec=sudo -E /usr/local/bin/mochiinstall
66
Icon=system-software-install
77
Terminal=false
88
Categories=System;
99
X-KDE-Authorize=true
10-
Trusted=true
11-

‎archiso-mochios/airootfs/usr/lib/mochiinstall/installer.py‎

Lines changed: 109 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,20 @@ def setup_btrfs(root_part, target, lfn):
211211
run(["mount", "-o", "compress=zstd,subvol=cache", root_part, f"{target}/var/cache"])
212212

213213

214-
def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", kernels=None, extra_pkgs=None, abort_flag=None):
214+
def format_ext4(part, lfn):
215+
lfn(f"formatting root {part} as ext4...")
216+
retry_cmd(["mkfs.ext4", "-F", "-L", "MOCHIOS", part], lfn, timeout=120)
217+
218+
219+
def setup_ext4(root_part, target, lfn):
220+
lfn("mounting ext4 root...")
221+
os.makedirs(target, exist_ok=True)
222+
run(["mount", root_part, target])
223+
os.makedirs(f"{target}/boot", exist_ok=True)
224+
os.makedirs(f"{target}/home", exist_ok=True)
225+
226+
227+
def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", kernels=None, extra_pkgs=None, abort_flag=None, filesystem="btrfs"):
215228
if kernels is None:
216229
kernels = ["linux"]
217230

@@ -226,12 +239,14 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
226239
"base",
227240
*kernel_pkgs,
228241
"linux-firmware",
229-
"btrfs-progs", "snapper", "sudo", "vim", "nano",
242+
"sudo", "vim", "nano",
230243
"gptfdisk",
231244
"networkmanager", "dhcpcd", "reflector",
232245
"sbctl",
233246
"zsh", "git", "flatpak",
234247
]
248+
if filesystem == "btrfs":
249+
base.extend(["btrfs-progs", "snapper"])
235250
abortable_run(["pacstrap", "-K", target] + base, abort_flag, timeout=900, log_fn=lfn)
236251

237252
# step 2: desktop environment
@@ -240,7 +255,8 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
240255
"kwin", "konsole", "dolphin", "kate", "gwenview",
241256
"kwallet-pam", "breeze", "breeze-gtk",
242257
"pipewire", "pipewire-pulse", "wireplumber", "kpipewire",
243-
"plasma-nm"],
258+
"plasma-nm", "systemsettings", "powerdevil", "plasma-pa",
259+
"polkit-kde-agent", "xdg-desktop-portal-kde", "bluedevil"],
244260
"gnome": ["gnome", "gnome-extra"],
245261
"hyprland": ["hyprland", "kitty", "xdg-desktop-portal-hyprland",
246262
"wofi", "waybar", "dunst", "polkit-kde-agent",
@@ -278,6 +294,7 @@ def configure_system(target, config, lfn, efi_uuid, swap_uuid, root_uuid):
278294
bootloader = config.get("bootloader", "limine")
279295
kernels = config.get("kernels", ["linux"])
280296
disk = config.get("disk", "")
297+
filesystem = config.get("filesystem", "btrfs")
281298

282299
lfn("configuring system...")
283300
t = Path(target)
@@ -299,25 +316,34 @@ def ch(cmd, to=120, check=True, input_data=None):
299316
ch(["mkinitcpio", "-P"], to=300)
300317

301318
lfn("writing fstab...")
302-
fstab = (
303-
f"UUID={efi_uuid} /boot vfat rw,noatime,fmask=0022,dmask=0022 0 2\n"
304-
f"UUID={swap_uuid} swap swap defaults 0 0\n"
305-
f"UUID={root_uuid} /mnt/btrfs btrfs rw,noatime,compress=zstd,subvolid=5 0 0\n"
306-
f"UUID={root_uuid} / btrfs rw,noatime,compress=zstd,subvol=root_a 0 0\n"
307-
f"UUID={root_uuid} /home btrfs rw,noatime,compress=zstd,subvol=home 0 0\n"
308-
f"UUID={root_uuid} /var btrfs rw,noatime,compress=zstd,subvol=var 0 0\n"
309-
f"UUID={root_uuid} /var/cache btrfs rw,noatime,compress=zstd,subvol=cache 0 0\n"
310-
)
319+
if filesystem == "btrfs":
320+
fstab = (
321+
f"UUID={efi_uuid} /boot vfat rw,noatime,fmask=0022,dmask=0022 0 2\n"
322+
f"UUID={swap_uuid} swap swap defaults 0 0\n"
323+
f"UUID={root_uuid} /mnt/btrfs btrfs rw,noatime,compress=zstd,subvolid=5 0 0\n"
324+
f"UUID={root_uuid} / btrfs rw,noatime,compress=zstd,subvol=root_a 0 0\n"
325+
f"UUID={root_uuid} /home btrfs rw,noatime,compress=zstd,subvol=home 0 0\n"
326+
f"UUID={root_uuid} /var btrfs rw,noatime,compress=zstd,subvol=var 0 0\n"
327+
f"UUID={root_uuid} /var/cache btrfs rw,noatime,compress=zstd,subvol=cache 0 0\n"
328+
)
329+
os.makedirs(f"{target}/mnt/btrfs", exist_ok=True)
330+
else:
331+
fstab = (
332+
f"UUID={efi_uuid} /boot vfat rw,noatime,fmask=0022,dmask=0022 0 2\n"
333+
f"UUID={swap_uuid} swap swap defaults 0 0\n"
334+
f"UUID={root_uuid} / ext4 rw,noatime 0 1\n"
335+
f"UUID={root_uuid} /home ext4 rw,noatime 0 2\n"
336+
)
311337
(t / "etc/fstab").write_text(fstab)
312-
os.makedirs(f"{target}/mnt/btrfs", exist_ok=True)
313338
ch(["systemctl", "daemon-reload"])
314339

315-
(t / "etc/abroot.conf").write_text(
316-
f"ROOT_PART=\"UUID={root_uuid}\"\n"
317-
f"BTRFS_MOUNT=\"/mnt/btrfs\"\n"
318-
f"ACTIVE_ROOT=\"root_a\"\n"
319-
f"NEXT_ROOT=\"root_b\"\n"
320-
)
340+
if filesystem == "btrfs":
341+
(t / "etc/abroot.conf").write_text(
342+
f"ROOT_PART=\"UUID={root_uuid}\"\n"
343+
f"BTRFS_MOUNT=\"/mnt/btrfs\"\n"
344+
f"ACTIVE_ROOT=\"root_a\"\n"
345+
f"NEXT_ROOT=\"root_b\"\n"
346+
)
321347

322348
lfn("enabling multilib repo...")
323349
pmconf = t / "etc/pacman.conf"
@@ -353,11 +379,11 @@ def ch(cmd, to=120, check=True, input_data=None):
353379
lfn(" [yellow]mochios key not found, skipping[/]")
354380

355381
if bootloader == "limine":
356-
install_limine(target, disk, root_uuid, lfn, ch, kernels=kernels)
382+
install_limine(target, disk, root_uuid, lfn, ch, kernels=kernels, filesystem=filesystem)
357383
elif bootloader == "grub":
358-
install_grub(target, disk, root_uuid, lfn, ch, kernels=kernels)
384+
install_grub(target, disk, root_uuid, lfn, ch, kernels=kernels, filesystem=filesystem)
359385
elif bootloader == "mochiboot":
360-
install_mochiboot(target, disk, root_uuid, lfn, ch, kernels=kernels)
386+
install_mochiboot(target, disk, root_uuid, lfn, ch, kernels=kernels, filesystem=filesystem)
361387

362388
lfn("signing boot files with sbctl...")
363389
keydir = t / "var/lib/sbctl/keys/db"
@@ -401,19 +427,20 @@ def get_uuid(part):
401427
return run(["blkid", "-s", "UUID", "-o", "value", part], capture=True, check=True).stdout.strip()
402428

403429

404-
def install_limine(target, disk, root_uuid, lfn, ch, kernels=None):
430+
def install_limine(target, disk, root_uuid, lfn, ch, kernels=None, filesystem="btrfs"):
405431
if kernels is None:
406432
kernels = ["linux"]
407433
lfn("installing limine...")
408434

435+
root_flags = "rootflags=subvol=root_a " if filesystem == "btrfs" else ""
409436
config_lines = ["TIMEOUT=5", "VERBOSE=no", ""]
410437
for k in kernels:
411438
vmlinuz = f"/boot/vmlinuz-{k}"
412439
label = f"MOCHIOS ({k})" if len(kernels) > 1 else "MOCHIOS"
413440
config_lines.append(f":{label}")
414441
config_lines.append(" PROTOCOL=linux")
415442
config_lines.append(f" KERNEL_PATH={vmlinuz}")
416-
config_lines.append(f" CMDLINE=root=UUID={root_uuid} rootflags=subvol=root_a rw loglevel=4")
443+
config_lines.append(f" CMDLINE=root=UUID={root_uuid} {root_flags}rw loglevel=4")
417444
config_lines.append("")
418445

419446
config = "\n".join(config_lines)
@@ -434,33 +461,36 @@ def install_limine(target, disk, root_uuid, lfn, ch, kernels=None):
434461
ch(["cp", "/usr/share/limine/BOOTIA32.EFI", "/boot/EFI/BOOT/BOOTIA32.EFI"], to=30)
435462

436463

437-
def install_grub(target, disk, root_uuid, lfn, ch, kernels=None):
464+
def install_grub(target, disk, root_uuid, lfn, ch, kernels=None, filesystem="btrfs"):
438465
if kernels is None:
439466
kernels = ["linux"]
440467
lfn("installing grub...")
441468

442469
grub_def = Path(target) / "etc/default/grub"
443470
grub_text = grub_def.read_text() if grub_def.exists() else ""
471+
root_flags = "rootflags=subvol=root_a" if filesystem == "btrfs" else ""
444472
new_grub_text = []
445473
for line in grub_text.split("\n"):
446474
if line.startswith("GRUB_CMDLINE_LINUX="):
447-
new_grub_text.append('GRUB_CMDLINE_LINUX="rootflags=subvol=root_a"')
475+
new_grub_text.append(f'GRUB_CMDLINE_LINUX="{root_flags}"')
448476
else:
449477
new_grub_text.append(line)
450478
if "GRUB_CMDLINE_LINUX=" not in grub_text:
451-
new_grub_text.append('GRUB_CMDLINE_LINUX="rootflags=subvol=root_a"')
479+
new_grub_text.append(f'GRUB_CMDLINE_LINUX="{root_flags}"')
452480
grub_def.write_text("\n".join(new_grub_text))
453481

454482
ch(["grub-install", "--target=x86_64-efi", "--efi-directory=/boot", "--bootloader-id=MOCHIOS", "--removable"])
455483
ch(["grub-install", "--target=i386-pc", disk])
456484
ch(["grub-mkconfig", "-o", "/boot/grub/grub.cfg"])
457485

458486

459-
def install_mochiboot(target, disk, root_uuid, lfn, ch, kernels=None):
487+
def install_mochiboot(target, disk, root_uuid, lfn, ch, kernels=None, filesystem="btrfs"):
460488
if kernels is None:
461489
kernels = ["linux"]
462490
lfn("installing mochiboot...")
463491

492+
root_flags = "rootflags=subvol=root_a " if filesystem == "btrfs" else ""
493+
464494
config_lines = [
465495
"TIMEOUT=5",
466496
"VERBOSE=no",
@@ -488,12 +518,12 @@ def install_mochiboot(target, disk, root_uuid, lfn, ch, kernels=None):
488518
config_lines.append(f":{label}")
489519
config_lines.append(" PROTOCOL=linux")
490520
config_lines.append(f" KERNEL_PATH={vmlinuz}")
491-
config_lines.append(f" CMDLINE=root=UUID={root_uuid} rootflags=subvol=root_a rw loglevel=4")
521+
config_lines.append(f" CMDLINE=root=UUID={root_uuid} {root_flags}rw loglevel=4")
492522
config_lines.append("")
493523
config_lines.append(":MOCHIOS (recovery mode)")
494524
config_lines.append(" PROTOCOL=linux")
495525
config_lines.append(f" KERNEL_PATH=/boot/vmlinuz-{kernels[0]}")
496-
config_lines.append(f" CMDLINE=root=UUID={root_uuid} rootflags=subvol=root_a rw loglevel=4 mochi.recovery")
526+
config_lines.append(f" CMDLINE=root=UUID={root_uuid} {root_flags}rw loglevel=4 mochi.recovery")
497527
config_lines.append("")
498528

499529
config = "\n".join(config_lines)
@@ -542,18 +572,43 @@ def cleanup_mounts(target):
542572
_sp.run(["umount", "-l", "/mnt/btrfs_tmp"], capture_output=True, check=False, timeout=10)
543573

544574

575+
_INSTALL_LOCK = "/tmp/mochiinstall.lock"
576+
577+
def _acquire_lock():
578+
try:
579+
fd = os.open(_INSTALL_LOCK, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o644)
580+
os.write(fd, str(os.getpid()).encode())
581+
os.close(fd)
582+
return True
583+
except FileExistsError:
584+
return False
585+
586+
def _release_lock():
587+
try:
588+
os.remove(_INSTALL_LOCK)
589+
except OSError:
590+
pass
591+
592+
545593
def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None):
546594
if log_fn is None:
547595
log_fn = print
548596
if config is None:
549597
config = {}
550598

599+
if not _acquire_lock():
600+
raise RuntimeError("another installer instance is already running")
601+
551602
mounts_cleanup_needed = False
552603
_STEP_COUNT[0] = 0
553604
try:
554605
if abort_flag and abort_flag():
555606
raise RuntimeError("installation aborted")
556607
log_fn("starting mochios installation...")
608+
609+
# pre-flight: unmount any leftover mounts from failed installs
610+
_unmount_all()
611+
557612
disk = select_disk(config.get("disk"))
558613
bios_part, efi_part, swap_part, root_part_p = partition_disk(disk, log_fn)
559614
mounts_cleanup_needed = True
@@ -562,17 +617,31 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
562617
raise RuntimeError("installation aborted")
563618
format_efi(efi_part, log_fn)
564619
format_swap(swap_part, log_fn)
565-
format_btrfs(root_part_p, log_fn)
620+
621+
filesystem = config.get("filesystem", "btrfs")
622+
if filesystem == "ext4":
623+
format_ext4(root_part_p, log_fn)
624+
else:
625+
format_btrfs(root_part_p, log_fn)
566626

567627
if abort_flag and abort_flag():
568628
raise RuntimeError("installation aborted")
569629
_CLEANUP_TARGET[0] = target
570-
setup_btrfs(root_part_p, target, log_fn)
630+
if filesystem == "ext4":
631+
setup_ext4(root_part_p, target, log_fn)
632+
else:
633+
setup_btrfs(root_part_p, target, log_fn)
571634

572635
efi_uuid = get_uuid(efi_part)
573636
swap_uuid = get_uuid(swap_part)
574637
root_uuid = get_uuid(root_part_p)
575638

639+
if filesystem == "btrfs":
640+
log_fn("configuring snapper for root...")
641+
run(["arch-chroot", target, "snapper", "-c", "root", "create-config", "/"], check=False, timeout=30)
642+
run(["arch-chroot", target, "systemctl", "enable", "snapper-timeline.timer"], check=False)
643+
run(["arch-chroot", target, "systemctl", "enable", "snapper-cleanup.timer"], check=False)
644+
576645
run(["swapon", swap_part], check=False)
577646
run(["mount", efi_part, f"{target}/boot"])
578647

@@ -582,11 +651,15 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
582651

583652
# ensure [mochi] repo is available for pacstrap
584653
mochi_conf = "\n[mochi]\nSigLevel = Optional TrustAll\nServer = https://github.com/iluxz/MochiOS/raw/gh-pages/os/x86_64\n"
585-
with open("/etc/pacman.conf", "a") as f:
586-
if "[mochi]" not in open("/etc/pacman.conf").read():
654+
already_has_mochi = False
655+
if os.path.exists("/etc/pacman.conf"):
656+
with open("/etc/pacman.conf") as check:
657+
already_has_mochi = "[mochi]" in check.read()
658+
if not already_has_mochi:
659+
with open("/etc/pacman.conf", "a") as f:
587660
f.write(mochi_conf)
588661

589-
pacstrap_base(target, log_fn, de=config.get("de", "kde"), greeter=config.get("greeter", "sddm"), bootloader=config.get("bootloader", "limine"), kernels=config.get("kernels", ["linux"]), extra_pkgs=repo_extra, abort_flag=abort_flag)
662+
pacstrap_base(target, log_fn, de=config.get("de", "kde"), greeter=config.get("greeter", "sddm"), bootloader=config.get("bootloader", "limine"), kernels=config.get("kernels", ["linux"]), extra_pkgs=repo_extra, abort_flag=abort_flag, filesystem=filesystem)
590663

591664
log_fn("relaxing SigLevel for custom packages...")
592665
pmconf_path = f"{target}/etc/pacman.conf"
@@ -675,6 +748,7 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
675748
log_fn(f"[dim]{traceback.format_exc()[-500:]}[/]")
676749
return False
677750
finally:
751+
_release_lock()
678752
if mounts_cleanup_needed:
679753
log_fn("[yellow]cleaning up mounts after failure...[/]")
680754
cleanup_mounts(target)

‎archiso-mochios/airootfs/usr/lib/mochiinstall/mochiinstall_app.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,14 @@ def step_disk(self) -> None:
294294
self.body.mount(self._wrap(*kids))
295295

296296
def step_fs(self) -> None:
297+
fs = self.config.get("filesystem", "btrfs")
297298
self.body.mount(self._wrap(
298299
Static("[bold]filesystem[/]"),
299-
SelectionList((("btrfs (snapshots + abroot)", "btrfs", True)), id="fs"),
300+
SelectionList(
301+
("btrfs (snapshots + abroot)", "btrfs", fs == "btrfs"),
302+
("ext4 (traditional)", "ext4", fs == "ext4"),
303+
id="fs",
304+
),
300305
))
301306
self._nav()
302307

@@ -399,6 +404,10 @@ def collect_current(self) -> None:
399404
sel = self.query_one("#disk_list", SelectionList)
400405
if sel.selected:
401406
self.config["disk"] = sel.selected[0]
407+
elif self.step == 2:
408+
sel = self.query_one("#fs", SelectionList)
409+
if sel.selected:
410+
self.config["filesystem"] = sel.selected[0]
402411
elif self.step == 3:
403412
sel = self.query_one("#kernel", SelectionList)
404413
self.config["kernels"] = sel.selected if sel.selected else ["linux"]

‎archiso-mochios/airootfs/usr/share/applications/mochiinstall.desktop‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
Type=Application
33
Name=MochiOS Installer
44
Comment=Install MochiOS to your system
5-
Exec=mochiinstall
5+
Exec=sudo -E /usr/local/bin/mochiinstall
66
Icon=system-software-install
77
Terminal=false
88
Categories=System;
99
X-KDE-Authorize=true
10-
Trusted=true
11-

‎archiso-mochios/airootfs/usr/share/sddm/themes/mochios-nightly/Main.qml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import QtQuick.Controls 2.15
33
import QtQuick.Layouts 1.15
44

55
Rectangle {
6-
width: 1920
7-
height: 1080
6+
width: Screen.width
7+
height: Screen.height
88
color: "#0d0719"
99

1010
Canvas {

‎archiso-mochios/airootfs/usr/share/sddm/themes/mochios/Main.qml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import QtQuick.Controls 2.15
33
import QtQuick.Layouts 1.15
44

55
Rectangle {
6-
width: 1920
7-
height: 1080
6+
width: Screen.width
7+
height: Screen.height
88
color: "#231937"
99

1010
Rectangle {

0 commit comments

Comments
 (0)