Removed old safety logics for partitions. Partitions will now always be formatted when .format() is called on them. The safety now lay in the code parsing the declerative partition layouts. Also added the encrypt/mount logic for encrypted partitions, which by default will be unencrypted unless a password is specified.
This commit is contained in:
parent
af790faf7a
commit
d76760b45f
|
|
@ -76,6 +76,7 @@ def suggest_single_disk_layout(block_device):
|
||||||
"start" : "1MiB",
|
"start" : "1MiB",
|
||||||
"size" : "513MiB",
|
"size" : "513MiB",
|
||||||
"boot" : True,
|
"boot" : True,
|
||||||
|
"encrypted" : False,
|
||||||
"format" : True,
|
"format" : True,
|
||||||
"mountpoint" : "/boot",
|
"mountpoint" : "/boot",
|
||||||
"filesystem" : {
|
"filesystem" : {
|
||||||
|
|
@ -86,7 +87,7 @@ def suggest_single_disk_layout(block_device):
|
||||||
# Root
|
# Root
|
||||||
"type" : "primary",
|
"type" : "primary",
|
||||||
"start" : "513MiB",
|
"start" : "513MiB",
|
||||||
"encrypted" : True,
|
"encrypted" : False,
|
||||||
"format" : True,
|
"format" : True,
|
||||||
"size" : "100%" if block_device.size < MIN_SIZE_TO_ALLOW_HOME_PART else f"{min(block_device.size, 20)*1024}MiB",
|
"size" : "100%" if block_device.size < MIN_SIZE_TO_ALLOW_HOME_PART else f"{min(block_device.size, 20)*1024}MiB",
|
||||||
"mountpoint" : "/",
|
"mountpoint" : "/",
|
||||||
|
|
@ -99,7 +100,7 @@ def suggest_single_disk_layout(block_device):
|
||||||
layout[block_device]['partitions'].append({
|
layout[block_device]['partitions'].append({
|
||||||
# Home
|
# Home
|
||||||
"type" : "primary",
|
"type" : "primary",
|
||||||
"encrypted" : True,
|
"encrypted" : False,
|
||||||
"format" : True,
|
"format" : True,
|
||||||
"start" : f"{min(block_device.size*0.2, 20)*1024}MiB",
|
"start" : f"{min(block_device.size*0.2, 20)*1024}MiB",
|
||||||
"size" : "100%",
|
"size" : "100%",
|
||||||
|
|
@ -138,6 +139,7 @@ def suggest_multi_disk_layout(block_devices):
|
||||||
"start" : "1MiB",
|
"start" : "1MiB",
|
||||||
"size" : "513MiB",
|
"size" : "513MiB",
|
||||||
"boot" : True,
|
"boot" : True,
|
||||||
|
"encrypted" : False,
|
||||||
"format" : True,
|
"format" : True,
|
||||||
"mountpoint" : "/boot",
|
"mountpoint" : "/boot",
|
||||||
"filesystem" : {
|
"filesystem" : {
|
||||||
|
|
@ -148,7 +150,7 @@ def suggest_multi_disk_layout(block_devices):
|
||||||
# Root
|
# Root
|
||||||
"type" : "primary",
|
"type" : "primary",
|
||||||
"start" : "513MiB",
|
"start" : "513MiB",
|
||||||
"encrypted" : True,
|
"encrypted" : False,
|
||||||
"format" : True,
|
"format" : True,
|
||||||
"size" : "100%",
|
"size" : "100%",
|
||||||
"mountpoint" : "/",
|
"mountpoint" : "/",
|
||||||
|
|
@ -160,7 +162,7 @@ def suggest_multi_disk_layout(block_devices):
|
||||||
layout[home_device]['partitions'].append({
|
layout[home_device]['partitions'].append({
|
||||||
# Home
|
# Home
|
||||||
"type" : "primary",
|
"type" : "primary",
|
||||||
"encrypted" : True,
|
"encrypted" : False,
|
||||||
"format" : True,
|
"format" : True,
|
||||||
"start" : "4MiB",
|
"start" : "4MiB",
|
||||||
"size" : "100%",
|
"size" : "100%",
|
||||||
|
|
@ -514,7 +516,7 @@ class Partition:
|
||||||
from .luks import luks2
|
from .luks import luks2
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with luks2(self, 'luksloop', password, auto_unmount=True) as unlocked_device:
|
with luks2(self, storage.get('ENC_IDENTIFIER', 'ai')+'loop', password, auto_unmount=True) as unlocked_device:
|
||||||
return unlocked_device.filesystem
|
return unlocked_device.filesystem
|
||||||
except SysCallError:
|
except SysCallError:
|
||||||
return None
|
return None
|
||||||
|
|
@ -540,35 +542,12 @@ class Partition:
|
||||||
|
|
||||||
return True if files > 0 else False
|
return True if files > 0 else False
|
||||||
|
|
||||||
def safe_to_format(self):
|
|
||||||
if self.allow_formatting is False:
|
|
||||||
log(f"Partition {self} is not marked for formatting.", level=logging.DEBUG)
|
|
||||||
return False
|
|
||||||
elif self.target_mountpoint == '/boot':
|
|
||||||
try:
|
|
||||||
if self.has_content():
|
|
||||||
log(f"Partition {self} is a boot partition and has content inside.", level=logging.DEBUG)
|
|
||||||
return False
|
|
||||||
except SysCallError as err:
|
|
||||||
log(err.message, logging.DEBUG)
|
|
||||||
log(f"Partition {self} was identified as /boot but we could not mount to check for content, continuing!", level=logging.DEBUG)
|
|
||||||
pass
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def encrypt(self, *args, **kwargs):
|
def encrypt(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
A wrapper function for luks2() instances and the .encrypt() method of that instance.
|
A wrapper function for luks2() instances and the .encrypt() method of that instance.
|
||||||
"""
|
"""
|
||||||
from .luks import luks2
|
from .luks import luks2
|
||||||
|
|
||||||
if not self._encrypted:
|
|
||||||
raise DiskError(f"Attempting to encrypt a partition that was not marked for encryption: {self}")
|
|
||||||
|
|
||||||
if not self.safe_to_format():
|
|
||||||
log(f"Partition {self} was marked as protected but encrypt() was called on it!", level=logging.ERROR, fg="red")
|
|
||||||
return False
|
|
||||||
|
|
||||||
handle = luks2(self, None, None)
|
handle = luks2(self, None, None)
|
||||||
return handle.encrypt(self, *args, **kwargs)
|
return handle.encrypt(self, *args, **kwargs)
|
||||||
|
|
||||||
|
|
@ -745,6 +724,8 @@ class Filesystem:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def load_layout(self, layout :dict):
|
def load_layout(self, layout :dict):
|
||||||
|
from .luks import luks2
|
||||||
|
|
||||||
# If the layout tells us to wipe the drive, we do so
|
# If the layout tells us to wipe the drive, we do so
|
||||||
if layout.get('wipe', False):
|
if layout.get('wipe', False):
|
||||||
if self.mode == GPT:
|
if self.mode == GPT:
|
||||||
|
|
@ -770,11 +751,11 @@ class Filesystem:
|
||||||
raise ValueError("BlockDevice().load_layout() doesn't know how to continue without either a UUID or creation of partition.")
|
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('filesystem', {}).get('format', None):
|
||||||
if partition.get('encrypt', False):
|
if partition.get('encrypted', False):
|
||||||
assert partition.get('password')
|
assert partition.get('password')
|
||||||
|
|
||||||
partition['device_instance'].encrypt(password=partition['password'])
|
partition['device_instance'].encrypt(password=partition['password'])
|
||||||
with archinstall.luks2(partition['device_instance'], 'luksloop', partition['password']) as unlocked_device:
|
with luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai')+'loop', partition['password']) as unlocked_device:
|
||||||
unlocked_device.format(partition['filesystem']['format'], allow_formatting=partition.get('format', False))
|
unlocked_device.format(partition['filesystem']['format'], allow_formatting=partition.get('format', False))
|
||||||
else:
|
else:
|
||||||
partition['device_instance'].format(partition['filesystem']['format'], allow_formatting=partition.get('format', False))
|
partition['device_instance'].format(partition['filesystem']['format'], allow_formatting=partition.get('format', False))
|
||||||
|
|
@ -957,7 +938,8 @@ def encrypted_partitions(blockdevices :dict) -> bool:
|
||||||
if partition.get('encrypted', False):
|
if partition.get('encrypted', False):
|
||||||
yield partition
|
yield partition
|
||||||
|
|
||||||
def find_partition_by_mountpoint(partitions, relative_mountpoint :str):
|
def find_partition_by_mountpoint(block_devices, relative_mountpoint :str):
|
||||||
for partition in partitions:
|
for device in block_devices:
|
||||||
if partition.get('mountpoint', None) == relative_mountpoint:
|
for partition in block_devices[device]['partitions']:
|
||||||
return partition
|
if partition.get('mountpoint', None) == relative_mountpoint:
|
||||||
|
return partition
|
||||||
|
|
@ -126,13 +126,21 @@ class Installer:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def mount_ordered_layout(self, layouts :dict):
|
def mount_ordered_layout(self, layouts :dict):
|
||||||
|
from .luks import luks2
|
||||||
|
|
||||||
mountpoints = {}
|
mountpoints = {}
|
||||||
for blockdevice in layouts:
|
for blockdevice in layouts:
|
||||||
for partition in layouts[blockdevice]['partitions']:
|
for partition in layouts[blockdevice]['partitions']:
|
||||||
mountpoints[partition['mountpoint']] = partition['device_instance']
|
mountpoints[partition['mountpoint']] = partition
|
||||||
|
|
||||||
for mountpoint in sorted(mountpoints.keys()):
|
for mountpoint in sorted(mountpoints.keys()):
|
||||||
mountpoints[mountpoint].mount(f"{self.target}{mountpoint}")
|
if mountpoints[mountpoint]['encrypted']:
|
||||||
|
loopdev = storage.get('ENC_IDENTIFIER', 'ai')+'loop'
|
||||||
|
password = mountpoints[mountpoint]['password']
|
||||||
|
with luks2(mountpoints[mountpoint]['device_instance'], loopdev, password, auto_unmount=False) as unlocked_device:
|
||||||
|
unlocked_device.mount(f"{self.target}{mountpoint}")
|
||||||
|
else:
|
||||||
|
mountpoints[mountpoint]['device_instance'].mount(f"{self.target}{mountpoint}")
|
||||||
|
|
||||||
def mount(self, partition, mountpoint, create_mountpoint=True):
|
def mount(self, partition, mountpoint, create_mountpoint=True):
|
||||||
if create_mountpoint and not os.path.isdir(f'{self.target}{mountpoint}'):
|
if create_mountpoint and not os.path.isdir(f'{self.target}{mountpoint}'):
|
||||||
|
|
@ -437,6 +445,9 @@ class Installer:
|
||||||
elif partition.mountpoint == self.target:
|
elif partition.mountpoint == self.target:
|
||||||
root_partition = partition
|
root_partition = partition
|
||||||
|
|
||||||
|
if boot_partition is None and root_partition is None:
|
||||||
|
raise ValueError(f"Could not detect root (/) or boot (/boot) in {self.target} based on: {self.partitions}")
|
||||||
|
|
||||||
self.log(f'Adding bootloader {bootloader} to {boot_partition if boot_partition else root_partition}', level=logging.INFO)
|
self.log(f'Adding bootloader {bootloader} to {boot_partition if boot_partition else root_partition}', level=logging.INFO)
|
||||||
|
|
||||||
if bootloader == 'systemd-bootctl':
|
if bootloader == 'systemd-bootctl':
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@ class luks2:
|
||||||
self.mapdev = None
|
self.mapdev = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
# if self.partition.allow_formatting:
|
|
||||||
# self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs)
|
|
||||||
# else:
|
|
||||||
if not self.key_file:
|
if not self.key_file:
|
||||||
self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique?
|
self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique?
|
||||||
|
|
||||||
|
|
@ -42,9 +39,6 @@ class luks2:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def encrypt(self, partition, password=None, key_size=512, hash_type='sha512', iter_time=10000, key_file=None):
|
def encrypt(self, partition, password=None, key_size=512, hash_type='sha512', iter_time=10000, key_file=None):
|
||||||
if not self.partition.allow_formatting:
|
|
||||||
raise DiskError(f'Could not encrypt volume {partition} due to it having a formatting lock.')
|
|
||||||
|
|
||||||
log(f'Encrypting {partition} (This might take a while)', level=logging.INFO)
|
log(f'Encrypting {partition} (This might take a while)', level=logging.INFO)
|
||||||
|
|
||||||
if not key_file:
|
if not key_file:
|
||||||
|
|
@ -132,7 +126,6 @@ class luks2:
|
||||||
if os.path.islink(f'/dev/mapper/{mountpoint}'):
|
if os.path.islink(f'/dev/mapper/{mountpoint}'):
|
||||||
self.mapdev = f'/dev/mapper/{mountpoint}'
|
self.mapdev = f'/dev/mapper/{mountpoint}'
|
||||||
unlocked_partition = Partition(self.mapdev, None, encrypted=True, filesystem=get_filesystem_type(self.mapdev), autodetect_filesystem=False)
|
unlocked_partition = Partition(self.mapdev, None, encrypted=True, filesystem=get_filesystem_type(self.mapdev), autodetect_filesystem=False)
|
||||||
unlocked_partition.allow_formatting = self.partition.allow_formatting
|
|
||||||
return unlocked_partition
|
return unlocked_partition
|
||||||
|
|
||||||
def close(self, mountpoint=None):
|
def close(self, mountpoint=None):
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,6 @@ storage = {
|
||||||
'PROFILE_DB': None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.
|
'PROFILE_DB': None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.
|
||||||
'LOG_PATH': '/var/log/archinstall',
|
'LOG_PATH': '/var/log/archinstall',
|
||||||
'LOG_FILE': 'install.log',
|
'LOG_FILE': 'install.log',
|
||||||
'MOUNT_POINT': '/mnt',
|
'MOUNT_POINT': '/mnt/archinstall',
|
||||||
|
'ENC_IDENTIFIER': 'ainst'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import signal
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from .disk import BlockDevice, valid_fs_type, suggest_single_disk_layout, suggest_multi_disk_layout
|
from .disk import BlockDevice, valid_fs_type, find_partition_by_mountpoint, suggest_single_disk_layout, suggest_multi_disk_layout
|
||||||
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
|
||||||
|
|
@ -190,18 +190,19 @@ def generic_multi_select(options, text="Select one or more of the options above
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
return selected_options
|
return selected_options
|
||||||
|
|
||||||
def select_encrypted_partitions(blockdevices :dict) -> dict:
|
def select_encrypted_partitions(block_devices :dict, password :str) -> dict:
|
||||||
if len(blockdevices) == 1:
|
root = find_partition_by_mountpoint(block_devices, '/')
|
||||||
if len(blockdevices[0]['partitions']) == 2:
|
root['encrypted'] = True
|
||||||
root = find_partition_by_mountpoint(blockdevices[0]['partitions'], '/')
|
root['password'] = password
|
||||||
blockdevices[0]['partitions'][root]['encrypted'] = True
|
|
||||||
return True
|
|
||||||
|
|
||||||
options = []
|
return block_devices
|
||||||
for partition in blockdevices.values():
|
|
||||||
options.append({key: val for key, val in partition.items() if val})
|
|
||||||
|
|
||||||
print(generic_multi_select(options, f"Choose which partitions to encrypt (leave blank when done): "))
|
# TODO: Next version perhaps we can support multiple encrypted partitions
|
||||||
|
#options = []
|
||||||
|
#for partition in block_devices.values():
|
||||||
|
# options.append({key: val for key, val in partition.items() if val})
|
||||||
|
|
||||||
|
#print(generic_multi_select(options, f"Choose which partitions to encrypt (leave blank when done): "))
|
||||||
|
|
||||||
class MiniCurses:
|
class MiniCurses:
|
||||||
def __init__(self, width, height):
|
def __init__(self, width, height):
|
||||||
|
|
|
||||||
|
|
@ -87,11 +87,11 @@ def ask_user_questions():
|
||||||
if (passwd := archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ')):
|
if (passwd := archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ')):
|
||||||
archinstall.arguments['!encryption-password'] = passwd
|
archinstall.arguments['!encryption-password'] = passwd
|
||||||
|
|
||||||
# If no partitions was marked as encrypted (rare), but a password was supplied -
|
if archinstall.arguments['harddrives'] and archinstall.arguments.get('!encryption-password', None):
|
||||||
# then we need to identify which partitions to encrypt. This will default to / (root) if only
|
# If no partitions was marked as encrypted, but a password was supplied and we have some disks to format..
|
||||||
# root and boot are detected.
|
# Then we need to identify which partitions to encrypt. This will default to / (root).
|
||||||
if len(list(archinstall.encrypted_partitions(archinstall.storage['disk_layouts']))) == 0:
|
if len(list(archinstall.encrypted_partitions(archinstall.storage['disk_layouts']))) == 0:
|
||||||
archinstall.storage['disk_layouts'] = archinstall.select_encrypted_partitions(archinstall.storage['disk_layouts'])
|
archinstall.storage['disk_layouts'] = archinstall.select_encrypted_partitions(archinstall.storage['disk_layouts'], archinstall.arguments['!encryption-password'])
|
||||||
|
|
||||||
# Ask which boot-loader to use (will only ask if we're in BIOS (non-efi) mode)
|
# Ask which boot-loader to use (will only ask if we're in BIOS (non-efi) mode)
|
||||||
if not archinstall.arguments.get("bootloader", None):
|
if not archinstall.arguments.get("bootloader", None):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue