""" Wrapper for UEFI operations """ # -*- coding: utf-8 -*- # # uefi.py # # Copyright 2015 Neil Williams # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # pylint: disable=missing-docstring,duplicate-code import os import logging import cliapp from vmdebootstrap.base import ( Base, runcmd, mount_wrapper, umount_wrapper, ) from vmdebootstrap.constants import arch_table class Uefi(Base): name = 'uefi' def __init__(self): super(Uefi, self).__init__() self.bootdir = None def check_settings(self, oldstable=False): if not self.settings['use-uefi'] and self.settings['esp-size'] != 5242880: raise cliapp.AppException( 'You must specify use-uefi for esp-size to have effect') if self.settings['arch'] in arch_table and\ arch_table[self.settings['arch']]['exclusive'] and\ (not self.settings['use-uefi'] and not self.settings['squash']): raise cliapp.AppException( 'Only UEFI is supported on %s' % self.settings['arch']) elif self.settings['use-uefi'] and self.settings['arch'] not in arch_table: raise cliapp.AppException( '%s is not a supported UEFI architecture' % self.settings['arch']) if self.settings['use-uefi'] and ( self.settings['bootsize'] or self.settings['bootoffset']): raise cliapp.AppException( 'A separate boot partition is not supported with UEFI') if self.settings['use-uefi'] and not self.settings['grub']: raise cliapp.AppException( 'UEFI without Grub is not supported.') # wheezy (which became oldstable on 04/25/2015) only had amd64 uefi if oldstable: if self.settings['arch'] != 'amd64' and self.settings['use-uefi']: raise cliapp.AppException( 'Only amd64 supports UEFI in Wheezy') def efi_packages(self): packages = [] if not self.settings['use-uefi'] or\ self.settings['arch'] not in arch_table: return packages pkg = arch_table[self.settings['arch']]['package'] self.message("Adding %s to debootstrap" % pkg) packages.append(pkg) extra = arch_table[self.settings['arch']]['extra'] if extra and isinstance(extra, str): bin_pkg = arch_table[str(extra)]['bin_package'] self.message("Adding support for %s using %s" % (extra, bin_pkg)) packages.append(bin_pkg) return packages def copy_efi_binary(self, efi_removable, efi_install): if self.settings['arch'] not in arch_table: return logging.debug("using bootdir=%s", self.bootdir) if efi_removable.startswith('/'): efi_removable = efi_removable[1:] if efi_install.startswith('/'): efi_install = efi_install[1:] efi_output = os.path.join(self.bootdir, efi_removable) efi_input = os.path.join(self.bootdir, efi_install) logging.debug("moving %s to %s", efi_output, efi_input) if not os.path.exists(efi_input): logging.warning("%s does not exist (%s)", efi_input, efi_install) raise cliapp.AppException("Missing %s" % efi_input) if not os.path.exists(os.path.dirname(efi_output)): os.makedirs(os.path.dirname(efi_output)) logging.debug( 'Moving UEFI support: %s -> %s', efi_input, efi_output) if os.path.exists(efi_output): os.unlink(efi_output) os.rename(efi_input, efi_output) def configure_efi(self, rootdir): """ Copy the bootloader file from the package into the location so needs to be after grub and kernel already installed. """ if self.settings['arch'] not in arch_table: return self.message('Configuring EFI') mount_wrapper(rootdir) efi_removable = str(arch_table[self.settings['arch']]['removable']) efi_install = str(arch_table[self.settings['arch']]['install']) self.message('Installing UEFI support binary') logging.debug("moving %s to %s", efi_removable, efi_install) try: self.copy_efi_binary(efi_removable, efi_install) finally: umount_wrapper(rootdir) def configure_extra_efi(self, rootdir): if self.settings['arch'] not in arch_table: return extra = arch_table[self.settings['arch']]['extra'] if extra: mount_wrapper(rootdir) efi_removable = str(arch_table[extra]['removable']) efi_install = str(arch_table[extra]['install']) self.message('Copying UEFI support binary for %s' % extra) try: self.copy_efi_binary(efi_removable, efi_install) finally: umount_wrapper(rootdir) def partition_esp(self): if not self.settings['use-uefi']: return espsize = self.settings['esp-size'] / (1024 * 1024) self.message("Using ESP size: %smib %s bytes" % (espsize, self.settings['esp-size'])) runcmd(['parted', '-s', self.settings['image'], 'mkpart', 'primary', 'fat32', '1', str(espsize)]) runcmd(['parted', '-s', self.settings['image'], 'set', '1', 'boot', 'on']) runcmd(['parted', '-s', self.settings['image'], 'set', '1', 'esp', 'on']) def prepare_esp(self, rootdir, bootdev): self.bootdir = '%s/%s/%s' % (rootdir, 'boot', 'efi') logging.debug("bootdir:%s", self.bootdir) self.mkfs(bootdev, fstype='vfat') os.makedirs(self.bootdir) return self.bootdir def make_root(self, extent): bootsize = self.settings['esp-size'] / (1024 * 1024) + 1 runcmd(['parted', '-s', self.settings['image'], 'mkpart', 'primary', str(bootsize), extent])