See: https://www.redhat.com/archives/libguestfs/2017-February/msg00064.html --- v2v/input_ova.ml | 5 ++--- v2v/utils.ml | 46 ++++++++++++++++++++++++++-------------------- v2v/utils.mli | 7 +++---- v2v/v2v_unit_tests.ml | 7 +++++++ 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml index 3c11cd0..411e901 100644 --- a/v2v/input_ova.ml +++ b/v2v/input_ova.ml @@ -90,9 +90,8 @@ object match detect_file_type ova with | `Tar -> (* Normal ovas are tar file (not compressed). *) - let qmajor, qminor = qemu_img_version () in - if qmajor > 2 || (qmajor == 2 && qminor >= 8) then ( - (* If QEMU is 2.8 or newer we don't have to extract everything. + if qemu_img_supports_offset_and_size () then ( + (* In newer QEMU we don't have to extract everything. * We can access disks inside the tar archive directly. *) untar_metadata ova tmpdir; diff --git a/v2v/utils.ml b/v2v/utils.ml index 6a3074e..295134b 100644 --- a/v2v/utils.ml +++ b/v2v/utils.ml @@ -91,26 +91,32 @@ let du filename = | line::_ -> Int64.of_string line | [] -> invalid_arg filename -let qemu_img_version () = - let lines = external_command "qemu-img --version" in - match lines with - | [] -> error (f_"'qemu-img --version' returned no output") - | line :: _ -> - let rex = Str.regexp - "qemu-img version \\([0-9]+\\)\\.\\([0-9]+\\)" in - if Str.string_match rex line 0 then ( - try - int_of_string (Str.matched_group 1 line), - int_of_string (Str.matched_group 2 line) - with Failure _ -> - warning (f_"failed to parse qemu-img version(%S), assuming 0.9") - line; - 0, 9 - ) else ( - warning (f_"failed to read qemu-img version(%S), assuming 0.9") - line; - 0, 9 - ) +let qemu_img_supports_offset_and_size () = + (* We actually attempt to create a qcow2 file with a raw backing + * file that has an offset and size. + *) + let tmp = Filename.temp_file "v2vqemuimgtst" ".img" in + Unix.truncate tmp 1024; + + let json = [ + "file", JSON.Dict [ + "driver", JSON.String "raw"; + "offset", JSON.Int 512; + "size", JSON.Int 512; + "file", JSON.Dict [ + "filename", JSON.String tmp + ] + ] + ] in + + let cmd = + sprintf "qemu-img info 'json:%s' >/dev/null%s" + (quote (JSON.string_of_doc ~fmt:JSON.Compact json)) + (if verbose () then "" else " 2>&1") in + debug "%s" cmd; + let r = Sys.command cmd in + Unix.unlink tmp; + r = 0 let find_file_in_tar tar filename = let lines = external_command (sprintf "tar tRvf %s" (Filename.quote tar)) in diff --git a/v2v/utils.mli b/v2v/utils.mli index eb47d03..b75baa7 100644 --- a/v2v/utils.mli +++ b/v2v/utils.mli @@ -51,10 +51,9 @@ val du : string -> int64 This can raise either [Failure] or [Invalid_argument] in case of errors. *) -val qemu_img_version : unit -> int * int -(** Returns version of qemu-img as a tuple [(major, minor)]. - - In case of error [(0,9)] is returned. *) +val qemu_img_supports_offset_and_size : unit -> bool +(** Return true iff [qemu-img] supports the ["offset"] and ["size"] + parameters to open a subset of a file. *) val find_file_in_tar : string -> string -> int64 * int64 (** [find_file_in_tar tar filename] looks up file in [tar] archive and returns diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml index a89d8b0..1133d92 100644 --- a/v2v/v2v_unit_tests.ml +++ b/v2v/v2v_unit_tests.ml @@ -778,6 +778,12 @@ let test_shell_unquote ctx = assert_equal ~printer "i`" (Utils.shell_unquote "\"i\\`\""); assert_equal ~printer "j\"" (Utils.shell_unquote "\"j\\\"\"") +let test_qemu_img_supports ctx = + (* No assertion here, we don't know if qemu-img supports the + * feature, so just run the code and make sure it doesn't crash. + *) + ignore (Utils.qemu_img_supports_offset_and_size ()) + (* Suites declaration. *) let suite = "virt-v2v" >::: @@ -788,6 +794,7 @@ let suite = "Windows_virtio.virtio_iso_path_matches_guest_os" >:: test_virtio_iso_path_matches_guest_os; "Utils.shell_unquote" >:: test_shell_unquote; + "Utils.qemu_img_supports" >:: test_qemu_img_supports; ] let () = -- 2.10.2