# # Copyright (C) 2023 Soleta Networks # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU Affero General Public License as published by the # Free Software Foundation; either version 3 of the License, or # (at your option) any later version. import json import logging import os import shlex import subprocess from src.utils.probe import OSFamily, get_os_family from src.utils.disk import get_partition_device, get_efi_partition from src.utils.uefi import * from src.utils.fs import * def _boot_uefi_windows(disk, part, mountpoint): logging.info(f'Booting windows system') bootlabel = f'Part-{disk:02d}-{part:02d}' esp, esp_disk, esp_part_number = get_efi_partition(disk) esp_mountpoint = esp.replace('dev', 'mnt') if not mount_mkdir(esp, esp_mountpoint): raise RuntimeError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') loader_paths = [f'{esp_mountpoint}/EFI/{bootlabel}/Boot/bootmgfw.efi', f'{esp_mountpoint}/EFI/Microsoft/Boot/bootmgfw.efi'] try: for efi_app in loader_paths: if os.path.exists(efi_app): loader = efi_app[len(esp_mountpoint):] logging.info(f'Found bootloader at ESP partition: {loader}') break else: raise RuntimeError(f'Unable to locate Windows EFI bootloader bootmgfw.efi') efibootmgr_delete_bootentry(bootlabel) efibootmgr_create_bootentry(esp_disk, esp_part_number, loader, bootlabel) efibootmgr_bootnext(bootlabel) finally: umount(esp_mountpoint) def _boot_uefi_linux(disk, part, mountpoint): logging.info(f'Booting Linux system') bootlabel = f'Part-{disk:02d}-{part:02d}' esp, esp_disk, esp_part_number = get_efi_partition(disk) esp_mountpoint = esp.replace('dev', 'mnt') if not mount_mkdir(esp, esp_mountpoint): raise RuntimeError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') loader_paths = [f'{esp_mountpoint}/EFI/{bootlabel}/Boot/shimx64.efi', f'{esp_mountpoint}/EFI/ubuntu/shimx64.efi'] try: for efi_app in loader_paths: if os.path.exists(efi_app): loader = efi_app[len(esp_mountpoint):] logging.info(f'Found bootloader at ESP partition: {loader}') break else: raise RuntimeError(f'Unable to locate Linux EFI bootloader shimx64.efi') efibootmgr_delete_bootentry(bootlabel) efibootmgr_create_bootentry(esp_disk, esp_part_number, loader, bootlabel) efibootmgr_bootnext(bootlabel) finally: umount(esp_mountpoint) def boot_os_at(disk, part): if not is_uefi_supported(disk): raise NotImplementedError('BIOS booting is not implemented yet') device = get_partition_device(disk, part) mountpoint = device.replace('dev', 'mnt') if not mount_mkdir(device, mountpoint): raise RuntimeError(f'Cannot probe OS family. Unable to mount {device} at {esp_mountpoint}.') logging.info(f'Booting system at {device}. Probing OS family...') os_family = get_os_family(mountpoint) try: if os_family == OSFamily.WINDOWS: _boot_uefi_windows(disk, part, mountpoint) elif os_family == OSFamily.LINUX: _boot_uefi_linux(disk, part, mountpoint) else: raise RuntimeError('Unknown OS family') finally: umount(mountpoint)