diff --git a/.gitignore b/.gitignore
index 35a8cbc..a588c01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.12
-SOURCES/libguestfs-1.36.3.tar.gz
+SOURCES/libguestfs-1.36.10.tar.gz
 SOURCES/libguestfs.keyring
 SOURCES/rhsrvany.exe
diff --git a/.libguestfs.metadata b/.libguestfs.metadata
index c246969..e7d2b1b 100644
--- a/.libguestfs.metadata
+++ b/.libguestfs.metadata
@@ -1,4 +1,4 @@
 8fec32284530ce6d485629fcbd1f7f3e005ae8a0 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.12
-269b49a6e6fcbc7beb287b27829cacbc35d4882b SOURCES/libguestfs-1.36.3.tar.gz
+93c94f8c614af17078b345ea3f5f5a187194cace SOURCES/libguestfs-1.36.10.tar.gz
 1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring
 2bd96e478fc004cd323b5bd754c856641877dac6 SOURCES/rhsrvany.exe
diff --git a/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch b/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch
index 24af4ae..36203e1 100644
--- a/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch
+++ b/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch
@@ -1,4 +1,4 @@
-From c1b189f662e4dccce0c3ef72a458f5eba298e949 Mon Sep 17 00:00:00 2001
+From a237b1b342e1fa7d6b0229fd9b58dad21fd07877 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 21 Dec 2012 15:50:11 +0000
 Subject: [PATCH] RHEL 7: Remove libguestfs live (RHBZ#798980).
@@ -34,5 +34,5 @@ index 8ce4ca5b4..9be2b9c5f 100644
  
  static int
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch b/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch
index 6e565ff..23a11a9 100644
--- a/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch
+++ b/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch
@@ -1,4 +1,4 @@
-From ee68d9b7941ced89bc91878f09eb528773e624db Mon Sep 17 00:00:00 2001
+From 5cb76a0fdc42cecd218b905acfd4d3ce07faf748 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 18 Jul 2013 18:31:53 +0100
 Subject: [PATCH] RHEL 7: Remove 9p APIs from RHEL (RHBZ#921710).
@@ -16,7 +16,7 @@ Subject: [PATCH] RHEL 7: Remove 9p APIs from RHEL (RHBZ#921710).
  delete mode 100644 daemon/9p.c
 
 diff --git a/Makefile.am b/Makefile.am
-index 12486deee..14b277a35 100644
+index 494892206..ffe002837 100644
 --- a/Makefile.am
 +++ b/Makefile.am
 @@ -73,7 +73,7 @@ SUBDIRS += tests/xfs
@@ -30,7 +30,7 @@ index 12486deee..14b277a35 100644
  SUBDIRS += tests/disk-labels
 diff --git a/daemon/9p.c b/daemon/9p.c
 deleted file mode 100644
-index bd564a5be..000000000
+index fc5b01736..000000000
 --- a/daemon/9p.c
 +++ /dev/null
 @@ -1,225 +0,0 @@
@@ -216,7 +216,7 @@ index bd564a5be..000000000
 -  struct stat statbuf;
 -  int r;
 -
--  ABS_PATH (mountpoint, , return -1);
+-  ABS_PATH (mountpoint, 0, return -1);
 -
 -  mp = sysroot_path (mountpoint);
 -  if (!mp) {
@@ -260,10 +260,10 @@ index bd564a5be..000000000
 -  return 0;
 -}
 diff --git a/daemon/Makefile.am b/daemon/Makefile.am
-index 9381742c8..0670cda90 100644
+index 31414653f..7aeaf7b8d 100644
 --- a/daemon/Makefile.am
 +++ b/daemon/Makefile.am
-@@ -48,7 +48,6 @@ endif
+@@ -49,7 +49,6 @@ endif
  guestfsd_SOURCES = \
  	../common/errnostring/errnostring.h \
  	../common/protocol/guestfs_protocol.h \
@@ -272,7 +272,7 @@ index 9381742c8..0670cda90 100644
  	actions.h \
  	available.c \
 diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
-index 26abcc9bb..608eaea76 100644
+index f54015de0..d7fa51cf6 100644
 --- a/docs/C_SOURCE_FILES
 +++ b/docs/C_SOURCE_FILES
 @@ -49,7 +49,6 @@ common/windows/windows.h
@@ -284,13 +284,14 @@ index 26abcc9bb..608eaea76 100644
  daemon/actions.h
  daemon/augeas.c
 diff --git a/generator/actions_core.ml b/generator/actions_core.ml
-index ed89f74aa..2567981d7 100644
+index 5e487df02..dc54d616a 100644
 --- a/generator/actions_core.ml
 +++ b/generator/actions_core.ml
-@@ -6372,27 +6372,6 @@ This returns true iff the device exists and contains all zero bytes.
+@@ -6371,27 +6371,6 @@ This returns true iff the device exists and contains all zero bytes.
+ 
  Note that for large devices this can take a long time to run." };
  
-   { defaults with
+-  { defaults with
 -    name = "list_9p"; added = (1, 11, 12);
 -    style = RStringList "mounttags", [], [];
 -    shortdesc = "list 9p filesystems";
@@ -311,10 +312,9 @@ index ed89f74aa..2567981d7 100644
 -Any other options required can be passed in the optional C<options>
 -parameter." };
 -
--  { defaults with
+   { defaults with
      name = "list_dm_devices"; added = (1, 11, 15);
      style = RStringList "devices", [], [];
-     shortdesc = "list device mapper devices";
 diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
 index b3be31996..7f92e0427 100644
 --- a/generator/proc_nr.ml
@@ -349,7 +349,7 @@ index 8fa8599d3..7a5272684 100644
    src/optargs-ntfsclone_out.c \
    src/optargs-ntfsfix.c \
 diff --git a/po/POTFILES b/po/POTFILES
-index 904e751de..143d1cd9d 100644
+index 447b2a1e3..2856b36a3 100644
 --- a/po/POTFILES
 +++ b/po/POTFILES
 @@ -39,7 +39,6 @@ customize/crypt-c.c
@@ -369,5 +369,5 @@ index 904e751de..143d1cd9d 100644
  gobject/src/optargs-ntfsclone_out.c
  gobject/src/optargs-ntfsfix.c
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch b/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch
index 26bb7ee..43b43a8 100644
--- a/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch
+++ b/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch
@@ -1,4 +1,4 @@
-From a000794c30a6c6603f000d39b6674bfb3be26037 Mon Sep 17 00:00:00 2001
+From 0b0b38041f963b36be1d2e38a7cd7743cece0722 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Mon, 29 Jul 2013 14:47:56 +0100
 Subject: [PATCH] RHEL 7: Disable unsupported remote drive protocols
@@ -23,14 +23,14 @@ We hope to gradually add some of these back over the lifetime of RHEL 7.
 In RHEL 7.2: rbd (Ceph) support was enabled.
 ---
  docs/guestfs-testing.pod               |  20 -------
- fish/guestfish.pod                     |  64 ++-------------------
+ fish/guestfish.pod                     |  66 ++--------------------
  fish/test-add-uri.sh                   |  32 -----------
  generator/actions_core.ml              |  50 +----------------
  lib/drives.c                           |   8 +++
  lib/guestfs.pod                        | 100 ---------------------------------
  tests/disks/test-qemu-drive-libvirt.sh |  28 ---------
  tests/disks/test-qemu-drive.sh         |  60 --------------------
- 8 files changed, 15 insertions(+), 347 deletions(-)
+ 8 files changed, 16 insertions(+), 348 deletions(-)
 
 diff --git a/docs/guestfs-testing.pod b/docs/guestfs-testing.pod
 index 1e88ed4df..ce64755db 100644
@@ -64,7 +64,7 @@ index 1e88ed4df..ce64755db 100644
  
  Run L<virt-alignment-scan(1)> on guests or disk images:
 diff --git a/fish/guestfish.pod b/fish/guestfish.pod
-index 3b71c3a21..cbaaca516 100644
+index feaae7f8c..a9fc8d2df 100644
 --- a/fish/guestfish.pod
 +++ b/fish/guestfish.pod
 @@ -131,9 +131,9 @@ To list what is available do:
@@ -135,7 +135,7 @@ index 3b71c3a21..cbaaca516 100644
  =head2 B<-a nbd://example.com[:port]>
  
  =head2 B<-a nbd://example.com[:port]/exportname>
-@@ -1203,28 +1169,6 @@ The equivalent API command would be:
+@@ -1203,35 +1169,13 @@ The equivalent API command would be:
  
   ><fs> add pool/disk protocol:rbd server:tcp:example.com:port
  
@@ -161,9 +161,17 @@ index 3b71c3a21..cbaaca516 100644
 -
 - ><fs> add /disk protocol:ssh server:tcp:example.com [username:user]
 -
- =head1 PROGRESS BARS
+ Note that the URIs follow the syntax of
+ L<RFC 3986|https://tools.ietf.org/html/rfc3986>: in particular, there
+ are restrictions on the allowed characters for the various components
+ of the URI.  Characters such as C<:>, C<@>, and C</> B<must> be
+ percent-encoded:
+ 
+- $ guestfish -a ssh://user:pass%40word@example.com/disk.img
++ $ guestfish -a rbd://user:pass%40word@example.com[:port]/pool/disk
+ 
+ In this case, the password is C<pass@word>.
  
- Some (not all) long-running commands send progress notification
 diff --git a/fish/test-add-uri.sh b/fish/test-add-uri.sh
 index 756df997b..8f84fd31b 100755
 --- a/fish/test-add-uri.sh
@@ -214,7 +222,7 @@ index 756df997b..8f84fd31b 100755
  rm test-add-uri.out
  rm test-add-uri.img
 diff --git a/generator/actions_core.ml b/generator/actions_core.ml
-index 2567981d7..e4b2b8c4c 100644
+index dc54d616a..ee2539c09 100644
 --- a/generator/actions_core.ml
 +++ b/generator/actions_core.ml
 @@ -522,29 +522,6 @@ F<filename> is interpreted as a local file or device.
@@ -299,7 +307,7 @@ index 2567981d7..e4b2b8c4c 100644
  example if using the libvirt backend and if the libvirt backend is configured to
  start the qemu appliance as a special user such as C<qemu.qemu>.  If in doubt,
 diff --git a/lib/drives.c b/lib/drives.c
-index 4cf41cd9b..2d86ca88a 100644
+index 509522430..d3887c148 100644
 --- a/lib/drives.c
 +++ b/lib/drives.c
 @@ -165,6 +165,7 @@ create_drive_non_file (guestfs_h *g,
@@ -485,39 +493,39 @@ index e02cda6f8..41aa7ad83 100644
  
  Libguestfs has APIs for inspecting an unknown disk image to find out
 diff --git a/tests/disks/test-qemu-drive-libvirt.sh b/tests/disks/test-qemu-drive-libvirt.sh
-index a1a7b8906..aefd7cb4a 100755
+index 3520e8a83..7671afb4a 100755
 --- a/tests/disks/test-qemu-drive-libvirt.sh
 +++ b/tests/disks/test-qemu-drive-libvirt.sh
 @@ -64,34 +64,6 @@ check_output
- grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail
+ grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail ceph2
  rm "$DEBUG_QEMU_FILE"
  
 -# Gluster.
 -
 -$guestfish -d gluster run ||:
 -check_output
--grep -sq -- '-drive file=gluster://1.2.3.4:1234/volname/image,' "$DEBUG_QEMU_FILE" || fail
+-grep -sq -- '-drive file=gluster://1.2.3.4:1234/volname/image,' "$DEBUG_QEMU_FILE" || fail gluster
 -rm "$DEBUG_QEMU_FILE"
 -
 -# iSCSI.
 -
 -$guestfish -d iscsi run ||:
 -check_output
--grep -sq -- '-drive file=iscsi://1.2.3.4:1234/iqn.2003-01.org.linux-iscsi.fedora,' "$DEBUG_QEMU_FILE" || fail
+-grep -sq -- '-drive file=iscsi://1.2.3.4:1234/iqn.2003-01.org.linux-iscsi.fedora' "$DEBUG_QEMU_FILE" || fail iscsi
 -rm "$DEBUG_QEMU_FILE"
 -
 -# NBD.
 -
 -$guestfish -d nbd run ||:
 -check_output
--grep -sq -- '-drive file=nbd:1.2.3.4:1234,' "$DEBUG_QEMU_FILE" || fail
+-grep -sq -- '-drive file=nbd:1.2.3.4:1234,' "$DEBUG_QEMU_FILE" || fail nbd
 -rm "$DEBUG_QEMU_FILE"
 -
 -# Sheepdog.
 -
 -$guestfish -d sheepdog run ||:
 -check_output
--grep -sq -- '-drive file=sheepdog:volume,' "$DEBUG_QEMU_FILE" || fail
+-grep -sq -- '-drive file=sheepdog:volume,' "$DEBUG_QEMU_FILE" || fail sheepdog
 -rm "$DEBUG_QEMU_FILE"
 -
  # Local, stored in a pool.
@@ -599,5 +607,5 @@ index 19dd60a2f..583e031bd 100755
 -grep -sq -- '-drive file=ssh://rich@example.com/disk.img,' "$DEBUG_QEMU_FILE" || fail
 -rm "$DEBUG_QEMU_FILE"
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch b/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch
index 4560d5a..f16ac1b 100644
--- a/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch
+++ b/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch
@@ -1,4 +1,4 @@
-From 07dfad456fb78bbb5c3c1342f45c48dff4db2c36 Mon Sep 17 00:00:00 2001
+From 30f46900825b5a48024220d651d12166e2d8fe92 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 19 Sep 2014 13:38:20 +0100
 Subject: [PATCH] RHEL 7: Remove User-Mode Linux (RHBZ#1144197).
@@ -9,7 +9,7 @@ This isn't supported in RHEL 7.
  1 file changed, 13 insertions(+)
 
 diff --git a/lib/launch-uml.c b/lib/launch-uml.c
-index c391af309..3033daa88 100644
+index 65745ff47..3b67f2598 100644
 --- a/lib/launch-uml.c
 +++ b/lib/launch-uml.c
 @@ -44,7 +44,9 @@ struct backend_uml_data {
@@ -22,7 +22,7 @@ index c391af309..3033daa88 100644
  
  /* Run uml_mkcow to create a COW overlay. */
  static char *
-@@ -82,6 +84,7 @@ create_cow_overlay_uml (guestfs_h *g, void *datav, struct drive *drv)
+@@ -81,6 +83,7 @@ create_cow_overlay_uml (guestfs_h *g, void *datav, struct drive *drv)
    return make_cow_overlay (g, drv->src.u.path);
  }
  
@@ -30,7 +30,7 @@ index c391af309..3033daa88 100644
  /* Test for features which are not supported by the UML backend.
   * Possibly some of these should just be warnings, not errors.
   */
-@@ -129,10 +132,17 @@ uml_supported (guestfs_h *g)
+@@ -128,10 +131,17 @@ uml_supported (guestfs_h *g)
  
    return true;
  }
@@ -48,7 +48,7 @@ index c391af309..3033daa88 100644
    struct backend_uml_data *data = datav;
    CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline);
    int console_sock = -1, daemon_sock = -1;
-@@ -486,8 +496,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg)
+@@ -491,8 +501,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg)
    }
    g->state = CONFIG;
    return -1;
@@ -59,7 +59,7 @@ index c391af309..3033daa88 100644
  /* This is called from the forked subprocess just before vmlinux runs,
   * so it can just print the message straight to stderr, where it will
   * be picked up and funnelled through the usual appliance event API.
-@@ -517,6 +529,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv)
+@@ -522,6 +534,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv)
  
    fputc ('\n', stderr);
  }
@@ -68,5 +68,5 @@ index c391af309..3033daa88 100644
  static int
  shutdown_uml (guestfs_h *g, void *datav, int check_for_errors)
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch b/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch
index f339a3e..a40ac53 100644
--- a/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch
+++ b/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch
@@ -1,4 +1,4 @@
-From 9185b9edc455e72ae44abc98b98aaef79b0a7a69 Mon Sep 17 00:00:00 2001
+From a16c5c28835dab579f7ff0c782bff4706f5efc28 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Sun, 28 Sep 2014 19:14:43 +0100
 Subject: [PATCH] RHEL 7: v2v: Select correct qemu binary for -o qemu mode
@@ -29,5 +29,5 @@ index ccdda8ad4..19757e007 100644
  let flag t k =
    assert (String.is_prefix k "-");
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch b/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch
index d569485..749237d 100644
--- a/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch
+++ b/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch
@@ -1,4 +1,4 @@
-From d4f2cb392ed4b88b14f3c3f8e08b02b5f52a9430 Mon Sep 17 00:00:00 2001
+From ba16c33451e806c58601eceec54e4c7048f398bc Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Tue, 30 Sep 2014 10:50:27 +0100
 Subject: [PATCH] RHEL 7: v2v: Disable the --qemu-boot option (RHBZ#1147313).
@@ -14,7 +14,7 @@ qemu script.
  2 files changed, 2 insertions(+), 14 deletions(-)
 
 diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
-index c294e5778..9f02098c0 100644
+index c7c7437ec..5a1ea04f3 100644
 --- a/v2v/cmdline.ml
 +++ b/v2v/cmdline.ml
 @@ -199,7 +199,6 @@ let parse_cmdline () =
@@ -25,7 +25,7 @@ index c294e5778..9f02098c0 100644
      [ L"root" ],    Getopt.String ("ask|... ", set_root_choice), s_"How to choose root filesystem";
      [ L"vdsm-compat" ], Getopt.Symbol ("0.10|1.1", ["0.10"; "1.1"], set_vdsm_compat), s_"Write qcow2 with compat=0.10|1.1";
      [ L"vdsm-image-uuid" ], Getopt.String ("uuid", add_vdsm_image_uuid), s_"Output image UUID(s)";
-@@ -403,6 +402,8 @@ read the man page virt-v2v(1).
+@@ -405,6 +404,8 @@ read the man page virt-v2v(1).
          | Some d when not (is_directory d) ->
             error (f_"-os %s: output directory does not exist or is not a directory") d
          | Some d -> d in
@@ -35,7 +35,7 @@ index c294e5778..9f02098c0 100644
        output_format, output_alloc
  
 diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
-index 838b5986f..79c742e3f 100644
+index 5d4ed9ae5..ff91e29b8 100644
 --- a/v2v/virt-v2v.pod
 +++ b/v2v/virt-v2v.pod
 @@ -145,11 +145,6 @@ Since F<guest-domain.xml> contains the path(s) to the guest disk
@@ -73,5 +73,5 @@ index 838b5986f..79c742e3f 100644
  
  =item B<--quiet>
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch b/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch
index f43ed77..fb75f80 100644
--- a/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch
+++ b/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch
@@ -1,4 +1,4 @@
-From d40e0b93a58edc9c67184e0108731556bc44b46f Mon Sep 17 00:00:00 2001
+From 4706dff15716286461c0826da9f703dc1b49177d Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 2 Oct 2014 16:44:00 +0100
 Subject: [PATCH] RHEL 7: Revert "tests: rsync: Skip this test when the backend
@@ -70,5 +70,5 @@ index c6d98cfd1..246396276 100755
  
  guestfish --network -N test-rsync.img=fs -m /dev/sda1 <<EOF
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0008-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch b/SOURCES/0008-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch
index 376de4e..1f25364 100644
--- a/SOURCES/0008-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch
+++ b/SOURCES/0008-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch
@@ -1,4 +1,4 @@
-From c8cb6c1ff5e9ac311fcbbacfb3e3f3035394117f Mon Sep 17 00:00:00 2001
+From a46f806126a9ab8240194f3637665365fea278b2 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 2 Oct 2014 16:44:04 +0100
 Subject: [PATCH] RHEL 7: Revert "appliance: Change example ping lines to ping
@@ -10,10 +10,10 @@ This reverts commit 07c0926b588db5c86214917b609c2f477c817c0e.
  1 file changed, 2 insertions(+), 1 deletion(-)
 
 diff --git a/appliance/init b/appliance/init
-index 8a26e1a02..624e20fa6 100755
+index 59b5c4955..c6a269dd1 100755
 --- a/appliance/init
 +++ b/appliance/init
-@@ -154,7 +154,8 @@ if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then
+@@ -157,7 +157,8 @@ if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then
      date
      echo -n "clocksource: "
      cat /sys/devices/system/clocksource/clocksource0/current_clocksource
@@ -24,5 +24,5 @@ index 8a26e1a02..624e20fa6 100755
      echo -n "uptime: "; cat /proc/uptime
  fi
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch b/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch
index ab14e8b..4ab9832 100644
--- a/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch
+++ b/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch
@@ -1,4 +1,4 @@
-From 706ec2c841cda0de58a52001b1567d2b72fdacdf Mon Sep 17 00:00:00 2001
+From 5a411a67cf166eb44b8f88858eabaa80d6a0d504 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 2 Oct 2014 16:44:07 +0100
 Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Use qemu-bridge-helper to
@@ -32,7 +32,7 @@ index 41aa7ad83..6443e3bae 100644
  
  I<Note (1):> This is B<highly experimental> and has a tendency to eat
 diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
-index 168bba6ac..bc5d4d215 100644
+index 4ddf9b87f..def9cfe07 100644
 --- a/lib/launch-libvirt.c
 +++ b/lib/launch-libvirt.c
 @@ -115,7 +115,6 @@ struct backend_libvirt_data {
@@ -43,7 +43,7 @@ index 168bba6ac..bc5d4d215 100644
    char name[DOMAIN_NAME_LEN];   /* random name */
    bool is_kvm;                  /* false = qemu, true = kvm (from capabilities)*/
    struct version libvirt_version; /* libvirt version */
-@@ -436,12 +435,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
+@@ -435,12 +434,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
      guestfs_get_backend_setting (g, "internal_libvirt_imagelabel");
    data->selinux_norelabel_disks =
      guestfs_int_get_backend_setting_bool (g, "internal_libvirt_norelabel_disks");
@@ -56,7 +56,7 @@ index 168bba6ac..bc5d4d215 100644
    guestfs_pop_error_handler (g);
  
    if (g->enable_network && check_bridge_exists (g, data->network_bridge) == -1)
-@@ -1384,19 +1377,6 @@ construct_libvirt_xml_devices (guestfs_h *g,
+@@ -1383,19 +1376,6 @@ construct_libvirt_xml_devices (guestfs_h *g,
        } end_element ();
      } end_element ();
  
@@ -76,7 +76,7 @@ index 168bba6ac..bc5d4d215 100644
      /* Libvirt adds some devices by default.  Indicate to libvirt
       * that we don't want them.
       */
-@@ -1771,6 +1751,27 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g,
+@@ -1793,6 +1773,27 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g,
        attribute ("value", tmpdir);
      } end_element ();
  
@@ -104,7 +104,7 @@ index 168bba6ac..bc5d4d215 100644
      /* The qemu command line arguments requested by the caller. */
      for (hp = g->hv_params; hp; hp = hp->next) {
        start_element ("qemu:arg") {
-@@ -2096,9 +2097,6 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
+@@ -2118,9 +2119,6 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
    free (data->selinux_imagelabel);
    data->selinux_imagelabel = NULL;
  
@@ -115,5 +115,5 @@ index 168bba6ac..bc5d4d215 100644
      free (data->secrets[i].secret);
    free (data->secrets);
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch b/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch
index 66b876a..85929df 100644
--- a/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch
+++ b/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch
@@ -1,4 +1,4 @@
-From 39c453f02083fa1b17a826a3b44b3405b601d792 Mon Sep 17 00:00:00 2001
+From f725f168ec3019da2332e5cae91a518a7897f8ff Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Mon, 21 Sep 2015 12:38:50 -0400
 Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Better error when bridge /
@@ -10,7 +10,7 @@ This reverts commit edcd02a965ae6675c0ee9ecd8d98a1a641c6ef60.
  1 file changed, 47 deletions(-)
 
 diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
-index bc5d4d215..0c2879dbf 100644
+index def9cfe07..681281b9b 100644
 --- a/lib/launch-libvirt.c
 +++ b/lib/launch-libvirt.c
 @@ -155,7 +155,6 @@ static int is_blk (const char *path);
@@ -21,7 +21,7 @@ index bc5d4d215..0c2879dbf 100644
  
  #if HAVE_LIBSELINUX
  static void selinux_warning (guestfs_h *g, const char *func, const char *selinux_op, const char *data);
-@@ -437,9 +436,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
+@@ -436,9 +435,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
      guestfs_int_get_backend_setting_bool (g, "internal_libvirt_norelabel_disks");
    guestfs_pop_error_handler (g);
  
@@ -31,7 +31,7 @@ index bc5d4d215..0c2879dbf 100644
    /* Locate and/or build the appliance. */
    TRACE0 (launch_build_libvirt_appliance_start);
  
-@@ -2009,49 +2005,6 @@ is_blk (const char *path)
+@@ -2031,49 +2027,6 @@ is_blk (const char *path)
    return S_ISBLK (statbuf.st_mode);
  }
  
@@ -82,5 +82,5 @@ index bc5d4d215..0c2879dbf 100644
  ignore_errors (void *ignore, virErrorPtr ignore2)
  {
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch b/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch
index c41dea0..105081b 100644
--- a/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch
+++ b/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch
@@ -1,4 +1,4 @@
-From 8d2911ce34aca7ba67c9921fb8cb9207e2215fa8 Mon Sep 17 00:00:00 2001
+From 88dc95888f15c353581d0e9779d654935d9e820b Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 10 Oct 2014 17:45:39 +0100
 Subject: [PATCH] RHEL 7: Revert "appliance: add dhcp-client on Mageia"
@@ -9,10 +9,10 @@ This reverts commit 8f3a2ca5358d5601be7a9247b6d08193c4e2da46.
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/appliance/packagelist.in b/appliance/packagelist.in
-index 8ed3afedc..0477bfc55 100644
+index a2f6107b8..8a71f6e98 100644
 --- a/appliance/packagelist.in
 +++ b/appliance/packagelist.in
-@@ -188,7 +188,7 @@ ifelse(MAGEIA,1,
+@@ -189,7 +189,7 @@ ifelse(MAGEIA,1,
    chkconfig /* for /etc/init.d */
    cdrkit-genisoimage
    cdrkit-isotools
@@ -22,5 +22,5 @@ index 8ed3afedc..0477bfc55 100644
    gfs2-utils
    grub
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch b/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch
index 9445d49..50f5a2c 100644
--- a/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch
+++ b/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch
@@ -1,4 +1,4 @@
-From b70a988f7ecc6c446d88c1172332fe7c3c74dec3 Mon Sep 17 00:00:00 2001
+From b7640b6a60366d615f2b7bd24ed923a3c6c2eddb Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 10 Oct 2014 17:45:48 +0100
 Subject: [PATCH] RHEL 7: Revert "appliance: add dhcpcd and gptfdisk on
@@ -10,7 +10,7 @@ This reverts commit 979e7a49147f4ef1387337db262bf7ea12f627e3.
  1 file changed, 1 insertion(+), 2 deletions(-)
 
 diff --git a/appliance/packagelist.in b/appliance/packagelist.in
-index 0477bfc55..961a2a3b1 100644
+index 8a71f6e98..e088ace30 100644
 --- a/appliance/packagelist.in
 +++ b/appliance/packagelist.in
 @@ -105,8 +105,7 @@ ifelse(ARCHLINUX,1,
@@ -24,5 +24,5 @@ index 0477bfc55..961a2a3b1 100644
    hivex
    iproute2
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch b/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch
index e378ecd..5e69636 100644
--- a/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch
+++ b/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch
@@ -1,4 +1,4 @@
-From 1b565df653cff8421e7af40728e27c79d563d474 Mon Sep 17 00:00:00 2001
+From 169f16907f701d7d6eaf157eff0141bdf3632760 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 10 Oct 2014 17:46:02 +0100
 Subject: [PATCH] RHEL 7: Revert "appliance: Use dhclient or dhcpcd instead of
@@ -11,10 +11,10 @@ This reverts commit 67e6f32a240c7c234e6af637c1cd324b36a82cd3.
  2 files changed, 6 insertions(+), 16 deletions(-)
 
 diff --git a/appliance/init b/appliance/init
-index 624e20fa6..2e18be4fe 100755
+index c6a269dd1..2c9aecd5f 100755
 --- a/appliance/init
 +++ b/appliance/init
-@@ -118,15 +118,12 @@ shopt -u nullglob
+@@ -120,15 +120,12 @@ shopt -u nullglob
  ip addr add 127.0.0.1/8 brd + dev lo scope host
  ip link set dev lo up
  
@@ -37,7 +37,7 @@ index 624e20fa6..2e18be4fe 100755
  # Scan for MDs.
  mdadm -As --auto=yes --run
 diff --git a/appliance/packagelist.in b/appliance/packagelist.in
-index 961a2a3b1..b437b02e0 100644
+index e088ace30..8019af158 100644
 --- a/appliance/packagelist.in
 +++ b/appliance/packagelist.in
 @@ -26,7 +26,6 @@ ifelse(REDHAT,1,
@@ -64,16 +64,16 @@ index 961a2a3b1..b437b02e0 100644
    grub
    hivex
    iproute2
-@@ -133,8 +130,6 @@ ifelse(SUSE,1,
-   augeas-lenses
+@@ -134,8 +131,6 @@ ifelse(SUSE,1,
    btrfsprogs
+   cdrkit-cdrtools-compat
    cryptsetup
 -  dhcpcd
 -  dhcp-client
    genisoimage
    glibc-locale
    gptfdisk
-@@ -160,7 +155,6 @@ ifelse(FRUGALWARE,1,
+@@ -161,7 +156,6 @@ ifelse(FRUGALWARE,1,
    augeas
    cryptsetup-luks
    cdrkit
@@ -81,7 +81,7 @@ index 961a2a3b1..b437b02e0 100644
    grub2
    hfsplus
    iproute2
-@@ -187,7 +181,6 @@ ifelse(MAGEIA,1,
+@@ -188,7 +182,6 @@ ifelse(MAGEIA,1,
    chkconfig /* for /etc/init.d */
    cdrkit-genisoimage
    cdrkit-isotools
@@ -90,5 +90,5 @@ index 961a2a3b1..b437b02e0 100644
    gfs2-utils
    grub
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch b/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch
index f19674b..be866fb 100644
--- a/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch
+++ b/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch
@@ -1,4 +1,4 @@
-From 08a8b9cf677d1c21890e14fcb34f49bf0800e912 Mon Sep 17 00:00:00 2001
+From 060fa25dd5046c3b6cea8c0d2c55ac9607042e9c Mon Sep 17 00:00:00 2001
 From: Pino Toscano <ptoscano@redhat.com>
 Date: Fri, 24 Oct 2014 16:33:50 +0100
 Subject: [PATCH] RHEL 7: Disable alternate Augeas lenses.
@@ -9,20 +9,18 @@ not required in RHEL.
 See:
 https://www.redhat.com/archives/libguestfs/2014-October/msg00220.html
 ---
- appliance/Makefile.am | 2 --
+ appliance/Makefile.am | 1 -
  daemon/augeas.c       | 5 ++++-
- daemon/lvm-filter.c   | 4 ++--
- 3 files changed, 6 insertions(+), 5 deletions(-)
+ 2 files changed, 4 insertions(+), 2 deletions(-)
 
 diff --git a/appliance/Makefile.am b/appliance/Makefile.am
-index 05b9d42e9..1e142cbd0 100644
+index 42896b9a7..6cc147a18 100644
 --- a/appliance/Makefile.am
 +++ b/appliance/Makefile.am
-@@ -92,8 +92,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_lvm_conf.aug guestfs_shadow
+@@ -91,7 +91,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_shadow.aug
  	rm -rf tmp-d
  	mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc tmp-d/usr/share/guestfs
  	ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd
--	ln $(srcdir)/guestfs_lvm_conf.aug tmp-d/usr/share/guestfs/guestfs_lvm_conf.aug
 -	ln $(srcdir)/guestfs_shadow.aug tmp-d/usr/share/guestfs/guestfs_shadow.aug
  	( cd tmp-d && tar zcf - * ) > $@-t
  	rm -r tmp-d
@@ -57,28 +55,6 @@ index 5adc959a5..dc5266ee4 100644
  
    return 0;
  }
-diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c
-index 5c9ce1866..bd32626e6 100644
---- a/daemon/lvm-filter.c
-+++ b/daemon/lvm-filter.c
-@@ -140,7 +140,7 @@ set_filter (char *const *filters)
-    * but do that only after having applied the transformation.
-    */
-   const int flags = AUG_NO_ERR_CLOSE | AUG_NO_LOAD;
--  aug = aug_init (lvm_system_dir, "/usr/share/guestfs/", flags);
-+  aug = aug_init (lvm_system_dir, NULL, flags);
-   if (!aug) {
-     reply_with_error ("augeas initialization failed");
-     return -1;
-@@ -151,7 +151,7 @@ set_filter (char *const *filters)
-     return -1;
-   }
- 
--  r = aug_transform (aug, "guestfs_lvm_conf", "/lvm/lvm.conf",
-+  r = aug_transform (aug, "lvm", "/lvm/lvm.conf",
-                      0 /* = included */);
-   if (r == -1) {
-     AUGEAS_ERROR ("aug_transform");
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch b/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch
index 9ef5daf..656fd9f 100644
--- a/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch
+++ b/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch
@@ -1,4 +1,4 @@
-From 53e3905783593eaa4a06ea3ee416e9dc1da3a60a Mon Sep 17 00:00:00 2001
+From fcc0b3562ac001eaa93d216dcdf567108d96b8b8 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 24 Apr 2015 09:45:41 -0400
 Subject: [PATCH] RHEL 7: Fix list of supported sound cards to match RHEL qemu
@@ -9,7 +9,7 @@ Subject: [PATCH] RHEL 7: Fix list of supported sound cards to match RHEL qemu
  1 file changed, 3 insertions(+), 2 deletions(-)
 
 diff --git a/v2v/utils.ml b/v2v/utils.ml
-index e53f9fe0a..8f1053ec9 100644
+index 56a35c7b9..d72dc3477 100644
 --- a/v2v/utils.ml
 +++ b/v2v/utils.ml
 @@ -40,13 +40,14 @@ let kvm_arch = function
@@ -30,5 +30,5 @@ index e53f9fe0a..8f1053ec9 100644
  (* Find the UEFI firmware. *)
  let find_uefi_firmware guest_arch =
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch b/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch
index 930b2a5..cb3e179 100644
--- a/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch
+++ b/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch
@@ -1,4 +1,4 @@
-From 8fb7f81181a566fac5ee572ee630946294f735ff Mon Sep 17 00:00:00 2001
+From 6e6a8a32ab3c3ff33897a6883632a8887c7b508e Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 30 Apr 2015 17:20:26 -0400
 Subject: [PATCH] RHEL 7: v2v: efi: Remove references to Fedora / kraxel's OVMF
@@ -6,8 +6,8 @@ Subject: [PATCH] RHEL 7: v2v: efi: Remove references to Fedora / kraxel's OVMF
 
 ---
  generator/UEFI.ml | 6 ------
- v2v/utils.ml      | 3 +--
- 2 files changed, 1 insertion(+), 8 deletions(-)
+ v2v/utils.ml      | 1 -
+ 2 files changed, 7 deletions(-)
 
 diff --git a/generator/UEFI.ml b/generator/UEFI.ml
 index 95797aad9..881009cfb 100644
@@ -27,7 +27,7 @@ index 95797aad9..881009cfb 100644
      "/usr/share/OVMF/OVMF_CODE.fd",
      None,
 diff --git a/v2v/utils.ml b/v2v/utils.ml
-index 8f1053ec9..212c8a0a0 100644
+index d72dc3477..2061eea61 100644
 --- a/v2v/utils.ml
 +++ b/v2v/utils.ml
 @@ -54,7 +54,6 @@ let find_uefi_firmware guest_arch =
@@ -38,15 +38,6 @@ index 8f1053ec9..212c8a0a0 100644
      | "x86_64" -> Uefi.uefi_x86_64_firmware
      | "aarch64" -> Uefi.uefi_aarch64_firmware
      | arch ->
-@@ -62,7 +61,7 @@ let find_uefi_firmware guest_arch =
-              guest_arch in
-   let rec loop = function
-     | [] ->
--       error (f_"cannot find firmware for UEFI guests.\n\nYou probably need to install OVMF, or Gerd's firmware repo (https://www.kraxel.org/repos/), or AAVMF (if using aarch64)")
-+       error (f_"cannot find firmware for UEFI guests.\n\nYou probably need to install OVMF, or AAVMF (if using aarch64)")
-     | ({ Uefi.code = code; vars = vars_template } as ret) :: rest ->
-        if Sys.file_exists code && Sys.file_exists vars_template then ret
-        else loop rest
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch b/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch
index 399c924..92b2d72 100644
--- a/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch
+++ b/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch
@@ -1,4 +1,4 @@
-From 0c01f7c2c9acb1336d996df65acddb33c2dc0181 Mon Sep 17 00:00:00 2001
+From 7246417f3ba33616846d3c3f3ec097e1b9692de7 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Tue, 7 Jul 2015 09:28:03 -0400
 Subject: [PATCH] RHEL 7: Reject use of libguestfs-winsupport features except
@@ -43,5 +43,5 @@ index 606c89807..bba57c56f 100644
       * as a progress bar hint.
       *)
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch b/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch
index 59dd738..c010fa4 100644
--- a/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch
+++ b/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch
@@ -1,4 +1,4 @@
-From 006717a7f2c939fd99154d0b7af6447c30ef7ec1 Mon Sep 17 00:00:00 2001
+From 5cd87d524afba59a3916f4c953a4e4b6bccf8c04 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 23 Jul 2015 18:15:36 -0400
 Subject: [PATCH] RHEL 7: daemon: umount-all: Hack to avoid umount: /sysroot:
@@ -13,7 +13,7 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1246032
  1 file changed, 5 insertions(+)
 
 diff --git a/daemon/mount.c b/daemon/mount.c
-index f2aedfd11..14b24bff9 100644
+index 0ad9626a7..b44753441 100644
 --- a/daemon/mount.c
 +++ b/daemon/mount.c
 @@ -28,6 +28,8 @@
@@ -36,5 +36,5 @@ index f2aedfd11..14b24bff9 100644
    for (i = 0; i < mounts.size; ++i) {
      CLEANUP_FREE char *err = NULL;
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch b/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch
index 875a270..24c4f22 100644
--- a/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch
+++ b/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch
@@ -1,4 +1,4 @@
-From 93d34d8282b48c737fe2e1e749dfa916086b15c9 Mon Sep 17 00:00:00 2001
+From 00ff00aa5a5ce998bd3cfe0457ace9f783e2e3ae Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Sun, 30 Aug 2015 03:21:57 -0400
 Subject: [PATCH] RHEL 7: Fix tests for libguestfs-winsupport 7.2.
@@ -89,5 +89,5 @@ index f1da222a9..ff94fe39b 100755
  
  # We also update the Registry several times, for firstboot, and (ONLY
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch b/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch
index 725e320..abba042 100644
--- a/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch
+++ b/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch
@@ -1,4 +1,4 @@
-From db662b2d47088d792bb158103719ac07dfc8e3e0 Mon Sep 17 00:00:00 2001
+From 6af2d1ad18bfd41491c3415be64712b0f842b920 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Mon, 21 Sep 2015 15:49:17 +0100
 Subject: [PATCH] RHEL 7: Revert "v2v: Add a support matrix to the manual
@@ -10,7 +10,7 @@ This reverts commit a03bffa15a5357d5d0244595caf99607be1ec3ab.
  1 file changed, 97 deletions(-)
 
 diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
-index 79c742e3f..fca0a2a93 100644
+index ff91e29b8..5bef6ae8a 100644
 --- a/v2v/virt-v2v.pod
 +++ b/v2v/virt-v2v.pod
 @@ -145,103 +145,6 @@ Since F<guest-domain.xml> contains the path(s) to the guest disk
@@ -98,7 +98,7 @@ index 79c742e3f..fca0a2a93 100644
 -
 -=item Ubuntu 10.04, 12.04, 14.04, 16.04, and up
 -
--=item Windows XP to Windows 8.1 / Windows Server 2012 R2
+-=item Windows XP to Windows 10 / Windows Server 2016
 -
 -We use Windows internal version numbers, see
 -L<https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions>
@@ -118,5 +118,5 @@ index 79c742e3f..fca0a2a93 100644
  
  =over 4
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch b/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch
index b01c0c2..eed5ec0 100644
--- a/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch
+++ b/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch
@@ -1,4 +1,4 @@
-From 1995428106fe0e14832e0b0d07e5b71740b193a4 Mon Sep 17 00:00:00 2001
+From ef6ad315f02830f04a467cd32be09e2b25ce3824 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Wed, 27 May 2015 10:03:00 -0400
 Subject: [PATCH] RHEL 7: All qemu-kvm in RHEL 7 supports discard of qcow2
@@ -12,10 +12,10 @@ For rationale behind this, see:
  1 file changed, 2 insertions(+), 10 deletions(-)
 
 diff --git a/lib/qemu.c b/lib/qemu.c
-index d60692f0d..6bb54b70d 100644
+index a5278129c..c9debe937 100644
 --- a/lib/qemu.c
 +++ b/lib/qemu.c
-@@ -610,10 +610,6 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv,
+@@ -963,10 +963,6 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv,
     * discard option on -drive at all.
     */
    bool qemu15 = guestfs_int_version_ge (qemu_version, 1, 5, 0);
@@ -26,7 +26,7 @@ index d60692f0d..6bb54b70d 100644
  
    if (!qemu15)
      NOT_SUPPORTED (g, false,
-@@ -638,12 +634,8 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv,
+@@ -991,12 +987,8 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv,
    }
    else if (STREQ (drv->src.format, "raw"))
      /* OK */ ;
@@ -42,5 +42,5 @@ index d60692f0d..6bb54b70d 100644
      /* It's possible in future other formats will support discard, but
       * currently (qemu 1.7) none of them do.
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch b/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch
index edf48ec..4bb5241 100644
--- a/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch
+++ b/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch
@@ -1,4 +1,4 @@
-From ec0693476e8459771fa74cb820b7f9f89a6ba915 Mon Sep 17 00:00:00 2001
+From 6af62afc2e3287b1c87908f300167aeffac6017a Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Mon, 21 Sep 2015 13:12:43 -0400
 Subject: [PATCH] RHEL 7: tests: Disable daemon tests that require the 'unix'
@@ -24,5 +24,5 @@ index 053cad3e1..0d723fee4 100644
  TESTS_ENVIRONMENT = $(top_builddir)/run --test
  
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch b/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch
index 27e1379..89e3131 100644
--- a/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch
+++ b/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch
@@ -1,4 +1,4 @@
-From c299f3e835dd3480960df3ea941099a43f399b96 Mon Sep 17 00:00:00 2001
+From 56aa0b649b144e78e791e134ee33422c273a8f22 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 14 Jan 2016 11:53:42 -0500
 Subject: [PATCH] RHEL 7: v2v: Disable the virt-v2v --in-place option.
@@ -36,7 +36,7 @@ index 133a411bc..297406496 100644
  	test-v2v-networks-and-bridges-expected.xml \
  	test-v2v-networks-and-bridges.sh \
 diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
-index 9f02098c0..9aecb5cd6 100644
+index 5a1ea04f3..3e3d5c312 100644
 --- a/v2v/cmdline.ml
 +++ b/v2v/cmdline.ml
 @@ -179,7 +179,7 @@ let parse_cmdline () =
@@ -48,7 +48,7 @@ index 9f02098c0..9aecb5cd6 100644
      [ L"machine-readable" ], Getopt.Set machine_readable, s_"Make output machine readable";
      [ S 'n'; L"network" ],        Getopt.String ("in:out", add_network),    s_"Map network 'in' to 'out'";
      [ L"no-copy" ], Getopt.Clear do_copy,         s_"Just write the metadata";
-@@ -333,6 +333,10 @@ read the man page virt-v2v(1).
+@@ -335,6 +335,10 @@ read the man page virt-v2v(1).
            error (f_"expecting an OVA file name on the command line") in
        Input_ova.input_ova filename in
  
@@ -184,7 +184,7 @@ index 6f7d78f39..000000000
 -# Clean up.
 -rm -r $d
 diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
-index fca0a2a93..c45828b58 100644
+index 5bef6ae8a..1c866e773 100644
 --- a/v2v/virt-v2v.pod
 +++ b/v2v/virt-v2v.pod
 @@ -15,8 +15,6 @@ virt-v2v - Convert a guest to use KVM
@@ -227,7 +227,7 @@ index fca0a2a93..c45828b58 100644
  =item B<--machine-readable>
  
  This option is used to make the output more machine friendly
-@@ -1632,7 +1613,7 @@ Minimum free space: 10 MB
+@@ -1657,7 +1638,7 @@ Minimum free space: 10 MB
  =head2 Minimum free space check in the host
  
  You must have sufficient free space in the host directory used to
@@ -236,7 +236,7 @@ index fca0a2a93..c45828b58 100644
  which directory this is, use:
  
   $ df -h "`guestfish get-cachedir`"
-@@ -1750,31 +1731,6 @@ that instead.
+@@ -1789,31 +1770,6 @@ that instead.
     </devices>
   </domain>
  
@@ -269,5 +269,5 @@ index fca0a2a93..c45828b58 100644
  
  The I<--machine-readable> option can be used to make the output more
 -- 
-2.13.4
+2.14.3
 
diff --git a/SOURCES/0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch b/SOURCES/0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch
deleted file mode 100644
index 8d9744d..0000000
--- a/SOURCES/0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From c04a77d09ad5b0a5238681f6e2b9b485f44f1599 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 23 Jun 2016 10:38:47 -0400
-Subject: [PATCH] RHEL 7: v2v: Remove --dcpath option (RHBZ#1315237,
- RHBZ#1429430)
-
-This is no longer required, since RHEL 7.3.
----
- v2v/cmdline.ml       |  2 +-
- v2v/test-v2v-docs.sh |  2 +-
- v2v/virt-v2v.pod     | 13 -------------
- 3 files changed, 2 insertions(+), 15 deletions(-)
-
-diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
-index 9aecb5cd6..a2f132b6c 100644
---- a/v2v/cmdline.ml
-+++ b/v2v/cmdline.ml
-@@ -172,7 +172,7 @@ let parse_cmdline () =
-     [ S 'b'; L"bridge" ],        Getopt.String ("in:out", add_bridge),     s_"Map bridge 'in' to 'out'";
-     [ L"compressed" ], Getopt.Set compressed,     s_"Compress output file";
-     [ L"dcpath"; L"dcPath" ],  Getopt.String ("path", set_string_option_once "--dcpath" dcpath),
--                                            s_"Override dcPath (for vCenter)";
-+                                            "";
-     [ L"debug-overlay"; L"debug-overlays" ], Getopt.Set debug_overlays, s_"Save overlay files";
-     [ S 'i' ],        Getopt.String (i_options, set_input_mode), s_"Set input mode (default: libvirt)";
-     [ M"ic" ],       Getopt.String ("uri", set_string_option_once "-ic" input_conn),
-diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh
-index c5d98de7f..02750faf3 100755
---- a/v2v/test-v2v-docs.sh
-+++ b/v2v/test-v2v-docs.sh
-@@ -22,4 +22,4 @@ $TEST_FUNCTIONS
- skip_if_skipped
- 
- $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \
--  --ignore=--dcPath,--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
-+  --ignore=--dcpath,--dcPath,--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
-diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
-index c45828b58..f4def737a 100644
---- a/v2v/virt-v2v.pod
-+++ b/v2v/virt-v2v.pod
-@@ -169,19 +169,6 @@ Write a compressed output file.  This is only allowed if the output
- format is qcow2 (see I<-of> below), and is equivalent to the I<-c>
- option of L<qemu-img(1)>.
- 
--=item B<--dcpath> Folder/Datacenter
--
--B<NB:> You don't need to use this parameter if you have
--S<libvirt E<ge> 1.2.20>.
--
--For VMware vCenter, override the C<dcPath=...> parameter used to
--select the datacenter.  Virt-v2v can usually calculate this from the
--C<vpx://> URI, but if it gets it wrong, then you can override it using
--this setting.  Go to your vCenter web folder interface, eg.
--C<https://vcenter.example.com/folder> (I<without> a trailing slash),
--and examine the C<dcPath=> parameter in the URLs that appear on this
--page.
--
- =item B<--debug-overlays>
- 
- Save the overlay file(s) created during conversion.  This option is
--- 
-2.13.4
-
diff --git a/SOURCES/0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/SOURCES/0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch
new file mode 100644
index 0000000..3e457c0
--- /dev/null
+++ b/SOURCES/0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch
@@ -0,0 +1,26 @@
+From f1905ec2781ed29bebbb2b6311d8c82261c09a88 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 2 Mar 2017 14:21:37 +0100
+Subject: [PATCH] RHEL 7: v2v: -i disk: force VNC as display (RHBZ#1372671)
+
+The SDL output mode is not supported in RHEL 7's qemu-kvm.
+---
+ v2v/input_disk.ml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml
+index 27f855352..1f319a487 100644
+--- a/v2v/input_disk.ml
++++ b/v2v/input_disk.ml
+@@ -83,7 +83,7 @@ class input_disk input_format disk = object
+       s_features = [ "acpi"; "apic"; "pae" ];
+       s_firmware = UnknownFirmware;       (* causes virt-v2v to autodetect *)
+       s_display =
+-        Some { s_display_type = Window; s_keymap = None; s_password = None;
++        Some { s_display_type = VNC; s_keymap = None; s_password = None;
+                s_listen = LNoListen; s_port = None };
+       s_video = None;
+       s_sound = None;
+-- 
+2.14.3
+
diff --git a/SOURCES/0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch b/SOURCES/0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch
new file mode 100644
index 0000000..57abe79
--- /dev/null
+++ b/SOURCES/0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch
@@ -0,0 +1,27 @@
+From fa0f50b8a18a1265b3876de50fb720247e980ceb Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Wed, 8 Mar 2017 11:03:40 +0100
+Subject: [PATCH] RHEL 7: v2v: do not mention SUSE Xen hosts (RHBZ#1430203)
+
+They are not supported in RHEL 7.
+---
+ v2v/virt-v2v.pod | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 1c866e773..709075fba 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -1194,8 +1194,7 @@ Remove the F<guest.xml> and F<guest-disk*> files.
+ 
+ =head1 INPUT FROM XEN
+ 
+-Virt-v2v is able to import Xen guests from RHEL 5 Xen or SLES and
+-openSUSE Xen hosts.
++Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts.
+ 
+ Virt-v2v uses libvirt for access to the remote Xen host, and therefore
+ the input mode should be I<-i libvirt>.  As this is the default, you
+-- 
+2.14.3
+
diff --git a/SOURCES/0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/SOURCES/0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch
deleted file mode 100644
index 1abb7fb..0000000
--- a/SOURCES/0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From ba326a8e1e0258a4254d1304f3c7447e996e3dc4 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 2 Mar 2017 14:21:37 +0100
-Subject: [PATCH] RHEL 7: v2v: -i disk: force VNC as display (RHBZ#1372671)
-
-The SDL output mode is not supported in RHEL 7's qemu-kvm.
----
- v2v/input_disk.ml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml
-index 27f855352..1f319a487 100644
---- a/v2v/input_disk.ml
-+++ b/v2v/input_disk.ml
-@@ -83,7 +83,7 @@ class input_disk input_format disk = object
-       s_features = [ "acpi"; "apic"; "pae" ];
-       s_firmware = UnknownFirmware;       (* causes virt-v2v to autodetect *)
-       s_display =
--        Some { s_display_type = Window; s_keymap = None; s_password = None;
-+        Some { s_display_type = VNC; s_keymap = None; s_password = None;
-                s_listen = LNoListen; s_port = None };
-       s_video = None;
-       s_sound = None;
--- 
-2.13.4
-
diff --git a/SOURCES/0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch b/SOURCES/0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch
deleted file mode 100644
index 459fe6d..0000000
--- a/SOURCES/0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 6a753511ad8624efd71529aae0644b84ca0336f6 Mon Sep 17 00:00:00 2001
-From: Pino Toscano <ptoscano@redhat.com>
-Date: Wed, 8 Mar 2017 11:03:40 +0100
-Subject: [PATCH] RHEL 7: v2v: do not mention SUSE Xen hosts (RHBZ#1430203)
-
-They are not supported in RHEL 7.
----
- v2v/virt-v2v.pod | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
-index f4def737a..7ad674d43 100644
---- a/v2v/virt-v2v.pod
-+++ b/v2v/virt-v2v.pod
-@@ -1178,8 +1178,7 @@ Remove the F<guest.xml> and F<guest-disk*> files.
- 
- =head1 INPUT FROM XEN
- 
--Virt-v2v is able to import Xen guests from RHEL 5 Xen or SLES and
--openSUSE Xen hosts.
-+Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts.
- 
- Virt-v2v uses libvirt for access to the remote Xen host, and therefore
- the input mode should be I<-i libvirt>.  As this is the default, you
--- 
-2.13.4
-
diff --git a/SOURCES/0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch b/SOURCES/0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch
new file mode 100644
index 0000000..e92d14d
--- /dev/null
+++ b/SOURCES/0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch
@@ -0,0 +1,42 @@
+From 563085e246220a3e7e88309f82d2edf71cd3db5a Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 28 Feb 2017 15:48:18 +0000
+Subject: [PATCH] sysprep: Remove DHCP_HOSTNAME= from ifcfg-* files
+ (RHBZ#1427529).
+
+(cherry picked from commit 0f99537cb69c88f7ceb6c69a9d9ae10baaaa3623)
+---
+ sysprep/sysprep_operation_net_hostname.ml | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/sysprep/sysprep_operation_net_hostname.ml b/sysprep/sysprep_operation_net_hostname.ml
+index 3824d42ae..7284d630f 100644
+--- a/sysprep/sysprep_operation_net_hostname.ml
++++ b/sysprep/sysprep_operation_net_hostname.ml
+@@ -30,10 +30,12 @@ let net_hostname_perform (g : Guestfs.guestfs) root side_effects =
+     let filenames = g#glob_expand "/etc/sysconfig/network-scripts/ifcfg-*" in
+     Array.iter (
+       fun filename ->
+-        (* Replace HOSTNAME=... entry. *)
++        (* Remove HOSTNAME=... and DHCP_HOSTNAME=... entries. *)
+         let lines = Array.to_list (g#read_lines filename) in
+         let lines = List.filter (
+-          fun line -> not (String.is_prefix line "HOSTNAME=")
++          fun line ->
++            not (String.is_prefix line "HOSTNAME=") &&
++            not (String.is_prefix line "DHCP_HOSTNAME=")
+         ) lines in
+         let file = String.concat "\n" lines ^ "\n" in
+         g#write filename file;
+@@ -46,7 +48,7 @@ let op = {
+   defaults with
+     name = "net-hostname";
+     enabled_by_default = true;
+-    heading = s_"Remove HOSTNAME in network interface configuration";
++    heading = s_"Remove HOSTNAME and DHCP_HOSTNAME in network interface configuration";
+     pod_description = Some (s_"\
+ For Fedora and Red Hat Enterprise Linux,
+ this is removed from C<ifcfg-*> files.");
+-- 
+2.14.3
+
diff --git a/SOURCES/0027-p2v-Run-fewer-scp-commands.patch b/SOURCES/0027-p2v-Run-fewer-scp-commands.patch
new file mode 100644
index 0000000..bcd0172
--- /dev/null
+++ b/SOURCES/0027-p2v-Run-fewer-scp-commands.patch
@@ -0,0 +1,134 @@
+From 847f9845085f76be8a00eba10fd995fe5e25ea21 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 30 Mar 2017 13:13:03 +0100
+Subject: [PATCH] p2v: Run fewer 'scp' commands.
+
+Each scp command takes a considerable amount of time -- several
+seconds -- because it must set up, authenticate and tear down a new
+connection.  Avoid this by combining several copies into a single
+command.
+
+We still have to use two scp commands because we want to check that
+some files are copied and ignore failures in a second set of
+informational files.
+
+(cherry picked from commit d178deeeb814471b9d70431626b6cd515a21d0c1)
+---
+ p2v/conversion.c | 31 +++++++++++--------------------
+ p2v/p2v.h        |  2 +-
+ p2v/ssh.c        | 25 +++++++++++++++++++++----
+ 3 files changed, 33 insertions(+), 25 deletions(-)
+
+diff --git a/p2v/conversion.c b/p2v/conversion.c
+index 94a466640..27c6b2f2d 100644
+--- a/p2v/conversion.c
++++ b/p2v/conversion.c
+@@ -366,28 +366,19 @@ start_conversion (struct config *config,
+   }
+ 
+   /* Copy the static files to the remote dir. */
+-  if (scp_file (config, name_file, remote_dir) == -1) {
+-    set_conversion_error ("scp: %s to %s: %s",
+-                          name_file, remote_dir, get_ssh_error ());
++
++  /* These three files must not fail, so check for errors here. */
++  if (scp_file (config, remote_dir,
++                name_file, libvirt_xml_file, wrapper_script, NULL) == -1) {
++    set_conversion_error ("scp: %s: %s",
++                          remote_dir, get_ssh_error ());
+     goto out;
+   }
+-  if (scp_file (config, libvirt_xml_file, remote_dir) == -1) {
+-    set_conversion_error ("scp: %s to %s: %s",
+-                          libvirt_xml_file, remote_dir, get_ssh_error ());
+-    goto out;
+-  }
+-  if (scp_file (config, wrapper_script, remote_dir) == -1) {
+-    set_conversion_error ("scp: %s to %s: %s",
+-                          wrapper_script, remote_dir, get_ssh_error ());
+-    goto out;
+-  }
+-  /* It's not essential that these files are copied. */
+-  ignore_value (scp_file (config, dmesg_file, remote_dir));
+-  ignore_value (scp_file (config, lscpu_file, remote_dir));
+-  ignore_value (scp_file (config, lspci_file, remote_dir));
+-  ignore_value (scp_file (config, lsscsi_file, remote_dir));
+-  ignore_value (scp_file (config, lsusb_file, remote_dir));
+-  ignore_value (scp_file (config, p2v_version_file, remote_dir));
++
++  /* It's not essential that these files are copied, so ignore errors. */
++  ignore_value (scp_file (config, remote_dir,
++                          dmesg_file, lscpu_file, lspci_file, lsscsi_file,
++                          lsusb_file, p2v_version_file, NULL));
+ 
+   /* Do the conversion.  This runs until virt-v2v exits. */
+   if (notify_ui)
+diff --git a/p2v/p2v.h b/p2v/p2v.h
+index 5223aa216..b26648a01 100644
+--- a/p2v/p2v.h
++++ b/p2v/p2v.h
+@@ -128,7 +128,7 @@ extern int test_connection (struct config *);
+ extern mexp_h *open_data_connection (struct config *, const char *local_ipaddr, int local_port, int *remote_port);
+ extern mexp_h *start_remote_connection (struct config *, const char *remote_dir);
+ extern const char *get_ssh_error (void);
+-extern int scp_file (struct config *config, const char *localfile, const char *remotefile);
++extern int scp_file (struct config *config, const char *target, const char *local, ...) __attribute__((sentinel));
+ 
+ /* nbd.c */
+ extern void set_nbd_option (const char *opt);
+diff --git a/p2v/ssh.c b/p2v/ssh.c
+index dfcab0e40..991888348 100644
+--- a/p2v/ssh.c
++++ b/p2v/ssh.c
+@@ -572,14 +572,18 @@ start_ssh (unsigned spawn_flags, struct config *config,
+ #endif
+ 
+ /**
+- * Upload a file to remote using L<scp(1)>.
++ * Upload file(s) to remote using L<scp(1)>.
++ *
++ * Note that the target (directory or file) comes before the list of
++ * local files, because the list of local files is a varargs list.
+  *
+  * This is a simplified version of L</start_ssh> above.
+  */
+ int
+-scp_file (struct config *config, const char *localfile, const char *remotefile)
++scp_file (struct config *config, const char *target, const char *local, ...)
+ {
+   size_t i = 0;
++  va_list args;
+   const size_t MAX_ARGS = 64;
+   const char *argv[MAX_ARGS];
+   char port_str[64];
+@@ -618,12 +622,25 @@ scp_file (struct config *config, const char *localfile, const char *remotefile)
+     ADD_ARG (argv, i, "-i");
+     ADD_ARG (argv, i, config->identity_file);
+   }
+-  ADD_ARG (argv, i, localfile);
++
++  /* Source files or directories.
++   * Strictly speaking this could abort() if the list of files is
++   * too long, but that never happens in virt-p2v. XXX
++   */
++  va_start (args, local);
++  do ADD_ARG (argv, i, local);
++  while ((local = va_arg (args, const char *)) != NULL);
++  va_end (args);
++
++  /* The target file or directory.  We need to rewrite this as
++   * "username@server:target".
++   */
+   if (asprintf (&remote, "%s@%s:%s",
+                 config->username ? config->username : "root",
+-                config->server, remotefile) == -1)
++                config->server, target) == -1)
+     error (EXIT_FAILURE, errno, "asprintf");
+   ADD_ARG (argv, i, remote);
++
+   ADD_ARG (argv, i, NULL);
+ 
+ #if DEBUG_STDERR
+-- 
+2.14.3
+
diff --git a/SOURCES/0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch b/SOURCES/0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch
deleted file mode 100644
index 8fc66d6..0000000
--- a/SOURCES/0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From db166d40204d854d852880c154ae55a18b6f8acf Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Tue, 28 Feb 2017 15:48:18 +0000
-Subject: [PATCH] sysprep: Remove DHCP_HOSTNAME= from ifcfg-* files
- (RHBZ#1427529).
-
-(cherry picked from commit 0f99537cb69c88f7ceb6c69a9d9ae10baaaa3623)
----
- sysprep/sysprep_operation_net_hostname.ml | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/sysprep/sysprep_operation_net_hostname.ml b/sysprep/sysprep_operation_net_hostname.ml
-index 3824d42ae..7284d630f 100644
---- a/sysprep/sysprep_operation_net_hostname.ml
-+++ b/sysprep/sysprep_operation_net_hostname.ml
-@@ -30,10 +30,12 @@ let net_hostname_perform (g : Guestfs.guestfs) root side_effects =
-     let filenames = g#glob_expand "/etc/sysconfig/network-scripts/ifcfg-*" in
-     Array.iter (
-       fun filename ->
--        (* Replace HOSTNAME=... entry. *)
-+        (* Remove HOSTNAME=... and DHCP_HOSTNAME=... entries. *)
-         let lines = Array.to_list (g#read_lines filename) in
-         let lines = List.filter (
--          fun line -> not (String.is_prefix line "HOSTNAME=")
-+          fun line ->
-+            not (String.is_prefix line "HOSTNAME=") &&
-+            not (String.is_prefix line "DHCP_HOSTNAME=")
-         ) lines in
-         let file = String.concat "\n" lines ^ "\n" in
-         g#write filename file;
-@@ -46,7 +48,7 @@ let op = {
-   defaults with
-     name = "net-hostname";
-     enabled_by_default = true;
--    heading = s_"Remove HOSTNAME in network interface configuration";
-+    heading = s_"Remove HOSTNAME and DHCP_HOSTNAME in network interface configuration";
-     pod_description = Some (s_"\
- For Fedora and Red Hat Enterprise Linux,
- this is removed from C<ifcfg-*> files.");
--- 
-2.13.4
-
diff --git a/SOURCES/0028-p2v-Fix-list-of-files-in-documentation.patch b/SOURCES/0028-p2v-Fix-list-of-files-in-documentation.patch
new file mode 100644
index 0000000..a0b8b01
--- /dev/null
+++ b/SOURCES/0028-p2v-Fix-list-of-files-in-documentation.patch
@@ -0,0 +1,66 @@
+From 77faaa76368ecd4e758d0705a44c1afc25c95796 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 30 Mar 2017 14:45:47 +0100
+Subject: [PATCH] p2v: Fix list of files in documentation.
+
+(cherry picked from commit 38e7a1e038a91e34010ca0f89b0da077be821421)
+---
+ p2v/virt-p2v.pod | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
+index ee870fdd9..7fd637152 100644
+--- a/p2v/virt-p2v.pod
++++ b/p2v/virt-p2v.pod
+@@ -724,18 +724,6 @@ Into this directory are written various files which include:
+ 
+ =item F<dmesg>
+ 
+-I<(before conversion)>
+-
+-The dmesg output from the physical machine.  Useful for detecting
+-problems such as missing device drivers or firmware on the virt-p2v
+-ISO.
+-
+-=item F<environment>
+-
+-I<(before conversion)>
+-
+-The content of the environment where L<virt-v2v(1)> will run.
+-
+ =item F<lscpu>
+ 
+ =item F<lspci>
+@@ -746,8 +734,18 @@ The content of the environment where L<virt-v2v(1)> will run.
+ 
+ I<(before conversion)>
+ 
+-The output of the corresponding commands (ie L<lscpu(1)> etc) on the
+-physical machine.  Useful for debugging novel hardware configurations.
++The output of the corresponding commands (ie L<dmesg(1)>, L<lscpu(1)>
++etc) on the physical machine.
++
++The dmesg output is useful for detecting problems such as missing
++device drivers or firmware on the virt-p2v ISO.  The others are useful
++for debugging novel hardware configurations.
++
++=item F<environment>
++
++I<(before conversion)>
++
++The content of the environment where L<virt-v2v(1)> will run.
+ 
+ =item F<name>
+ 
+@@ -799,7 +797,7 @@ B<unedited> log file in any bug reports or support tickets.
+ 
+ =item F<virt-v2v-wrapper.sh>
+ 
+-I<(during/after conversion)>
++I<(before conversion)>
+ 
+ This is the wrapper script which is used when running virt-v2v.  For
+ interest only, do not attempt to run this script yourself.
+-- 
+2.14.3
+
diff --git a/SOURCES/0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch b/SOURCES/0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch
deleted file mode 100644
index 251d7fb..0000000
--- a/SOURCES/0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch
+++ /dev/null
@@ -1,181 +0,0 @@
-From a1385efa3499d7668128c90e26790e08e61897de Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Tue, 28 Mar 2017 23:03:31 +0100
-Subject: [PATCH] p2v, v2v: Ensure the full version is always available in
- several places.
-
-Ensure the full version of virt-v2v and virt-p2v is available in the
-conversion log file, the only log file that we reliably get from users
-and customers.  "Full version" means the major, minor, release and
-extra fields.  The extra field is especially important as it contains
-the downstream package release in Fedora, RHEL etc.
-
-This change saves the virt-p2v version as a comment in the
-physical.xml file, which is included in full in the conversion log (by
-virt-v2v).
-
-It also ensures that the initial virt-v2v debug message contains the
-full version number including the 'extra' field.
-
-  $ cat virt-v2v-conversion-log.txt
-  virt-v2v: libguestfs 1.37.7local,libvirt (x86_64)
-  ...
-  <!-- virt-p2v 1.37.7local,libvirt -->
-
-It also adds 'p2v-version' and 'v2v-version' files in the virt-p2v
-debug directory.  These are strictly superfluous but could be useful
-for end users.
-
-  $ cat p2v-version
-  virt-p2v 1.37.7local,libvirt
-  $ cat v2v-version
-  virt-v2v 1.37.7local,libvirt
-
-(cherry picked from commit 7cae10f0c11ebde643ec575f7f779aa1e7103d6b)
----
- p2v/conversion.c | 40 ++++++++++++++++++++++++++++++++++++----
- p2v/virt-p2v.pod |  8 ++++++++
- v2v/v2v.ml       |  4 ++--
- 3 files changed, 46 insertions(+), 6 deletions(-)
-
-diff --git a/p2v/conversion.c b/p2v/conversion.c
-index 0c17ef242..beda2b89b 100644
---- a/p2v/conversion.c
-+++ b/p2v/conversion.c
-@@ -95,6 +95,7 @@ static void generate_libvirt_xml (struct config *, struct data_conn *, const cha
- static void generate_wrapper_script (struct config *, const char *remote_dir, const char *filename);
- static void generate_system_data (const char *dmesg_file, const char *lscpu_file, const char *lspci_file, const char *lsscsi_file, const char *lsusb_file);
- static const char *map_interface_to_network (struct config *, const char *interface);
-+static void generate_p2v_version_file (const char *p2v_version_file);
- static void print_quoted (FILE *fp, const char *s);
- 
- static char *conversion_error;
-@@ -206,6 +207,7 @@ start_conversion (struct config *config,
-   char lspci_file[]       = "/tmp/p2v.XXXXXX/lspci";
-   char lsscsi_file[]      = "/tmp/p2v.XXXXXX/lsscsi";
-   char lsusb_file[]       = "/tmp/p2v.XXXXXX/lsusb";
-+  char p2v_version_file[] = "/tmp/p2v.XXXXXX/p2v-version";
-   int inhibit_fd = -1;
- 
- #if DEBUG_STDERR
-@@ -342,6 +344,7 @@ start_conversion (struct config *config,
-   memcpy (lspci_file, tmpdir, strlen (tmpdir));
-   memcpy (lsscsi_file, tmpdir, strlen (tmpdir));
-   memcpy (lsusb_file, tmpdir, strlen (tmpdir));
-+  memcpy (p2v_version_file, tmpdir, strlen (tmpdir));
- 
-   /* Generate the static files. */
-   generate_name (config, name_file);
-@@ -349,6 +352,7 @@ start_conversion (struct config *config,
-   generate_wrapper_script (config, remote_dir, wrapper_script);
-   generate_system_data (dmesg_file,
-                         lscpu_file, lspci_file, lsscsi_file, lsusb_file);
-+  generate_p2v_version_file (p2v_version_file);
- 
-   /* Open the control connection.  This also creates remote_dir. */
-   if (notify_ui)
-@@ -383,6 +387,7 @@ start_conversion (struct config *config,
-   ignore_value (scp_file (config, lspci_file, remote_dir));
-   ignore_value (scp_file (config, lsscsi_file, remote_dir));
-   ignore_value (scp_file (config, lsusb_file, remote_dir));
-+  ignore_value (scp_file (config, p2v_version_file, remote_dir));
- 
-   /* Do the conversion.  This runs until virt-v2v exits. */
-   if (notify_ui)
-@@ -546,10 +551,10 @@ cleanup_data_conns (struct data_conn *data_conns, size_t nr)
-   } while (0)
- 
- /* An XML comment. */
--#define comment(str)						\
--  do {                                                          \
--    if (xmlTextWriterWriteComment (xo, BAD_CAST (str)) == -1)	\
--      error (EXIT_FAILURE, errno, "xmlTextWriterWriteComment");	\
-+#define comment(fs,...)                                                 \
-+  do {                                                                  \
-+    if (xmlTextWriterWriteFormatComment (xo, fs, ##__VA_ARGS__) == -1)	\
-+      error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatComment");   \
-   } while (0)
- 
- /**
-@@ -579,6 +584,8 @@ generate_libvirt_xml (struct config *config, struct data_conn *data_conns,
- 
-   memkb = config->memory / 1024;
- 
-+  comment (" %s %s ", getprogname (), PACKAGE_VERSION_FULL);
-+
-   comment
-     (" NOTE!\n"
-      "\n"
-@@ -859,6 +866,13 @@ generate_wrapper_script (struct config *config, const char *remote_dir,
-   fprintf (fp, "\n");
- 
-   fprintf (fp,
-+           "# Log the version of virt-v2v (for information only).\n");
-+  if (config->sudo)
-+    fprintf (fp, "sudo -n ");
-+  fprintf (fp, "virt-v2v --version > v2v-version\n");
-+  fprintf (fp, "\n");
-+
-+  fprintf (fp,
-            "# Run virt-v2v.  Send stdout back to virt-p2v.  Send stdout\n"
-            "# and stderr (debugging info) to the log file.\n");
-   fprintf (fp, "v2v 2>> $log | tee -a $log\n");
-@@ -939,3 +953,21 @@ generate_system_data (const char *dmesg_file,
- 
-   ignore_value (system (cmd));
- }
-+
-+/**
-+ * Generate a file containing the version of virt-p2v.
-+ *
-+ * The version of virt-v2v is contained in the conversion log.
-+ */
-+static void
-+generate_p2v_version_file (const char *p2v_version_file)
-+{
-+  FILE *fp = fopen (p2v_version_file, "w");
-+  if (fp == NULL) {
-+    perror (p2v_version_file);
-+    return;                     /* non-fatal */
-+  }
-+  fprintf (fp, "%s %s\n",
-+           getprogname (), PACKAGE_VERSION_FULL);
-+  fclose (fp);
-+}
-diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
-index 4a5f58724..ee870fdd9 100644
---- a/p2v/virt-p2v.pod
-+++ b/p2v/virt-p2v.pod
-@@ -767,6 +767,14 @@ Note this is not "real" libvirt XML (and must B<never> be loaded into
- libvirt, which would reject it anyhow).  Also it is not the same as
- the libvirt XML which virt-v2v generates in certain output modes.
- 
-+=item F<p2v-version>
-+
-+=item F<v2v-version>
-+
-+I<(before conversion)>
-+
-+The versions of virt-p2v and virt-v2v respectively.
-+
- =item F<status>
- 
- I<(after conversion)>
-diff --git a/v2v/v2v.ml b/v2v/v2v.ml
-index 551524dc5..cc7b88966 100644
---- a/v2v/v2v.ml
-+++ b/v2v/v2v.ml
-@@ -42,8 +42,8 @@ let rec main () =
- 
-   (* Print the version, easier than asking users to tell us. *)
-   debug "%s: %s %s (%s)"
--        prog Guestfs_config.package_name
--        Guestfs_config.package_version Guestfs_config.host_cpu;
-+        prog Guestfs_config.package_name Guestfs_config.package_version_full
-+        Guestfs_config.host_cpu;
- 
-   (* Print the libvirt version if debugging.  Note that if
-    * we're configured --without-libvirt, then this will throw
--- 
-2.13.4
-
diff --git a/SOURCES/0029-p2v-Run-fewer-scp-commands.patch b/SOURCES/0029-p2v-Run-fewer-scp-commands.patch
deleted file mode 100644
index e714803..0000000
--- a/SOURCES/0029-p2v-Run-fewer-scp-commands.patch
+++ /dev/null
@@ -1,134 +0,0 @@
-From f047435a1087f438c645d729f68f6578e8cb861d Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 30 Mar 2017 13:13:03 +0100
-Subject: [PATCH] p2v: Run fewer 'scp' commands.
-
-Each scp command takes a considerable amount of time -- several
-seconds -- because it must set up, authenticate and tear down a new
-connection.  Avoid this by combining several copies into a single
-command.
-
-We still have to use two scp commands because we want to check that
-some files are copied and ignore failures in a second set of
-informational files.
-
-(cherry picked from commit d178deeeb814471b9d70431626b6cd515a21d0c1)
----
- p2v/conversion.c | 31 +++++++++++--------------------
- p2v/p2v.h        |  2 +-
- p2v/ssh.c        | 25 +++++++++++++++++++++----
- 3 files changed, 33 insertions(+), 25 deletions(-)
-
-diff --git a/p2v/conversion.c b/p2v/conversion.c
-index beda2b89b..0da9a62e0 100644
---- a/p2v/conversion.c
-+++ b/p2v/conversion.c
-@@ -366,28 +366,19 @@ start_conversion (struct config *config,
-   }
- 
-   /* Copy the static files to the remote dir. */
--  if (scp_file (config, name_file, remote_dir) == -1) {
--    set_conversion_error ("scp: %s to %s: %s",
--                          name_file, remote_dir, get_ssh_error ());
-+
-+  /* These three files must not fail, so check for errors here. */
-+  if (scp_file (config, remote_dir,
-+                name_file, libvirt_xml_file, wrapper_script, NULL) == -1) {
-+    set_conversion_error ("scp: %s: %s",
-+                          remote_dir, get_ssh_error ());
-     goto out;
-   }
--  if (scp_file (config, libvirt_xml_file, remote_dir) == -1) {
--    set_conversion_error ("scp: %s to %s: %s",
--                          libvirt_xml_file, remote_dir, get_ssh_error ());
--    goto out;
--  }
--  if (scp_file (config, wrapper_script, remote_dir) == -1) {
--    set_conversion_error ("scp: %s to %s: %s",
--                          wrapper_script, remote_dir, get_ssh_error ());
--    goto out;
--  }
--  /* It's not essential that these files are copied. */
--  ignore_value (scp_file (config, dmesg_file, remote_dir));
--  ignore_value (scp_file (config, lscpu_file, remote_dir));
--  ignore_value (scp_file (config, lspci_file, remote_dir));
--  ignore_value (scp_file (config, lsscsi_file, remote_dir));
--  ignore_value (scp_file (config, lsusb_file, remote_dir));
--  ignore_value (scp_file (config, p2v_version_file, remote_dir));
-+
-+  /* It's not essential that these files are copied, so ignore errors. */
-+  ignore_value (scp_file (config, remote_dir,
-+                          dmesg_file, lscpu_file, lspci_file, lsscsi_file,
-+                          lsusb_file, p2v_version_file, NULL));
- 
-   /* Do the conversion.  This runs until virt-v2v exits. */
-   if (notify_ui)
-diff --git a/p2v/p2v.h b/p2v/p2v.h
-index 5223aa216..b26648a01 100644
---- a/p2v/p2v.h
-+++ b/p2v/p2v.h
-@@ -128,7 +128,7 @@ extern int test_connection (struct config *);
- extern mexp_h *open_data_connection (struct config *, const char *local_ipaddr, int local_port, int *remote_port);
- extern mexp_h *start_remote_connection (struct config *, const char *remote_dir);
- extern const char *get_ssh_error (void);
--extern int scp_file (struct config *config, const char *localfile, const char *remotefile);
-+extern int scp_file (struct config *config, const char *target, const char *local, ...) __attribute__((sentinel));
- 
- /* nbd.c */
- extern void set_nbd_option (const char *opt);
-diff --git a/p2v/ssh.c b/p2v/ssh.c
-index 8beaf74bb..bfeb80661 100644
---- a/p2v/ssh.c
-+++ b/p2v/ssh.c
-@@ -572,14 +572,18 @@ start_ssh (unsigned spawn_flags, struct config *config,
- #endif
- 
- /**
-- * Upload a file to remote using L<scp(1)>.
-+ * Upload file(s) to remote using L<scp(1)>.
-+ *
-+ * Note that the target (directory or file) comes before the list of
-+ * local files, because the list of local files is a varargs list.
-  *
-  * This is a simplified version of L</start_ssh> above.
-  */
- int
--scp_file (struct config *config, const char *localfile, const char *remotefile)
-+scp_file (struct config *config, const char *target, const char *local, ...)
- {
-   size_t i = 0;
-+  va_list args;
-   const size_t MAX_ARGS = 64;
-   const char *argv[MAX_ARGS];
-   char port_str[64];
-@@ -618,12 +622,25 @@ scp_file (struct config *config, const char *localfile, const char *remotefile)
-     ADD_ARG (argv, i, "-i");
-     ADD_ARG (argv, i, config->identity_file);
-   }
--  ADD_ARG (argv, i, localfile);
-+
-+  /* Source files or directories.
-+   * Strictly speaking this could abort() if the list of files is
-+   * too long, but that never happens in virt-p2v. XXX
-+   */
-+  va_start (args, local);
-+  do ADD_ARG (argv, i, local);
-+  while ((local = va_arg (args, const char *)) != NULL);
-+  va_end (args);
-+
-+  /* The target file or directory.  We need to rewrite this as
-+   * "username@server:target".
-+   */
-   if (asprintf (&remote, "%s@%s:%s",
-                 config->username ? config->username : "root",
--                config->server, remotefile) == -1)
-+                config->server, target) == -1)
-     error (EXIT_FAILURE, errno, "asprintf");
-   ADD_ARG (argv, i, remote);
-+
-   ADD_ARG (argv, i, NULL);
- 
- #if DEBUG_STDERR
--- 
-2.13.4
-
diff --git a/SOURCES/0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch b/SOURCES/0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch
new file mode 100644
index 0000000..17bd1cf
--- /dev/null
+++ b/SOURCES/0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch
@@ -0,0 +1,46 @@
+From f06fc3401bc88206502f6f876a553634c8acf220 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 30 Mar 2017 19:34:29 +0100
+Subject: [PATCH] p2v: tests: Fix fake scp command so it can handle multiple
+ local files.
+
+Fixes commit d178deeeb814471b9d70431626b6cd515a21d0c1.
+
+(cherry picked from commit b417c877f4ea848af8f8538957ab677c65637027)
+---
+ p2v/test-virt-p2v-scp.sh | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/p2v/test-virt-p2v-scp.sh b/p2v/test-virt-p2v-scp.sh
+index c8a405db4..29900b663 100755
+--- a/p2v/test-virt-p2v-scp.sh
++++ b/p2v/test-virt-p2v-scp.sh
+@@ -44,15 +44,19 @@ while true ; do
+     esac
+ done
+ 
+-# Hopefully there are two arguments left, the source (local) file
+-# and a remote file of the form user@server:remote.
+-if [ $# -ne 2 ]; then
++# Hopefully there are >= two arguments left, the source (local)
++# file(s) and a remote file of the form user@server:remote.
++if [ $# -lt 2 ]; then
+     echo "$0: incorrect number of arguments found:" "$@"
+     exit 1
+ fi
+ 
+-local="$1"
+-remote="$(echo $2 | awk -F: '{print $2}')"
++# https://stackoverflow.com/questions/1853946/getting-the-last-argument-passed-to-a-shell-script/1854031#1854031
++remote="${@: -1}"
++# https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bash/26163980#26163980
++set -- "${@:1:$(($#-1))}"
++
++remote="$(echo $remote | awk -F: '{print $2}')"
+ 
+ # Use the copy command.
+-exec cp "$local" "$remote"
++exec cp "$@" "$remote"
+-- 
+2.14.3
+
diff --git a/SOURCES/0030-p2v-Fix-list-of-files-in-documentation.patch b/SOURCES/0030-p2v-Fix-list-of-files-in-documentation.patch
deleted file mode 100644
index cf988af..0000000
--- a/SOURCES/0030-p2v-Fix-list-of-files-in-documentation.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From 90ee2a3d8b55cf983d765c2c7666cad16e16250f Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 30 Mar 2017 14:45:47 +0100
-Subject: [PATCH] p2v: Fix list of files in documentation.
-
-(cherry picked from commit 38e7a1e038a91e34010ca0f89b0da077be821421)
----
- p2v/virt-p2v.pod | 28 +++++++++++++---------------
- 1 file changed, 13 insertions(+), 15 deletions(-)
-
-diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
-index ee870fdd9..7fd637152 100644
---- a/p2v/virt-p2v.pod
-+++ b/p2v/virt-p2v.pod
-@@ -724,18 +724,6 @@ Into this directory are written various files which include:
- 
- =item F<dmesg>
- 
--I<(before conversion)>
--
--The dmesg output from the physical machine.  Useful for detecting
--problems such as missing device drivers or firmware on the virt-p2v
--ISO.
--
--=item F<environment>
--
--I<(before conversion)>
--
--The content of the environment where L<virt-v2v(1)> will run.
--
- =item F<lscpu>
- 
- =item F<lspci>
-@@ -746,8 +734,18 @@ The content of the environment where L<virt-v2v(1)> will run.
- 
- I<(before conversion)>
- 
--The output of the corresponding commands (ie L<lscpu(1)> etc) on the
--physical machine.  Useful for debugging novel hardware configurations.
-+The output of the corresponding commands (ie L<dmesg(1)>, L<lscpu(1)>
-+etc) on the physical machine.
-+
-+The dmesg output is useful for detecting problems such as missing
-+device drivers or firmware on the virt-p2v ISO.  The others are useful
-+for debugging novel hardware configurations.
-+
-+=item F<environment>
-+
-+I<(before conversion)>
-+
-+The content of the environment where L<virt-v2v(1)> will run.
- 
- =item F<name>
- 
-@@ -799,7 +797,7 @@ B<unedited> log file in any bug reports or support tickets.
- 
- =item F<virt-v2v-wrapper.sh>
- 
--I<(during/after conversion)>
-+I<(before conversion)>
- 
- This is the wrapper script which is used when running virt-v2v.  For
- interest only, do not attempt to run this script yourself.
--- 
-2.13.4
-
diff --git a/SOURCES/0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch b/SOURCES/0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch
new file mode 100644
index 0000000..643a430
--- /dev/null
+++ b/SOURCES/0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch
@@ -0,0 +1,1942 @@
+From e43fe85f28ba6fb184e6894db019668f0515c38d Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Mon, 10 Apr 2017 15:24:26 +0100
+Subject: [PATCH] v2v: Implement -i vmx to read VMware vmx files directly
+ (RHBZ#1441197).
+
+This is a mostly complete implementation of a VMX parser and input
+class for virt-v2v.  It parses the name, memory size, CPU topology,
+firmware, video, sound, hard disks, removable disks and network
+interfaces from the VMX file.  It only omits support for floppies and
+SCSI CD-ROMs.
+
+The input class is split into two major parts: a generic VMX file
+parser (Parse_vmx), and the Input_vmx module which translates the VMX
+tree into the source device model.
+
+This also contains tests.  There are simple unit tests of the
+Parse_vmx module, and also some more complete parsing tests taken from
+real guests.
+
+(cherry picked from commit ca40078cdda9167d4658ddfe24c828c7ee76be37)
+---
+ v2v/Makefile.am               |  15 ++
+ v2v/cmdline.ml                |  12 +-
+ v2v/input_vmx.ml              | 349 ++++++++++++++++++++++++++++++++++++++
+ v2v/input_vmx.mli             |  22 +++
+ v2v/name_from_disk.ml         |   2 +-
+ v2v/parse_vmx.ml              | 381 ++++++++++++++++++++++++++++++++++++++++++
+ v2v/parse_vmx.mli             |  89 ++++++++++
+ v2v/test-v2v-i-vmx-1.expected |  39 +++++
+ v2v/test-v2v-i-vmx-1.vmx      | 172 +++++++++++++++++++
+ v2v/test-v2v-i-vmx-2.expected |  19 +++
+ v2v/test-v2v-i-vmx-2.vmx      |  84 ++++++++++
+ v2v/test-v2v-i-vmx-3.expected |  19 +++
+ v2v/test-v2v-i-vmx-3.vmx      |  91 ++++++++++
+ v2v/test-v2v-i-vmx-4.expected |  19 +++
+ v2v/test-v2v-i-vmx-4.vmx      |  88 ++++++++++
+ v2v/test-v2v-i-vmx.sh         |  48 ++++++
+ v2v/v2v_unit_tests.ml         | 143 ++++++++++++++++
+ v2v/virt-v2v.pod              |  72 +++++++-
+ 18 files changed, 1655 insertions(+), 9 deletions(-)
+ create mode 100644 v2v/input_vmx.ml
+ create mode 100644 v2v/input_vmx.mli
+ create mode 100644 v2v/parse_vmx.ml
+ create mode 100644 v2v/parse_vmx.mli
+ create mode 100644 v2v/test-v2v-i-vmx-1.expected
+ create mode 100644 v2v/test-v2v-i-vmx-1.vmx
+ create mode 100644 v2v/test-v2v-i-vmx-2.expected
+ create mode 100644 v2v/test-v2v-i-vmx-2.vmx
+ create mode 100644 v2v/test-v2v-i-vmx-3.expected
+ create mode 100644 v2v/test-v2v-i-vmx-3.vmx
+ create mode 100644 v2v/test-v2v-i-vmx-4.expected
+ create mode 100644 v2v/test-v2v-i-vmx-4.vmx
+ create mode 100755 v2v/test-v2v-i-vmx.sh
+
+diff --git a/v2v/Makefile.am b/v2v/Makefile.am
+index 297406496..0df759eca 100644
+--- a/v2v/Makefile.am
++++ b/v2v/Makefile.am
+@@ -38,6 +38,7 @@ SOURCES_MLI = \
+ 	input_libvirt_xen_ssh.mli \
+ 	input_libvirtxml.mli \
+ 	input_ova.mli \
++	input_vmx.mli \
+ 	inspect_source.mli \
+ 	libvirt_utils.mli \
+ 	linux.mli \
+@@ -55,6 +56,7 @@ SOURCES_MLI = \
+ 	OVF.mli \
+ 	parse_ovf_from_ova.mli \
+ 	parse_libvirt_xml.mli \
++	parse_vmx.mli \
+ 	qemu_command.mli \
+ 	target_bus_assignment.mli \
+ 	types.mli \
+@@ -80,6 +82,7 @@ SOURCES_ML = \
+ 	windows_virtio.ml \
+ 	modules_list.ml \
+ 	input_disk.ml \
++	parse_vmx.ml \
+ 	parse_libvirt_xml.ml \
+ 	create_libvirt_xml.ml \
+ 	qemu_command.ml \
+@@ -89,6 +92,7 @@ SOURCES_ML = \
+ 	input_libvirt_xen_ssh.ml \
+ 	input_libvirt.ml \
+ 	input_ova.ml \
++	input_vmx.ml \
+ 	linux_bootloaders.ml \
+ 	linux_kernels.ml \
+ 	convert_linux.ml \
+@@ -268,6 +272,7 @@ TESTS = \
+ 	test-v2v-i-ova-subfolders.sh \
+ 	test-v2v-i-ova-tar.sh \
+ 	test-v2v-i-ova-two-disks.sh \
++	test-v2v-i-vmx.sh \
+ 	test-v2v-bad-networks-and-bridges.sh
+ 
+ if HAVE_LIBVIRT
+@@ -411,6 +416,15 @@ EXTRA_DIST += \
+ 	test-v2v-i-ova.ovf \
+ 	test-v2v-i-ova.sh \
+ 	test-v2v-i-ova.xml \
++	test-v2v-i-vmx.sh \
++	test-v2v-i-vmx-1.expected \
++	test-v2v-i-vmx-2.expected \
++	test-v2v-i-vmx-3.expected \
++	test-v2v-i-vmx-4.expected \
++	test-v2v-i-vmx-1.vmx \
++	test-v2v-i-vmx-2.vmx \
++	test-v2v-i-vmx-3.vmx \
++	test-v2v-i-vmx-4.vmx \
+ 	test-v2v-machine-readable.sh \
+ 	test-v2v-networks-and-bridges-expected.xml \
+ 	test-v2v-networks-and-bridges.sh \
+@@ -450,6 +464,7 @@ v2v_unit_tests_BOBJECTS = \
+ 	windows.cmo \
+ 	windows_virtio.cmo \
+ 	linux.cmo \
++	parse_vmx.cmo \
+ 	v2v_unit_tests.cmo
+ v2v_unit_tests_XOBJECTS = $(v2v_unit_tests_BOBJECTS:.cmo=.cmx)
+ 
+diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
+index 3e3d5c312..db2346a38 100644
+--- a/v2v/cmdline.ml
++++ b/v2v/cmdline.ml
+@@ -86,6 +86,7 @@ let parse_cmdline () =
+     | "libvirt" -> input_mode := `Libvirt
+     | "libvirtxml" -> input_mode := `LibvirtXML
+     | "ova" -> input_mode := `OVA
++    | "vmx" -> input_mode := `VMX
+     | s ->
+       error (f_"unknown -i option: %s") s
+   in
+@@ -333,7 +334,16 @@ read the man page virt-v2v(1).
+         | [filename] -> filename
+         | _ ->
+           error (f_"expecting an OVA file name on the command line") in
+-      Input_ova.input_ova filename in
++      Input_ova.input_ova filename
++
++    | `VMX ->
++      (* -i vmx: Expecting an vmx filename. *)
++      let filename =
++        match args with
++        | [filename] -> filename
++        | _ ->
++          error (f_"expecting a VMX file name on the command line") in
++      Input_vmx.input_vmx filename in
+ 
+   (* Prevent use of --in-place option in RHEL. *)
+   if in_place then
+diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
+new file mode 100644
+index 000000000..bb09f0bf8
+--- /dev/null
++++ b/v2v/input_vmx.ml
+@@ -0,0 +1,349 @@
++(* virt-v2v
++ * Copyright (C) 2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *)
++
++open Printf
++open Scanf
++
++open Common_gettext.Gettext
++open Common_utils
++
++open Types
++open Utils
++open Name_from_disk
++
++external identity : 'a -> 'a = "%identity"
++
++let rec find_disks vmx vmx_filename =
++  find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename
++
++(* Find all SCSI hard disks.
++ *
++ * In the VMX file:
++ *   scsi0.virtualDev = "pvscsi"  # or may be "lsilogic" etc.
++ *   scsi0:0.deviceType = "scsi-hardDisk"
++ *   scsi0:0.fileName = "guest.vmdk"
++ *)
++and find_scsi_disks vmx vmx_filename =
++  let get_scsi_controller_target ns =
++    sscanf ns "scsi%d:%d" (fun c t -> c, t)
++  in
++  let is_scsi_controller_target ns =
++    try ignore (get_scsi_controller_target ns); true
++    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
++  in
++  let scsi_device_types = [ "scsi-harddisk" ] in
++  let scsi_controller = Source_SCSI in
++
++  find_hdds vmx vmx_filename
++            get_scsi_controller_target is_scsi_controller_target
++            scsi_device_types scsi_controller
++
++(* Find all IDE hard disks.
++ *
++ * In the VMX file:
++ *   ide0:0.deviceType = "ata-hardDisk"
++ *   ide0:0.fileName = "guest.vmdk"
++ *)
++and find_ide_disks vmx vmx_filename =
++  let get_ide_controller_target ns =
++    sscanf ns "ide%d:%d" (fun c t -> c, t)
++  in
++  let is_ide_controller_target ns =
++    try ignore (get_ide_controller_target ns); true
++    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
++  in
++  let ide_device_types = [ "ata-harddisk" ] in
++  let ide_controller = Source_IDE in
++
++  find_hdds vmx vmx_filename
++            get_ide_controller_target is_ide_controller_target
++            ide_device_types ide_controller
++
++and find_hdds vmx vmx_filename
++              get_controller_target is_controller_target
++              device_types controller =
++  (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *)
++  let hdds =
++    Parse_vmx.select_namespaces (
++      function
++      | [ns] ->
++         (* Check the namespace is '(ide|scsi)X:Y' *)
++         if not (is_controller_target ns) then false
++         else (
++           (* Check the deviceType is one we are looking for. *)
++           match Parse_vmx.get_string vmx [ns; "deviceType"] with
++           | Some str ->
++              let str = String.lowercase_ascii str in
++              List.mem str device_types
++           | None -> false
++         )
++      | _ -> false
++    ) vmx in
++
++  (* Map the subset to a list of disks. *)
++  let hdds =
++    Parse_vmx.map (
++      fun path v ->
++        match path, v with
++        | [ns; "filename"], Some filename ->
++           let c, t = get_controller_target ns in
++           let s = { s_disk_id = (-1);
++                     s_qemu_uri = qemu_uri_of_filename vmx_filename filename;
++                     s_format = Some "vmdk";
++                     s_controller = Some controller } in
++           Some (c, t, s)
++        | _ -> None
++    ) hdds in
++  let hdds = filter_map identity hdds in
++
++  (* We don't have a way to return the controllers and targets, so
++   * just make sure the disks are sorted into order, since Parse_vmx
++   * won't return them in any particular order.
++   *)
++  let hdds = List.sort compare hdds in
++  let hdds = List.map (fun (_, _, source) -> source) hdds in
++
++  (* Set the s_disk_id field to an incrementing number. *)
++  let hdds = mapi (fun i source -> { source with s_disk_id = i }) hdds in
++
++  hdds
++
++(* The filename can be an absolute path, but is more often a
++ * path relative to the location of the vmx file.
++ *
++ * Note that we always end up with an absolute path, which is
++ * also useful because it means we won't have any paths that
++ * could be misinterpreted by qemu.
++ *)
++and qemu_uri_of_filename vmx_filename filename =
++  if not (Filename.is_relative filename) then
++    filename
++  else (
++    let dir = Filename.dirname (absolute_path vmx_filename) in
++    dir // filename
++  )
++
++(* Find all removable disks.
++ *
++ * In the VMX file:
++ *   ide1:0.deviceType = "cdrom-image"
++ *   ide1:0.fileName = "boot.iso"
++ *
++ * XXX This only supports IDE CD-ROMs, but we could support SCSI
++ * CD-ROMs and floppies in future.
++ *)
++and find_removables vmx =
++  let get_ide_controller_target ns =
++    sscanf ns "ide%d:%d" (fun c t -> c, t)
++  in
++  let is_ide_controller_target ns =
++    try ignore (get_ide_controller_target ns); true
++    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
++  in
++  let device_types = [ "atapi-cdrom";
++                       "cdrom-image"; "cdrom-raw" ] in
++
++  (* Find namespaces matching 'ideX:Y' with suitable deviceType. *)
++  let devs =
++    Parse_vmx.select_namespaces (
++      function
++      | [ns] ->
++         (* Check the namespace is 'ideX:Y' *)
++         if not (is_ide_controller_target ns) then false
++         else (
++           (* Check the deviceType is one we are looking for. *)
++           match Parse_vmx.get_string vmx [ns; "deviceType"] with
++           | Some str ->
++              let str = String.lowercase_ascii str in
++              List.mem str device_types
++           | None -> false
++         )
++      | _ -> false
++    ) vmx in
++
++  (* Map the subset to a list of CD-ROMs. *)
++  let devs =
++    Parse_vmx.map (
++      fun path v ->
++        match path, v with
++        | [ns], None ->
++           let c, t = get_ide_controller_target ns in
++           let s = { s_removable_type = CDROM;
++                     s_removable_controller = Some Source_IDE;
++                     s_removable_slot = Some (ide_slot c t) } in
++           Some s
++        | _ -> None
++    ) devs in
++  let devs = filter_map identity devs in
++
++  (* Sort by slot. *)
++  let devs =
++    List.sort
++      (fun { s_removable_slot = s1 } { s_removable_slot = s2 } ->
++        compare s1 s2)
++      devs in
++
++  devs
++
++and ide_slot c t =
++  (* Assuming the old master/slave arrangement. *)
++  c * 2 + t
++
++(* Find all ethernet cards.
++ *
++ * In the VMX file:
++ *   ethernet0.virtualDev = "vmxnet3"
++ *   ethernet0.networkName = "VM Network"
++ *   ethernet0.generatedAddress = "00:01:02:03:04:05"
++ *   ethernet0.connectionType = "bridged" # also: "custom", "nat" or not present
++ *)
++and find_nics vmx =
++  let get_ethernet_port ns =
++    sscanf ns "ethernet%d" (fun p -> p)
++  in
++  let is_ethernet_port ns =
++    try ignore (get_ethernet_port ns); true
++    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
++  in
++
++  (* Find namespaces matching 'ethernetX'. *)
++  let nics =
++    Parse_vmx.select_namespaces (
++      function
++      | [ns] -> is_ethernet_port ns
++      | _ -> false
++    ) vmx in
++
++  (* Map the subset to a list of NICs. *)
++  let nics =
++    Parse_vmx.map (
++      fun path v ->
++        match path, v with
++        | [ns], None ->
++           let port = get_ethernet_port ns in
++           let mac = Parse_vmx.get_string vmx [ns; "generatedAddress"] in
++           let model = Parse_vmx.get_string vmx [ns; "virtualDev"] in
++           let model =
++             match model with
++             | Some m when String.lowercase_ascii m = "e1000" ->
++                Some Source_e1000
++             | Some model ->
++                Some (Source_other_nic (String.lowercase_ascii model))
++             | None -> None in
++           let vnet = Parse_vmx.get_string vmx [ns; "networkName"] in
++           let vnet =
++             match vnet with
++             | Some vnet -> vnet
++             | None -> ns (* "ethernetX" *) in
++           let vnet_type =
++             match Parse_vmx.get_string vmx [ns; "connectionType"] with
++             | Some b when String.lowercase_ascii b = "bridged" ->
++                Bridge
++             | Some _ | None -> Network in
++           Some (port,
++                 { s_mac = mac; s_nic_model = model;
++                   s_vnet = vnet; s_vnet_orig = vnet;
++                   s_vnet_type = vnet_type })
++        | _ -> None
++    ) nics in
++  let nics = filter_map identity nics in
++
++  (* Sort by port. *)
++  let nics = List.sort compare nics in
++
++  let nics = List.map (fun (_, source) -> source) nics in
++  nics
++
++class input_vmx vmx_filename = object
++  inherit input
++
++  method as_options = "-i vmx " ^ vmx_filename
++
++  method source () =
++    (* Parse the VMX file. *)
++    let vmx = Parse_vmx.parse_file vmx_filename in
++
++    let name =
++      match Parse_vmx.get_string vmx ["displayName"] with
++      | None ->
++         warning (f_"no displayName key found in VMX file");
++         name_from_disk vmx_filename
++      | Some s -> s in
++
++    let memory_mb =
++      match Parse_vmx.get_int64 vmx ["memSize"] with
++      | None -> 32_L            (* default is really 32 MB! *)
++      | Some i -> i in
++    let memory = memory_mb *^ 1024L *^ 1024L in
++
++    let vcpu =
++      match Parse_vmx.get_int vmx ["numvcpus"] with
++      | None -> 1
++      | Some i -> i in
++
++    let firmware =
++      match Parse_vmx.get_string vmx ["firmware"] with
++      | None -> BIOS
++      | Some "efi" -> UEFI
++      (* Other values are not documented for this field ... *)
++      | Some fw ->
++         warning (f_"unknown firmware value '%s', assuming BIOS") fw;
++         BIOS in
++
++    let video =
++      if Parse_vmx.namespace_present vmx ["svga"] then
++        (* We could also parse svga.vramSize. *)
++        Some (Source_other_video "vmvga")
++      else
++        None in
++
++    let sound =
++      match Parse_vmx.get_string vmx ["sound"; "virtualDev"] with
++      | Some ("sb16") -> Some { s_sound_model = SB16 }
++      | Some ("es1371") -> Some { s_sound_model = ES1370 (* hmmm ... *) }
++      | Some "hdaudio" -> Some { s_sound_model = ICH6 (* intel-hda *) }
++      | Some model ->
++         warning (f_"unknown sound device '%s' ignored") model;
++         None
++      | None -> None in
++
++    let disks = find_disks vmx vmx_filename in
++    let removables = find_removables vmx in
++    let nics = find_nics vmx in
++
++    let source = {
++      s_hypervisor = VMware;
++      s_name = name;
++      s_orig_name = name;
++      s_memory = memory;
++      s_vcpu = vcpu;
++      s_features = [];
++      s_firmware = firmware;
++      s_display = None;
++      s_video = video;
++      s_sound = sound;
++      s_disks = disks;
++      s_removables = removables;
++      s_nics = nics;
++    } in
++
++    source
++end
++
++let input_vmx = new input_vmx
++let () = Modules_list.register_input_module "vmx"
+diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli
+new file mode 100644
+index 000000000..f236f8716
+--- /dev/null
++++ b/v2v/input_vmx.mli
+@@ -0,0 +1,22 @@
++(* virt-v2v
++ * Copyright (C) 2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *)
++
++(** [-i vmx] source. *)
++
++val input_vmx : string -> Types.input
++(** [input_vmx filename] sets up an input from vmware vmx file. *)
+diff --git a/v2v/name_from_disk.ml b/v2v/name_from_disk.ml
+index 82f09250a..452d9462c 100644
+--- a/v2v/name_from_disk.ml
++++ b/v2v/name_from_disk.ml
+@@ -24,7 +24,7 @@ let name_from_disk disk =
+   (* Remove the extension (or suffix), only if it's one usually
+    * used for disk images. *)
+   let suffixes = [
+-    ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk";
++    ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; ".vmx";
+     "-sda";
+   ] in
+   let rec loop = function
+diff --git a/v2v/parse_vmx.ml b/v2v/parse_vmx.ml
+new file mode 100644
+index 000000000..33ec17d3d
+--- /dev/null
++++ b/v2v/parse_vmx.ml
+@@ -0,0 +1,381 @@
++(* virt-v2v
++ * Copyright (C) 2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *)
++
++open Printf
++
++open Common_utils
++open Common_gettext.Gettext
++
++(* As far as I can tell the VMX format is totally unspecified.
++ * However libvirt has a useful selection of .vmx files in the
++ * sources which explore some of the darker regions of this
++ * format.
++ *
++ * So here are some facts about VMX derived from libvirt and
++ * other places:
++ *
++ * - Keys are compared case insensitively.  We assume here
++ *   that keys are 7-bit ASCII.
++ *
++ * - Multiple keys with the same name are not allowed.
++ *
++ * - Escaping in the value string is possible using a very weird
++ *   escape format: "|22" means the character '\x22'.  To write
++ *   a pipe character you must use "|7C".
++ *
++ * - Boolean values are written "TRUE", "FALSE", "True", "true", etc.
++ *   Because of the quotes they cannot be distinguished from strings.
++ *
++ * - Comments (#...) and blank lines are ignored.  Some files start
++ *   with a hash-bang path, but we ignore those as comments.  This
++ *   parser also ignores any other line which it doesn't understand,
++ *   but will print a warning.
++ *
++ * - Multi-line values are not permitted.
++ *
++ * - Keys are namespaced using dots, eg. scsi0:0.deviceType has
++ *   the namespace "scsi0:0" and the key name "deviceType".
++ *
++ * - Using namespace.present = "FALSE" means that all other keys
++ *   in and under the namespace are ignored.
++ *
++ * - You cannot have a namespace and a key with the same name, eg.
++ *   this is not allowed:
++ *     namespace = "some value"
++ *     namespace.foo = "another value"
++ *
++ * - The Hashicorp packer VMX writer considers some special keys
++ *   as not requiring any quotes around their values, but I'm
++ *   ignoring that for now.
++ *)
++
++(* This VMX file:
++ *
++ *   foo.a = "abc"
++ *   foo.b = "def"
++ *   foo.bar.c = "abc"
++ *   foo.bar.d = "def"
++ *
++ * would be represented by this structure:
++ *
++ *   "foo" => Namespace (             # "foo" is a namespace
++ *              "a" => Key "abc";     # "foo.a" is a key with value "abc"
++ *              "b" => Key "def";
++ *              "bar" => Namespace (  # "foo.bar" is another namespace
++ *                         "c" => Key "abc";
++ *                         "d" => Key "def";
++ *                       )
++ *            )
++ *   ‘( => )’s represent the StringMap type.
++ *)
++type t = key StringMap.t
++
++and key =
++  | Key of string
++  | Namespace of t
++
++let empty = StringMap.empty
++
++(* Compare two trees for equality. *)
++let rec equal vmx1 vmx2 =
++  let cmp k1 k2 =
++    match k1, k2 with
++    | Key v1, Key v2 -> v1 = v2
++    | Key _, Namespace _ -> false
++    | Namespace _, Key _ -> false
++    | Namespace vmx1, Namespace vmx2 -> equal vmx1 vmx2
++  in
++  StringMap.equal cmp vmx1 vmx2
++
++(* Higher-order functions. *)
++let rec select_namespaces pred vmx =
++  _select_namespaces [] pred vmx
++
++and _select_namespaces path pred vmx =
++  StringMap.fold (
++    fun k v new_vmx ->
++      let path = path @ [k] in
++      match v with
++      | Key _ -> new_vmx
++      | Namespace _ when pred path ->
++         StringMap.add k v new_vmx
++      | Namespace t ->
++         let t = _select_namespaces path pred t in
++         if not (equal t empty) then
++           StringMap.add k (Namespace t) new_vmx
++         else
++           new_vmx
++  ) vmx empty
++
++let rec map f vmx =
++  _map [] f vmx
++
++and _map path f vmx =
++  StringMap.fold (
++    fun k v r ->
++      let path = path @ [k] in
++      match v with
++      | Key v -> r @ [ f path (Some v) ]
++      | Namespace t -> r @ [ f path None ] @ _map path f t
++  ) vmx []
++
++let rec namespace_present vmx = function
++  | [] -> false
++  | [ns] ->
++     let ns = String.lowercase_ascii ns in
++     (try
++        let v = StringMap.find ns vmx in
++        match v with
++        | Key _ -> false
++        | Namespace _ -> true
++      with
++        Not_found -> false
++     )
++  | ns :: path ->
++     let ns = String.lowercase_ascii ns in
++     (try
++        let v = StringMap.find ns vmx in
++        match v with
++        | Key _ -> false
++        | Namespace vmx -> namespace_present vmx path
++      with
++        Not_found -> false
++     )
++
++(* Dump the vmx structure to [chan].  Used for debugging. *)
++let rec print chan indent vmx =
++  StringMap.iter (print_key chan indent) vmx
++
++and print_key chan indent k = function
++  | Key v ->
++     output_spaces chan indent;
++     fprintf chan "%s = \"%s\"\n" k v
++  | Namespace vmx ->
++     output_spaces chan indent;
++     fprintf chan "namespace '%s':\n" k;
++     print chan (indent+4) vmx
++
++(* As above, but creates a string instead. *)
++let rec to_string indent vmx =
++  StringMap.fold (fun k v str -> str ^ to_string_key indent k v) vmx ""
++
++and to_string_key indent k = function
++  | Key v ->
++     String.spaces indent ^ sprintf "%s = \"%s\"\n" k v
++  | Namespace vmx ->
++     String.spaces indent ^ sprintf "namespace '%s':\n" k ^
++       to_string (indent+4) vmx
++
++(* Access keys in the tree. *)
++let rec get_string vmx = function
++  | [] -> None
++  | [k] ->
++     let k = String.lowercase_ascii k in
++     (try
++        let v = StringMap.find k vmx in
++        match v with
++        | Key v -> Some v
++        | Namespace _ -> None
++      with Not_found -> None
++     )
++  | ns :: path ->
++     let ns = String.lowercase_ascii ns in
++     (try
++        let v = StringMap.find ns vmx in
++        match v with
++        | Key v -> None
++        | Namespace vmx -> get_string vmx path
++      with
++        Not_found -> None
++     )
++
++let get_int64 vmx path =
++  match get_string vmx path with
++  | None -> None
++  | Some i -> Some (Int64.of_string i)
++
++let get_int vmx path =
++  match get_string vmx path with
++  | None -> None
++  | Some i -> Some (int_of_string i)
++
++let rec get_bool vmx path =
++  match get_string vmx path with
++  | None -> None
++  | Some t -> Some (vmx_bool_of_string t)
++
++and vmx_bool_of_string t =
++  if String.lowercase_ascii t = "true" then true
++  else if String.lowercase_ascii t = "false" then false
++  else failwith "bool_of_string"
++
++(* Regular expression used to match key = "value" in VMX file. *)
++let rex = Str.regexp "^\\([^ \t=]+\\)[ \t]*=[ \t]*\"\\(.*\\)\"$"
++
++(* Remove the weird escapes used in value strings.  See description above. *)
++let remove_vmx_escapes str =
++  let len = String.length str in
++  let out = Bytes.make len '\000' in
++  let j = ref 0 in
++
++  let rec loop i =
++    if i >= len then ()
++    else (
++      let c = String.unsafe_get str i in
++      if i <= len-3 && c = '|' then (
++        let c1 = str.[i+1] and c2 = str.[i+2] in
++        if Char.isxdigit c1 && Char.isxdigit c2 then (
++          let x = Char.hexdigit c1 * 0x10 + Char.hexdigit c2 in
++          Bytes.set out !j (Char.chr x);
++          incr j;
++          loop (i+3)
++        )
++        else (
++          Bytes.set out !j c;
++          incr j;
++          loop (i+1)
++        )
++      )
++      else (
++        Bytes.set out !j c;
++        incr j;
++        loop (i+1)
++      )
++    )
++  in
++  loop 0;
++
++  (* Truncate the output string to its real size and return it
++   * as an immutable string.
++   *)
++  Bytes.sub_string out 0 !j
++
++(* Parsing. *)
++let rec parse_file vmx_filename =
++  (* Read the whole file as a list of lines. *)
++  let str = read_whole_file vmx_filename in
++  if verbose () then eprintf "VMX file:\n%s\n" str;
++  parse_string str
++
++and parse_string str =
++  let lines = String.nsplit "\n" str in
++
++  (* I've never seen any VMX file with CR-LF endings, and VMware
++   * itself is Linux-based, but to be on the safe side ...
++   *)
++  let lines = List.map (String.trimr ~test:((=) '\r')) lines in
++
++  (* Ignore blank lines and comments. *)
++  let lines = List.filter (
++    fun line ->
++      let line = String.triml line in
++      let len = String.length line in
++      len > 0 && line.[0] != '#'
++  ) lines in
++
++  (* Parse the lines into key = "value". *)
++  let lines = filter_map (
++    fun line ->
++      if Str.string_match rex line 0 then (
++        let key = Str.matched_group 1 line in
++        let key = String.lowercase_ascii key in
++        let value = Str.matched_group 2 line in
++        let value = remove_vmx_escapes value in
++        Some (key, value)
++      )
++      else (
++        warning (f_"vmx parser: cannot parse this line, ignoring: %s") line;
++        None
++      )
++  ) lines in
++
++  (* Split the keys into namespace paths. *)
++  let lines =
++    List.map (fun (key, value) -> String.nsplit "." key, value) lines in
++
++  (* Build a tree from the flat list and return it.  This is horribly
++   * inefficient, at least O(n²), possibly even O(n².log n).  Hope
++   * there are no large VMX files!  (XXX)
++   *)
++  let vmx =
++    List.fold_left (
++      fun vmx (path, value) -> insert vmx value path
++    ) empty lines in
++
++  (* If we're verbose, dump the parsed VMX for debugging purposes. *)
++  if verbose () then (
++    eprintf "parsed VMX tree:\n";
++    print stderr 0 vmx
++  );
++
++  (* Drop all present = "FALSE" namespaces. *)
++  let vmx = drop_not_present vmx in
++
++  vmx
++
++and insert vmx value = function
++  | [] -> assert false
++  | [k] ->
++     if StringMap.mem k vmx then (
++       warning (f_"vmx parser: duplicate key '%s' ignored") k;
++       vmx
++     ) else
++       StringMap.add k (Key value) vmx
++  | ns :: path ->
++     let v =
++       try
++         (match StringMap.find ns vmx with
++          | Namespace vmx -> Some vmx
++          | Key _ -> None
++         )
++       with Not_found -> None in
++     let v =
++       match v with
++       | None ->
++          (* Completely new namespace. *)
++          insert empty value path
++       | Some v ->
++          (* Insert the subkey into the previously created namespace. *)
++          insert v value path in
++     StringMap.add ns (Namespace v) vmx
++
++(* Find any "present" keys.  If we find present = "FALSE", then
++ * drop the containing namespace and all subkeys and subnamespaces.
++ *)
++and drop_not_present vmx =
++  StringMap.fold (
++    fun k v new_vmx ->
++      match v with
++      | Key _ ->
++         StringMap.add k v new_vmx
++      | Namespace vmx when contains_key_present_false vmx ->
++         (* drop this namespace and all sub-spaces *)
++         new_vmx
++      | Namespace v ->
++         (* recurse into sub-namespace and do the same check *)
++         let v = drop_not_present v in
++         StringMap.add k (Namespace v) new_vmx
++  ) vmx empty
++
++and contains_key_present_false vmx =
++  try
++    match StringMap.find "present" vmx with
++    | Key v when vmx_bool_of_string v = false -> true
++    | Key _ | Namespace _ -> false
++  with
++    Failure _ | Not_found -> false
+diff --git a/v2v/parse_vmx.mli b/v2v/parse_vmx.mli
+new file mode 100644
+index 000000000..0e4f21f07
+--- /dev/null
++++ b/v2v/parse_vmx.mli
+@@ -0,0 +1,89 @@
++(* virt-v2v
++ * Copyright (C) 2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *)
++
++(** A simple parser for VMware [.vmx] files. *)
++
++type t
++
++val parse_file : string -> t
++(** [parse_file filename] parses a VMX file. *)
++
++val parse_string : string -> t
++(** [parse_string s] parses VMX from a string. *)
++
++val get_string : t -> string list -> string option
++(** Find a key and return it as a string.  If not present, returns [None].
++
++    Note that if [namespace.present = "FALSE"] is found in the file
++    then all keys in [namespace] and below it are ignored.  This
++    applies to all [get_*] functions. *)
++
++val get_int64 : t -> string list -> int64 option
++(** Find a key and return it as an [int64].
++    If not present, returns [None].
++
++    Raises [Failure _] if the key is present but was not parseable
++    as an integer. *)
++
++val get_int : t -> string list -> int option
++(** Find a key and return it as an [int].
++    If not present, returns [None].
++
++    Raises [Failure _] if the key is present but was not parseable
++    as an integer. *)
++
++val get_bool : t -> string list -> bool option
++(** Find a key and return it as a boolean.
++
++    You cannot return [namespace.present = "FALSE"] booleans this way.
++    They are processed by the parser and the namespace and anything
++    below it are removed from the tree.
++
++    Raises [Failure _] if the key is present but was not parseable
++    as a boolean. *)
++
++val namespace_present : t -> string list -> bool
++(** Returns true iff the namespace ({b note:} not key) is present. *)
++
++val select_namespaces : (string list -> bool) -> t -> t
++(** Filter the VMX file, selecting exactly namespaces (and their
++    keys) matching the predicate.  The predicate is a function which
++    is called on each {i namespace} path ({b note:} not on
++    namespace + key paths).  If the predicate matches a
++    namespace, then all sub-namespaces under that namespace are
++    selected implicitly. *)
++
++val map : (string list -> string option -> 'a) -> t -> 'a list
++(** Map all the entries in the VMX file into a list using the
++    map function.  The map function takes two arguments.  The
++    first is the path to the namespace or key, and the second
++    is the key value (or [None] if the path refers to a namespace). *)
++
++val equal : t -> t -> bool
++(** Compare two VMX files for equality.  This is mainly used for
++    testing the parser. *)
++
++val empty : t
++(** An empty VMX file. *)
++
++val print : out_channel -> int -> t -> unit
++(** [print chan indent] prints the VMX file to the output channel.
++    [indent] is the indentation applied to each line of output. *)
++
++val to_string : int -> t -> string
++(** Same as {!print} but it creates a printable (multiline) string. *)
+diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected
+new file mode 100644
+index 000000000..c7ef1f5d5
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-1.expected
+@@ -0,0 +1,39 @@
++[   0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx
++Source guest information (--print-source option):
++
++    source name: BZ1308535_21disks
++hypervisor type: vmware
++         memory: 2147483648 (bytes)
++       nr vCPUs: 1
++   CPU features: 
++       firmware: bios
++        display: 
++          video: vmvga
++          sound: 
++disks:
++	/BZ1308535_21disks.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_1.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_2.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_3.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_4.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_5.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_6.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_7.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_8.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_9.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_10.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_11.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_12.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_13.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_14.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_15.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_16.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_17.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_18.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_19.vmdk (vmdk) [scsi]
++	/BZ1308535_21disks_20.vmdk (vmdk) [scsi]
++removable media:
++	CD-ROM [ide] in slot 2
++NICs:
++	Network "VM Network" mac: 00:0c:29:36:ef:31 [vmxnet3]
++
+diff --git a/v2v/test-v2v-i-vmx-1.vmx b/v2v/test-v2v-i-vmx-1.vmx
+new file mode 100644
+index 000000000..3f2f060a5
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-1.vmx
+@@ -0,0 +1,172 @@
++.encoding = "UTF-8"
++config.version = "8"
++virtualHW.version = "8"
++nvram = "BZ1308535_21disks.nvram"
++pciBridge0.present = "TRUE"
++svga.present = "TRUE"
++pciBridge4.present = "TRUE"
++pciBridge4.virtualDev = "pcieRootPort"
++pciBridge4.functions = "8"
++pciBridge5.present = "TRUE"
++pciBridge5.virtualDev = "pcieRootPort"
++pciBridge5.functions = "8"
++pciBridge6.present = "TRUE"
++pciBridge6.virtualDev = "pcieRootPort"
++pciBridge6.functions = "8"
++pciBridge7.present = "TRUE"
++pciBridge7.virtualDev = "pcieRootPort"
++pciBridge7.functions = "8"
++vmci0.present = "TRUE"
++hpet0.present = "TRUE"
++displayName = "BZ1308535_21disks"
++extendedConfigFile = "BZ1308535_21disks.vmxf"
++virtualHW.productCompatibility = "hosted"
++memSize = "2048"
++sched.cpu.units = "mhz"
++powerType.powerOff = "soft"
++powerType.suspend = "hard"
++powerType.reset = "soft"
++scsi0.virtualDev = "pvscsi"
++scsi0.present = "TRUE"
++scsi1.virtualDev = "pvscsi"
++scsi1.present = "TRUE"
++ide1:0.deviceType = "cdrom-image"
++ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso"
++ide1:0.present = "TRUE"
++floppy0.startConnected = "FALSE"
++floppy0.clientDevice = "TRUE"
++floppy0.fileName = "vmware-null-remote-floppy"
++ethernet0.virtualDev = "vmxnet3"
++ethernet0.networkName = "VM Network"
++ethernet0.addressType = "generated"
++ethernet0.present = "TRUE"
++scsi0:0.deviceType = "scsi-hardDisk"
++scsi0:0.fileName = "BZ1308535_21disks.vmdk"
++scsi0:0.present = "TRUE"
++scsi0:1.deviceType = "scsi-hardDisk"
++scsi0:1.fileName = "BZ1308535_21disks_1.vmdk"
++scsi0:1.present = "TRUE"
++scsi0:2.deviceType = "scsi-hardDisk"
++scsi0:2.fileName = "BZ1308535_21disks_2.vmdk"
++scsi0:2.present = "TRUE"
++scsi0:3.deviceType = "scsi-hardDisk"
++scsi0:3.fileName = "BZ1308535_21disks_3.vmdk"
++scsi0:3.present = "TRUE"
++scsi0:4.deviceType = "scsi-hardDisk"
++scsi0:4.fileName = "BZ1308535_21disks_4.vmdk"
++scsi0:4.present = "TRUE"
++scsi0:5.deviceType = "scsi-hardDisk"
++scsi0:5.fileName = "BZ1308535_21disks_5.vmdk"
++scsi0:5.present = "TRUE"
++scsi0:6.deviceType = "scsi-hardDisk"
++scsi0:6.fileName = "BZ1308535_21disks_6.vmdk"
++scsi0:6.present = "TRUE"
++scsi0:8.deviceType = "scsi-hardDisk"
++scsi0:8.fileName = "BZ1308535_21disks_7.vmdk"
++scsi0:8.present = "TRUE"
++scsi0:9.deviceType = "scsi-hardDisk"
++scsi0:9.fileName = "BZ1308535_21disks_8.vmdk"
++scsi0:9.present = "TRUE"
++scsi0:10.deviceType = "scsi-hardDisk"
++scsi0:10.fileName = "BZ1308535_21disks_9.vmdk"
++scsi0:10.present = "TRUE"
++scsi0:11.deviceType = "scsi-hardDisk"
++scsi0:11.fileName = "BZ1308535_21disks_10.vmdk"
++scsi0:11.present = "TRUE"
++scsi0:12.deviceType = "scsi-hardDisk"
++scsi0:12.fileName = "BZ1308535_21disks_11.vmdk"
++scsi0:12.present = "TRUE"
++scsi0:13.deviceType = "scsi-hardDisk"
++scsi0:13.fileName = "BZ1308535_21disks_12.vmdk"
++scsi0:13.present = "TRUE"
++scsi0:14.deviceType = "scsi-hardDisk"
++scsi0:14.fileName = "BZ1308535_21disks_13.vmdk"
++scsi0:14.present = "TRUE"
++scsi0:15.deviceType = "scsi-hardDisk"
++scsi0:15.fileName = "BZ1308535_21disks_14.vmdk"
++scsi0:15.present = "TRUE"
++scsi1:0.deviceType = "scsi-hardDisk"
++scsi1:0.fileName = "BZ1308535_21disks_15.vmdk"
++scsi1:0.present = "TRUE"
++scsi1:1.deviceType = "scsi-hardDisk"
++scsi1:1.fileName = "BZ1308535_21disks_16.vmdk"
++scsi1:1.present = "TRUE"
++scsi1:2.deviceType = "scsi-hardDisk"
++scsi1:2.fileName = "BZ1308535_21disks_17.vmdk"
++scsi1:2.present = "TRUE"
++scsi1:3.deviceType = "scsi-hardDisk"
++scsi1:3.fileName = "BZ1308535_21disks_18.vmdk"
++scsi1:3.present = "TRUE"
++scsi1:4.deviceType = "scsi-hardDisk"
++scsi1:4.fileName = "BZ1308535_21disks_19.vmdk"
++scsi1:4.present = "TRUE"
++scsi1:5.deviceType = "scsi-hardDisk"
++scsi1:5.fileName = "BZ1308535_21disks_20.vmdk"
++scsi1:5.present = "TRUE"
++guestOS = "rhel6-64"
++toolScripts.afterPowerOn = "TRUE"
++toolScripts.afterResume = "TRUE"
++toolScripts.beforeSuspend = "TRUE"
++toolScripts.beforePowerOff = "TRUE"
++uuid.bios = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31"
++uuid.location = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31"
++vc.uuid = "52 31 cb fc c1 3f 96 32-83 c0 bb 70 6c 90 5c fd"
++chipset.onlineStandby = "FALSE"
++sched.cpu.min = "0"
++sched.cpu.shares = "normal"
++sched.mem.min = "0"
++sched.mem.minSize = "0"
++sched.mem.shares = "normal"
++svga.vramSize = "8388608"
++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/BZ1308535_21disks/BZ1308535_21disks-6a024f8a.vswp"
++replay.supported = "FALSE"
++replay.filename = ""
++scsi0:0.redo = ""
++scsi0:1.redo = ""
++scsi0:2.redo = ""
++scsi0:3.redo = ""
++scsi0:4.redo = ""
++scsi0:5.redo = ""
++scsi0:6.redo = ""
++scsi0:8.redo = ""
++scsi0:9.redo = ""
++scsi0:10.redo = ""
++scsi0:11.redo = ""
++scsi0:12.redo = ""
++scsi0:13.redo = ""
++scsi0:14.redo = ""
++scsi0:15.redo = ""
++scsi1:0.redo = ""
++scsi1:1.redo = ""
++scsi1:2.redo = ""
++scsi1:3.redo = ""
++scsi1:4.redo = ""
++scsi1:5.redo = ""
++pciBridge0.pciSlotNumber = "17"
++pciBridge4.pciSlotNumber = "21"
++pciBridge5.pciSlotNumber = "22"
++pciBridge6.pciSlotNumber = "23"
++pciBridge7.pciSlotNumber = "24"
++scsi0.pciSlotNumber = "160"
++scsi1.pciSlotNumber = "192"
++ethernet0.pciSlotNumber = "224"
++vmci0.pciSlotNumber = "32"
++scsi0.sasWWID = "50 05 05 6f e6 46 bd 80"
++scsi1.sasWWID = "50 05 05 6f e6 46 bc 80"
++ethernet0.generatedAddress = "00:0c:29:36:ef:31"
++ethernet0.generatedAddressOffset = "0"
++vmci0.id = "2000088881"
++hostCPUID.0 = "0000000d756e65476c65746e49656e69"
++hostCPUID.1 = "000206a700100800179ae3bfbfebfbff"
++hostCPUID.80000001 = "00000000000000000000000128100800"
++guestCPUID.0 = "0000000d756e65476c65746e49656e69"
++guestCPUID.1 = "000206a700010800969822030fabfbff"
++guestCPUID.80000001 = "00000000000000000000000128100800"
++userCPUID.0 = "0000000d756e65476c65746e49656e69"
++userCPUID.1 = "000206a700100800169822030fabfbff"
++userCPUID.80000001 = "00000000000000000000000128100800"
++evcCompatibilityMode = "FALSE"
++vmotion.checkpointFBSize = "8388608"
++cleanShutdown = "TRUE"
++softPowerOff = "TRUE"
++tools.remindInstall = "TRUE"
+diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected
+new file mode 100644
+index 000000000..a04bd0f62
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-2.expected
+@@ -0,0 +1,19 @@
++[   0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx
++Source guest information (--print-source option):
++
++    source name: Fedora 20
++hypervisor type: vmware
++         memory: 2147483648 (bytes)
++       nr vCPUs: 1
++   CPU features: 
++       firmware: bios
++        display: 
++          video: vmvga
++          sound: 
++disks:
++	/Fedora 20.vmdk (vmdk) [scsi]
++removable media:
++
++NICs:
++	Network "VM Network" mac: 00:50:56:9b:5f:0d [vmxnet3]
++
+diff --git a/v2v/test-v2v-i-vmx-2.vmx b/v2v/test-v2v-i-vmx-2.vmx
+new file mode 100644
+index 000000000..d9dcf3a5c
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-2.vmx
+@@ -0,0 +1,84 @@
++.encoding = "UTF-8"
++config.version = "8"
++virtualHW.version = "10"
++nvram = "Fedora 20.nvram"
++pciBridge0.present = "TRUE"
++svga.present = "TRUE"
++pciBridge4.present = "TRUE"
++pciBridge4.virtualDev = "pcieRootPort"
++pciBridge4.functions = "8"
++pciBridge5.present = "TRUE"
++pciBridge5.virtualDev = "pcieRootPort"
++pciBridge5.functions = "8"
++pciBridge6.present = "TRUE"
++pciBridge6.virtualDev = "pcieRootPort"
++pciBridge6.functions = "8"
++pciBridge7.present = "TRUE"
++pciBridge7.virtualDev = "pcieRootPort"
++pciBridge7.functions = "8"
++vmci0.present = "TRUE"
++hpet0.present = "TRUE"
++displayName = "Fedora 20"
++extendedConfigFile = "Fedora 20.vmxf"
++virtualHW.productCompatibility = "hosted"
++svga.vramSize = "8388608"
++memSize = "2048"
++sched.cpu.units = "mhz"
++sched.cpu.affinity = "all"
++powerType.powerOff = "soft"
++powerType.suspend = "hard"
++powerType.reset = "soft"
++scsi0.virtualDev = "pvscsi"
++scsi0.present = "TRUE"
++sata0.present = "TRUE"
++scsi0:0.deviceType = "scsi-hardDisk"
++scsi0:0.fileName = "Fedora 20.vmdk"
++sched.scsi0:0.shares = "normal"
++sched.scsi0:0.throughputCap = "off"
++scsi0:0.present = "TRUE"
++ethernet0.virtualDev = "vmxnet3"
++ethernet0.networkName = "VM Network"
++ethernet0.addressType = "vpx"
++ethernet0.generatedAddress = "00:50:56:9b:5f:0d"
++ethernet0.present = "TRUE"
++sata0:0.startConnected = "FALSE"
++sata0:0.deviceType = "cdrom-image"
++sata0:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/Fedora-20-x86_64-netinst.iso"
++sata0:0.present = "TRUE"
++floppy0.startConnected = "FALSE"
++floppy0.clientDevice = "TRUE"
++floppy0.fileName = "vmware-null-remote-floppy"
++vmci.filter.enable = "TRUE"
++guestOS = "rhel7-64"
++toolScripts.afterPowerOn = "TRUE"
++toolScripts.afterResume = "TRUE"
++toolScripts.beforeSuspend = "TRUE"
++toolScripts.beforePowerOff = "TRUE"
++uuid.bios = "42 1b 4b 87 e6 b7 d8 81-07 a0 c9 d2 21 cd 3c 6b"
++vc.uuid = "50 1b 1f 1b 73 00 32 bf-93 a1 1c b2 b4 e6 17 d6"
++sched.cpu.min = "0"
++sched.cpu.shares = "normal"
++sched.mem.min = "0"
++sched.mem.minSize = "0"
++sched.mem.shares = "normal"
++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Fedora 20/Fedora 20-c71e4118.vswp"
++uuid.location = "56 4d 0f 53 00 63 d5 55-41 01 4c f7 55 ce 03 0e"
++replay.supported = "TRUE"
++replay.filename = ""
++scsi0:0.redo = ""
++pciBridge0.pciSlotNumber = "17"
++pciBridge4.pciSlotNumber = "21"
++pciBridge5.pciSlotNumber = "22"
++pciBridge6.pciSlotNumber = "23"
++pciBridge7.pciSlotNumber = "24"
++scsi0.pciSlotNumber = "160"
++ethernet0.pciSlotNumber = "192"
++vmci0.pciSlotNumber = "32"
++sata0.pciSlotNumber = "33"
++scsi0.sasWWID = "50 05 05 67 e6 b7 d8 80"
++vmci0.id = "567098475"
++vmotion.checkpointFBSize = "8388608"
++cleanShutdown = "TRUE"
++softPowerOff = "TRUE"
++sata0:0.allowGuestConnectionControl = "TRUE"
++tools.syncTime = "FALSE"
+diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected
+new file mode 100644
+index 000000000..64808a77b
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-3.expected
+@@ -0,0 +1,19 @@
++[   0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx
++Source guest information (--print-source option):
++
++    source name: RHEL 7.1 UEFI
++hypervisor type: vmware
++         memory: 2147483648 (bytes)
++       nr vCPUs: 1
++   CPU features: 
++       firmware: uefi
++        display: 
++          video: vmvga
++          sound: 
++disks:
++	/RHEL 7.1 UEFI.vmdk (vmdk) [scsi]
++removable media:
++	CD-ROM [ide] in slot 2
++NICs:
++	Network "VM Network" mac: 00:0c:29:4b:2b:8c [vmxnet3]
++
+diff --git a/v2v/test-v2v-i-vmx-3.vmx b/v2v/test-v2v-i-vmx-3.vmx
+new file mode 100644
+index 000000000..c39215555
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-3.vmx
+@@ -0,0 +1,91 @@
++.encoding = "UTF-8"
++config.version = "8"
++virtualHW.version = "8"
++nvram = "RHEL 7.1 UEFI.nvram"
++pciBridge0.present = "TRUE"
++svga.present = "TRUE"
++pciBridge4.present = "TRUE"
++pciBridge4.virtualDev = "pcieRootPort"
++pciBridge4.functions = "8"
++pciBridge5.present = "TRUE"
++pciBridge5.virtualDev = "pcieRootPort"
++pciBridge5.functions = "8"
++pciBridge6.present = "TRUE"
++pciBridge6.virtualDev = "pcieRootPort"
++pciBridge6.functions = "8"
++pciBridge7.present = "TRUE"
++pciBridge7.virtualDev = "pcieRootPort"
++pciBridge7.functions = "8"
++vmci0.present = "TRUE"
++hpet0.present = "TRUE"
++displayName = "RHEL 7.1 UEFI"
++extendedConfigFile = "RHEL 7.1 UEFI.vmxf"
++virtualHW.productCompatibility = "hosted"
++memSize = "2048"
++firmware = "efi"
++sched.cpu.units = "mhz"
++powerType.powerOff = "soft"
++powerType.suspend = "hard"
++powerType.reset = "soft"
++scsi0.virtualDev = "pvscsi"
++scsi0.present = "TRUE"
++ide1:0.startConnected = "FALSE"
++ide1:0.deviceType = "cdrom-image"
++ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso"
++ide1:0.present = "TRUE"
++floppy0.startConnected = "FALSE"
++floppy0.clientDevice = "TRUE"
++floppy0.fileName = "vmware-null-remote-floppy"
++ethernet0.virtualDev = "vmxnet3"
++ethernet0.networkName = "VM Network"
++ethernet0.addressType = "generated"
++ethernet0.present = "TRUE"
++scsi0:0.deviceType = "scsi-hardDisk"
++scsi0:0.fileName = "RHEL 7.1 UEFI.vmdk"
++scsi0:0.present = "TRUE"
++guestOS = "rhel6-64"
++toolScripts.afterPowerOn = "TRUE"
++toolScripts.afterResume = "TRUE"
++toolScripts.beforeSuspend = "TRUE"
++toolScripts.beforePowerOff = "TRUE"
++uuid.bios = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c"
++uuid.location = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c"
++vc.uuid = "52 3f 29 10 d3 81 16 43-fa b0 e3 af 3b ba 36 e5"
++chipset.onlineStandby = "FALSE"
++sched.cpu.min = "0"
++sched.cpu.shares = "normal"
++sched.mem.min = "0"
++sched.mem.minSize = "0"
++sched.mem.shares = "normal"
++svga.vramSize = "8388608"
++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/RHEL 7.1 UEFI/RHEL 7.1 UEFI-58ff6e6f.vswp"
++replay.supported = "FALSE"
++replay.filename = ""
++scsi0:0.redo = ""
++pciBridge0.pciSlotNumber = "17"
++pciBridge4.pciSlotNumber = "21"
++pciBridge5.pciSlotNumber = "22"
++pciBridge6.pciSlotNumber = "23"
++pciBridge7.pciSlotNumber = "24"
++scsi0.pciSlotNumber = "160"
++ethernet0.pciSlotNumber = "192"
++vmci0.pciSlotNumber = "32"
++scsi0.sasWWID = "50 05 05 69 a7 21 91 00"
++ethernet0.generatedAddress = "00:0c:29:4b:2b:8c"
++ethernet0.generatedAddressOffset = "0"
++vmci0.id = "-716493940"
++hostCPUID.0 = "0000000d756e65476c65746e49656e69"
++hostCPUID.1 = "000206a700100800179ae3bfbfebfbff"
++hostCPUID.80000001 = "00000000000000000000000128100800"
++guestCPUID.0 = "0000000d756e65476c65746e49656e69"
++guestCPUID.1 = "000206a700010800969822030fabfbff"
++guestCPUID.80000001 = "00000000000000000000000128100800"
++userCPUID.0 = "0000000d756e65476c65746e49656e69"
++userCPUID.1 = "000206a700100800169822030fabfbff"
++userCPUID.80000001 = "00000000000000000000000128100800"
++evcCompatibilityMode = "FALSE"
++vmotion.checkpointFBSize = "8388608"
++cleanShutdown = "TRUE"
++softPowerOff = "TRUE"
++ide1:0.allowGuestConnectionControl = "TRUE"
++tools.syncTime = "FALSE"
+diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected
+new file mode 100644
+index 000000000..208920b29
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-4.expected
+@@ -0,0 +1,19 @@
++[   0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx
++Source guest information (--print-source option):
++
++    source name: Windows 7 x64
++hypervisor type: vmware
++         memory: 2147483648 (bytes)
++       nr vCPUs: 1
++   CPU features: 
++       firmware: bios
++        display: 
++          video: vmvga
++          sound: 
++disks:
++	/Windows 7 x64.vmdk (vmdk) [scsi]
++removable media:
++	CD-ROM [ide] in slot 2
++NICs:
++	Network "VM Network" mac: 00:0c:29:94:89:23 [e1000]
++
+diff --git a/v2v/test-v2v-i-vmx-4.vmx b/v2v/test-v2v-i-vmx-4.vmx
+new file mode 100644
+index 000000000..7756cf248
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-4.vmx
+@@ -0,0 +1,88 @@
++.encoding = "UTF-8"
++config.version = "8"
++virtualHW.version = "8"
++nvram = "Windows 7 x64.nvram"
++pciBridge0.present = "TRUE"
++svga.present = "TRUE"
++pciBridge4.present = "TRUE"
++pciBridge4.virtualDev = "pcieRootPort"
++pciBridge4.functions = "8"
++pciBridge5.present = "TRUE"
++pciBridge5.virtualDev = "pcieRootPort"
++pciBridge5.functions = "8"
++pciBridge6.present = "TRUE"
++pciBridge6.virtualDev = "pcieRootPort"
++pciBridge6.functions = "8"
++pciBridge7.present = "TRUE"
++pciBridge7.virtualDev = "pcieRootPort"
++pciBridge7.functions = "8"
++vmci0.present = "TRUE"
++hpet0.present = "TRUE"
++displayName = "Windows 7 x64"
++extendedConfigFile = "Windows 7 x64.vmxf"
++virtualHW.productCompatibility = "hosted"
++memSize = "2048"
++sched.cpu.units = "mhz"
++powerType.powerOff = "soft"
++powerType.suspend = "hard"
++powerType.reset = "soft"
++scsi0.virtualDev = "lsisas1068"
++scsi0.present = "TRUE"
++ide1:0.deviceType = "cdrom-image"
++ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso"
++ide1:0.present = "TRUE"
++floppy0.startConnected = "FALSE"
++floppy0.clientDevice = "TRUE"
++floppy0.fileName = "vmware-null-remote-floppy"
++ethernet0.virtualDev = "e1000"
++ethernet0.networkName = "VM Network"
++ethernet0.addressType = "generated"
++ethernet0.present = "TRUE"
++scsi0:0.deviceType = "scsi-hardDisk"
++scsi0:0.fileName = "Windows 7 x64.vmdk"
++scsi0:0.present = "TRUE"
++guestOS = "windows7-64"
++toolScripts.afterPowerOn = "TRUE"
++toolScripts.afterResume = "TRUE"
++toolScripts.beforeSuspend = "TRUE"
++toolScripts.beforePowerOff = "TRUE"
++uuid.bios = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23"
++uuid.location = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23"
++vc.uuid = "52 7a 63 e1 2c 2f 50 46-91 66 3a e8 fa f9 c4 65"
++chipset.onlineStandby = "FALSE"
++sched.cpu.min = "0"
++sched.cpu.shares = "normal"
++sched.mem.min = "0"
++sched.mem.minSize = "0"
++sched.mem.shares = "normal"
++svga.vramSize = "8388608"
++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Windows 7 x64/Windows 7 x64-8e3b0929.vswp"
++replay.supported = "FALSE"
++replay.filename = ""
++scsi0:0.redo = ""
++pciBridge0.pciSlotNumber = "17"
++pciBridge4.pciSlotNumber = "21"
++pciBridge5.pciSlotNumber = "22"
++pciBridge6.pciSlotNumber = "23"
++pciBridge7.pciSlotNumber = "24"
++scsi0.pciSlotNumber = "160"
++ethernet0.pciSlotNumber = "32"
++vmci0.pciSlotNumber = "33"
++scsi0.sasWWID = "50 05 05 6a 63 a5 a8 30"
++ethernet0.generatedAddress = "00:0c:29:94:89:23"
++ethernet0.generatedAddressOffset = "0"
++vmci0.id = "496273699"
++hostCPUID.0 = "0000000b756e65476c65746e49656e69"
++hostCPUID.1 = "000206c220200800029ee3ffbfebfbff"
++hostCPUID.80000001 = "0000000000000000000000012c100800"
++guestCPUID.0 = "0000000b756e65476c65746e49656e69"
++guestCPUID.1 = "000206c200010800829822030fabfbff"
++guestCPUID.80000001 = "00000000000000000000000128100800"
++userCPUID.0 = "0000000b756e65476c65746e49656e69"
++userCPUID.1 = "000206c220200800029822030fabfbff"
++userCPUID.80000001 = "00000000000000000000000128100800"
++evcCompatibilityMode = "FALSE"
++vmotion.checkpointFBSize = "8388608"
++cleanShutdown = "TRUE"
++softPowerOff = "TRUE"
++tools.remindInstall = "TRUE"
+diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh
+new file mode 100755
+index 000000000..5353e7e2a
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx.sh
+@@ -0,0 +1,48 @@
++#!/bin/bash -
++# libguestfs virt-v2v test script
++# Copyright (C) 2017 Red Hat Inc.
++#
++# 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 2 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, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++
++# Test -i ova option.
++
++set -e
++
++$TEST_FUNCTIONS
++skip_if_skipped
++skip_if_backend uml
++
++export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools"
++export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
++
++rm -f test-v2v-i-vmx-*.actual
++
++for i in 1 2 3 4; do
++    $VG virt-v2v --debug-gc \
++        -i vmx test-v2v-i-vmx-$i.vmx \
++        --print-source > test-v2v-i-vmx-$i.actual
++
++    # Normalize the print-source output.
++    mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old
++    sed \
++        -e "s,$(pwd),," \
++        < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual
++    rm test-v2v-i-vmx-$i.actual.old
++
++    # Check the output.
++    diff -u test-v2v-i-vmx-$i.expected test-v2v-i-vmx-$i.actual
++done
++
++rm test-v2v-i-vmx-*.actual
+diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml
+index 873610a7c..1b4332a9e 100644
+--- a/v2v/v2v_unit_tests.ml
++++ b/v2v/v2v_unit_tests.ml
+@@ -787,6 +787,148 @@ let test_qemu_img_supports ctx =
+    *)
+   ignore (Utils.qemu_img_supports_offset_and_size ())
+ 
++(* Test the VMX file parser in the Parse_vmx module. *)
++let test_vmx_parse_string ctx =
++  let cmp = Parse_vmx.equal in
++  let printer = Parse_vmx.to_string 0 in
++
++  (* This should be identical to the empty file. *)
++  let t = Parse_vmx.parse_string "\
++test.foo = \"a\"
++test.bar = \"b\"
++test.present = \"FALSE\"
++" in
++  assert_equal ~cmp ~printer Parse_vmx.empty t;
++
++  (* Test weird escapes. *)
++  let t1 = Parse_vmx.parse_string "\
++foo = \"a|20|21b\"
++" in
++  let t2 = Parse_vmx.parse_string "\
++foo = \"a !b\"
++" in
++  assert_equal ~cmp ~printer t1 t2;
++
++  (* Test case insensitivity. *)
++  let t1 = Parse_vmx.parse_string "\
++foo = \"abc\"
++" in
++  let t2 = Parse_vmx.parse_string "\
++fOO = \"abc\"
++" in
++  assert_equal ~cmp ~printer t1 t2;
++  let t = Parse_vmx.parse_string "\
++flag = \"true\"
++" in
++  assert_bool "parse_vmx: failed case insensitivity test for booleans #1"
++              (Parse_vmx.get_bool t ["FLAG"] = Some true);
++  let t = Parse_vmx.parse_string "\
++flag = \"TRUE\"
++" in
++  assert_bool "parse_vmx: failed case insensitivity test for booleans #2"
++              (Parse_vmx.get_bool t ["Flag"] = Some true);
++
++  (* Missing keys. *)
++  let t = Parse_vmx.parse_string "\
++foo = \"a\"
++" in
++  assert_bool "parse_vmx: failed missing key test"
++              (Parse_vmx.get_string t ["bar"] = None);
++
++  (* namespace_present function *)
++  let t = Parse_vmx.parse_string "\
++foo.bar.present = \"TRUE\"
++foo.baz.present = \"FALSE\"
++foo.a.b = \"abc\"
++foo.a.c = \"abc\"
++foo.b = \"abc\"
++foo.c.a = \"abc\"
++foo.c.b = \"abc\"
++" in
++ assert_bool "parse_vmx: namespace_present #1"
++             (Parse_vmx.namespace_present t ["foo"] = true);
++ assert_bool "parse_vmx: namespace_present #2"
++             (Parse_vmx.namespace_present t ["foo"; "bar"] = true);
++ assert_bool "parse_vmx: namespace_present #3"
++             (* this whole namespace should have been culled *)
++             (Parse_vmx.namespace_present t ["foo"; "baz"] = false);
++ assert_bool "parse_vmx: namespace_present #4"
++             (Parse_vmx.namespace_present t ["foo"; "a"] = true);
++ assert_bool "parse_vmx: namespace_present #5"
++             (* this is a key, not a namespace *)
++             (Parse_vmx.namespace_present t ["foo"; "a"; "b"] = false);
++ assert_bool "parse_vmx: namespace_present #6"
++             (Parse_vmx.namespace_present t ["foo"; "b"] = false);
++ assert_bool "parse_vmx: namespace_present #7"
++             (Parse_vmx.namespace_present t ["foo"; "c"] = true);
++ assert_bool "parse_vmx: namespace_present #8"
++             (Parse_vmx.namespace_present t ["foo"; "d"] = false);
++
++ (* map function *)
++  let t = Parse_vmx.parse_string "\
++foo.bar.present = \"TRUE\"
++foo.baz.present = \"FALSE\"
++foo.a.b = \"abc\"
++foo.a.c = \"abc\"
++foo.b = \"abc\"
++foo.c.a = \"abc\"
++foo.c.b = \"abc\"
++" in
++  let xs =
++    Parse_vmx.map (
++      fun path ->
++        let path = String.concat "." path in
++        function
++        | None -> sprintf "%s.present = \"true\"\n" path
++        | Some v -> sprintf "%s = \"%s\"\n" path v
++    ) t in
++  let xs = List.sort compare xs in
++  let s = String.concat "" xs in
++  assert_equal ~printer:identity "\
++foo.a.b = \"abc\"
++foo.a.c = \"abc\"
++foo.a.present = \"true\"
++foo.b = \"abc\"
++foo.bar.present = \"TRUE\"
++foo.bar.present = \"true\"
++foo.c.a = \"abc\"
++foo.c.b = \"abc\"
++foo.c.present = \"true\"
++foo.present = \"true\"
++" s;
++
++  (* select_namespaces function *)
++  let t1 = Parse_vmx.parse_string "\
++foo.bar.present = \"TRUE\"
++foo.a.b = \"abc\"
++foo.a.c = \"abc\"
++foo.b = \"abc\"
++foo.c.a = \"abc\"
++foo.c.b = \"abc\"
++" in
++  let t2 =
++    Parse_vmx.select_namespaces
++      (function ["foo"] -> true | _ -> false) t1 in
++  assert_equal ~cmp ~printer t1 t2;
++
++  let t1 = Parse_vmx.parse_string "\
++foo.bar.present = \"TRUE\"
++foo.a.b = \"abc\"
++foo.a.c = \"abc\"
++foo.b = \"abc\"
++foo.c.a = \"abc\"
++foo.c.b = \"abc\"
++foo.c.c.d.e.f = \"abc\"
++" in
++  let t1 =
++    Parse_vmx.select_namespaces
++      (function ["foo"; "a"] -> true | _ -> false) t1 in
++  let t2 = Parse_vmx.parse_string "\
++foo.a.b = \"abc\"
++foo.a.c = \"abc\"
++" in
++  assert_equal ~cmp ~printer t2 t1
++
+ (* Suites declaration. *)
+ let suite =
+   "virt-v2v" >:::
+@@ -798,6 +940,7 @@ let suite =
+         test_virtio_iso_path_matches_guest_os;
+       "Utils.shell_unquote" >:: test_shell_unquote;
+       "Utils.qemu_img_supports" >:: test_qemu_img_supports;
++      "Parse_vmx.parse_string" >::test_vmx_parse_string;
+     ]
+ 
+ let () =
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 709075fba..7ed5c5d86 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -41,7 +41,8 @@ libguestfs E<ge> 1.28.
+  ... ───▶│  (default) │   │            │ ──┐ └────────────┘
+          └────────────┘   │            │ ─┐└──────▶ -o glance
+  -i libvirtxml ─────────▶ │            │ ┐└─────────▶ -o rhv
+-                          └────────────┘ └──────────▶ -o vdsm
++ -i vmx ────────────────▶ │            │ └──────────▶ -o vdsm
++                          └────────────┘
+ 
+ Virt-v2v has a number of possible input and output modes, selected
+ using the I<-i> and I<-o> options.  Only one input and output mode can
+@@ -60,6 +61,8 @@ method used by L<virt-p2v(1)> behind the scenes.
+ 
+ I<-i ova> is used for reading from a VMware ova source file.
+ 
++I<-i vmx> is used for reading from a VMware vmx file.
++
+ I<-o glance> is used for writing to OpenStack Glance.
+ 
+ I<-o libvirt> is used for writing to any libvirt target.  Libvirt can
+@@ -228,6 +231,14 @@ ova manifest file and check the vmdk volumes for validity (checksums)
+ as well as analyzing the ovf file, and then convert the guest.  See
+ L</INPUT FROM VMWARE OVA> below
+ 
++=item B<-i> B<vmx>
++
++Set the input method to I<vmx>.
++
++In this mode you can read a VMware vmx file directly.  This is useful
++when VMware VMs are stored on an NFS server which you can mount
++directly.  See L</INPUT FROM VMWARE VMX> below
++
+ =item B<-ic> libvirtURI
+ 
+ Specify a libvirt connection URI to use when reading the guest.  This
+@@ -859,9 +870,10 @@ I<--bridge> option instead.  For example:
+ 
+ Virt-v2v is able to import guests from VMware vCenter Server.
+ 
+-vCenter E<ge> 5.0 is required.  If you don't have vCenter, using OVA
+-is recommended instead (see L</INPUT FROM VMWARE OVA> below), or if
+-that is not possible then see L</INPUT FROM VMWARE ESXi HYPERVISOR>.
++vCenter E<ge> 5.0 is required.  If you don’t have vCenter, using OVA
++or VMX is recommended instead (see L</INPUT FROM VMWARE OVA> and/or
++L</INPUT FROM VMWARE VMX> below), or if that is not possible then see
++L</INPUT FROM VMWARE ESXi HYPERVISOR>.
+ 
+ Virt-v2v uses libvirt for access to vCenter, and therefore the input
+ mode should be I<-i libvirt>.  As this is the default, you don't need
+@@ -1132,12 +1144,58 @@ directory containing the files:
+ 
+  $ virt-v2v -i ova /path/to/files -o local -os /var/tmp
+ 
++=head1 INPUT FROM VMWARE VMX
++
++Virt-v2v is able to import guests from VMware’s vmx files.  This is
++useful where VMware virtual machines are stored on a separate NFS
++server and you are able to mount the NFS storage directly.
++
++If you find a folder of files called F<I<guest>.vmx>,
++F<I<guest>.vmxf>, F<I<guest>.nvram> and one or more F<.vmdk> disk
++images, then you can use this method.
++
++=head2 VMX: REMOVE VMWARE TOOLS FROM WINDOWS GUESTS
++
++For Windows guests, you should remove VMware tools before conversion.
++Although this is not strictly necessary, and the guest will still be
++able to run, if you don't do this then the converted guest will
++complain on every boot.  The tools cannot be removed after conversion
++because the uninstaller checks if it is running on VMware and refuses
++to start (which is also the reason that virt-v2v cannot remove them).
++
++This is not necessary for Linux guests, as virt-v2v is able to remove
++VMware tools.
++
++=head2 VMX: GUEST MUST BE SHUT DOWN
++
++B<The guest must be shut down before conversion starts>.  If you don't
++shut it down, you will end up with a corrupted VM disk on the target.
++With other methods, virt-v2v tries to prevent concurrent access, but
++because the I<-i vmx> method works directly against the storage,
++checking for concurrent access is not possible.
++
++=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER
++
++Virt-v2v must be able to access the F<.vmx> file and any local
++F<.vmdk> disks.  Normally this means you must mount the NFS storage
++containing these files.
++
++=head2 VMX: IMPORTING A GUEST
++
++To import a vmx file, do:
++
++ $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp
++
++Virt-v2v processes the vmx file and uses it to find the location of
++any vmdk disks.
++
+ =head1 INPUT FROM VMWARE ESXi HYPERVISOR
+ 
+ Virt-v2v cannot access an ESXi hypervisor directly.  You should use
+-the OVA method above (see L</INPUT FROM VMWARE OVA>) if possible, as
+-it is much faster and requires much less disk space than the method
+-described in this section.
++the OVA or VMX methods above (see L</INPUT FROM VMWARE OVA> and/or
++L</INPUT FROM VMWARE VMX>) if possible, as it is much faster and
++requires much less disk space than the method described in this
++section.
+ 
+ You can use the L<virt-v2v-copy-to-local(1)> tool to copy the guest
+ off the hypervisor into a local file, and then convert it.
+-- 
+2.14.3
+
diff --git a/SOURCES/0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch b/SOURCES/0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch
deleted file mode 100644
index 5227af2..0000000
--- a/SOURCES/0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 2fd825ed1984d761697f0b8814c425e69ff31719 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 30 Mar 2017 19:34:29 +0100
-Subject: [PATCH] p2v: tests: Fix fake scp command so it can handle multiple
- local files.
-
-Fixes commit d178deeeb814471b9d70431626b6cd515a21d0c1.
-
-(cherry picked from commit b417c877f4ea848af8f8538957ab677c65637027)
----
- p2v/test-virt-p2v-scp.sh | 16 ++++++++++------
- 1 file changed, 10 insertions(+), 6 deletions(-)
-
-diff --git a/p2v/test-virt-p2v-scp.sh b/p2v/test-virt-p2v-scp.sh
-index c8a405db4..29900b663 100755
---- a/p2v/test-virt-p2v-scp.sh
-+++ b/p2v/test-virt-p2v-scp.sh
-@@ -44,15 +44,19 @@ while true ; do
-     esac
- done
- 
--# Hopefully there are two arguments left, the source (local) file
--# and a remote file of the form user@server:remote.
--if [ $# -ne 2 ]; then
-+# Hopefully there are >= two arguments left, the source (local)
-+# file(s) and a remote file of the form user@server:remote.
-+if [ $# -lt 2 ]; then
-     echo "$0: incorrect number of arguments found:" "$@"
-     exit 1
- fi
- 
--local="$1"
--remote="$(echo $2 | awk -F: '{print $2}')"
-+# https://stackoverflow.com/questions/1853946/getting-the-last-argument-passed-to-a-shell-script/1854031#1854031
-+remote="${@: -1}"
-+# https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bash/26163980#26163980
-+set -- "${@:1:$(($#-1))}"
-+
-+remote="$(echo $remote | awk -F: '{print $2}')"
- 
- # Use the copy command.
--exec cp "$local" "$remote"
-+exec cp "$@" "$remote"
--- 
-2.13.4
-
diff --git a/SOURCES/0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch b/SOURCES/0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch
new file mode 100644
index 0000000..35078ba
--- /dev/null
+++ b/SOURCES/0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch
@@ -0,0 +1,75 @@
+From f5ce5692f4701fc122af82759a790cfe01a18c35 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 12 Apr 2017 08:32:58 +0100
+Subject: [PATCH] v2v: tests: Fix -i vmx test so it is more stable.
+
+When running under valgrind, the process takes a fraction of a second
+to start up, changing the "Opening the guest" timestamp, which broke
+the test.
+
+Fixes commit ca40078cdda9167d4658ddfe24c828c7ee76be37.
+
+(cherry picked from commit ec61873d397f050fe28987f10ec919778d27818a)
+---
+ v2v/test-v2v-i-vmx-1.expected | 2 +-
+ v2v/test-v2v-i-vmx-2.expected | 2 +-
+ v2v/test-v2v-i-vmx-3.expected | 2 +-
+ v2v/test-v2v-i-vmx-4.expected | 2 +-
+ v2v/test-v2v-i-vmx.sh         | 1 +
+ 5 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected
+index c7ef1f5d5..128c34762 100644
+--- a/v2v/test-v2v-i-vmx-1.expected
++++ b/v2v/test-v2v-i-vmx-1.expected
+@@ -1,4 +1,4 @@
+-[   0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx
++
+ Source guest information (--print-source option):
+ 
+     source name: BZ1308535_21disks
+diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected
+index a04bd0f62..7f3ee8154 100644
+--- a/v2v/test-v2v-i-vmx-2.expected
++++ b/v2v/test-v2v-i-vmx-2.expected
+@@ -1,4 +1,4 @@
+-[   0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx
++
+ Source guest information (--print-source option):
+ 
+     source name: Fedora 20
+diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected
+index 64808a77b..4664efdec 100644
+--- a/v2v/test-v2v-i-vmx-3.expected
++++ b/v2v/test-v2v-i-vmx-3.expected
+@@ -1,4 +1,4 @@
+-[   0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx
++
+ Source guest information (--print-source option):
+ 
+     source name: RHEL 7.1 UEFI
+diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected
+index 208920b29..d6dcda5b6 100644
+--- a/v2v/test-v2v-i-vmx-4.expected
++++ b/v2v/test-v2v-i-vmx-4.expected
+@@ -1,4 +1,4 @@
+-[   0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx
++
+ Source guest information (--print-source option):
+ 
+     source name: Windows 7 x64
+diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh
+index 5353e7e2a..997103d41 100755
+--- a/v2v/test-v2v-i-vmx.sh
++++ b/v2v/test-v2v-i-vmx.sh
+@@ -37,6 +37,7 @@ for i in 1 2 3 4; do
+     # Normalize the print-source output.
+     mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old
+     sed \
++        -e "s,.*Opening the source.*,," \
+         -e "s,$(pwd),," \
+         < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual
+     rm test-v2v-i-vmx-$i.actual.old
+-- 
+2.14.3
+
diff --git a/SOURCES/0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch b/SOURCES/0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch
new file mode 100644
index 0000000..251c462
--- /dev/null
+++ b/SOURCES/0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch
@@ -0,0 +1,36 @@
+From e70e7d95ed6130152186b88d9341c5c715cf29bf Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Mon, 14 Aug 2017 10:02:13 +0200
+Subject: [PATCH] RHEL 7: v2v: disable unconfig of manually installed VMware
+ tools (RHBZ#1477905)
+
+It looks like they may require connection to the VMware servers, which
+is not always available during conversion.
+---
+ v2v/convert_linux.ml | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
+index 32e08fa30..cd8a20d31 100644
+--- a/v2v/convert_linux.ml
++++ b/v2v/convert_linux.ml
+@@ -293,6 +293,7 @@ let rec convert (g : G.guestfs) inspect source output rcaps =
+     let remove = !remove in
+     Linux.remove g inspect remove;
+ 
++(*
+     (* VMware Tools may have been installed from a tarball, so the
+      * above code won't remove it.  Look for the uninstall tool and run
+      * if present.
+@@ -314,6 +315,8 @@ let rec convert (g : G.guestfs) inspect source output rcaps =
+           warning (f_"VMware tools was detected, but uninstallation failed.  The error message was: %s (ignored)")
+             msg
+     )
++*)
++    ()
+ 
+   and unconfigure_citrix () =
+     let pkgs =
+-- 
+2.14.3
+
diff --git a/SOURCES/0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch b/SOURCES/0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch
deleted file mode 100644
index 73059d6..0000000
--- a/SOURCES/0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From e7359e9feac4fa2163a7259d093e381273365c8e Mon Sep 17 00:00:00 2001
-From: Pavel Butsykin <pbutsykin@virtuozzo.com>
-Date: Mon, 3 Apr 2017 19:44:45 +0300
-Subject: [PATCH] v2v: windows convert: fix virtio block driver installation
- for w10/w2k16
-
-This patch fixes the problem of the first boot after installation virtio block
-drivers on Windows 10 / Server 2016. The problem is related to the change in
-the behavior of Windows-Kernel-Pnp. To fix we need to add a field "Version" to
-HKLM/SYSTEM/DriverDatabase/DriverPackages/drv_inf_label then Windows-Kernel-Pnp
-will be able to correctly install the virtio block driver.
-
-Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
-(cherry picked from commit cc162b49e6c87bf3535168853dadf10f7610865f)
----
- v2v/windows_virtio.ml | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml
-index 2f5349d25..965d6ac8b 100644
---- a/v2v/windows_virtio.ml
-+++ b/v2v/windows_virtio.ml
-@@ -220,6 +220,13 @@ and ddb_regedits inspect drv_name drv_pciid =
-     [ "DriverDatabase"; "DeviceIds"; "PCI"; drv_pciid ],
-     [ drv_inf, REG_BINARY "\x01\xff\x00\x00" ];
- 
-+    [ "DriverDatabase"; "DriverPackages"; drv_inf_label ],
-+    [ "Version", REG_BINARY ("\x00\xff\x09\x00\x00\x00\x00\x00" ^
-+                             "\x7b\xe9\x36\x4d\x25\xe3\xce\x11" ^
-+                             "\xbf\xc1\x08\x00\x2b\xe1\x03\x18" ^
-+                             (String.make 24 '\x00')) ];
-+    (* Version is necessary for Windows-Kernel-Pnp in w10/w2k16 *)
-+
-     [ "DriverDatabase"; "DriverPackages"; drv_inf_label;
-       "Configurations"; drv_config ],
-     [ "ConfigFlags", REG_DWORD 0_l;
--- 
-2.13.4
-
diff --git a/SOURCES/0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch b/SOURCES/0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch
new file mode 100644
index 0000000..f0ff572
--- /dev/null
+++ b/SOURCES/0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch
@@ -0,0 +1,42 @@
+From 3c4780cda6bfdd20d2a71857e326cc9cd2fd708c Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Mon, 8 May 2017 09:55:42 +0100
+Subject: [PATCH] v2v: -i ova: Prefer pigz or pxz for uncompressing OVA files
+ (RHBZ#1448739).
+
+If the parallel tools pigz or pxz are available, prefer them for
+uncompressing gz- and xz-compressed OVA files respectively.  If not
+available then gzip or xz are used as normal.
+---
+ v2v/input_ova.ml | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
+index c91011873..69cdf576b 100644
+--- a/v2v/input_ova.ml
++++ b/v2v/input_ova.ml
+@@ -40,9 +40,19 @@ let libvirt_supports_json_raw_driver () =
+   else
+     true
+ 
++let pigz_available =
++  let test = lazy (shell_command "pigz --help >/dev/null 2>&1" = 0) in
++  fun () -> Lazy.force test
++
++let pxz_available =
++  let test = lazy (shell_command "pxz --help >/dev/null 2>&1" = 0) in
++  fun () -> Lazy.force test
++
+ let zcat_command_of_format = function
+-  | `GZip -> "gzip -c -d"
+-  | `XZ -> "xz -c -d"
++  | `GZip ->
++     if pigz_available () then "pigz -c -d" else "gzip -c -d"
++  | `XZ ->
++     if pxz_available () then "pxz -c -d" else "xz -c -d"
+ 
+ (* Untar part or all files from tar archive. If [paths] is specified it is
+  * a list of paths in the tar archive.
+-- 
+2.14.3
+
diff --git a/SOURCES/0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch b/SOURCES/0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch
deleted file mode 100644
index 1f9a86d..0000000
--- a/SOURCES/0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 9b24787dab3d5dea740a1667f69bc75b763cf699 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Tue, 11 Apr 2017 12:16:51 +0100
-Subject: [PATCH] v2v: -o qemu: Fix creation of ICH6 sound device.
-
-Fixes commit f6ece2c01a9a1a43d6715103e7dbdda0f09ee862.
-
-(cherry picked from commit e562f52c95fe8eefdab778918d152335f56012c6)
----
- v2v/output_qemu.ml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml
-index 84efd4529..abff29c2b 100644
---- a/v2v/output_qemu.ml
-+++ b/v2v/output_qemu.ml
-@@ -183,7 +183,7 @@ object
-           match model with
-           | AC97      -> arg "-device" "AC97"
-           | ES1370    -> arg "-device" "ES1370"
--          | ICH6      -> arg "-device" "intel-hda -device hda-duplex"
-+          | ICH6      -> arg "-device" "intel-hda"; arg "-device" "hda-duplex"
-           | ICH9      -> arg "-device" "ich9-intel-hda"
-           | PCSpeaker -> arg "-soundhw" "pcspk" (* not qdev-ified *)
-           | SB16      -> arg "-device" "sb16"
--- 
-2.13.4
-
diff --git a/SOURCES/0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch b/SOURCES/0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch
deleted file mode 100644
index 5a4730e..0000000
--- a/SOURCES/0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 12d1057fba45b534d0cfbbcc900e5032e314b150 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Tue, 11 Apr 2017 08:29:47 +0100
-Subject: [PATCH] ocaml: Add Bytes.sub_string function to Bytes compat module.
-
-This is only used when OCaml < 4.02 (eg. RHEL 7).  For more recent
-versions the real Bytes.sub_string function is used instead.
-
-(cherry picked from commit bb846887de7a252204152c3e6df80d39a5ea33af)
----
- m4/guestfs_ocaml.m4 | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/m4/guestfs_ocaml.m4 b/m4/guestfs_ocaml.m4
-index 0479e70ab..d8bd89f00 100644
---- a/m4/guestfs_ocaml.m4
-+++ b/m4/guestfs_ocaml.m4
-@@ -120,6 +120,7 @@ AS_IF([test "x$have_Bytes_module" = "xno"],[
- include String
- let of_string = String.copy
- let to_string = String.copy
-+let sub_string = String.sub
- EOF
-     ln -s ../generator/bytes.ml mllib/bytes.ml
-     OCAML_GENERATOR_BYTES_COMPAT_CMO='$(top_builddir)/generator/bytes.cmo'
--- 
-2.13.4
-
diff --git a/SOURCES/0034-v2v-add-crypto-support-RHBZ-1451665.patch b/SOURCES/0034-v2v-add-crypto-support-RHBZ-1451665.patch
new file mode 100644
index 0000000..e741ccd
--- /dev/null
+++ b/SOURCES/0034-v2v-add-crypto-support-RHBZ-1451665.patch
@@ -0,0 +1,87 @@
+From a8853952b43e15fd4aa287d235d8583782475531 Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Mon, 22 May 2017 11:31:45 +0200
+Subject: [PATCH] v2v: add crypto support (RHBZ#1451665)
+
+Make use of the additional command line arguments, and API needed to
+decrypt LUKS partitions.  This extends to v2v the work done in other
+OCaml tools with commit 6b26a0cce4f1d6264bee88902b8931e39288c901,
+since it seems to be working fine after a basic testing.
+
+Related to: RHBZ#1362649
+
+(cherry picked from commit 7e6c16f1e7698317991b875f2d7ab3ce9e94c8bb)
+---
+ v2v/cmdline.ml   |  2 +-
+ v2v/v2v.ml       |  3 +++
+ v2v/virt-v2v.pod | 20 ++++++++++++++++++++
+ 3 files changed, 24 insertions(+), 1 deletion(-)
+
+diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
+index db2346a38..6b105886c 100644
+--- a/v2v/cmdline.ml
++++ b/v2v/cmdline.ml
+@@ -235,7 +235,7 @@ A short summary of the options is given below.  For detailed help please
+ read the man page virt-v2v(1).
+ ")
+       prog in
+-  let opthandle = create_standard_options argspec ~anon_fun usage_msg in
++  let opthandle = create_standard_options argspec ~anon_fun ~key_opts:true usage_msg in
+   Getopt.parse opthandle;
+ 
+   (* Dereference the arguments. *)
+diff --git a/v2v/v2v.ml b/v2v/v2v.ml
+index c1d412295..d03662c84 100644
+--- a/v2v/v2v.ml
++++ b/v2v/v2v.ml
+@@ -90,6 +90,9 @@ let rec main () =
+ 
+   g#launch ();
+ 
++  (* Decrypt the disks. *)
++  inspect_decrypt g;
++
+   (* Inspection - this also mounts up the filesystems. *)
+   (match conversion_mode with
+    | Copying _ -> message (f_"Inspecting the overlay")
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 7ed5c5d86..77b6f514f 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -191,6 +191,17 @@ Save the overlay file(s) created during conversion.  This option is
+ only used for debugging virt-v2v and may be removed in a future
+ version.
+ 
++=item B<--echo-keys>
++
++When prompting for keys and passphrases, virt-v2v normally turns
++echoing off so you cannot see what you are typing.  If you are not
++worried about Tempest attacks and there is no one else in the room you
++can specify this flag to see what you are typing.
++
++Note this options only applies to keys and passphrases for encrypted
++devices and partitions, not for passwords used to connect to remote
++servers.
++
+ =item B<-i> B<disk>
+ 
+ Set the input method to I<disk>.
+@@ -257,6 +268,15 @@ For I<-i disk> only, this specifies the format of the input disk
+ image.  For other input methods you should specify the input
+ format in the metadata.
+ 
++=item B<--keys-from-stdin>
++
++Read key or passphrase parameters from stdin.  The default is
++to try to read passphrases from the user by opening F</dev/tty>.
++
++Note this options only applies to keys and passphrases for encrypted
++devices and partitions, not for passwords used to connect to remote
++servers.
++
+ =item B<--machine-readable>
+ 
+ This option is used to make the output more machine friendly
+-- 
+2.14.3
+
diff --git a/SOURCES/0035-mllib-Add-Char.hexdigit-function.patch b/SOURCES/0035-mllib-Add-Char.hexdigit-function.patch
deleted file mode 100644
index de1d233..0000000
--- a/SOURCES/0035-mllib-Add-Char.hexdigit-function.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 0279339ee9a7b61ebcb3f64846d94f8171872737 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Tue, 11 Apr 2017 08:32:04 +0100
-Subject: [PATCH] mllib: Add Char.hexdigit function.
-
-Same as the function defined in fish/fish.c.
-
-(cherry picked from commit ef261d69ed199cc07474a36c890f63df461b35a7)
----
- mllib/common_utils.ml  | 19 +++++++++++++++++++
- mllib/common_utils.mli |  4 ++++
- 2 files changed, 23 insertions(+)
-
-diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
-index e1d63292e..4593614aa 100644
---- a/mllib/common_utils.ml
-+++ b/mllib/common_utils.ml
-@@ -70,6 +70,25 @@ module Char = struct
-       | 'a'..'z' -> true
-       | 'A'..'Z' -> true
-       | _ -> false
-+
-+    let hexdigit = function
-+      | '0' -> 0
-+      | '1' -> 1
-+      | '2' -> 2
-+      | '3' -> 3
-+      | '4' -> 4
-+      | '5' -> 5
-+      | '6' -> 6
-+      | '7' -> 7
-+      | '8' -> 8
-+      | '9' -> 9
-+      | 'a' | 'A' -> 10
-+      | 'b' | 'B' -> 11
-+      | 'c' | 'C' -> 12
-+      | 'd' | 'D' -> 13
-+      | 'e' | 'E' -> 14
-+      | 'f' | 'F' -> 15
-+      | _ -> -1
- end
- 
- module String = struct
-diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli
-index 1cd38ba83..ec41a8ff8 100644
---- a/mllib/common_utils.mli
-+++ b/mllib/common_utils.mli
-@@ -43,6 +43,10 @@ module Char : sig
-     (** Return true if the character is a US ASCII 7 bit alphabetic. *)
-     val isalnum : char -> bool
-     (** Return true if the character is a US ASCII 7 bit alphanumeric. *)
-+
-+    val hexdigit : char -> int
-+    (** Return the value of a hex digit.  If the char is not in
-+        the set [[0-9a-fA-F]] then this returns [-1]. *)
- end
- (** Override the Char module from stdlib. *)
- 
--- 
-2.13.4
-
diff --git a/SOURCES/0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch b/SOURCES/0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch
new file mode 100644
index 0000000..0e2618a
--- /dev/null
+++ b/SOURCES/0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch
@@ -0,0 +1,763 @@
+From 9542f12a306e05b73f5c4ecd4e4e61e03797098a Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 30 Aug 2017 17:14:03 +0100
+Subject: [PATCH] v2v: Implement input from nbdkit vddk plugin (RHBZ#1477912).
+
+(cherry picked from commit bbda5a6a68846acf971e0f4cbf83cacfa083d6e9)
+---
+ v2v/Makefile.am            |   2 +
+ v2v/cmdline.ml             |  53 +++++++-
+ v2v/input_libvirt.ml       |  16 ++-
+ v2v/input_libvirt.mli      |   8 +-
+ v2v/input_libvirt_vddk.ml  | 314 +++++++++++++++++++++++++++++++++++++++++++++
+ v2v/input_libvirt_vddk.mli |  24 ++++
+ v2v/types.ml               |  12 ++
+ v2v/types.mli              |  13 ++
+ v2v/virt-v2v.pod           | 155 ++++++++++++++++++++++
+ 9 files changed, 588 insertions(+), 9 deletions(-)
+ create mode 100644 v2v/input_libvirt_vddk.ml
+ create mode 100644 v2v/input_libvirt_vddk.mli
+
+diff --git a/v2v/Makefile.am b/v2v/Makefile.am
+index 0df759eca..87776a509 100644
+--- a/v2v/Makefile.am
++++ b/v2v/Makefile.am
+@@ -35,6 +35,7 @@ SOURCES_MLI = \
+ 	input_libvirt.mli \
+ 	input_libvirt_other.mli \
+ 	input_libvirt_vcenter_https.mli \
++	input_libvirt_vddk.mli \
+ 	input_libvirt_xen_ssh.mli \
+ 	input_libvirtxml.mli \
+ 	input_ova.mli \
+@@ -89,6 +90,7 @@ SOURCES_ML = \
+ 	input_libvirtxml.ml \
+ 	input_libvirt_other.ml \
+ 	input_libvirt_vcenter_https.ml \
++	input_libvirt_vddk.ml \
+ 	input_libvirt_xen_ssh.ml \
+ 	input_libvirt.ml \
+ 	input_ova.ml \
+diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
+index 6b105886c..3050104d0 100644
+--- a/v2v/cmdline.ml
++++ b/v2v/cmdline.ml
+@@ -63,6 +63,15 @@ let parse_cmdline () =
+   let output_name = ref None in
+   let output_storage = ref None in
+   let password_file = ref None in
++  let vddk = ref None in
++  let vddk_config = ref None in
++  let vddk_cookie = ref None in
++  let vddk_nfchostport = ref None in
++  let vddk_port = ref None in
++  let vddk_snapshot = ref None in
++  let vddk_thumbprint = ref None in
++  let vddk_transports = ref None in
++  let vddk_vimapiver = ref None in
+   let vdsm_vm_uuid = ref None in
+   let vdsm_ovf_output = ref None in (* default "." *)
+ 
+@@ -201,6 +210,24 @@ let parse_cmdline () =
+                                             s_"Use password from file";
+     [ L"print-source" ], Getopt.Set print_source, s_"Print source and stop";
+     [ L"root" ],    Getopt.String ("ask|... ", set_root_choice), s_"How to choose root filesystem";
++    [ L"vddk" ],     Getopt.String ("libpath", set_string_option_once "--vddk" vddk),
++                                            s_"Use nbdkit VDDK plugin";
++    [ L"vddk-config" ], Getopt.String ("filename", set_string_option_once "--vddk-config" vddk_config),
++                                            s_"Set VDDK config file";
++    [ L"vddk-cookie" ], Getopt.String ("cookie", set_string_option_once "--vddk-cookie" vddk_cookie),
++                                            s_"Set VDDK cookie";
++    [ L"vddk-nfchostport" ], Getopt.String ("nfchostport", set_string_option_once "--vddk-nfchostport" vddk_nfchostport),
++                                            s_"Set VDDK nfchostport";
++    [ L"vddk-port" ], Getopt.String ("port", set_string_option_once "--vddk-port" vddk_port),
++                                            s_"Set VDDK port";
++    [ L"vddk-snapshot" ], Getopt.String ("snapshot-moref", set_string_option_once "--vddk-snapshot" vddk_snapshot),
++                                            s_"Set VDDK snapshot";
++    [ L"vddk-thumbprint" ], Getopt.String ("thumbprint", set_string_option_once "--vddk-thumbprint" vddk_thumbprint),
++                                            s_"Set VDDK thumbprint";
++    [ L"vddk-transports" ], Getopt.String ("transports", set_string_option_once "--vddk-transports" vddk_transports),
++                                            s_"Set VDDK transports";
++    [ L"vddk-vimapiver" ], Getopt.String ("apiver", set_string_option_once "--vddk-vimapiver" vddk_vimapiver),
++                                            s_"Set VDDK vimapiver";
+     [ L"vdsm-compat" ], Getopt.Symbol ("0.10|1.1", ["0.10"; "1.1"], set_vdsm_compat), s_"Write qcow2 with compat=0.10|1.1";
+     [ L"vdsm-image-uuid" ], Getopt.String ("uuid", add_vdsm_image_uuid), s_"Output image UUID(s)";
+     [ L"vdsm-vol-uuid" ], Getopt.String ("uuid", add_vdsm_vol_uuid), s_"Output vol UUID(s)";
+@@ -263,6 +290,29 @@ read the man page virt-v2v(1).
+   let print_source = !print_source in
+   let qemu_boot = !qemu_boot in
+   let root_choice = !root_choice in
++  let vddk_options =
++    match !vddk with
++    | Some libdir ->
++      Some { vddk_libdir = libdir;
++             vddk_config = !vddk_config;
++             vddk_cookie = !vddk_cookie;
++             vddk_nfchostport = !vddk_nfchostport;
++             vddk_port = !vddk_port;
++             vddk_snapshot = !vddk_snapshot;
++             vddk_thumbprint = !vddk_thumbprint;
++             vddk_transports = !vddk_transports;
++             vddk_vimapiver = !vddk_vimapiver }
++    | None ->
++      if !vddk_config <> None ||
++         !vddk_cookie <> None ||
++         !vddk_nfchostport <> None ||
++         !vddk_port <> None ||
++         !vddk_snapshot <> None ||
++         !vddk_thumbprint <> None ||
++         !vddk_transports <> None ||
++         !vddk_vimapiver <> None then
++        error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘--vddk’.");
++      None in
+   let vdsm_compat = !vdsm_compat in
+   let vdsm_image_uuids = List.rev !vdsm_image_uuids in
+   let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in
+@@ -278,6 +328,7 @@ read the man page virt-v2v(1).
+     printf "libguestfs-rewrite\n";
+     printf "vcenter-https\n";
+     printf "xen-ssh\n";
++    printf "vddk\n";
+     printf "colours-option\n";
+     printf "vdsm-compat-option\n";
+     List.iter (printf "input:%s\n") (Modules_list.input_modules ());
+@@ -316,7 +367,7 @@ read the man page virt-v2v(1).
+         | [guest] -> guest
+         | _ ->
+           error (f_"expecting a libvirt guest name on the command line") in
+-      Input_libvirt.input_libvirt dcpath password input_conn guest
++      Input_libvirt.input_libvirt dcpath vddk_options password input_conn guest
+ 
+     | `LibvirtXML ->
+       (* -i libvirtxml: Expecting a filename (XML file). *)
+diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml
+index 0bc386430..e8143b6ad 100644
+--- a/v2v/input_libvirt.ml
++++ b/v2v/input_libvirt.ml
+@@ -27,7 +27,7 @@ open Types
+ open Utils
+ 
+ (* Choose the right subclass based on the URI. *)
+-let input_libvirt dcpath password libvirt_uri guest =
++let input_libvirt dcpath vddk_options password libvirt_uri guest =
+   match libvirt_uri with
+   | None ->
+     Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+@@ -47,10 +47,18 @@ let input_libvirt dcpath password libvirt_uri guest =
+     | Some _, Some "" ->
+       Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+ 
+-    (* vCenter over https *)
++    (* vCenter over https, or
++     * vCenter or ESXi using nbdkit vddk plugin
++     *)
+     | Some server, Some ("esx"|"gsx"|"vpx" as scheme) ->
+-      Input_libvirt_vcenter_https.input_libvirt_vcenter_https
+-        dcpath password libvirt_uri parsed_uri scheme server guest
++       (match vddk_options with
++        | None ->
++           Input_libvirt_vcenter_https.input_libvirt_vcenter_https
++             dcpath password libvirt_uri parsed_uri scheme server guest
++        | Some vddk_options ->
++           Input_libvirt_vddk.input_libvirt_vddk vddk_options password
++                                                 libvirt_uri parsed_uri guest
++       )
+ 
+     (* Xen over SSH *)
+     | Some server, Some ("xen+ssh" as scheme) ->
+diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli
+index f5e6314d9..0a6aa3c54 100644
+--- a/v2v/input_libvirt.mli
++++ b/v2v/input_libvirt.mli
+@@ -18,7 +18,7 @@
+ 
+ (** [-i libvirt] source. *)
+ 
+-val input_libvirt : string option -> string option -> string option -> string -> Types.input
+-(** [input_libvirt dcpath password libvirt_uri guest] creates and returns a
+-    new {!Types.input} object specialized for reading input from
+-    libvirt sources. *)
++val input_libvirt : string option -> Types.vddk_options option -> string option -> string option -> string -> Types.input
++(** [input_libvirt dcpath vddk_options password libvirt_uri guest] creates
++    and returns a new {!Types.input} object specialized for reading input
++    from libvirt sources. *)
+diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
+new file mode 100644
+index 000000000..89d2552f6
+--- /dev/null
++++ b/v2v/input_libvirt_vddk.ml
+@@ -0,0 +1,314 @@
++(* virt-v2v
++ * Copyright (C) 2009-2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *)
++
++(** [-i libvirt] when the source is VMware via nbdkit vddk plugin *)
++
++open Unix
++
++open Common_gettext.Gettext
++open Common_utils
++open Unix_utils
++
++open Types
++open Utils
++open Input_libvirt_other
++open Parse_libvirt_xml
++open Xpath_helpers
++
++open Printf
++
++(* Subclass specialized for handling VMware via nbdkit vddk plugin. *)
++class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
++
++  (* The VDDK path. *)
++  let libdir = vddk_options.vddk_libdir in
++  (* Compute the LD_LIBRARY_PATH that we must pass to nbdkit. *)
++  let library_path = libdir // sprintf "lib%d" Sys.word_size in
++
++  (* Is SELinux enabled and enforcing on the host? *)
++  let have_selinux =
++    0 = Sys.command "getenforce 2>/dev/null | grep -isq Enforcing" in
++
++  (* Check that the VDDK path looks reasonable. *)
++  let error_unless_vddk_libdir () =
++    if not (is_directory libdir) then
++      error (f_"‘--vddk %s’ does not point to a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir;
++
++    if not (is_directory library_path) then
++      error (f_"VDDK library path %s not found or not a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
++            library_path
++  in
++
++  (* Check that nbdkit is available and new enough. *)
++  let error_unless_nbdkit_working () =
++    if 0 <> Sys.command "nbdkit --version >/dev/null" then
++      error (f_"nbdkit is not installed or not working.  It is required to use ‘--vddk’.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.");
++
++    (* Check it's a new enough version.  The latest features we
++     * require are ‘--exit-with-parent’ and ‘--selinux-label’, both
++     * added in 1.1.14.
++     *)
++    let lines = external_command "nbdkit --help" in
++    let lines = String.concat " " lines in
++    if String.find lines "exit-with-parent" == -1 ||
++       String.find lines "selinux-label" == -1 then
++      error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ 1.1.14")
++  in
++
++  (* Check that the VDDK plugin is installed and working *)
++  let error_unless_nbdkit_vddk_working () =
++    let cmd =
++      sprintf "LD_LIBRARY_PATH=%s nbdkit vddk --dump-plugin >/dev/null"
++              (quote library_path) in
++    if Sys.command cmd <> 0 then (
++      (* See if we can diagnose why ... *)
++      let cmd =
++        sprintf "LD_LIBRARY_PATH=%s LANG=C nbdkit vddk --dump-plugin 2>&1 | grep -sq libvixDiskLib.so"
++                (quote library_path) in
++      let needs_library = Sys.command cmd = 0 in
++      if not needs_library then
++        error (f_"nbdkit VDDK plugin is not installed or not working.  It is required if you want to use VDDK.
++
++The VDDK plugin is not enabled by default when you compile nbdkit.  You have to read the instructions in the nbdkit sources under ‘plugins/vddk/README.VDDK’ to find out how to enable the VDDK plugin.
++
++See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
++      else
++        error (f_"nbdkit VDDK plugin is not installed or not working.  It is required if you want to use VDDK.
++
++It looks like you did not set the right path in the ‘--vddk’ option, or your copy of the VDDK directory is incomplete.  There should be a library called ’%s/libvixDiskLib.so.?’.
++
++See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
++    )
++  in
++
++  let error_unless_thumbprint () =
++    if vddk_options.vddk_thumbprint = None then
++      error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server.  To find the thumbprint, see the nbdkit-vddk-plugin(1) manual.  See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
++  in
++
++object
++  inherit input_libvirt password libvirt_uri guest
++
++  method source () =
++    error_unless_vddk_libdir ();
++    error_unless_nbdkit_working ();
++    error_unless_nbdkit_vddk_working ();
++    error_unless_thumbprint ();
++
++    (* Get the libvirt XML.  This also checks (as a side-effect)
++     * that the domain is not running.  (RHBZ#1138586)
++     *)
++    let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in
++    let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in
++
++    (* Find the <vmware:moref> element from the XML.  This was added
++     * in libvirt >= 3.7 and is required.
++     *)
++    let moref =
++      let doc = Xml.parse_memory xml in
++      let xpathctx = Xml.xpath_new_context doc in
++      Xml.xpath_register_ns xpathctx
++        "vmware" "http://libvirt.org/schemas/domain/vmware/1.0";
++      let xpath_string = xpath_string xpathctx in
++      match xpath_string "/domain/vmware:moref" with
++      | Some moref -> moref
++      | None ->
++         error (f_"<vmware:moref> was not found in the output of ‘virsh dumpxml \"%s\"’.  The most likely reason is that libvirt is too old, try upgrading libvirt to ≥ 3.7.") guest in
++
++    (* Create a temporary directory where we place the sockets and
++     * password file.
++     *)
++    let tmpdir =
++      let base_dir = (open_guestfs ())#get_cachedir () in
++      let t = Mkdtemp.temp_dir ~base_dir "vddk." in
++      (* tmpdir must be readable (but not writable) by "other" so that
++       * qemu can open the sockets.  If we place a password file in
++       * this directory then we'll chmod that to 0600 below.
++       *)
++      chmod t 0o755;
++      rmdir_on_exit t;
++      t in
++
++    (* Start constructing the parts of the incredibly long nbdkit
++     * command line which don't change between disks.
++     *)
++    let args =
++      let add_arg, get_args =
++        let args = ref [] in
++        let add_arg a = push_front a args in
++        let get_args () = List.rev !args in
++        add_arg, get_args in
++
++      (* It probably never happens that the server name can be missing
++       * from the libvirt URI, but we need a server name to pass to
++       * nbdkit, so ...
++       *)
++      let server =
++        match parsed_uri.Xml.uri_server with
++        | Some server -> server
++        | None ->
++           match libvirt_uri with
++           | Some libvirt_uri ->
++              error (f_"‘-ic %s’ URL does not contain a host name field")
++                    libvirt_uri
++           | None ->
++              error (f_"you must use the ‘-ic’ parameter.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") in
++
++      (* Similar to above, we also need a username to pass. *)
++      let user =
++        match parsed_uri.Xml.uri_user with
++        | Some user -> user
++        | None -> "root" (* ? *) in
++
++      add_arg "nbdkit";
++      if verbose () then add_arg "--verbose";
++      add_arg "--readonly";         (* important! readonly mode *)
++      add_arg "--foreground";       (* run in foreground *)
++      add_arg "--exit-with-parent"; (* exit when virt-v2v exits *)
++      add_arg "--newstyle";         (* use newstyle NBD protocol *)
++      add_arg "--exportname"; add_arg "/";
++      if have_selinux then (        (* label the socket so qemu can open it *)
++        add_arg "--selinux-label"; add_arg "system_u:object_r:svirt_t:s0"
++      );
++
++      (* Name of the plugin.  Everything following is a plugin parameter. *)
++      add_arg "vddk";
++
++      let password_param =
++        match password with
++        | None ->
++           (* nbdkit asks for the password interactively *)
++           "password=-"
++        | Some password ->
++           let password_file = tmpdir // "password" in
++           let chan = open_out password_file in
++           chmod password_file 0o600;
++           output_string chan password;
++           close_out chan;
++           (* nbdkit reads the password from the file *)
++           "password=+" ^ password_file in
++      add_arg (sprintf "server=%s" server);
++      add_arg (sprintf "user=%s" user);
++      add_arg password_param;
++      add_arg (sprintf "vm=moref=%s" moref);
++      add_arg (sprintf "libdir=%s" libdir);
++
++      (* The passthrough parameters. *)
++      let pt name = may (fun field -> add_arg (sprintf "%s=%s" name field)) in
++      pt "config" vddk_options.vddk_config;
++      pt "cookie" vddk_options.vddk_cookie;
++      pt "nfchostport" vddk_options.vddk_nfchostport;
++      pt "port" vddk_options.vddk_port;
++      pt "snapshot" vddk_options.vddk_snapshot;
++      pt "thumbprint" vddk_options.vddk_thumbprint;
++      pt "transports" vddk_options.vddk_transports;
++      pt "vimapiver" vddk_options.vddk_vimapiver;
++
++      get_args () in
++
++    (* Create an nbdkit instance for each disk and rewrite the source
++     * paths to point to the NBD socket.
++     *)
++    let disks = List.map (
++      function
++      | { p_source_disk = disk; p_source = P_dont_rewrite } ->
++         disk
++
++      | { p_source = P_source_dev _ } -> (* Should never happen. *)
++         error (f_"source disk has <source dev=...> attribute in XML")
++
++      | { p_source_disk = disk; p_source = P_source_file path } ->
++         (* The <source file=...> attribute returned by the libvirt
++          * VMX driver looks like "[datastore] path".  We can use it
++          * directly as the nbdkit file= parameter, and it is passed
++          * directly in this form to VDDK.
++          *)
++
++         let sock = tmpdir // sprintf "nbdkit%d.sock" disk.s_disk_id in
++         let qemu_uri = sprintf "nbd:unix:%s:exportname=/" sock in
++
++         let pidfile = tmpdir // sprintf "nbdkit%d.pid" disk.s_disk_id in
++
++         (* Construct the final command line with the "static" args
++          * above plus the args which vary for each disk.
++          *)
++         let args =
++           args @ [ "--pidfile"; pidfile;
++                    "--unix"; sock;
++                    sprintf "file=%s" path ] in
++         let args = Array.of_list args in
++
++         (* Start an nbdkit instance in the background.  By using
++          * --exit-with-parent we don't have to worry about cleaning
++          * it up, hopefully.
++          *)
++         let pid = fork () in
++         if pid = 0 then (
++           (* Child process (nbdkit). *)
++           putenv "LD_LIBRARY_PATH" library_path;
++           execvp "nbdkit" args
++         );
++
++         (* Wait for the pidfile to appear so we know that nbdkit
++          * is listening for requests.
++          *)
++         let rec loop i =
++           if i = 0 then false
++           else if Sys.file_exists pidfile then true
++           else (
++             sleep 1;
++             loop (i-1)
++           )
++         in
++         if not (loop 30) then (
++           if verbose () then
++             error (f_"nbdkit did not start up.  See previous debugging messages for problems.")
++           else
++             error (f_"nbdkit did not start up.  There may be errors printed by nbdkit above.
++
++If the messages above are not sufficient to diagnose the problem then add the ‘virt-v2v -v -x’ options and examine the debugging output carefully.")
++         );
++
++         if have_selinux then (
++           (* Note that Unix domain sockets have both a file label and
++            * a socket/process label.  Using --selinux-label above
++            * only set the socket label, but we must also set the file
++            * label.
++            *)
++           ignore (
++               run_command ["chcon"; "system_u:object_r:svirt_image_t:s0";
++                            sock]
++           );
++         );
++         (* ... and the regular Unix permissions, in case qemu is
++          * running as another user.
++          *)
++         chmod sock 0o777;
++
++         { disk with s_qemu_uri = qemu_uri }
++     ) disks in
++
++    if verbose () then (
++      eprintf "vddk: tmpdir %s:\n%!" tmpdir;
++      ignore (Sys.command (sprintf "ls -laZ %s" (quote tmpdir)))
++    );
++
++    { source with s_disks = disks }
++end
++
++let input_libvirt_vddk = new input_libvirt_vddk
+diff --git a/v2v/input_libvirt_vddk.mli b/v2v/input_libvirt_vddk.mli
+new file mode 100644
+index 000000000..19a34c202
+--- /dev/null
++++ b/v2v/input_libvirt_vddk.mli
+@@ -0,0 +1,24 @@
++(* virt-v2v
++ * Copyright (C) 2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *)
++
++(** [-i libvirt] when the source is VMware via nbdkit vddk plugin *)
++
++val input_libvirt_vddk : Types.vddk_options -> string option -> string option -> Xml.uri -> string -> Types.input
++(** [input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest]
++    creates and returns a {!Types.input} object specialized for reading
++    the guest disks using the nbdkit vddk plugin. *)
+diff --git a/v2v/types.ml b/v2v/types.ml
+index 3efb9ff46..4f9205aa0 100644
+--- a/v2v/types.ml
++++ b/v2v/types.ml
+@@ -472,6 +472,18 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string
+ 
+ type output_allocation = Sparse | Preallocated
+ 
++type vddk_options = {
++    vddk_libdir : string;
++    vddk_config : string option;
++    vddk_cookie : string option;
++    vddk_nfchostport : string option;
++    vddk_port : string option;
++    vddk_snapshot : string option;
++    vddk_thumbprint : string option;
++    vddk_transports : string option;
++    vddk_vimapiver : string option;
++}
++
+ class virtual input = object
+   method precheck () = ()
+   method virtual as_options : string
+diff --git a/v2v/types.mli b/v2v/types.mli
+index 2880546ae..087a03702 100644
+--- a/v2v/types.mli
++++ b/v2v/types.mli
+@@ -328,6 +328,19 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string
+ type output_allocation = Sparse | Preallocated
+ (** Type of [-oa] (output allocation) option. *)
+ 
++type vddk_options = {
++    vddk_libdir : string;
++    vddk_config : string option;
++    vddk_cookie : string option;
++    vddk_nfchostport : string option;
++    vddk_port : string option;
++    vddk_snapshot : string option;
++    vddk_thumbprint : string option;
++    vddk_transports : string option;
++    vddk_vimapiver : string option;
++}
++(** Various options passed through to the nbdkit vddk plugin unmodified. *)
++
+ (** {2 Input object}
+ 
+     There is one of these used for the [-i] option. *)
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 77b6f514f..d713d0b1f 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -514,6 +514,35 @@ boot an operating system from the first VirtIO disk.  Specifically,
+ F</boot> must be on the first VirtIO disk, and it cannot chainload an
+ OS which is not in the first VirtIO disk.
+ 
++=item B<--vddk> LIBDIR
++
++Enable VDDK input from VMware vCenter or ESXi.  C<LIBDIR> is the top
++directory of the VDDK library.  This directory should I<contain>
++subdirectories called F<include>, F<lib64> etc., but do not include
++F<lib64> actually in the parameter.
++
++See L</INPUT FROM VDDK> below for details.
++
++=item B<--vddk-config> FILENAME
++
++=item B<--vddk-cookie> COOKIE
++
++=item B<--vddk-nfchostport> PORT
++
++=item B<--vddk-port> PORT
++
++=item B<--vddk-snapshot> SNAPSHOT-MOREF
++
++=item B<--vddk-thumbprint> xx:xx:xx:...
++
++=item B<--vddk-transports> MODE:MODE:...
++
++=item B<--vddk-vimapiver> APIVER
++
++When using VDDK mode, these options are passed unmodified to the
++L<nbdkit(1)> VDDK plugin.  Please refer to L<nbdkit-vddk-plugin(1)>.
++Only I<--vddk-thumbprint> is required, the others are optional.
++
+ =item B<--vdsm-compat=0.10>
+ 
+ =item B<--vdsm-compat=1.1>
+@@ -1270,6 +1299,130 @@ Perform the conversion of the guest using virt-v2v:
+ 
+ Remove the F<guest.xml> and F<guest-disk*> files.
+ 
++=head1 INPUT FROM VDDK
++
++Virt-v2v is able to import guests using VMware’s proprietary VDDK
++library (a.k.a. VixDiskLib).
++
++=head2 VDDK: PREREQUISITES
++
++=over 4
++
++=item 1.
++
++As the VDDK library is not open source, and the license of this
++library does not permit redistribution or commercial use, you must
++obtain VDDK yourself and satisfy yourself that your usage of the
++library is permitted by the license.
++
++=item 2.
++
++You must also compile nbdkit, enabling the VDDK plugin.  At least
++nbdkit E<ge> 1.1.14 is required, but it is usually best to compile
++from the git tree.
++
++=over 4
++
++=item *
++
++L<https://github.com/libguestfs/nbdkit>
++
++=item *
++
++L<https://github.com/libguestfs/nbdkit/tree/master/plugins/vddk>
++
++=back
++
++=item 3.
++
++You can run nbdkit from its source directory without needing to
++install it.  Set C<$PATH> to include the nbdkit top build directory
++(the directory containing a shell script called F<nbdkit>):
++
++ export PATH=/path/to/nbdkit:$PATH
++
++=item 4.
++
++You must find the SSL "thumbprint" of your VMware server.  How to do
++this is explained in L<nbdkit-vddk-plugin(1)>, also available at the
++link given in item 2 above.
++
++=item 5.
++
++VDDK imports require a feature added in libvirt E<ge> 3.7.
++
++=back
++
++=head2 VDDK: URI
++
++Construct the correct C<vpx://> (for vCenter) or C<esx://> (for ESXi)
++URL.  It will look something like these:
++
++ vpx://root@vcenter.example.com/Datacenter/esxi
++
++ esx://root@esxi.example.com
++
++To verify that you have the correct URL, use the L<virsh(1)> command
++to list the guests on the server:
++
++ $ virsh -c 'vpx://root@vcenter.example.com/Datacenter/esxi' list --all
++ Enter root's password for vcenter.example.com: ***
++ 
++  Id    Name                           State
++ ----------------------------------------------------
++  -     Fedora 20                      shut off
++  -     Windows 2003                   shut off
++
++If you get an error "Peer certificate cannot be authenticated with
++given CA certificates" or similar, then you can either import the
++vCenter host’s certificate, or bypass signature verification by adding
++the C<?no_verify=1> flag:
++
++ $ virsh -c 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' list --all
++
++You should also try dumping the metadata from any guest on your
++server, like this:
++
++ $ virsh -c 'vpx://root@vcenter.example.com/Datacenter/esxi' dumpxml "Windows 2003"
++ <domain type='vmware'>
++   <name>Windows 2003</name>
++   [...]
++   <vmware:moref>vm-123</vmware:moref>
++ </domain>
++
++If C<E<lt>vmware:morefE<gt>> does not appear in the metadata, then you
++need to upgrade libvirt.
++
++B<If the above commands do not work, then virt-v2v is not going to
++work either>.  Fix your URI and/or your VMware server before
++continuing.
++
++=head2 VDDK: IMPORTING A GUEST
++
++To import a particular guest from vCenter server or ESXi hypervisor,
++use a command like the following, substituting the URI, guest name and
++SSL thumbprint:
++
++ $ export PATH=/path/to/nbdkit:$PATH
++ $ virt-v2v \
++     -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \
++     --vddk /path/to/vmware-vix-disklib-distrib \
++     --vddk-thumbprint xx:xx:xx:... \
++     "Windows 2003" \
++     -o local -os /var/tmp
++
++Other options that you might need to add in rare circumstances include
++I<--vddk-config>, I<--vddk-cookie>, I<--vddk-nfchostport>,
++I<--vddk-port>, I<--vddk-snapshot>, I<--vddk-transports> and
++I<--vddk-vimapiver>, which are all explained in the
++L<nbdkit-vddk-plugin(1)> documentation.
++
++=head2 VDDK: DEBUGGING VDDK FAILURES
++
++The VDDK library can be operated in a verbose mode where it gives
++(very) verbose messages.  Use ‘virt-v2v -v -x’ as usual to enable
++verbose messages.
++
+ =head1 INPUT FROM XEN
+ 
+ Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts.
+@@ -2032,6 +2185,8 @@ L<virt-v2v-copy-to-local(1)>,
+ L<virt-v2v-test-harness(1)>,
+ L<engine-image-uploader(8)>,
+ L<import-to-ovirt.pl|http://git.annexia.org/?p=import-to-ovirt.git>,
++L<nbdkit(1)>,
++L<nbdkit-vddk-plugin(1)>,
+ L<http://libguestfs.org/>.
+ 
+ =head1 AUTHORS
+-- 
+2.14.3
+
diff --git a/SOURCES/0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch b/SOURCES/0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch
new file mode 100644
index 0000000..e149135
--- /dev/null
+++ b/SOURCES/0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch
@@ -0,0 +1,50 @@
+From c73e6d1e2dcbcf2c7b17096953e48bc5a84ee7d2 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 16 May 2017 20:12:54 +0200
+Subject: [PATCH] s390x: launch: libvirt: Use <console> device sclp for
+ appliance debug messages (RHBZ#1376547).
+
+Thanks: Cole Robinson, Dan Horak, Thomas Huth.
+(cherry picked from commit 6328f332361675abb0233db890d2bfe0d9a5092a)
+---
+ lib/launch-libvirt.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
+index 681281b9b..49bd40583 100644
+--- a/lib/launch-libvirt.c
++++ b/lib/launch-libvirt.c
+@@ -1347,6 +1347,7 @@ construct_libvirt_xml_devices (guestfs_h *g,
+         return -1;
+     }
+ 
++#ifndef __s390x__
+     /* Console. */
+     start_element ("serial") {
+       attribute ("type", "unix");
+@@ -1358,6 +1359,22 @@ construct_libvirt_xml_devices (guestfs_h *g,
+         attribute ("port", "0");
+       } end_element ();
+     } end_element ();
++#else
++    /* https://bugzilla.redhat.com/show_bug.cgi?id=1376547#c14
++     * and https://libvirt.org/formatdomain.html#elementCharConsole
++     */
++    start_element ("console") {
++      attribute ("type", "unix");
++      start_element ("source") {
++        attribute ("mode", "connect");
++        attribute ("path", params->data->console_path);
++      } end_element ();
++      start_element ("target") {
++	attribute ("type", "sclp");
++        attribute ("port", "0");
++      } end_element ();
++    } end_element ();
++#endif
+ 
+     /* Virtio-serial for guestfsd communication. */
+     start_element ("channel") {
+-- 
+2.14.3
+
diff --git a/SOURCES/0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch b/SOURCES/0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch
deleted file mode 100644
index ec063d5..0000000
--- a/SOURCES/0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch
+++ /dev/null
@@ -1,1954 +0,0 @@
-From 79c0796259820d1ee49bf442392bc3cc5d82322d Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Mon, 10 Apr 2017 15:24:26 +0100
-Subject: [PATCH] v2v: Implement -i vmx to read VMware vmx files directly
- (RHBZ#1441197).
-
-This is a mostly complete implementation of a VMX parser and input
-class for virt-v2v.  It parses the name, memory size, CPU topology,
-firmware, video, sound, hard disks, removable disks and network
-interfaces from the VMX file.  It only omits support for floppies and
-SCSI CD-ROMs.
-
-The input class is split into two major parts: a generic VMX file
-parser (Parse_vmx), and the Input_vmx module which translates the VMX
-tree into the source device model.
-
-This also contains tests.  There are simple unit tests of the
-Parse_vmx module, and also some more complete parsing tests taken from
-real guests.
-
-(cherry picked from commit ca40078cdda9167d4658ddfe24c828c7ee76be37)
----
- v2v/Makefile.am               |  15 ++
- v2v/cmdline.ml                |  12 +-
- v2v/input_vmx.ml              | 349 ++++++++++++++++++++++++++++++++++++++
- v2v/input_vmx.mli             |  22 +++
- v2v/name_from_disk.ml         |   2 +-
- v2v/parse_vmx.ml              | 381 ++++++++++++++++++++++++++++++++++++++++++
- v2v/parse_vmx.mli             |  89 ++++++++++
- v2v/test-v2v-i-vmx-1.expected |  42 +++++
- v2v/test-v2v-i-vmx-1.vmx      | 172 +++++++++++++++++++
- v2v/test-v2v-i-vmx-2.expected |  22 +++
- v2v/test-v2v-i-vmx-2.vmx      |  84 ++++++++++
- v2v/test-v2v-i-vmx-3.expected |  22 +++
- v2v/test-v2v-i-vmx-3.vmx      |  91 ++++++++++
- v2v/test-v2v-i-vmx-4.expected |  22 +++
- v2v/test-v2v-i-vmx-4.vmx      |  88 ++++++++++
- v2v/test-v2v-i-vmx.sh         |  48 ++++++
- v2v/v2v_unit_tests.ml         | 143 ++++++++++++++++
- v2v/virt-v2v.pod              |  72 +++++++-
- 18 files changed, 1667 insertions(+), 9 deletions(-)
- create mode 100644 v2v/input_vmx.ml
- create mode 100644 v2v/input_vmx.mli
- create mode 100644 v2v/parse_vmx.ml
- create mode 100644 v2v/parse_vmx.mli
- create mode 100644 v2v/test-v2v-i-vmx-1.expected
- create mode 100644 v2v/test-v2v-i-vmx-1.vmx
- create mode 100644 v2v/test-v2v-i-vmx-2.expected
- create mode 100644 v2v/test-v2v-i-vmx-2.vmx
- create mode 100644 v2v/test-v2v-i-vmx-3.expected
- create mode 100644 v2v/test-v2v-i-vmx-3.vmx
- create mode 100644 v2v/test-v2v-i-vmx-4.expected
- create mode 100644 v2v/test-v2v-i-vmx-4.vmx
- create mode 100755 v2v/test-v2v-i-vmx.sh
-
-diff --git a/v2v/Makefile.am b/v2v/Makefile.am
-index 297406496..0df759eca 100644
---- a/v2v/Makefile.am
-+++ b/v2v/Makefile.am
-@@ -38,6 +38,7 @@ SOURCES_MLI = \
- 	input_libvirt_xen_ssh.mli \
- 	input_libvirtxml.mli \
- 	input_ova.mli \
-+	input_vmx.mli \
- 	inspect_source.mli \
- 	libvirt_utils.mli \
- 	linux.mli \
-@@ -55,6 +56,7 @@ SOURCES_MLI = \
- 	OVF.mli \
- 	parse_ovf_from_ova.mli \
- 	parse_libvirt_xml.mli \
-+	parse_vmx.mli \
- 	qemu_command.mli \
- 	target_bus_assignment.mli \
- 	types.mli \
-@@ -80,6 +82,7 @@ SOURCES_ML = \
- 	windows_virtio.ml \
- 	modules_list.ml \
- 	input_disk.ml \
-+	parse_vmx.ml \
- 	parse_libvirt_xml.ml \
- 	create_libvirt_xml.ml \
- 	qemu_command.ml \
-@@ -89,6 +92,7 @@ SOURCES_ML = \
- 	input_libvirt_xen_ssh.ml \
- 	input_libvirt.ml \
- 	input_ova.ml \
-+	input_vmx.ml \
- 	linux_bootloaders.ml \
- 	linux_kernels.ml \
- 	convert_linux.ml \
-@@ -268,6 +272,7 @@ TESTS = \
- 	test-v2v-i-ova-subfolders.sh \
- 	test-v2v-i-ova-tar.sh \
- 	test-v2v-i-ova-two-disks.sh \
-+	test-v2v-i-vmx.sh \
- 	test-v2v-bad-networks-and-bridges.sh
- 
- if HAVE_LIBVIRT
-@@ -411,6 +416,15 @@ EXTRA_DIST += \
- 	test-v2v-i-ova.ovf \
- 	test-v2v-i-ova.sh \
- 	test-v2v-i-ova.xml \
-+	test-v2v-i-vmx.sh \
-+	test-v2v-i-vmx-1.expected \
-+	test-v2v-i-vmx-2.expected \
-+	test-v2v-i-vmx-3.expected \
-+	test-v2v-i-vmx-4.expected \
-+	test-v2v-i-vmx-1.vmx \
-+	test-v2v-i-vmx-2.vmx \
-+	test-v2v-i-vmx-3.vmx \
-+	test-v2v-i-vmx-4.vmx \
- 	test-v2v-machine-readable.sh \
- 	test-v2v-networks-and-bridges-expected.xml \
- 	test-v2v-networks-and-bridges.sh \
-@@ -450,6 +464,7 @@ v2v_unit_tests_BOBJECTS = \
- 	windows.cmo \
- 	windows_virtio.cmo \
- 	linux.cmo \
-+	parse_vmx.cmo \
- 	v2v_unit_tests.cmo
- v2v_unit_tests_XOBJECTS = $(v2v_unit_tests_BOBJECTS:.cmo=.cmx)
- 
-diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
-index a2f132b6c..0850f9136 100644
---- a/v2v/cmdline.ml
-+++ b/v2v/cmdline.ml
-@@ -86,6 +86,7 @@ let parse_cmdline () =
-     | "libvirt" -> input_mode := `Libvirt
-     | "libvirtxml" -> input_mode := `LibvirtXML
-     | "ova" -> input_mode := `OVA
-+    | "vmx" -> input_mode := `VMX
-     | s ->
-       error (f_"unknown -i option: %s") s
-   in
-@@ -331,7 +332,16 @@ read the man page virt-v2v(1).
-         | [filename] -> filename
-         | _ ->
-           error (f_"expecting an OVA file name on the command line") in
--      Input_ova.input_ova filename in
-+      Input_ova.input_ova filename
-+
-+    | `VMX ->
-+      (* -i vmx: Expecting an vmx filename. *)
-+      let filename =
-+        match args with
-+        | [filename] -> filename
-+        | _ ->
-+          error (f_"expecting a VMX file name on the command line") in
-+      Input_vmx.input_vmx filename in
- 
-   (* Prevent use of --in-place option in RHEL. *)
-   if in_place then
-diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
-new file mode 100644
-index 000000000..bb09f0bf8
---- /dev/null
-+++ b/v2v/input_vmx.ml
-@@ -0,0 +1,349 @@
-+(* virt-v2v
-+ * Copyright (C) 2017 Red Hat Inc.
-+ *
-+ * 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 2 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, write to the Free Software Foundation, Inc.,
-+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *)
-+
-+open Printf
-+open Scanf
-+
-+open Common_gettext.Gettext
-+open Common_utils
-+
-+open Types
-+open Utils
-+open Name_from_disk
-+
-+external identity : 'a -> 'a = "%identity"
-+
-+let rec find_disks vmx vmx_filename =
-+  find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename
-+
-+(* Find all SCSI hard disks.
-+ *
-+ * In the VMX file:
-+ *   scsi0.virtualDev = "pvscsi"  # or may be "lsilogic" etc.
-+ *   scsi0:0.deviceType = "scsi-hardDisk"
-+ *   scsi0:0.fileName = "guest.vmdk"
-+ *)
-+and find_scsi_disks vmx vmx_filename =
-+  let get_scsi_controller_target ns =
-+    sscanf ns "scsi%d:%d" (fun c t -> c, t)
-+  in
-+  let is_scsi_controller_target ns =
-+    try ignore (get_scsi_controller_target ns); true
-+    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
-+  in
-+  let scsi_device_types = [ "scsi-harddisk" ] in
-+  let scsi_controller = Source_SCSI in
-+
-+  find_hdds vmx vmx_filename
-+            get_scsi_controller_target is_scsi_controller_target
-+            scsi_device_types scsi_controller
-+
-+(* Find all IDE hard disks.
-+ *
-+ * In the VMX file:
-+ *   ide0:0.deviceType = "ata-hardDisk"
-+ *   ide0:0.fileName = "guest.vmdk"
-+ *)
-+and find_ide_disks vmx vmx_filename =
-+  let get_ide_controller_target ns =
-+    sscanf ns "ide%d:%d" (fun c t -> c, t)
-+  in
-+  let is_ide_controller_target ns =
-+    try ignore (get_ide_controller_target ns); true
-+    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
-+  in
-+  let ide_device_types = [ "ata-harddisk" ] in
-+  let ide_controller = Source_IDE in
-+
-+  find_hdds vmx vmx_filename
-+            get_ide_controller_target is_ide_controller_target
-+            ide_device_types ide_controller
-+
-+and find_hdds vmx vmx_filename
-+              get_controller_target is_controller_target
-+              device_types controller =
-+  (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *)
-+  let hdds =
-+    Parse_vmx.select_namespaces (
-+      function
-+      | [ns] ->
-+         (* Check the namespace is '(ide|scsi)X:Y' *)
-+         if not (is_controller_target ns) then false
-+         else (
-+           (* Check the deviceType is one we are looking for. *)
-+           match Parse_vmx.get_string vmx [ns; "deviceType"] with
-+           | Some str ->
-+              let str = String.lowercase_ascii str in
-+              List.mem str device_types
-+           | None -> false
-+         )
-+      | _ -> false
-+    ) vmx in
-+
-+  (* Map the subset to a list of disks. *)
-+  let hdds =
-+    Parse_vmx.map (
-+      fun path v ->
-+        match path, v with
-+        | [ns; "filename"], Some filename ->
-+           let c, t = get_controller_target ns in
-+           let s = { s_disk_id = (-1);
-+                     s_qemu_uri = qemu_uri_of_filename vmx_filename filename;
-+                     s_format = Some "vmdk";
-+                     s_controller = Some controller } in
-+           Some (c, t, s)
-+        | _ -> None
-+    ) hdds in
-+  let hdds = filter_map identity hdds in
-+
-+  (* We don't have a way to return the controllers and targets, so
-+   * just make sure the disks are sorted into order, since Parse_vmx
-+   * won't return them in any particular order.
-+   *)
-+  let hdds = List.sort compare hdds in
-+  let hdds = List.map (fun (_, _, source) -> source) hdds in
-+
-+  (* Set the s_disk_id field to an incrementing number. *)
-+  let hdds = mapi (fun i source -> { source with s_disk_id = i }) hdds in
-+
-+  hdds
-+
-+(* The filename can be an absolute path, but is more often a
-+ * path relative to the location of the vmx file.
-+ *
-+ * Note that we always end up with an absolute path, which is
-+ * also useful because it means we won't have any paths that
-+ * could be misinterpreted by qemu.
-+ *)
-+and qemu_uri_of_filename vmx_filename filename =
-+  if not (Filename.is_relative filename) then
-+    filename
-+  else (
-+    let dir = Filename.dirname (absolute_path vmx_filename) in
-+    dir // filename
-+  )
-+
-+(* Find all removable disks.
-+ *
-+ * In the VMX file:
-+ *   ide1:0.deviceType = "cdrom-image"
-+ *   ide1:0.fileName = "boot.iso"
-+ *
-+ * XXX This only supports IDE CD-ROMs, but we could support SCSI
-+ * CD-ROMs and floppies in future.
-+ *)
-+and find_removables vmx =
-+  let get_ide_controller_target ns =
-+    sscanf ns "ide%d:%d" (fun c t -> c, t)
-+  in
-+  let is_ide_controller_target ns =
-+    try ignore (get_ide_controller_target ns); true
-+    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
-+  in
-+  let device_types = [ "atapi-cdrom";
-+                       "cdrom-image"; "cdrom-raw" ] in
-+
-+  (* Find namespaces matching 'ideX:Y' with suitable deviceType. *)
-+  let devs =
-+    Parse_vmx.select_namespaces (
-+      function
-+      | [ns] ->
-+         (* Check the namespace is 'ideX:Y' *)
-+         if not (is_ide_controller_target ns) then false
-+         else (
-+           (* Check the deviceType is one we are looking for. *)
-+           match Parse_vmx.get_string vmx [ns; "deviceType"] with
-+           | Some str ->
-+              let str = String.lowercase_ascii str in
-+              List.mem str device_types
-+           | None -> false
-+         )
-+      | _ -> false
-+    ) vmx in
-+
-+  (* Map the subset to a list of CD-ROMs. *)
-+  let devs =
-+    Parse_vmx.map (
-+      fun path v ->
-+        match path, v with
-+        | [ns], None ->
-+           let c, t = get_ide_controller_target ns in
-+           let s = { s_removable_type = CDROM;
-+                     s_removable_controller = Some Source_IDE;
-+                     s_removable_slot = Some (ide_slot c t) } in
-+           Some s
-+        | _ -> None
-+    ) devs in
-+  let devs = filter_map identity devs in
-+
-+  (* Sort by slot. *)
-+  let devs =
-+    List.sort
-+      (fun { s_removable_slot = s1 } { s_removable_slot = s2 } ->
-+        compare s1 s2)
-+      devs in
-+
-+  devs
-+
-+and ide_slot c t =
-+  (* Assuming the old master/slave arrangement. *)
-+  c * 2 + t
-+
-+(* Find all ethernet cards.
-+ *
-+ * In the VMX file:
-+ *   ethernet0.virtualDev = "vmxnet3"
-+ *   ethernet0.networkName = "VM Network"
-+ *   ethernet0.generatedAddress = "00:01:02:03:04:05"
-+ *   ethernet0.connectionType = "bridged" # also: "custom", "nat" or not present
-+ *)
-+and find_nics vmx =
-+  let get_ethernet_port ns =
-+    sscanf ns "ethernet%d" (fun p -> p)
-+  in
-+  let is_ethernet_port ns =
-+    try ignore (get_ethernet_port ns); true
-+    with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
-+  in
-+
-+  (* Find namespaces matching 'ethernetX'. *)
-+  let nics =
-+    Parse_vmx.select_namespaces (
-+      function
-+      | [ns] -> is_ethernet_port ns
-+      | _ -> false
-+    ) vmx in
-+
-+  (* Map the subset to a list of NICs. *)
-+  let nics =
-+    Parse_vmx.map (
-+      fun path v ->
-+        match path, v with
-+        | [ns], None ->
-+           let port = get_ethernet_port ns in
-+           let mac = Parse_vmx.get_string vmx [ns; "generatedAddress"] in
-+           let model = Parse_vmx.get_string vmx [ns; "virtualDev"] in
-+           let model =
-+             match model with
-+             | Some m when String.lowercase_ascii m = "e1000" ->
-+                Some Source_e1000
-+             | Some model ->
-+                Some (Source_other_nic (String.lowercase_ascii model))
-+             | None -> None in
-+           let vnet = Parse_vmx.get_string vmx [ns; "networkName"] in
-+           let vnet =
-+             match vnet with
-+             | Some vnet -> vnet
-+             | None -> ns (* "ethernetX" *) in
-+           let vnet_type =
-+             match Parse_vmx.get_string vmx [ns; "connectionType"] with
-+             | Some b when String.lowercase_ascii b = "bridged" ->
-+                Bridge
-+             | Some _ | None -> Network in
-+           Some (port,
-+                 { s_mac = mac; s_nic_model = model;
-+                   s_vnet = vnet; s_vnet_orig = vnet;
-+                   s_vnet_type = vnet_type })
-+        | _ -> None
-+    ) nics in
-+  let nics = filter_map identity nics in
-+
-+  (* Sort by port. *)
-+  let nics = List.sort compare nics in
-+
-+  let nics = List.map (fun (_, source) -> source) nics in
-+  nics
-+
-+class input_vmx vmx_filename = object
-+  inherit input
-+
-+  method as_options = "-i vmx " ^ vmx_filename
-+
-+  method source () =
-+    (* Parse the VMX file. *)
-+    let vmx = Parse_vmx.parse_file vmx_filename in
-+
-+    let name =
-+      match Parse_vmx.get_string vmx ["displayName"] with
-+      | None ->
-+         warning (f_"no displayName key found in VMX file");
-+         name_from_disk vmx_filename
-+      | Some s -> s in
-+
-+    let memory_mb =
-+      match Parse_vmx.get_int64 vmx ["memSize"] with
-+      | None -> 32_L            (* default is really 32 MB! *)
-+      | Some i -> i in
-+    let memory = memory_mb *^ 1024L *^ 1024L in
-+
-+    let vcpu =
-+      match Parse_vmx.get_int vmx ["numvcpus"] with
-+      | None -> 1
-+      | Some i -> i in
-+
-+    let firmware =
-+      match Parse_vmx.get_string vmx ["firmware"] with
-+      | None -> BIOS
-+      | Some "efi" -> UEFI
-+      (* Other values are not documented for this field ... *)
-+      | Some fw ->
-+         warning (f_"unknown firmware value '%s', assuming BIOS") fw;
-+         BIOS in
-+
-+    let video =
-+      if Parse_vmx.namespace_present vmx ["svga"] then
-+        (* We could also parse svga.vramSize. *)
-+        Some (Source_other_video "vmvga")
-+      else
-+        None in
-+
-+    let sound =
-+      match Parse_vmx.get_string vmx ["sound"; "virtualDev"] with
-+      | Some ("sb16") -> Some { s_sound_model = SB16 }
-+      | Some ("es1371") -> Some { s_sound_model = ES1370 (* hmmm ... *) }
-+      | Some "hdaudio" -> Some { s_sound_model = ICH6 (* intel-hda *) }
-+      | Some model ->
-+         warning (f_"unknown sound device '%s' ignored") model;
-+         None
-+      | None -> None in
-+
-+    let disks = find_disks vmx vmx_filename in
-+    let removables = find_removables vmx in
-+    let nics = find_nics vmx in
-+
-+    let source = {
-+      s_hypervisor = VMware;
-+      s_name = name;
-+      s_orig_name = name;
-+      s_memory = memory;
-+      s_vcpu = vcpu;
-+      s_features = [];
-+      s_firmware = firmware;
-+      s_display = None;
-+      s_video = video;
-+      s_sound = sound;
-+      s_disks = disks;
-+      s_removables = removables;
-+      s_nics = nics;
-+    } in
-+
-+    source
-+end
-+
-+let input_vmx = new input_vmx
-+let () = Modules_list.register_input_module "vmx"
-diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli
-new file mode 100644
-index 000000000..f236f8716
---- /dev/null
-+++ b/v2v/input_vmx.mli
-@@ -0,0 +1,22 @@
-+(* virt-v2v
-+ * Copyright (C) 2017 Red Hat Inc.
-+ *
-+ * 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 2 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, write to the Free Software Foundation, Inc.,
-+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *)
-+
-+(** [-i vmx] source. *)
-+
-+val input_vmx : string -> Types.input
-+(** [input_vmx filename] sets up an input from vmware vmx file. *)
-diff --git a/v2v/name_from_disk.ml b/v2v/name_from_disk.ml
-index 82f09250a..452d9462c 100644
---- a/v2v/name_from_disk.ml
-+++ b/v2v/name_from_disk.ml
-@@ -24,7 +24,7 @@ let name_from_disk disk =
-   (* Remove the extension (or suffix), only if it's one usually
-    * used for disk images. *)
-   let suffixes = [
--    ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk";
-+    ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; ".vmx";
-     "-sda";
-   ] in
-   let rec loop = function
-diff --git a/v2v/parse_vmx.ml b/v2v/parse_vmx.ml
-new file mode 100644
-index 000000000..33ec17d3d
---- /dev/null
-+++ b/v2v/parse_vmx.ml
-@@ -0,0 +1,381 @@
-+(* virt-v2v
-+ * Copyright (C) 2017 Red Hat Inc.
-+ *
-+ * 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 2 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, write to the Free Software Foundation, Inc.,
-+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *)
-+
-+open Printf
-+
-+open Common_utils
-+open Common_gettext.Gettext
-+
-+(* As far as I can tell the VMX format is totally unspecified.
-+ * However libvirt has a useful selection of .vmx files in the
-+ * sources which explore some of the darker regions of this
-+ * format.
-+ *
-+ * So here are some facts about VMX derived from libvirt and
-+ * other places:
-+ *
-+ * - Keys are compared case insensitively.  We assume here
-+ *   that keys are 7-bit ASCII.
-+ *
-+ * - Multiple keys with the same name are not allowed.
-+ *
-+ * - Escaping in the value string is possible using a very weird
-+ *   escape format: "|22" means the character '\x22'.  To write
-+ *   a pipe character you must use "|7C".
-+ *
-+ * - Boolean values are written "TRUE", "FALSE", "True", "true", etc.
-+ *   Because of the quotes they cannot be distinguished from strings.
-+ *
-+ * - Comments (#...) and blank lines are ignored.  Some files start
-+ *   with a hash-bang path, but we ignore those as comments.  This
-+ *   parser also ignores any other line which it doesn't understand,
-+ *   but will print a warning.
-+ *
-+ * - Multi-line values are not permitted.
-+ *
-+ * - Keys are namespaced using dots, eg. scsi0:0.deviceType has
-+ *   the namespace "scsi0:0" and the key name "deviceType".
-+ *
-+ * - Using namespace.present = "FALSE" means that all other keys
-+ *   in and under the namespace are ignored.
-+ *
-+ * - You cannot have a namespace and a key with the same name, eg.
-+ *   this is not allowed:
-+ *     namespace = "some value"
-+ *     namespace.foo = "another value"
-+ *
-+ * - The Hashicorp packer VMX writer considers some special keys
-+ *   as not requiring any quotes around their values, but I'm
-+ *   ignoring that for now.
-+ *)
-+
-+(* This VMX file:
-+ *
-+ *   foo.a = "abc"
-+ *   foo.b = "def"
-+ *   foo.bar.c = "abc"
-+ *   foo.bar.d = "def"
-+ *
-+ * would be represented by this structure:
-+ *
-+ *   "foo" => Namespace (             # "foo" is a namespace
-+ *              "a" => Key "abc";     # "foo.a" is a key with value "abc"
-+ *              "b" => Key "def";
-+ *              "bar" => Namespace (  # "foo.bar" is another namespace
-+ *                         "c" => Key "abc";
-+ *                         "d" => Key "def";
-+ *                       )
-+ *            )
-+ *   ‘( => )’s represent the StringMap type.
-+ *)
-+type t = key StringMap.t
-+
-+and key =
-+  | Key of string
-+  | Namespace of t
-+
-+let empty = StringMap.empty
-+
-+(* Compare two trees for equality. *)
-+let rec equal vmx1 vmx2 =
-+  let cmp k1 k2 =
-+    match k1, k2 with
-+    | Key v1, Key v2 -> v1 = v2
-+    | Key _, Namespace _ -> false
-+    | Namespace _, Key _ -> false
-+    | Namespace vmx1, Namespace vmx2 -> equal vmx1 vmx2
-+  in
-+  StringMap.equal cmp vmx1 vmx2
-+
-+(* Higher-order functions. *)
-+let rec select_namespaces pred vmx =
-+  _select_namespaces [] pred vmx
-+
-+and _select_namespaces path pred vmx =
-+  StringMap.fold (
-+    fun k v new_vmx ->
-+      let path = path @ [k] in
-+      match v with
-+      | Key _ -> new_vmx
-+      | Namespace _ when pred path ->
-+         StringMap.add k v new_vmx
-+      | Namespace t ->
-+         let t = _select_namespaces path pred t in
-+         if not (equal t empty) then
-+           StringMap.add k (Namespace t) new_vmx
-+         else
-+           new_vmx
-+  ) vmx empty
-+
-+let rec map f vmx =
-+  _map [] f vmx
-+
-+and _map path f vmx =
-+  StringMap.fold (
-+    fun k v r ->
-+      let path = path @ [k] in
-+      match v with
-+      | Key v -> r @ [ f path (Some v) ]
-+      | Namespace t -> r @ [ f path None ] @ _map path f t
-+  ) vmx []
-+
-+let rec namespace_present vmx = function
-+  | [] -> false
-+  | [ns] ->
-+     let ns = String.lowercase_ascii ns in
-+     (try
-+        let v = StringMap.find ns vmx in
-+        match v with
-+        | Key _ -> false
-+        | Namespace _ -> true
-+      with
-+        Not_found -> false
-+     )
-+  | ns :: path ->
-+     let ns = String.lowercase_ascii ns in
-+     (try
-+        let v = StringMap.find ns vmx in
-+        match v with
-+        | Key _ -> false
-+        | Namespace vmx -> namespace_present vmx path
-+      with
-+        Not_found -> false
-+     )
-+
-+(* Dump the vmx structure to [chan].  Used for debugging. *)
-+let rec print chan indent vmx =
-+  StringMap.iter (print_key chan indent) vmx
-+
-+and print_key chan indent k = function
-+  | Key v ->
-+     output_spaces chan indent;
-+     fprintf chan "%s = \"%s\"\n" k v
-+  | Namespace vmx ->
-+     output_spaces chan indent;
-+     fprintf chan "namespace '%s':\n" k;
-+     print chan (indent+4) vmx
-+
-+(* As above, but creates a string instead. *)
-+let rec to_string indent vmx =
-+  StringMap.fold (fun k v str -> str ^ to_string_key indent k v) vmx ""
-+
-+and to_string_key indent k = function
-+  | Key v ->
-+     String.spaces indent ^ sprintf "%s = \"%s\"\n" k v
-+  | Namespace vmx ->
-+     String.spaces indent ^ sprintf "namespace '%s':\n" k ^
-+       to_string (indent+4) vmx
-+
-+(* Access keys in the tree. *)
-+let rec get_string vmx = function
-+  | [] -> None
-+  | [k] ->
-+     let k = String.lowercase_ascii k in
-+     (try
-+        let v = StringMap.find k vmx in
-+        match v with
-+        | Key v -> Some v
-+        | Namespace _ -> None
-+      with Not_found -> None
-+     )
-+  | ns :: path ->
-+     let ns = String.lowercase_ascii ns in
-+     (try
-+        let v = StringMap.find ns vmx in
-+        match v with
-+        | Key v -> None
-+        | Namespace vmx -> get_string vmx path
-+      with
-+        Not_found -> None
-+     )
-+
-+let get_int64 vmx path =
-+  match get_string vmx path with
-+  | None -> None
-+  | Some i -> Some (Int64.of_string i)
-+
-+let get_int vmx path =
-+  match get_string vmx path with
-+  | None -> None
-+  | Some i -> Some (int_of_string i)
-+
-+let rec get_bool vmx path =
-+  match get_string vmx path with
-+  | None -> None
-+  | Some t -> Some (vmx_bool_of_string t)
-+
-+and vmx_bool_of_string t =
-+  if String.lowercase_ascii t = "true" then true
-+  else if String.lowercase_ascii t = "false" then false
-+  else failwith "bool_of_string"
-+
-+(* Regular expression used to match key = "value" in VMX file. *)
-+let rex = Str.regexp "^\\([^ \t=]+\\)[ \t]*=[ \t]*\"\\(.*\\)\"$"
-+
-+(* Remove the weird escapes used in value strings.  See description above. *)
-+let remove_vmx_escapes str =
-+  let len = String.length str in
-+  let out = Bytes.make len '\000' in
-+  let j = ref 0 in
-+
-+  let rec loop i =
-+    if i >= len then ()
-+    else (
-+      let c = String.unsafe_get str i in
-+      if i <= len-3 && c = '|' then (
-+        let c1 = str.[i+1] and c2 = str.[i+2] in
-+        if Char.isxdigit c1 && Char.isxdigit c2 then (
-+          let x = Char.hexdigit c1 * 0x10 + Char.hexdigit c2 in
-+          Bytes.set out !j (Char.chr x);
-+          incr j;
-+          loop (i+3)
-+        )
-+        else (
-+          Bytes.set out !j c;
-+          incr j;
-+          loop (i+1)
-+        )
-+      )
-+      else (
-+        Bytes.set out !j c;
-+        incr j;
-+        loop (i+1)
-+      )
-+    )
-+  in
-+  loop 0;
-+
-+  (* Truncate the output string to its real size and return it
-+   * as an immutable string.
-+   *)
-+  Bytes.sub_string out 0 !j
-+
-+(* Parsing. *)
-+let rec parse_file vmx_filename =
-+  (* Read the whole file as a list of lines. *)
-+  let str = read_whole_file vmx_filename in
-+  if verbose () then eprintf "VMX file:\n%s\n" str;
-+  parse_string str
-+
-+and parse_string str =
-+  let lines = String.nsplit "\n" str in
-+
-+  (* I've never seen any VMX file with CR-LF endings, and VMware
-+   * itself is Linux-based, but to be on the safe side ...
-+   *)
-+  let lines = List.map (String.trimr ~test:((=) '\r')) lines in
-+
-+  (* Ignore blank lines and comments. *)
-+  let lines = List.filter (
-+    fun line ->
-+      let line = String.triml line in
-+      let len = String.length line in
-+      len > 0 && line.[0] != '#'
-+  ) lines in
-+
-+  (* Parse the lines into key = "value". *)
-+  let lines = filter_map (
-+    fun line ->
-+      if Str.string_match rex line 0 then (
-+        let key = Str.matched_group 1 line in
-+        let key = String.lowercase_ascii key in
-+        let value = Str.matched_group 2 line in
-+        let value = remove_vmx_escapes value in
-+        Some (key, value)
-+      )
-+      else (
-+        warning (f_"vmx parser: cannot parse this line, ignoring: %s") line;
-+        None
-+      )
-+  ) lines in
-+
-+  (* Split the keys into namespace paths. *)
-+  let lines =
-+    List.map (fun (key, value) -> String.nsplit "." key, value) lines in
-+
-+  (* Build a tree from the flat list and return it.  This is horribly
-+   * inefficient, at least O(n²), possibly even O(n².log n).  Hope
-+   * there are no large VMX files!  (XXX)
-+   *)
-+  let vmx =
-+    List.fold_left (
-+      fun vmx (path, value) -> insert vmx value path
-+    ) empty lines in
-+
-+  (* If we're verbose, dump the parsed VMX for debugging purposes. *)
-+  if verbose () then (
-+    eprintf "parsed VMX tree:\n";
-+    print stderr 0 vmx
-+  );
-+
-+  (* Drop all present = "FALSE" namespaces. *)
-+  let vmx = drop_not_present vmx in
-+
-+  vmx
-+
-+and insert vmx value = function
-+  | [] -> assert false
-+  | [k] ->
-+     if StringMap.mem k vmx then (
-+       warning (f_"vmx parser: duplicate key '%s' ignored") k;
-+       vmx
-+     ) else
-+       StringMap.add k (Key value) vmx
-+  | ns :: path ->
-+     let v =
-+       try
-+         (match StringMap.find ns vmx with
-+          | Namespace vmx -> Some vmx
-+          | Key _ -> None
-+         )
-+       with Not_found -> None in
-+     let v =
-+       match v with
-+       | None ->
-+          (* Completely new namespace. *)
-+          insert empty value path
-+       | Some v ->
-+          (* Insert the subkey into the previously created namespace. *)
-+          insert v value path in
-+     StringMap.add ns (Namespace v) vmx
-+
-+(* Find any "present" keys.  If we find present = "FALSE", then
-+ * drop the containing namespace and all subkeys and subnamespaces.
-+ *)
-+and drop_not_present vmx =
-+  StringMap.fold (
-+    fun k v new_vmx ->
-+      match v with
-+      | Key _ ->
-+         StringMap.add k v new_vmx
-+      | Namespace vmx when contains_key_present_false vmx ->
-+         (* drop this namespace and all sub-spaces *)
-+         new_vmx
-+      | Namespace v ->
-+         (* recurse into sub-namespace and do the same check *)
-+         let v = drop_not_present v in
-+         StringMap.add k (Namespace v) new_vmx
-+  ) vmx empty
-+
-+and contains_key_present_false vmx =
-+  try
-+    match StringMap.find "present" vmx with
-+    | Key v when vmx_bool_of_string v = false -> true
-+    | Key _ | Namespace _ -> false
-+  with
-+    Failure _ | Not_found -> false
-diff --git a/v2v/parse_vmx.mli b/v2v/parse_vmx.mli
-new file mode 100644
-index 000000000..0e4f21f07
---- /dev/null
-+++ b/v2v/parse_vmx.mli
-@@ -0,0 +1,89 @@
-+(* virt-v2v
-+ * Copyright (C) 2017 Red Hat Inc.
-+ *
-+ * 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 2 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, write to the Free Software Foundation, Inc.,
-+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *)
-+
-+(** A simple parser for VMware [.vmx] files. *)
-+
-+type t
-+
-+val parse_file : string -> t
-+(** [parse_file filename] parses a VMX file. *)
-+
-+val parse_string : string -> t
-+(** [parse_string s] parses VMX from a string. *)
-+
-+val get_string : t -> string list -> string option
-+(** Find a key and return it as a string.  If not present, returns [None].
-+
-+    Note that if [namespace.present = "FALSE"] is found in the file
-+    then all keys in [namespace] and below it are ignored.  This
-+    applies to all [get_*] functions. *)
-+
-+val get_int64 : t -> string list -> int64 option
-+(** Find a key and return it as an [int64].
-+    If not present, returns [None].
-+
-+    Raises [Failure _] if the key is present but was not parseable
-+    as an integer. *)
-+
-+val get_int : t -> string list -> int option
-+(** Find a key and return it as an [int].
-+    If not present, returns [None].
-+
-+    Raises [Failure _] if the key is present but was not parseable
-+    as an integer. *)
-+
-+val get_bool : t -> string list -> bool option
-+(** Find a key and return it as a boolean.
-+
-+    You cannot return [namespace.present = "FALSE"] booleans this way.
-+    They are processed by the parser and the namespace and anything
-+    below it are removed from the tree.
-+
-+    Raises [Failure _] if the key is present but was not parseable
-+    as a boolean. *)
-+
-+val namespace_present : t -> string list -> bool
-+(** Returns true iff the namespace ({b note:} not key) is present. *)
-+
-+val select_namespaces : (string list -> bool) -> t -> t
-+(** Filter the VMX file, selecting exactly namespaces (and their
-+    keys) matching the predicate.  The predicate is a function which
-+    is called on each {i namespace} path ({b note:} not on
-+    namespace + key paths).  If the predicate matches a
-+    namespace, then all sub-namespaces under that namespace are
-+    selected implicitly. *)
-+
-+val map : (string list -> string option -> 'a) -> t -> 'a list
-+(** Map all the entries in the VMX file into a list using the
-+    map function.  The map function takes two arguments.  The
-+    first is the path to the namespace or key, and the second
-+    is the key value (or [None] if the path refers to a namespace). *)
-+
-+val equal : t -> t -> bool
-+(** Compare two VMX files for equality.  This is mainly used for
-+    testing the parser. *)
-+
-+val empty : t
-+(** An empty VMX file. *)
-+
-+val print : out_channel -> int -> t -> unit
-+(** [print chan indent] prints the VMX file to the output channel.
-+    [indent] is the indentation applied to each line of output. *)
-+
-+val to_string : int -> t -> string
-+(** Same as {!print} but it creates a printable (multiline) string. *)
-diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected
-new file mode 100644
-index 000000000..d32a29987
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-1.expected
-@@ -0,0 +1,42 @@
-+[   0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx
-+Source guest information (--print-source option):
-+
-+    source name: BZ1308535_21disks
-+hypervisor type: vmware
-+         memory: 2147483648 (bytes)
-+       nr vCPUs: 1
-+     CPU vendor: 
-+      CPU model: 
-+   CPU topology: sockets: - cores/socket: - threads/core: -
-+   CPU features: 
-+       firmware: bios
-+        display: 
-+          video: vmvga
-+          sound: 
-+disks:
-+	/BZ1308535_21disks.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_1.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_2.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_3.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_4.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_5.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_6.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_7.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_8.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_9.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_10.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_11.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_12.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_13.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_14.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_15.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_16.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_17.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_18.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_19.vmdk (vmdk) [scsi]
-+	/BZ1308535_21disks_20.vmdk (vmdk) [scsi]
-+removable media:
-+	CD-ROM [ide] in slot 2
-+NICs:
-+	Network "VM Network" mac: 00:0c:29:36:ef:31 [vmxnet3]
-+
-diff --git a/v2v/test-v2v-i-vmx-1.vmx b/v2v/test-v2v-i-vmx-1.vmx
-new file mode 100644
-index 000000000..3f2f060a5
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-1.vmx
-@@ -0,0 +1,172 @@
-+.encoding = "UTF-8"
-+config.version = "8"
-+virtualHW.version = "8"
-+nvram = "BZ1308535_21disks.nvram"
-+pciBridge0.present = "TRUE"
-+svga.present = "TRUE"
-+pciBridge4.present = "TRUE"
-+pciBridge4.virtualDev = "pcieRootPort"
-+pciBridge4.functions = "8"
-+pciBridge5.present = "TRUE"
-+pciBridge5.virtualDev = "pcieRootPort"
-+pciBridge5.functions = "8"
-+pciBridge6.present = "TRUE"
-+pciBridge6.virtualDev = "pcieRootPort"
-+pciBridge6.functions = "8"
-+pciBridge7.present = "TRUE"
-+pciBridge7.virtualDev = "pcieRootPort"
-+pciBridge7.functions = "8"
-+vmci0.present = "TRUE"
-+hpet0.present = "TRUE"
-+displayName = "BZ1308535_21disks"
-+extendedConfigFile = "BZ1308535_21disks.vmxf"
-+virtualHW.productCompatibility = "hosted"
-+memSize = "2048"
-+sched.cpu.units = "mhz"
-+powerType.powerOff = "soft"
-+powerType.suspend = "hard"
-+powerType.reset = "soft"
-+scsi0.virtualDev = "pvscsi"
-+scsi0.present = "TRUE"
-+scsi1.virtualDev = "pvscsi"
-+scsi1.present = "TRUE"
-+ide1:0.deviceType = "cdrom-image"
-+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso"
-+ide1:0.present = "TRUE"
-+floppy0.startConnected = "FALSE"
-+floppy0.clientDevice = "TRUE"
-+floppy0.fileName = "vmware-null-remote-floppy"
-+ethernet0.virtualDev = "vmxnet3"
-+ethernet0.networkName = "VM Network"
-+ethernet0.addressType = "generated"
-+ethernet0.present = "TRUE"
-+scsi0:0.deviceType = "scsi-hardDisk"
-+scsi0:0.fileName = "BZ1308535_21disks.vmdk"
-+scsi0:0.present = "TRUE"
-+scsi0:1.deviceType = "scsi-hardDisk"
-+scsi0:1.fileName = "BZ1308535_21disks_1.vmdk"
-+scsi0:1.present = "TRUE"
-+scsi0:2.deviceType = "scsi-hardDisk"
-+scsi0:2.fileName = "BZ1308535_21disks_2.vmdk"
-+scsi0:2.present = "TRUE"
-+scsi0:3.deviceType = "scsi-hardDisk"
-+scsi0:3.fileName = "BZ1308535_21disks_3.vmdk"
-+scsi0:3.present = "TRUE"
-+scsi0:4.deviceType = "scsi-hardDisk"
-+scsi0:4.fileName = "BZ1308535_21disks_4.vmdk"
-+scsi0:4.present = "TRUE"
-+scsi0:5.deviceType = "scsi-hardDisk"
-+scsi0:5.fileName = "BZ1308535_21disks_5.vmdk"
-+scsi0:5.present = "TRUE"
-+scsi0:6.deviceType = "scsi-hardDisk"
-+scsi0:6.fileName = "BZ1308535_21disks_6.vmdk"
-+scsi0:6.present = "TRUE"
-+scsi0:8.deviceType = "scsi-hardDisk"
-+scsi0:8.fileName = "BZ1308535_21disks_7.vmdk"
-+scsi0:8.present = "TRUE"
-+scsi0:9.deviceType = "scsi-hardDisk"
-+scsi0:9.fileName = "BZ1308535_21disks_8.vmdk"
-+scsi0:9.present = "TRUE"
-+scsi0:10.deviceType = "scsi-hardDisk"
-+scsi0:10.fileName = "BZ1308535_21disks_9.vmdk"
-+scsi0:10.present = "TRUE"
-+scsi0:11.deviceType = "scsi-hardDisk"
-+scsi0:11.fileName = "BZ1308535_21disks_10.vmdk"
-+scsi0:11.present = "TRUE"
-+scsi0:12.deviceType = "scsi-hardDisk"
-+scsi0:12.fileName = "BZ1308535_21disks_11.vmdk"
-+scsi0:12.present = "TRUE"
-+scsi0:13.deviceType = "scsi-hardDisk"
-+scsi0:13.fileName = "BZ1308535_21disks_12.vmdk"
-+scsi0:13.present = "TRUE"
-+scsi0:14.deviceType = "scsi-hardDisk"
-+scsi0:14.fileName = "BZ1308535_21disks_13.vmdk"
-+scsi0:14.present = "TRUE"
-+scsi0:15.deviceType = "scsi-hardDisk"
-+scsi0:15.fileName = "BZ1308535_21disks_14.vmdk"
-+scsi0:15.present = "TRUE"
-+scsi1:0.deviceType = "scsi-hardDisk"
-+scsi1:0.fileName = "BZ1308535_21disks_15.vmdk"
-+scsi1:0.present = "TRUE"
-+scsi1:1.deviceType = "scsi-hardDisk"
-+scsi1:1.fileName = "BZ1308535_21disks_16.vmdk"
-+scsi1:1.present = "TRUE"
-+scsi1:2.deviceType = "scsi-hardDisk"
-+scsi1:2.fileName = "BZ1308535_21disks_17.vmdk"
-+scsi1:2.present = "TRUE"
-+scsi1:3.deviceType = "scsi-hardDisk"
-+scsi1:3.fileName = "BZ1308535_21disks_18.vmdk"
-+scsi1:3.present = "TRUE"
-+scsi1:4.deviceType = "scsi-hardDisk"
-+scsi1:4.fileName = "BZ1308535_21disks_19.vmdk"
-+scsi1:4.present = "TRUE"
-+scsi1:5.deviceType = "scsi-hardDisk"
-+scsi1:5.fileName = "BZ1308535_21disks_20.vmdk"
-+scsi1:5.present = "TRUE"
-+guestOS = "rhel6-64"
-+toolScripts.afterPowerOn = "TRUE"
-+toolScripts.afterResume = "TRUE"
-+toolScripts.beforeSuspend = "TRUE"
-+toolScripts.beforePowerOff = "TRUE"
-+uuid.bios = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31"
-+uuid.location = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31"
-+vc.uuid = "52 31 cb fc c1 3f 96 32-83 c0 bb 70 6c 90 5c fd"
-+chipset.onlineStandby = "FALSE"
-+sched.cpu.min = "0"
-+sched.cpu.shares = "normal"
-+sched.mem.min = "0"
-+sched.mem.minSize = "0"
-+sched.mem.shares = "normal"
-+svga.vramSize = "8388608"
-+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/BZ1308535_21disks/BZ1308535_21disks-6a024f8a.vswp"
-+replay.supported = "FALSE"
-+replay.filename = ""
-+scsi0:0.redo = ""
-+scsi0:1.redo = ""
-+scsi0:2.redo = ""
-+scsi0:3.redo = ""
-+scsi0:4.redo = ""
-+scsi0:5.redo = ""
-+scsi0:6.redo = ""
-+scsi0:8.redo = ""
-+scsi0:9.redo = ""
-+scsi0:10.redo = ""
-+scsi0:11.redo = ""
-+scsi0:12.redo = ""
-+scsi0:13.redo = ""
-+scsi0:14.redo = ""
-+scsi0:15.redo = ""
-+scsi1:0.redo = ""
-+scsi1:1.redo = ""
-+scsi1:2.redo = ""
-+scsi1:3.redo = ""
-+scsi1:4.redo = ""
-+scsi1:5.redo = ""
-+pciBridge0.pciSlotNumber = "17"
-+pciBridge4.pciSlotNumber = "21"
-+pciBridge5.pciSlotNumber = "22"
-+pciBridge6.pciSlotNumber = "23"
-+pciBridge7.pciSlotNumber = "24"
-+scsi0.pciSlotNumber = "160"
-+scsi1.pciSlotNumber = "192"
-+ethernet0.pciSlotNumber = "224"
-+vmci0.pciSlotNumber = "32"
-+scsi0.sasWWID = "50 05 05 6f e6 46 bd 80"
-+scsi1.sasWWID = "50 05 05 6f e6 46 bc 80"
-+ethernet0.generatedAddress = "00:0c:29:36:ef:31"
-+ethernet0.generatedAddressOffset = "0"
-+vmci0.id = "2000088881"
-+hostCPUID.0 = "0000000d756e65476c65746e49656e69"
-+hostCPUID.1 = "000206a700100800179ae3bfbfebfbff"
-+hostCPUID.80000001 = "00000000000000000000000128100800"
-+guestCPUID.0 = "0000000d756e65476c65746e49656e69"
-+guestCPUID.1 = "000206a700010800969822030fabfbff"
-+guestCPUID.80000001 = "00000000000000000000000128100800"
-+userCPUID.0 = "0000000d756e65476c65746e49656e69"
-+userCPUID.1 = "000206a700100800169822030fabfbff"
-+userCPUID.80000001 = "00000000000000000000000128100800"
-+evcCompatibilityMode = "FALSE"
-+vmotion.checkpointFBSize = "8388608"
-+cleanShutdown = "TRUE"
-+softPowerOff = "TRUE"
-+tools.remindInstall = "TRUE"
-diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected
-new file mode 100644
-index 000000000..dc3eb60f2
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-2.expected
-@@ -0,0 +1,22 @@
-+[   0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx
-+Source guest information (--print-source option):
-+
-+    source name: Fedora 20
-+hypervisor type: vmware
-+         memory: 2147483648 (bytes)
-+       nr vCPUs: 1
-+     CPU vendor: 
-+      CPU model: 
-+   CPU topology: sockets: - cores/socket: - threads/core: -
-+   CPU features: 
-+       firmware: bios
-+        display: 
-+          video: vmvga
-+          sound: 
-+disks:
-+	/Fedora 20.vmdk (vmdk) [scsi]
-+removable media:
-+
-+NICs:
-+	Network "VM Network" mac: 00:50:56:9b:5f:0d [vmxnet3]
-+
-diff --git a/v2v/test-v2v-i-vmx-2.vmx b/v2v/test-v2v-i-vmx-2.vmx
-new file mode 100644
-index 000000000..d9dcf3a5c
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-2.vmx
-@@ -0,0 +1,84 @@
-+.encoding = "UTF-8"
-+config.version = "8"
-+virtualHW.version = "10"
-+nvram = "Fedora 20.nvram"
-+pciBridge0.present = "TRUE"
-+svga.present = "TRUE"
-+pciBridge4.present = "TRUE"
-+pciBridge4.virtualDev = "pcieRootPort"
-+pciBridge4.functions = "8"
-+pciBridge5.present = "TRUE"
-+pciBridge5.virtualDev = "pcieRootPort"
-+pciBridge5.functions = "8"
-+pciBridge6.present = "TRUE"
-+pciBridge6.virtualDev = "pcieRootPort"
-+pciBridge6.functions = "8"
-+pciBridge7.present = "TRUE"
-+pciBridge7.virtualDev = "pcieRootPort"
-+pciBridge7.functions = "8"
-+vmci0.present = "TRUE"
-+hpet0.present = "TRUE"
-+displayName = "Fedora 20"
-+extendedConfigFile = "Fedora 20.vmxf"
-+virtualHW.productCompatibility = "hosted"
-+svga.vramSize = "8388608"
-+memSize = "2048"
-+sched.cpu.units = "mhz"
-+sched.cpu.affinity = "all"
-+powerType.powerOff = "soft"
-+powerType.suspend = "hard"
-+powerType.reset = "soft"
-+scsi0.virtualDev = "pvscsi"
-+scsi0.present = "TRUE"
-+sata0.present = "TRUE"
-+scsi0:0.deviceType = "scsi-hardDisk"
-+scsi0:0.fileName = "Fedora 20.vmdk"
-+sched.scsi0:0.shares = "normal"
-+sched.scsi0:0.throughputCap = "off"
-+scsi0:0.present = "TRUE"
-+ethernet0.virtualDev = "vmxnet3"
-+ethernet0.networkName = "VM Network"
-+ethernet0.addressType = "vpx"
-+ethernet0.generatedAddress = "00:50:56:9b:5f:0d"
-+ethernet0.present = "TRUE"
-+sata0:0.startConnected = "FALSE"
-+sata0:0.deviceType = "cdrom-image"
-+sata0:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/Fedora-20-x86_64-netinst.iso"
-+sata0:0.present = "TRUE"
-+floppy0.startConnected = "FALSE"
-+floppy0.clientDevice = "TRUE"
-+floppy0.fileName = "vmware-null-remote-floppy"
-+vmci.filter.enable = "TRUE"
-+guestOS = "rhel7-64"
-+toolScripts.afterPowerOn = "TRUE"
-+toolScripts.afterResume = "TRUE"
-+toolScripts.beforeSuspend = "TRUE"
-+toolScripts.beforePowerOff = "TRUE"
-+uuid.bios = "42 1b 4b 87 e6 b7 d8 81-07 a0 c9 d2 21 cd 3c 6b"
-+vc.uuid = "50 1b 1f 1b 73 00 32 bf-93 a1 1c b2 b4 e6 17 d6"
-+sched.cpu.min = "0"
-+sched.cpu.shares = "normal"
-+sched.mem.min = "0"
-+sched.mem.minSize = "0"
-+sched.mem.shares = "normal"
-+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Fedora 20/Fedora 20-c71e4118.vswp"
-+uuid.location = "56 4d 0f 53 00 63 d5 55-41 01 4c f7 55 ce 03 0e"
-+replay.supported = "TRUE"
-+replay.filename = ""
-+scsi0:0.redo = ""
-+pciBridge0.pciSlotNumber = "17"
-+pciBridge4.pciSlotNumber = "21"
-+pciBridge5.pciSlotNumber = "22"
-+pciBridge6.pciSlotNumber = "23"
-+pciBridge7.pciSlotNumber = "24"
-+scsi0.pciSlotNumber = "160"
-+ethernet0.pciSlotNumber = "192"
-+vmci0.pciSlotNumber = "32"
-+sata0.pciSlotNumber = "33"
-+scsi0.sasWWID = "50 05 05 67 e6 b7 d8 80"
-+vmci0.id = "567098475"
-+vmotion.checkpointFBSize = "8388608"
-+cleanShutdown = "TRUE"
-+softPowerOff = "TRUE"
-+sata0:0.allowGuestConnectionControl = "TRUE"
-+tools.syncTime = "FALSE"
-diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected
-new file mode 100644
-index 000000000..9e643526f
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-3.expected
-@@ -0,0 +1,22 @@
-+[   0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx
-+Source guest information (--print-source option):
-+
-+    source name: RHEL 7.1 UEFI
-+hypervisor type: vmware
-+         memory: 2147483648 (bytes)
-+       nr vCPUs: 1
-+     CPU vendor: 
-+      CPU model: 
-+   CPU topology: sockets: - cores/socket: - threads/core: -
-+   CPU features: 
-+       firmware: uefi
-+        display: 
-+          video: vmvga
-+          sound: 
-+disks:
-+	/RHEL 7.1 UEFI.vmdk (vmdk) [scsi]
-+removable media:
-+	CD-ROM [ide] in slot 2
-+NICs:
-+	Network "VM Network" mac: 00:0c:29:4b:2b:8c [vmxnet3]
-+
-diff --git a/v2v/test-v2v-i-vmx-3.vmx b/v2v/test-v2v-i-vmx-3.vmx
-new file mode 100644
-index 000000000..c39215555
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-3.vmx
-@@ -0,0 +1,91 @@
-+.encoding = "UTF-8"
-+config.version = "8"
-+virtualHW.version = "8"
-+nvram = "RHEL 7.1 UEFI.nvram"
-+pciBridge0.present = "TRUE"
-+svga.present = "TRUE"
-+pciBridge4.present = "TRUE"
-+pciBridge4.virtualDev = "pcieRootPort"
-+pciBridge4.functions = "8"
-+pciBridge5.present = "TRUE"
-+pciBridge5.virtualDev = "pcieRootPort"
-+pciBridge5.functions = "8"
-+pciBridge6.present = "TRUE"
-+pciBridge6.virtualDev = "pcieRootPort"
-+pciBridge6.functions = "8"
-+pciBridge7.present = "TRUE"
-+pciBridge7.virtualDev = "pcieRootPort"
-+pciBridge7.functions = "8"
-+vmci0.present = "TRUE"
-+hpet0.present = "TRUE"
-+displayName = "RHEL 7.1 UEFI"
-+extendedConfigFile = "RHEL 7.1 UEFI.vmxf"
-+virtualHW.productCompatibility = "hosted"
-+memSize = "2048"
-+firmware = "efi"
-+sched.cpu.units = "mhz"
-+powerType.powerOff = "soft"
-+powerType.suspend = "hard"
-+powerType.reset = "soft"
-+scsi0.virtualDev = "pvscsi"
-+scsi0.present = "TRUE"
-+ide1:0.startConnected = "FALSE"
-+ide1:0.deviceType = "cdrom-image"
-+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso"
-+ide1:0.present = "TRUE"
-+floppy0.startConnected = "FALSE"
-+floppy0.clientDevice = "TRUE"
-+floppy0.fileName = "vmware-null-remote-floppy"
-+ethernet0.virtualDev = "vmxnet3"
-+ethernet0.networkName = "VM Network"
-+ethernet0.addressType = "generated"
-+ethernet0.present = "TRUE"
-+scsi0:0.deviceType = "scsi-hardDisk"
-+scsi0:0.fileName = "RHEL 7.1 UEFI.vmdk"
-+scsi0:0.present = "TRUE"
-+guestOS = "rhel6-64"
-+toolScripts.afterPowerOn = "TRUE"
-+toolScripts.afterResume = "TRUE"
-+toolScripts.beforeSuspend = "TRUE"
-+toolScripts.beforePowerOff = "TRUE"
-+uuid.bios = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c"
-+uuid.location = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c"
-+vc.uuid = "52 3f 29 10 d3 81 16 43-fa b0 e3 af 3b ba 36 e5"
-+chipset.onlineStandby = "FALSE"
-+sched.cpu.min = "0"
-+sched.cpu.shares = "normal"
-+sched.mem.min = "0"
-+sched.mem.minSize = "0"
-+sched.mem.shares = "normal"
-+svga.vramSize = "8388608"
-+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/RHEL 7.1 UEFI/RHEL 7.1 UEFI-58ff6e6f.vswp"
-+replay.supported = "FALSE"
-+replay.filename = ""
-+scsi0:0.redo = ""
-+pciBridge0.pciSlotNumber = "17"
-+pciBridge4.pciSlotNumber = "21"
-+pciBridge5.pciSlotNumber = "22"
-+pciBridge6.pciSlotNumber = "23"
-+pciBridge7.pciSlotNumber = "24"
-+scsi0.pciSlotNumber = "160"
-+ethernet0.pciSlotNumber = "192"
-+vmci0.pciSlotNumber = "32"
-+scsi0.sasWWID = "50 05 05 69 a7 21 91 00"
-+ethernet0.generatedAddress = "00:0c:29:4b:2b:8c"
-+ethernet0.generatedAddressOffset = "0"
-+vmci0.id = "-716493940"
-+hostCPUID.0 = "0000000d756e65476c65746e49656e69"
-+hostCPUID.1 = "000206a700100800179ae3bfbfebfbff"
-+hostCPUID.80000001 = "00000000000000000000000128100800"
-+guestCPUID.0 = "0000000d756e65476c65746e49656e69"
-+guestCPUID.1 = "000206a700010800969822030fabfbff"
-+guestCPUID.80000001 = "00000000000000000000000128100800"
-+userCPUID.0 = "0000000d756e65476c65746e49656e69"
-+userCPUID.1 = "000206a700100800169822030fabfbff"
-+userCPUID.80000001 = "00000000000000000000000128100800"
-+evcCompatibilityMode = "FALSE"
-+vmotion.checkpointFBSize = "8388608"
-+cleanShutdown = "TRUE"
-+softPowerOff = "TRUE"
-+ide1:0.allowGuestConnectionControl = "TRUE"
-+tools.syncTime = "FALSE"
-diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected
-new file mode 100644
-index 000000000..a70533d2e
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-4.expected
-@@ -0,0 +1,22 @@
-+[   0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx
-+Source guest information (--print-source option):
-+
-+    source name: Windows 7 x64
-+hypervisor type: vmware
-+         memory: 2147483648 (bytes)
-+       nr vCPUs: 1
-+     CPU vendor: 
-+      CPU model: 
-+   CPU topology: sockets: - cores/socket: - threads/core: -
-+   CPU features: 
-+       firmware: bios
-+        display: 
-+          video: vmvga
-+          sound: 
-+disks:
-+	/Windows 7 x64.vmdk (vmdk) [scsi]
-+removable media:
-+	CD-ROM [ide] in slot 2
-+NICs:
-+	Network "VM Network" mac: 00:0c:29:94:89:23 [e1000]
-+
-diff --git a/v2v/test-v2v-i-vmx-4.vmx b/v2v/test-v2v-i-vmx-4.vmx
-new file mode 100644
-index 000000000..7756cf248
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx-4.vmx
-@@ -0,0 +1,88 @@
-+.encoding = "UTF-8"
-+config.version = "8"
-+virtualHW.version = "8"
-+nvram = "Windows 7 x64.nvram"
-+pciBridge0.present = "TRUE"
-+svga.present = "TRUE"
-+pciBridge4.present = "TRUE"
-+pciBridge4.virtualDev = "pcieRootPort"
-+pciBridge4.functions = "8"
-+pciBridge5.present = "TRUE"
-+pciBridge5.virtualDev = "pcieRootPort"
-+pciBridge5.functions = "8"
-+pciBridge6.present = "TRUE"
-+pciBridge6.virtualDev = "pcieRootPort"
-+pciBridge6.functions = "8"
-+pciBridge7.present = "TRUE"
-+pciBridge7.virtualDev = "pcieRootPort"
-+pciBridge7.functions = "8"
-+vmci0.present = "TRUE"
-+hpet0.present = "TRUE"
-+displayName = "Windows 7 x64"
-+extendedConfigFile = "Windows 7 x64.vmxf"
-+virtualHW.productCompatibility = "hosted"
-+memSize = "2048"
-+sched.cpu.units = "mhz"
-+powerType.powerOff = "soft"
-+powerType.suspend = "hard"
-+powerType.reset = "soft"
-+scsi0.virtualDev = "lsisas1068"
-+scsi0.present = "TRUE"
-+ide1:0.deviceType = "cdrom-image"
-+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso"
-+ide1:0.present = "TRUE"
-+floppy0.startConnected = "FALSE"
-+floppy0.clientDevice = "TRUE"
-+floppy0.fileName = "vmware-null-remote-floppy"
-+ethernet0.virtualDev = "e1000"
-+ethernet0.networkName = "VM Network"
-+ethernet0.addressType = "generated"
-+ethernet0.present = "TRUE"
-+scsi0:0.deviceType = "scsi-hardDisk"
-+scsi0:0.fileName = "Windows 7 x64.vmdk"
-+scsi0:0.present = "TRUE"
-+guestOS = "windows7-64"
-+toolScripts.afterPowerOn = "TRUE"
-+toolScripts.afterResume = "TRUE"
-+toolScripts.beforeSuspend = "TRUE"
-+toolScripts.beforePowerOff = "TRUE"
-+uuid.bios = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23"
-+uuid.location = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23"
-+vc.uuid = "52 7a 63 e1 2c 2f 50 46-91 66 3a e8 fa f9 c4 65"
-+chipset.onlineStandby = "FALSE"
-+sched.cpu.min = "0"
-+sched.cpu.shares = "normal"
-+sched.mem.min = "0"
-+sched.mem.minSize = "0"
-+sched.mem.shares = "normal"
-+svga.vramSize = "8388608"
-+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Windows 7 x64/Windows 7 x64-8e3b0929.vswp"
-+replay.supported = "FALSE"
-+replay.filename = ""
-+scsi0:0.redo = ""
-+pciBridge0.pciSlotNumber = "17"
-+pciBridge4.pciSlotNumber = "21"
-+pciBridge5.pciSlotNumber = "22"
-+pciBridge6.pciSlotNumber = "23"
-+pciBridge7.pciSlotNumber = "24"
-+scsi0.pciSlotNumber = "160"
-+ethernet0.pciSlotNumber = "32"
-+vmci0.pciSlotNumber = "33"
-+scsi0.sasWWID = "50 05 05 6a 63 a5 a8 30"
-+ethernet0.generatedAddress = "00:0c:29:94:89:23"
-+ethernet0.generatedAddressOffset = "0"
-+vmci0.id = "496273699"
-+hostCPUID.0 = "0000000b756e65476c65746e49656e69"
-+hostCPUID.1 = "000206c220200800029ee3ffbfebfbff"
-+hostCPUID.80000001 = "0000000000000000000000012c100800"
-+guestCPUID.0 = "0000000b756e65476c65746e49656e69"
-+guestCPUID.1 = "000206c200010800829822030fabfbff"
-+guestCPUID.80000001 = "00000000000000000000000128100800"
-+userCPUID.0 = "0000000b756e65476c65746e49656e69"
-+userCPUID.1 = "000206c220200800029822030fabfbff"
-+userCPUID.80000001 = "00000000000000000000000128100800"
-+evcCompatibilityMode = "FALSE"
-+vmotion.checkpointFBSize = "8388608"
-+cleanShutdown = "TRUE"
-+softPowerOff = "TRUE"
-+tools.remindInstall = "TRUE"
-diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh
-new file mode 100755
-index 000000000..5353e7e2a
---- /dev/null
-+++ b/v2v/test-v2v-i-vmx.sh
-@@ -0,0 +1,48 @@
-+#!/bin/bash -
-+# libguestfs virt-v2v test script
-+# Copyright (C) 2017 Red Hat Inc.
-+#
-+# 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 2 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, write to the Free Software
-+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-+
-+# Test -i ova option.
-+
-+set -e
-+
-+$TEST_FUNCTIONS
-+skip_if_skipped
-+skip_if_backend uml
-+
-+export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools"
-+export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
-+
-+rm -f test-v2v-i-vmx-*.actual
-+
-+for i in 1 2 3 4; do
-+    $VG virt-v2v --debug-gc \
-+        -i vmx test-v2v-i-vmx-$i.vmx \
-+        --print-source > test-v2v-i-vmx-$i.actual
-+
-+    # Normalize the print-source output.
-+    mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old
-+    sed \
-+        -e "s,$(pwd),," \
-+        < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual
-+    rm test-v2v-i-vmx-$i.actual.old
-+
-+    # Check the output.
-+    diff -u test-v2v-i-vmx-$i.expected test-v2v-i-vmx-$i.actual
-+done
-+
-+rm test-v2v-i-vmx-*.actual
-diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml
-index bd65788b0..dd805a3ab 100644
---- a/v2v/v2v_unit_tests.ml
-+++ b/v2v/v2v_unit_tests.ml
-@@ -787,6 +787,148 @@ let test_qemu_img_supports ctx =
-    *)
-   ignore (Utils.qemu_img_supports_offset_and_size ())
- 
-+(* Test the VMX file parser in the Parse_vmx module. *)
-+let test_vmx_parse_string ctx =
-+  let cmp = Parse_vmx.equal in
-+  let printer = Parse_vmx.to_string 0 in
-+
-+  (* This should be identical to the empty file. *)
-+  let t = Parse_vmx.parse_string "\
-+test.foo = \"a\"
-+test.bar = \"b\"
-+test.present = \"FALSE\"
-+" in
-+  assert_equal ~cmp ~printer Parse_vmx.empty t;
-+
-+  (* Test weird escapes. *)
-+  let t1 = Parse_vmx.parse_string "\
-+foo = \"a|20|21b\"
-+" in
-+  let t2 = Parse_vmx.parse_string "\
-+foo = \"a !b\"
-+" in
-+  assert_equal ~cmp ~printer t1 t2;
-+
-+  (* Test case insensitivity. *)
-+  let t1 = Parse_vmx.parse_string "\
-+foo = \"abc\"
-+" in
-+  let t2 = Parse_vmx.parse_string "\
-+fOO = \"abc\"
-+" in
-+  assert_equal ~cmp ~printer t1 t2;
-+  let t = Parse_vmx.parse_string "\
-+flag = \"true\"
-+" in
-+  assert_bool "parse_vmx: failed case insensitivity test for booleans #1"
-+              (Parse_vmx.get_bool t ["FLAG"] = Some true);
-+  let t = Parse_vmx.parse_string "\
-+flag = \"TRUE\"
-+" in
-+  assert_bool "parse_vmx: failed case insensitivity test for booleans #2"
-+              (Parse_vmx.get_bool t ["Flag"] = Some true);
-+
-+  (* Missing keys. *)
-+  let t = Parse_vmx.parse_string "\
-+foo = \"a\"
-+" in
-+  assert_bool "parse_vmx: failed missing key test"
-+              (Parse_vmx.get_string t ["bar"] = None);
-+
-+  (* namespace_present function *)
-+  let t = Parse_vmx.parse_string "\
-+foo.bar.present = \"TRUE\"
-+foo.baz.present = \"FALSE\"
-+foo.a.b = \"abc\"
-+foo.a.c = \"abc\"
-+foo.b = \"abc\"
-+foo.c.a = \"abc\"
-+foo.c.b = \"abc\"
-+" in
-+ assert_bool "parse_vmx: namespace_present #1"
-+             (Parse_vmx.namespace_present t ["foo"] = true);
-+ assert_bool "parse_vmx: namespace_present #2"
-+             (Parse_vmx.namespace_present t ["foo"; "bar"] = true);
-+ assert_bool "parse_vmx: namespace_present #3"
-+             (* this whole namespace should have been culled *)
-+             (Parse_vmx.namespace_present t ["foo"; "baz"] = false);
-+ assert_bool "parse_vmx: namespace_present #4"
-+             (Parse_vmx.namespace_present t ["foo"; "a"] = true);
-+ assert_bool "parse_vmx: namespace_present #5"
-+             (* this is a key, not a namespace *)
-+             (Parse_vmx.namespace_present t ["foo"; "a"; "b"] = false);
-+ assert_bool "parse_vmx: namespace_present #6"
-+             (Parse_vmx.namespace_present t ["foo"; "b"] = false);
-+ assert_bool "parse_vmx: namespace_present #7"
-+             (Parse_vmx.namespace_present t ["foo"; "c"] = true);
-+ assert_bool "parse_vmx: namespace_present #8"
-+             (Parse_vmx.namespace_present t ["foo"; "d"] = false);
-+
-+ (* map function *)
-+  let t = Parse_vmx.parse_string "\
-+foo.bar.present = \"TRUE\"
-+foo.baz.present = \"FALSE\"
-+foo.a.b = \"abc\"
-+foo.a.c = \"abc\"
-+foo.b = \"abc\"
-+foo.c.a = \"abc\"
-+foo.c.b = \"abc\"
-+" in
-+  let xs =
-+    Parse_vmx.map (
-+      fun path ->
-+        let path = String.concat "." path in
-+        function
-+        | None -> sprintf "%s.present = \"true\"\n" path
-+        | Some v -> sprintf "%s = \"%s\"\n" path v
-+    ) t in
-+  let xs = List.sort compare xs in
-+  let s = String.concat "" xs in
-+  assert_equal ~printer:identity "\
-+foo.a.b = \"abc\"
-+foo.a.c = \"abc\"
-+foo.a.present = \"true\"
-+foo.b = \"abc\"
-+foo.bar.present = \"TRUE\"
-+foo.bar.present = \"true\"
-+foo.c.a = \"abc\"
-+foo.c.b = \"abc\"
-+foo.c.present = \"true\"
-+foo.present = \"true\"
-+" s;
-+
-+  (* select_namespaces function *)
-+  let t1 = Parse_vmx.parse_string "\
-+foo.bar.present = \"TRUE\"
-+foo.a.b = \"abc\"
-+foo.a.c = \"abc\"
-+foo.b = \"abc\"
-+foo.c.a = \"abc\"
-+foo.c.b = \"abc\"
-+" in
-+  let t2 =
-+    Parse_vmx.select_namespaces
-+      (function ["foo"] -> true | _ -> false) t1 in
-+  assert_equal ~cmp ~printer t1 t2;
-+
-+  let t1 = Parse_vmx.parse_string "\
-+foo.bar.present = \"TRUE\"
-+foo.a.b = \"abc\"
-+foo.a.c = \"abc\"
-+foo.b = \"abc\"
-+foo.c.a = \"abc\"
-+foo.c.b = \"abc\"
-+foo.c.c.d.e.f = \"abc\"
-+" in
-+  let t1 =
-+    Parse_vmx.select_namespaces
-+      (function ["foo"; "a"] -> true | _ -> false) t1 in
-+  let t2 = Parse_vmx.parse_string "\
-+foo.a.b = \"abc\"
-+foo.a.c = \"abc\"
-+" in
-+  assert_equal ~cmp ~printer t2 t1
-+
- (* Suites declaration. *)
- let suite =
-   "virt-v2v" >:::
-@@ -798,6 +940,7 @@ let suite =
-         test_virtio_iso_path_matches_guest_os;
-       "Utils.shell_unquote" >:: test_shell_unquote;
-       "Utils.qemu_img_supports" >:: test_qemu_img_supports;
-+      "Parse_vmx.parse_string" >::test_vmx_parse_string;
-     ]
- 
- let () =
-diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
-index 7ad674d43..31d1ce029 100644
---- a/v2v/virt-v2v.pod
-+++ b/v2v/virt-v2v.pod
-@@ -41,7 +41,8 @@ libguestfs E<ge> 1.28.
-  ... ───▶│  (default) │   │            │ ──┐ └────────────┘
-          └────────────┘   │            │ ─┐└──────▶ -o glance
-  -i libvirtxml ─────────▶ │            │ ┐└─────────▶ -o rhv
--                          └────────────┘ └──────────▶ -o vdsm
-+ -i vmx ────────────────▶ │            │ └──────────▶ -o vdsm
-+                          └────────────┘
- 
- Virt-v2v has a number of possible input and output modes, selected
- using the I<-i> and I<-o> options.  Only one input and output mode can
-@@ -60,6 +61,8 @@ method used by L<virt-p2v(1)> behind the scenes.
- 
- I<-i ova> is used for reading from a VMware ova source file.
- 
-+I<-i vmx> is used for reading from a VMware vmx file.
-+
- I<-o glance> is used for writing to OpenStack Glance.
- 
- I<-o libvirt> is used for writing to any libvirt target.  Libvirt can
-@@ -215,6 +218,14 @@ ova manifest file and check the vmdk volumes for validity (checksums)
- as well as analyzing the ovf file, and then convert the guest.  See
- L</INPUT FROM VMWARE OVA> below
- 
-+=item B<-i> B<vmx>
-+
-+Set the input method to I<vmx>.
-+
-+In this mode you can read a VMware vmx file directly.  This is useful
-+when VMware VMs are stored on an NFS server which you can mount
-+directly.  See L</INPUT FROM VMWARE VMX> below
-+
- =item B<-ic> libvirtURI
- 
- Specify a libvirt connection URI to use when reading the guest.  This
-@@ -843,9 +854,10 @@ I<--bridge> option instead.  For example:
- 
- Virt-v2v is able to import guests from VMware vCenter Server.
- 
--vCenter E<ge> 5.0 is required.  If you don't have vCenter, using OVA
--is recommended instead (see L</INPUT FROM VMWARE OVA> below), or if
--that is not possible then see L</INPUT FROM VMWARE ESXi HYPERVISOR>.
-+vCenter E<ge> 5.0 is required.  If you don’t have vCenter, using OVA
-+or VMX is recommended instead (see L</INPUT FROM VMWARE OVA> and/or
-+L</INPUT FROM VMWARE VMX> below), or if that is not possible then see
-+L</INPUT FROM VMWARE ESXi HYPERVISOR>.
- 
- Virt-v2v uses libvirt for access to vCenter, and therefore the input
- mode should be I<-i libvirt>.  As this is the default, you don't need
-@@ -1116,12 +1128,58 @@ directory containing the files:
- 
-  $ virt-v2v -i ova /path/to/files -o local -os /var/tmp
- 
-+=head1 INPUT FROM VMWARE VMX
-+
-+Virt-v2v is able to import guests from VMware’s vmx files.  This is
-+useful where VMware virtual machines are stored on a separate NFS
-+server and you are able to mount the NFS storage directly.
-+
-+If you find a folder of files called F<I<guest>.vmx>,
-+F<I<guest>.vmxf>, F<I<guest>.nvram> and one or more F<.vmdk> disk
-+images, then you can use this method.
-+
-+=head2 VMX: REMOVE VMWARE TOOLS FROM WINDOWS GUESTS
-+
-+For Windows guests, you should remove VMware tools before conversion.
-+Although this is not strictly necessary, and the guest will still be
-+able to run, if you don't do this then the converted guest will
-+complain on every boot.  The tools cannot be removed after conversion
-+because the uninstaller checks if it is running on VMware and refuses
-+to start (which is also the reason that virt-v2v cannot remove them).
-+
-+This is not necessary for Linux guests, as virt-v2v is able to remove
-+VMware tools.
-+
-+=head2 VMX: GUEST MUST BE SHUT DOWN
-+
-+B<The guest must be shut down before conversion starts>.  If you don't
-+shut it down, you will end up with a corrupted VM disk on the target.
-+With other methods, virt-v2v tries to prevent concurrent access, but
-+because the I<-i vmx> method works directly against the storage,
-+checking for concurrent access is not possible.
-+
-+=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER
-+
-+Virt-v2v must be able to access the F<.vmx> file and any local
-+F<.vmdk> disks.  Normally this means you must mount the NFS storage
-+containing these files.
-+
-+=head2 VMX: IMPORTING A GUEST
-+
-+To import a vmx file, do:
-+
-+ $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp
-+
-+Virt-v2v processes the vmx file and uses it to find the location of
-+any vmdk disks.
-+
- =head1 INPUT FROM VMWARE ESXi HYPERVISOR
- 
- Virt-v2v cannot access an ESXi hypervisor directly.  You should use
--the OVA method above (see L</INPUT FROM VMWARE OVA>) if possible, as
--it is much faster and requires much less disk space than the method
--described in this section.
-+the OVA or VMX methods above (see L</INPUT FROM VMWARE OVA> and/or
-+L</INPUT FROM VMWARE VMX>) if possible, as it is much faster and
-+requires much less disk space than the method described in this
-+section.
- 
- You can use the L<virt-v2v-copy-to-local(1)> tool to copy the guest
- off the hypervisor into a local file, and then convert it.
--- 
-2.13.4
-
diff --git a/SOURCES/0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch b/SOURCES/0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch
new file mode 100644
index 0000000..a4346dd
--- /dev/null
+++ b/SOURCES/0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch
@@ -0,0 +1,37 @@
+From f774a2efed860774ba3a8e47e8ac81eeed2508fa Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 17 May 2017 12:16:07 +0200
+Subject: [PATCH] s390x: launch: direct: Use sclp as serial console on this
+ architecture.
+
+The same change to the direct backend as made to the libvirt backend
+in the previous commit.
+
+(cherry picked from commit ade2652bdac16656ba4ed821d74528a6de188fa0)
+---
+ lib/launch-direct.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/lib/launch-direct.c b/lib/launch-direct.c
+index 9cc153b21..147e158de 100644
+--- a/lib/launch-direct.c
++++ b/lib/launch-direct.c
+@@ -592,8 +592,15 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+   ADD_CMDLINE (VIRTIO_SERIAL);
+ 
+   /* Create the serial console. */
++#ifndef __s390x__
+   ADD_CMDLINE ("-serial");
+   ADD_CMDLINE ("stdio");
++#else
++  ADD_CMDLINE ("-chardev");
++  ADD_CMDLINE ("stdio,id=charconsole0");
++  ADD_CMDLINE ("-device");
++  ADD_CMDLINE ("sclpconsole,chardev=charconsole0");
++#endif
+ 
+   if (g->verbose &&
+       guestfs_int_qemu_supports_device (g, data->qemu_data,
+-- 
+2.14.3
+
diff --git a/SOURCES/0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch b/SOURCES/0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch
deleted file mode 100644
index 81b8164..0000000
--- a/SOURCES/0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 427106e2ca70009c30706f0a55ba72c51cd13e0d Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Wed, 12 Apr 2017 08:32:58 +0100
-Subject: [PATCH] v2v: tests: Fix -i vmx test so it is more stable.
-
-When running under valgrind, the process takes a fraction of a second
-to start up, changing the "Opening the guest" timestamp, which broke
-the test.
-
-Fixes commit ca40078cdda9167d4658ddfe24c828c7ee76be37.
-
-(cherry picked from commit ec61873d397f050fe28987f10ec919778d27818a)
----
- v2v/test-v2v-i-vmx-1.expected | 2 +-
- v2v/test-v2v-i-vmx-2.expected | 2 +-
- v2v/test-v2v-i-vmx-3.expected | 2 +-
- v2v/test-v2v-i-vmx-4.expected | 2 +-
- v2v/test-v2v-i-vmx.sh         | 1 +
- 5 files changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected
-index d32a29987..902a850c5 100644
---- a/v2v/test-v2v-i-vmx-1.expected
-+++ b/v2v/test-v2v-i-vmx-1.expected
-@@ -1,4 +1,4 @@
--[   0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx
-+
- Source guest information (--print-source option):
- 
-     source name: BZ1308535_21disks
-diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected
-index dc3eb60f2..6e87862ac 100644
---- a/v2v/test-v2v-i-vmx-2.expected
-+++ b/v2v/test-v2v-i-vmx-2.expected
-@@ -1,4 +1,4 @@
--[   0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx
-+
- Source guest information (--print-source option):
- 
-     source name: Fedora 20
-diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected
-index 9e643526f..0d1585b96 100644
---- a/v2v/test-v2v-i-vmx-3.expected
-+++ b/v2v/test-v2v-i-vmx-3.expected
-@@ -1,4 +1,4 @@
--[   0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx
-+
- Source guest information (--print-source option):
- 
-     source name: RHEL 7.1 UEFI
-diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected
-index a70533d2e..06f58d7ad 100644
---- a/v2v/test-v2v-i-vmx-4.expected
-+++ b/v2v/test-v2v-i-vmx-4.expected
-@@ -1,4 +1,4 @@
--[   0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx
-+
- Source guest information (--print-source option):
- 
-     source name: Windows 7 x64
-diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh
-index 5353e7e2a..997103d41 100755
---- a/v2v/test-v2v-i-vmx.sh
-+++ b/v2v/test-v2v-i-vmx.sh
-@@ -37,6 +37,7 @@ for i in 1 2 3 4; do
-     # Normalize the print-source output.
-     mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old
-     sed \
-+        -e "s,.*Opening the source.*,," \
-         -e "s,$(pwd),," \
-         < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual
-     rm test-v2v-i-vmx-$i.actual.old
--- 
-2.13.4
-
diff --git a/SOURCES/0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch b/SOURCES/0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch
new file mode 100644
index 0000000..6592e9d
--- /dev/null
+++ b/SOURCES/0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch
@@ -0,0 +1,26 @@
+From 1dc3311d91d3d0caa2796ea5b52e07d84b2d3a90 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 17 May 2017 11:24:39 +0200
+Subject: [PATCH] s390x: appliance: Use /dev/ttysclp0 for serial console.
+
+(cherry picked from commit 5fc76d6d10a1095c9301edbf4716114e4e94882c)
+---
+ lib/appliance-kcmdline.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/lib/appliance-kcmdline.c b/lib/appliance-kcmdline.c
+index 4dde7a865..ff7bda494 100644
+--- a/lib/appliance-kcmdline.c
++++ b/lib/appliance-kcmdline.c
+@@ -44,6 +44,8 @@
+ #define SERIAL_CONSOLE "console=hvc0 console=ttyS0"
+ #elif defined(__arm__) || defined(__aarch64__)
+ #define SERIAL_CONSOLE "console=ttyAMA0"
++#elif defined(__s390x__)
++#define SERIAL_CONSOLE "console=ttysclp0"
+ #else
+ #define SERIAL_CONSOLE "console=ttyS0"
+ #endif
+-- 
+2.14.3
+
diff --git a/SOURCES/0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch b/SOURCES/0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch
deleted file mode 100644
index 4646451..0000000
--- a/SOURCES/0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0828c8f3f4fceaba6fab17d2dfaf689702265c85 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 13 Apr 2017 09:57:37 +0100
-Subject: [PATCH] v2v: -o rhv: Quote parameter to rm -rf.
-
-This was safe before, the change just prevents accidental errors.
-
-(cherry picked from commit 24a6c5b57c25e0e59697831b55000d6f8e21fd38)
----
- v2v/output_rhv.ml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/v2v/output_rhv.ml b/v2v/output_rhv.ml
-index f407b4eda..02bd31269 100644
---- a/v2v/output_rhv.ml
-+++ b/v2v/output_rhv.ml
-@@ -205,7 +205,7 @@ object
-         List.iter (
-           fun image_uuid ->
-             let d = images_dir // image_uuid in
--            let cmd = sprintf "rm -rf %s" d in
-+            let cmd = sprintf "rm -rf %s" (quote d) in
-             Changeuid.command changeuid_t cmd
-         ) image_uuids
-       )
--- 
-2.13.4
-
diff --git a/SOURCES/0039-init-Add-comment-that-we-should-consider-using-proc-.patch b/SOURCES/0039-init-Add-comment-that-we-should-consider-using-proc-.patch
new file mode 100644
index 0000000..98cdce5
--- /dev/null
+++ b/SOURCES/0039-init-Add-comment-that-we-should-consider-using-proc-.patch
@@ -0,0 +1,29 @@
+From 630c80558888131c094c15d8854a527d3c41261f Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 17 May 2017 11:38:05 +0200
+Subject: [PATCH] init: Add comment that we should consider using
+ /proc/consoles.
+
+Although we can't use it at the moment because it is incorrect
+on at least s390x (RHBZ#1351968).
+
+(cherry picked from commit fa6bc0fd83317d43df38c50bf94966b31024ca35)
+---
+ appliance/init | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/appliance/init b/appliance/init
+index 2c9aecd5f..735ba8946 100755
+--- a/appliance/init
++++ b/appliance/init
+@@ -179,6 +179,7 @@ else
+   # Run virt-rescue shell.
+ 
+   # Get name of the serial port, from console= passed by libguestfs.
++  # XXX Consider using /proc/consoles
+   guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline |
+                    sed s/console=//)
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch b/SOURCES/0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch
deleted file mode 100644
index 62912ab..0000000
--- a/SOURCES/0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 30ffdce6bc603f1aaf0ee77270bd1d8ff09cbf0c Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Wed, 12 Apr 2017 23:09:32 +0100
-Subject: [PATCH] v2v: windows: Install both legacy and modern virtio keys in
- the registry (RHBZ#1431579).
-
-Thanks: Kun Wei (for finding the bug)
-Thanks: Ladi Prosek (for diagnosing the problem and proposing the fix)
-(cherry picked from commit d8e1c4bb474203d71903261fb06fe267c3cce3c7)
----
- v2v/windows_virtio.ml | 12 ++++++++----
- 1 file changed, 8 insertions(+), 4 deletions(-)
-
-diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml
-index 965d6ac8b..9e6088c28 100644
---- a/v2v/windows_virtio.ml
-+++ b/v2v/windows_virtio.ml
-@@ -34,8 +34,10 @@ let virtio_win =
-       Guestfs_config.datadir // "virtio-win"
- 
- let scsi_class_guid = "{4D36E97B-E325-11CE-BFC1-08002BE10318}"
--let viostor_pciid = "VEN_1AF4&DEV_1001&SUBSYS_00021AF4&REV_00"
--let vioscsi_pciid = "VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00"
-+let viostor_legacy_pciid = "VEN_1AF4&DEV_1001&SUBSYS_00021AF4&REV_00"
-+let viostor_modern_pciid = "VEN_1AF4&DEV_1042&SUBSYS_11001AF4&REV_01"
-+let vioscsi_legacy_pciid = "VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00"
-+let vioscsi_modern_pciid = "VEN_1AF4&DEV_1048&SUBSYS_11001AF4&REV_01"
- 
- let rec install_drivers ((g, _) as reg) inspect rcaps =
-   (* Copy the virtio drivers to the guest. *)
-@@ -102,7 +104,8 @@ let rec install_drivers ((g, _) as reg) inspect rcaps =
-                              inspect.i_windows_systemroot driver_name in
-         let target = g#case_sensitive_path target in
-         g#cp source target;
--        add_guestor_to_registry reg inspect driver_name viostor_pciid;
-+        add_guestor_to_registry reg inspect driver_name viostor_legacy_pciid;
-+        add_guestor_to_registry reg inspect driver_name viostor_modern_pciid;
-         Virtio_blk
- 
-       | Some Virtio_SCSI, _, true ->
-@@ -113,7 +116,8 @@ let rec install_drivers ((g, _) as reg) inspect rcaps =
-                              inspect.i_windows_systemroot in
-         let target = g#case_sensitive_path target in
-         g#cp source target;
--        add_guestor_to_registry reg inspect "vioscsi" vioscsi_pciid;
-+        add_guestor_to_registry reg inspect "vioscsi" vioscsi_legacy_pciid;
-+        add_guestor_to_registry reg inspect "vioscsi" vioscsi_modern_pciid;
-         Virtio_SCSI
- 
-       | Some IDE, _, _ ->
--- 
-2.13.4
-
diff --git a/SOURCES/0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch b/SOURCES/0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch
new file mode 100644
index 0000000..478530a
--- /dev/null
+++ b/SOURCES/0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch
@@ -0,0 +1,77 @@
+From 516f008f29e77d676907208e51e2f57bb73888aa Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 16 May 2017 19:58:59 +0200
+Subject: [PATCH] s390x: launch: direct: Use virtio-*-ccw on this architecture.
+
+PCI devices don't exist/work.  You would see errors such as:
+
+qemu-system-s390x: -device virtio-rng-pci,rng=rng0: MSI-X support is mandatory in the S390 architecture
+(cherry picked from commit ddde6f9e2f14ccf8d91a8587052d0abcfb6496f1)
+---
+ lib/guestfs-internal.h | 26 +++++++++++++++++---------
+ lib/launch-direct.c    |  4 ++--
+ 2 files changed, 19 insertions(+), 11 deletions(-)
+
+diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h
+index 949cacfef..f035e0931 100644
+--- a/lib/guestfs-internal.h
++++ b/lib/guestfs-internal.h
+@@ -142,20 +142,28 @@
+ /* Maximum size of Windows explorer.exe.  2.6MB on Windows 7. */
+ #define MAX_WINDOWS_EXPLORER_SIZE (4 * 1000 * 1000)
+ 
+-/* Differences in device names on ARM (virtio-mmio) vs normal
+- * hardware with PCI.
++/* Differences in device names on ARMv7 (virtio-mmio), s/390x (CCW) vs
++ * normal hardware with PCI.
+  */
+-#if !defined(__arm__)
+-#define VIRTIO_BLK "virtio-blk-pci"
+-#define VIRTIO_SCSI "virtio-scsi-pci"
+-#define VIRTIO_SERIAL "virtio-serial-pci"
+-#define VIRTIO_NET "virtio-net-pci"
+-#else /* ARMv7 */
++#if defined(__arm__)
+ #define VIRTIO_BLK "virtio-blk-device"
+ #define VIRTIO_SCSI "virtio-scsi-device"
+ #define VIRTIO_SERIAL "virtio-serial-device"
+ #define VIRTIO_NET "virtio-net-device"
+-#endif /* ARMv7 */
++#define VIRTIO_RNG "virtio-rng-device"
++#elif defined(__s390x__)
++#define VIRTIO_BLK "virtio-blk-ccw"
++#define VIRTIO_SCSI "virtio-scsi-ccw"
++#define VIRTIO_SERIAL "virtio-serial-ccw"
++#define VIRTIO_NET "virtio-net-ccw"
++#define VIRTIO_RNG "virtio-rng-ccw"
++#else
++#define VIRTIO_BLK "virtio-blk-pci"
++#define VIRTIO_SCSI "virtio-scsi-pci"
++#define VIRTIO_SERIAL "virtio-serial-pci"
++#define VIRTIO_NET "virtio-net-pci"
++#define VIRTIO_RNG "virtio-rng-pci"
++#endif
+ 
+ /* Machine types. */
+ #ifdef __arm__
+diff --git a/lib/launch-direct.c b/lib/launch-direct.c
+index 147e158de..c8841bfe4 100644
+--- a/lib/launch-direct.c
++++ b/lib/launch-direct.c
+@@ -463,11 +463,11 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+    * when needing entropy.
+    */
+   if (guestfs_int_qemu_supports_device (g, data->qemu_data,
+-                                        "virtio-rng-pci")) {
++                                        VIRTIO_RNG)) {
+     ADD_CMDLINE ("-object");
+     ADD_CMDLINE ("rng-random,filename=/dev/urandom,id=rng0");
+     ADD_CMDLINE ("-device");
+-    ADD_CMDLINE ("virtio-rng-pci,rng=rng0");
++    ADD_CMDLINE (VIRTIO_RNG ",rng=rng0");
+   }
+ 
+   /* Add drives */
+-- 
+2.14.3
+
diff --git a/SOURCES/0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch b/SOURCES/0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch
deleted file mode 100644
index 895d438..0000000
--- a/SOURCES/0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From e2ebd5a963612aec0f9035c7603739cf8245ce59 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Tue, 2 May 2017 10:57:53 +0100
-Subject: [PATCH] v2v: -o rhv: Add Windows 2016 Server type in OVF output
- (RHBZ#1447202).
-
-Thanks: Kun Wei
-
-See also:
-https://github.com/oVirt/ovirt-engine/commit/d233325d7b808e8bae83645ac645dfea9dfe8407
-
-(cherry picked from commit d0344f3522c116d3ccba6d52cd100562ee6e1e23)
----
- v2v/OVF.ml | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/v2v/OVF.ml b/v2v/OVF.ml
-index 1f838f543..e380d35f6 100644
---- a/v2v/OVF.ml
-+++ b/v2v/OVF.ml
-@@ -194,9 +194,13 @@ and get_ostype = function
-     "windows_10"
- 
-   | { i_type = "windows"; i_major_version = 10; i_minor_version = 0;
--      i_arch = "x86_64" } ->
-+      i_arch = "x86_64"; i_product_variant = "Client" } ->
-     "windows_10x64"
- 
-+  | { i_type = "windows"; i_major_version = 10; i_minor_version = 0;
-+      i_arch = "x86_64" } ->
-+    "windows_2016x64"
-+
-   | { i_type = typ; i_distro = distro;
-       i_major_version = major; i_minor_version = minor; i_arch = arch;
-       i_product_name = product } ->
--- 
-2.13.4
-
diff --git a/SOURCES/0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch b/SOURCES/0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch
deleted file mode 100644
index ab0ecee..0000000
--- a/SOURCES/0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 8b72cf35f3c758aca31269f454339fdffeccbcf0 Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Mon, 12 Jun 2017 13:15:34 +0100
-Subject: [PATCH] daemon: lvm: Pass --yes option to force pvresize
- (RHBZ#1460577).
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-LVM2 >= 2.02.171 requires the ‘--yes’ option to force pvresize to work
-in various circumstances, eg. reducing the size of an existing PV.
-
-Pass this flag unconditionally.
-
-Note this does NOT break earlier versions which just ignore this flag.
-
-(cherry picked from commit 8a98fe91b889f666c8160f4c23af220247b4b8f3)
----
- daemon/lvm.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/daemon/lvm.c b/daemon/lvm.c
-index a270b1305..085e852f1 100644
---- a/daemon/lvm.c
-+++ b/daemon/lvm.c
-@@ -625,6 +625,7 @@ do_pvresize_size (const char *device, int64_t size)
- 
-   r = command (NULL, &err,
-                str_lvm, "pvresize",
-+               "--yes",
-                "--setphysicalvolumesize", buf,
-                device, NULL);
-   if (r == -1) {
--- 
-2.13.4
-
diff --git a/SOURCES/0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch b/SOURCES/0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch
new file mode 100644
index 0000000..a9ecc13
--- /dev/null
+++ b/SOURCES/0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch
@@ -0,0 +1,40 @@
+From a5a3600b8341278ee8c18dca89b9a9ba75ec2eca Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 17 May 2017 13:38:43 +0200
+Subject: [PATCH] s390x: tests: regressions: Skip IDE tests on S/390.
+
+IDE interface is not supported.
+
+(cherry picked from commit 93af83de853b87c555624227741bdf8af1918703)
+---
+ tests/regressions/rhbz690819.sh | 1 +
+ tests/regressions/rhbz975797.sh | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/tests/regressions/rhbz690819.sh b/tests/regressions/rhbz690819.sh
+index d18b4d81a..0b790862d 100755
+--- a/tests/regressions/rhbz690819.sh
++++ b/tests/regressions/rhbz690819.sh
+@@ -29,6 +29,7 @@ skip_if_arch arm
+ skip_if_arch aarch64
+ skip_if_arch ppc64
+ skip_if_arch ppc64le
++skip_if_arch s390x
+ skip_if_backend libvirt
+ # UML doesn't support the 'iface' parameter.
+ skip_if_backend uml
+diff --git a/tests/regressions/rhbz975797.sh b/tests/regressions/rhbz975797.sh
+index bc6a1c63f..04e8d23de 100755
+--- a/tests/regressions/rhbz975797.sh
++++ b/tests/regressions/rhbz975797.sh
+@@ -29,6 +29,7 @@ skip_if_arch arm
+ skip_if_arch aarch64
+ skip_if_arch ppc64
+ skip_if_arch ppc64le
++skip_if_arch s390x
+ skip_if_backend libvirt
+ # UML doesn't support the 'iface' parameter.
+ skip_if_backend uml
+-- 
+2.14.3
+
diff --git a/SOURCES/0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch b/SOURCES/0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch
new file mode 100644
index 0000000..bf204d6
--- /dev/null
+++ b/SOURCES/0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch
@@ -0,0 +1,155 @@
+From eddfb0a765e0246d0fb397414f32403f055488a3 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 18 May 2017 15:59:38 +0100
+Subject: [PATCH] lib: Add VIRTIO_DEVICE_NAME macro to handle virtio-mmio vs
+ CCW vs virtio-PCI.
+
+(cherry picked from commit a5bd493e3f90945cb8e913f9c680bedbdf26aaaa)
+
+PT: the VIRTIO_DEVICE_NAME macros are left in guestfs-internal.h, since
+the VIRTIO_* macros were used in other places than launch-direct.c.
+---
+ lib/guestfs-internal.h | 22 +++++-----------------
+ lib/launch-direct.c    | 16 ++++++++--------
+ lib/launch-libvirt.c   |  2 +-
+ lib/qemu.c             |  2 +-
+ 4 files changed, 15 insertions(+), 27 deletions(-)
+
+diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h
+index f035e0931..d962aacd4 100644
+--- a/lib/guestfs-internal.h
++++ b/lib/guestfs-internal.h
+@@ -142,27 +142,15 @@
+ /* Maximum size of Windows explorer.exe.  2.6MB on Windows 7. */
+ #define MAX_WINDOWS_EXPLORER_SIZE (4 * 1000 * 1000)
+ 
+-/* Differences in device names on ARMv7 (virtio-mmio), s/390x (CCW) vs
+- * normal hardware with PCI.
++/* Differences in qemu device names on ARMv7 (virtio-mmio), s/390x
++ * (CCW) vs normal hardware with PCI.
+  */
+ #if defined(__arm__)
+-#define VIRTIO_BLK "virtio-blk-device"
+-#define VIRTIO_SCSI "virtio-scsi-device"
+-#define VIRTIO_SERIAL "virtio-serial-device"
+-#define VIRTIO_NET "virtio-net-device"
+-#define VIRTIO_RNG "virtio-rng-device"
++#define VIRTIO_DEVICE_NAME(type) type "-device"
+ #elif defined(__s390x__)
+-#define VIRTIO_BLK "virtio-blk-ccw"
+-#define VIRTIO_SCSI "virtio-scsi-ccw"
+-#define VIRTIO_SERIAL "virtio-serial-ccw"
+-#define VIRTIO_NET "virtio-net-ccw"
+-#define VIRTIO_RNG "virtio-rng-ccw"
++#define VIRTIO_DEVICE_NAME(type) type "-ccw"
+ #else
+-#define VIRTIO_BLK "virtio-blk-pci"
+-#define VIRTIO_SCSI "virtio-scsi-pci"
+-#define VIRTIO_SERIAL "virtio-serial-pci"
+-#define VIRTIO_NET "virtio-net-pci"
+-#define VIRTIO_RNG "virtio-rng-pci"
++#define VIRTIO_DEVICE_NAME(type) type "-pci"
+ #endif
+ 
+ /* Machine types. */
+diff --git a/lib/launch-direct.c b/lib/launch-direct.c
+index c8841bfe4..0fef05927 100644
+--- a/lib/launch-direct.c
++++ b/lib/launch-direct.c
+@@ -349,7 +349,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+    */
+   if (guestfs_int_qemu_supports (g, data->qemu_data, "-global")) {
+     ADD_CMDLINE ("-global");
+-    ADD_CMDLINE (VIRTIO_BLK ".scsi=off");
++    ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-blk") ".scsi=off");
+   }
+ 
+   if (guestfs_int_qemu_supports (g, data->qemu_data, "-nodefconfig"))
+@@ -463,11 +463,11 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+    * when needing entropy.
+    */
+   if (guestfs_int_qemu_supports_device (g, data->qemu_data,
+-                                        VIRTIO_RNG)) {
++                                        VIRTIO_DEVICE_NAME ("virtio-rng"))) {
+     ADD_CMDLINE ("-object");
+     ADD_CMDLINE ("rng-random,filename=/dev/urandom,id=rng0");
+     ADD_CMDLINE ("-device");
+-    ADD_CMDLINE (VIRTIO_RNG ",rng=rng0");
++    ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-rng") ",rng=rng0");
+   }
+ 
+   /* Add drives */
+@@ -477,7 +477,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+   if (virtio_scsi) {
+     /* Create the virtio-scsi bus. */
+     ADD_CMDLINE ("-device");
+-    ADD_CMDLINE (VIRTIO_SCSI ",id=scsi");
++    ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-scsi") ",id=scsi");
+   }
+ 
+   ITER_DRIVES (g, i, drv) {
+@@ -564,7 +564,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+       ADD_CMDLINE ("-drive");
+       ADD_CMDLINE_PRINTF ("%s,if=none" /* sic */, param);
+       ADD_CMDLINE ("-device");
+-      ADD_CMDLINE_PRINTF (VIRTIO_BLK ",drive=hd%zu", i);
++      ADD_CMDLINE_PRINTF (VIRTIO_DEVICE_NAME ("virtio-blk") ",drive=hd%zu", i);
+     }
+   }
+ 
+@@ -581,7 +581,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+     }
+     else {
+       ADD_CMDLINE ("-device");
+-      ADD_CMDLINE (VIRTIO_BLK ",drive=appliance");
++      ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-blk") ",drive=appliance");
+     }
+ 
+     appliance_dev = make_appliance_dev (g, virtio_scsi);
+@@ -589,7 +589,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+ 
+   /* Create the virtio serial bus. */
+   ADD_CMDLINE ("-device");
+-  ADD_CMDLINE (VIRTIO_SERIAL);
++  ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-serial"));
+ 
+   /* Create the serial console. */
+ #ifndef __s390x__
+@@ -626,7 +626,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+     ADD_CMDLINE ("-netdev");
+     ADD_CMDLINE ("user,id=usernet,net=169.254.0.0/16");
+     ADD_CMDLINE ("-device");
+-    ADD_CMDLINE (VIRTIO_NET ",netdev=usernet");
++    ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-net") ",netdev=usernet");
+   }
+ 
+   ADD_CMDLINE ("-append");
+diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
+index 49bd40583..d10c7cb40 100644
+--- a/lib/launch-libvirt.c
++++ b/lib/launch-libvirt.c
+@@ -1803,7 +1803,7 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g,
+       } end_element ();
+ 
+       start_element ("qemu:arg") {
+-        attribute ("value", VIRTIO_NET ",netdev=usernet");
++        attribute ("value", VIRTIO_DEVICE_NAME ("virtio-net") ",netdev=usernet");
+       } end_element ();
+     }
+ 
+diff --git a/lib/qemu.c b/lib/qemu.c
+index c9debe937..887e31bc4 100644
+--- a/lib/qemu.c
++++ b/lib/qemu.c
+@@ -619,7 +619,7 @@ guestfs_int_qemu_supports_virtio_scsi (guestfs_h *g, struct qemu_data *data,
+     if (old_or_broken_virtio_scsi (qemu_version))
+       data->virtio_scsi = 2;
+     else {
+-      r = guestfs_int_qemu_supports_device (g, data, VIRTIO_SCSI);
++      r = guestfs_int_qemu_supports_device (g, data, VIRTIO_DEVICE_NAME ("virtio-scsi"));
+       if (r > 0)
+         data->virtio_scsi = 1;
+       else if (r == 0)
+-- 
+2.14.3
+
diff --git a/SOURCES/0042-resize-make-sure-the-input-disk-is-read-only.patch b/SOURCES/0042-resize-make-sure-the-input-disk-is-read-only.patch
deleted file mode 100644
index 57f41f9..0000000
--- a/SOURCES/0042-resize-make-sure-the-input-disk-is-read-only.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From f1ed6a32939717d89e7bc3f9c0934b7788f2708a Mon Sep 17 00:00:00 2001
-From: Pino Toscano <ptoscano@redhat.com>
-Date: Wed, 21 Jun 2017 16:34:05 +0200
-Subject: [PATCH] resize: make sure the input disk is read-only
-
-Fixes commit 8a2b0738d1b79f288b14fc35294567430d10b7ec.
-
-(cherry picked from commit 1ca2a8b7ba41d7e4baf1aec5d65ace3b66f2dc37)
----
- resize/resize.ml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/resize/resize.ml b/resize/resize.ml
-index dc96b23ea..4028aa1ac 100644
---- a/resize/resize.ml
-+++ b/resize/resize.ml
-@@ -348,7 +348,7 @@ read the man page virt-resize(1).
-   (* Add in and out disks to the handle and launch. *)
-   let connect_both_disks () =
-     let g = open_guestfs () in
--    add_drive_uri g ?format (snd infile);
-+    add_drive_uri g ?format ~readonly:true (snd infile);
-     (* The output disk is being created, so use cache=unsafe here. *)
-     add_drive_uri g ?format:output_format ~readonly:false ~cachemode:"unsafe"
-       (snd outfile);
--- 
-2.13.4
-
diff --git a/SOURCES/0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch b/SOURCES/0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch
deleted file mode 100644
index 5fb5f1d..0000000
--- a/SOURCES/0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 1f182ed648b7cf9d4f9f9fdceeb5be69cd2be4ae Mon Sep 17 00:00:00 2001
-From: "Richard W.M. Jones" <rjones@redhat.com>
-Date: Thu, 29 Jun 2017 23:59:15 +0100
-Subject: [PATCH] lib: libvirt: Pass copyonread flag through to the libvirt XML
- (RHBZ#1466563).
-
-We were dropping the add_drive copyonread flag when using the libvirt
-backend.  This resulted in significant performance degradation (2x-3x
-slower) when running virt-v2v against VMware servers.
-
-Thanks: Kun Wei.
-
-(cherry picked from commit d96209ef07fef3db0e411648348f1b1dcf384e70)
----
- lib/launch-libvirt.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
-index 0c2879dbf..144937b5b 100644
---- a/lib/launch-libvirt.c
-+++ b/lib/launch-libvirt.c
-@@ -1547,7 +1547,8 @@ construct_libvirt_xml_disk (guestfs_h *g,
- 
-       if (construct_libvirt_xml_disk_driver_qemu (g, data, drv, xo, format,
-                                                   drv->cachemode ? : "writeback",
--                                                  drv->discard, false)
-+                                                  drv->discard,
-+                                                  drv->copyonread)
-           == -1)
-         return -1;
-     }
--- 
-2.13.4
-
diff --git a/SOURCES/0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch b/SOURCES/0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch
new file mode 100644
index 0000000..718d515
--- /dev/null
+++ b/SOURCES/0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch
@@ -0,0 +1,81 @@
+From 46aaa657c76d473fcd6ac41a84101d7805306f58 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 11 Oct 2017 13:43:26 +0100
+Subject: [PATCH] v2v: -i vmx: Allow deviceType field to be completely omitted.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Microsoft make some VMX files available here which we could not parse.
+These files lack the expected ‘scsi0:0.deviceType’ field:
+https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/
+
+According to
+http://faq.sanbarrow.com/index.php?action=artikel&cat=7&id=54&artlang=en
+this is permitted.  Also several other deviceType values may be found.
+
+Allow such VMX to be parsed.
+
+Thanks: Tom Sorensen
+
+Cherry picked from commit 418289029da9641b74984eb15eb1563649c38dd1.
+For RHEL 7.5: I inlined the Option.map function since that does not
+exist in this branch.
+---
+ v2v/input_vmx.ml | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
+index bb09f0bf8..a4f77c2ab 100644
+--- a/v2v/input_vmx.ml
++++ b/v2v/input_vmx.ml
+@@ -35,7 +35,8 @@ let rec find_disks vmx vmx_filename =
+  *
+  * In the VMX file:
+  *   scsi0.virtualDev = "pvscsi"  # or may be "lsilogic" etc.
+- *   scsi0:0.deviceType = "scsi-hardDisk"
++ *   scsi0:0.deviceType = "disk" | "plainDisk" | "rawDisk" | "scsi-hardDisk"
++ *                        | omitted
+  *   scsi0:0.fileName = "guest.vmdk"
+  *)
+ and find_scsi_disks vmx vmx_filename =
+@@ -46,7 +47,8 @@ and find_scsi_disks vmx vmx_filename =
+     try ignore (get_scsi_controller_target ns); true
+     with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
+   in
+-  let scsi_device_types = [ "scsi-harddisk" ] in
++  let scsi_device_types = [ Some "disk"; Some "plaindisk"; Some "rawdisk";
++                            Some "scsi-harddisk"; None ] in
+   let scsi_controller = Source_SCSI in
+ 
+   find_hdds vmx vmx_filename
+@@ -67,7 +69,7 @@ and find_ide_disks vmx vmx_filename =
+     try ignore (get_ide_controller_target ns); true
+     with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
+   in
+-  let ide_device_types = [ "ata-harddisk" ] in
++  let ide_device_types = [ Some "ata-harddisk" ] in
+   let ide_controller = Source_IDE in
+ 
+   find_hdds vmx vmx_filename
+@@ -86,11 +88,12 @@ and find_hdds vmx vmx_filename
+          if not (is_controller_target ns) then false
+          else (
+            (* Check the deviceType is one we are looking for. *)
+-           match Parse_vmx.get_string vmx [ns; "deviceType"] with
+-           | Some str ->
+-              let str = String.lowercase_ascii str in
+-              List.mem str device_types
+-           | None -> false
++           let dt = Parse_vmx.get_string vmx [ns; "deviceType"] in
++           let dt =
++             match dt with
++             | None -> None
++             | Some dt -> Some (String.lowercase_ascii dt) in
++           List.mem dt device_types
+          )
+       | _ -> false
+     ) vmx in
+-- 
+2.14.3
+
diff --git a/SOURCES/0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch b/SOURCES/0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch
deleted file mode 100644
index 2bb50df..0000000
--- a/SOURCES/0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 6e33d4506d9a454921cac0207646ff1a1ba02684 Mon Sep 17 00:00:00 2001
-From: Pino Toscano <ptoscano@redhat.com>
-Date: Mon, 14 Aug 2017 10:02:13 +0200
-Subject: [PATCH] RHEL 7: v2v: disable unconfig of manually installed VMware
- tools (RHBZ#1477905)
-
-It looks like they may require connection to the VMware servers, which
-is not always available during conversion.
----
- v2v/convert_linux.ml | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
-index 6c4985e84..d5c5825f4 100644
---- a/v2v/convert_linux.ml
-+++ b/v2v/convert_linux.ml
-@@ -295,6 +295,7 @@ let rec convert (g : G.guestfs) inspect source output rcaps =
-     let remove = !remove in
-     Linux.remove g inspect remove;
- 
-+(*
-     (* VMware Tools may have been installed from a tarball, so the
-      * above code won't remove it.  Look for the uninstall tool and run
-      * if present.
-@@ -311,6 +312,8 @@ let rec convert (g : G.guestfs) inspect source output rcaps =
-           warning (f_"VMware tools was detected, but uninstallation failed.  The error message was: %s (ignored)")
-             msg
-     )
-+*)
-+    ()
- 
-   and unconfigure_citrix () =
-     let pkgs =
--- 
-2.13.4
-
diff --git a/SOURCES/0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch b/SOURCES/0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch
new file mode 100644
index 0000000..f0522a5
--- /dev/null
+++ b/SOURCES/0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch
@@ -0,0 +1,146 @@
+From 18f83f6a6945e7356a880c6b861c758e399ac55c Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 11 Oct 2017 13:33:12 +0100
+Subject: [PATCH] v2v: -i vmx: Add a test case which lacks scsi0:0.deviceType =
+ "scsi-hardDisk"
+
+VMX file from:
+https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/
+
+Thanks: Tom Sorensen
+(cherry picked from commit 6c54b68acb707d8f3dcd80453c23f57c54989be9)
+---
+ v2v/test-v2v-i-vmx-5.expected | 19 ++++++++++
+ v2v/test-v2v-i-vmx-5.vmx      | 80 +++++++++++++++++++++++++++++++++++++++++++
+ v2v/test-v2v-i-vmx.sh         |  2 +-
+ 3 files changed, 100 insertions(+), 1 deletion(-)
+ create mode 100644 v2v/test-v2v-i-vmx-5.expected
+ create mode 100644 v2v/test-v2v-i-vmx-5.vmx
+
+diff --git a/v2v/test-v2v-i-vmx-5.expected b/v2v/test-v2v-i-vmx-5.expected
+new file mode 100644
+index 000000000..4a33db13c
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-5.expected
+@@ -0,0 +1,19 @@
++
++Source guest information (--print-source option):
++
++    source name: MSEdge - Win10_preview
++hypervisor type: vmware
++         memory: 2147483648 (bytes)
++       nr vCPUs: 1
++   CPU features: 
++       firmware: bios
++        display: 
++          video: 
++          sound: 
++disks:
++	/MSEdge - Win10_preview.vmdk (vmdk) [scsi]
++removable media:
++
++NICs:
++	Bridge "ethernet0" mac: 00:0c:29:bf:e4:5d [e1000e]
++
+diff --git a/v2v/test-v2v-i-vmx-5.vmx b/v2v/test-v2v-i-vmx-5.vmx
+new file mode 100644
+index 000000000..eb54d85be
+--- /dev/null
++++ b/v2v/test-v2v-i-vmx-5.vmx
+@@ -0,0 +1,80 @@
++.encoding = "UTF-8"
++config.version = "8"
++virtualHW.version = "11"
++memsize = "2048"
++MemAllowAutoScaleDown = "FALSE"
++displayName = "MSEdge - Win10_preview"
++guestOS = "windows9-64"
++cpuid.coresPerSocket = "1"
++vmci0.present = "TRUE"
++ethernet0.present = "TRUE"
++ethernet0.addressType = "generated"
++ethernet0.connectionType = "bridged"
++ethernet0.virtualDev = "e1000e"
++ethernet0.startConnected = "TRUE"
++scsi0.present = "TRUE"
++scsi0.virtualDev = "lsisas1068"
++scsi0:0.present = "TRUE"
++scsi0:0.fileName = "MSEdge - Win10_preview.vmdk"
++bios.bootorder = "hdd,CDROM"
++cleanshutdown = "TRUE"
++ethernet0.bsdname = "en0"
++ethernet0.displayname = "Ethernet"
++ethernet0.linkstatepropagation.enable = "FALSE"
++gui.fullscreenatpoweron = "FALSE"
++gui.viewmodeatpoweron = "windowed"
++hgfs.linkrootshare = "TRUE"
++hgfs.maprootshare = "TRUE"
++isolation.tools.hgfs.disable = "FALSE"
++monitor.phys_bits_used = "42"
++msg.autoanswer = "true"
++numa.autosize.cookie = "10001"
++numa.autosize.vcpu.maxpervirtualnode = "1"
++nvram = "MSEdge - Win10_preview.nvram"
++proxyapps.publishtohost = "FALSE"
++remotedisplay.vnc.enabled = "FALSE"
++remotedisplay.vnc.port = "5900"
++replay.filename = ""
++replay.supported = "FALSE"
++scsi0:0.redo = ""
++softpoweroff = "TRUE"
++tools.synctime = "true"
++uuid.action = "create"
++virtualhw.productcompatibility = "hosted"
++vm.genid = "-570734802784577186"
++vm.genidx = "-5042519231342505152"
++vmotion.checkpointfbsize = "33554432"
++pciBridge0.present = "TRUE"
++tools.upgrade.policy = "useGlobal"
++pciBridge4.present = "TRUE"
++pciBridge4.virtualDev = "pcieRootPort"
++pciBridge4.functions = "8"
++pciBridge5.present = "TRUE"
++pciBridge5.virtualDev = "pcieRootPort"
++pciBridge5.functions = "8"
++pciBridge6.present = "TRUE"
++pciBridge6.virtualDev = "pcieRootPort"
++pciBridge6.functions = "8"
++pciBridge7.present = "TRUE"
++pciBridge7.virtualDev = "pcieRootPort"
++pciBridge7.functions = "8"
++hpet0.present = "TRUE"
++extendedConfigFile = "MSEdge - Win10_preview.vmxf"
++uuid.bios = "56 4d 54 59 5d 0c 51 8d-d3 40 38 4f fe bf e4 5d"
++uuid.location = "56 4d 54 59 5d 0c 51 8d-d3 40 38 4f fe bf e4 5d"
++migrate.hostlog = ".\MSEdge - Win10_preview-aee69569.hlog"
++pciBridge0.pciSlotNumber = "17"
++pciBridge4.pciSlotNumber = "21"
++pciBridge5.pciSlotNumber = "22"
++pciBridge6.pciSlotNumber = "23"
++pciBridge7.pciSlotNumber = "24"
++scsi0.pciSlotNumber = "160"
++ethernet0.pciSlotNumber = "192"
++vmci0.pciSlotNumber = "32"
++scsi0.sasWWID = "50 05 05 69 5d 0c 51 80"
++ethernet0.generatedAddress = "00:0c:29:bf:e4:5d"
++ethernet0.generatedAddressOffset = "0"
++vmci0.id = "-20978595"
++vmotion.checkpointSVGAPrimarySize = "33554432"
++toolsInstallManager.updateCounter = "1"
++toolsInstallManager.lastInstallError = "21004"
+diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh
+index 997103d41..3822e7426 100755
+--- a/v2v/test-v2v-i-vmx.sh
++++ b/v2v/test-v2v-i-vmx.sh
+@@ -29,7 +29,7 @@ export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
+ 
+ rm -f test-v2v-i-vmx-*.actual
+ 
+-for i in 1 2 3 4; do
++for i in 1 2 3 4 5; do
+     $VG virt-v2v --debug-gc \
+         -i vmx test-v2v-i-vmx-$i.vmx \
+         --print-source > test-v2v-i-vmx-$i.actual
+-- 
+2.14.3
+
diff --git a/SOURCES/0045-v2v-vddk-Print-passthrough-options.patch b/SOURCES/0045-v2v-vddk-Print-passthrough-options.patch
new file mode 100644
index 0000000..355d423
--- /dev/null
+++ b/SOURCES/0045-v2v-vddk-Print-passthrough-options.patch
@@ -0,0 +1,78 @@
+From e94aedc6fc64f255ab1fa2fcd31f78e86c28c5de Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Mon, 16 Oct 2017 14:32:28 +0100
+Subject: [PATCH] v2v: vddk: Print passthrough options.
+
+Changes the output to look like:
+
+[   0.0] Opening the source -i libvirt -ic vpx://... guestname --vddk ... --vddk-thumbprint ...
+
+(cherry picked from commit ce2aa47d1d79223c1a7a49b3f41e09078f22f554)
+---
+ v2v/input_libvirt_vddk.ml | 42 ++++++++++++++++++++++++++++++++----------
+ 1 file changed, 32 insertions(+), 10 deletions(-)
+
+diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
+index 89d2552f6..b322a9c49 100644
+--- a/v2v/input_libvirt_vddk.ml
++++ b/v2v/input_libvirt_vddk.ml
+@@ -101,8 +101,34 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
+       error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server.  To find the thumbprint, see the nbdkit-vddk-plugin(1) manual.  See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
+   in
+ 
++  (* List of passthrough parameters. *)
++  let vddk_passthrus =
++    [ "config",      (fun { vddk_config }      -> vddk_config);
++      "cookie",      (fun { vddk_cookie }      -> vddk_cookie);
++      "nfchostport", (fun { vddk_nfchostport } -> vddk_nfchostport);
++      "port",        (fun { vddk_port }        -> vddk_port);
++      "snapshot",    (fun { vddk_snapshot }    -> vddk_snapshot);
++      "thumbprint",  (fun { vddk_thumbprint }  -> vddk_thumbprint);
++      "transports",  (fun { vddk_transports }  -> vddk_transports);
++      "vimapiver",   (fun { vddk_vimapiver }   -> vddk_vimapiver) ] in
++
+ object
+-  inherit input_libvirt password libvirt_uri guest
++  inherit input_libvirt password libvirt_uri guest as super
++
++  method as_options =
++    let pt_options =
++      String.concat "" (
++        List.map (
++          fun (name, get_field) ->
++            match get_field vddk_options with
++            | None -> ""
++            | Some field -> sprintf " --vddk-%s %s" name field
++        ) vddk_passthrus
++      ) in
++    sprintf "%s --vddk %s%s"
++            super#as_options (* superclass prints "-i libvirt etc" *)
++            vddk_options.vddk_libdir
++            pt_options
+ 
+   method source () =
+     error_unless_vddk_libdir ();
+@@ -209,15 +235,11 @@ object
+       add_arg (sprintf "libdir=%s" libdir);
+ 
+       (* The passthrough parameters. *)
+-      let pt name = may (fun field -> add_arg (sprintf "%s=%s" name field)) in
+-      pt "config" vddk_options.vddk_config;
+-      pt "cookie" vddk_options.vddk_cookie;
+-      pt "nfchostport" vddk_options.vddk_nfchostport;
+-      pt "port" vddk_options.vddk_port;
+-      pt "snapshot" vddk_options.vddk_snapshot;
+-      pt "thumbprint" vddk_options.vddk_thumbprint;
+-      pt "transports" vddk_options.vddk_transports;
+-      pt "vimapiver" vddk_options.vddk_vimapiver;
++      List.iter (
++        fun (name, get_field) ->
++          may (fun field -> add_arg (sprintf "%s=%s" name field))
++              (get_field vddk_options)
++      ) vddk_passthrus;
+ 
+       get_args () in
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch b/SOURCES/0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch
new file mode 100644
index 0000000..1401342
--- /dev/null
+++ b/SOURCES/0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch
@@ -0,0 +1,51 @@
+From bf7dba21337b2671f877f4e37e5eb031b26fc6e2 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 17 Oct 2017 10:43:30 +0100
+Subject: [PATCH] v2v: vddk: Check if nbdkit supports --selinux-label before
+ using.
+
+Give a better error message if not.
+
+Thanks: Ming Xie.
+(cherry picked from commit 59b4c4779f7dac645c794393d91c46467afab91c)
+---
+ v2v/input_libvirt_vddk.ml | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
+index b322a9c49..f0b150efa 100644
+--- a/v2v/input_libvirt_vddk.ml
++++ b/v2v/input_libvirt_vddk.ml
+@@ -101,6 +101,20 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
+       error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server.  To find the thumbprint, see the nbdkit-vddk-plugin(1) manual.  See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
+   in
+ 
++  (* Check that nbdkit was compiled with SELinux support (for the
++   * --selinux-label option).
++   *)
++  let error_unless_nbdkit_compiled_with_selinux () =
++    let lines = external_command "nbdkit --dump-config" in
++    (* In nbdkit <= 1.1.15 the selinux attribute was not present
++     * at all in --dump-config output so there was no way to tell.
++     * Ignore this case because there will be an error later when
++     * we try to use the --selinux-label parameter.
++     *)
++    if List.mem "selinux=no" (List.map String.trim lines) then
++      error (f_"nbdkit was compiled without SELinux support.  You will have to recompile nbdkit with libselinux-devel installed, or else set SELinux to Permissive mode while doing the conversion.")
++  in
++
+   (* List of passthrough parameters. *)
+   let vddk_passthrus =
+     [ "config",      (fun { vddk_config }      -> vddk_config);
+@@ -135,6 +149,8 @@ object
+     error_unless_nbdkit_working ();
+     error_unless_nbdkit_vddk_working ();
+     error_unless_thumbprint ();
++    if have_selinux then
++      error_unless_nbdkit_compiled_with_selinux ();
+ 
+     (* Get the libvirt XML.  This also checks (as a side-effect)
+      * that the domain is not running.  (RHBZ#1138586)
+-- 
+2.14.3
+
diff --git a/SOURCES/0047-v2v-vddk-Force-source-format-to-raw.patch b/SOURCES/0047-v2v-vddk-Force-source-format-to-raw.patch
new file mode 100644
index 0000000..0771002
--- /dev/null
+++ b/SOURCES/0047-v2v-vddk-Force-source-format-to-raw.patch
@@ -0,0 +1,31 @@
+From 37f2bf9dff5e01904556248203f1dce9c9034eed Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 17 Oct 2017 10:56:14 +0100
+Subject: [PATCH] v2v: vddk: Force source format to raw.
+
+Thanks: Ming Xie.
+(cherry picked from commit 2ff287c4a7f12c26b8fb3a574129fbfb9a9157e7)
+---
+ v2v/input_libvirt_vddk.ml | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
+index f0b150efa..33b34bd2e 100644
+--- a/v2v/input_libvirt_vddk.ml
++++ b/v2v/input_libvirt_vddk.ml
+@@ -338,7 +338,11 @@ If the messages above are not sufficient to diagnose the problem then add the 
+           *)
+          chmod sock 0o777;
+ 
+-         { disk with s_qemu_uri = qemu_uri }
++         (* nbdkit from a vddk source always presents us with the raw
++          * disk blocks from the guest, so force the format to raw here.
++          *)
++         { disk with s_qemu_uri = qemu_uri;
++                     s_format = Some "raw" }
+      ) disks in
+ 
+     if verbose () then (
+-- 
+2.14.3
+
diff --git a/SOURCES/0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch b/SOURCES/0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch
new file mode 100644
index 0000000..5eeaae5
--- /dev/null
+++ b/SOURCES/0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch
@@ -0,0 +1,322 @@
+From 8018cf4c1206253c0f58e79b9afc171b3855b826 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 13 Oct 2017 15:45:39 +0100
+Subject: [PATCH] v2v: Remove --dcpath parameter and related functionality.
+
+With modern libvirt, when fetching the XML of a VMware guest libvirt
+passes us the datacenter path (dcpath).  However with older libvirt we
+had to guess this value, or else the user had to supply it on the
+command line.
+
+This commit removes all the guessing code and the --dcpath parameter
+(which will now give an error).
+
+This requires libvirt >= 1.2.20 for virt-v2v, released Oct 2015.
+
+(cherry picked from commit 3fdd923ce2d31e21a441042f9ded3c45dec6bbcb)
+---
+ v2v/cmdline.ml                      |  6 +----
+ v2v/copy_to_local.ml                | 15 ++++++------
+ v2v/input_libvirt.ml                |  4 ++--
+ v2v/input_libvirt.mli               |  4 ++--
+ v2v/input_libvirt_vcenter_https.ml  | 31 +++++++-----------------
+ v2v/input_libvirt_vcenter_https.mli |  2 +-
+ v2v/test-v2v-docs.sh                |  2 +-
+ v2v/vCenter.ml                      | 47 +------------------------------------
+ v2v/vCenter.mli                     |  8 -------
+ v2v/virt-v2v.pod                    | 13 ----------
+ 10 files changed, 24 insertions(+), 108 deletions(-)
+
+diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
+index 3050104d0..dfbb776ab 100644
+--- a/v2v/cmdline.ml
++++ b/v2v/cmdline.ml
+@@ -54,7 +54,6 @@ let parse_cmdline () =
+   let print_source = ref false in
+   let qemu_boot = ref false in
+ 
+-  let dcpath = ref None in
+   let input_conn = ref None in
+   let input_format = ref None in
+   let in_place = ref false in
+@@ -181,8 +180,6 @@ let parse_cmdline () =
+   let argspec = [
+     [ S 'b'; L"bridge" ],        Getopt.String ("in:out", add_bridge),     s_"Map bridge 'in' to 'out'";
+     [ L"compressed" ], Getopt.Set compressed,     s_"Compress output file (-of qcow2 only)";
+-    [ L"dcpath"; L"dcPath" ],  Getopt.String ("path", set_string_option_once "--dcpath" dcpath),
+-                                            s_"Override dcPath (for vCenter)";
+     [ L"debug-overlay"; L"debug-overlays" ], Getopt.Set debug_overlays, s_"Save overlay files";
+     [ S 'i' ],        Getopt.String (i_options, set_input_mode), s_"Set input mode (default: libvirt)";
+     [ M"ic" ],       Getopt.String ("uri", set_string_option_once "-ic" input_conn),
+@@ -268,7 +265,6 @@ read the man page virt-v2v(1).
+   (* Dereference the arguments. *)
+   let args = List.rev !args in
+   let compressed = !compressed in
+-  let dcpath = !dcpath in
+   let debug_overlays = !debug_overlays in
+   let do_copy = !do_copy in
+   let input_conn = !input_conn in
+@@ -367,7 +363,7 @@ read the man page virt-v2v(1).
+         | [guest] -> guest
+         | _ ->
+           error (f_"expecting a libvirt guest name on the command line") in
+-      Input_libvirt.input_libvirt dcpath vddk_options password input_conn guest
++      Input_libvirt.input_libvirt vddk_options password input_conn guest
+ 
+     | `LibvirtXML ->
+       (* -i libvirtxml: Expecting a filename (XML file). *)
+diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml
+index 88fd9abde..ca5578f3f 100644
+--- a/v2v/copy_to_local.ml
++++ b/v2v/copy_to_local.ml
+@@ -144,6 +144,11 @@ read the man page virt-v2v-copy-to-local(1).
+   let disks =
+     match source with
+     | ESXi server ->
++       let dcpath =
++         match dcpath with
++         | Some dcpath -> dcpath
++         | None ->
++            error (f_"vcenter: <vmware:datacenterpath> was not found in the XML.  You need to upgrade to libvirt ≥ 1.2.20.") in
+        List.map (
+          fun (remote_disk, local_disk) ->
+            let url, sslverify =
+@@ -242,14 +247,10 @@ and parse_libvirt_xml guest_name xml =
+   let xpathctx = Xml.xpath_new_context doc in
+   Xml.xpath_register_ns xpathctx
+                         "vmware" "http://libvirt.org/schemas/domain/vmware/1.0";
+-  let xpath_string = xpath_string xpathctx
+-  and xpath_string_default = xpath_string_default xpathctx in
++  let xpath_string = xpath_string xpathctx in
+ 
+-  (* Get the dcpath, only present for libvirt >= 1.2.20 so use a
+-   * sensible default for older versions.
+-   *)
+-  let dcpath =
+-    xpath_string_default "/domain/vmware:datacenterpath" "ha-datacenter" in
++  (* Get the dcpath, present in libvirt >= 1.2.20. *)
++  let dcpath = xpath_string "/domain/vmware:datacenterpath" in
+ 
+   (* Parse the disks. *)
+   let get_disks, add_disk =
+diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml
+index e8143b6ad..f4a8114f0 100644
+--- a/v2v/input_libvirt.ml
++++ b/v2v/input_libvirt.ml
+@@ -27,7 +27,7 @@ open Types
+ open Utils
+ 
+ (* Choose the right subclass based on the URI. *)
+-let input_libvirt dcpath vddk_options password libvirt_uri guest =
++let input_libvirt vddk_options password libvirt_uri guest =
+   match libvirt_uri with
+   | None ->
+     Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+@@ -54,7 +54,7 @@ let input_libvirt dcpath vddk_options password libvirt_uri guest =
+        (match vddk_options with
+         | None ->
+            Input_libvirt_vcenter_https.input_libvirt_vcenter_https
+-             dcpath password libvirt_uri parsed_uri scheme server guest
++             password libvirt_uri parsed_uri scheme server guest
+         | Some vddk_options ->
+            Input_libvirt_vddk.input_libvirt_vddk vddk_options password
+                                                  libvirt_uri parsed_uri guest
+diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli
+index 0a6aa3c54..acf2ca417 100644
+--- a/v2v/input_libvirt.mli
++++ b/v2v/input_libvirt.mli
+@@ -18,7 +18,7 @@
+ 
+ (** [-i libvirt] source. *)
+ 
+-val input_libvirt : string option -> Types.vddk_options option -> string option -> string option -> string -> Types.input
+-(** [input_libvirt dcpath vddk_options password libvirt_uri guest] creates
++val input_libvirt : Types.vddk_options option -> string option -> string option -> string -> Types.input
++(** [input_libvirt vddk_options password libvirt_uri guest] creates
+     and returns a new {!Types.input} object specialized for reading input
+     from libvirt sources. *)
+diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
+index df0e89315..497caca4f 100644
+--- a/v2v/input_libvirt_vcenter_https.ml
++++ b/v2v/input_libvirt_vcenter_https.ml
+@@ -36,7 +36,7 @@ let readahead_for_copying = Some (64 * 1024 * 1024)
+ 
+ (* Subclass specialized for handling VMware vCenter over https. *)
+ class input_libvirt_vcenter_https
+-  cmdline_dcPath password libvirt_uri parsed_uri scheme server guest =
++        password libvirt_uri parsed_uri scheme server guest =
+ object
+   inherit input_libvirt password libvirt_uri guest
+ 
+@@ -68,33 +68,18 @@ object
+     let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in
+     let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in
+ 
+-    (* Find the <vmware:datacenterpath> element from the XML, if it
+-     * exists.  This was added in libvirt >= 1.2.20.
++    (* Find the <vmware:datacenterpath> element from the XML.  This
++     * was added in libvirt >= 1.2.20.
+      *)
+-    let xml_dcPath =
++    dcPath <- (
+       let doc = Xml.parse_memory xml in
+       let xpathctx = Xml.xpath_new_context doc in
+       Xml.xpath_register_ns xpathctx
+         "vmware" "http://libvirt.org/schemas/domain/vmware/1.0";
+-      let xpath_string = xpath_string xpathctx in
+-      xpath_string "/domain/vmware:datacenterpath" in
+-
+-    (* Calculate the dcPath we're going to use. *)
+-    dcPath <- (
+-      match cmdline_dcPath, xml_dcPath with
+-      (* Command line --dcpath parameter overrides everything, allowing
+-       * users to correct any mistakes in v2v or libvirt.
+-       *)
+-      | Some p, (None|Some _) ->
+-         debug "vcenter: using --dcpath from the command line: %s" p;
+-         p
+-      | None, Some p ->
+-         debug "vcenter: using <vmware:datacenterpath> from libvirt: %s" p;
+-         p
+-      | None, None ->
+-         let p = VCenter.guess_dcPath parsed_uri scheme in
+-         debug "vcenter: guessed dcPath from URI: %s" p;
+-         p
++      match xpath_string xpathctx "/domain/vmware:datacenterpath" with
++      | Some dcPath -> dcPath
++      | None ->
++         error (f_"vcenter: <vmware:datacenterpath> was not found in the XML.  You need to upgrade to libvirt ≥ 1.2.20.")
+     );
+ 
+     (* Save the original source paths, so that we can remap them again
+diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli
+index 840b5a90f..d347f5fe6 100644
+--- a/v2v/input_libvirt_vcenter_https.mli
++++ b/v2v/input_libvirt_vcenter_https.mli
+@@ -18,4 +18,4 @@
+ 
+ (** [-i libvirt] when the source is VMware vCenter *)
+ 
+-val input_libvirt_vcenter_https : string option -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input
++val input_libvirt_vcenter_https : string option -> string option -> Xml.uri -> string -> string -> string -> Types.input
+diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh
+index c5d98de7f..5e49d5240 100755
+--- a/v2v/test-v2v-docs.sh
++++ b/v2v/test-v2v-docs.sh
+@@ -22,4 +22,4 @@ $TEST_FUNCTIONS
+ skip_if_skipped
+ 
+ $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \
+-  --ignore=--dcPath,--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
++  --ignore=--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
+diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
+index f6e4288f2..2f7e32ad6 100644
+--- a/v2v/vCenter.ml
++++ b/v2v/vCenter.ml
+@@ -99,7 +99,7 @@ let get_session_cookie password scheme uri sslverify url =
+ 
+     if status = "404" then (
+       dump_response stderr;
+-      error (f_"vcenter: URL not found: %s\n\nThe '--dcpath' parameter may be useful.  See the explanation in the virt-v2v(1) man page OPTIONS section.") url
++      error (f_"vcenter: URL not found: %s") url
+     );
+ 
+     if status <> "200" then (
+@@ -126,51 +126,6 @@ let get_session_cookie password scheme uri sslverify url =
+       Some !session_cookie
+   )
+ 
+-let multiple_slash = Str.regexp "/+"
+-let default_dc = "ha-datacenter"
+-
+-let guess_dcPath uri = function
+-  | "vpx" ->
+-     (match uri.uri_path with
+-      | None ->
+-         warning (f_"vcenter: URI (-ic parameter) contains no path, so we cannot determine the dcPath (datacenter name)");
+-         default_dc
+-      | Some path ->
+-         (* vCenter: URIs are *usually* '/Folder/Datacenter/esxi' so we can
+-          * just chop off the first '/' and final '/esxi' to get the dcPath.
+-          *
+-          * The libvirt driver allows things like '/DC///esxi////' so we also
+-          * have to handle trailing slashes and collapse multiple slashes into
+-          * single (RHBZ#1258342).
+-          *
+-          * However if there is a cluster involved then the URI may be
+-          * /Folder/Datacenter/Cluster/esxi but dcPath=Folder/Datacenter/Cluster
+-          * won't work.  In this case the user has to adjust the path to
+-          * remove the Cluster name (which still works in libvirt).
+-          *)
+-         (* Collapse multiple slashes to single slash. *)
+-         let path = Str.global_replace multiple_slash "/" path in
+-         (* Chop off the first and trailing '/' (if found). *)
+-         let path =
+-           let len = String.length path in
+-           if len > 0 && path.[0] = '/' then
+-             String.sub path 1 (len-1)
+-           else path in
+-         let path =
+-           let len = String.length path in
+-           if len > 0 && path.[len-1] = '/' then
+-             String.sub path 0 (len-1)
+-           else path in
+-         (* Chop off the final element (ESXi hostname). *)
+-         let len =
+-           try String.rindex path '/' with Not_found -> String.length path in
+-         String.sub path 0 len
+-     );
+-  | "esx" -> (* Connecting to an ESXi hypervisor directly, so it's fixed. *)
+-     default_dc
+-  | _ ->     (* Don't know, so guess. *)
+-     default_dc
+-
+ let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
+ 
+ let map_source_to_https dcPath uri server path =
+diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli
+index 224f45009..55d70b486 100644
+--- a/v2v/vCenter.mli
++++ b/v2v/vCenter.mli
+@@ -35,14 +35,6 @@ val get_session_cookie : string option -> string -> Xml.uri -> bool -> string ->
+     The session cookie is memoized so you can call this function as
+     often as you want, and only a single log in is made. *)
+ 
+-val guess_dcPath : Xml.uri -> string -> string
+-(** Try to guess the dcPath parameter from a URI.  The mapping is
+-    not precise.
+-
+-    This function is only used with [libvirt < 1.2.20] because later
+-    versions of libvirt provide the dcPath (see
+-    https://bugzilla.redhat.com/1263574). *)
+-
+ val map_source_to_uri : int option -> string -> string option -> Xml.uri -> string -> string -> string -> string
+ (** [map_source_to_uri readahead dcPath password uri scheme server path]
+     maps the [<source path=...>] string to a qemu URI.
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index d713d0b1f..92ed147d7 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -172,19 +172,6 @@ Write a compressed output file.  This is only allowed if the output
+ format is qcow2 (see I<-of> below), and is equivalent to the I<-c>
+ option of L<qemu-img(1)>.
+ 
+-=item B<--dcpath> Folder/Datacenter
+-
+-B<NB:> You don't need to use this parameter if you have
+-S<libvirt E<ge> 1.2.20>.
+-
+-For VMware vCenter, override the C<dcPath=...> parameter used to
+-select the datacenter.  Virt-v2v can usually calculate this from the
+-C<vpx://> URI, but if it gets it wrong, then you can override it using
+-this setting.  Go to your vCenter web folder interface, eg.
+-C<https://vcenter.example.com/folder> (I<without> a trailing slash),
+-and examine the C<dcPath=> parameter in the URLs that appear on this
+-page.
+-
+ =item B<--debug-overlays>
+ 
+ Save the overlay file(s) created during conversion.  This option is
+-- 
+2.14.3
+
diff --git a/SOURCES/0049-v2v-vCenter-Refactor-the-API-to-this-module.patch b/SOURCES/0049-v2v-vCenter-Refactor-the-API-to-this-module.patch
new file mode 100644
index 0000000..fe05d32
--- /dev/null
+++ b/SOURCES/0049-v2v-vCenter-Refactor-the-API-to-this-module.patch
@@ -0,0 +1,496 @@
+From f00bde700faf0708c8af440efdcc6b48e93f3ce4 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 13 Oct 2017 16:30:16 +0100
+Subject: [PATCH] v2v: vCenter: Refactor the API to this module.
+
+This module had a selection of functions taking a different mix of
+parameters and doing slightly different things.  You could call one
+function to return an https://... URL, or another function to return a
+qemu URL, and there was a third function to get the session cookie but
+you generally had to call that anyway (and it was implicitly called
+when making the qemu URL!)
+
+Integrate these into a single function which returns a struct
+returning all possible values.
+
+This is conceptually refactoring, except that the session cookie is no
+longer memoized, but we didn't use this feature (of calling
+get_session_cookie multiple times) anyway.
+
+(cherry picked from commit fb79fcde2947ff7e73f96343e8311e43b22a6f66)
+---
+ v2v/copy_to_local.ml               |  12 +-
+ v2v/input_libvirt_vcenter_https.ml |  12 +-
+ v2v/vCenter.ml                     | 319 +++++++++++++++++++------------------
+ v2v/vCenter.mli                    |  66 +++++---
+ 4 files changed, 211 insertions(+), 198 deletions(-)
+
+diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml
+index ca5578f3f..5fb1b79ff 100644
+--- a/v2v/copy_to_local.ml
++++ b/v2v/copy_to_local.ml
+@@ -151,14 +151,10 @@ read the man page virt-v2v-copy-to-local(1).
+             error (f_"vcenter: <vmware:datacenterpath> was not found in the XML.  You need to upgrade to libvirt ≥ 1.2.20.") in
+        List.map (
+          fun (remote_disk, local_disk) ->
+-           let url, sslverify =
+-             VCenter.map_source_to_https dcpath parsed_uri
+-                                         server remote_disk in
+-           debug "esxi: source disk %s (sslverify=%b)" url sslverify;
+-           let cookie =
+-             VCenter.get_session_cookie password "esx"
+-                                        parsed_uri sslverify url in
+-           (url, local_disk, sslverify, cookie)
++           let { VCenter.https_url; sslverify; session_cookie } =
++             VCenter.map_source dcpath parsed_uri "esx" server remote_disk in
++           debug "esxi: source disk %s (sslverify=%b)" https_url sslverify;
++           (https_url, local_disk, sslverify, session_cookie)
+        ) disks
+     | Test | Xen_ssh _ ->
+        List.map (fun (remote_disk, local_disk) ->
+diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
+index 497caca4f..1153e74a3 100644
+--- a/v2v/input_libvirt_vcenter_https.ml
++++ b/v2v/input_libvirt_vcenter_https.ml
+@@ -102,9 +102,9 @@ object
+       | { p_source = P_source_dev _ } -> assert false
+       | { p_source_disk = disk; p_source = P_dont_rewrite } -> disk
+       | { p_source_disk = disk; p_source = P_source_file path } ->
+-        let qemu_uri =
+-          VCenter.map_source_to_uri readahead dcPath password
+-                                    parsed_uri scheme server path in
++        let { VCenter.qemu_uri } =
++          VCenter.map_source ?readahead ?password
++                             dcPath parsed_uri scheme server path in
+ 
+         (* The libvirt ESX driver doesn't normally specify a format, but
+          * the format of the -flat file is *always* raw, so force it here.
+@@ -123,9 +123,9 @@ object
+     | None -> ()
+     | Some orig_path ->
+       let readahead = readahead_for_copying in
+-      let backing_qemu_uri =
+-        VCenter.map_source_to_uri readahead dcPath password
+-                                  parsed_uri scheme server orig_path in
++      let { VCenter.qemu_uri = backing_qemu_uri } =
++        VCenter.map_source ?readahead ?password
++                           dcPath parsed_uri scheme server orig_path in
+ 
+       (* Rebase the qcow2 overlay to adjust the readahead parameter. *)
+       let cmd = [ "qemu-img"; "rebase"; "-u"; "-b"; backing_qemu_uri;
+diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
+index 2f7e32ad6..341a40b25 100644
+--- a/v2v/vCenter.ml
++++ b/v2v/vCenter.ml
+@@ -38,167 +38,168 @@ let uri_quote str =
+   done;
+   String.concat "" (List.rev !xs)
+ 
+-(* Memoized session cookie. *)
+-let session_cookie = ref ""
+-
+-let get_session_cookie password scheme uri sslverify url =
+-  if !session_cookie <> "" then
+-    Some !session_cookie
+-  else (
+-    let curl_args = ref [
+-      "head", None;
+-      "silent", None;
+-      "url", Some url;
+-    ] in
+-    (match uri.uri_user, password with
+-     | None, None -> ()
+-     | None, Some _ ->
+-        warning (f_"--password-file parameter ignored because 'user@' was not given in the URL")
+-     | Some user, None ->
+-        push_back curl_args ("user", Some user)
+-     | Some user, Some password ->
+-        push_back curl_args ("user", Some (user ^ ":" ^ password))
+-    );
+-    if not sslverify then push_back curl_args ("insecure", None);
+-
+-    let curl_h = Curl.create !curl_args in
+-    let lines = Curl.run curl_h in
+-
+-    let dump_response chan =
+-      Curl.print chan curl_h;
+-
+-      (* Dump out the output of the command. *)
+-      List.iter (fun x -> fprintf chan "%s\n" x) lines;
+-      flush chan
+-    in
+-
+-    if verbose () then dump_response stderr;
+-
+-    (* Look for the last HTTP/x.y NNN status code in the output. *)
+-    let status = ref "" in
+-    List.iter (
+-      fun line ->
+-        let len = String.length line in
+-        if len >= 12 && String.sub line 0 5 = "HTTP/" then
+-          status := String.sub line 9 3
+-    ) lines;
+-    let status = !status in
+-    if status = "" then (
+-      dump_response stderr;
+-      error (f_"vcenter: no status code in output of 'curl' command.  Is 'curl' installed?")
+-    );
+-
+-    if status = "401" then (
+-      dump_response stderr;
+-      if uri.uri_user <> None then
+-        error (f_"vcenter: incorrect username or password")
+-      else
+-        error (f_"vcenter: incorrect username or password.  You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
+-              scheme
+-    );
+-
+-    if status = "404" then (
+-      dump_response stderr;
+-      error (f_"vcenter: URL not found: %s") url
+-    );
+-
+-    if status <> "200" then (
+-      dump_response stderr;
+-      error (f_"vcenter: invalid response from server")
+-    );
+-
+-    (* Get the cookie. *)
+-    List.iter (
+-      fun line ->
+-        let len = String.length line in
+-        if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
+-          let line = String.sub line 12 (len-12) in
+-          let cookie, _ = String.split ";" line in
+-          session_cookie := cookie
+-        )
+-    ) lines;
+-    if !session_cookie = "" then (
+-      dump_response stderr;
+-      warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through");
+-      None
+-    )
+-    else
+-      Some !session_cookie
+-  )
++type remote_resource = {
++  https_url : string;
++  qemu_uri : string;
++  session_cookie : string option;
++  sslverify : bool;
++}
+ 
+ let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
+ 
+-let map_source_to_https dcPath uri server path =
+-  if not (Str.string_match source_re path 0) then
+-    (path, true)
+-  else (
+-    let datastore = Str.matched_group 1 path
+-    and path = Str.matched_group 2 path in
+-
+-    let port =
+-      match uri.uri_port with
+-      | 443 -> ""
+-      | n when n >= 1 -> ":" ^ string_of_int n
+-      | _ -> "" in
+-
+-    (* XXX Old virt-v2v could also handle snapshots, ie:
+-     * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
+-     * XXX Need to handle templates.  The file is called "-delta.vmdk" in
+-     * place of "-flat.vmdk".
+-     *)
+-    let url =
+-      sprintf
+-        "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
+-        server port
+-        (uri_quote path) (uri_quote dcPath) (uri_quote datastore) in
+-
+-    (* If no_verify=1 was passed in the libvirt URI, then we have to
+-     * turn off certificate verification here too.
+-     *)
+-    let sslverify =
+-      match uri.uri_query_raw with
+-      | None -> true
+-      | Some query ->
+-        (* XXX only works if the query string is not URI-quoted *)
+-        String.find query "no_verify=1" = -1 in
+-
+-    (url, sslverify)
+-  )
+-
+-let map_source_to_uri readahead dcPath password uri scheme server path =
+-  let url, sslverify = map_source_to_https dcPath uri server path in
+-
+-  (* Now we have to query the server to get the session cookie. *)
+-  let session_cookie = get_session_cookie password scheme uri sslverify url in
+-
+-  (* Construct the JSON parameters. *)
+-  let json_params = [
+-    "file.driver", JSON.String "https";
+-    "file.url", JSON.String url;
+-    (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *)
+-    "file.timeout", JSON.Int 2000;
+-  ] in
+-
+-  let json_params =
+-    match readahead with
+-    | None -> json_params
+-    | Some readahead ->
+-       ("file.readahead", JSON.Int readahead) :: json_params in
+-
+-  let json_params =
+-    if sslverify then json_params
+-    else ("file.sslverify", JSON.String "off") :: json_params in
+-
+-  let json_params =
+-    match session_cookie with
+-    | None -> json_params
+-    | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in
+-
+-  debug "vcenter: json parameters: %s" (JSON.string_of_doc json_params);
+-
+-  (* Turn the JSON parameters into a 'json:' protocol string.
+-   * Note this requires qemu-img >= 2.1.0.
++let rec map_source ?readahead ?password dcPath uri scheme server path =
++  (* If no_verify=1 was passed in the libvirt URI, then we have to
++   * turn off certificate verification here too.
+    *)
+-  let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
++  let sslverify =
++    match uri.uri_query_raw with
++    | None -> true
++    | Some query ->
++       (* XXX only works if the query string is not URI-quoted *)
++       String.find query "no_verify=1" = -1 in
+ 
+-  qemu_uri
++  let https_url =
++    if not (Str.string_match source_re path 0) then
++      path
++    else (
++      let datastore = Str.matched_group 1 path
++      and path = Str.matched_group 2 path in
++
++      let port =
++        match uri.uri_port with
++        | 443 -> ""
++        | n when n >= 1 -> ":" ^ string_of_int n
++        | _ -> "" in
++
++      (* XXX Old virt-v2v could also handle snapshots, ie:
++       * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
++       * XXX Need to handle templates.  The file is called "-delta.vmdk" in
++       * place of "-flat.vmdk".
++       *)
++      sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
++              server port
++              (uri_quote path) (uri_quote dcPath) (uri_quote datastore)
++    ) in
++
++  let session_cookie =
++    get_session_cookie password scheme uri sslverify https_url in
++
++  let qemu_uri =
++    (* Construct the JSON parameters for the qemu URI. *)
++    let json_params = [
++      "file.driver", JSON.String "https";
++      "file.url", JSON.String https_url;
++      (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *)
++      "file.timeout", JSON.Int 2000;
++    ] in
++
++    let json_params =
++      match readahead with
++      | None -> json_params
++      | Some readahead ->
++         ("file.readahead", JSON.Int readahead) :: json_params in
++
++    let json_params =
++      if sslverify then json_params
++      else ("file.sslverify", JSON.String "off") :: json_params in
++
++    let json_params =
++      match session_cookie with
++      | None -> json_params
++      | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in
++
++    debug "vcenter: json parameters: %s" (JSON.string_of_doc json_params);
++
++    (* Turn the JSON parameters into a 'json:' protocol string.
++     * Note this requires qemu-img >= 2.1.0.
++     *)
++    let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
++
++    qemu_uri in
++
++  (* Return the struct. *)
++  { https_url = https_url;
++    qemu_uri = qemu_uri;
++    session_cookie = session_cookie;
++    sslverify = sslverify }
++
++and get_session_cookie password scheme uri sslverify https_url =
++  let curl_args = ref [
++    "head", None;
++    "silent", None;
++    "url", Some https_url;
++  ] in
++  (match uri.uri_user, password with
++   | None, None -> ()
++   | None, Some _ ->
++      warning (f_"--password-file parameter ignored because 'user@' was not given in the URL")
++   | Some user, None ->
++      push_back curl_args ("user", Some user)
++   | Some user, Some password ->
++      push_back curl_args ("user", Some (user ^ ":" ^ password))
++  );
++  if not sslverify then push_back curl_args ("insecure", None);
++
++  let curl_h = Curl.create !curl_args in
++  let lines = Curl.run curl_h in
++
++  let dump_response chan =
++    Curl.print chan curl_h;
++
++    (* Dump out the output of the command. *)
++    List.iter (fun x -> fprintf chan "%s\n" x) lines;
++    flush chan
++  in
++
++  if verbose () then dump_response stderr;
++
++  (* Look for the last HTTP/x.y NNN status code in the output. *)
++  let status = ref "" in
++  List.iter (
++    fun line ->
++      let len = String.length line in
++      if len >= 12 && String.sub line 0 5 = "HTTP/" then
++        status := String.sub line 9 3
++  ) lines;
++  let status = !status in
++  if status = "" then (
++    dump_response stderr;
++    error (f_"vcenter: no status code in output of ‘curl’ command.  Is ‘curl’ installed?")
++  );
++
++  if status = "401" then (
++    dump_response stderr;
++    if uri.uri_user <> None then
++      error (f_"vcenter: incorrect username or password")
++    else
++      error (f_"vcenter: incorrect username or password.  You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
++            scheme
++  );
++
++  if status = "404" then (
++    dump_response stderr;
++    error (f_"vcenter: URL not found: %s") https_url
++  );
++
++  if status <> "200" then (
++    dump_response stderr;
++    error (f_"vcenter: invalid response from server")
++  );
++
++  (* Get the cookie. *)
++  let rec loop = function
++    | [] ->
++       dump_response stderr;
++       warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through");
++       None
++    | line :: lines ->
++       let len = String.length line in
++       if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
++         let line = String.sub line 12 (len-12) in
++         let cookie, _ = String.split ";" line in
++         Some cookie
++       )
++       else
++         loop lines
++  in
++  loop lines
+diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli
+index 55d70b486..03749966f 100644
+--- a/v2v/vCenter.mli
++++ b/v2v/vCenter.mli
+@@ -18,35 +18,51 @@
+ 
+ (** Functions for dealing with VMware vCenter. *)
+ 
+-val get_session_cookie : string option -> string -> Xml.uri -> bool -> string -> string option
+-(** [get_session_cookie password scheme uri sslverify url]
+-    contacts the vCenter server, logs in, and gets the session cookie,
+-    which can later be passed back to the server instead of having to
+-    log in each time (this is also more efficient since it avoids
+-    vCenter running out of authentication sessions).
++type remote_resource = {
++  https_url : string;
++  (** The full URL of the remote disk as an https link on the vCenter
++      server.  It will have the general form
++      [https://vcenter/folder/.../guest-flat.vmdk?dcPath=...&...] *)
+ 
+-    Returns [None] if the session cookie could not be read (but
+-    authentication was successful).  You can proceed without the
+-    session cookie in this case, but there is an unavoidable
+-    danger of running out of authentication sessions.  If the
+-    session cookie could not be read, this function prints a
+-    warning.
++  qemu_uri : string;
++  (** The remote disk as a QEMU URI.  This opaque blob (usually a
++      [json:] URL) can be passed to [qemu] or [qemu-img] as a backing
++      file. *)
+ 
+-    The session cookie is memoized so you can call this function as
+-    often as you want, and only a single log in is made. *)
++  session_cookie : string option;
++  (** When creating the URLs above, the module contacts the vCenter
++      server, logs in, and gets the session cookie, which can later
++      be passed back to the server instead of having to log in each
++      time (this is also more efficient since it avoids vCenter
++      running out of authentication sessions).
+ 
+-val map_source_to_uri : int option -> string -> string option -> Xml.uri -> string -> string -> string -> string
+-(** [map_source_to_uri readahead dcPath password uri scheme server path]
+-    maps the [<source path=...>] string to a qemu URI.
++      This can be [None] if the session cookie could not be read (but
++      authentication was successful).  You can proceed without the
++      session cookie in this case, but there is an unavoidable
++      danger of running out of authentication sessions.  If the
++      session cookie could not be read, this function prints a
++      warning.
+ 
+-    The [path] will be something like:
++      If authentication {i failed} then the {!map_source} function
++      would exit with an error, so [None] does not indicate auth
++      failure. *)
+ 
++  sslverify : bool;
++  (** This is true except when the libvirt URI had [?no_verify=1] in
++      the parameters. *)
++}
++(** The "remote resource" is the structure returned by the {!map_source}
++    function. *)
++
++val map_source : ?readahead:int -> ?password:string -> string -> Xml.uri -> string -> string -> string -> remote_resource
++(** [map_source ?readahead ?password dcPath uri scheme server path]
++    maps the [<source path=...>] string to a {!remote_resource}
++    structure containing both an [https://] URL and a qemu URI,
++    both pointing the guest disk.
++
++    The input [path] comes from libvirt and will be something like:
+     ["[datastore1] Fedora 20/Fedora 20.vmdk"]
++    (including those literal spaces in the string).
+ 
+-    including those literal spaces in the string. *)
+-
+-val map_source_to_https : string -> Xml.uri -> string -> string -> string * bool
+-(** [map_source_to_https dcPath uri server path] is the same as
+-    {!map_source_to_uri} but it produces a regular [https://...] URL.
+-    The returned boolean is whether TLS certificate verification
+-    should be done. *)
++    This checks that the disk exists and that authentication is
++    correct, otherwise it will fail. *)
+-- 
+2.14.3
+
diff --git a/SOURCES/0050-v2v-vCenter-Split-up-get_session_cookie-function.patch b/SOURCES/0050-v2v-vCenter-Split-up-get_session_cookie-function.patch
new file mode 100644
index 0000000..9267e21
--- /dev/null
+++ b/SOURCES/0050-v2v-vCenter-Split-up-get_session_cookie-function.patch
@@ -0,0 +1,140 @@
+From 4965f1eae5bb56c47c7acf295822afb1108f624e Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 13 Oct 2017 17:01:04 +0100
+Subject: [PATCH] v2v: vCenter: Split up get_session_cookie function.
+
+This is a small refactoring where we split get_session_cookie into a
+function to fetch the URL and a function to parse the cookie.
+
+(cherry picked from commit 2052fb7d1f9a173d71ab88358281def0c6b03f06)
+---
+ v2v/vCenter.ml | 106 ++++++++++++++++++++++++++++++++-------------------------
+ 1 file changed, 59 insertions(+), 47 deletions(-)
+
+diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
+index 341a40b25..7fc0811a4 100644
+--- a/v2v/vCenter.ml
++++ b/v2v/vCenter.ml
+@@ -124,6 +124,45 @@ let rec map_source ?readahead ?password dcPath uri scheme server path =
+     sslverify = sslverify }
+ 
+ and get_session_cookie password scheme uri sslverify https_url =
++  let status, headers, dump_response =
++    fetch_headers_from_url password scheme uri sslverify https_url in
++
++  if status = "401" then (
++    dump_response stderr;
++    if uri.uri_user <> None then
++      error (f_"vcenter: incorrect username or password")
++    else
++      error (f_"vcenter: incorrect username or password.  You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
++            scheme
++  );
++
++  if status = "404" then (
++    dump_response stderr;
++    error (f_"vcenter: URL not found: %s") https_url
++  );
++
++  if status <> "200" then (
++    dump_response stderr;
++    error (f_"vcenter: invalid response from server")
++  );
++
++  (* Get the cookie. *)
++  let rec loop = function
++    | [] ->
++       dump_response stderr;
++       warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through");
++       None
++    | ("set-cookie", cookie) :: _ ->
++       let cookie, _ = String.split ";" cookie in
++       Some cookie
++
++    | _ :: headers ->
++       loop headers
++  in
++  loop headers
++
++(* Fetch the status and reply headers from a URL. *)
++and fetch_headers_from_url password scheme uri sslverify https_url =
+   let curl_args = ref [
+     "head", None;
+     "silent", None;
+@@ -153,53 +192,26 @@ and get_session_cookie password scheme uri sslverify https_url =
+ 
+   if verbose () then dump_response stderr;
+ 
++  let statuses, headers =
++    List.partition (
++      fun line ->
++        let len = String.length line in
++        len >= 12 && String.sub line 0 5 = "HTTP/"
++    ) lines in
++
+   (* Look for the last HTTP/x.y NNN status code in the output. *)
+-  let status = ref "" in
+-  List.iter (
+-    fun line ->
+-      let len = String.length line in
+-      if len >= 12 && String.sub line 0 5 = "HTTP/" then
+-        status := String.sub line 9 3
+-  ) lines;
+-  let status = !status in
+-  if status = "" then (
+-    dump_response stderr;
+-    error (f_"vcenter: no status code in output of ‘curl’ command.  Is ‘curl’ installed?")
+-  );
+-
+-  if status = "401" then (
+-    dump_response stderr;
+-    if uri.uri_user <> None then
+-      error (f_"vcenter: incorrect username or password")
+-    else
+-      error (f_"vcenter: incorrect username or password.  You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
+-            scheme
+-  );
+-
+-  if status = "404" then (
+-    dump_response stderr;
+-    error (f_"vcenter: URL not found: %s") https_url
+-  );
+-
+-  if status <> "200" then (
+-    dump_response stderr;
+-    error (f_"vcenter: invalid response from server")
+-  );
+-
+-  (* Get the cookie. *)
+-  let rec loop = function
++  let status =
++    match statuses with
+     | [] ->
+        dump_response stderr;
+-       warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through");
+-       None
+-    | line :: lines ->
+-       let len = String.length line in
+-       if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
+-         let line = String.sub line 12 (len-12) in
+-         let cookie, _ = String.split ";" line in
+-         Some cookie
+-       )
+-       else
+-         loop lines
+-  in
+-  loop lines
++       error (f_"vcenter: no status code in output of ‘curl’ command.  Is ‘curl’ installed?")
++    | ss -> String.sub (List.hd (List.rev ss)) 9 3 in
++
++  let headers =
++    List.map (
++      fun header ->
++        let h, c = String.split ": " header in
++        String.lowercase_ascii h, c
++    ) headers in
++
++  status, headers, dump_response
+-- 
+2.14.3
+
diff --git a/SOURCES/0051-v2v-vCenter-Factor-out-get_https_url-code.patch b/SOURCES/0051-v2v-vCenter-Factor-out-get_https_url-code.patch
new file mode 100644
index 0000000..2ee10a3
--- /dev/null
+++ b/SOURCES/0051-v2v-vCenter-Factor-out-get_https_url-code.patch
@@ -0,0 +1,79 @@
+From 56835fbc66a9ae540764d1628922afaaa5b2fffc Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 13 Oct 2017 17:08:23 +0100
+Subject: [PATCH] v2v: vCenter: Factor out get_https_url code.
+
+Pure refactoring.
+
+(cherry picked from commit 388a70139910ed4b03d9765e403c35bb26cbe422)
+---
+ v2v/vCenter.ml | 46 ++++++++++++++++++++++++----------------------
+ 1 file changed, 24 insertions(+), 22 deletions(-)
+
+diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
+index 7fc0811a4..f53affb48 100644
+--- a/v2v/vCenter.ml
++++ b/v2v/vCenter.ml
+@@ -58,28 +58,7 @@ let rec map_source ?readahead ?password dcPath uri scheme server path =
+        (* XXX only works if the query string is not URI-quoted *)
+        String.find query "no_verify=1" = -1 in
+ 
+-  let https_url =
+-    if not (Str.string_match source_re path 0) then
+-      path
+-    else (
+-      let datastore = Str.matched_group 1 path
+-      and path = Str.matched_group 2 path in
+-
+-      let port =
+-        match uri.uri_port with
+-        | 443 -> ""
+-        | n when n >= 1 -> ":" ^ string_of_int n
+-        | _ -> "" in
+-
+-      (* XXX Old virt-v2v could also handle snapshots, ie:
+-       * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
+-       * XXX Need to handle templates.  The file is called "-delta.vmdk" in
+-       * place of "-flat.vmdk".
+-       *)
+-      sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
+-              server port
+-              (uri_quote path) (uri_quote dcPath) (uri_quote datastore)
+-    ) in
++  let https_url = get_https_url dcPath uri server path in
+ 
+   let session_cookie =
+     get_session_cookie password scheme uri sslverify https_url in
+@@ -123,6 +102,29 @@ let rec map_source ?readahead ?password dcPath uri scheme server path =
+     session_cookie = session_cookie;
+     sslverify = sslverify }
+ 
++and get_https_url dcPath uri server path =
++  if not (Str.string_match source_re path 0) then
++    path
++  else (
++    let datastore = Str.matched_group 1 path
++    and path = Str.matched_group 2 path in
++
++    let port =
++      match uri.uri_port with
++      | 443 -> ""
++      | n when n >= 1 -> ":" ^ string_of_int n
++      | _ -> "" in
++
++    (* XXX Old virt-v2v could also handle snapshots, ie:
++     * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
++     * XXX Need to handle templates.  The file is called "-delta.vmdk" in
++     * place of "-flat.vmdk".
++     *)
++    sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
++            server port
++            (uri_quote path) (uri_quote dcPath) (uri_quote datastore)
++  )
++
+ and get_session_cookie password scheme uri sslverify https_url =
+   let status, headers, dump_response =
+     fetch_headers_from_url password scheme uri sslverify https_url in
+-- 
+2.14.3
+
diff --git a/SOURCES/0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch b/SOURCES/0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch
new file mode 100644
index 0000000..f4b8b62
--- /dev/null
+++ b/SOURCES/0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch
@@ -0,0 +1,71 @@
+From bdeb7926bea75bb62a5165eb94ee4084d678f7fe Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 13 Oct 2017 17:14:07 +0100
+Subject: [PATCH] v2v: vCenter: Handle disks with snapshots (RHBZ#1172425).
+
+This implements a missing feature from old virt-v2v, namely being able
+to cope with a guest with snapshots.  Note this only converts the top
+(latest) snapshot.  As in old virt-v2v it does NOT convert the whole
+chain of snapshots.
+
+(cherry picked from commit c380920034612290eef4476ab4e731c492c68869)
+---
+ v2v/vCenter.ml | 28 ++++++++++++++++++++++++----
+ 1 file changed, 24 insertions(+), 4 deletions(-)
+
+diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
+index f53affb48..a1aaf7b7e 100644
+--- a/v2v/vCenter.ml
++++ b/v2v/vCenter.ml
+@@ -46,6 +46,7 @@ type remote_resource = {
+ }
+ 
+ let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
++let snapshot_re = Str.regexp "^\\(.*\\)-[0-9][0-9][0-9][0-9][0-9][0-9]\\(\\.vmdk\\)$"
+ 
+ let rec map_source ?readahead ?password dcPath uri scheme server path =
+   (* If no_verify=1 was passed in the libvirt URI, then we have to
+@@ -58,7 +59,28 @@ let rec map_source ?readahead ?password dcPath uri scheme server path =
+        (* XXX only works if the query string is not URI-quoted *)
+        String.find query "no_verify=1" = -1 in
+ 
+-  let https_url = get_https_url dcPath uri server path in
++  let https_url =
++    let https_url = get_https_url dcPath uri server path in
++    (* Check the URL exists. *)
++    let status, _, _ =
++      fetch_headers_from_url password scheme uri sslverify https_url in
++    (* If a disk is actually a snapshot image it will have '-00000n'
++     * appended to its name, e.g.:
++     *   [yellow:storage1] RHEL4-X/RHEL4-X-000003.vmdk
++     * The flat storage is still called RHEL4-X-flat, however. If we got
++     * a 404 and the vmdk name looks like it might be a snapshot, try
++     * again without the snapshot suffix.
++     *)
++    if status = "404" && Str.string_match snapshot_re path 0 then (
++      let path = Str.matched_group 1 path ^ Str.matched_group 2 path in
++      get_https_url dcPath uri server path
++    )
++    else
++      (* Note that other non-200 status errors will be handled
++       * in get_session_cookie below, so we don't have to worry
++       * about them here.
++       *)
++      https_url in
+ 
+   let session_cookie =
+     get_session_cookie password scheme uri sslverify https_url in
+@@ -115,9 +137,7 @@ and get_https_url dcPath uri server path =
+       | n when n >= 1 -> ":" ^ string_of_int n
+       | _ -> "" in
+ 
+-    (* XXX Old virt-v2v could also handle snapshots, ie:
+-     * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
+-     * XXX Need to handle templates.  The file is called "-delta.vmdk" in
++    (* XXX Need to handle templates.  The file is called "-delta.vmdk" in
+      * place of "-flat.vmdk".
+      *)
+     sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
+-- 
+2.14.3
+
diff --git a/SOURCES/0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch b/SOURCES/0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch
new file mode 100644
index 0000000..09a4f80
--- /dev/null
+++ b/SOURCES/0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch
@@ -0,0 +1,126 @@
+From 9dcd0326952b2d0ad6f95f51bd9e0f5487603e30 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 2 Mar 2017 12:42:46 +0000
+Subject: [PATCH] generator: Deprecate direct mode (guestfs_set_direct,
+ guestfs_get_direct).
+
+(cherry picked from commit 26948d5cb17391a32856b18b8a5d6ae58a179507)
+---
+ generator/actions_properties.ml            | 28 ----------------------------
+ generator/actions_properties_deprecated.ml | 30 ++++++++++++++++++++++++++++++
+ rescue/rescue.c                            |  3 +++
+ test-tool/test-tool.c                      |  1 -
+ 4 files changed, 33 insertions(+), 29 deletions(-)
+
+diff --git a/generator/actions_properties.ml b/generator/actions_properties.ml
+index 8f6455b81..87144b14f 100644
+--- a/generator/actions_properties.ml
++++ b/generator/actions_properties.ml
+@@ -259,34 +259,6 @@ C<guestfs_set_event_callback>)." };
+     longdesc = "\
+ Return the command trace flag." };
+ 
+-  { defaults with
+-    name = "set_direct"; added = (1, 0, 72);
+-    style = RErr, [Bool "direct"], [];
+-    fish_alias = ["direct"]; config_only = true;
+-    blocking = false;
+-    shortdesc = "enable or disable direct appliance mode";
+-    longdesc = "\
+-If the direct appliance mode flag is enabled, then stdin and
+-stdout are passed directly through to the appliance once it
+-is launched.
+-
+-One consequence of this is that log messages aren't caught
+-by the library and handled by C<guestfs_set_log_message_callback>,
+-but go straight to stdout.
+-
+-You probably don't want to use this unless you know what you
+-are doing.
+-
+-The default is disabled." };
+-
+-  { defaults with
+-    name = "get_direct"; added = (1, 0, 72);
+-    style = RBool "direct", [], [];
+-    blocking = false;
+-    shortdesc = "get direct appliance mode flag";
+-    longdesc = "\
+-Return the direct appliance mode flag." };
+-
+   { defaults with
+     name = "set_recovery_proc"; added = (1, 0, 77);
+     style = RErr, [Bool "recoveryproc"], [];
+diff --git a/generator/actions_properties_deprecated.ml b/generator/actions_properties_deprecated.ml
+index def17b926..53277822e 100644
+--- a/generator/actions_properties_deprecated.ml
++++ b/generator/actions_properties_deprecated.ml
+@@ -125,6 +125,36 @@ Return the current backend.
+ 
+ See C<guestfs_set_backend> and L<guestfs(3)/BACKEND>." };
+ 
++  { defaults with
++    name = "set_direct"; added = (1, 0, 72);
++    style = RErr, [Bool "direct"], [];
++    deprecated_by = Deprecated_no_replacement;
++    fish_alias = ["direct"]; config_only = true;
++    blocking = false;
++    shortdesc = "enable or disable direct appliance mode";
++    longdesc = "\
++If the direct appliance mode flag is enabled, then stdin and
++stdout are passed directly through to the appliance once it
++is launched.
++
++One consequence of this is that log messages aren't caught
++by the library and handled by C<guestfs_set_log_message_callback>,
++but go straight to stdout.
++
++You probably don't want to use this unless you know what you
++are doing.
++
++The default is disabled." };
++
++  { defaults with
++    name = "get_direct"; added = (1, 0, 72);
++    style = RBool "direct", [], [];
++    deprecated_by = Deprecated_no_replacement;
++    blocking = false;
++    shortdesc = "get direct appliance mode flag";
++    longdesc = "\
++Return the direct appliance mode flag." };
++
+ ]
+ 
+ let daemon_functions = [
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index 45967b2ad..b692e5a07 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -295,9 +295,12 @@ main (int argc, char *argv[])
+     usage (EXIT_FAILURE);
+   }
+ 
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+   /* Setting "direct mode" is required for the rescue appliance. */
+   if (guestfs_set_direct (g, 1) == -1)
+     exit (EXIT_FAILURE);
++#pragma GCC diagnostic pop
+ 
+   {
+     /* The libvirt backend doesn't support direct mode.  As a temporary
+diff --git a/test-tool/test-tool.c b/test-tool/test-tool.c
+index 20e2a32fa..2ae266d7d 100644
+--- a/test-tool/test-tool.c
++++ b/test-tool/test-tool.c
+@@ -224,7 +224,6 @@ main (int argc, char *argv[])
+   p = guestfs_get_cachedir (g);
+   printf ("guestfs_get_cachedir: %s\n", p ? : "(null)");
+   free (p);
+-  printf ("guestfs_get_direct: %d\n", guestfs_get_direct (g));
+   p = guestfs_get_hv (g);
+   printf ("guestfs_get_hv: %s\n", p);
+   free (p);
+-- 
+2.14.3
+
diff --git a/SOURCES/0054-New-API-internal-get-console-socket-to-support-virt-.patch b/SOURCES/0054-New-API-internal-get-console-socket-to-support-virt-.patch
new file mode 100644
index 0000000..30eced5
--- /dev/null
+++ b/SOURCES/0054-New-API-internal-get-console-socket-to-support-virt-.patch
@@ -0,0 +1,184 @@
+From 78588ae92828fad9b8ea09e2edf3899466975470 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 2 Mar 2017 11:06:27 +0000
+Subject: [PATCH] New API: internal-get-console-socket to support virt-rescue.
+
+This API intended for use by virt-rescue only gets the file descriptor
+of the console socket.
+
+(cherry picked from commit 84c9f98c2e09a459ced3c7e85191f2e47d149a52)
+---
+ generator/actions_core.ml                  | 11 +++++++
+ generator/actions_properties_deprecated.ml |  4 +--
+ lib/Makefile.am                            |  1 +
+ lib/conn-socket.c                          | 16 +++++++++-
+ lib/guestfs-internal.h                     |  3 ++
+ lib/rescue.c                               | 47 ++++++++++++++++++++++++++++++
+ 6 files changed, 79 insertions(+), 3 deletions(-)
+ create mode 100644 lib/rescue.c
+
+diff --git a/generator/actions_core.ml b/generator/actions_core.ml
+index ee2539c09..dbacdfadf 100644
+--- a/generator/actions_core.ml
++++ b/generator/actions_core.ml
+@@ -1678,6 +1678,17 @@ call it returns a simple true/false boolean result, instead
+ of throwing an exception if a feature is not found.  For
+ other documentation see C<guestfs_available>." };
+ 
++  { defaults with
++    name = "internal_get_console_socket"; added = (1, 37, 1);
++    style = RInt "fd", [], [];
++    visibility = VInternal;
++    test_excuse = "writing to the socket may block";
++    shortdesc = "get the appliance console socket";
++    longdesc = "\
++This call is used by L<virt-rescue(1)> to write directly to
++appliance console (for passing through keystrokes).  It should
++not normally be used by other libguestfs users." };
++
+ ]
+ 
+ let daemon_functions = [
+diff --git a/generator/actions_properties_deprecated.ml b/generator/actions_properties_deprecated.ml
+index 53277822e..f36509e75 100644
+--- a/generator/actions_properties_deprecated.ml
++++ b/generator/actions_properties_deprecated.ml
+@@ -128,7 +128,7 @@ See C<guestfs_set_backend> and L<guestfs(3)/BACKEND>." };
+   { defaults with
+     name = "set_direct"; added = (1, 0, 72);
+     style = RErr, [Bool "direct"], [];
+-    deprecated_by = Deprecated_no_replacement;
++    deprecated_by = Replaced_by "internal_get_console_socket";
+     fish_alias = ["direct"]; config_only = true;
+     blocking = false;
+     shortdesc = "enable or disable direct appliance mode";
+@@ -149,7 +149,7 @@ The default is disabled." };
+   { defaults with
+     name = "get_direct"; added = (1, 0, 72);
+     style = RBool "direct", [], [];
+-    deprecated_by = Deprecated_no_replacement;
++    deprecated_by = Replaced_by "internal_get_console_socket";
+     blocking = false;
+     shortdesc = "get direct appliance mode flag";
+     longdesc = "\
+diff --git a/lib/Makefile.am b/lib/Makefile.am
+index 22974187f..c3e013a52 100644
+--- a/lib/Makefile.am
++++ b/lib/Makefile.am
+@@ -117,6 +117,7 @@ libguestfs_la_SOURCES = \
+ 	private-data.c \
+ 	proto.c \
+ 	qemu.c \
++	rescue.c \
+ 	stringsbuf.c \
+ 	structs-compare.c \
+ 	structs-copy.c \
+diff --git a/lib/conn-socket.c b/lib/conn-socket.c
+index 2cd261a2b..8ecfed856 100644
+--- a/lib/conn-socket.c
++++ b/lib/conn-socket.c
+@@ -1,5 +1,5 @@
+ /* libguestfs
+- * Copyright (C) 2013 Red Hat Inc.
++ * Copyright (C) 2013-2017 Red Hat Inc.
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+@@ -397,6 +397,19 @@ handle_log_message (guestfs_h *g,
+   return 1;
+ }
+ 
++static int
++get_console_sock (guestfs_h *g, struct connection *connv)
++{
++  struct connection_socket *conn = (struct connection_socket *) connv;
++
++  if (conn->console_sock == -1) {
++    error (g, _("console socket not connected"));
++    return -1;
++  }
++
++  return conn->console_sock;
++}
++
+ static void
+ free_conn_socket (guestfs_h *g, struct connection *connv)
+ {
+@@ -418,6 +431,7 @@ static struct connection_ops ops = {
+   .read_data = read_data,
+   .write_data = write_data,
+   .can_read_data = can_read_data,
++  .get_console_sock = get_console_sock,
+ };
+ 
+ /**
+diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h
+index d962aacd4..3bae02b8a 100644
+--- a/lib/guestfs-internal.h
++++ b/lib/guestfs-internal.h
+@@ -369,6 +369,9 @@ struct connection_ops {
+    * Returns: 1 = yes, 0 = no, -1 = error
+    */
+   int (*can_read_data) (guestfs_h *g, struct connection *);
++
++  /* Get the console socket (to support virt-rescue). */
++  int (*get_console_sock) (guestfs_h *g, struct connection *);
+ };
+ 
+ /**
+diff --git a/lib/rescue.c b/lib/rescue.c
+new file mode 100644
+index 000000000..ae7811a31
+--- /dev/null
++++ b/lib/rescue.c
+@@ -0,0 +1,47 @@
++/* libguestfs
++ * Copyright (C) 2017 Red Hat Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/**
++ * Support for virt-rescue(1).
++ */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <libintl.h>
++
++#include "guestfs.h"
++#include "guestfs-internal.h"
++#include "guestfs-internal-actions.h"
++
++int
++guestfs_impl_internal_get_console_socket (guestfs_h *g)
++{
++  if (!g->conn) {
++    error (g, _("no console socket, the handle must be launched"));
++    return -1;
++  }
++
++  if (!g->conn->ops->get_console_sock)
++    NOT_SUPPORTED (g, -1,
++           _("connection class does not support getting the console socket"));
++
++  return g->conn->ops->get_console_sock (g, g->conn);
++}
+-- 
+2.14.3
+
diff --git a/SOURCES/0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch b/SOURCES/0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch
new file mode 100644
index 0000000..62ca9b1
--- /dev/null
+++ b/SOURCES/0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch
@@ -0,0 +1,39 @@
+From ef4efa57d1c0fffe4d81ea70ad8f44d07667cfeb Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 3 Mar 2017 10:14:20 +0000
+Subject: [PATCH] lib: Return EPIPE for "appliance closed the connection
+ unexpectedly".
+
+(cherry picked from commit 8af9acd4e31e9880e14735b2242c496ee017c0d9)
+---
+ lib/errors.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/lib/errors.c b/lib/errors.c
+index c2af611ee..ace6a89cf 100644
+--- a/lib/errors.c
++++ b/lib/errors.c
+@@ -358,12 +358,15 @@ void
+ guestfs_int_unexpected_close_error (guestfs_h *g)
+ {
+   if (g->verbose)
+-    error (g, _("appliance closed the connection unexpectedly, see earlier error messages"));
++    guestfs_int_error_errno (g, EPIPE,
++                             _("appliance closed the connection unexpectedly, "
++                               "see earlier error messages"));
+   else
+-    error (g, _(
+-		"appliance closed the connection unexpectedly.\n"
+-		"This usually means the libguestfs appliance crashed.\n"
+-		DEBUG_ADVICE));
++    guestfs_int_error_errno (g, EPIPE,
++                             _("appliance closed the connection unexpectedly.\n"
++                               "This usually means the libguestfs appliance "
++                               "crashed.\n"
++                               DEBUG_ADVICE));
+ }
+ 
+ /**
+-- 
+2.14.3
+
diff --git a/SOURCES/0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch b/SOURCES/0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch
new file mode 100644
index 0000000..314e154
--- /dev/null
+++ b/SOURCES/0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch
@@ -0,0 +1,535 @@
+From 2d013d5d67d5896869dff4b08c0674b2d91e721f Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 2 Mar 2017 13:46:48 +0000
+Subject: [PATCH] rescue: Modify virt-rescue so it doesn't use direct mode
+ (RHBZ#1152819, RHBZ#1171654).
+
+Instead of using "direct mode" (which was basically a quick hack),
+virt-rescue now launches the appliance with a running daemon.
+
+The daemon doesn't do much -- there is still a bash shell which the
+user interacts with.  The daemon is there simply to provide the
+initial GUESTFS_LAUNCH_FLAG message and to handle shutdown a bit more
+gracefully.
+
+To interact with the shell, and replacing direct mode, virt-rescue now
+prints out log messages (the output of the shell), and sends input
+typed by the user directly to the console socket.  This uses the
+guestfs_internal_get_console_socket API added previously.  Most of the
+complexity behind this is hidden in virt-rescue.
+
+This fully fixes the handling of ^C (RHBZ#1152819).  Also there were
+earlier reports that full screen commands like 'vim' didn't work well,
+(RHBZ#1171654), but in this version vim appears to work fine, albeit
+only using 80x24 of the screen because of the serial console.
+
+(cherry picked from commit 32d60801443647b3523b9374c431fefdbf054e3c)
+---
+ appliance/init     |  93 ++++++++--------
+ rescue/Makefile.am |   1 +
+ rescue/rescue.c    | 306 +++++++++++++++++++++++++++++++++++++++++++++--------
+ 3 files changed, 313 insertions(+), 87 deletions(-)
+
+diff --git a/appliance/init b/appliance/init
+index 735ba8946..ea763c2d3 100755
+--- a/appliance/init
++++ b/appliance/init
+@@ -160,60 +160,63 @@ if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then
+     echo -n "uptime: "; cat /proc/uptime
+ fi
+ 
+-if ! test "$guestfs_rescue" = 1; then
+-  # Run the daemon.
+-  cmd="guestfsd"
+-  eval `grep -Eo 'guestfs_channel=[^[:space:]]+' /proc/cmdline`
+-  if test "x$guestfs_channel" != "x"; then
++# Run the daemon.
++cmd="guestfsd"
++eval `grep -Eo 'guestfs_channel=[^[:space:]]+' /proc/cmdline`
++if test "x$guestfs_channel" != "x"; then
+     cmd="$cmd --channel $guestfs_channel"
+-  fi
+-  if test "$guestfs_verbose" = 1; then
++fi
++if test "$guestfs_verbose" = 1; then
+     cmd="$cmd --verbose"
+-  fi
+-  if test "$guestfs_network" = 1; then
++fi
++if test "$guestfs_network" = 1; then
+     cmd="$cmd --network"
+-  fi
+-  echo $cmd
+-  $cmd
++fi
++if ! test "$guestfs_rescue" = 1; then
++    echo $cmd
++    $cmd
+ else
+-  # Run virt-rescue shell.
++    # Run virt-rescue shell.
+ 
+-  # Get name of the serial port, from console= passed by libguestfs.
+-  # XXX Consider using /proc/consoles
+-  guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline |
+-                   sed s/console=//)
++    # We need a daemon, even in virt-rescue.
++    $cmd &
+ 
+-  # Remove LD_PRELOAD=libSegFault set above.
+-  unset LD_PRELOAD
++    # Get name of the serial port, from console= passed by libguestfs.
++    # XXX Consider using /proc/consoles
++    guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline |
++                     sed s/console=//)
+ 
+-  :> $HOME/.bashrc
+-  grep -Eo 'TERM=[^[:space:]]+' /proc/cmdline >> $HOME/.bashrc
+-  echo "PS1='><rescue> '" >> $HOME/.bashrc
+-  echo "export TERM PS1" >> $HOME/.bashrc
++    # Remove LD_PRELOAD=libSegFault set above.
++    unset LD_PRELOAD
+ 
+-  # The shell is opened by default on /dev/console, which (on Linux)
+-  # is not a controlling terminal, causing job control to fail.  For
+-  # how we work around this, see:
+-  # https://busybox.net/FAQ.html#job_control
+-  run_bash_with_ctty ()
+-  {
+-    setsid bash -c \
+-      "exec bash </dev/$guestfs_serial >/dev/$guestfs_serial 2>&1"
+-  }
++    :> $HOME/.bashrc
++    grep -Eo 'TERM=[^[:space:]]+' /proc/cmdline >> $HOME/.bashrc
++    echo "PS1='><rescue> '" >> $HOME/.bashrc
++    echo "export TERM PS1" >> $HOME/.bashrc
+ 
+-  echo
+-  echo "------------------------------------------------------------"
+-  echo
+-  echo "Welcome to virt-rescue, the libguestfs rescue shell."
+-  echo
+-  echo "Note: The contents of / are the rescue appliance."
+-  echo "You have to mount the guest's partitions under /sysroot"
+-  echo "before you can examine them."
+-  echo
+-  run_bash_with_ctty
+-  echo
+-  echo "virt-rescue: Syncing the disk now before exiting ..."
+-  echo
++    # The shell is opened by default on /dev/console, which (on Linux)
++    # is not a controlling terminal, causing job control to fail.  For
++    # how we work around this, see:
++    # https://busybox.net/FAQ.html#job_control
++    run_bash_with_ctty ()
++    {
++        setsid bash -c \
++            "exec bash </dev/$guestfs_serial >/dev/$guestfs_serial 2>&1"
++    }
++
++    echo
++    echo "------------------------------------------------------------"
++    echo
++    echo "Welcome to virt-rescue, the libguestfs rescue shell."
++    echo
++    echo "Note: The contents of / (root) are the rescue appliance."
++    echo "You have to mount the guest's partitions under /sysroot"
++    echo "before you can examine them."
++    echo
++    run_bash_with_ctty
++    echo
++    echo "virt-rescue: Syncing the disk now before exiting ..."
++    echo
+ fi
+ 
+ sync
+diff --git a/rescue/Makefile.am b/rescue/Makefile.am
+index 7919aafd5..99d4b79ae 100644
+--- a/rescue/Makefile.am
++++ b/rescue/Makefile.am
+@@ -30,6 +30,7 @@ virt_rescue_SOURCES = \
+ 
+ virt_rescue_CPPFLAGS = \
+ 	-DGUESTFS_WARN_DEPRECATED=1 \
++	-DGUESTFS_PRIVATE=1 \
+ 	-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
+ 	-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
+ 	-I$(top_srcdir)/lib -I$(top_builddir)/lib \
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index b692e5a07..b145dcd40 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -23,21 +23,32 @@
+ #include <string.h>
+ #include <inttypes.h>
+ #include <unistd.h>
++#include <fcntl.h>
+ #include <getopt.h>
+ #include <errno.h>
+ #include <error.h>
++#include <signal.h>
++#include <termios.h>
++#include <poll.h>
+ #include <locale.h>
+ #include <assert.h>
+ #include <libintl.h>
+ 
++#include "full-write.h"
++#include "getprogname.h"
+ #include "ignore-value.h"
+ #include "xvasprintf.h"
+-#include "getprogname.h"
+ 
+ #include "guestfs.h"
+ #include "options.h"
+ #include "display-options.h"
+ 
++static void log_message_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);
++static void do_rescue (int sock);
++static void raw_tty (void);
++static void restore_tty (void);
++static void tstp_handler (int sig);
++static void cont_handler (int sig);
+ static void add_scratch_disks (int n, struct drv **drvs);
+ static void do_suggestion (struct drv *drvs);
+ 
+@@ -54,6 +65,9 @@ int inspector = 0;
+ int in_guestfish = 0;
+ int in_virt_rescue = 1;
+ 
++/* Old terminal settings. */
++static struct termios old_termios;
++
+ static void __attribute__((noreturn))
+ usage (int status)
+ {
+@@ -135,6 +149,8 @@ main (int argc, char *argv[])
+   int memsize = 0;
+   int smp = 0;
+   int suggest = 0;
++  char *append_full;
++  int sock;
+ 
+   g = guestfs_create ();
+   if (g == NULL)
+@@ -295,30 +311,6 @@ main (int argc, char *argv[])
+     usage (EXIT_FAILURE);
+   }
+ 
+-#pragma GCC diagnostic push
+-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+-  /* Setting "direct mode" is required for the rescue appliance. */
+-  if (guestfs_set_direct (g, 1) == -1)
+-    exit (EXIT_FAILURE);
+-#pragma GCC diagnostic pop
+-
+-  {
+-    /* The libvirt backend doesn't support direct mode.  As a temporary
+-     * workaround, force the appliance backend, but warn about it.
+-     */
+-    CLEANUP_FREE char *backend = guestfs_get_backend (g);
+-    if (backend) {
+-      if (STREQ (backend, "libvirt") ||
+-          STRPREFIX (backend, "libvirt:")) {
+-        fprintf (stderr, _("%s: warning: virt-rescue doesn't work with the libvirt backend\n"
+-                           "at the moment.  As a workaround, forcing backend = 'direct'.\n"),
+-                 getprogname ());
+-        if (guestfs_set_backend (g, "direct") == -1)
+-          exit (EXIT_FAILURE);
+-      }
+-    }
+-  }
+-
+   /* Set other features. */
+   if (memsize > 0)
+     if (guestfs_set_memsize (g, memsize) == -1)
+@@ -330,16 +322,15 @@ main (int argc, char *argv[])
+     if (guestfs_set_smp (g, smp) == -1)
+       exit (EXIT_FAILURE);
+ 
+-  {
+-    /* Kernel command line must include guestfs_rescue=1 (see
+-     * appliance/init) as well as other options.
+-     */
+-    CLEANUP_FREE char *append_full = xasprintf ("guestfs_rescue=1%s%s",
+-                                                append ? " " : "",
+-                                                append ? append : "");
+-    if (guestfs_set_append (g, append_full) == -1)
+-      exit (EXIT_FAILURE);
+-  }
++  /* Kernel command line must include guestfs_rescue=1 (see
++   * appliance/init) as well as other options.
++   */
++  append_full = xasprintf ("guestfs_rescue=1%s%s",
++                           append ? " " : "",
++                           append ? append : "");
++  if (guestfs_set_append (g, append_full) == -1)
++    exit (EXIT_FAILURE);
++  free (append_full);
+ 
+   /* Add drives. */
+   add_drives (drvs);
+@@ -347,22 +338,253 @@ main (int argc, char *argv[])
+   /* Free up data structures, no longer needed after this point. */
+   free_drives (drvs);
+ 
+-  /* Run the appliance.  This won't return until the user quits the
+-   * appliance.
++  /* Add an event handler to print "log messages".  These will be the
++   * output of the appliance console during launch and shutdown.
++   * After launch, we will read the console messages directly from the
++   * socket and they won't be passed through the event callback.
+    */
+-  if (!verbose)
+-    guestfs_set_error_handler (g, NULL, NULL);
++  if (guestfs_set_event_callback (g, log_message_callback,
++                                  GUESTFS_EVENT_APPLIANCE, 0, NULL) == -1)
++    exit (EXIT_FAILURE);
+ 
+-  /* We expect launch to fail, so ignore the return value, and don't
+-   * bother with explicit guestfs_shutdown either.
++  /* Run the appliance. */
++  if (guestfs_launch (g) == -1)
++    exit (EXIT_FAILURE);
++
++  sock = guestfs_internal_get_console_socket (g);
++  if (sock == -1)
++    exit (EXIT_FAILURE);
++
++  /* Try to set all sockets to non-blocking. */
++  if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
++    perror ("could not set stdin to non-blocking");
++  if (fcntl (STDOUT_FILENO, F_SETFL, O_NONBLOCK) == -1)
++    perror ("could not set stdout to non-blocking");
++  if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1)
++    perror ("could not set console socket to non-blocking");
++
++  /* Save the initial state of the tty so we always have the original
++   * state to go back to.
++   */
++  if (tcgetattr (STDIN_FILENO, &old_termios) == -1) {
++    perror ("tcgetattr: stdin");
++    exit (EXIT_FAILURE);
++  }
++
++  /* Put stdin in raw mode so that we can receive ^C and other
++   * special keys.
++   */
++  raw_tty ();
++
++  /* Restore the tty settings when the process exits. */
++  atexit (restore_tty);
++
++  /* Catch tty stop and cont signals so we can cleanup.
++   * See https://www.gnu.org/software/libc/manual/html_node/Signaling-Yourself.html
+    */
+-  ignore_value (guestfs_launch (g));
++  signal (SIGTSTP, tstp_handler);
++  signal (SIGCONT, cont_handler);
++
++  do_rescue (sock);
++
++  restore_tty ();
++
++  /* Shut down the appliance. */
++  guestfs_push_error_handler (g, NULL, NULL);
++  if (guestfs_shutdown (g) == -1) {
++    const char *err;
++
++    /* Ignore "appliance closed the connection unexpectedly" since
++     * this can happen if the user reboots the appliance.
++     */
++    if (guestfs_last_errno (g) == EPIPE)
++      goto next;
+ 
++    /* Otherwise it's a real error. */
++    err = guestfs_last_error (g);
++    fprintf (stderr, "libguestfs: error: %s\n", err);
++    exit (EXIT_FAILURE);
++  }
++ next:
++  guestfs_pop_error_handler (g);
+   guestfs_close (g);
+ 
+   exit (EXIT_SUCCESS);
+ }
+ 
++static void
++log_message_callback (guestfs_h *g, void *opaque, uint64_t event,
++                      int event_handle, int flags,
++                      const char *buf, size_t buf_len,
++                      const uint64_t *array, size_t array_len)
++{
++  if (buf_len > 0) {
++    ignore_value (full_write (STDOUT_FILENO, buf, buf_len));
++  }
++}
++
++/* This is the main loop for virt-rescue.  We read and write
++ * directly to the console socket.
++ */
++#define BUFSIZE 4096
++static char rbuf[BUFSIZE];      /* appliance -> local tty */
++static char wbuf[BUFSIZE];      /* local tty -> appliance */
++
++static void
++do_rescue (int sock)
++{
++  size_t rlen = 0;
++  size_t wlen = 0;
++
++  while (sock >= 0 || rlen > 0) {
++    struct pollfd fds[3];
++    nfds_t nfds = 2;
++    int r;
++    ssize_t n;
++
++    fds[0].fd = STDIN_FILENO;
++    fds[0].events = 0;
++    if (BUFSIZE-wlen > 0)
++      fds[0].events = POLLIN;
++    fds[0].revents = 0;
++
++    fds[1].fd = STDOUT_FILENO;
++    fds[1].events = 0;
++    if (rlen > 0)
++      fds[1].events |= POLLOUT;
++    fds[1].revents = 0;
++
++    if (sock >= 0) {
++      fds[2].fd = sock;
++      fds[2].events = 0;
++      if (BUFSIZE-rlen > 0)
++        fds[2].events |= POLLIN;
++      if (wlen > 0)
++        fds[2].events |= POLLOUT;
++      fds[2].revents = 0;
++      nfds++;
++    }
++
++    r = poll (fds, nfds, -1);
++    if (r == -1) {
++      if (errno == EINTR || errno == EAGAIN)
++        continue;
++      perror ("poll");
++      return;
++    }
++
++    /* Input from local tty. */
++    if ((fds[0].revents & POLLIN) != 0) {
++      assert (BUFSIZE-wlen > 0);
++      n = read (STDIN_FILENO, wbuf+wlen, BUFSIZE-wlen);
++      if (n == -1) {
++        if (errno == EINTR || errno == EAGAIN)
++          continue;
++        perror ("read");
++        return;
++      }
++      if (n == 0) {
++        /* We don't expect this to happen.  Maybe the whole tty went away?
++         * Anyway, we should exit as soon as possible.
++         */
++        return;
++      }
++      if (n > 0)
++        wlen += n;
++    }
++
++    /* Log message from appliance. */
++    if (nfds > 2 && (fds[2].revents & POLLIN) != 0) {
++      assert (BUFSIZE-rlen > 0);
++      n = read (sock, rbuf+rlen, BUFSIZE-rlen);
++      if (n == -1) {
++        if (errno == EINTR || errno == EAGAIN)
++          continue;
++        if (errno == ECONNRESET)
++          goto appliance_closed;
++        perror ("read");
++        return;
++      }
++      if (n == 0) {
++      appliance_closed:
++        sock = -1;
++        /* Don't actually close the socket, because it's owned by
++         * the guestfs handle.
++         */
++        continue;
++      }
++      if (n > 0)
++        rlen += n;
++    }
++
++    /* Write log messages to local tty. */
++    if ((fds[1].revents & POLLOUT) != 0) {
++      assert (rlen > 0);
++      n = write (STDOUT_FILENO, rbuf, rlen);
++      if (n == -1) {
++        perror ("write");
++        continue;
++      }
++      rlen -= n;
++      memmove (rbuf, rbuf+n, rlen);
++    }
++
++    /* Write commands to the appliance. */
++    if (nfds > 2 && (fds[2].revents & POLLOUT) != 0) {
++      assert (wlen > 0);
++      n = write (sock, wbuf, wlen);
++      if (n == -1) {
++        perror ("write");
++        continue;
++      }
++      wlen -= n;
++      memmove (wbuf, wbuf+n, wlen);
++    }
++  }
++}
++
++/* Put the tty in raw mode. */
++static void
++raw_tty (void)
++{
++  struct termios termios;
++
++  if (tcgetattr (STDIN_FILENO, &termios) == -1) {
++    perror ("tcgetattr: stdin");
++    exit (EXIT_FAILURE);
++  }
++  cfmakeraw (&termios);
++  if (tcsetattr (STDIN_FILENO, TCSANOW, &termios) == -1) {
++    perror ("tcsetattr: stdin");
++    exit (EXIT_FAILURE);
++  }
++}
++
++/* Restore the tty to (presumably) cooked mode as it was when
++ * the program was started.
++ */
++static void
++restore_tty (void)
++{
++  tcsetattr (STDIN_FILENO, TCSANOW, &old_termios);
++}
++
++/* When we get SIGTSTP, switch back to cooked mode. */
++static void
++tstp_handler (int sig)
++{
++  restore_tty ();
++  signal (SIGTSTP, SIG_DFL);
++  raise (SIGTSTP);
++}
++
++/* When we get SIGCONF, switch to raw mode. */
++static void
++cont_handler (int sig)
++{
++  raw_tty ();
++}
++
+ static void suggest_filesystems (void);
+ 
+ static int
+-- 
+2.14.3
+
diff --git a/SOURCES/0057-rescue-Implement-m-and-i-options.patch b/SOURCES/0057-rescue-Implement-m-and-i-options.patch
new file mode 100644
index 0000000..cc57d7f
--- /dev/null
+++ b/SOURCES/0057-rescue-Implement-m-and-i-options.patch
@@ -0,0 +1,400 @@
+From 5b0f9d72d49053d246463b7bb024f21f1c24d983 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 3 Mar 2017 13:52:31 +0000
+Subject: [PATCH] rescue: Implement -m and -i options.
+
+`virt-rescue -a disk -i' does the right thing.
+
+`-m' was previously an alternate form of `--memsize'.  By sniffing the
+parameter we can make `-m MB' continue to work, while also allowing
+`-m' to be used as a short form for the `--mount' option.
+
+This also removes most of the description of `--suggest' from the man
+page, since it is no longer needed.
+
+(cherry picked from commit 33d2ae796119ae5dd38e2afcbf1ba4216bd99846)
+---
+ appliance/init         | 12 +++++--
+ rescue/Makefile.am     |  3 +-
+ rescue/rescue.c        | 87 +++++++++++++++++++++++++++++++++++++-------------
+ rescue/virt-rescue.pod | 80 ++++++++++++++++++++++++++++------------------
+ 4 files changed, 126 insertions(+), 56 deletions(-)
+
+diff --git a/appliance/init b/appliance/init
+index ea763c2d3..4133de434 100755
+--- a/appliance/init
++++ b/appliance/init
+@@ -181,6 +181,10 @@ else
+     # We need a daemon, even in virt-rescue.
+     $cmd &
+ 
++    # XXX This gives a bit of time for virt-rescue to connect to the
++    # daemon and mount any filesystems.
++    sleep 2
++
+     # Get name of the serial port, from console= passed by libguestfs.
+     # XXX Consider using /proc/consoles
+     guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline |
+@@ -210,8 +214,12 @@ else
+     echo "Welcome to virt-rescue, the libguestfs rescue shell."
+     echo
+     echo "Note: The contents of / (root) are the rescue appliance."
+-    echo "You have to mount the guest's partitions under /sysroot"
+-    echo "before you can examine them."
++    if ! test -d "/sysroot/dev"; then
++        echo "You have to mount the guest's partitions under /sysroot"
++        echo "before you can examine them."
++    else
++        echo "Use 'cd /sysroot' or 'chroot /sysroot' to see guest filesystems."
++    fi
+     echo
+     run_bash_with_ctty
+     echo
+diff --git a/rescue/Makefile.am b/rescue/Makefile.am
+index 99d4b79ae..c83c43458 100644
+--- a/rescue/Makefile.am
++++ b/rescue/Makefile.am
+@@ -35,7 +35,7 @@ virt_rescue_CPPFLAGS = \
+ 	-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
+ 	-I$(top_srcdir)/lib -I$(top_builddir)/lib \
+ 	-I$(top_srcdir)/common/options -I$(top_builddir)/common/options \
+-	-I$(top_srcdir)/fish \
++	-I$(top_srcdir)/common/windows -I$(top_builddir)/common/windows \
+ 	-I$(srcdir)/../gnulib/lib -I../gnulib/lib
+ 
+ virt_rescue_CFLAGS = \
+@@ -43,6 +43,7 @@ virt_rescue_CFLAGS = \
+ 	$(LIBXML2_CFLAGS)
+ 
+ virt_rescue_LDADD = \
++	$(top_builddir)/common/windows/libwindows.la \
+ 	$(top_builddir)/common/options/liboptions.la \
+ 	$(top_builddir)/common/utils/libutils.la \
+ 	$(top_builddir)/lib/libguestfs.la \
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index b145dcd40..2b461378d 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -23,7 +23,6 @@
+ #include <string.h>
+ #include <inttypes.h>
+ #include <unistd.h>
+-#include <fcntl.h>
+ #include <getopt.h>
+ #include <errno.h>
+ #include <error.h>
+@@ -37,9 +36,11 @@
+ #include "full-write.h"
+ #include "getprogname.h"
+ #include "ignore-value.h"
++#include "nonblocking.h"
+ #include "xvasprintf.h"
+ 
+ #include "guestfs.h"
++#include "windows.h"
+ #include "options.h"
+ #include "display-options.h"
+ 
+@@ -87,7 +88,9 @@ usage (int status)
+               "  -d|--domain guest    Add disks from libvirt guest\n"
+               "  --format[=raw|..]    Force disk format for -a option\n"
+               "  --help               Display brief help\n"
+-              "  -m|--memsize MB      Set memory size in megabytes\n"
++              "  -i|--inspector       Automatically mount filesystems\n"
++              "  -m|--mount dev[:mnt[:opts[:fstype]] Mount dev on mnt (if omitted, /)\n"
++              "  --memsize MB         Set memory size in megabytes\n"
+               "  --network            Enable network\n"
+               "  -r|--ro              Access read-only\n"
+               "  --scratch[=N]        Add scratch disk(s)\n"
+@@ -116,7 +119,7 @@ main (int argc, char *argv[])
+ 
+   enum { HELP_OPTION = CHAR_MAX + 1 };
+ 
+-  static const char options[] = "a:c:d:m:rvVwx";
++  static const char options[] = "a:c:d:im:rvVwx";
+   static const struct option long_options[] = {
+     { "add", 1, 0, 'a' },
+     { "append", 1, 0, 0 },
+@@ -124,8 +127,10 @@ main (int argc, char *argv[])
+     { "domain", 1, 0, 'd' },
+     { "format", 2, 0, 0 },
+     { "help", 0, 0, HELP_OPTION },
++    { "inspector", 0, 0, 'i' },
+     { "long-options", 0, 0, 0 },
+-    { "memsize", 1, 0, 'm' },
++    { "mount", 1, 0, 'm' },
++    { "memsize", 1, 0, 0 },
+     { "network", 0, 0, 0 },
+     { "ro", 0, 0, 'r' },
+     { "rw", 0, 0, 'w' },
+@@ -140,13 +145,16 @@ main (int argc, char *argv[])
+   };
+   struct drv *drvs = NULL;
+   struct drv *drv;
++  struct mp *mps = NULL;
++  struct mp *mp;
++  char *p;
+   const char *format = NULL;
+   bool format_consumed = true;
+   int c;
+   int option_index;
+   int network = 0;
+   const char *append = NULL;
+-  int memsize = 0;
++  int memsize = 0, m;
+   int smp = 0;
+   int suggest = 0;
+   char *append_full;
+@@ -196,6 +204,10 @@ main (int argc, char *argv[])
+                    _("--scratch parameter '%s' should be >= 1"), optarg);
+           add_scratch_disks (n, &drvs);
+         }
++      } else if (STREQ (long_options[option_index].name, "memsize")) {
++        if (sscanf (optarg, "%d", &memsize) != 1)
++          error (EXIT_FAILURE, 0,
++                 _("could not parse memory size '%s'"), optarg);
+       } else
+         error (EXIT_FAILURE, 0,
+                _("unknown long option: %s (%d)"),
+@@ -214,10 +226,19 @@ main (int argc, char *argv[])
+       OPTION_d;
+       break;
+ 
++    case 'i':
++      OPTION_i;
++      break;
++
+     case 'm':
+-      if (sscanf (optarg, "%d", &memsize) != 1)
+-        error (EXIT_FAILURE, 0,
+-               _("could not parse memory size '%s'"), optarg);
++      /* For backwards compatibility with virt-rescue <= 1.36, we
++       * must handle -m <number> as a synonym for --memsize.
++       */
++      if (sscanf (optarg, "%d", &m) == 1)
++        memsize = m;
++      else {
++        OPTION_m;
++      }
+       break;
+ 
+     case 'r':
+@@ -288,7 +309,6 @@ main (int argc, char *argv[])
+    * options parsing code.  Assert here that they have known-good
+    * values.
+    */
+-  assert (inspector == 0);
+   assert (keys_from_stdin == 0);
+   assert (echo_keys == 0);
+   assert (live == 0);
+@@ -332,12 +352,6 @@ main (int argc, char *argv[])
+     exit (EXIT_FAILURE);
+   free (append_full);
+ 
+-  /* Add drives. */
+-  add_drives (drvs);
+-
+-  /* Free up data structures, no longer needed after this point. */
+-  free_drives (drvs);
+-
+   /* Add an event handler to print "log messages".  These will be the
+    * output of the appliance console during launch and shutdown.
+    * After launch, we will read the console messages directly from the
+@@ -347,21 +361,50 @@ main (int argc, char *argv[])
+                                   GUESTFS_EVENT_APPLIANCE, 0, NULL) == -1)
+     exit (EXIT_FAILURE);
+ 
+-  /* Run the appliance. */
++  /* Do the guest drives and mountpoints. */
++  add_drives (drvs);
+   if (guestfs_launch (g) == -1)
+     exit (EXIT_FAILURE);
++  if (inspector)
++    inspect_mount ();
++  mount_mps (mps);
++
++  free_drives (drvs);
++  free_mps (mps);
++
++  /* Also bind-mount /dev etc under /sysroot, if -i was given. */
++  if (inspector) {
++    CLEANUP_FREE_STRING_LIST char **roots;
++    int windows;
++
++    roots = guestfs_inspect_get_roots (g);
++    windows = roots && roots[0] && is_windows (g, roots[0]);
++    if (!windows) {
++      const char *cmd[5] = { "mount", "--rbind", NULL, NULL, NULL };
++      char *r;
++
++      cmd[2] = "/dev"; cmd[3] = "/sysroot/dev";
++      r = guestfs_debug (g, "sh", (char **) cmd);
++      free (r);
++
++      cmd[2] = "/proc"; cmd[3] = "/sysroot/proc";
++      r = guestfs_debug (g, "sh", (char **) cmd);
++      free (r);
++
++      cmd[2] = "/sys"; cmd[3] = "/sysroot/sys";
++      r = guestfs_debug (g, "sh", (char **) cmd);
++      free (r);
++    }
++  }
+ 
+   sock = guestfs_internal_get_console_socket (g);
+   if (sock == -1)
+     exit (EXIT_FAILURE);
+ 
+   /* Try to set all sockets to non-blocking. */
+-  if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
+-    perror ("could not set stdin to non-blocking");
+-  if (fcntl (STDOUT_FILENO, F_SETFL, O_NONBLOCK) == -1)
+-    perror ("could not set stdout to non-blocking");
+-  if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1)
+-    perror ("could not set console socket to non-blocking");
++  ignore_value (set_nonblocking_flag (STDIN_FILENO, 1));
++  ignore_value (set_nonblocking_flag (STDOUT_FILENO, 1));
++  ignore_value (set_nonblocking_flag (sock, 1));
+ 
+   /* Save the initial state of the tty so we always have the original
+    * state to go back to.
+diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
+index b8aa32637..b651f84e7 100644
+--- a/rescue/virt-rescue.pod
++++ b/rescue/virt-rescue.pod
+@@ -6,9 +6,7 @@ virt-rescue - Run a rescue shell on a virtual machine
+ 
+  virt-rescue [--options] -d domname
+ 
+- virt-rescue [--options] -a disk.img [-a disk.img ...]
+-
+- virt-rescue --suggest (-d domname | -a disk.img ...)
++ virt-rescue [--options] -a disk.img [-a disk.img ...] [-i]
+ 
+ Old style:
+ 
+@@ -26,13 +24,13 @@ machine or disk image.
+ You can run virt-rescue on any virtual machine known to libvirt, or
+ directly on disk image(s):
+ 
+- virt-rescue -d GuestName
++ virt-rescue -d GuestName -i
+ 
+- virt-rescue --ro -a /path/to/disk.img
++ virt-rescue --ro -a /path/to/disk.img -i
+ 
+  virt-rescue -a /dev/sdc
+ 
+-For live VMs you I<must> use the --ro option.
++For live VMs you I<must> use the I<--ro> option.
+ 
+ When you run virt-rescue on a virtual machine or disk image, you are
+ placed in an interactive bash shell where you can use many ordinary
+@@ -41,26 +39,10 @@ rescue appliance.  You must mount the virtual machine's filesystems by
+ hand.  There is an empty directory called F</sysroot> where you can
+ mount filesystems.
+ 
+-You can get virt-rescue to suggest mount commands for you by using the
+-I<--suggest> option (in another terminal):
+-
+- $ virt-rescue --suggest -d Fedora15
+- Inspecting the virtual machine or disk image ...
+- 
+- This disk contains one or more operating systems.  You can use these
+- mount commands in virt-rescue (at the ><rescue> prompt) to mount the
+- filesystems.
+- 
+- # /dev/vg_f15x32/lv_root is the root of a linux operating system
+- # type: linux, distro: fedora, version: 15.0
+- # Fedora release 15 (Lovelock)
+- 
+- mount /dev/vg_f15x32/lv_root /sysroot/
+- mount /dev/vda1 /sysroot/boot
+- mount --bind /dev /sysroot/dev
+- mount --bind /dev/pts /sysroot/dev/pts
+- mount --bind /proc /sysroot/proc
+- mount --bind /sys /sysroot/sys
++To automatically mount the virtual machine's filesystems under
++F</sysroot> use the I<-i> option.  This uses libguestfs inspection to
++find the filesystems and mount them in the right place.  You can also
++mount filesystems individually using the I<-m> option.
+ 
+ Another way is to list the logical volumes (with L<lvs(8)>) and
+ partitions (with L<parted(8)>) and mount them by hand:
+@@ -170,7 +152,15 @@ If you have untrusted raw-format guest disk images, you should use
+ this option to specify the disk format.  This avoids a possible
+ security problem with malicious guests (CVE-2010-3851).
+ 
+-=item B<-m> MB
++=item B<-i>
++
++=item B<--inspector>
++
++Using L<virt-inspector(1)> code, inspect the disks looking for
++an operating system and mount filesystems as they would be
++mounted on the real virtual machine.
++
++The filesystems are mounted on F</sysroot> in the rescue environment.
+ 
+ =item B<--memsize> MB
+ 
+@@ -179,6 +169,33 @@ default is set by libguestfs and is small but adequate for running
+ system tools.  The occasional program might need more memory.  The
+ parameter is specified in megabytes.
+ 
++=item B<-m> dev[:mountpoint[:options[:fstype]]]
++
++=item B<--mount> dev[:mountpoint[:options[:fstype]]]
++
++Mount the named partition or logical volume on the given mountpoint
++B<in the guest> (this has nothing to do with mountpoints in the host).
++
++If the mountpoint is omitted, it defaults to F</>.  You have to mount
++something on F</>.
++
++The filesystems are mounted under F</sysroot> in the rescue environment.
++
++The third (and rarely used) part of the mount parameter is the list of
++mount options used to mount the underlying filesystem.  If this is not
++given, then the mount options are either the empty string or C<ro>
++(the latter if the I<--ro> flag is used).  By specifying the mount
++options, you override this default choice.  Probably the only time you
++would use this is to enable ACLs and/or extended attributes if the
++filesystem can support them:
++
++ -m /dev/sda1:/:acl,user_xattr
++
++The fourth part of the parameter is the filesystem driver to use, such
++as C<ext3> or C<ntfs>. This is rarely needed, but can be useful if
++multiple drivers are valid for a filesystem (eg: C<ext2> and C<ext3>),
++or if libguestfs misidentifies a filesystem.
++
+ =item B<--network>
+ 
+ Enable QEMU user networking in the guest.  See L</NETWORK>.
+@@ -217,9 +234,10 @@ Enable N E<ge> 2 virtual CPUs in the rescue appliance.
+ 
+ =item B<--suggest>
+ 
+-Inspect the disk image and suggest what mount commands should be used
+-to mount the disks.  You should use the I<--suggest> option in a
+-second terminal, then paste the commands into another virt-rescue.
++This option was used in older versions of virt-rescue to suggest what
++commands you could use to mount filesystems under F</sysroot>.  For
++the current version of virt-rescue, it is easier to use the I<-i>
++option instead.
+ 
+ This option implies I<--ro> and is safe to use even if the guest is up
+ or if another virt-rescue is running.
+@@ -240,7 +258,7 @@ Display version number and exit.
+ 
+ =item B<--rw>
+ 
+-This changes the I<-a> and I<-d> options so that disks are
++This changes the I<-a>, I<-d> and I<-m> options so that disks are
+ added and mounts are done read-write.
+ 
+ See L<guestfish(1)/OPENING DISKS FOR READ AND WRITE>.
+-- 
+2.14.3
+
diff --git a/SOURCES/0058-rescue-Implement-escape-sequences.patch b/SOURCES/0058-rescue-Implement-escape-sequences.patch
new file mode 100644
index 0000000..4c00900
--- /dev/null
+++ b/SOURCES/0058-rescue-Implement-escape-sequences.patch
@@ -0,0 +1,615 @@
+From 50e044064b4388f11912d96d2eb52aea1b292734 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Sat, 4 Mar 2017 11:47:59 +0000
+Subject: [PATCH] rescue: Implement escape sequences.
+
+This implements a few useful escape sequences:
+
+><rescue> ^]?
+virt-rescue escape sequences:
+ ^] ? - print this message
+ ^] h - print this message
+ ^] q - quit virt-rescue
+ ^] s - sync the filesystems
+ ^] u - unmount filesystems
+ ^] x - quit virt-rescue
+ ^] z - suspend virt-rescue
+to pass the escape key through to the rescue shell, type it twice
+
+^]i
+
+root device: /dev/sda3
+  product name: Fedora 25 (Twenty Five)
+  type: linux
+  distro: fedora
+
+^]z
+[3]+  Stopped                 ./run virt-rescue --scratch
+$ fg
+
+><rescue> ^]u
+
+unmounting filesystems ...
+[   21.158558] XFS (sda3): Unmounting Filesystem
+
+(cherry picked from commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54)
+---
+ rescue/Makefile.am     |   4 +-
+ rescue/escape.c        | 302 +++++++++++++++++++++++++++++++++++++++++++++++++
+ rescue/rescue.c        |  30 ++++-
+ rescue/rescue.h        |  47 ++++++++
+ rescue/virt-rescue.pod |  74 ++++++++++++
+ 5 files changed, 454 insertions(+), 3 deletions(-)
+ create mode 100644 rescue/escape.c
+ create mode 100644 rescue/rescue.h
+
+diff --git a/rescue/Makefile.am b/rescue/Makefile.am
+index c83c43458..eb60bafa4 100644
+--- a/rescue/Makefile.am
++++ b/rescue/Makefile.am
+@@ -26,7 +26,9 @@ EXTRA_DIST = \
+ bin_PROGRAMS = virt-rescue
+ 
+ virt_rescue_SOURCES = \
+-	rescue.c
++	escape.c \
++	rescue.c \
++	rescue.h
+ 
+ virt_rescue_CPPFLAGS = \
+ 	-DGUESTFS_WARN_DEPRECATED=1 \
+diff --git a/rescue/escape.c b/rescue/escape.c
+new file mode 100644
+index 000000000..f7f7d84c4
+--- /dev/null
++++ b/rescue/escape.c
+@@ -0,0 +1,302 @@
++/* virt-rescue
++ * Copyright (C) 2010-2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <string.h>
++#include <unistd.h>
++#include <signal.h>
++#include <locale.h>
++#include <libintl.h>
++
++#include "c-ctype.h"
++
++#include "guestfs.h"
++#include "guestfs-internal-frontend.h"
++
++#include "rescue.h"
++
++static void print_help (void);
++static void print_inspector (void);
++static void crlf (void);
++static void print_escape_key (void);
++
++/* Parse the -e parameter from the command line. */
++int
++parse_escape_key (const char *arg)
++{
++  size_t len;
++
++  if (STREQ (arg, "none"))
++    return 0;
++
++  len = strlen (arg);
++  if (arg == 0)
++    return -1;
++
++  switch (arg[0]) {
++  case '^':
++    if (len == 2 &&
++        ((arg[1] >= 'a' && arg[1] <= 'z') ||
++         (arg[1] >= 'A' && arg[1] <= '_'))) {
++      return c_toupper (arg[1]) - '@';
++    }
++    else
++      return -1;
++    break;
++  }
++
++  return -1;
++}
++
++/* Print one-line end user description of the escape key.
++ *
++ * This is printed when virt-rescue starts.
++ */
++void
++print_escape_key_help (void)
++{
++  crlf ();
++  /* Difficult to translate this string. XXX */
++  printf ("The virt-rescue escape key is ‘");
++  print_escape_key ();
++  printf ("’.  Type ‘");
++  print_escape_key ();
++  printf (" h’ for help.");
++  crlf ();
++}
++
++void
++init_escape_state (struct escape_state *state)
++{
++  state->in_escape = false;
++}
++
++/* Process escapes in the tty input buffer.
++ *
++ * This function has a state parameter so that we can handle an escape
++ * sequence split over the end of the buffer.
++ *
++ * Escape sequences are removed from the buffer.
++ *
++ * Returns true iff virt-rescue should exit.
++ */
++bool
++process_escapes (struct escape_state *state, char *buf, size_t *len)
++{
++  size_t i;
++
++  for (i = 0; i < *len; ++i) {
++#define DROP_CURRENT_CHAR() \
++    memmove (&buf[i], &buf[i+1], --(*len))
++#define PRINT_ESC() \
++    do { print_escape_key (); putchar (buf[i]); crlf (); } while (0)
++
++    if (!state->in_escape) {
++      if (buf[i] == escape_key) {
++        /* Drop the escape key from the buffer and go to escape mode. */
++        DROP_CURRENT_CHAR ();
++        state->in_escape = true;
++      }
++    }
++    else /* in escape sequence */ {
++      if (buf[i] == escape_key) /* ^] ^] means send ^] to rescue shell */
++        state->in_escape = false;
++      else {
++        switch (buf[i]) {
++        case '?': case 'h':
++          PRINT_ESC ();
++          print_help ();
++          break;
++
++        case 'i':
++          PRINT_ESC ();
++          print_inspector ();
++          break;
++
++        case 'q': case 'x':
++          PRINT_ESC ();
++          return true /* exit virt-rescue at once */;
++
++        case 's':
++          PRINT_ESC ();
++          printf (_("attempting to sync filesystems ..."));
++          crlf ();
++          guestfs_sync (g);
++          break;
++
++        case 'u':
++          PRINT_ESC ();
++          printf (_("unmounting filesystems ..."));
++          crlf ();
++          guestfs_umount_all (g);
++          break;
++
++        case 'z':
++          PRINT_ESC ();
++          raise (SIGTSTP);
++          break;
++
++        default:
++          /* Any unrecognized escape sequence will be dropped.  We
++           * could be obnoxious and ring the bell, but I hate it when
++           * programs do that.
++           */
++          break;
++        }
++
++        /* Drop the escape key and return to non-escape mode. */
++        DROP_CURRENT_CHAR ();
++        state->in_escape = false;
++
++        /* The output is line buffered, this is just to make sure
++         * everything gets written to stdout before we continue
++         * writing to STDOUT_FILENO.
++         */
++        fflush (stdout);
++      }
++    } /* in escape sequence */
++  } /* for */
++
++  return false /* don't exit */;
++}
++
++/* This is called when the user types ^] h */
++static void
++print_help (void)
++{
++  printf (_("virt-rescue escape sequences:"));
++  crlf ();
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" ? - print this message"));
++  crlf ();
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" h - print this message"));
++  crlf ();
++
++  if (inspector) {
++    putchar (' ');
++    print_escape_key ();
++    printf (_(" i - print inspection data"));
++    crlf ();
++  }
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" q - quit virt-rescue"));
++  crlf ();
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" s - sync the filesystems"));
++  crlf ();
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" u - unmount filesystems"));
++  crlf ();
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" x - quit virt-rescue"));
++  crlf ();
++
++  putchar (' ');
++  print_escape_key ();
++  printf (_(" z - suspend virt-rescue"));
++  crlf ();
++
++  printf (_("to pass the escape key through to the rescue shell, type it twice"));
++  crlf ();
++}
++
++/* This is called when the user types ^] i */
++static void
++print_inspector (void)
++{
++  CLEANUP_FREE_STRING_LIST char **roots;
++  size_t i;
++  const char *root;
++  char *str;
++
++  if (inspector) {
++    roots = guestfs_inspect_get_roots (g);
++    if (roots) {
++      crlf ();
++      for (i = 0; roots[i] != NULL; ++i) {
++        root = roots[i];
++        printf (_("root device: %s"), root);
++        crlf ();
++
++        str = guestfs_inspect_get_product_name (g, root);
++        if (str) {
++          printf (_("  product name: %s"), str);
++          crlf ();
++        }
++        free (str);
++
++        str = guestfs_inspect_get_type (g, root);
++        if (str) {
++          printf (_("  type: %s"), str);
++          crlf ();
++        }
++        free (str);
++
++        str = guestfs_inspect_get_distro (g, root);
++        if (str) {
++          printf (_("  distro: %s"), str);
++          crlf ();
++        }
++        free (str);
++      }
++    }
++  }
++}
++
++/* Because the terminal is in raw mode, we have to send CR LF instead
++ * of printing just \n.
++ */
++static void
++crlf (void)
++{
++  putchar ('\r');
++  putchar ('\n');
++}
++
++static void
++print_escape_key (void)
++{
++  switch (escape_key) {
++  case 0:
++    printf ("none");
++    break;
++  case '\x1'...'\x1f':
++    putchar ('^');
++    putchar (escape_key + '@');
++    break;
++  default:
++    abort ();
++  }
++}
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index 2b461378d..5281b1161 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -1,5 +1,5 @@
+ /* virt-rescue
+- * Copyright (C) 2010-2012 Red Hat Inc.
++ * Copyright (C) 2010-2017 Red Hat Inc.
+  *
+  * 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
+@@ -40,10 +40,14 @@
+ #include "xvasprintf.h"
+ 
+ #include "guestfs.h"
++#include "guestfs-internal-frontend.h"
++
+ #include "windows.h"
+ #include "options.h"
+ #include "display-options.h"
+ 
++#include "rescue.h"
++
+ static void log_message_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);
+ static void do_rescue (int sock);
+ static void raw_tty (void);
+@@ -65,6 +69,7 @@ const char *libvirt_uri = NULL;
+ int inspector = 0;
+ int in_guestfish = 0;
+ int in_virt_rescue = 1;
++int escape_key = '\x1d';        /* ^] */
+ 
+ /* Old terminal settings. */
+ static struct termios old_termios;
+@@ -86,6 +91,7 @@ usage (int status)
+               "  --append kernelopts  Append kernel options\n"
+               "  -c|--connect uri     Specify libvirt URI for -d option\n"
+               "  -d|--domain guest    Add disks from libvirt guest\n"
++              "  -e ^x|none           Set or disable escape key (default ^])\n"
+               "  --format[=raw|..]    Force disk format for -a option\n"
+               "  --help               Display brief help\n"
+               "  -i|--inspector       Automatically mount filesystems\n"
+@@ -119,7 +125,7 @@ main (int argc, char *argv[])
+ 
+   enum { HELP_OPTION = CHAR_MAX + 1 };
+ 
+-  static const char options[] = "a:c:d:im:rvVwx";
++  static const char options[] = "a:c:d:e:im:rvVwx";
+   static const struct option long_options[] = {
+     { "add", 1, 0, 'a' },
+     { "append", 1, 0, 0 },
+@@ -226,6 +232,12 @@ main (int argc, char *argv[])
+       OPTION_d;
+       break;
+ 
++    case 'e':
++      escape_key = parse_escape_key (optarg);
++      if (escape_key == -1)
++        error (EXIT_FAILURE, 0, _("unrecognized escape key: %s"), optarg);
++      break;
++
+     case 'i':
+       OPTION_i;
+       break;
+@@ -428,6 +440,10 @@ main (int argc, char *argv[])
+   signal (SIGTSTP, tstp_handler);
+   signal (SIGCONT, cont_handler);
+ 
++  /* Print the escape key if set. */
++  if (escape_key > 0)
++    print_escape_key_help ();
++
+   do_rescue (sock);
+ 
+   restore_tty ();
+@@ -478,6 +494,9 @@ do_rescue (int sock)
+ {
+   size_t rlen = 0;
+   size_t wlen = 0;
++  struct escape_state escape_state;
++
++  init_escape_state (&escape_state);
+ 
+   while (sock >= 0 || rlen > 0) {
+     struct pollfd fds[3];
+@@ -534,6 +553,13 @@ do_rescue (int sock)
+       }
+       if (n > 0)
+         wlen += n;
++
++      /* Process escape sequences in the tty input.  If the function
++       * returns true, then we exit the loop causing virt-rescue to
++       * exit.
++       */
++      if (escape_key > 0 && process_escapes (&escape_state, wbuf, &wlen))
++        return;
+     }
+ 
+     /* Log message from appliance. */
+diff --git a/rescue/rescue.h b/rescue/rescue.h
+new file mode 100644
+index 000000000..ccffb5eb3
+--- /dev/null
++++ b/rescue/rescue.h
+@@ -0,0 +1,47 @@
++/* virt-rescue
++ * Copyright (C) 2010-2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#ifndef RESCUE_H
++#define RESCUE_H
++
++#include <stdbool.h>
++
++#include "guestfs.h"
++
++extern guestfs_h *g;
++extern int read_only;
++extern int live;
++extern int verbose;
++extern int keys_from_stdin;
++extern int echo_keys;
++extern const char *libvirt_uri;
++extern int inspector;
++extern int in_guestfish;
++extern int in_virt_rescue;
++extern int escape_key;
++
++/* escape.c */
++struct escape_state {
++  bool in_escape;
++};
++extern void init_escape_state (struct escape_state *state);
++extern bool process_escapes (struct escape_state *state, char *buf, size_t *len);
++extern int parse_escape_key (const char *);
++extern void print_escape_key_help (void);
++
++#endif /* RESCUE_H */
+diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
+index b651f84e7..bd6f954e9 100644
+--- a/rescue/virt-rescue.pod
++++ b/rescue/virt-rescue.pod
+@@ -128,6 +128,29 @@ not used at all.
+ Add all the disks from the named libvirt guest.  Domain UUIDs can be
+ used instead of names.
+ 
++=item B<-e none>
++
++Disable the escape key.
++
++=item B<-e> KEY
++
++Set the escape key to the given key sequence.  The default is C<^]>.
++To specify the escape key you can use:
++
++=over 4
++
++=item C<^x>
++
++Control key + C<x> key.
++
++=item C<none>
++
++I<-e none> means there is no escape key, escapes are disabled.
++
++=back
++
++See L</ESCAPE KEY> below for further information.
++
+ =item B<--format=raw|qcow2|..>
+ 
+ =item B<--format>
+@@ -321,6 +344,57 @@ See L<bash(1)> for more details.
+ 
+ =back
+ 
++=head1 ESCAPE KEY
++
++Virt-rescue supports various keyboard escape sequences which are
++entered by pressing C<^]> (Control key + C<]> key).
++
++You can change the escape key using the I<-e> option on the command
++line (see above), and you can disable escapes completely using
++I<-e none>.  The rest of this section assumes the default escape key.
++
++The following escapes can be used:
++
++=over 4
++
++=item C<^] ?>
++
++=item C<^] h>
++
++Prints a brief help text about escape sequences.
++
++=item C<^] i>
++
++Prints brief libguestfs inspection information for the guest.  This
++only works if you used I<-i> on the virt-rescue command line.
++
++=item C<^] q>
++
++=item C<^] x>
++
++Quits virt-rescue immediately.
++
++=item C<^] s>
++
++Synchronize the filesystems (sync).
++
++=item C<^] u>
++
++Unmounts all the filesystems, except for the root (appliance)
++filesystems.
++
++=item C<^] z>
++
++Suspend virt-rescue (like pressing C<^Z> except that it affects
++virt-rescue rather than the program inside the rescue shell).
++
++=item C<^] ^]>
++
++Sends the literal character C<^]> (ASCII 0x1d) through to the rescue
++shell.
++
++=back
++
+ =head1 CAPTURING CORE DUMPS
+ 
+ If you are testing a tool inside virt-rescue and the tool (B<not>
+-- 
+2.14.3
+
diff --git a/SOURCES/0059-rescue-Move-suggest-code-to-separate-file.patch b/SOURCES/0059-rescue-Move-suggest-code-to-separate-file.patch
new file mode 100644
index 0000000..00585e9
--- /dev/null
+++ b/SOURCES/0059-rescue-Move-suggest-code-to-separate-file.patch
@@ -0,0 +1,397 @@
+From 0a3e771414378057d0e838c6a45d2f840ff7a8af Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Sat, 4 Mar 2017 15:35:09 +0000
+Subject: [PATCH] rescue: Move --suggest code to separate file.
+
+Just code motion.
+
+(cherry picked from commit 5ea17e97e4413c3db4449ded72b9677cce09444f)
+---
+ rescue/Makefile.am |   3 +-
+ rescue/rescue.c    | 144 -------------------------------------------
+ rescue/rescue.h    |   5 ++
+ rescue/suggest.c   | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 182 insertions(+), 145 deletions(-)
+ create mode 100644 rescue/suggest.c
+
+diff --git a/rescue/Makefile.am b/rescue/Makefile.am
+index eb60bafa4..d478c8e3d 100644
+--- a/rescue/Makefile.am
++++ b/rescue/Makefile.am
+@@ -28,7 +28,8 @@ bin_PROGRAMS = virt-rescue
+ virt_rescue_SOURCES = \
+ 	escape.c \
+ 	rescue.c \
+-	rescue.h
++	rescue.h \
++	suggest.c
+ 
+ virt_rescue_CPPFLAGS = \
+ 	-DGUESTFS_WARN_DEPRECATED=1 \
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index 5281b1161..a1aac53e4 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -55,7 +55,6 @@ static void restore_tty (void);
+ static void tstp_handler (int sig);
+ static void cont_handler (int sig);
+ static void add_scratch_disks (int n, struct drv **drvs);
+-static void do_suggestion (struct drv *drvs);
+ 
+ /* Currently open libguestfs handle. */
+ guestfs_h *g;
+@@ -654,149 +653,6 @@ cont_handler (int sig)
+   raw_tty ();
+ }
+ 
+-static void suggest_filesystems (void);
+-
+-static int
+-compare_keys_len (const void *p1, const void *p2)
+-{
+-  const char *key1 = * (char * const *) p1;
+-  const char *key2 = * (char * const *) p2;
+-  return strlen (key1) - strlen (key2);
+-}
+-
+-/* virt-rescue --suggest flag does a kind of inspection on the
+- * drives and suggests mount commands that you should use.
+- */
+-static void
+-do_suggestion (struct drv *drvs)
+-{
+-  CLEANUP_FREE_STRING_LIST char **roots = NULL;
+-  size_t i;
+-
+-  /* For inspection, force add_drives to add the drives read-only. */
+-  read_only = 1;
+-
+-  /* Add drives. */
+-  add_drives (drvs);
+-
+-  /* Free up data structures, no longer needed after this point. */
+-  free_drives (drvs);
+-
+-  printf (_("Inspecting the virtual machine or disk image ...\n\n"));
+-  fflush (stdout);
+-
+-  if (guestfs_launch (g) == -1)
+-    exit (EXIT_FAILURE);
+-
+-  /* Don't use inspect_mount, since for virt-rescue we should allow
+-   * arbitrary disks and disks with more than one OS on them.  Let's
+-   * do this using the basic API instead.
+-   */
+-  roots = guestfs_inspect_os (g);
+-  if (roots == NULL)
+-    exit (EXIT_FAILURE);
+-
+-  if (roots[0] == NULL) {
+-    suggest_filesystems ();
+-    return;
+-  }
+-
+-  printf (_("This disk contains one or more operating systems.  You can use these mount\n"
+-            "commands in virt-rescue (at the ><rescue> prompt) to mount the filesystems.\n\n"));
+-
+-  for (i = 0; roots[i] != NULL; ++i) {
+-    CLEANUP_FREE_STRING_LIST char **mps = NULL;
+-    CLEANUP_FREE char *type = NULL, *distro = NULL, *product_name = NULL;
+-    int major, minor;
+-    size_t j;
+-
+-    type = guestfs_inspect_get_type (g, roots[i]);
+-    distro = guestfs_inspect_get_distro (g, roots[i]);
+-    product_name = guestfs_inspect_get_product_name (g, roots[i]);
+-    major = guestfs_inspect_get_major_version (g, roots[i]);
+-    minor = guestfs_inspect_get_minor_version (g, roots[i]);
+-
+-    printf (_("# %s is the root of a %s operating system\n"
+-              "# type: %s, distro: %s, version: %d.%d\n"
+-              "# %s\n\n"),
+-            roots[i], type ? : "unknown",
+-            type ? : "unknown", distro ? : "unknown", major, minor,
+-            product_name ? : "");
+-
+-    mps = guestfs_inspect_get_mountpoints (g, roots[i]);
+-    if (mps == NULL)
+-      exit (EXIT_FAILURE);
+-
+-    /* Sort by key length, shortest key first, so that we end up
+-     * mounting the filesystems in the correct order.
+-     */
+-    qsort (mps, guestfs_int_count_strings (mps) / 2, 2 * sizeof (char *),
+-           compare_keys_len);
+-
+-    for (j = 0; mps[j] != NULL; j += 2)
+-      printf ("mount %s /sysroot%s\n", mps[j+1], mps[j]);
+-
+-    /* If it's Linux, print the bind-mounts and a chroot command. */
+-    if (type && STREQ (type, "linux")) {
+-      printf ("mount --rbind /dev /sysroot/dev\n");
+-      printf ("mount --rbind /proc /sysroot/proc\n");
+-      printf ("mount --rbind /sys /sysroot/sys\n");
+-      printf ("\n");
+-      printf ("cd /sysroot\n");
+-      printf ("chroot /sysroot\n");
+-    }
+-
+-    printf ("\n");
+-  }
+-}
+-
+-/* Inspection failed, so it doesn't contain any OS that we recognise.
+- * However there might still be filesystems so print some suggestions
+- * for those.
+- */
+-static void
+-suggest_filesystems (void)
+-{
+-  size_t i, count;
+-
+-  CLEANUP_FREE_STRING_LIST char **fses = guestfs_list_filesystems (g);
+-  if (fses == NULL)
+-    exit (EXIT_FAILURE);
+-
+-  /* Count how many are not swap or unknown.  Possibly we should try
+-   * mounting to see which are mountable, but that has a high
+-   * probability of breaking.
+-   */
+-#define TEST_MOUNTABLE(fs) STRNEQ ((fs), "swap") && STRNEQ ((fs), "unknown")
+-  count = 0;
+-  for (i = 0; fses[i] != NULL; i += 2) {
+-    if (TEST_MOUNTABLE (fses[i+1]))
+-      count++;
+-  }
+-
+-  if (count == 0) {
+-    printf (_("This disk contains no mountable filesystems that we recognize.\n\n"
+-              "However you can still use virt-rescue on the disk image, to try to mount\n"
+-              "filesystems that are not recognized by libguestfs, or to create partitions,\n"
+-              "logical volumes and filesystems on a blank disk.\n"));
+-    return;
+-  }
+-
+-  printf (_("This disk contains one or more filesystems, but we don't recognize any\n"
+-            "operating system.  You can use these mount commands in virt-rescue (at the\n"
+-            "><rescue> prompt) to mount these filesystems.\n\n"));
+-
+-  for (i = 0; fses[i] != NULL; i += 2) {
+-    printf (_("# %s has type '%s'\n"), fses[i], fses[i+1]);
+-
+-    if (TEST_MOUNTABLE (fses[i+1]))
+-      printf ("mount %s /sysroot\n", fses[i]);
+-
+-    printf ("\n");
+-  }
+-#undef TEST_MOUNTABLE
+-}
+-
+ static void add_scratch_disk (struct drv **drvs);
+ 
+ static void
+diff --git a/rescue/rescue.h b/rescue/rescue.h
+index ccffb5eb3..4f5a04a71 100644
+--- a/rescue/rescue.h
++++ b/rescue/rescue.h
+@@ -23,6 +23,8 @@
+ 
+ #include "guestfs.h"
+ 
++#include "options.h"
++
+ extern guestfs_h *g;
+ extern int read_only;
+ extern int live;
+@@ -44,4 +46,7 @@ extern bool process_escapes (struct escape_state *state, char *buf, size_t *len)
+ extern int parse_escape_key (const char *);
+ extern void print_escape_key_help (void);
+ 
++/* suggest.c */
++extern void do_suggestion (struct drv *drvs);
++
+ #endif /* RESCUE_H */
+diff --git a/rescue/suggest.c b/rescue/suggest.c
+new file mode 100644
+index 000000000..13141ccc2
+--- /dev/null
++++ b/rescue/suggest.c
+@@ -0,0 +1,175 @@
++/* virt-rescue
++ * Copyright (C) 2010-2017 Red Hat Inc.
++ *
++ * 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 2 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <locale.h>
++#include <libintl.h>
++
++#include "guestfs.h"
++#include "guestfs-internal-frontend.h"
++
++#include "options.h"
++
++#include "rescue.h"
++
++static void suggest_filesystems (void);
++
++static int
++compare_keys_len (const void *p1, const void *p2)
++{
++  const char *key1 = * (char * const *) p1;
++  const char *key2 = * (char * const *) p2;
++  return strlen (key1) - strlen (key2);
++}
++
++/* virt-rescue --suggest flag does a kind of inspection on the
++ * drives and suggests mount commands that you should use.
++ */
++void
++do_suggestion (struct drv *drvs)
++{
++  CLEANUP_FREE_STRING_LIST char **roots = NULL;
++  size_t i;
++
++  /* For inspection, force add_drives to add the drives read-only. */
++  read_only = 1;
++
++  /* Add drives. */
++  add_drives (drvs);
++
++  /* Free up data structures, no longer needed after this point. */
++  free_drives (drvs);
++
++  printf (_("Inspecting the virtual machine or disk image ...\n\n"));
++  fflush (stdout);
++
++  if (guestfs_launch (g) == -1)
++    exit (EXIT_FAILURE);
++
++  /* Don't use inspect_mount, since for virt-rescue we should allow
++   * arbitrary disks and disks with more than one OS on them.  Let's
++   * do this using the basic API instead.
++   */
++  roots = guestfs_inspect_os (g);
++  if (roots == NULL)
++    exit (EXIT_FAILURE);
++
++  if (roots[0] == NULL) {
++    suggest_filesystems ();
++    return;
++  }
++
++  printf (_("This disk contains one or more operating systems.  You can use these mount\n"
++            "commands in virt-rescue (at the ><rescue> prompt) to mount the filesystems.\n\n"));
++
++  for (i = 0; roots[i] != NULL; ++i) {
++    CLEANUP_FREE_STRING_LIST char **mps = NULL;
++    CLEANUP_FREE char *type = NULL, *distro = NULL, *product_name = NULL;
++    int major, minor;
++    size_t j;
++
++    type = guestfs_inspect_get_type (g, roots[i]);
++    distro = guestfs_inspect_get_distro (g, roots[i]);
++    product_name = guestfs_inspect_get_product_name (g, roots[i]);
++    major = guestfs_inspect_get_major_version (g, roots[i]);
++    minor = guestfs_inspect_get_minor_version (g, roots[i]);
++
++    printf (_("# %s is the root of a %s operating system\n"
++              "# type: %s, distro: %s, version: %d.%d\n"
++              "# %s\n\n"),
++            roots[i], type ? : "unknown",
++            type ? : "unknown", distro ? : "unknown", major, minor,
++            product_name ? : "");
++
++    mps = guestfs_inspect_get_mountpoints (g, roots[i]);
++    if (mps == NULL)
++      exit (EXIT_FAILURE);
++
++    /* Sort by key length, shortest key first, so that we end up
++     * mounting the filesystems in the correct order.
++     */
++    qsort (mps, guestfs_int_count_strings (mps) / 2, 2 * sizeof (char *),
++           compare_keys_len);
++
++    for (j = 0; mps[j] != NULL; j += 2)
++      printf ("mount %s /sysroot%s\n", mps[j+1], mps[j]);
++
++    /* If it's Linux, print the bind-mounts and a chroot command. */
++    if (type && STREQ (type, "linux")) {
++      printf ("mount --rbind /dev /sysroot/dev\n");
++      printf ("mount --rbind /proc /sysroot/proc\n");
++      printf ("mount --rbind /sys /sysroot/sys\n");
++      printf ("\n");
++      printf ("cd /sysroot\n");
++      printf ("chroot /sysroot\n");
++    }
++
++    printf ("\n");
++  }
++}
++
++/* Inspection failed, so it doesn't contain any OS that we recognise.
++ * However there might still be filesystems so print some suggestions
++ * for those.
++ */
++static void
++suggest_filesystems (void)
++{
++  size_t i, count;
++
++  CLEANUP_FREE_STRING_LIST char **fses = guestfs_list_filesystems (g);
++  if (fses == NULL)
++    exit (EXIT_FAILURE);
++
++  /* Count how many are not swap or unknown.  Possibly we should try
++   * mounting to see which are mountable, but that has a high
++   * probability of breaking.
++   */
++#define TEST_MOUNTABLE(fs) STRNEQ ((fs), "swap") && STRNEQ ((fs), "unknown")
++  count = 0;
++  for (i = 0; fses[i] != NULL; i += 2) {
++    if (TEST_MOUNTABLE (fses[i+1]))
++      count++;
++  }
++
++  if (count == 0) {
++    printf (_("This disk contains no mountable filesystems that we recognize.\n\n"
++              "However you can still use virt-rescue on the disk image, to try to mount\n"
++              "filesystems that are not recognized by libguestfs, or to create partitions,\n"
++              "logical volumes and filesystems on a blank disk.\n"));
++    return;
++  }
++
++  printf (_("This disk contains one or more filesystems, but we don't recognize any\n"
++            "operating system.  You can use these mount commands in virt-rescue (at the\n"
++            "><rescue> prompt) to mount these filesystems.\n\n"));
++
++  for (i = 0; fses[i] != NULL; i += 2) {
++    printf (_("# %s has type '%s'\n"), fses[i], fses[i+1]);
++
++    if (TEST_MOUNTABLE (fses[i+1]))
++      printf ("mount %s /sysroot\n", fses[i]);
++
++    printf ("\n");
++  }
++#undef TEST_MOUNTABLE
++}
+-- 
+2.14.3
+
diff --git a/SOURCES/0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch b/SOURCES/0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch
new file mode 100644
index 0000000..34c658e
--- /dev/null
+++ b/SOURCES/0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch
@@ -0,0 +1,35 @@
+From 71b79b9aa2bdfa9a39fa1d81ab2d59331c386039 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 24 Mar 2017 22:51:06 +0000
+Subject: [PATCH] rescue: docs: It is no longer necessary to mount filesystems
+ by hand.
+
+Fix the manual page to reflect the new -i option.
+
+Fixes commit 33d2ae796119ae5dd38e2afcbf1ba4216bd99846.
+
+(cherry picked from commit c38b48409e067ba973d02bb10273350aa31b558e)
+---
+ rescue/virt-rescue.pod | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
+index bd6f954e9..dfa74e204 100644
+--- a/rescue/virt-rescue.pod
++++ b/rescue/virt-rescue.pod
+@@ -35,9 +35,9 @@ For live VMs you I<must> use the I<--ro> option.
+ When you run virt-rescue on a virtual machine or disk image, you are
+ placed in an interactive bash shell where you can use many ordinary
+ Linux commands.  What you see in F</> (F</bin>, F</lib> etc) is the
+-rescue appliance.  You must mount the virtual machine's filesystems by
+-hand.  There is an empty directory called F</sysroot> where you can
+-mount filesystems.
++rescue appliance.  You must mount the virtual machine's filesystems.
++There is an empty directory called F</sysroot> where you can mount
++filesystems.
+ 
+ To automatically mount the virtual machine's filesystems under
+ F</sysroot> use the I<-i> option.  This uses libguestfs inspection to
+-- 
+2.14.3
+
diff --git a/SOURCES/0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch b/SOURCES/0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch
new file mode 100644
index 0000000..bc9eddb
--- /dev/null
+++ b/SOURCES/0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch
@@ -0,0 +1,27 @@
+From 2bcdb1d5a81d1591e7de4fa6f2333e99c02b3e5b Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 24 Mar 2017 22:52:02 +0000
+Subject: [PATCH] rescue: docs: Note that you can run virt-rescue on disks too.
+
+(cherry picked from commit 267569f7ad22ad14d9ef4fa27b038469ae115c45)
+---
+ rescue/virt-rescue.pod | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
+index dfa74e204..5cfbd6e1c 100644
+--- a/rescue/virt-rescue.pod
++++ b/rescue/virt-rescue.pod
+@@ -69,7 +69,8 @@ Virt-rescue can be used on I<any> disk image file or device, not just
+ a virtual machine.  For example you can use it on a blank file if you
+ want to partition that file (although we would recommend using
+ L<guestfish(1)> instead as it is more suitable for this purpose).  You
+-can even use virt-rescue on things like SD cards.
++can even use virt-rescue on things like USB drives, SD cards and hard
++disks.
+ 
+ You can get virt-rescue to give you scratch disk(s) to play with.
+ This is useful for testing out Linux utilities (see I<--scratch>).
+-- 
+2.14.3
+
diff --git a/SOURCES/0062-rescue-Don-t-document-suggest-option-in-help-output.patch b/SOURCES/0062-rescue-Don-t-document-suggest-option-in-help-output.patch
new file mode 100644
index 0000000..099b02e
--- /dev/null
+++ b/SOURCES/0062-rescue-Don-t-document-suggest-option-in-help-output.patch
@@ -0,0 +1,41 @@
+From b8e5d0c7c03f7b96d6a60c505d227d9de3ba582d Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Sat, 25 Mar 2017 23:34:09 +0000
+Subject: [PATCH] rescue: Don't document --suggest option in --help output.
+
+Also fix the docs test to ignore it.
+
+Updates/fixes commit 33d2ae796119ae5dd38e2afcbf1ba4216bd99846.
+
+(cherry picked from commit aa7b7e26c3aa434f2b299055df63c52fb3a2f93f)
+---
+ rescue/rescue.c                 | 1 -
+ rescue/test-virt-rescue-docs.sh | 3 ++-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index a1aac53e4..6f9dcd733 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -101,7 +101,6 @@ usage (int status)
+               "  --scratch[=N]        Add scratch disk(s)\n"
+               "  --selinux            For backwards compat only, does nothing\n"
+               "  --smp N              Enable SMP with N >= 2 virtual CPUs\n"
+-              "  --suggest            Suggest mount commands for this guest\n"
+               "  -v|--verbose         Verbose messages\n"
+               "  -V|--version         Display version and exit\n"
+               "  -w|--rw              Mount read-write\n"
+diff --git a/rescue/test-virt-rescue-docs.sh b/rescue/test-virt-rescue-docs.sh
+index 25f8f6095..e5fbf26f4 100755
+--- a/rescue/test-virt-rescue-docs.sh
++++ b/rescue/test-virt-rescue-docs.sh
+@@ -21,4 +21,5 @@ set -e
+ $TEST_FUNCTIONS
+ skip_if_skipped
+ 
+-$top_srcdir/podcheck.pl virt-rescue.pod virt-rescue
++$top_srcdir/podcheck.pl virt-rescue.pod virt-rescue \
++                        --ignore=--suggest
+-- 
+2.14.3
+
diff --git a/SOURCES/0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch b/SOURCES/0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch
new file mode 100644
index 0000000..22dfee6
--- /dev/null
+++ b/SOURCES/0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch
@@ -0,0 +1,119 @@
+From 54c42d18d82ae4c5c0562600b47a7710a583ea07 Mon Sep 17 00:00:00 2001
+From: Pavel Butsykin <pbutsykin@virtuozzo.com>
+Date: Tue, 2 May 2017 15:35:06 +0300
+Subject: [PATCH] v2v: bootloaders: search grub config for all distributions
+
+This patch improves the search of grub config on EFI partition. This
+means that the config will be found not only for rhel but also for
+many other distributions.  Tests were performed on the following
+distributions: centos, fedora, ubuntu, suse. In all cases, the config
+path was /boot/efi/EFI/*distname*/grub.cfg
+
+The main purpose of the patch is to improve support for converting of
+vm with UEFI for most distributions. Unfortunately this patch does not
+solve the problem for all distributions, for example Debian does not
+store grub config on the EFI partition, therefore for such
+distributions another solution is necessary.
+
+Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
+(cherry picked from commit a76e9040b20f97eb5c9accbefcbf55999554dc48)
+---
+ v2v/linux_bootloaders.ml | 76 ++++++++++++++++++++++++++++++------------------
+ 1 file changed, 48 insertions(+), 28 deletions(-)
+
+diff --git a/v2v/linux_bootloaders.ml b/v2v/linux_bootloaders.ml
+index c3fd09ca8..25dab02fe 100644
+--- a/v2v/linux_bootloaders.ml
++++ b/v2v/linux_bootloaders.ml
+@@ -49,6 +49,13 @@ let remove_hd_prefix path =
+ 
+ (* Grub1 (AKA grub-legacy) representation. *)
+ class bootloader_grub1 (g : G.guestfs) inspect grub_config =
++  let () =
++  (* Apply the "grub" lens if it is not handling the file
++   * already -- Augeas < 1.7.0 will error out otherwise.
++   *)
++  if g#aug_ls ("/files" ^ grub_config) = [||] then
++    g#aug_transform "grub" grub_config in
++
+   (* Grub prefix?  Usually "/boot". *)
+   let grub_prefix =
+     let mounts = g#inspect_get_mountpoints inspect.i_root in
+@@ -345,33 +352,46 @@ object (self)
+ end
+ 
+ let detect_bootloader (g : G.guestfs) inspect =
+-  let config_file, typ =
+-    let locations = [
+-      "/boot/grub2/grub.cfg", Grub2;
+-      "/boot/grub/grub.cfg", Grub2;
+-      "/boot/grub/menu.lst", Grub1;
+-      "/boot/grub/grub.conf", Grub1;
+-    ] in
+-    let locations =
+-      match inspect.i_firmware with
+-      | I_UEFI _ ->
+-        [
+-          "/boot/efi/EFI/redhat/grub.cfg", Grub2;
+-          "/boot/efi/EFI/redhat/grub.conf", Grub1;
+-        ] @ locations
+-      | I_BIOS -> locations in
+-    try
+-      List.find (
+-        fun (config_file, _) -> g#is_file ~followsymlinks:true config_file
+-      ) locations
+-    with
+-      Not_found ->
+-        error (f_"no bootloader detected") in
++  (* Where to start searching for bootloaders. *)
++  let mp =
++    match inspect.i_firmware with
++    | I_BIOS -> "/boot"
++    | I_UEFI _ -> "/boot/efi/EFI" in
+ 
+-  match typ with
+-  | Grub1 ->
+-    if config_file = "/boot/efi/EFI/redhat/grub.conf" then
+-      g#aug_transform "grub" "/boot/efi/EFI/redhat/grub.conf";
++  (* Find all paths below the mountpoint, then filter them to find
++   * the grub config file.
++   *)
++  let paths =
++    try List.map ((^) mp) (Array.to_list (g#find mp))
++    with G.Error msg ->
++      error (f_"could not find bootloader mount point (%s): %s") mp msg in
+ 
+-    new bootloader_grub1 g inspect config_file
+-  | Grub2 -> new bootloader_grub2 g config_file
++  (* We can determine if the bootloader config file is grub 1 or
++   * grub 2 just by looking at the filename.
++   *)
++  let bootloader_type_of_filename path =
++    match last_part_of path '/' with
++    | Some "grub.cfg" -> Some Grub2
++    | Some ("grub.conf" | "menu.lst") -> Some Grub1
++    | Some _
++    | None -> None
++  in
++
++  let grub_config, typ =
++    let rec loop = function
++      | [] -> error (f_"no bootloader detected")
++      | path :: paths ->
++         match bootloader_type_of_filename path with
++         | None -> loop paths
++         | Some typ ->
++            if not (g#is_file ~followsymlinks:true path) then loop paths
++            else path, typ
++    in
++    loop paths in
++
++  let bl =
++    (match typ with
++     | Grub1 -> new bootloader_grub1 g inspect grub_config
++     | Grub2 -> new bootloader_grub2 g grub_config) in
++  debug "detected bootloader %s at %s" bl#name grub_config;
++  bl
+-- 
+2.14.3
+
diff --git a/SOURCES/0064-rescue-fix-size-check.patch b/SOURCES/0064-rescue-fix-size-check.patch
new file mode 100644
index 0000000..94e3233
--- /dev/null
+++ b/SOURCES/0064-rescue-fix-size-check.patch
@@ -0,0 +1,30 @@
+From ab6cefa227e23008eda69f8e7390d2eaed376d5c Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Mon, 23 Oct 2017 17:42:03 +0200
+Subject: [PATCH] rescue: fix size check
+
+Compare it to the right variable, not to the pointer itself.
+
+Fixes commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54.
+
+(cherry picked from commit 0998e3f1cdf9eb441ea1f45e45860feac47fccd8)
+---
+ rescue/escape.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/rescue/escape.c b/rescue/escape.c
+index f7f7d84c4..d6dc9d329 100644
+--- a/rescue/escape.c
++++ b/rescue/escape.c
+@@ -49,7 +49,7 @@ parse_escape_key (const char *arg)
+     return 0;
+ 
+   len = strlen (arg);
+-  if (arg == 0)
++  if (len == 0)
+     return -1;
+ 
+   switch (arg[0]) {
+-- 
+2.14.3
+
diff --git a/SOURCES/0065-rescue-initialize-CLEANUP-pointer-variable.patch b/SOURCES/0065-rescue-initialize-CLEANUP-pointer-variable.patch
new file mode 100644
index 0000000..2d24a3e
--- /dev/null
+++ b/SOURCES/0065-rescue-initialize-CLEANUP-pointer-variable.patch
@@ -0,0 +1,31 @@
+From d4d3e90ad9c9e144171ece825f60cb804449f835 Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Mon, 23 Oct 2017 17:44:23 +0200
+Subject: [PATCH] rescue: initialize CLEANUP pointer variable
+
+This way it will not try to free uninitialized memory when going out of
+scope, and the inspector mode is not enabled.
+
+Fixes commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54.
+
+(cherry picked from commit 0942241395b7faf02fd651a0d7b99628458febe4)
+---
+ rescue/escape.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/rescue/escape.c b/rescue/escape.c
+index d6dc9d329..ae4919f69 100644
+--- a/rescue/escape.c
++++ b/rescue/escape.c
+@@ -236,7 +236,7 @@ print_help (void)
+ static void
+ print_inspector (void)
+ {
+-  CLEANUP_FREE_STRING_LIST char **roots;
++  CLEANUP_FREE_STRING_LIST char **roots = NULL;
+   size_t i;
+   const char *root;
+   char *str;
+-- 
+2.14.3
+
diff --git a/SOURCES/0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch b/SOURCES/0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch
new file mode 100644
index 0000000..d1dc45f
--- /dev/null
+++ b/SOURCES/0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch
@@ -0,0 +1,32 @@
+From 0ce5239605cf455e4891224b6594f33f24b7bd9a Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Thu, 2 Nov 2017 11:13:42 +0100
+Subject: [PATCH] v2v: -i ova: parse MAC address from <rasd:Address>
+ (RHBZ#1506572)
+
+Read the MAC address of the network interfaces from the <rasd:Address>
+tag of the OVF.  This seems to be one of the possible ways used in OVFs.
+
+(cherry picked from commit a1b008e2d138a90cbf2147d69d5d2d4d745b03cd)
+---
+ v2v/parse_ovf_from_ova.ml | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/v2v/parse_ovf_from_ova.ml b/v2v/parse_ovf_from_ova.ml
+index 989483e2e..dba0ce585 100644
+--- a/v2v/parse_ovf_from_ova.ml
++++ b/v2v/parse_ovf_from_ova.ml
+@@ -211,8 +211,9 @@ let parse_ovf_from_ova ovf_filename =
+       Xml.xpathctx_set_current_context xpathctx n;
+       let vnet =
+         xpath_string_default "rasd:ElementName/text()" (sprintf"eth%d" i) in
++      let mac = xpath_string "rasd:Address/text()" in
+       let nic = {
+-        s_mac = None;
++        s_mac = mac;
+         s_nic_model = None;
+         s_vnet = vnet;
+         s_vnet_orig = vnet;
+-- 
+2.14.3
+
diff --git a/SOURCES/0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch b/SOURCES/0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch
new file mode 100644
index 0000000..7a63e5e
--- /dev/null
+++ b/SOURCES/0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch
@@ -0,0 +1,126 @@
+From 35372c4b210bc49969bf96e7a17897ec29ba4625 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 19 Oct 2017 12:05:43 +0100
+Subject: [PATCH] v2v: Fix RPM file owned test (RHBZ#1503958).
+
+Linux.file_owner is not used by any other function, so remove it.
+
+Linux.is_file_owned is only used when removing kmod-xenpv on old RHEL
+releases, and so is only required to work for RPM.
+
+The old file_owner/is_file_owned functions were completely broken for
+the RPM case.  This replaces them with a simpler, working
+implementation of is_file_owned only.
+
+Thanks: Ming Xie for finding and reporting the original bug.
+(cherry picked from commit e6bc59a7d46707f5037afc8a73206d2773c3fccd)
+---
+ v2v/linux.ml  | 61 ++++++++++++++++++++++++++---------------------------------
+ v2v/linux.mli |  3 ---
+ 2 files changed, 27 insertions(+), 37 deletions(-)
+
+diff --git a/v2v/linux.ml b/v2v/linux.ml
+index fad9b0c61..11b0e2cbf 100644
+--- a/v2v/linux.ml
++++ b/v2v/linux.ml
+@@ -98,7 +98,7 @@ let file_list_of_package (g : Guestfs.guestfs) inspect app =
+     error (f_"don't know how to get list of files from package using %s")
+       format
+ 
+-let rec file_owner (g : G.guestfs) { i_package_format = package_format } path =
++let is_file_owned (g : G.guestfs) { i_package_format = package_format } path =
+   match package_format with
+   | "deb" ->
+       (* With dpkg usually the directories are owned by all the packages
+@@ -108,48 +108,41 @@ let rec file_owner (g : G.guestfs) { i_package_format = package_format } path =
+        *)
+       let cmd = [| "dpkg"; "-S"; path |] in
+       debug "%s" (String.concat " " (Array.to_list cmd));
+-      let lines =
+-        try g#command_lines cmd
+-        with Guestfs.Error msg as exn ->
+-          if String.find msg "no path found matching pattern" >= 0 then
+-            raise Not_found
+-          else
+-            raise exn in
+-      if Array.length lines = 0 then
+-        error (f_"internal error: file_owner: dpkg command returned no output");
+-      let line = lines.(0) in
+-      let line =
+-        try String.sub line 0 (String.rindex line ':')
+-        with Invalid_argument _ ->
+-          error (f_"internal error: file_owner: invalid dpkg output: '%s'")
+-                line in
+-      fst (String.split "," line)
+-
+-  | "rpm" ->
+-      (* Although it is possible in RPM for multiple packages to own
+-       * a file, this deliberately only returns one package.
+-       *)
+-      let cmd = [| "rpm"; "-qf"; "--qf"; "%{NAME}\\n"; path |] in
+-      debug "%s" (String.concat " " (Array.to_list cmd));
+       (try
+-         let pkgs = g#command_lines cmd in
+-         pkgs.(0)
++         let lines = g#command_lines cmd in
++         if Array.length lines = 0 then
++           error (f_"internal error: is_file_owned: dpkg command returned no output");
++         (* Just check the output looks something like "pkg: filename". *)
++         if String.find lines.(0) ": " >= 0 then
++           true
++         else
++           error (f_"internal error: is_file_owned: unexpected output from dpkg command: %s")
++                 lines.(0)
+        with Guestfs.Error msg as exn ->
+-         if String.find msg "is not owned" >= 0 then
+-           raise Not_found
++         if String.find msg "no path found matching pattern" >= 0 then
++           false
+          else
+            raise exn
+-       | Invalid_argument _ (* pkgs.(0) raises index out of bounds *) ->
+-         error (f_"internal error: file_owner: rpm command returned no output")
+       )
+ 
++  | "rpm" ->
++     (* Run rpm -qf and print a magic string if the file is owned.
++      * If not owned, rpm will print "... is not owned by any package"
++      * and exit with an error.  Unfortunately the string is sent to
++      * stdout, so here we ignore the exit status of rpm and just
++      * look for one of the two strings.
++      *)
++     let magic = "FILE_OWNED_TEST" in
++     let cmd = sprintf "rpm -qf --qf %s %s 2>&1 ||:"
++                       (quote (magic ^ "\n")) (quote path) in
++     let r = g#sh cmd in
++     if String.find r magic >= 0 then true
++     else if String.find r "is not owned" >= 0 then false
++     else failwithf "RPM file owned test failed: %s" r
++
+   | format ->
+     error (f_"don't know how to find file owner using %s") format
+ 
+-and is_file_owned g inspect path =
+-  try ignore (file_owner g inspect path); true
+-  with Not_found -> false
+-
+ let is_package_manager_save_file filename =
+   (* Recognized suffixes of package managers. *)
+   let suffixes = [ ".dpkg-old"; ".dpkg-new"; ".rpmsave"; ".rpmnew"; ] in
+diff --git a/v2v/linux.mli b/v2v/linux.mli
+index 705073644..08146a460 100644
+--- a/v2v/linux.mli
++++ b/v2v/linux.mli
+@@ -29,9 +29,6 @@ val remove : Guestfs.guestfs -> Types.inspect -> string list -> unit
+ val file_list_of_package : Guestfs.guestfs -> Types.inspect -> Guestfs.application2 -> string list
+ (** Return list of files owned by package. *)
+ 
+-val file_owner : Guestfs.guestfs -> Types.inspect -> string -> string
+-(** Return the name of the package that owns a file. *)
+-
+ val is_file_owned : Guestfs.guestfs -> Types.inspect -> string -> bool
+ (** Returns true if the file is owned by an installed package. *)
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch b/SOURCES/0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch
new file mode 100644
index 0000000..28de6f3
--- /dev/null
+++ b/SOURCES/0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch
@@ -0,0 +1,37 @@
+From 67b740a77543bc0f0c6b4d0f52c8855b8705822b Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Fri, 1 Dec 2017 14:46:13 +0100
+Subject: [PATCH] v2v: bootloaders: handle no default grubby kernel
+ (RHBZ#1519204)
+
+When using grubby to get the default kernel of a guest, do not fail
+with a bogus error like:
+
+virt-v2v: error: libguestfs error: statns: statns_stub: path must start
+with a / character
+
+in case there is no default kernel that can be determined (e.g. because
+of a bogus configuration).
+---
+ v2v/linux_bootloaders.ml | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/v2v/linux_bootloaders.ml b/v2v/linux_bootloaders.ml
+index 25dab02fe..e241d93c2 100644
+--- a/v2v/linux_bootloaders.ml
++++ b/v2v/linux_bootloaders.ml
+@@ -281,7 +281,10 @@ object (self)
+       let res =
+         match get_default_method with
+         | MethodGrubby ->
+-          Some (g#command [| "grubby"; "--default-kernel" |])
++          let res = g#command [| "grubby"; "--default-kernel" |] in
++          (match res with
++           | "" -> None
++           | _ -> Some res)
+         | MethodPerlBootloader ->
+           let cmd =
+             [| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; "
+-- 
+2.14.3
+
diff --git a/SOURCES/0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch b/SOURCES/0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch
new file mode 100644
index 0000000..b39b9fe
--- /dev/null
+++ b/SOURCES/0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch
@@ -0,0 +1,47 @@
+From db196dc098d213638d7513bb98a72d1778658299 Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Tue, 5 Dec 2017 15:36:34 +0100
+Subject: [PATCH] lib: libvirt: stop using <shareable/> for appliance disk
+ (RHBZ#1518517)
+
+Commit aa9e0057b19e29f76c9a81f9aebeeb1cb5bf1fdb made the libvirt backend
+use <shareable/> for the disk of the appliance, since at that time all
+the instances were using the disk directly.
+OTOH, commit 3ad44c866042919374e2d840502e53da2ed8aef0 switched to
+overlays for read-only disks, including the appliance, so effectively
+protecting the appliance.
+
+Because of this, the libvirt backend does not need <shareable/> anymore.
+
+Thanks to: Daniel Berrange, Richard W.M. Jones,  Peter Krempa.
+---
+ lib/launch-libvirt.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
+index d10c7cb40..05c398ba0 100644
+--- a/lib/launch-libvirt.c
++++ b/lib/launch-libvirt.c
+@@ -969,10 +969,6 @@ static int construct_libvirt_xml_appliance (guestfs_h *g, const struct libvirt_x
+     }						\
+   } while (0)
+ 
+-/* <element/> */
+-#define empty_element(element)					\
+-  do { start_element(element) {} end_element (); } while (0)
+-
+ /* key=value attribute of the current element. */
+ #define attribute(key,value)                                            \
+   if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), BAD_CAST (value)) == -1){ \
+@@ -1758,8 +1754,6 @@ construct_libvirt_xml_appliance (guestfs_h *g,
+         == -1)
+       return -1;
+ 
+-    empty_element ("shareable");
+-
+   } end_element ();
+ 
+   return 0;
+-- 
+2.14.3
+
diff --git a/SOURCES/0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch b/SOURCES/0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch
new file mode 100644
index 0000000..edc2498
--- /dev/null
+++ b/SOURCES/0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch
@@ -0,0 +1,35 @@
+From be3d03e538592cff01d3e3693ada6e973df55abd Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Mon, 16 Oct 2017 10:06:54 +0100
+Subject: [PATCH] v2v: vddk: Make it clearer that you should not run nbdkit
+ 'make install'.
+
+(cherry picked from commit d81a2ee185599c23a128ab65be9d48b415abf461)
+---
+ v2v/virt-v2v.pod | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 92ed147d7..4f7ea8da6 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -1322,11 +1322,12 @@ L<https://github.com/libguestfs/nbdkit/tree/master/plugins/vddk>
+ 
+ =item 3.
+ 
+-You can run nbdkit from its source directory without needing to
+-install it.  Set C<$PATH> to include the nbdkit top build directory
+-(the directory containing a shell script called F<nbdkit>):
++You do B<not> need to run C<make install>.  You can run nbdkit from
++its source directory.  Set C<$PATH> to point to the nbdkit top build
++directory (that is, the directory containing a shell script called
++F<nbdkit>), eg:
+ 
+- export PATH=/path/to/nbdkit:$PATH
++ export PATH=/path/to/nbdkit-1.1.x:$PATH
+ 
+ =item 4.
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch b/SOURCES/0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch
new file mode 100644
index 0000000..dac42e3
--- /dev/null
+++ b/SOURCES/0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch
@@ -0,0 +1,28 @@
+From 6b6ab3bf31cbca8e4920315bbd46badf6d532529 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 7 Nov 2017 10:03:54 +0000
+Subject: [PATCH] podwrapper: nbdkit-* man pages are libguestfs man pages.
+
+Don't use the external link for these.
+
+Thanks: Ming Xie.
+(cherry picked from commit 441fa82ee0d878ed63b1c213d8197c1f0ffde2a0)
+---
+ podwrapper.pl.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/podwrapper.pl.in b/podwrapper.pl.in
+index 619d3af2b..9b90d0faa 100755
+--- a/podwrapper.pl.in
++++ b/podwrapper.pl.in
+@@ -552,6 +552,7 @@ SUBHTML: {
+         return 1 if /^guestunmount/;
+         return 1 if /^hivex/;
+         return 1 if /^supermin/;
++        return 1 if /^nbdkit/;
+         return 0;
+     }
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch b/SOURCES/0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch
new file mode 100644
index 0000000..dbeaedb
--- /dev/null
+++ b/SOURCES/0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch
@@ -0,0 +1,56 @@
+From f49162600c5ed54341ebeba9bc773fefc6b8153d Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 7 Nov 2017 10:07:03 +0000
+Subject: [PATCH] v2v: vddk: Update minimum version of nbdkit to 1.1.16.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+While 1.1.14 will technically still work, 1.1.16 adds the
+‘selinux=yes|no’ flag to ‘--dump-config’ output.  It's also the more
+widely available and tested version at the time of writing.
+
+Thanks: Ming Xie.
+(cherry picked from commit 415e9d82e901647438f68e4748720d88153778aa)
+---
+ v2v/input_libvirt_vddk.ml | 5 +++--
+ v2v/virt-v2v.pod          | 2 +-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
+index 33b34bd2e..d1f2ae360 100644
+--- a/v2v/input_libvirt_vddk.ml
++++ b/v2v/input_libvirt_vddk.ml
+@@ -61,13 +61,14 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
+ 
+     (* Check it's a new enough version.  The latest features we
+      * require are ‘--exit-with-parent’ and ‘--selinux-label’, both
+-     * added in 1.1.14.
++     * added in 1.1.14.  (We use 1.1.16 as the minimum here because
++     * it also adds the selinux=yes|no flag in --dump-config).
+      *)
+     let lines = external_command "nbdkit --help" in
+     let lines = String.concat " " lines in
+     if String.find lines "exit-with-parent" == -1 ||
+        String.find lines "selinux-label" == -1 then
+-      error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ 1.1.14")
++      error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ 1.1.16")
+   in
+ 
+   (* Check that the VDDK plugin is installed and working *)
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 4f7ea8da6..48a20cccc 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -1305,7 +1305,7 @@ library is permitted by the license.
+ =item 2.
+ 
+ You must also compile nbdkit, enabling the VDDK plugin.  At least
+-nbdkit E<ge> 1.1.14 is required, but it is usually best to compile
++nbdkit E<ge> 1.1.16 is required, but it is usually best to compile
+ from the git tree.
+ 
+ =over 4
+-- 
+2.14.3
+
diff --git a/SOURCES/0073-v2v-vddk-Further-rework-documentation.patch b/SOURCES/0073-v2v-vddk-Further-rework-documentation.patch
new file mode 100644
index 0000000..731cdb8
--- /dev/null
+++ b/SOURCES/0073-v2v-vddk-Further-rework-documentation.patch
@@ -0,0 +1,59 @@
+From 9e64238a389264b34af20b49da929d5bf6ccd436 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 7 Nov 2017 11:32:16 +0000
+Subject: [PATCH] v2v: vddk: Further rework documentation.
+
+Thanks for suggestions from Ming Xie.
+
+(cherry picked from commit 12d87361a4623587c53196e70157448158c02c7f)
+---
+ v2v/virt-v2v.pod | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 48a20cccc..417c25331 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -1304,6 +1304,10 @@ library is permitted by the license.
+ 
+ =item 2.
+ 
++VDDK E<ge> 6.5 is required.
++
++=item 3.
++
+ You must also compile nbdkit, enabling the VDDK plugin.  At least
+ nbdkit E<ge> 1.1.16 is required, but it is usually best to compile
+ from the git tree.
+@@ -1320,12 +1324,14 @@ L<https://github.com/libguestfs/nbdkit/tree/master/plugins/vddk>
+ 
+ =back
+ 
+-=item 3.
++Compile nbdkit as described in the sources (see link above).
+ 
+-You do B<not> need to run C<make install>.  You can run nbdkit from
+-its source directory.  Set C<$PATH> to point to the nbdkit top build
+-directory (that is, the directory containing a shell script called
+-F<nbdkit>), eg:
++You do B<not> need to run C<make install> because you can run nbdkit
++from its source directory.  The source directory has a shell script
++called F<nbdkit> which runs the locally built copy of nbdkit and its
++plugins.  So set C<$PATH> to point to the nbdkit top build directory
++(that is, the directory containing the shell script called F<nbdkit>),
++eg:
+ 
+  export PATH=/path/to/nbdkit-1.1.x:$PATH
+ 
+@@ -1333,7 +1339,7 @@ F<nbdkit>), eg:
+ 
+ You must find the SSL "thumbprint" of your VMware server.  How to do
+ this is explained in L<nbdkit-vddk-plugin(1)>, also available at the
+-link given in item 2 above.
++link above.
+ 
+ =item 5.
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch b/SOURCES/0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch
new file mode 100644
index 0000000..1fae654
--- /dev/null
+++ b/SOURCES/0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch
@@ -0,0 +1,57 @@
+From 5b64c3085942856f520823c12c871a4d96b75e35 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 6 Dec 2017 15:48:50 +0000
+Subject: [PATCH] v2v: docs: Remove min version of VDDK, recommend nbdkit >=
+ 1.1.25 (RHBZ#1513884).
+
+Requires -> recommends because older versions of nbdkit will likely
+work also.
+
+See also:
+https://bugzilla.redhat.com/show_bug.cgi?id=1513884#c3
+
+(cherry picked from commit 5ac24b490ebcf2e16e4ee2284a7f59bcc47cc808)
+---
+ v2v/virt-v2v.pod | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 417c25331..13f021c6d 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -1304,13 +1304,9 @@ library is permitted by the license.
+ 
+ =item 2.
+ 
+-VDDK E<ge> 6.5 is required.
+-
+-=item 3.
+-
+-You must also compile nbdkit, enabling the VDDK plugin.  At least
+-nbdkit E<ge> 1.1.16 is required, but it is usually best to compile
+-from the git tree.
++You must also compile nbdkit, enabling the VDDK plugin.  nbdkit E<ge>
++1.1.25 is recommended, but it is usually best to compile from the git
++tree.
+ 
+ =over 4
+ 
+@@ -1335,13 +1331,13 @@ eg:
+ 
+  export PATH=/path/to/nbdkit-1.1.x:$PATH
+ 
+-=item 4.
++=item 3.
+ 
+ You must find the SSL "thumbprint" of your VMware server.  How to do
+ this is explained in L<nbdkit-vddk-plugin(1)>, also available at the
+ link above.
+ 
+-=item 5.
++=item 4.
+ 
+ VDDK imports require a feature added in libvirt E<ge> 3.7.
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch b/SOURCES/0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch
new file mode 100644
index 0000000..3cd9e53
--- /dev/null
+++ b/SOURCES/0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch
@@ -0,0 +1,33 @@
+From 8e556500316c8e53993f50fe9ecb56d9524f5cab Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 6 Dec 2017 15:53:41 +0000
+Subject: [PATCH] v2v: docs: State that --vddk-thumbprint is only required if
+ --vddk present (RHBZ#1513884).
+
+Thanks: Ming Xie, Pino Toscano.
+
+See also:
+https://bugzilla.redhat.com/show_bug.cgi?id=1513884#c2
+
+(cherry picked from commit 4b43697f9bc9b0fa33e26fbc2fce136ebaa89005)
+---
+ v2v/virt-v2v.pod | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 13f021c6d..e798ad1e7 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -528,7 +528,8 @@ See L</INPUT FROM VDDK> below for details.
+ 
+ When using VDDK mode, these options are passed unmodified to the
+ L<nbdkit(1)> VDDK plugin.  Please refer to L<nbdkit-vddk-plugin(1)>.
+-Only I<--vddk-thumbprint> is required, the others are optional.
++If I<--vddk> is present, I<--vddk-thumbprint> is also required,
++the rest are optional.
+ 
+ =item B<--vdsm-compat=0.10>
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch b/SOURCES/0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch
new file mode 100644
index 0000000..a437475
--- /dev/null
+++ b/SOURCES/0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch
@@ -0,0 +1,518 @@
+From f8209cc000c28648efd4d73eeeec7bac3dd7c1dd Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Thu, 7 Dec 2017 14:41:32 +0000
+Subject: [PATCH] =?UTF-8?q?v2v:=20vddk:=20Switch=20to=20using=20=E2=80=98-?=
+ =?UTF-8?q?it=20vddk=E2=80=99=20to=20specify=20VDDK=20as=20input=20transpo?=
+ =?UTF-8?q?rt.?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Previously the presence of the ‘--vddk <libdir>’ option magically
+enabled VDDK mode.  However we want to introduce other transports for
+VMware conversions so this wasn't a very clean choice.
+
+With this commit you must use ‘-it vddk’ to specify that you want VDDK
+as a disk transport.  The previous ‘--vddk <libdir>’ option has been
+renamed to ‘--vddk-libdir <libdir>’ to be consistent with the other
+passthrough options, and it is no longer required.
+
+A new command line looks like:
+
+  $ export PATH=/path/to/nbdkit:$PATH
+  $ virt-v2v \
+      -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \
+|     -it vddk \
+|     --vddk-libdir /path/to/vmware-vix-disklib-distrib \
+      --vddk-thumbprint xx:xx:xx:... \
+      "Windows 2003" \
+      -o local -os /var/tmp
+
+where only the two lines marked with ‘|’ have changed.
+
+(cherry picked from commit 6f347b4f802717d4557fdae90c90afa030b8a414)
+---
+ v2v/cmdline.ml            | 69 +++++++++++++++++++++++++++++------------------
+ v2v/input_libvirt.ml      | 37 ++++++++++++-------------
+ v2v/input_libvirt.mli     |  8 +++---
+ v2v/input_libvirt_vddk.ml | 61 ++++++++++++++++++++++++++++-------------
+ v2v/test-v2v-docs.sh      |  2 +-
+ v2v/types.ml              |  2 +-
+ v2v/types.mli             |  2 +-
+ v2v/virt-v2v.pod          | 30 +++++++++++++++------
+ 8 files changed, 131 insertions(+), 80 deletions(-)
+
+diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
+index dfbb776ab..81562d1f5 100644
+--- a/v2v/cmdline.ml
++++ b/v2v/cmdline.ml
+@@ -56,15 +56,16 @@ let parse_cmdline () =
+ 
+   let input_conn = ref None in
+   let input_format = ref None in
++  let input_transport = ref None in
+   let in_place = ref false in
+   let output_conn = ref None in
+   let output_format = ref None in
+   let output_name = ref None in
+   let output_storage = ref None in
+   let password_file = ref None in
+-  let vddk = ref None in
+   let vddk_config = ref None in
+   let vddk_cookie = ref None in
++  let vddk_libdir = ref None in
+   let vddk_nfchostport = ref None in
+   let vddk_port = ref None in
+   let vddk_snapshot = ref None in
+@@ -186,6 +187,8 @@ let parse_cmdline () =
+                                             s_"Libvirt URI";
+     [ M"if" ],       Getopt.String ("format", set_string_option_once "-if" input_format),
+                                             s_"Input format (for -i disk)";
++    [ M"it" ],       Getopt.String ("transport", set_string_option_once "-it" input_transport),
++                                    s_"Input transport";
+     [ L"in-place" ], Getopt.Set in_place,         "";
+     [ L"machine-readable" ], Getopt.Set machine_readable, s_"Make output machine readable";
+     [ S 'n'; L"network" ],        Getopt.String ("in:out", add_network),    s_"Map network 'in' to 'out'";
+@@ -207,12 +210,12 @@ let parse_cmdline () =
+                                             s_"Use password from file";
+     [ L"print-source" ], Getopt.Set print_source, s_"Print source and stop";
+     [ L"root" ],    Getopt.String ("ask|... ", set_root_choice), s_"How to choose root filesystem";
+-    [ L"vddk" ],     Getopt.String ("libpath", set_string_option_once "--vddk" vddk),
+-                                            s_"Use nbdkit VDDK plugin";
+     [ L"vddk-config" ], Getopt.String ("filename", set_string_option_once "--vddk-config" vddk_config),
+                                             s_"Set VDDK config file";
+     [ L"vddk-cookie" ], Getopt.String ("cookie", set_string_option_once "--vddk-cookie" vddk_cookie),
+                                             s_"Set VDDK cookie";
++    [ L"vddk-libdir" ], Getopt.String ("libdir", set_string_option_once "--vddk-libdir" vddk_libdir),
++                                    s_"Set VDDK library parent directory";
+     [ L"vddk-nfchostport" ], Getopt.String ("nfchostport", set_string_option_once "--vddk-nfchostport" vddk_nfchostport),
+                                             s_"Set VDDK nfchostport";
+     [ L"vddk-port" ], Getopt.String ("port", set_string_option_once "--vddk-port" vddk_port),
+@@ -270,6 +273,12 @@ read the man page virt-v2v(1).
+   let input_conn = !input_conn in
+   let input_format = !input_format in
+   let input_mode = !input_mode in
++  let input_transport =
++    match !input_transport with
++    | None -> None
++    | Some "vddk" -> Some `VDDK
++    | Some transport ->
++       error (f_"unknown input transport ‘-it %s’") transport in
+   let in_place = !in_place in
+   let machine_readable = !machine_readable in
+   let network_map = !network_map in
+@@ -287,28 +296,15 @@ read the man page virt-v2v(1).
+   let qemu_boot = !qemu_boot in
+   let root_choice = !root_choice in
+   let vddk_options =
+-    match !vddk with
+-    | Some libdir ->
+-      Some { vddk_libdir = libdir;
+-             vddk_config = !vddk_config;
+-             vddk_cookie = !vddk_cookie;
+-             vddk_nfchostport = !vddk_nfchostport;
+-             vddk_port = !vddk_port;
+-             vddk_snapshot = !vddk_snapshot;
+-             vddk_thumbprint = !vddk_thumbprint;
+-             vddk_transports = !vddk_transports;
+-             vddk_vimapiver = !vddk_vimapiver }
+-    | None ->
+-      if !vddk_config <> None ||
+-         !vddk_cookie <> None ||
+-         !vddk_nfchostport <> None ||
+-         !vddk_port <> None ||
+-         !vddk_snapshot <> None ||
+-         !vddk_thumbprint <> None ||
+-         !vddk_transports <> None ||
+-         !vddk_vimapiver <> None then
+-        error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘--vddk’.");
+-      None in
++      { vddk_config = !vddk_config;
++        vddk_cookie = !vddk_cookie;
++        vddk_libdir = !vddk_libdir;
++        vddk_nfchostport = !vddk_nfchostport;
++        vddk_port = !vddk_port;
++        vddk_snapshot = !vddk_snapshot;
++        vddk_thumbprint = !vddk_thumbprint;
++        vddk_transports = !vddk_transports;
++        vddk_vimapiver = !vddk_vimapiver } in
+   let vdsm_compat = !vdsm_compat in
+   let vdsm_image_uuids = List.rev !vdsm_image_uuids in
+   let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in
+@@ -341,6 +337,26 @@ read the man page virt-v2v(1).
+       let password = read_first_line_from_file filename in
+       Some password in
+ 
++  (* Input transport affects whether some parameters should or
++   * should not be used.
++   *)
++  (match input_transport with
++   | None ->
++      if !vddk_config <> None ||
++         !vddk_cookie <> None ||
++         !vddk_libdir <> None ||
++         !vddk_nfchostport <> None ||
++         !vddk_port <> None ||
++         !vddk_snapshot <> None ||
++         !vddk_thumbprint <> None ||
++         !vddk_transports <> None ||
++         !vddk_vimapiver <> None then
++        error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘-it vddk’.")
++   | Some `VDDK ->
++      if !vddk_thumbprint = None then
++        error (f_"‘--vddk-thumbprint’ is required when using ‘-it vddk’.")
++  );
++
+   (* Parsing of the argument(s) depends on the input mode. *)
+   let input =
+     match input_mode with
+@@ -363,7 +379,8 @@ read the man page virt-v2v(1).
+         | [guest] -> guest
+         | _ ->
+           error (f_"expecting a libvirt guest name on the command line") in
+-      Input_libvirt.input_libvirt vddk_options password input_conn guest
++      Input_libvirt.input_libvirt vddk_options password
++                                  input_conn input_transport guest
+ 
+     | `LibvirtXML ->
+       (* -i libvirtxml: Expecting a filename (XML file). *)
+diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml
+index f4a8114f0..16006dc0c 100644
+--- a/v2v/input_libvirt.ml
++++ b/v2v/input_libvirt.ml
+@@ -27,7 +27,7 @@ open Types
+ open Utils
+ 
+ (* Choose the right subclass based on the URI. *)
+-let input_libvirt vddk_options password libvirt_uri guest =
++let input_libvirt vddk_options password libvirt_uri input_transport guest =
+   match libvirt_uri with
+   | None ->
+     Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+@@ -39,29 +39,26 @@ let input_libvirt vddk_options password libvirt_uri guest =
+         error (f_"could not parse '-ic %s'.  Original error message was: %s")
+           orig_uri msg in
+ 
+-    match server, scheme with
+-    | None, _
+-    | Some "", _                        (* Not a remote URI. *)
++    match server, scheme, input_transport with
++    | None, _, _
++    | Some "", _, _                     (* Not a remote URI. *)
+ 
+-    | Some _, None                      (* No scheme? *)
+-    | Some _, Some "" ->
++    | Some _, None, _                   (* No scheme? *)
++    | Some _, Some "", _ ->
+       Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+ 
+-    (* vCenter over https, or
+-     * vCenter or ESXi using nbdkit vddk plugin
+-     *)
+-    | Some server, Some ("esx"|"gsx"|"vpx" as scheme) ->
+-       (match vddk_options with
+-        | None ->
+-           Input_libvirt_vcenter_https.input_libvirt_vcenter_https
+-             password libvirt_uri parsed_uri scheme server guest
+-        | Some vddk_options ->
+-           Input_libvirt_vddk.input_libvirt_vddk vddk_options password
+-                                                 libvirt_uri parsed_uri guest
+-       )
++    (* vCenter over https. *)
++    | Some server, Some ("esx"|"gsx"|"vpx" as scheme), None ->
++       Input_libvirt_vcenter_https.input_libvirt_vcenter_https
++         password libvirt_uri parsed_uri scheme server guest
++
++    (* vCenter or ESXi using nbdkit vddk plugin *)
++    | Some server, Some ("esx"|"gsx"|"vpx"), Some `VDDK ->
++       Input_libvirt_vddk.input_libvirt_vddk vddk_options password
++                                             libvirt_uri parsed_uri guest
+ 
+     (* Xen over SSH *)
+-    | Some server, Some ("xen+ssh" as scheme) ->
++    | Some server, Some ("xen+ssh" as scheme), _ ->
+       Input_libvirt_xen_ssh.input_libvirt_xen_ssh
+         password libvirt_uri parsed_uri scheme server guest
+ 
+@@ -71,7 +68,7 @@ let input_libvirt vddk_options password libvirt_uri guest =
+      *)
+ 
+     (* Unknown remote scheme. *)
+-    | Some _, Some _ ->
++    | Some _, Some _, _ ->
+       warning (f_"no support for remote libvirt connections to '-ic %s'.  The conversion may fail when it tries to read the source disks.")
+         orig_uri;
+       Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli
+index acf2ca417..eb3e48397 100644
+--- a/v2v/input_libvirt.mli
++++ b/v2v/input_libvirt.mli
+@@ -18,7 +18,7 @@
+ 
+ (** [-i libvirt] source. *)
+ 
+-val input_libvirt : Types.vddk_options option -> string option -> string option -> string -> Types.input
+-(** [input_libvirt vddk_options password libvirt_uri guest] creates
+-    and returns a new {!Types.input} object specialized for reading input
+-    from libvirt sources. *)
++val input_libvirt : Types.vddk_options -> string option -> string option -> [`VDDK] option -> string -> Types.input
++(** [input_libvirt vddk_options password libvirt_uri input_transport guest]
++    creates and returns a new {!Types.input} object specialized for reading
++    input from libvirt sources. *)
+diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
+index d1f2ae360..2f2ac4214 100644
+--- a/v2v/input_libvirt_vddk.ml
++++ b/v2v/input_libvirt_vddk.ml
+@@ -34,11 +34,19 @@ open Printf
+ 
+ (* Subclass specialized for handling VMware via nbdkit vddk plugin. *)
+ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
+-
+   (* The VDDK path. *)
+   let libdir = vddk_options.vddk_libdir in
+-  (* Compute the LD_LIBRARY_PATH that we must pass to nbdkit. *)
+-  let library_path = libdir // sprintf "lib%d" Sys.word_size in
++
++  (* VDDK libraries are located under lib32/ or lib64/ relative to the
++   * libdir.  Note this is unrelated to Linux multilib or multiarch.
++   *)
++  let libNN = sprintf "lib%d" Sys.word_size in
++
++  (* Compute the LD_LIBRARY_PATH that we may have to pass to nbdkit. *)
++  let library_path =
++    match libdir with
++    | None -> None
++    | Some libdir -> Some (libdir // libNN) in
+ 
+   (* Is SELinux enabled and enforcing on the host? *)
+   let have_selinux =
+@@ -46,18 +54,25 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
+ 
+   (* Check that the VDDK path looks reasonable. *)
+   let error_unless_vddk_libdir () =
+-    if not (is_directory libdir) then
+-      error (f_"‘--vddk %s’ does not point to a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir;
++    (match libdir with
++     | None -> ()
++     | Some libdir ->
++        if not (is_directory libdir) then
++          error (f_"‘--vddk-libdir %s’ does not point to a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir
++    );
+ 
+-    if not (is_directory library_path) then
+-      error (f_"VDDK library path %s not found or not a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
+-            library_path
++    (match library_path with
++     | None -> ()
++     | Some library_path ->
++        if not (is_directory library_path) then
++          error (f_"VDDK library path %s not found or not a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
++    )
+   in
+ 
+   (* Check that nbdkit is available and new enough. *)
+   let error_unless_nbdkit_working () =
+     if 0 <> Sys.command "nbdkit --version >/dev/null" then
+-      error (f_"nbdkit is not installed or not working.  It is required to use ‘--vddk’.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.");
++      error (f_"nbdkit is not installed or not working.  It is required to use ‘-it vddk’.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.");
+ 
+     (* Check it's a new enough version.  The latest features we
+      * require are ‘--exit-with-parent’ and ‘--selinux-label’, both
+@@ -73,14 +88,20 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
+ 
+   (* Check that the VDDK plugin is installed and working *)
+   let error_unless_nbdkit_vddk_working () =
++    let set_ld_library_path =
++      match library_path with
++      | None -> ""
++      | Some library_path ->
++         sprintf "LD_LIBRARY_PATH=%s " (quote library_path) in
++
+     let cmd =
+-      sprintf "LD_LIBRARY_PATH=%s nbdkit vddk --dump-plugin >/dev/null"
+-              (quote library_path) in
++      sprintf "%snbdkit vddk --dump-plugin >/dev/null"
++              set_ld_library_path in
+     if Sys.command cmd <> 0 then (
+       (* See if we can diagnose why ... *)
+       let cmd =
+-        sprintf "LD_LIBRARY_PATH=%s LANG=C nbdkit vddk --dump-plugin 2>&1 | grep -sq libvixDiskLib.so"
+-                (quote library_path) in
++        sprintf "LANG=C %snbdkit vddk --dump-plugin 2>&1 | grep -sq libvixDiskLib.so"
++                set_ld_library_path in
+       let needs_library = Sys.command cmd = 0 in
+       if not needs_library then
+         error (f_"nbdkit VDDK plugin is not installed or not working.  It is required if you want to use VDDK.
+@@ -91,9 +112,9 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
+       else
+         error (f_"nbdkit VDDK plugin is not installed or not working.  It is required if you want to use VDDK.
+ 
+-It looks like you did not set the right path in the ‘--vddk’ option, or your copy of the VDDK directory is incomplete.  There should be a library called ’%s/libvixDiskLib.so.?’.
++It looks like you did not set the right path in the ‘--vddk-libdir’ option, or your copy of the VDDK directory is incomplete.  There should be a library called ’<libdir>/%s/libvixDiskLib.so.?’.
+ 
+-See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
++See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libNN
+     )
+   in
+ 
+@@ -120,6 +141,7 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
+   let vddk_passthrus =
+     [ "config",      (fun { vddk_config }      -> vddk_config);
+       "cookie",      (fun { vddk_cookie }      -> vddk_cookie);
++      "libdir",      (fun { vddk_libdir }      -> vddk_libdir);
+       "nfchostport", (fun { vddk_nfchostport } -> vddk_nfchostport);
+       "port",        (fun { vddk_port }        -> vddk_port);
+       "snapshot",    (fun { vddk_snapshot }    -> vddk_snapshot);
+@@ -140,9 +162,8 @@ object
+             | Some field -> sprintf " --vddk-%s %s" name field
+         ) vddk_passthrus
+       ) in
+-    sprintf "%s --vddk %s%s"
++    sprintf "%s -it vddk %s"
+             super#as_options (* superclass prints "-i libvirt etc" *)
+-            vddk_options.vddk_libdir
+             pt_options
+ 
+   method source () =
+@@ -249,7 +270,6 @@ object
+       add_arg (sprintf "user=%s" user);
+       add_arg password_param;
+       add_arg (sprintf "vm=moref=%s" moref);
+-      add_arg (sprintf "libdir=%s" libdir);
+ 
+       (* The passthrough parameters. *)
+       List.iter (
+@@ -299,7 +319,10 @@ object
+          let pid = fork () in
+          if pid = 0 then (
+            (* Child process (nbdkit). *)
+-           putenv "LD_LIBRARY_PATH" library_path;
++           (match library_path with
++            | None -> ()
++            | Some x -> putenv "LD_LIBRARY_PATH" x
++           );
+            execvp "nbdkit" args
+          );
+ 
+diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh
+index 5e49d5240..c8ca193eb 100755
+--- a/v2v/test-v2v-docs.sh
++++ b/v2v/test-v2v-docs.sh
+@@ -22,4 +22,4 @@ $TEST_FUNCTIONS
+ skip_if_skipped
+ 
+ $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \
+-  --ignore=--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
++  --ignore=--debug-overlay,--ic,--if,--in-place,--it,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
+diff --git a/v2v/types.ml b/v2v/types.ml
+index 4f9205aa0..43bd28804 100644
+--- a/v2v/types.ml
++++ b/v2v/types.ml
+@@ -473,9 +473,9 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string
+ type output_allocation = Sparse | Preallocated
+ 
+ type vddk_options = {
+-    vddk_libdir : string;
+     vddk_config : string option;
+     vddk_cookie : string option;
++    vddk_libdir : string option;
+     vddk_nfchostport : string option;
+     vddk_port : string option;
+     vddk_snapshot : string option;
+diff --git a/v2v/types.mli b/v2v/types.mli
+index 087a03702..fd944bebf 100644
+--- a/v2v/types.mli
++++ b/v2v/types.mli
+@@ -329,9 +329,9 @@ type output_allocation = Sparse | Preallocated
+ (** Type of [-oa] (output allocation) option. *)
+ 
+ type vddk_options = {
+-    vddk_libdir : string;
+     vddk_config : string option;
+     vddk_cookie : string option;
++    vddk_libdir : string option;
+     vddk_nfchostport : string option;
+     vddk_port : string option;
+     vddk_snapshot : string option;
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index e798ad1e7..7aca22b3c 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -255,6 +255,13 @@ For I<-i disk> only, this specifies the format of the input disk
+ image.  For other input methods you should specify the input
+ format in the metadata.
+ 
++=item B<-it> B<vddk>
++
++Use VMware VDDK as a transport to copy the input disks.  See
++L</INPUT FROM VDDK> below.  If you use this parameter then you may
++need to use other I<--vddk*> options to specify how to connect through
++VDDK.
++
+ =item B<--keys-from-stdin>
+ 
+ Read key or passphrase parameters from stdin.  The default is
+@@ -501,13 +508,20 @@ boot an operating system from the first VirtIO disk.  Specifically,
+ F</boot> must be on the first VirtIO disk, and it cannot chainload an
+ OS which is not in the first VirtIO disk.
+ 
+-=item B<--vddk> LIBDIR
++=item B<--vddk-libdir> LIBDIR
+ 
+-Enable VDDK input from VMware vCenter or ESXi.  C<LIBDIR> is the top
+-directory of the VDDK library.  This directory should I<contain>
++Set the VDDK library directory.  This directory should I<contain>
+ subdirectories called F<include>, F<lib64> etc., but do not include
+ F<lib64> actually in the parameter.
+ 
++In most cases this parameter is required when using the I<-it vddk>
++(VDDK) transport.  See L</INPUT FROM VDDK> below for details.
++
++=item B<--vddk-thumbprint> xx:xx:xx:...
++
++Set the thumbprint of the remote VMware server.
++
++This parameter is required when using the I<-it vddk> (VDDK) transport.
+ See L</INPUT FROM VDDK> below for details.
+ 
+ =item B<--vddk-config> FILENAME
+@@ -520,16 +534,13 @@ See L</INPUT FROM VDDK> below for details.
+ 
+ =item B<--vddk-snapshot> SNAPSHOT-MOREF
+ 
+-=item B<--vddk-thumbprint> xx:xx:xx:...
+-
+ =item B<--vddk-transports> MODE:MODE:...
+ 
+ =item B<--vddk-vimapiver> APIVER
+ 
+ When using VDDK mode, these options are passed unmodified to the
+ L<nbdkit(1)> VDDK plugin.  Please refer to L<nbdkit-vddk-plugin(1)>.
+-If I<--vddk> is present, I<--vddk-thumbprint> is also required,
+-the rest are optional.
++These are all optional.
+ 
+ =item B<--vdsm-compat=0.10>
+ 
+@@ -1390,6 +1401,8 @@ continuing.
+ 
+ =head2 VDDK: IMPORTING A GUEST
+ 
++The I<-it vddk> parameter selects VDDK as the input transport for disks.
++
+ To import a particular guest from vCenter server or ESXi hypervisor,
+ use a command like the following, substituting the URI, guest name and
+ SSL thumbprint:
+@@ -1397,7 +1410,8 @@ SSL thumbprint:
+  $ export PATH=/path/to/nbdkit:$PATH
+  $ virt-v2v \
+      -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \
+-     --vddk /path/to/vmware-vix-disklib-distrib \
++     -it vddk \
++     --vddk-libdir /path/to/vmware-vix-disklib-distrib \
+      --vddk-thumbprint xx:xx:xx:... \
+      "Windows 2003" \
+      -o local -os /var/tmp
+-- 
+2.14.3
+
diff --git a/SOURCES/0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch b/SOURCES/0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch
new file mode 100644
index 0000000..77752e4
--- /dev/null
+++ b/SOURCES/0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch
@@ -0,0 +1,619 @@
+From d45c983b7181946323ebd93cccf1100b45b55470 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Fri, 8 Dec 2017 10:43:45 +0000
+Subject: [PATCH] =?UTF-8?q?v2v:=20-i=20vmx:=20Enhance=20VMX=20support=20wi?=
+ =?UTF-8?q?th=20ability=20to=20use=20=E2=80=98-it=20ssh=E2=80=99=20transpo?=
+ =?UTF-8?q?rt.?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This enhances the existing VMX input support allowing it to be
+used over SSH to the ESXi server.
+
+The original command (for local .vmx files) was:
+
+ $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp
+
+Adding ‘-it ssh’ and using an SSH remote path gives the new syntax:
+
+ $ virt-v2v \
+     -i vmx -it ssh \
+     "ssh://root@esxi.example.com/vmfs/volumes/datastore1/guest/guest.vmx" \
+     -o local -os /var/tmp
+
+I anticipate that this input method will be widely used enough that it
+deserves its own example at the top of the man page.
+
+(cherry picked from commit 1d38216d20141cef9ce83ca4ddbe9c79f5da4f39)
+---
+ v2v/cmdline.ml              |  26 ++++--
+ v2v/input_libvirt_other.ml  |   9 ---
+ v2v/input_libvirt_other.mli |   1 -
+ v2v/input_vmx.ml            | 193 +++++++++++++++++++++++++++++++++++++-------
+ v2v/input_vmx.mli           |   5 +-
+ v2v/utils.ml                |   9 +++
+ v2v/utils.mli               |   2 +
+ v2v/virt-v2v.pod            | 106 ++++++++++++++++++++----
+ 8 files changed, 290 insertions(+), 61 deletions(-)
+
+diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
+index 81562d1f5..dfcc77ecd 100644
+--- a/v2v/cmdline.ml
++++ b/v2v/cmdline.ml
+@@ -276,6 +276,7 @@ read the man page virt-v2v(1).
+   let input_transport =
+     match !input_transport with
+     | None -> None
++    | Some "ssh" -> Some `SSH
+     | Some "vddk" -> Some `VDDK
+     | Some transport ->
+        error (f_"unknown input transport ‘-it %s’") transport in
+@@ -341,7 +342,8 @@ read the man page virt-v2v(1).
+    * should not be used.
+    *)
+   (match input_transport with
+-   | None ->
++   | None
++   | Some `SSH ->
+       if !vddk_config <> None ||
+          !vddk_cookie <> None ||
+          !vddk_libdir <> None ||
+@@ -379,6 +381,12 @@ read the man page virt-v2v(1).
+         | [guest] -> guest
+         | _ ->
+           error (f_"expecting a libvirt guest name on the command line") in
++      let input_transport =
++        match input_transport with
++        | None -> None
++        | Some `VDDK -> Some `VDDK
++        | Some `SSH ->
++           error (f_"only ‘-it vddk’ can be used here") in
+       Input_libvirt.input_libvirt vddk_options password
+                                   input_conn input_transport guest
+ 
+@@ -401,13 +409,19 @@ read the man page virt-v2v(1).
+       Input_ova.input_ova filename
+ 
+     | `VMX ->
+-      (* -i vmx: Expecting an vmx filename. *)
+-      let filename =
++      (* -i vmx: Expecting a vmx filename or SSH remote path. *)
++      let arg =
+         match args with
+-        | [filename] -> filename
++        | [arg] -> arg
+         | _ ->
+-          error (f_"expecting a VMX file name on the command line") in
+-      Input_vmx.input_vmx filename in
++          error (f_"expecting a single VMX file name or SSH remote path on the command line") in
++      let input_transport =
++        match input_transport with
++        | None -> None
++        | Some `SSH -> Some `SSH
++        | Some `VDDK ->
++           error (f_"only ‘-it ssh’ can be used here") in
++      Input_vmx.input_vmx input_transport arg in
+ 
+   (* Prevent use of --in-place option in RHEL. *)
+   if in_place then
+diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml
+index dc16cb11b..a487a2b76 100644
+--- a/v2v/input_libvirt_other.ml
++++ b/v2v/input_libvirt_other.ml
+@@ -39,15 +39,6 @@ let error_if_libvirt_does_not_support_json_backingfile () =
+        Libvirt_utils.libvirt_get_version () < (2, 1, 0) then
+     error (f_"because of libvirt bug https://bugzilla.redhat.com/1134878 you must EITHER upgrade to libvirt >= 2.1.0 OR set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.")
+ 
+-(* xen+ssh URLs use the SSH driver in CURL.  Currently this requires
+- * ssh-agent authentication.  Give a clear error if this hasn't been
+- * set up (RHBZ#1139973).
+- *)
+-let error_if_no_ssh_agent () =
+-  try ignore (Sys.getenv "SSH_AUTH_SOCK")
+-  with Not_found ->
+-    error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set).  Please read \"INPUT FROM RHEL 5 XEN\" in the virt-v2v(1) man page.")
+-
+ (* Superclass. *)
+ class virtual input_libvirt (password : string option) libvirt_uri guest =
+ object
+diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli
+index 494ca908a..8b1e8aa1d 100644
+--- a/v2v/input_libvirt_other.mli
++++ b/v2v/input_libvirt_other.mli
+@@ -19,7 +19,6 @@
+ (** [-i libvirt] source. *)
+ 
+ val error_if_libvirt_does_not_support_json_backingfile : unit -> unit
+-val error_if_no_ssh_agent : unit -> unit
+ 
+ class virtual input_libvirt : string option -> string option -> string -> object
+   method precheck : unit -> unit
+diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
+index a4f77c2ab..092a7b70c 100644
+--- a/v2v/input_vmx.ml
++++ b/v2v/input_vmx.ml
+@@ -19,6 +19,7 @@
+ open Printf
+ open Scanf
+ 
++open Unix_utils
+ open Common_gettext.Gettext
+ open Common_utils
+ 
+@@ -26,10 +27,86 @@ open Types
+ open Utils
+ open Name_from_disk
+ 
+-external identity : 'a -> 'a = "%identity"
++type vmx_source =
++  | File of string              (* local file or NFS *)
++  | SSH of Xml.uri              (* SSH URI *)
+ 
+-let rec find_disks vmx vmx_filename =
+-  find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename
++(* The single filename on the command line is intepreted either as
++ * a local file or a remote SSH URI (only if ‘-it ssh’).
++ *)
++let vmx_source_of_arg input_transport arg =
++  match input_transport, arg with
++  | None, arg -> File arg
++  | Some `SSH, arg ->
++     let uri =
++       try Xml.parse_uri arg
++       with Invalid_argument _ ->
++         error (f_"remote vmx ‘%s’ could not be parsed as a URI") arg in
++     if uri.Xml.uri_scheme <> None && uri.Xml.uri_scheme <> Some "ssh" then
++       error (f_"vmx URI start with ‘ssh://...’");
++     if uri.Xml.uri_server = None then
++       error (f_"vmx URI remote server name omitted");
++     if uri.Xml.uri_path = None || uri.Xml.uri_path = Some "/" then
++       error (f_"vmx URI path component looks incorrect");
++     SSH uri
++
++(* Return various fields from the URI.  The checks in vmx_source_of_arg
++ * should ensure that none of these assertions fail.
++ *)
++let port_of_uri { Xml.uri_port } =
++  match uri_port with i when i <= 0 -> None | i -> Some i
++let server_of_uri { Xml.uri_server } =
++  match uri_server with None -> assert false | Some s -> s
++let path_of_uri { Xml.uri_path } =
++  match uri_path with None -> assert false | Some p -> p
++
++(* 'scp' a remote file into a temporary local file, returning the path
++ * of the temporary local file.
++ *)
++let scp_from_remote_to_temporary uri tmpdir filename =
++  let localfile = tmpdir // filename in
++
++  let cmd =
++    sprintf "scp%s%s %s%s:%s %s"
++            (if verbose () then "" else " -q")
++            (match port_of_uri uri with
++             | None -> ""
++             | Some port -> sprintf " -P %d" port)
++            (match uri.Xml.uri_user with
++             | None -> ""
++             | Some user -> quote user ^ "@")
++            (quote (server_of_uri uri))
++            (* The double quoting of the path is counter-intuitive
++             * but correct, see:
++             * https://stackoverflow.com/questions/19858176/how-to-escape-spaces-in-path-during-scp-copy-in-linux
++             *)
++            (quote (quote (path_of_uri uri)))
++            (quote localfile) in
++  if verbose () then
++    eprintf "%s\n%!" cmd;
++  if Sys.command cmd <> 0 then
++    error (f_"could not copy the VMX file from the remote server, see earlier error messages");
++  localfile
++
++(* Test if [path] exists on the remote server. *)
++let remote_file_exists uri path =
++  let cmd =
++    sprintf "ssh%s %s%s test -f %s"
++            (match port_of_uri uri with
++             | None -> ""
++             | Some port -> sprintf " -p %d" port)
++            (match uri.Xml.uri_user with
++             | None -> ""
++             | Some user -> quote user ^ "@")
++            (quote (server_of_uri uri))
++            (* Double quoting is necessary here, see above. *)
++            (quote (quote path)) in
++  if verbose () then
++    eprintf "%s\n%!" cmd;
++  Sys.command cmd = 0
++
++let rec find_disks vmx vmx_source =
++  find_scsi_disks vmx vmx_source @ find_ide_disks vmx vmx_source
+ 
+ (* Find all SCSI hard disks.
+  *
+@@ -39,7 +116,7 @@ let rec find_disks vmx vmx_filename =
+  *                        | omitted
+  *   scsi0:0.fileName = "guest.vmdk"
+  *)
+-and find_scsi_disks vmx vmx_filename =
++and find_scsi_disks vmx vmx_source =
+   let get_scsi_controller_target ns =
+     sscanf ns "scsi%d:%d" (fun c t -> c, t)
+   in
+@@ -51,7 +128,7 @@ and find_scsi_disks vmx vmx_filename =
+                             Some "scsi-harddisk"; None ] in
+   let scsi_controller = Source_SCSI in
+ 
+-  find_hdds vmx vmx_filename
++  find_hdds vmx vmx_source
+             get_scsi_controller_target is_scsi_controller_target
+             scsi_device_types scsi_controller
+ 
+@@ -61,7 +138,7 @@ and find_scsi_disks vmx vmx_filename =
+  *   ide0:0.deviceType = "ata-hardDisk"
+  *   ide0:0.fileName = "guest.vmdk"
+  *)
+-and find_ide_disks vmx vmx_filename =
++and find_ide_disks vmx vmx_source =
+   let get_ide_controller_target ns =
+     sscanf ns "ide%d:%d" (fun c t -> c, t)
+   in
+@@ -72,11 +149,11 @@ and find_ide_disks vmx vmx_filename =
+   let ide_device_types = [ Some "ata-harddisk" ] in
+   let ide_controller = Source_IDE in
+ 
+-  find_hdds vmx vmx_filename
++  find_hdds vmx vmx_source
+             get_ide_controller_target is_ide_controller_target
+             ide_device_types ide_controller
+ 
+-and find_hdds vmx vmx_filename
++and find_hdds vmx vmx_source
+               get_controller_target is_controller_target
+               device_types controller =
+   (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *)
+@@ -105,9 +182,9 @@ and find_hdds vmx vmx_filename
+         match path, v with
+         | [ns; "filename"], Some filename ->
+            let c, t = get_controller_target ns in
++           let uri, format = qemu_uri_of_filename vmx_source filename in
+            let s = { s_disk_id = (-1);
+-                     s_qemu_uri = qemu_uri_of_filename vmx_filename filename;
+-                     s_format = Some "vmdk";
++                     s_qemu_uri = uri; s_format = Some format;
+                      s_controller = Some controller } in
+            Some (c, t, s)
+         | _ -> None
+@@ -129,17 +206,54 @@ and find_hdds vmx vmx_filename
+ (* The filename can be an absolute path, but is more often a
+  * path relative to the location of the vmx file.
+  *
+- * Note that we always end up with an absolute path, which is
+- * also useful because it means we won't have any paths that
+- * could be misinterpreted by qemu.
++ * This constructs a QEMU URI of the filename relative to the
++ * vmx file (which might be remote over SSH).
+  *)
+-and qemu_uri_of_filename vmx_filename filename =
+-  if not (Filename.is_relative filename) then
+-    filename
+-  else (
+-    let dir = Filename.dirname (absolute_path vmx_filename) in
+-    dir // filename
+-  )
++and qemu_uri_of_filename vmx_source filename =
++  match vmx_source with
++  | File vmx_filename ->
++     (* Always ensure this returns an absolute path to avoid
++      * any confusion with filenames containing colons.
++      *)
++     absolute_path_from_other_file vmx_filename filename, "vmdk"
++
++  | SSH uri ->
++     let vmx_path = path_of_uri uri in
++     let abs_path = absolute_path_from_other_file vmx_path filename in
++     let format = "vmdk" in
++
++     (* XXX This is a hack to work around qemu / VMDK limitation
++      *   "Cannot use relative extent paths with VMDK descriptor file"
++      * We can remove this if the above is fixed.
++      *)
++     let abs_path, format =
++       let flat_vmdk =
++         Str.replace_first (Str.regexp "\\.vmdk$") "-flat.vmdk" abs_path in
++       if remote_file_exists uri flat_vmdk then (flat_vmdk, "raw")
++       else (abs_path, format) in
++
++     let json_params = [
++       "file.driver", JSON.String "ssh";
++       "file.path", JSON.String abs_path;
++       "file.host", JSON.String (server_of_uri uri);
++       "file.host_key_check", JSON.String "no";
++     ] in
++     let json_params =
++       match uri.Xml.uri_user with
++       | None -> json_params
++       | Some user ->
++          ("file.user", JSON.String user) :: json_params in
++     let json_params =
++       match port_of_uri uri with
++       | None -> json_params
++       | Some port ->
++          ("file.port", JSON.Int port) :: json_params in
++
++     "json:" ^ JSON.string_of_doc json_params, format
++
++and absolute_path_from_other_file other_filename filename =
++  if not (Filename.is_relative filename) then filename
++  else (Filename.dirname (absolute_path other_filename)) // filename
+ 
+ (* Find all removable disks.
+  *
+@@ -272,21 +386,46 @@ and find_nics vmx =
+   let nics = List.map (fun (_, source) -> source) nics in
+   nics
+ 
+-class input_vmx vmx_filename = object
++class input_vmx input_transport arg =
++  let tmpdir =
++    let base_dir = (open_guestfs ())#get_cachedir () in
++    let t = Mkdtemp.temp_dir ~base_dir "vmx." in
++    rmdir_on_exit t;
++    t in
++object
+   inherit input
+ 
+-  method as_options = "-i vmx " ^ vmx_filename
++  method as_options = "-i vmx " ^ arg
++
++  method precheck () =
++    match input_transport with
++    | None -> ()
++    | Some `SSH ->
++       if backend_is_libvirt () then
++         error (f_"because libvirtd doesn't pass the SSH_AUTH_SOCK environment variable to qemu you must set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.");
++       error_if_no_ssh_agent ()
+ 
+   method source () =
+-    (* Parse the VMX file. *)
+-    let vmx = Parse_vmx.parse_file vmx_filename in
++    let vmx_source = vmx_source_of_arg input_transport arg in
++
++    (* If the transport is SSH, fetch the file from remote, else
++     * parse it from local.
++     *)
++    let vmx =
++      match vmx_source with
++      | File filename -> Parse_vmx.parse_file filename
++      | SSH uri ->
++         let filename = scp_from_remote_to_temporary uri tmpdir "source.vmx" in
++         Parse_vmx.parse_file filename in
+ 
+     let name =
+       match Parse_vmx.get_string vmx ["displayName"] with
++      | Some s -> s
+       | None ->
+          warning (f_"no displayName key found in VMX file");
+-         name_from_disk vmx_filename
+-      | Some s -> s in
++         match vmx_source with
++         | File filename -> name_from_disk filename
++         | SSH uri -> name_from_disk (path_of_uri uri) in
+ 
+     let memory_mb =
+       match Parse_vmx.get_int64 vmx ["memSize"] with
+@@ -325,7 +464,7 @@ class input_vmx vmx_filename = object
+          None
+       | None -> None in
+ 
+-    let disks = find_disks vmx vmx_filename in
++    let disks = find_disks vmx vmx_source in
+     let removables = find_removables vmx in
+     let nics = find_nics vmx in
+ 
+diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli
+index f236f8716..34ec2a5c6 100644
+--- a/v2v/input_vmx.mli
++++ b/v2v/input_vmx.mli
+@@ -18,5 +18,6 @@
+ 
+ (** [-i vmx] source. *)
+ 
+-val input_vmx : string -> Types.input
+-(** [input_vmx filename] sets up an input from vmware vmx file. *)
++val input_vmx : [`SSH] option -> string -> Types.input
++(** [input_vmx input_transport arg] sets up an input
++    from vmware vmx file. *)
+diff --git a/v2v/utils.ml b/v2v/utils.ml
+index 2061eea61..158077bf6 100644
+--- a/v2v/utils.ml
++++ b/v2v/utils.ml
+@@ -127,6 +127,15 @@ let backend_is_libvirt () =
+   let backend = fst (String.split ":" backend) in
+   backend = "libvirt"
+ 
++(* When using the SSH driver in qemu (currently) this requires
++ * ssh-agent authentication.  Give a clear error if this hasn't been
++ * set up (RHBZ#1139973).  This might improve if we switch to libssh1.
++ *)
++let error_if_no_ssh_agent () =
++  try ignore (Sys.getenv "SSH_AUTH_SOCK")
++  with Not_found ->
++    error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set).  This is required by qemu to do passwordless ssh access.  See the virt-v2v(1) man page for more information.")
++
+ let find_file_in_tar tar filename =
+   let lines = external_command (sprintf "tar tRvf %s" (Filename.quote tar)) in
+   let rec loop lines =
+diff --git a/v2v/utils.mli b/v2v/utils.mli
+index b2fd0be1b..042454565 100644
+--- a/v2v/utils.mli
++++ b/v2v/utils.mli
+@@ -61,6 +61,8 @@ val qemu_img_supports_offset_and_size : unit -> bool
+ val backend_is_libvirt : unit -> bool
+ (** Return true iff the current backend is libvirt. *)
+ 
++val error_if_no_ssh_agent : unit -> unit
++
+ val find_file_in_tar : string -> string -> int64 * int64
+ (** [find_file_in_tar tar filename] looks up file in [tar] archive and returns
+     a tuple containing at which byte it starts and how long the file is.
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index 7aca22b3c..d0387734a 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -113,6 +113,23 @@ Note that after conversion, the guest will appear in the RHV-M Export
+ Storage Domain, from where you will need to import it using the RHV-M
+ user interface.  (See L</OUTPUT TO RHV>).
+ 
++=head2 Convert from ESXi hypervisor over SSH to local libvirt
++
++You have an ESXi hypervisor called C<esxi.example.com> with SSH access
++enabled.  You want to convert from VMFS storage on that server to
++a local file.
++
++ virt-v2v \
++   -i vmx -it ssh \
++   "root@esxi.example.com/vmfs/volumes/datastore1/guest/guest.vmx" \
++   -o local -os /var/tmp
++
++The guest must not be running.  Virt-v2v would I<not> need to be run
++as root in this case.
++
++For more information about converting from VMX files see
++L</INPUT FROM VMWARE VMX> below.
++
+ =head2 Convert disk image to OpenStack glance
+ 
+ Given a disk image from another hypervisor that you want to convert to
+@@ -233,9 +250,10 @@ L</INPUT FROM VMWARE OVA> below
+ 
+ Set the input method to I<vmx>.
+ 
+-In this mode you can read a VMware vmx file directly.  This is useful
+-when VMware VMs are stored on an NFS server which you can mount
+-directly.  See L</INPUT FROM VMWARE VMX> below
++In this mode you can read a VMware vmx file directly or over SSH.
++This is useful when VMware VMs are stored on an NFS server which you
++can mount directly, or where you have access by SSH to an ESXi
++hypervisor.  See L</INPUT FROM VMWARE VMX> below
+ 
+ =item B<-ic> libvirtURI
+ 
+@@ -255,6 +273,11 @@ For I<-i disk> only, this specifies the format of the input disk
+ image.  For other input methods you should specify the input
+ format in the metadata.
+ 
++=item B<-it> B<ssh>
++
++When using I<-i vmx>, this enables the ssh transport.
++See L</INPUT FROM VMWARE VMX> below.
++
+ =item B<-it> B<vddk>
+ 
+ Use VMware VDDK as a transport to copy the input disks.  See
+@@ -1194,9 +1217,23 @@ directory containing the files:
+ 
+ =head1 INPUT FROM VMWARE VMX
+ 
+-Virt-v2v is able to import guests from VMware’s vmx files.  This is
+-useful where VMware virtual machines are stored on a separate NFS
+-server and you are able to mount the NFS storage directly.
++Virt-v2v is able to import guests from VMware’s vmx files.
++
++This is useful in two cases:
++
++=over 4
++
++=item 1.
++
++VMware virtual machines are stored on a separate NFS server and you
++are able to mount the NFS storage directly.
++
++=item 2.
++
++You have enabled SSH access to the VMware ESXi hypervisor and there is
++a C</vmfs/volumes> folder containing the virtual machines.
++
++=back
+ 
+ If you find a folder of files called F<I<guest>.vmx>,
+ F<I<guest>.vmxf>, F<I<guest>.nvram> and one or more F<.vmdk> disk
+@@ -1222,28 +1259,65 @@ With other methods, virt-v2v tries to prevent concurrent access, but
+ because the I<-i vmx> method works directly against the storage,
+ checking for concurrent access is not possible.
+ 
+-=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER
++=head2 VMX: ACCESS TO THE STORAGE CONTAINING THE VMX AND VMDK FILES
+ 
+-Virt-v2v must be able to access the F<.vmx> file and any local
+-F<.vmdk> disks.  Normally this means you must mount the NFS storage
+-containing these files.
++If the vmx and vmdk files aren't available locally then you must
++I<either> mount the NFS storage on the conversion server I<or> enable
++passwordless SSH on the ESXi hypervisor.
++
++=head3 VMX: Passwordless SSH using ssh-agent
++
++You must also use ssh-agent, and add your ssh public key to
++F</etc/ssh/keys-root/authorized_keys> (on the ESXi hypervisor).
++
++After doing this, you should check that passwordless access works from
++the virt-v2v server to the ESXi hypervisor.  For example:
++
++ $ ssh root@esxi.example.com
++ [ logs straight into the shell, no password is requested ]
++
++Note that password-interactive and Kerberos access are B<not>
++supported.  You B<have> to set up ssh access using ssh-agent and
++authorized_keys.
++
++=head3 VMX: Construct the SSH URI
++
++When using the SSH input transport you must specify a remote
++C<ssh://...> URI pointing to the VMX file.  A typical URI looks like:
++
++ ssh://root@esxi.example.com/vmfs/volumes/datastore1/my%20guest/my%20guest.vmx
++
++Any space must be escaped with C<%20> and other non-ASCII characters
++may also need to be URI-escaped.
++
++The username is not required if it is the same as your local username.
++
++You may optionally supply a port number after the hostname if the SSH
++server is not listening on the default port (22).
+ 
+ =head2 VMX: IMPORTING A GUEST
+ 
+-To import a vmx file, do:
++To import a vmx file from a local file or NFS, do:
+ 
+  $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp
+ 
++To import a vmx file over SSH, add I<-it ssh> to select the SSH
++transport and supply a remote SSH URI:
++
++ $ virt-v2v \
++     -i vmx -it ssh \
++     "ssh://root@esxi.example.com/vmfs/volumes/datastore1/guest/guest.vmx" \
++     -o local -os /var/tmp
++
+ Virt-v2v processes the vmx file and uses it to find the location of
+ any vmdk disks.
+ 
+ =head1 INPUT FROM VMWARE ESXi HYPERVISOR
+ 
+-Virt-v2v cannot access an ESXi hypervisor directly.  You should use
+-the OVA or VMX methods above (see L</INPUT FROM VMWARE OVA> and/or
+-L</INPUT FROM VMWARE VMX>) if possible, as it is much faster and
+-requires much less disk space than the method described in this
+-section.
++You should use the OVA or VMX methods above (see L</INPUT FROM VMWARE
++OVA> and/or L</INPUT FROM VMWARE VMX>) if possible, as it is much
++faster and requires much less disk space than the method described in
++this section.
+ 
+ You can use the L<virt-v2v-copy-to-local(1)> tool to copy the guest
+ off the hypervisor into a local file, and then convert it.
+-- 
+2.14.3
+
diff --git a/SOURCES/0078-builder-use-the-template-arch-when-caching-all-templ.patch b/SOURCES/0078-builder-use-the-template-arch-when-caching-all-templ.patch
new file mode 100644
index 0000000..7349fbb
--- /dev/null
+++ b/SOURCES/0078-builder-use-the-template-arch-when-caching-all-templ.patch
@@ -0,0 +1,153 @@
+From 244157fcea33dad2c99ca4b740b5483ed36e4238 Mon Sep 17 00:00:00 2001
+From: Pino Toscano <ptoscano@redhat.com>
+Date: Wed, 29 Nov 2017 15:29:57 +0100
+Subject: [PATCH] builder: use the template arch when caching all templates
+
+When caching all the templates, use the architecture of each template,
+instead of the architecture passed as --arch (or the host architecture,
+as default).  This way, the right destination filename will be used.
+
+Fixes commit b1cf6246f3c80762cf27dbdb24168589a34daf00.
+
+Thanks to: Erik Skultety.
+
+(cherry picked from commit b34f457cf2dd66626abf743c90881bfe6532ec9b)
+---
+ builder/Makefile.am                   |  2 +
+ builder/builder.ml                    |  4 +-
+ builder/test-virt-builder-cacheall.sh | 88 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 92 insertions(+), 2 deletions(-)
+ create mode 100755 builder/test-virt-builder-cacheall.sh
+
+diff --git a/builder/Makefile.am b/builder/Makefile.am
+index 2bbf1247a..c260a327f 100644
+--- a/builder/Makefile.am
++++ b/builder/Makefile.am
+@@ -28,6 +28,7 @@ EXTRA_DIST = \
+ 	test-simplestreams/streams/v1/index.json \
+ 	test-simplestreams/streams/v1/net.cirros-cloud_released_download.json \
+ 	test-virt-builder.sh \
++	test-virt-builder-cacheall.sh \
+ 	test-virt-builder-docs.sh \
+ 	test-virt-builder-list.sh \
+ 	test-virt-builder-list-simplestreams.sh \
+@@ -236,6 +237,7 @@ yajl_tests_LINK = \
+ 	  $(yajl_tests_THEOBJECTS) -o $@
+ 
+ TESTS = \
++	test-virt-builder-cacheall.sh \
+ 	test-virt-builder-docs.sh \
+ 	test-virt-builder-list.sh \
+ 	test-virt-index-validate.sh \
+diff --git a/builder/builder.ml b/builder/builder.ml
+index 213fd56a1..ce99e0339 100644
+--- a/builder/builder.ml
++++ b/builder/builder.ml
+@@ -251,8 +251,8 @@ let main () =
+         List.iter (
+           fun (name,
+                { Index.revision = revision; file_uri = file_uri;
+-                 proxy = proxy }) ->
+-            let template = name, cmdline.arch, revision in
++                 proxy = proxy; arch = arch }) ->
++            let template = name, arch, revision in
+             message (f_"Downloading: %s") file_uri;
+             let progress_bar = not (quiet ()) in
+             ignore (Downloader.download downloader ~template ~progress_bar
+diff --git a/builder/test-virt-builder-cacheall.sh b/builder/test-virt-builder-cacheall.sh
+new file mode 100755
+index 000000000..c80d9ecd2
+--- /dev/null
++++ b/builder/test-virt-builder-cacheall.sh
+@@ -0,0 +1,88 @@
++#!/bin/bash -
++# libguestfs virt-builder test script
++# Copyright (C) 2017 Red Hat Inc.
++#
++# 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 2 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, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++
++set -e
++
++$TEST_FUNCTIONS
++skip_if_skipped
++
++tmpdir="$(mktemp -d)"
++echo "tmpdir= $tmpdir"
++reposdir="$tmpdir/virt-builder/repos.d"
++repodir="$tmpdir/repo"
++indexfile="$repodir/index"
++cachedir="$tmpdir/cache"
++
++mkdir -p "$reposdir"
++mkdir -p "$repodir"
++
++# Create some fake images.
++img1_path="$repodir/img1.raw"
++img1_size=10485760  # 10G
++qemu-img create -f raw "$img1_path" $img1_size
++img1_csum=`do_sha256 "$img1_path"`
++
++img2_path="$repodir/img2.qcow2"
++img2_size=5242880  # 5G
++qemu-img create -f qcow2 "$img2_path" $img2_size
++img2_csum=`do_sha256 "$img2_path"`
++
++# Create an index for the images.
++cat > "$indexfile" <<EOF
++[img1]
++name=img1
++file=$(basename "$img1_path")
++arch=x86_64
++size=$img1_size
++checksum[sha512]=$img1_csum
++revision=1
++
++[img2]
++name=img2
++file=$(basename "$img2_path")
++arch=aarch64
++size=$img2_size
++checksum[sha512]=$img2_csum
++revision=3
++EOF
++
++# Create the repository.
++cat > "$reposdir/repo1.conf" <<EOF
++[repo1]
++uri=$indexfile
++EOF
++
++export XDG_CONFIG_HOME=
++export XDG_CONFIG_DIRS="$tmpdir"
++export XDG_CACHE_HOME="$cachedir"
++
++short_list=$($VG virt-builder --no-check-signature --no-cache --list)
++
++if [ "$short_list" != "img1                     x86_64     img1
++img2                     aarch64    img2" ]; then
++    echo "$0: unexpected --list output:"
++    echo "$short_list"
++    exit 1
++fi
++
++$VG virt-builder --no-check-signature --cache-all-templates
++ls -lh "$cachedir/virt-builder"
++test -f "$cachedir/virt-builder/img1.x86_64.1"
++test -f "$cachedir/virt-builder/img2.aarch64.3"
++
++rm -rf "$tmpdir"
+-- 
+2.14.3
+
diff --git a/SOURCES/0079-v2v-docs-Match-the-two-instances-of-path-to-nbdkit-i.patch b/SOURCES/0079-v2v-docs-Match-the-two-instances-of-path-to-nbdkit-i.patch
new file mode 100644
index 0000000..d39e580
--- /dev/null
+++ b/SOURCES/0079-v2v-docs-Match-the-two-instances-of-path-to-nbdkit-i.patch
@@ -0,0 +1,31 @@
+From 91971da7f4b7d4a0b6a77160e30f7f12b65e2927 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Mon, 18 Dec 2017 10:29:11 +0000
+Subject: [PATCH] v2v: docs: Match the two instances of /path/to/nbdkit in the
+ documentation.
+
+Fixes commit d81a2ee185599c23a128ab65be9d48b415abf461.
+See also:
+https://bugzilla.redhat.com/show_bug.cgi?id=1513884#c5
+
+(cherry picked from commit dab065a8eed6c6d8d9c53956393566812cfe6a2e)
+---
+ v2v/virt-v2v.pod | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
+index d0387734a..7d3923bda 100644
+--- a/v2v/virt-v2v.pod
++++ b/v2v/virt-v2v.pod
+@@ -1481,7 +1481,7 @@ To import a particular guest from vCenter server or ESXi hypervisor,
+ use a command like the following, substituting the URI, guest name and
+ SSL thumbprint:
+ 
+- $ export PATH=/path/to/nbdkit:$PATH
++ $ export PATH=/path/to/nbdkit-1.1.x:$PATH
+  $ virt-v2v \
+      -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \
+      -it vddk \
+-- 
+2.14.3
+
diff --git a/SOURCES/0080-launch-direct-Omit-locking-option-for-non-file-disks.patch b/SOURCES/0080-launch-direct-Omit-locking-option-for-non-file-disks.patch
new file mode 100644
index 0000000..a350111
--- /dev/null
+++ b/SOURCES/0080-launch-direct-Omit-locking-option-for-non-file-disks.patch
@@ -0,0 +1,33 @@
+From 05095797e4adf7c5afa807972c25dbe0998f5bcf Mon Sep 17 00:00:00 2001
+From: Lars Seipel <ls@slrz.net>
+Date: Thu, 23 Nov 2017 06:15:28 +0100
+Subject: [PATCH] launch: direct: Omit locking option for non-file disks
+ (RHBZ#1516094)
+
+QEMU does not accept options unrecognized by the block driver
+in use. Disable locking only for read-only disks that are
+file-backed, as that's the only block driver it is supported
+with.
+
+Signed-off-by: Lars Seipel <ls@slrz.net>
+(cherry picked from commit 35320dd0edb94d09d231bcded57aa883a5e7c784)
+---
+ lib/launch-direct.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/launch-direct.c b/lib/launch-direct.c
+index 0fef05927..4f31ac231 100644
+--- a/lib/launch-direct.c
++++ b/lib/launch-direct.c
+@@ -534,7 +534,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+          escaped_file,
+          drv->disk_label ? ",serial=" : "",
+          drv->disk_label ? drv->disk_label : "",
+-         data->qemu_mandatory_locking ? ",file.backing.file.locking=off" : "",
++         data->qemu_mandatory_locking && drv->src.protocol == drive_protocol_file ? ",file.backing.file.locking=off" : "",
+          i);
+     }
+ 
+-- 
+2.14.3
+
diff --git a/SOURCES/0081-launch-direct-Use-old-style-file-and-format-paramete.patch b/SOURCES/0081-launch-direct-Use-old-style-file-and-format-paramete.patch
new file mode 100644
index 0000000..6f809ef
--- /dev/null
+++ b/SOURCES/0081-launch-direct-Use-old-style-file-and-format-paramete.patch
@@ -0,0 +1,68 @@
+From 6db3412d15981d7624817d06999cb2ef4a03eed7 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 17 Jan 2018 10:11:53 +0000
+Subject: [PATCH] launch: direct: Use old-style file= and format= parameters
+ when not disabling locking (RHBZ#1503497).
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Ancient qemu 1.5 (in RHEL 7) does not understand the
+file.file.filename= and file.driver= parameters.  Go back to using the
+old-style file= and format= parameters when we're not trying to set
+the file.backing.file.locking=off parameter.
+
+Fixes commit 9fe592808ccfd9ed184b88ca9c6cad2e1798dee3.
+
+Thanks: Yongkui Guo, Václav Kadlčík.
+(cherry picked from commit a30b51747fc6605f50a9d5d8095fd2b6d1473b1c)
+---
+ lib/launch-direct.c | 32 +++++++++++++++++++++++++-------
+ 1 file changed, 25 insertions(+), 7 deletions(-)
+
+diff --git a/lib/launch-direct.c b/lib/launch-direct.c
+index 4f31ac231..3d6e72e78 100644
+--- a/lib/launch-direct.c
++++ b/lib/launch-direct.c
+@@ -529,13 +529,31 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
+     else {
+       /* Writable qcow2 overlay on top of read-only drive. */
+       escaped_file = guestfs_int_qemu_escape_param (g, drv->overlay);
+-      param = safe_asprintf
+-        (g, "file.file.filename=%s,cache=unsafe,file.driver=qcow2%s%s%s,id=hd%zu",
+-         escaped_file,
+-         drv->disk_label ? ",serial=" : "",
+-         drv->disk_label ? drv->disk_label : "",
+-         data->qemu_mandatory_locking && drv->src.protocol == drive_protocol_file ? ",file.backing.file.locking=off" : "",
+-         i);
++      if (data->qemu_mandatory_locking &&
++	/* Add the file-specific locking option only for files, as
++	 * qemu won't accept options unknown to the block driver in
++	 * use.
++	 */
++	drv->src.protocol == drive_protocol_file) {
++        param = safe_asprintf
++          (g, "file.file.filename=%s,file.driver=qcow2,file.backing.file.locking=off,cache=unsafe%s%s,id=hd%zu",
++           escaped_file,
++           drv->disk_label ? ",serial=" : "",
++           drv->disk_label ? drv->disk_label : "",
++           i);
++      } else {
++        /* Ancient qemu (esp. qemu 1.5 in RHEL 7) didn't understand the
++         * file.file.filename= parameter, so use the safer old-style
++         * form of parameters unless we actually want to specify the
++         * locking flag above.
++         */
++        param = safe_asprintf
++          (g, "file=%s,format=qcow2,cache=unsafe%s%s,id=hd%zu",
++           escaped_file,
++           drv->disk_label ? ",serial=" : "",
++           drv->disk_label ? drv->disk_label : "",
++           i);
++      }
+     }
+ 
+     /* If there's an explicit 'iface', use it.  Otherwise default to
+-- 
+2.14.3
+
diff --git a/SOURCES/brew-overrides.sh b/SOURCES/brew-overrides.sh
index 38baffe..ea91c18 100755
--- a/SOURCES/brew-overrides.sh
+++ b/SOURCES/brew-overrides.sh
@@ -8,30 +8,22 @@
 
 set -x
 
-# The kernel package doesn't install unless xfsprogs >= 4.3.0
-# is installed.
-xfsprogs="$(brew -q latest-pkg rhel-7.4-candidate xfsprogs |
-            awk '{print $1}')"
-
-# linux-firmware is for virt-p2v, see RHBZ#1364419
-linux_firmware="$(brew -q latest-pkg rhel-7.4-candidate linux-firmware |
-                  awk '{print $1}')"
-
 pkgs="
-  hivex-1.3.10-5.8.el7
-  libvirt-3.1.0-2.el7
-  libselinux-2.5-9.el7
-  $linux_firmware
-  ocaml-findlib-1.3.3-7.el7
-  policycoreutils-2.5-12.el7
-  rdma-core-13-1.el7
-  $xfsprogs
+  augeas-1.4.0-5.el7
+  hivex-1.3.10-6.9.el7
+  ocaml-4.05.0-6.el7
+  ocaml-camlp4-4.05.0-0.4.gitfc12d8c7.el7
+  ocaml-fileutils-0.4.4-9.el7
+  ocaml-findlib-1.7.3-7.el7
+  ocaml-gettext-0.3.7-1.el7
+  ocaml-srpm-macros-5-2.el7
+  supermin-5.1.19-1.el7
 "
 
 for pkg in $pkgs ; do
-    brew tag-pkg rhel-7.4-temp-override $pkg
+    brew tag-pkg rhel-7.5-temp-override $pkg
 done
 
 for pkg in $pkgs ; do
-    brew wait-repo rhel-7.4-build --build=$pkg
+    brew wait-repo rhel-7.5-build --build=$pkg
 done
diff --git a/SOURCES/copy-patches.sh b/SOURCES/copy-patches.sh
index 48bf28f..55eeb97 100755
--- a/SOURCES/copy-patches.sh
+++ b/SOURCES/copy-patches.sh
@@ -6,7 +6,7 @@ set -e
 # directory.  Use it like this:
 #   ./copy-patches.sh
 
-rhel_version=7.4
+rhel_version=7.5
 
 # Check we're in the right directory.
 if [ ! -f libguestfs.spec ]; then
diff --git a/SOURCES/libguestfs-1.36.10.tar.gz.sig b/SOURCES/libguestfs-1.36.10.tar.gz.sig
new file mode 100644
index 0000000..844b0b5
--- /dev/null
+++ b/SOURCES/libguestfs-1.36.10.tar.gz.sig
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIcBAABAgAGBQJZ6IBGAAoJEJFzj3Pht2igIyoQAKMmpv4f5kICU7LHte5uj7vi
+HY26QAPwlHe1YLDgfd8rPp3EIClqOP+F75mDdL2OBE8wmd8GSD2zWZF7RXtS90x3
+Q5DsBWfDrKrJPGZ/UfjrlKhbFSUui1yK/V6fMfw2RyLZmNgh3ykwxwsx7RmdcqYz
+/8ejIveqDHazvRdGHkCIXF8eAec+oYPMpmjufmoEMrkMTTcLQSUxZ0MvMC14L0z7
+K8lMp7UOa0P72GY3RYawgqIDKF1IbgTuNEeHb+7GXWjFELgqgRIyT/AQBduEdZEi
+dDPWTJgsX1px7HLiTG43FsdDDs0hIpI3l89BrgPX6IB1JlqGig4fg4HovlpS9B3U
+QMLSQORIjZUcViq2qHe2978ZaY1cV9R4oB0MYZxOVS/v7h8ED8aS5BmJTp+VBK8Y
+D9uhyebmGaDeIkRvxeqdDwsQcQb+kS8ivdw9keWguEYozG+G67p9LYg8jl/8bHek
+lktoJvIhrWdW0PrSIGrl++RJ4l/kv6jJsdpGwsySK2H4n7MeXangkxFtTluZpiWA
+0UoF6C0xnV2KfOPGODwOtrkGiU/k+0BGANZOqpMbqofaLV8mS4FnVsRtDyiVUN0R
+Q5RmrAvgfMt+vd0K57n55dr2+jxDtPtdGp/h2DD4g4uuacCe0jlUp1i+DYUi1H5/
+B3iWuIQHXwboqotBOtNQ
+=KIqK
+-----END PGP SIGNATURE-----
diff --git a/SOURCES/libguestfs-1.36.3.tar.gz.sig b/SOURCES/libguestfs-1.36.3.tar.gz.sig
deleted file mode 100644
index 10265fa..0000000
--- a/SOURCES/libguestfs-1.36.3.tar.gz.sig
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PGP SIGNATURE-----
-
-iQIcBAABAgAGBQJY1YWwAAoJEJFzj3Pht2ign80QAK4985NZFaRJn6cgoWtQJflH
-jjxSFkNokPUrA1LS3BFcHJyCaNldBn4FzMscdWYkVhVDe2K8HOq2wdWSt8tM1fFD
-A9pDMIWfdL2/t3UPDGlvf/h43mxE1y86i9LrHfKsjHUR22AGSJBrb5IUHNHS30P4
-4/4pik7t99ExDlMPHiAS4F0+Mnz22ATbVTsquewpBjB3S1jPTN5JQILY7NqAXvht
-Ua74xm6luDFNyr5XnKXRMW/oUxgsMY5cLXzwbGCREodjcvdWwBwdMjAHK0dXiOqC
-Y0oNF4/91wbn1yapAhR09t205A10n6J0ZswNWwEqgYQledahu7XFjkH0PRt1iDnd
-0Im29uuaEZP2PABrAIy95XLKiDBiKqBGFjIcqF3fmobPS3mLxVznLynmMOtQe2dJ
-gAULb/IcqonGXesL5npltAC6JPnMj9l+hFcyij+jGjBHAFF53lyq32lSvZ2gZ6K8
-B/Y9gNz2L3I7QZZCUIUxa+9KqIRndg2pDbEyJU5NOc2TEtbgo9JsVMxLtSAvDCNz
-UC6XZNZ4fh8qD4sLcgpWj2YLf+s1s+DSutcdMf6WR5Qae0rGx62z2ASJrIgPng79
-zU21SxdAOfL/h9VlCAVrLJ2vSf2WS91s1rf5WYAijS2tlz885wIUqZL91Nr1ivnf
-ZPMqpz6AVJXrgzDn2iQE
-=3M1c
------END PGP SIGNATURE-----
diff --git a/SPECS/libguestfs.spec b/SPECS/libguestfs.spec
index 4366c7a..6c0f1ab 100644
--- a/SPECS/libguestfs.spec
+++ b/SPECS/libguestfs.spec
@@ -13,8 +13,8 @@
 Summary:       Access and modify virtual machine disk images
 Name:          libguestfs
 Epoch:         1
-Version:       1.36.3
-Release:       6%{?dist}.3
+Version:       1.36.10
+Release:       6%{?dist}
 License:       LGPLv2+
 
 # Source and patches.
@@ -25,10 +25,10 @@ Source0:       http://libguestfs.org/download/1.36-stable/%{name}-%{version}.tar
 Source1:       http://libguestfs.org/download/1.36-stable/%{name}-%{version}.tar.gz.sig
 %endif
 
-ExclusiveArch: x86_64 %{power64} aarch64
+ExclusiveArch: x86_64 %{power64} aarch64 s390x
 
 # RHEL 7 git repository is:
-# https://github.com/libguestfs/libguestfs/tree/rhel-7.4
+# https://github.com/libguestfs/libguestfs/tree/rhel-7.5
 # Use 'copy-patches.sh' to copy the patches from the git repo
 # to the current directory.
 
@@ -56,27 +56,64 @@ Patch0020:     0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch
 Patch0021:     0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch
 Patch0022:     0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch
 Patch0023:     0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch
-Patch0024:     0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch
-Patch0025:     0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch
-Patch0026:     0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch
-Patch0027:     0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch
-Patch0028:     0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch
-Patch0029:     0029-p2v-Run-fewer-scp-commands.patch
-Patch0030:     0030-p2v-Fix-list-of-files-in-documentation.patch
-Patch0031:     0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch
-Patch0032:     0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch
-Patch0033:     0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch
-Patch0034:     0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch
-Patch0035:     0035-mllib-Add-Char.hexdigit-function.patch
-Patch0036:     0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch
-Patch0037:     0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch
-Patch0038:     0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch
-Patch0039:     0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch
-Patch0040:     0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch
-Patch0041:     0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch
-Patch0042:     0042-resize-make-sure-the-input-disk-is-read-only.patch
-Patch0043:     0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch
-Patch0044:     0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch
+Patch0024:     0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch
+Patch0025:     0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch
+Patch0026:     0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch
+Patch0027:     0027-p2v-Run-fewer-scp-commands.patch
+Patch0028:     0028-p2v-Fix-list-of-files-in-documentation.patch
+Patch0029:     0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch
+Patch0030:     0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch
+Patch0031:     0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch
+Patch0032:     0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch
+Patch0033:     0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch
+Patch0034:     0034-v2v-add-crypto-support-RHBZ-1451665.patch
+Patch0035:     0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch
+Patch0036:     0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch
+Patch0037:     0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch
+Patch0038:     0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch
+Patch0039:     0039-init-Add-comment-that-we-should-consider-using-proc-.patch
+Patch0040:     0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch
+Patch0041:     0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch
+Patch0042:     0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch
+Patch0043:     0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch
+Patch0044:     0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch
+Patch0045:     0045-v2v-vddk-Print-passthrough-options.patch
+Patch0046:     0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch
+Patch0047:     0047-v2v-vddk-Force-source-format-to-raw.patch
+Patch0048:     0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch
+Patch0049:     0049-v2v-vCenter-Refactor-the-API-to-this-module.patch
+Patch0050:     0050-v2v-vCenter-Split-up-get_session_cookie-function.patch
+Patch0051:     0051-v2v-vCenter-Factor-out-get_https_url-code.patch
+Patch0052:     0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch
+Patch0053:     0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch
+Patch0054:     0054-New-API-internal-get-console-socket-to-support-virt-.patch
+Patch0055:     0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch
+Patch0056:     0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch
+Patch0057:     0057-rescue-Implement-m-and-i-options.patch
+Patch0058:     0058-rescue-Implement-escape-sequences.patch
+Patch0059:     0059-rescue-Move-suggest-code-to-separate-file.patch
+Patch0060:     0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch
+Patch0061:     0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch
+Patch0062:     0062-rescue-Don-t-document-suggest-option-in-help-output.patch
+Patch0063:     0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch
+Patch0064:     0064-rescue-fix-size-check.patch
+Patch0065:     0065-rescue-initialize-CLEANUP-pointer-variable.patch
+Patch0066:     0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch
+Patch0067:     0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch
+Patch0068:     0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch
+Patch0069:     0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch
+Patch0070:     0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch
+Patch0071:     0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch
+Patch0072:     0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch
+Patch0073:     0073-v2v-vddk-Further-rework-documentation.patch
+Patch0074:     0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch
+Patch0075:     0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch
+Patch0076:     0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch
+Patch0077:     0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch
+Patch0078:     0078-builder-use-the-template-arch-when-caching-all-templ.patch
+Patch0079:     0079-v2v-docs-Match-the-two-instances-of-path-to-nbdkit-i.patch
+Patch0080:     0080-launch-direct-Omit-locking-option-for-non-file-disks.patch
+Patch0081:     0081-launch-direct-Use-old-style-file-and-format-paramete.patch
 
 # Use git for patch management.
 BuildRequires: git
@@ -141,7 +178,7 @@ BuildRequires: unzip
 BuildRequires: systemd-units
 BuildRequires: netpbm-progs
 BuildRequires: icoutils
-%ifnarch aarch64 %{power64}
+%ifnarch aarch64 %{power64} s390x
 # RHBZ#1177910
 BuildRequires: libvirt-daemon-kvm
 %endif
@@ -250,18 +287,10 @@ Requires:      fuse
 Requires:      /usr/bin/qemu-img
 
 # For libvirt backend.
-%ifarch %{ix86} x86_64 %{arm} aarch64 %{power64}
-Requires:      libvirt-daemon-kvm >= 1.2.8-3
-%endif
+# RHBZ#1500870, RHBZ#1501239
+Requires:      libvirt-daemon-kvm >= 3.9.0-1
 %ifarch aarch64
 Requires:      AAVMF
-# RHBZ#1177910
-# RHBZ#1463646
-Requires:      qemu-kvm
-%endif
-%ifarch %{power64}
-# RHBZ#1177910
-Requires:      qemu-kvm-rhev
 %endif
 
 # https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries#Packages_granted_exceptions
@@ -555,7 +584,7 @@ diskimage-builder command.  It is compatible with most
 diskimage-builder elements.
 
 
-%ifnarch %{power64}
+%ifnarch %{power64} s390x
 %package -n virt-v2v
 Summary:       Convert a virtual machine to run on KVM
 License:       GPLv2+
@@ -811,10 +840,7 @@ git commit -a -q -m "%{version} baseline"
 git am %{patches}
 
 # Patches affect Makefile.am and configure.ac, so rerun autotools.
-autoreconf
-autoconf
-
-mkdir -p daemon/m4
+autoreconf -fi
 
 # Replace developer-centric README that ships with libguestfs, with
 # our replacement file.
@@ -842,7 +868,7 @@ fi
 # brew, and for that reason we have to hack things here.  See:
 # https://bugzilla.redhat.com/show_bug.cgi?id=1125575#c18
 # https://bugzilla.redhat.com/show_bug.cgi?id=1177910
-%ifarch aarch64 %{power64}
+%ifarch aarch64 %{power64} s390x
 export vmchannel_test=no
 export QEMU=/usr/libexec/qemu-kvm
 %endif
@@ -874,7 +900,7 @@ make V=1 INSTALLDIRS=vendor %{?_smp_mflags}
 
 # Can't test on aarch64 or ppc64/ppc64le yet because we don't have
 # a working qemu available in brew.
-%ifnarch aarch64 %{power64}
+%ifnarch aarch64 %{power64} s390x
 
 # Note that the major tests are done after the package has been built.
 #
@@ -978,7 +1004,7 @@ mkdir -p $RPM_BUILD_ROOT%{_datadir}/virt-tools
 cp %{SOURCE96} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhsrvany.exe
 cp %{SOURCE97} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhev-apt.exe
 
-%ifarch %{power64}
+%ifarch %{power64} s390x
 # We don't ship virt-v2v on POWER (RHBZ#1287826).
 rm $RPM_BUILD_ROOT%{_bindir}/virt-p2v*
 rm $RPM_BUILD_ROOT%{_bindir}/virt-v2v*
@@ -996,7 +1022,7 @@ rm -rf $RPM_BUILD_ROOT%{_libdir}/ocaml/v2v_test_harness
 rm -rf $RPM_BUILD_ROOT%{_libdir}/ocaml/stublibs/dllv2v_test_harness*
 rm -f $RPM_BUILD_ROOT%{_mandir}/man1/virt-v2v-test-harness.1*
 
-%ifnarch %{power64}
+%ifnarch %{power64} s390x
 # Delete kiwi tools.
 rm $RPM_BUILD_ROOT%{_bindir}/virt-p2v-make-kiwi
 rm $RPM_BUILD_ROOT%{_mandir}/man1/virt-p2v-make-kiwi.1*
@@ -1166,7 +1192,7 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/
 %{_libdir}/guestfs/supermin.d/zz-packages-dib
 
 
-%ifnarch %{power64}
+%ifnarch %{power64} s390x
 %files -n virt-v2v
 %doc COPYING README v2v/TODO
 %{_bindir}/virt-v2v
@@ -1292,17 +1318,65 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/
 
 
 %changelog
-* Wed Aug 02 2017 Pino Toscano <ptoscano@redhat.com> - 1:1.36.3-6.el7_4.3
-- v2v: disable unconfiguration of manually installed VMware tools.
-  resolves: rhbz#1480623
-
-* Mon Jul 17 2017 Pino Toscano <ptoscano@redhat.com> - 1:1.36.3-6.el7_4.2
-- Make sure kernel-rt is never used as Requires.
-  resolves: rhbz#1471829
-
-* Wed Jul 12 2017 Pino Toscano <ptoscano@redhat.com> - 1:1.36.3-6.el7_4.1
+* Mon Jan 22 2018 Pino Toscano <ptoscano@redhat.com> - 1:1.36.10-6
+- Rebase to libguestfs 1.36.10 in RHEL 7.5.
+  resolves: rhbz#1472272
+- Build against OCaml 4.05
+  resolves: rhbz#1447981
 - Enable the copyonread flag when running the appliance using libvirt.
-  resolves: rhbz#1469902
+  resolves: rhbz#1466563
+- Make sure kernel-rt is never used as Requires.
+  resolves: rhbz#1471651
+- v2v: disable unconfiguration of manually installed VMware tools.
+  resolves: rhbz#1477905
+- v2v: prefer pigz or pxz for uncompressing OVA files, if available
+  resolves: rhbz#1448739
+- resize: handle empty UUIDs for swap partitions
+  resolves: rhbz#1482737
+- v2v: remove mention of --dcpath in an error message
+  resolves: rhbz#1486197
+- Disables the QEMU image file locking when opening disks as read-only
+  resolves: rhbz#1417306
+  resolves: rhbz#1503497
+- Briefly document the format used for URIs
+  resolves: rhbz#1450325
+- v2v: deal with grub2 configurations without a default set
+  resolves: rhbz#1472288
+- v2v: warn when a guest has passthrough devices
+  resolves: rhbz#1472719
+- v2v: fix three regular expressions
+  resolves: rhbz#1494555
+- v2v: enable conversion of full-disk LUKS-encrypted Linux guests
+  resolves: rhbz#1451665
+- v2v: new 'vddk' import method
+  resolves: rhbz#1477912
+  resolves: rhbz#1513884
+- Enable libguestfs to work on z Systems
+  resolves: rhbz#1479526
+- p2v: fx check for sudo requiring a password
+  resolves: rhbz#1500673
+- v2v: handle disks with snapshots in vCenter
+  resolves: rhbz#1172425
+- rescue: backport improved version
+  resolves: rhbz#1438710
+- v2v: improve bootloader detection
+  resolves: rhbz#1508299
+- v2v: parse MAC address of network interfaces in OVF files
+  resolves: rhbz#1506572
+- Unconditionally depend on libvirt-daemon-kvm >= 3.9.0-1, which will always
+  pull the right qemu-kvm too, and thus remove the unversioned dependencies
+  on it
+  resolves: rhbz#1500870
+- v2v: fix RPM file owned test
+  resolves: rhbz#1503958
+- Do not open read-only disks using <shareable/> in the libvirt backend
+  resolves: rhbz#1518517
+- v2v: handle better when grubby does not report any default kernel
+  resolves: rhbz#1519204
+- v2v: enhance vmx import method to access via SSH
+  resolves: rhbz#1523767
+- builder: fix caching of templates when using --cache-all-templates
+  resolves: rhbz#1523650
 
 * Thu Jun 22 2017 Pino Toscano <ptoscano@redhat.com> - 1:1.36.3-6
 - Rebase to libguestfs 1.36 in RHEL 7.4.