diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml index 82a158563..2cfe3a7a6 100644 --- a/v2v/convert_linux.ml +++ b/v2v/convert_linux.ml @@ -97,10 +97,9 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source rcaps = "/boot/grub/grub.conf", `Grub1; ] in let locations = - if inspect.i_uefi then - ("/boot/efi/EFI/redhat/grub.cfg", `Grub2) :: locations - else - locations in + match inspect.i_firmware with + | I_UEFI _ -> ("/boot/efi/EFI/redhat/grub.cfg", `Grub2) :: locations + | I_BIOS -> locations in try List.find ( fun (grub_config, _) -> g#is_file ~followsymlinks:true grub_config diff --git a/v2v/inspect_source.ml b/v2v/inspect_source.ml index 65dcb889c..86d78924e 100644 --- a/v2v/inspect_source.ml +++ b/v2v/inspect_source.ml @@ -65,11 +65,6 @@ let rec inspect_source root_choice g = StringMap.add name (app :: vs) map ) StringMap.empty apps in - (* See if this guest could use UEFI to boot. It should use GPT and - * it should have an EFI System Partition (ESP). - *) - let uefi = has_uefi_bootable_device g in - let inspect = { i_root = root; i_type = g#inspect_get_type root; @@ -84,7 +79,7 @@ let rec inspect_source root_choice g = i_mountpoints = mps; i_apps = apps; i_apps_map = apps_map; - i_uefi = uefi + i_firmware = get_firmware_bootable_device g; } in debug "%s" (string_of_inspect inspect); @@ -153,10 +148,20 @@ and reject_if_not_installed_image g root = if fmt <> "installed" then error (f_"libguestfs thinks this is not an installed operating system (it might be, for example, an installer disk or live CD). If this is wrong, it is probably a bug in libguestfs. root=%s fmt=%s") root fmt -and has_uefi_bootable_device g = +(* See if this guest could use UEFI to boot. It should use GPT and + * it should have an EFI System Partition (ESP). + * + * If it has ESP(s), then [UEFI devs] is returned where [devs] is the + * list of at least one ESP. + * + * Otherwise, [BIOS] is returned. + *) +and get_firmware_bootable_device g = let rec uefi_ESP_guid = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" and is_uefi_ESP dev { G.part_num = partnum } = g#part_get_gpt_type dev (Int32.to_int partnum) = uefi_ESP_guid + and part_dev_name dev { G.part_num = partnum } = + sprintf "%s%d" dev (Int32.to_int partnum) and parttype_is_gpt dev = try g#part_get_parttype dev = "gpt" with G.Error msg as exn -> @@ -164,14 +169,24 @@ and has_uefi_bootable_device g = if g#last_errno () <> G.Errno.errno_EINVAL then raise exn; debug "%s (ignored)" msg; false - and is_uefi_bootable_device dev = - parttype_is_gpt dev && ( - let partitions = Array.to_list (g#part_list dev) in - List.exists (is_uefi_ESP dev) partitions - ) + and is_uefi_bootable_part dev part = + parttype_is_gpt dev && is_uefi_ESP dev part in let devices = Array.to_list (g#list_devices ()) in - List.exists is_uefi_bootable_device devices + let uefi_list = ref [] in + + List.iter ( + fun dev -> + Array.iter ( + fun part -> + if is_uefi_bootable_part dev part then + uefi_list := part_dev_name dev part :: !uefi_list + ) (g#part_list dev) + ) devices; + + match !uefi_list with + | [] -> I_BIOS + | devices -> I_UEFI devices (* If some inspection fields are "unknown", then that indicates a * failure in inspection, and we shouldn't continue. For an example diff --git a/v2v/types.ml b/v2v/types.ml index 08e1631e2..bff03a291 100644 --- a/v2v/types.ml +++ b/v2v/types.ml @@ -301,6 +301,10 @@ let string_of_target_firmware = function | TargetBIOS -> "bios" | TargetUEFI -> "uefi" +type i_firmware = + | I_BIOS + | I_UEFI of string list + type inspect = { i_root : string; i_type : string; @@ -315,7 +319,7 @@ type inspect = { i_mountpoints : (string * string) list; i_apps : Guestfs.application2 list; i_apps_map : Guestfs.application2 list StringMap.t; - i_uefi : bool; + i_firmware : i_firmware; } let string_of_inspect inspect = @@ -330,7 +334,7 @@ i_package_format = %s i_package_management = %s i_product_name = %s i_product_variant = %s -i_uefi = %b +i_firmware = %s " inspect.i_root inspect.i_type inspect.i_distro @@ -341,7 +345,9 @@ i_uefi = %b inspect.i_package_management inspect.i_product_name inspect.i_product_variant - inspect.i_uefi + (match inspect.i_firmware with + | I_BIOS -> "BIOS" + | I_UEFI devices -> sprintf "UEFI [%s]" (String.concat ", " devices)) type mpstat = { mp_dev : string; diff --git a/v2v/types.mli b/v2v/types.mli index dacc99194..25420df94 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -204,6 +204,10 @@ type target_firmware = TargetBIOS | TargetUEFI val string_of_target_firmware : target_firmware -> string +type i_firmware = + | I_BIOS + | I_UEFI of string list + type inspect = { i_root : string; (** Root device. *) i_type : string; (** Usual inspection fields. *) @@ -221,7 +225,9 @@ type inspect = { (** This is a map from the app name to the application object. Since RPM allows multiple packages with the same name to be installed, the value is a list. *) - i_uefi : bool; (** True if the guest could boot with UEFI. *) + i_firmware : i_firmware; + (** The list of EFI system partitions for the guest with UEFI, + otherwise the BIOS identifier. *) } (** Inspection information. *) diff --git a/v2v/v2v.ml b/v2v/v2v.ml index fe81df5aa..79b6f0460 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -555,7 +555,10 @@ and get_target_firmware inspect guestcaps source output = | BIOS -> TargetBIOS | UEFI -> TargetUEFI | UnknownFirmware -> - if inspect.i_uefi then TargetUEFI else TargetBIOS in + match inspect.i_firmware with + | I_BIOS -> TargetBIOS + | I_UEFI devs -> TargetUEFI + in let supported_firmware = output#supported_firmware in if not (List.mem target_firmware supported_firmware) then error (f_"this guest cannot run on the target, because the target does not support %s firmware (supported firmware on target: %s)") diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml index 8e8957d76..60644487f 100644 --- a/v2v/v2v_unit_tests.ml +++ b/v2v/v2v_unit_tests.ml @@ -30,7 +30,7 @@ let inspect_defaults = { i_major_version = 0; i_minor_version = 0; i_root = ""; i_package_format = ""; i_package_management = ""; i_product_name = ""; i_product_variant = ""; i_mountpoints = []; - i_apps = []; i_apps_map = StringMap.empty; i_uefi = false + i_apps = []; i_apps_map = StringMap.empty; i_firmware = I_BIOS } let test_get_ostype ctx =