Renamed vfat -> fat32 for the purpose of consistency. Most actions are referring to fat32, it's only mkfs that has the notion vfat and then -F32 for format 32. And I think vfat confuses more people than it does good, so sticking with fat32 which works better with parted as well. Also added the partitioning logic, started on the mounting logic

This commit is contained in:
Anton Hvornum 2021-06-10 20:38:35 +02:00
parent 4691bad46b
commit 4e9b1c1635
3 changed files with 63 additions and 36 deletions

View File

@ -13,10 +13,19 @@ GPT = 0b00000001
MBR = 0b00000010 MBR = 0b00000010
# import ctypes def valid_fs_type(fstype :str) -> bool:
# import ctypes.util # https://www.gnu.org/software/parted/manual/html_node/mkpart.html
# libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
# libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p) return fstype in [
"ext2",
"fat16", "fat32",
"hfs", "hfs+", "hfsx",
"linux-swap",
"NTFS",
"reiserfs",
"ufs",
"btrfs",
]
class BlockDevice: class BlockDevice:
@ -177,6 +186,11 @@ class BlockDevice:
def flush_cache(self): def flush_cache(self):
self.part_cache = {} self.part_cache = {}
def get_partition(self, uuid):
for partition in self:
if partition.uuid == uuid:
return partition
class Partition: class Partition:
def __init__(self, path: str, block_device: BlockDevice, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False, autodetect_filesystem=True): def __init__(self, path: str, block_device: BlockDevice, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False, autodetect_filesystem=True):
@ -425,34 +439,34 @@ class Partition:
if filesystem == 'btrfs': if filesystem == 'btrfs':
if b'UUID' not in (mkfs := SysCommand(f'/usr/bin/mkfs.btrfs -f {path}')): if b'UUID' not in (mkfs := SysCommand(f'/usr/bin/mkfs.btrfs -f {path}')):
raise DiskError(f'Could not format {path} with {filesystem} because: {mkfs}') raise DiskError(f'Could not format {path} with {filesystem} because: {mkfs}')
self.filesystem = 'btrfs' self.filesystem = filesystem
elif filesystem == 'vfat': elif filesystem == 'fat32':
mkfs = SysCommand(f'/usr/bin/mkfs.vfat -F32 {path}') mkfs = SysCommand(f'/usr/bin/mkfs.vfat -F32 {path}')
if (b'mkfs.fat' not in mkfs and b'mkfs.vfat' not in mkfs) or b'command not found' in mkfs: if (b'mkfs.fat' not in mkfs and b'mkfs.vfat' not in mkfs) or b'command not found' in mkfs:
raise DiskError(f"Could not format {path} with {filesystem} because: {mkfs}") raise DiskError(f"Could not format {path} with {filesystem} because: {mkfs}")
self.filesystem = 'vfat' self.filesystem = filesystem
elif filesystem == 'ext4': elif filesystem == 'ext4':
if (handle := SysCommand(f'/usr/bin/mkfs.ext4 -F {path}')).exit_code != 0: if (handle := SysCommand(f'/usr/bin/mkfs.ext4 -F {path}')).exit_code != 0:
raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
self.filesystem = 'ext4' self.filesystem = filesystem
elif filesystem == 'xfs': elif filesystem == 'xfs':
if (handle := SysCommand(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0: if (handle := SysCommand(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0:
raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
self.filesystem = 'xfs' self.filesystem = filesystem
elif filesystem == 'f2fs': elif filesystem == 'f2fs':
if (handle := SysCommand(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0: if (handle := SysCommand(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0:
raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
self.filesystem = 'f2fs' self.filesystem = filesystem
elif filesystem == 'crypto_LUKS': elif filesystem == 'crypto_LUKS':
# from .luks import luks2 # from .luks import luks2
# encrypted_partition = luks2(self, None, None) # encrypted_partition = luks2(self, None, None)
# encrypted_partition.format(path) # encrypted_partition.format(path)
self.filesystem = 'crypto_LUKS' self.filesystem = filesystem
else: else:
raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.")
@ -583,12 +597,32 @@ class Filesystem:
# We then iterate the partitions in order # We then iterate the partitions in order
for partition in layout.get('partitions', []): for partition in layout.get('partitions', []):
# We don't want to re-add an existing partition (those containing a UUID already) # We don't want to re-add an existing partition (those containing a UUID already)
if 'UUID' not in partition: if partition.get('format', False) and not partition.get('uuid', None):
self.add_partition(partition.get('type', 'primary'), partition['device_instance'] = self.add_partition(partition.get('type', 'primary'),
start=partition.get('start', '1MiB'), # TODO: Revisit sane block starts (4MB for memorycards for instance) start=partition.get('start', '1MiB'), # TODO: Revisit sane block starts (4MB for memorycards for instance)
end=partition.get('size', '100%'), end=partition.get('size', '100%'),
partition_format=partition.get('filesystem', {}).get('format', 'btrfs')) partition_format=partition.get('filesystem', {}).get('format', 'btrfs'))
elif partition_uuid := partition.get('uuid'):
if partition_instance := self.blockdevice.get_partition(uuid=partition_uuid):
partition['device_instance'] = partition_instance
else:
raise ValueError("BlockDevice().load_layout() doesn't know how to continue without either a UUID or creation of partition.")
if partition.get('filesystem', {}).get('format', None):
if partition.get('encrypt', False):
assert partition.get('password')
partition['device_instance'].encrypt(password=partition['password'])
with archinstall.luks2(partition['device_instance'], 'luksloop', partition['password']) as unlocked_device:
unlocked_device.format(partition['filesystem']['format'], allow_formatting=partition.get('format', False))
else:
partition['device_instance'].format(partition['filesystem']['format'], allow_formatting=partition.get('format', False))
def mount_ordered_layout(self, layout :dict):
mountpoints = {}
for partition in layout['partitions']:
print(partition)
exit(0) exit(0)
def find_partition(self, mountpoint): def find_partition(self, mountpoint):
@ -610,17 +644,19 @@ class Filesystem:
""" """
return self.raw_parted(string).exit_code return self.raw_parted(string).exit_code
def use_entire_disk(self, root_filesystem_type='ext4'): def use_entire_disk(self, root_filesystem_type='ext4') -> Partition:
# TODO: Implement this with declarative profiles instead. # TODO: Implement this with declarative profiles instead.
raise ValueError("Installation().use_entire_disk() has to be re-worked.") raise ValueError("Installation().use_entire_disk() has to be re-worked.")
def add_partition(self, partition_type, start, end, partition_format=None): def add_partition(self, partition_type, start, end, partition_format=None):
log(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO) log(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO)
previous_partitions = self.blockdevice.partitions previous_partition_uuids = {partition.uuid for partition in self.blockdevice.partitions.values()}
if self.mode == MBR: if self.mode == MBR:
if len(self.blockdevice.partitions) > 3: if len(self.blockdevice.partitions) > 3:
DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions") DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions")
if partition_format: if partition_format:
partitioning = self.parted(f'{self.blockdevice.device} mkpart {partition_type} {partition_format} {start} {end}') == 0 partitioning = self.parted(f'{self.blockdevice.device} mkpart {partition_type} {partition_format} {start} {end}') == 0
else: else:
@ -628,12 +664,13 @@ class Filesystem:
if partitioning: if partitioning:
start_wait = time.time() start_wait = time.time()
while previous_partitions == self.blockdevice.partitions: while previous_partition_uuids == {partition.uuid for partition in self.blockdevice.partitions.values()}:
time.sleep(0.025) # Let the new partition come up in the kernel
if time.time() - start_wait > 10: if time.time() - start_wait > 10:
raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).") raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
time.sleep(0.025)
return True time.sleep(0.5) # Let the kernel catch up with quick block devices (nvme for instance)
return self.blockdevice.get_partition(uuid=(previous_partition_uuids ^ {partition.uuid for partition in self.blockdevice.partitions.values()}).pop())
def set_name(self, partition: int, name: str): def set_name(self, partition: int, name: str):
return self.parted(f'{self.blockdevice.device} name {partition + 1} "{name}"') == 0 return self.parted(f'{self.blockdevice.device} name {partition + 1} "{name}"') == 0

View File

@ -9,7 +9,7 @@ import signal
import sys import sys
import time import time
from .disk import BlockDevice from .disk import BlockDevice, valid_fs_type
from .exceptions import * from .exceptions import *
from .general import SysCommand from .general import SysCommand
from .hardware import AVAILABLE_GFX_DRIVERS, has_uefi from .hardware import AVAILABLE_GFX_DRIVERS, has_uefi
@ -580,20 +580,6 @@ def select_partition_layout(block_device):
} }
} }
def valid_fs_type(fstype :str) -> bool:
# https://www.gnu.org/software/parted/manual/html_node/mkpart.html
return fstype in [
"ext2",
"fat16", "fat32",
"hfs", "hfs+", "hfsx",
"linux-swap",
"NTFS",
"reiserfs",
"ufs",
"btrfs",
]
def valid_parted_position(pos :str): def valid_parted_position(pos :str):
if not len(pos): if not len(pos):
return False return False
@ -630,6 +616,7 @@ def get_default_partition_layout(block_devices):
"start" : "1MiB", "start" : "1MiB",
"size" : "513MiB", "size" : "513MiB",
"boot" : True, "boot" : True,
"format" : True,
"mountpoint" : "/boot", "mountpoint" : "/boot",
"filesystem" : { "filesystem" : {
"format" : "fat32" "format" : "fat32"
@ -640,6 +627,7 @@ def get_default_partition_layout(block_devices):
"type" : "primary", "type" : "primary",
"start" : "513MiB", "start" : "513MiB",
"encrypted" : True, "encrypted" : True,
"format" : True,
"size" : "100%" if block_devices[0].size < MIN_SIZE_TO_ALLOW_HOME_PART else f"{min(block_devices[0].size, 20)*1024}MiB", "size" : "100%" if block_devices[0].size < MIN_SIZE_TO_ALLOW_HOME_PART else f"{min(block_devices[0].size, 20)*1024}MiB",
"mountpoint" : "/", "mountpoint" : "/",
"filesystem" : { "filesystem" : {
@ -652,6 +640,7 @@ def get_default_partition_layout(block_devices):
# Home # Home
"type" : "primary", "type" : "primary",
"encrypted" : True, "encrypted" : True,
"format" : True,
"start" : f"{min(block_devices[0].size*0.2, 20)*1024}MiB", "start" : f"{min(block_devices[0].size*0.2, 20)*1024}MiB",
"size" : "100%", "size" : "100%",
"mountpoint" : "/home", "mountpoint" : "/home",

View File

@ -223,6 +223,7 @@ def perform_filesystem_operations():
for drive in archinstall.arguments['harddrives']: for drive in archinstall.arguments['harddrives']:
with archinstall.Filesystem(drive, mode) as fs: with archinstall.Filesystem(drive, mode) as fs:
fs.load_layout(archinstall.storage['disk_layouts'][drive]) fs.load_layout(archinstall.storage['disk_layouts'][drive])
fs.mount_ordered_layout(archinstall.storage['disk_layouts'][drive])
perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt')) perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt'))