diff options
author | PMR <pmr@pmr-lander> | 2016-12-05 15:38:06 +0000 |
---|---|---|
committer | PMR <pmr@pmr-lander> | 2016-12-05 15:38:06 +0000 |
commit | b4b3762ccb59069d283231fc1ff1d731d3d751c1 (patch) | |
tree | 4121856e82227c4457417e7e08c22b7f77493896 /bin | |
parent | cca42320aecd9f7dfe8b96931b5a4133e337fd36 (diff) | |
parent | ef45ffd37854ed990000055b93ed8cb28a3dc9e5 (diff) |
Merge #312473 from ~rodsmith/plainbox-provider-checkbox:uefi-pxe-boot
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/efi-pxeboot | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/bin/efi-pxeboot b/bin/efi-pxeboot new file mode 100755 index 0000000..724fefb --- /dev/null +++ b/bin/efi-pxeboot @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 + +""" +Script to test that the system PXE-booted, if run in EFI mode + +Copyright (c) 2016 Canonical Ltd. + +Authors + Rod Smith <rod.smith@canonical.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 3, +as published by the Free Software Foundation. + +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 <http://www.gnu.org/licenses/>. + +The purpose of this script is to identify whether an EFI-based +system booted from the network (test passes) or from a local disk +(test fails). + +Usage: + efi-pxeboot +""" + +import os +import shlex +import shutil +import sys + +from subprocess import Popen, PIPE + + +def discover_data(): + """Extract boot entry and boot order information. + + :returns: + boot_entries, boot_order, boot_current + """ + command = "efibootmgr -v" + bootinfo_bytes = (Popen(shlex.split(command), stdout=PIPE) + .communicate()[0]) + bootinfo = (bootinfo_bytes.decode(encoding="utf-8", errors="ignore") + .splitlines()) + boot_entries = {} + boot_order = [] + if len(bootinfo) > 1: + for s in bootinfo: + if "BootOrder" in s: + try: + boot_order = s.split(":")[1].replace(" ", "").split(",") + except IndexError: + pass + elif "BootCurrent" in s: + try: + boot_current = s.split(":")[1].strip() + except IndexError: + pass + else: + # On Boot#### lines, #### is characters 4-8.... + hex_value = s[4:8] + # ....and the description starts at character 10 + name = s[10:] + try: + # In normal efibootmgr output, only Boot#### entries + # have characters 4-8 that can be interpreted as + # hex values, so this will harmlessly error out on all + # but Boot#### entries.... + int(hex_value, 16) + boot_entries[hex_value] = name + except ValueError: + pass + return boot_entries, boot_order, boot_current + + +def is_pxe_booted(boot_entries, boot_order, boot_current): + retval = 0 + desc = boot_entries[boot_current] + print("The current boot item is {}".format(boot_current)) + print("The first BootOrder item is {}".format(boot_order[0])) + print("The description of Boot{} is '{}'".format(boot_current, desc)) + if boot_current != boot_order[0]: + # If the BootCurrent entry isn't the same as the first of the + # BootOrder entries, then something is causing the first boot entry + # to fail or be bypassed. This could be a Secure Boot failure, manual + # intervention, a bad boot entry, etc. This is not necessarily a + # problem, but warn of it anyhow.... + desc2 = boot_entries[boot_order[0]] + print("The description of Boot{} is '{}'".format(boot_order[0], desc2)) + print("WARNING: The system is booted using Boot{}, but the first". + format(boot_current)) + print("boot item is Boot{}!".format(boot_order[0])) + if "Network" in desc or "PXE" in desc or "NIC" in desc \ + or "Ethernet" in desc or "IP4" in desc or "IP6" in desc: + # These strings are present in network-boot descriptions. + print("The system seems to have PXE-booted; all OK.") + elif "ubuntu" in desc or "grub" in desc or "shim" in desc or "rEFInd" \ + or "refind_" in desc: + # This string indicates a boot directly from the normal Ubuntu GRUB + # or rEFInd installation on the hard disk. + print("The system seems to have booted directly from the hard disk!") + retval = 1 + elif "SATA" in desc or "Sata" in desc or "Hard Drive" in desc: + # These strings indicate booting with a "generic" disk entry (one + # that uses the fallback filename, EFI/BOOT/bootx64.efi or similar). + print("The system seems to have booted from a disk with the fallback " + "boot loader!") + retval = 1 + else: + # Probably a rare description. Call it an error so we can flag it and + # improve this script. + print("Unable to identify boot path.") + retval = 1 + return retval + + +def main(): + """Check to see if the system PXE-booted.""" + + if shutil.which("efibootmgr") is None: + print("The efibootmgr utility is not installed; exiting!") + return(4) + if not os.geteuid() == 0: + print("This program must be run as root (or via sudo); exiting!") + return(4) + + retval = 0 + boot_entries, boot_order, boot_current = discover_data() + if boot_entries == {}: + print("No EFI boot entries are available. This may indicate a " + "firmware problem.") + retval = 2 + if boot_order == []: + print("The EFI BootOrder variable is not available. This may " + "indicate a firmware") + print("problem.") + retval = 3 + if (retval == 0): + retval = is_pxe_booted(boot_entries, boot_order, boot_current) + return(retval) + + +if __name__ == '__main__': + sys.exit(main()) |