This commit is contained in:
HADEON 2026-05-18 17:34:16 +01:00 committed by GitHub
commit 893be4d159
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 164 additions and 26 deletions

View File

@ -118,6 +118,14 @@ def lvm_vol_change(vol: LvmVolume, activate: bool) -> None:
SysCommand(cmd)
def lvm_vg_change(vg: LvmVolumeGroup, activate: bool) -> None:
active_flag = 'y' if activate else 'n'
cmd = ['vgchange', '-a', active_flag, vg.name]
debug(f'vgchange volume group: {" ".join(cmd)}')
SysCommand(cmd)
def lvm_export_vg(vg: LvmVolumeGroup) -> None:
cmd = f'vgexport {vg.name}'

View File

@ -1,12 +1,18 @@
import os
from contextlib import suppress
from pathlib import Path
from typing import TYPE_CHECKING
from pydantic import BaseModel
from archinstall.lib.command import SysCommand
from archinstall.lib.exceptions import DiskError, SysCallError
from archinstall.lib.models.device import LsblkInfo
from archinstall.lib.models.device import EncryptionType, FilesystemType, LsblkInfo
from archinstall.lib.output import debug, info, warn
if TYPE_CHECKING:
from archinstall.lib.installer import Installer
class LsblkOutput(BaseModel):
blockdevices: list[LsblkInfo]
@ -196,3 +202,119 @@ def swapon(path: Path) -> None:
SysCommand(['swapon', str(path)])
except SysCallError as err:
raise DiskError(f'Could not enable swap {path}:\n{err.message}')
def teardown(installer: Installer) -> None:
if not installer._layout_teardown_required:
debug('No mounted layout registered for teardown')
return
info('Tearing down installation target')
with suppress(Exception):
os.sync()
_swapoff_layout(installer)
with suppress(SysCallError, DiskError):
umount(installer.target, recursive=True)
match installer._disk_encryption.encryption_type:
case EncryptionType.LUKS:
_teardown_luks_partitions(installer)
case EncryptionType.LUKS_ON_LVM:
_teardown_luks_lvm(installer)
_teardown_lvm(installer)
case EncryptionType.LVM_ON_LUKS:
_teardown_lvm(installer)
_teardown_luks_partitions(installer)
case EncryptionType.NO_ENCRYPTION:
_teardown_lvm(installer)
with suppress(SysCallError):
udev_sync()
installer._layout_teardown_required = False
def _swapoff_path(path: Path | None) -> None:
if path is None:
return
with suppress(SysCallError, DiskError):
SysCommand(['swapoff', str(path)])
def _swapoff_layout(installer: Installer) -> None:
for mod in installer._disk_config.device_modifications:
for part in mod.partitions:
if part.is_swap():
_swapoff_path(part.dev_path)
if part.mapper_name:
_swapoff_path(Path('/dev/mapper') / part.mapper_name)
if not installer._disk_config.lvm_config:
return
for vol in installer._disk_config.lvm_config.get_all_volumes():
if vol.fs_type == FilesystemType.LINUX_SWAP:
_swapoff_path(vol.dev_path)
if vol.mapper_name:
_swapoff_path(Path('/dev/mapper') / vol.mapper_name)
def _teardown_lvm(installer: Installer) -> None:
from archinstall.lib.disk.lvm import lvm_vg_change, lvm_vol_change
lvm_config = installer._disk_config.lvm_config
if not lvm_config:
return
for vg in reversed(lvm_config.vol_groups):
for vol in reversed(vg.volumes):
if not vol.dev_path:
continue
with suppress(SysCallError, DiskError):
lvm_vol_change(vol, False)
with suppress(SysCallError, DiskError):
lvm_vg_change(vg, False)
def _teardown_luks_partitions(installer: Installer) -> None:
from archinstall.lib.disk.luks import Luks2
for part_mod in reversed(installer._disk_encryption.partitions):
if not part_mod.dev_path or not part_mod.mapper_name:
continue
luks_handler = Luks2(
part_mod.dev_path,
mapper_name=part_mod.mapper_name,
)
with suppress(SysCallError, DiskError):
luks_handler.lock()
def _teardown_luks_lvm(installer: Installer) -> None:
from archinstall.lib.disk.luks import Luks2
for vol in reversed(installer._disk_encryption.lvm_volumes):
if not vol.dev_path or not vol.mapper_name:
continue
luks_handler = Luks2(
vol.dev_path,
mapper_name=vol.mapper_name,
)
with suppress(SysCallError, DiskError):
luks_handler.lock()

View File

@ -24,6 +24,7 @@ from archinstall.lib.disk.utils import (
get_unique_path_for_device,
mount,
swapon,
teardown,
)
from archinstall.lib.exceptions import DiskError, HardwareIncompatibilityError, RequirementError, ServiceException, SysCallError
from archinstall.lib.hardware import SysInfo
@ -131,45 +132,51 @@ class Installer:
self._zram_enabled = False
self._disable_fstrim = False
self._layout_teardown_required = False
self.pacman = Pacman(self.target, silent)
def __enter__(self) -> Self:
return self
def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> bool | None:
if exc_type is not None:
error(str(exc_value))
try:
if exc_type is not None:
error(str(exc_value))
self.sync_log_to_install_medium()
self.sync_log_to_install_medium()
# We avoid printing /mnt/<log path> because that might confuse people if they note it down
# and then reboot, and an identical log file will be found in the ISO medium anyway.
print(tr('[!] A log file has been created here: {}').format(logger.path))
print(tr('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues'))
# We avoid printing /mnt/<log path> because that might confuse people if they note it down
# and then reboot, and an identical log file will be found in the ISO medium anyway.
print(tr('[!] A log file has been created here: {}').format(logger.path))
print(tr('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues'))
# Return None to propagate the exception
return None
# Return None to propagate the exception
return None
info(tr('Syncing the system...'))
os.sync()
info(tr('Syncing the system...'))
os.sync()
if not (missing_steps := self.post_install_check()):
msg = f'Installation completed without any errors.\nLog files temporarily available at {logger.directory}.\nYou may reboot when ready.\n'
log(msg, fg='green')
self.sync_log_to_install_medium()
return True
else:
warn('Some required steps were not successfully installed/configured before leaving the installer:')
if not (missing_steps := self.post_install_check()):
msg = f'Installation completed without any errors.\nLog files temporarily available at {logger.directory}.\nYou may reboot when ready.\n'
log(msg, fg='green')
self.sync_log_to_install_medium()
return True
else:
warn('Some required steps were not successfully installed/configured before leaving the installer:')
for step in missing_steps:
warn(f' - {step}')
for step in missing_steps:
warn(f' - {step}')
warn(f'Detailed error logs can be found at: {logger.directory}')
warn('Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues')
warn(f'Detailed error logs can be found at: {logger.directory}')
warn('Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues')
self.sync_log_to_install_medium()
return False
self.sync_log_to_install_medium()
return False
finally:
try:
teardown(self)
except Exception as err:
warn(f'Failed to teardown installation target: {err}')
def remove_mod(self, mod: str) -> None:
if mod in self._modules:
@ -257,6 +264,7 @@ class Installer:
def mount_ordered_layout(self) -> None:
debug('Mounting ordered layout')
self._layout_teardown_required = True
luks_handlers: dict[Any, Luks2] = {}