@@ -262,6 +262,24 @@ def detect_disk_partitions_summary(disk):
262262 return "\n " .join (lines )
263263
264264
265+ def detect_existing_parts (disk ):
266+ """detect EFI, swap, and data partitions on a disk for existing mode.
267+ returns dict with 'efi', 'swap', 'data' keys (partition paths or None)."""
268+ parts = detect_partitions (disk )
269+ result = {"efi" : None , "swap" : None , "data" : None }
270+ for p in parts :
271+ fstype = p .get ("fstype" , "" )
272+ label = p .get ("label" , "" ).upper ()
273+ name = p ["name" ]
274+ if fstype == "vfat" and (label == "EFI" or "efi" in name .lower ()):
275+ result ["efi" ] = name
276+ elif fstype == "swap" or label == "SWAP" :
277+ result ["swap" ] = name
278+ elif fstype in ("ext4" , "btrfs" , "xfs" ) and result ["data" ] is None :
279+ result ["data" ] = name
280+ return result
281+
282+
265283def select_disk (disk ):
266284 if not disk or not disk .startswith ("/dev/" ):
267285 raise ValueError (f"invalid disk: { disk } " )
@@ -441,25 +459,22 @@ def ch(cmd, to=120, check=True, input_data=None):
441459 ch (["mkinitcpio" , "-P" ], to = 300 )
442460
443461 lfn ("writing fstab..." )
462+ fstab_lines = []
463+ if efi_uuid :
464+ fstab_lines .append (f"UUID={ efi_uuid } /boot vfat rw,noatime,fmask=0022,dmask=0022 0 2" )
465+ if swap_uuid :
466+ fstab_lines .append (f"UUID={ swap_uuid } swap swap defaults 0 0" )
444467 if filesystem == "btrfs" :
445- fstab = (
446- f"UUID={ efi_uuid } /boot vfat rw,noatime,fmask=0022,dmask=0022 0 2\n "
447- f"UUID={ swap_uuid } swap swap defaults 0 0\n "
448- f"UUID={ root_uuid } /mnt/btrfs btrfs rw,noatime,compress=zstd,subvolid=5 0 0\n "
449- f"UUID={ root_uuid } / btrfs rw,noatime,compress=zstd,subvol=root_a 0 0\n "
450- f"UUID={ root_uuid } /home btrfs rw,noatime,compress=zstd,subvol=home 0 0\n "
451- f"UUID={ root_uuid } /var btrfs rw,noatime,compress=zstd,subvol=var 0 0\n "
452- f"UUID={ root_uuid } /var/cache btrfs rw,noatime,compress=zstd,subvol=cache 0 0\n "
453- )
468+ fstab_lines .append (f"UUID={ root_uuid } /mnt/btrfs btrfs rw,noatime,compress=zstd,subvolid=5 0 0" )
469+ fstab_lines .append (f"UUID={ root_uuid } / btrfs rw,noatime,compress=zstd,subvol=root_a 0 0" )
470+ fstab_lines .append (f"UUID={ root_uuid } /home btrfs rw,noatime,compress=zstd,subvol=home 0 0" )
471+ fstab_lines .append (f"UUID={ root_uuid } /var btrfs rw,noatime,compress=zstd,subvol=var 0 0" )
472+ fstab_lines .append (f"UUID={ root_uuid } /var/cache btrfs rw,noatime,compress=zstd,subvol=cache 0 0" )
454473 os .makedirs (f"{ target } /mnt/btrfs" , exist_ok = True )
455474 else :
456- fstab = (
457- f"UUID={ efi_uuid } /boot vfat rw,noatime,fmask=0022,dmask=0022 0 2\n "
458- f"UUID={ swap_uuid } swap swap defaults 0 0\n "
459- f"UUID={ root_uuid } / ext4 rw,noatime 0 1\n "
460- f"UUID={ root_uuid } /home ext4 rw,noatime 0 2\n "
461- )
462- (t / "etc/fstab" ).write_text (fstab )
475+ fstab_lines .append (f"UUID={ root_uuid } / ext4 rw,noatime 0 1" )
476+ fstab_lines .append (f"UUID={ root_uuid } /home ext4 rw,noatime 0 2" )
477+ (t / "etc/fstab" ).write_text ("\n " .join (fstab_lines ) + "\n " )
463478 ch (["systemctl" , "daemon-reload" ])
464479
465480 if filesystem == "btrfs" :
@@ -735,40 +750,94 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
735750 _unmount_all ()
736751
737752 disk = select_disk (config .get ("disk" ))
738- bios_part , efi_part , swap_part , root_part_p = partition_disk (disk , log_fn )
739- mounts_cleanup_needed = True
753+ disk_mode = config .get ("disk_mode" , "wipe" )
740754
741- if abort_flag and abort_flag ():
742- raise RuntimeError ("installation aborted" )
743- format_efi (efi_part , log_fn )
744- format_swap (swap_part , log_fn )
755+ if disk_mode == "existing" :
756+ existing = detect_existing_parts (disk )
757+ efi_part = existing ["efi" ]
758+ swap_part = existing ["swap" ]
759+ root_part_p = config .get ("existing_root" ) or existing ["data" ]
745760
746- filesystem = config .get ("filesystem" , "btrfs" )
747- if filesystem == "ext4" :
748- format_ext4 (root_part_p , log_fn )
749- else :
750- format_btrfs (root_part_p , log_fn )
761+ if not root_part_p :
762+ raise RuntimeError ("no suitable root partition found on disk" )
751763
752- if abort_flag and abort_flag ():
753- raise RuntimeError ("installation aborted" )
754- _CLEANUP_TARGET [0 ] = target
755- if filesystem == "ext4" :
756- setup_ext4 (root_part_p , target , log_fn )
764+ log_fn (f"using existing partitions on { disk } :" )
765+ log_fn (f" root: { root_part_p } " )
766+ if efi_part :
767+ log_fn (f" efi: { efi_part } " )
768+ else :
769+ log_fn (" [yellow]no EFI partition found — you may need to set up boot manually[/]" )
770+ if swap_part :
771+ log_fn (f" swap: { swap_part } " )
772+ else :
773+ log_fn (" [yellow]no swap partition found — no swap will be active[/]" )
774+
775+ mounts_cleanup_needed = True
776+
777+ if abort_flag and abort_flag ():
778+ raise RuntimeError ("installation aborted" )
779+
780+ filesystem = config .get ("filesystem" , "btrfs" )
781+ if filesystem == "ext4" :
782+ format_ext4 (root_part_p , log_fn )
783+ else :
784+ format_btrfs (root_part_p , log_fn )
785+
786+ _CLEANUP_TARGET [0 ] = target
787+ if filesystem == "ext4" :
788+ setup_ext4 (root_part_p , target , log_fn )
789+ else :
790+ setup_btrfs (root_part_p , target , log_fn )
791+
792+ root_uuid = get_uuid (root_part_p )
793+ efi_uuid = get_uuid (efi_part ) if efi_part else ""
794+ swap_uuid = get_uuid (swap_part ) if swap_part else ""
795+
796+ if filesystem == "btrfs" :
797+ log_fn ("configuring snapper for root..." )
798+ run (["arch-chroot" , target , "snapper" , "-c" , "root" , "create-config" , "/" ], check = False , timeout = 30 )
799+ run (["arch-chroot" , target , "systemctl" , "enable" , "snapper-timeline.timer" ], check = False )
800+ run (["arch-chroot" , target , "systemctl" , "enable" , "snapper-cleanup.timer" ], check = False )
801+
802+ if swap_part :
803+ run (["swapon" , swap_part ], check = False )
804+ if efi_part :
805+ run (["mount" , efi_part , f"{ target } /boot" ])
757806 else :
758- setup_btrfs (root_part_p , target , log_fn )
807+ bios_part , efi_part , swap_part , root_part_p = partition_disk (disk , log_fn )
808+ mounts_cleanup_needed = True
809+
810+ if abort_flag and abort_flag ():
811+ raise RuntimeError ("installation aborted" )
812+ format_efi (efi_part , log_fn )
813+ format_swap (swap_part , log_fn )
814+
815+ filesystem = config .get ("filesystem" , "btrfs" )
816+ if filesystem == "ext4" :
817+ format_ext4 (root_part_p , log_fn )
818+ else :
819+ format_btrfs (root_part_p , log_fn )
820+
821+ if abort_flag and abort_flag ():
822+ raise RuntimeError ("installation aborted" )
823+ _CLEANUP_TARGET [0 ] = target
824+ if filesystem == "ext4" :
825+ setup_ext4 (root_part_p , target , log_fn )
826+ else :
827+ setup_btrfs (root_part_p , target , log_fn )
759828
760- efi_uuid = get_uuid (efi_part )
761- swap_uuid = get_uuid (swap_part )
762- root_uuid = get_uuid (root_part_p )
829+ efi_uuid = get_uuid (efi_part )
830+ swap_uuid = get_uuid (swap_part )
831+ root_uuid = get_uuid (root_part_p )
763832
764- if filesystem == "btrfs" :
765- log_fn ("configuring snapper for root..." )
766- run (["arch-chroot" , target , "snapper" , "-c" , "root" , "create-config" , "/" ], check = False , timeout = 30 )
767- run (["arch-chroot" , target , "systemctl" , "enable" , "snapper-timeline.timer" ], check = False )
768- run (["arch-chroot" , target , "systemctl" , "enable" , "snapper-cleanup.timer" ], check = False )
833+ if filesystem == "btrfs" :
834+ log_fn ("configuring snapper for root..." )
835+ run (["arch-chroot" , target , "snapper" , "-c" , "root" , "create-config" , "/" ], check = False , timeout = 30 )
836+ run (["arch-chroot" , target , "systemctl" , "enable" , "snapper-timeline.timer" ], check = False )
837+ run (["arch-chroot" , target , "systemctl" , "enable" , "snapper-cleanup.timer" ], check = False )
769838
770- run (["swapon" , swap_part ], check = False )
771- run (["mount" , efi_part , f"{ target } /boot" ])
839+ run (["swapon" , swap_part ], check = False )
840+ run (["mount" , efi_part , f"{ target } /boot" ])
772841
773842 extra_all = config .get ("extra_pkgs" , []) or []
774843 repo_extra = [p for p in extra_all if isinstance (p , str ) and p not in CUSTOM_EXTRAS ]
0 commit comments