From 517c99e542813dadc6cec6f94df681f729b26613 Mon Sep 17 00:00:00 2001 From: "Jose M. Guisado" Date: Wed, 16 Aug 2023 14:25:49 +0200 Subject: utils: add boot.py Add utility module related to the process of booting a system from a client's partition. The main utility function to boot a clients system is boot_os_at(), from which firmware (UEFI or BIOS) and os-family specific private functions are invoked. This initial commit adds UEFI windows boot function. --- src/utils/boot.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/utils/boot.py diff --git a/src/utils/boot.py b/src/utils/boot.py new file mode 100644 index 0000000..5a02ec6 --- /dev/null +++ b/src/utils/boot.py @@ -0,0 +1,63 @@ +# +# 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_os_at(disk, part): + if not is_uefi_supported(): + 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) + if os_family == OSFamily.WINDOWS: + _boot_uefi_windows(disk, part, mountpoint) + elif os_family == OSFamily.LINUX: + raise NotImplementedError('WIP: Linux UEFI boot not implemented yet.') + else: + raise RuntimeError('Unknown OS family') -- cgit v1.2.3-18-g5258