From e76f14f6debf7e776afa6d1360e77a57b4d7f76d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 03 2016 06:05:07 +0000 Subject: import libguestfs-1.32.7-3.el7 --- diff --git a/.gitignore b/.gitignore index 6d71182..7ed2d79 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ SOURCES/RHEV-Application-Provisioning-Tool.exe_4.12 -SOURCES/libguestfs-1.28.1.tar.gz +SOURCES/libguestfs-1.32.7.tar.gz +SOURCES/libguestfs.keyring SOURCES/rhsrvany.exe diff --git a/.libguestfs.metadata b/.libguestfs.metadata index f4542a4..f133307 100644 --- a/.libguestfs.metadata +++ b/.libguestfs.metadata @@ -1,3 +1,4 @@ 8fec32284530ce6d485629fcbd1f7f3e005ae8a0 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.12 -49b32fe74f1e856c9397213a25f2440375574514 SOURCES/libguestfs-1.28.1.tar.gz +601e78445b168478ac761517593716b3772f1c7b SOURCES/libguestfs-1.32.7.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 new file mode 100644 index 0000000..ad68535 --- /dev/null +++ b/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch @@ -0,0 +1,38 @@ +From bd1a920c9ada1d55f79f9e9e2693bd78a624f2ba Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 21 Dec 2012 15:50:11 +0000 +Subject: [PATCH] RHEL 7: Remove libguestfs live (RHBZ#798980). + +This isn't supported in RHEL 7. +--- + src/launch-unix.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/launch-unix.c b/src/launch-unix.c +index 973e14b..428fdc6 100644 +--- a/src/launch-unix.c ++++ b/src/launch-unix.c +@@ -37,6 +37,12 @@ + static int + launch_unix (guestfs_h *g, void *datav, const char *sockpath) + { ++ error (g, ++ "launch: In RHEL, only the 'libvirt' or 'direct' method is supported.\n" ++ "In particular, \"libguestfs live\" is not supported."); ++ return -1; ++ ++#if 0 + int r, daemon_sock = -1; + struct sockaddr_un addr; + uint32_t size; +@@ -108,6 +114,7 @@ launch_unix (guestfs_h *g, void *datav, const char *sockpath) + g->conn = NULL; + } + return -1; ++#endif + } + + static int +-- +1.8.3.1 + diff --git a/SOURCES/0001-v2v-Change-help-text-URLs-so-they-don-t-reference-es.patch b/SOURCES/0001-v2v-Change-help-text-URLs-so-they-don-t-reference-es.patch deleted file mode 100644 index 262fb55..0000000 --- a/SOURCES/0001-v2v-Change-help-text-URLs-so-they-don-t-reference-es.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 40ff641d49cec18b1d55277b4038d0b8f2f466b6 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 18 Oct 2014 13:53:19 +0100 -Subject: [PATCH] v2v: Change --help text URLs so they don't reference esx as - main server. - -(cherry picked from commit a7a5a223d4ca17b09a1e489fb3f147a2102f98d7) ---- - v2v/cmdline.ml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 0ef1338..6f8a964 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -190,9 +190,9 @@ let parse_cmdline () = - sprintf (f_"\ - %s: convert a guest to use KVM - -- virt-v2v -ic vpx://esx.example.com/Datacenter/esxi -os imported esx_guest -+ virt-v2v -ic vpx://vcenter.example.com/Datacenter/esxi -os imported esx_guest - -- virt-v2v -ic vpx://esx.example.com/Datacenter/esxi esx_guest \ -+ virt-v2v -ic vpx://vcenter.example.com/Datacenter/esxi esx_guest \ - -o rhev -os rhev.nfs:/export_domain --network rhevm - - virt-v2v -i libvirtxml guest-domain.xml -o local -os /var/tmp --- -1.8.3.1 - 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 new file mode 100644 index 0000000..1f12198 --- /dev/null +++ b/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch @@ -0,0 +1,344 @@ +From 46238a80e68fcb4c8b65b6f4aab050aa0316a8e7 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 18 Jul 2013 18:31:53 +0100 +Subject: [PATCH] RHEL 7: Remove 9p APIs from RHEL (RHBZ#921710). + +--- + Makefile.am | 2 +- + daemon/9p.c | 221 --------------------------------------------------- + daemon/Makefile.am | 1 - + generator/actions.ml | 23 ------ + gobject/Makefile.inc | 2 - + po/POTFILES | 2 - + 6 files changed, 1 insertion(+), 250 deletions(-) + delete mode 100644 daemon/9p.c + +diff --git a/Makefile.am b/Makefile.am +index 524e397..c77fc34 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -71,7 +71,7 @@ SUBDIRS += tests/xfs + SUBDIRS += tests/charsets + SUBDIRS += tests/xml + SUBDIRS += tests/mount-local +-SUBDIRS += tests/9p ++#SUBDIRS += tests/9p + SUBDIRS += tests/rsync + SUBDIRS += tests/bigdirs + SUBDIRS += tests/disk-labels +diff --git a/daemon/9p.c b/daemon/9p.c +deleted file mode 100644 +index a9e36d1..0000000 +--- a/daemon/9p.c ++++ /dev/null +@@ -1,221 +0,0 @@ +-/* libguestfs - the guestfsd daemon +- * Copyright (C) 2011 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 +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "daemon.h" +-#include "actions.h" +- +-#define BUS_PATH "/sys/bus/virtio/drivers/9pnet_virtio" +-GUESTFSD_EXT_CMD(str_mount, mount); +- +-static char *read_whole_file (const char *filename); +- +-/* https://bugzilla.redhat.com/show_bug.cgi?id=714981#c1 */ +-char ** +-do_list_9p (void) +-{ +- CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (r); +- +- DIR *dir; +- +- dir = opendir (BUS_PATH); +- if (!dir) { +- perror ("opendir: " BUS_PATH); +- if (errno != ENOENT) { +- reply_with_perror ("opendir: " BUS_PATH); +- return NULL; +- } +- +- /* If this directory doesn't exist, it probably means that +- * the virtio driver isn't loaded. Don't return an error +- * in this case, but return an empty list. +- */ +- if (end_stringsbuf (&r) == -1) +- return NULL; +- +- return take_stringsbuf (&r); +- } +- +- while (1) { +- struct dirent *d; +- +- errno = 0; +- d = readdir (dir); +- if (d == NULL) break; +- +- if (STRPREFIX (d->d_name, "virtio")) { +- char mount_tag_path[256]; +- snprintf (mount_tag_path, sizeof mount_tag_path, +- BUS_PATH "/%s/mount_tag", d->d_name); +- +- /* A bit unclear, but it looks like the virtio transport allows +- * the mount tag length to be unlimited (or up to 65536 bytes). +- * See: linux/include/linux/virtio_9p.h +- */ +- CLEANUP_FREE char *mount_tag = read_whole_file (mount_tag_path); +- if (mount_tag == 0) +- continue; +- +- if (add_string (&r, mount_tag) == -1) { +- closedir (dir); +- return NULL; +- } +- } +- } +- +- /* Check readdir didn't fail */ +- if (errno != 0) { +- reply_with_perror ("readdir: /sys/block"); +- closedir (dir); +- return NULL; +- } +- +- /* Close the directory handle */ +- if (closedir (dir) == -1) { +- reply_with_perror ("closedir: /sys/block"); +- return NULL; +- } +- +- /* Sort the tags. */ +- if (r.size > 0) +- sort_strings (r.argv, r.size); +- +- /* NULL terminate the list */ +- if (end_stringsbuf (&r) == -1) +- return NULL; +- +- return take_stringsbuf (&r); +-} +- +-/* Read whole file into dynamically allocated array. If there is an +- * error, DON'T call reply_with_perror, just return NULL. Returns a +- * \0-terminated string. +- */ +-static char * +-read_whole_file (const char *filename) +-{ +- char *r = NULL; +- size_t alloc = 0, size = 0; +- int fd; +- +- fd = open (filename, O_RDONLY|O_CLOEXEC); +- if (fd == -1) { +- perror (filename); +- return NULL; +- } +- +- while (1) { +- alloc += 256; +- char *r2 = realloc (r, alloc); +- if (r2 == NULL) { +- perror ("realloc"); +- free (r); +- close (fd); +- return NULL; +- } +- r = r2; +- +- /* The '- 1' in the size calculation ensures there is space below +- * to add \0 to the end of the input. +- */ +- ssize_t n = read (fd, r + size, alloc - size - 1); +- if (n == -1) { +- fprintf (stderr, "read: %s: %m\n", filename); +- free (r); +- close (fd); +- return NULL; +- } +- if (n == 0) +- break; +- size += n; +- } +- +- if (close (fd) == -1) { +- fprintf (stderr, "close: %s: %m\n", filename); +- free (r); +- return NULL; +- } +- +- r[size] = '\0'; +- +- return r; +-} +- +-/* Takes optional arguments, consult optargs_bitmask. */ +-int +-do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options) +-{ +- CLEANUP_FREE char *mp = NULL, *opts = NULL, *err = NULL; +- struct stat statbuf; +- int r; +- +- ABS_PATH (mountpoint, , return -1); +- +- mp = sysroot_path (mountpoint); +- if (!mp) { +- reply_with_perror ("malloc"); +- return -1; +- } +- +- /* Check the mountpoint exists and is a directory. */ +- if (stat (mp, &statbuf) == -1) { +- reply_with_perror ("%s", mountpoint); +- return -1; +- } +- if (!S_ISDIR (statbuf.st_mode)) { +- reply_with_perror ("%s: mount point is not a directory", mountpoint); +- return -1; +- } +- +- /* Add trans=virtio to the options. */ +- if ((optargs_bitmask & GUESTFS_MOUNT_9P_OPTIONS_BITMASK) && +- STRNEQ (options, "")) { +- if (asprintf (&opts, "trans=virtio,%s", options) == -1) { +- reply_with_perror ("asprintf"); +- return -1; +- } +- } +- else { +- opts = strdup ("trans=virtio"); +- if (opts == NULL) { +- reply_with_perror ("strdup"); +- return -1; +- } +- } +- +- r = command (NULL, &err, +- str_mount, "-o", opts, "-t", "9p", mount_tag, mp, NULL); +- if (r == -1) { +- reply_with_error ("%s on %s: %s", mount_tag, mountpoint, err); +- return -1; +- } +- +- return 0; +-} +diff --git a/daemon/Makefile.am b/daemon/Makefile.am +index 997d89f..20a6289 100644 +--- a/daemon/Makefile.am ++++ b/daemon/Makefile.am +@@ -83,7 +83,6 @@ endif + # https://rwmj.wordpress.com/2015/09/30/make-and-queuing-theory/#content + guestfsd_SOURCES = \ + stubs.c \ +- 9p.c \ + acl.c \ + actions.h \ + available.c \ +diff --git a/generator/actions.ml b/generator/actions.ml +index 304fd80..9248ded 100644 +--- a/generator/actions.ml ++++ b/generator/actions.ml +@@ -9359,29 +9359,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 +- name = "list_9p"; added = (1, 11, 12); +- style = RStringList "mounttags", [], []; +- proc_nr = Some 285; +- shortdesc = "list 9p filesystems"; +- longdesc = "\ +-List all 9p filesystems attached to the guest. A list of +-mount tags is returned." }; +- +- { defaults with +- name = "mount_9p"; added = (1, 11, 12); +- style = RErr, [String "mounttag"; String "mountpoint"], [OString "options"]; +- proc_nr = Some 286; +- camel_name = "Mount9P"; +- shortdesc = "mount 9p filesystem"; +- longdesc = "\ +-Mount the virtio-9p filesystem with the tag C on the +-directory C. +- +-If required, C will be automatically added to the options. +-Any other options required can be passed in the optional C +-parameter." }; +- +- { defaults with + name = "list_dm_devices"; added = (1, 11, 15); + style = RStringList "devices", [], []; + proc_nr = Some 287; +diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc +index 3bb8041..20c98ff 100644 +--- a/gobject/Makefile.inc ++++ b/gobject/Makefile.inc +@@ -87,7 +87,6 @@ guestfs_gobject_headers= \ + include/guestfs-gobject/optargs-mkfs_btrfs.h \ + include/guestfs-gobject/optargs-mkswap.h \ + include/guestfs-gobject/optargs-mktemp.h \ +- include/guestfs-gobject/optargs-mount_9p.h \ + include/guestfs-gobject/optargs-mount_local.h \ + include/guestfs-gobject/optargs-ntfsclone_out.h \ + include/guestfs-gobject/optargs-ntfsfix.h \ +@@ -173,7 +172,6 @@ guestfs_gobject_sources= \ + src/optargs-mkfs_btrfs.c \ + src/optargs-mkswap.c \ + src/optargs-mktemp.c \ +- src/optargs-mount_9p.c \ + src/optargs-mount_local.c \ + src/optargs-ntfsclone_out.c \ + src/optargs-ntfsfix.c \ +diff --git a/po/POTFILES b/po/POTFILES +index d025941..d4058ac 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -14,7 +14,6 @@ cat/ls.c + cat/visit.c + customize/crypt-c.c + customize/perl_edit-c.c +-daemon/9p.c + daemon/acl.c + daemon/augeas.c + daemon/available.c +@@ -213,7 +212,6 @@ gobject/src/optargs-mkfs.c + gobject/src/optargs-mkfs_btrfs.c + gobject/src/optargs-mkswap.c + gobject/src/optargs-mktemp.c +-gobject/src/optargs-mount_9p.c + gobject/src/optargs-mount_local.c + gobject/src/optargs-ntfsclone_out.c + gobject/src/optargs-ntfsfix.c +-- +1.8.3.1 + diff --git a/SOURCES/0002-mllib-Enhance-and-rename-detect_compression-function.patch b/SOURCES/0002-mllib-Enhance-and-rename-detect_compression-function.patch deleted file mode 100644 index 97af963..0000000 --- a/SOURCES/0002-mllib-Enhance-and-rename-detect_compression-function.patch +++ /dev/null @@ -1,93 +0,0 @@ -From c07dde3ade4465dc6de99fd0761cb2707fe65ac2 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 18 Oct 2014 18:41:01 +0100 -Subject: [PATCH] mllib: Enhance and rename 'detect_compression' function so it - can detect a few more file types. - -(cherry picked from commit d8e26d0e4dc3de649cf81584e8c060becd2e4531) ---- - builder/builder.ml | 6 +++++- - mllib/common_utils.ml | 29 ++++++++++++++++++++--------- - mllib/common_utils.mli | 6 ++---- - 3 files changed, 27 insertions(+), 14 deletions(-) - -diff --git a/builder/builder.ml b/builder/builder.ml -index 5195cfd..121c5fb 100644 ---- a/builder/builder.ml -+++ b/builder/builder.ml -@@ -315,8 +315,12 @@ let main () = - | None -> [] - | Some format -> [`Format, format] in - let compression_tag = -- match detect_compression template with -+ match detect_file_type template with - | `XZ -> [ `XZ, "" ] -+ | `GZip | `Tar | `Zip -> -+ eprintf (f_"%s: input file (%s) has an unsupported type\n") -+ prog template; -+ exit 1 - | `Unknown -> [] in - [ `Template, ""; `Filename, template; `Size, Int64.to_string size ] @ - format_tag @ compression_tag in -diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml -index adfad3f..295981c 100644 ---- a/mllib/common_utils.ml -+++ b/mllib/common_utils.ml -@@ -547,17 +547,28 @@ let rm_rf_only_files (g : Guestfs.guestfs) dir = - List.iter g#rm files - ) - --(* Detect compression of a file. -- * -- * Only detects the formats we need in virt-builder so far. -- *) --let detect_compression filename = -+(* Detect type of a file. *) -+let detect_file_type filename = - let chan = open_in filename in -- let buf = String.create 6 in -- really_input chan buf 0 6; -+ let get start size = -+ try -+ seek_in chan start; -+ let buf = String.create size in -+ really_input chan buf 0 size; -+ Some buf -+ with End_of_file | Invalid_argument _ -> None -+ in -+ let ret = -+ if get 0 6 = Some "\2537zXZ\000" then `XZ -+ else if get 0 4 = Some "PK\003\004" then `Zip -+ else if get 0 4 = Some "PK\005\006" then `Zip -+ else if get 0 4 = Some "PK\007\008" then `Zip -+ else if get 257 6 = Some "ustar\000" then `Tar -+ else if get 257 8 = Some "ustar\x20\x20\000" then `Tar -+ else if get 0 2 = Some "\x1f\x8b" then `GZip -+ else `Unknown in - close_in chan; -- if buf = "\2537zXZ\000" then `XZ -- else `Unknown -+ ret - - let is_block_device file = - try (Unix.stat file).Unix.st_kind = Unix.S_BLK -diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli -index d78fd70..112648a 100644 ---- a/mllib/common_utils.mli -+++ b/mllib/common_utils.mli -@@ -118,10 +118,8 @@ val rm_rf_only_files : Guestfs.guestfs -> string -> unit - - XXX Could be faster with a specific API for doing this. *) - --val detect_compression : string -> [`Unknown | `XZ] --(** Detect compression of a file. -- -- XXX Only detects the formats we need in virt-builder so far. *) -+val detect_file_type : string -> [`GZip | `Tar | `XZ | `Zip | `Unknown] -+(** Detect type of a file. *) - - val is_block_device : string -> bool - val is_char_device : string -> bool --- -1.8.3.1 - 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 new file mode 100644 index 0000000..56746fa --- /dev/null +++ b/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch @@ -0,0 +1,604 @@ +From b541b1915be389651e44954143e73531163cb1af Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 29 Jul 2013 14:47:56 +0100 +Subject: [PATCH] RHEL 7: Disable unsupported remote drive protocols + (RHBZ#962113). + +This disables support for unsupported remote drive protocols: + + * ftp + * ftps + * http + * https + * tftp + * gluster + * iscsi + * sheepdog + * ssh + +Note 'nbd' is not disabled, and of course 'file' works. + +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 | 21 ------- + fish/guestfish.pod | 64 ++------------------- + fish/test-add-uri.sh | 32 ----------- + generator/actions.ml | 50 +---------------- + src/drives.c | 8 +++ + src/guestfs.pod | 100 --------------------------------- + tests/disks/test-qemu-drive-libvirt.sh | 28 --------- + tests/disks/test-qemu-drive.sh | 60 -------------------- + 8 files changed, 15 insertions(+), 348 deletions(-) + +diff --git a/docs/guestfs-testing.pod b/docs/guestfs-testing.pod +index 2528604..b8093ee 100644 +--- a/docs/guestfs-testing.pod ++++ b/docs/guestfs-testing.pod +@@ -117,27 +117,6 @@ image. To exit, type C. + If you get an error, try enabling debugging (add C<-v> to the command + line). Also make sure that L succeeds. + +-=head2 Try to open a remote guest image with guestfish. +- +-B this test requires S 1.22> and S 1.5>. +-You may also have to disable libvirt by setting this: +- +- export LIBGUESTFS_BACKEND=direct +- +-If you have a disk image available over HTTP/FTP, try to open it. +- +- guestfish --ro -i --format=raw -a http://www.example.com/disk.img +- +-For SSH you will need to make sure that ssh-agent is set up so you +-don't need a password to log in to the remote machine. Then a command +-similar to this should work: +- +- guestfish --ro -i --format=raw \ +- -a ssh://remote.example.com/path/to/disk.img +- +-If you get an error, try enabling debugging (add C<-v> to the command +-line). Also make sure that L succeeds. +- + =head2 Run virt-alignment-scan on all your guests. + + Run L on guests or disk images: +diff --git a/fish/guestfish.pod b/fish/guestfish.pod +index c6f5663..05105e8 100644 +--- a/fish/guestfish.pod ++++ b/fish/guestfish.pod +@@ -131,9 +131,9 @@ To list what is available do: + + =head2 Remote drives + +-Access a remote disk using ssh: ++Access a remote disk using NBD: + +- guestfish -a ssh://example.com/path/to/disk.img ++ guestfish -a nbd://example.com + + =head2 Remote control + +@@ -1118,12 +1118,12 @@ L>. + On the command line, you can use the I<-a> option to add network + block devices using a URI-style format, for example: + +- guestfish -a ssh://root@example.com/disk.img ++ guestfish -a nbd://example.com + + URIs I be used with the L command. The equivalent + command using the API directly is: + +- > add /disk.img protocol:ssh server:tcp:example.com username:root ++ > add /disk.img protocol:nbd server:tcp:example.com + + The possible I<-a URI> formats are described below. + +@@ -1133,40 +1133,6 @@ The possible I<-a URI> formats are described below. + + Add the local disk image (or device) called F. + +-=head2 B<-a ftp://[user@]example.com[:port]/disk.img> +- +-=head2 B<-a ftps://[user@]example.com[:port]/disk.img> +- +-=head2 B<-a http://[user@]example.com[:port]/disk.img> +- +-=head2 B<-a https://[user@]example.com[:port]/disk.img> +- +-=head2 B<-a tftp://[user@]example.com[:port]/disk.img> +- +-Add a disk located on a remote FTP, HTTP or TFTP server. +- +-The equivalent API command would be: +- +- > add /disk.img protocol:(ftp|...) server:tcp:example.com +- +-=head2 B<-a gluster://example.com[:port]/volname/image> +- +-Add a disk image located on GlusterFS storage. +- +-The server is the one running C, and may be C. +- +-The equivalent API command would be: +- +- > add volname/image protocol:gluster server:tcp:example.com +- +-=head2 B<-a iscsi://example.com[:port]/target-iqn-name[/lun]> +- +-Add a disk located on an iSCSI server. +- +-The equivalent API command would be: +- +- > add target-iqn-name/lun protocol:iscsi server:tcp:example.com +- + =head2 B<-a nbd://example.com[:port]> + + =head2 B<-a nbd://example.com[:port]/exportname> +@@ -1201,28 +1167,6 @@ The equivalent API command would be: + + > add pool/disk protocol:rbd server:tcp:example.com:port + +-=head2 B<-a sheepdog://[example.com[:port]]/volume/image> +- +-Add a disk image located on a Sheepdog volume. +- +-The server name is optional. Although libguestfs and Sheepdog +-supports multiple servers, only at most one server can be specified +-when using this URI syntax. +- +-The equivalent API command would be: +- +- > add volume protocol:sheepdog [server:tcp:example.com] +- +-=head2 B<-a ssh://[user@]example.com[:port]/disk.img> +- +-Add a disk image located on a remote server, accessed using the Secure +-Shell (ssh) SFTP protocol. SFTP is supported out of the box by all +-major SSH servers. +- +-The equivalent API command would be: +- +- > add /disk protocol:ssh server:tcp:example.com [username:user] +- + =head1 PROGRESS BARS + + Some (not all) long-running commands send progress notification +diff --git a/fish/test-add-uri.sh b/fish/test-add-uri.sh +index 07b68c4..48c12b8 100755 +--- a/fish/test-add-uri.sh ++++ b/fish/test-add-uri.sh +@@ -37,14 +37,6 @@ function fail () + $VG guestfish -x -a file://$(pwd)/test-add-uri.img test-add-uri.out 2>&1 + grep -sq 'add_drive ".*/test-add-uri.img"' test-add-uri.out || fail + +-# curl +-$VG guestfish -x -a ftp://user@example.com/disk.img test-add-uri.out 2>&1 +-grep -sq 'add_drive "/disk.img" "protocol:ftp" "server:tcp:example.com" "username:user"' test-add-uri.out || fail +- +-# gluster +-$VG guestfish -x -a gluster://example.com/disk test-add-uri.out 2>&1 +-grep -sq 'add_drive "disk" "protocol:gluster" "server:tcp:example.com"' test-add-uri.out || fail +- + # NBD + $VG guestfish -x -a nbd://example.com test-add-uri.out 2>&1 + grep -sq 'add_drive "" "protocol:nbd" "server:tcp:example.com"' test-add-uri.out || fail +@@ -64,29 +56,5 @@ grep -sq 'add_drive "pool/disk" "protocol:rbd" "server:tcp:example.com:6789"' te + $VG guestfish -x -a rbd:///pool/disk test-add-uri.out 2>&1 + grep -sq 'add_drive "pool/disk" "protocol:rbd"' test-add-uri.out || fail + +-# sheepdog +-$VG guestfish -x -a sheepdog:///volume/image test-add-uri.out 2>&1 +-grep -sq 'add_drive "volume/image" "protocol:sheepdog"' test-add-uri.out || fail +- +-$VG guestfish -x -a sheepdog://example.com:3000/volume/image test-add-uri.out 2>&1 +-grep -sq 'add_drive "volume/image" "protocol:sheepdog" "server:tcp:example.com:3000"' test-add-uri.out || fail +- +-# ssh +-$VG guestfish -x -a ssh://example.com/disk.img test-add-uri.out 2>&1 +-grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com"' test-add-uri.out || fail +- +-$VG guestfish -x -a ssh://user@example.com/disk.img test-add-uri.out 2>&1 +-grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com" "username:user"' test-add-uri.out || fail +- +-$VG guestfish -x -a ssh://user@example.com:2000/disk.img test-add-uri.out 2>&1 +-grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com:2000" "username:user"' test-add-uri.out || fail +- +-# iSCSI +-$VG guestfish -x -a iscsi://example.com/iqn.2015-12.com.libguestfs:test1/0 test-add-uri.out 2>&1 +-grep -sq 'add_drive "iqn.2015-12.com.libguestfs:test1/0" "protocol:iscsi" "server:tcp:example.com"' test-add-uri.out || fail +- +-$VG guestfish -x -a iscsi://user:password@example.com/iqn.2015-12.com.libguestfs:test2/0 test-add-uri.out 2>&1 +-grep -sq 'add_drive "iqn.2015-12.com.libguestfs:test2/0" "protocol:iscsi" "server:tcp:example.com" "username:user" "secret:password"' test-add-uri.out || fail +- + rm test-add-uri.out + rm test-add-uri.img +diff --git a/generator/actions.ml b/generator/actions.ml +index 9248ded..dfeb34c 100644 +--- a/generator/actions.ml ++++ b/generator/actions.ml +@@ -1439,29 +1439,6 @@ F is interpreted as a local file or device. + This is the default if the optional protocol parameter + is omitted. + +-=item C +- +-Connect to a remote FTP, HTTP or TFTP server. +-The C parameter must also be supplied - see below. +- +-See also: L +- +-=item C +- +-Connect to the GlusterFS server. +-The C parameter must also be supplied - see below. +- +-See also: L +- +-=item C +- +-Connect to the iSCSI server. +-The C parameter must also be supplied - see below. +-The C parameter may be supplied. See below. +-The C parameter may be supplied. See below. +- +-See also: L. +- + =item C + + Connect to the Network Block Device server. +@@ -1478,22 +1455,6 @@ The C parameter may be supplied. See below. + + See also: L. + +-=item C +- +-Connect to the Sheepdog server. +-The C parameter may also be supplied - see below. +- +-See also: L. +- +-=item C +- +-Connect to the Secure Shell (ssh) server. +- +-The C parameter must be supplied. +-The C parameter may be supplied. See below. +- +-See also: L. +- + =back + + =item C +@@ -1504,13 +1465,8 @@ is a list of server(s). + Protocol Number of servers required + -------- -------------------------- + file List must be empty or param not used at all +- ftp|ftps|http|https|tftp Exactly one +- gluster Exactly one +- iscsi Exactly one + nbd Exactly one + rbd Zero or more +- sheepdog Zero or more +- ssh Exactly one + + Each list element is a string specifying a server. The string must be + in one of the following formats: +@@ -1526,10 +1482,10 @@ for the protocol is used (see F). + + =item C + +-For the C, C, C, C, C, C, C +-and C protocols, this specifies the remote username. ++For the C ++protocol, this specifies the remote username. + +-If not given, then the local username is used for C, and no authentication ++If not given, then no authentication + is attempted for ceph. But note this sometimes may give unexpected results, for + 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. If in doubt, +diff --git a/src/drives.c b/src/drives.c +index 5b54eca..309e312 100644 +--- a/src/drives.c ++++ b/src/drives.c +@@ -161,6 +161,7 @@ create_drive_non_file (guestfs_h *g, + return drv; + } + ++#if 0 /* DISABLED IN RHEL 7 */ + static struct drive * + create_drive_curl (guestfs_h *g, + const struct drive_create_data *data) +@@ -219,6 +220,7 @@ create_drive_gluster (guestfs_h *g, + + return create_drive_non_file (g, data); + } ++#endif /* DISABLED IN RHEL 7 */ + + static int + nbd_port (void) +@@ -287,6 +289,7 @@ create_drive_rbd (guestfs_h *g, + return create_drive_non_file (g, data); + } + ++#if 0 /* DISABLED IN RHEL 7 */ + static struct drive * + create_drive_sheepdog (guestfs_h *g, + const struct drive_create_data *data) +@@ -387,6 +390,7 @@ create_drive_iscsi (guestfs_h *g, + + return create_drive_non_file (g, data); + } ++#endif /* DISABLED IN RHEL 7 */ + + /* Traditionally you have been able to use /dev/null as a filename, as + * many times as you like. Ancient KVM (RHEL 5) cannot handle adding +@@ -840,6 +844,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, + drv = create_drive_file (g, &data); + } + } ++#if 0 /* DISABLED IN RHEL 7 */ + else if (STREQ (protocol, "ftp")) { + data.protocol = drive_protocol_ftp; + drv = create_drive_curl (g, &data); +@@ -864,6 +869,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, + data.protocol = drive_protocol_iscsi; + drv = create_drive_iscsi (g, &data); + } ++#endif /* DISABLED IN RHEL 7 */ + else if (STREQ (protocol, "nbd")) { + data.protocol = drive_protocol_nbd; + drv = create_drive_nbd (g, &data); +@@ -872,6 +878,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, + data.protocol = drive_protocol_rbd; + drv = create_drive_rbd (g, &data); + } ++#if 0 /* DISABLED IN RHEL 7 */ + else if (STREQ (protocol, "sheepdog")) { + data.protocol = drive_protocol_sheepdog; + drv = create_drive_sheepdog (g, &data); +@@ -884,6 +891,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, + data.protocol = drive_protocol_tftp; + drv = create_drive_curl (g, &data); + } ++#endif /* DISABLED IN RHEL 7 */ + else { + error (g, _("unknown protocol '%s'"), protocol); + drv = NULL; /*FALLTHROUGH*/ +diff --git a/src/guestfs.pod b/src/guestfs.pod +index dc41864..17d9a62 100644 +--- a/src/guestfs.pod ++++ b/src/guestfs.pod +@@ -705,70 +705,6 @@ servers. The server string is documented in + L. The C and C parameters are + also optional, and if not given, then no authentication will be used. + +-=head3 FTP, HTTP AND TFTP +- +-Libguestfs can access remote disks over FTP, FTPS, HTTP, HTTPS +-or TFTP protocols. +- +-To do this, set the optional C and C parameters of +-L like this: +- +- char **servers = { "www.example.org", NULL }; +- guestfs_add_drive_opts (g, "/disk.img", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "http", +- GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, +- -1); +- +-The C can be one of C<"ftp">, C<"ftps">, C<"http">, +-C<"https"> or C<"tftp">. +- +-C (the C parameter) is a list which must have a +-single element. The single element is a string defining the web, +-FTP or TFTP server. The format of this string is documented in +-L. +- +-=head3 GLUSTER +- +-Libguestfs can access Gluster disks. +- +-To do this, set the optional C and C parameters of +-L like this: +- +- char **servers = { "gluster.example.org:24007", NULL }; +- guestfs_add_drive_opts (g, "volname/image", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "gluster", +- GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, +- -1); +- +-C (the C parameter) is a list which must have a +-single element. The single element is a string defining the Gluster +-server. The format of this string is documented in +-L. +- +-Note that gluster usually requires the client process (ie. libguestfs) +-to run as B and will give unfathomable errors if it is not +-(eg. "No data available"). +- +-=head3 ISCSI +- +-Libguestfs can access iSCSI disks remotely. +- +-To do this, set the optional C and C parameters like +-this: +- +- char **server = { "iscsi.example.org:3000", NULL }; +- guestfs_add_drive_opts (g, "target-iqn-name/lun", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "iscsi", +- GUESTFS_ADD_DRIVE_OPTS_SERVER, server, +- -1); +- +-The C parameter is a list which must have a single element. +-The single element is a string defining the iSCSI server. The format +-of this string is documented in L. +- + =head3 NETWORK BLOCK DEVICE + + Libguestfs can access Network Block Device (NBD) disks remotely. +@@ -831,42 +767,6 @@ L + + =back + +-=head3 SHEEPDOG +- +-Libguestfs can access Sheepdog disks. +- +-To do this, set the optional C and C parameters of +-L like this: +- +- char **servers = { /* optional servers ... */ NULL }; +- guestfs_add_drive_opts (g, "volume", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "sheepdog", +- GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, +- -1); +- +-The optional list of C may be zero or more server addresses +-(C<"hostname:port">). The format of the server strings is documented +-in L. +- +-=head3 SSH +- +-Libguestfs can access disks over a Secure Shell (SSH) connection. +- +-To do this, set the C and C and (optionally) +-C parameters of L like this: +- +- char **server = { "remote.example.com", NULL }; +- guestfs_add_drive_opts (g, "/path/to/disk.img", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "ssh", +- GUESTFS_ADD_DRIVE_OPTS_SERVER, server, +- GUESTFS_ADD_DRIVE_OPTS_USERNAME, "remoteuser", +- -1); +- +-The format of the server string is documented in +-L. +- + =head2 INSPECTION + + 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 215a99e..894e9df 100755 +--- a/tests/disks/test-qemu-drive-libvirt.sh ++++ b/tests/disks/test-qemu-drive-libvirt.sh +@@ -76,34 +76,6 @@ check_output + grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail + 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 +-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 +-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 +-rm "$DEBUG_QEMU_FILE" +- +-# Sheepdog. +- +-$guestfish -d sheepdog run ||: +-check_output +-grep -sq -- '-drive file=sheepdog:volume,' "$DEBUG_QEMU_FILE" || fail +-rm "$DEBUG_QEMU_FILE" +- + # To do: + + # HTTP - curl not yet supported by libvirt +diff --git a/tests/disks/test-qemu-drive.sh b/tests/disks/test-qemu-drive.sh +index bcb7841..c0239ff 100755 +--- a/tests/disks/test-qemu-drive.sh ++++ b/tests/disks/test-qemu-drive.sh +@@ -61,45 +61,6 @@ check_output + grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail + rm "$DEBUG_QEMU_FILE" + +-# HTTP. +- +-guestfish < -Date: Sat, 18 Oct 2014 18:41:43 +0100 -Subject: [PATCH] v2v: -i ova: Allow directories and ZIP files to be used as - input (RHBZ#1152998). - -OVA is not a particularly well-specified format. The specification -allows a directory to be an OVA, so enable that. The spec doesn't -mention that ZIP can be used in place of tar, but since we have seen -these in the wild, allow that too. - -(cherry picked from commit 60405e5aa1b89ce4ad8b27efb992e82e38d6dbeb) ---- - README | 2 ++ - configure.ac | 7 +++++++ - v2v/input_ova.ml | 44 ++++++++++++++++++++++++++++++++++---------- - 3 files changed, 43 insertions(+), 10 deletions(-) - -diff --git a/README b/README -index b88a67d..30e241a 100644 ---- a/README -+++ b/README -@@ -179,6 +179,8 @@ The full requirements are described below. - +--------------+-------------+---+-----------------------------------------+ - | gtk2 | | O | Used by virt-p2v user interface. | - +--------------+-------------+---+-----------------------------------------+ -+| zip, unzip | | O | Used by virt-v2v for OVA files. | -++--------------+-------------+---+-----------------------------------------+ - | python-evtx | | O | Used by virt-log to parse Windows | - | | | | Event Log files. | - +--------------+-------------+---+-----------------------------------------+ -diff --git a/configure.ac b/configure.ac -index e11739d..74c72a1 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -720,6 +720,13 @@ if test "x$YACC" = "xyacc"; then - AC_MSG_FAILURE([GNU 'bison' is required (yacc won't work).]) - fi - -+dnl zip/unzip, used by virt-v2v -+AC_PATH_PROGS([ZIP],[zip],[no]) -+AC_DEFINE_UNQUOTED([ZIP],["$ZIP"],[Name of zip program.]) -+AM_CONDITIONAL([HAVE_ZIP],[test "x$ZIP" != "xno"]) -+AC_PATH_PROGS([UNZIP],[unzip],[no]) -+AC_DEFINE_UNQUOTED([UNZIP],["$UNZIP"],[Name of unzip program.]) -+ - dnl Check for QEMU for running binaries on this $host_cpu, fall - dnl back to basic 'qemu'. Allow the user to override it. - qemu_system="$( -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 7088e32..4ad38a0 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -36,13 +36,37 @@ object - method as_options = "-i ova " ^ ova - - method source () = -- (* Extract ova (tar) file. *) -- let cmd = sprintf "tar -xf %s -C %s" (quote ova) (quote tmpdir) in -- if verbose then printf "%s\n%!" cmd; -- if Sys.command cmd <> 0 then -- error (f_"error unpacking %s, see earlier error messages") ova; -+ (* Extract ova file. *) -+ let exploded = -+ (* The spec allows a directory to be specified as an ova. This -+ * is also pretty convenient. -+ *) -+ if is_directory ova then ova -+ else ( -+ match detect_file_type ova with -+ | `Tar -> -+ (* Normal ovas are tar file (not compressed). *) -+ let cmd = sprintf "tar -xf %s -C %s" (quote ova) (quote tmpdir) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ error (f_"error unpacking %s, see earlier error messages") ova; -+ tmpdir -+ | `Zip -> -+ (* However, although not permitted by the spec, people ship -+ * zip files as ova too. -+ *) -+ let cmd = sprintf "unzip%s -j -d %s %s" -+ (if verbose then "" else " -q") -+ (quote tmpdir) (quote ova) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ error (f_"error unpacking %s, see earlier error messages") ova; -+ tmpdir -+ | `GZip | `XZ | `Unknown -> -+ error (f_"%s: unsupported file format") ova -+ ) in - -- let files = Sys.readdir tmpdir in -+ let files = Sys.readdir exploded in - let ovf = ref "" in - (* Search for the ovf file. *) - Array.iter ( -@@ -58,13 +82,13 @@ object - Array.iter ( - fun mf -> - if Filename.check_suffix mf ".mf" then ( -- let chan = open_in (tmpdir // mf) in -+ let chan = open_in (exploded // mf) in - let rec loop () = - let line = input_line chan in - if Str.string_match rex line 0 then ( - let disk = Str.matched_group 1 line in - let expected = Str.matched_group 2 line in -- let cmd = sprintf "sha1sum %s" (quote (tmpdir // disk)) in -+ let cmd = sprintf "sha1sum %s" (quote (exploded // disk)) in - let out = external_command ~prog cmd in - match out with - | [] -> -@@ -86,7 +110,7 @@ object - ) files; - - (* Parse the ovf file. *) -- let xml = read_whole_file (tmpdir // ovf) in -+ let xml = read_whole_file (exploded // ovf) in - let doc = Xml.parse_memory xml in - - (* Handle namespaces. *) -@@ -164,7 +188,7 @@ object - let expr = sprintf "/ovf:Envelope/ovf:References/ovf:File[@ovf:id='%s']/@ovf:href" file_ref in - let file_name = xpath_to_string expr "" in - let disk = { -- s_qemu_uri= tmpdir // file_name; -+ s_qemu_uri= exploded // file_name; - s_format = Some "vmdk"; - s_target_dev = Some target_dev; - } in --- -1.8.3.1 - 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 new file mode 100644 index 0000000..77c228f --- /dev/null +++ b/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch @@ -0,0 +1,72 @@ +From 9fe323359240b77e8feb6104fc1518084ed8ecf9 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 19 Sep 2014 13:38:20 +0100 +Subject: [PATCH] RHEL 7: Remove User-Mode Linux (RHBZ#1144197). + +This isn't supported in RHEL 7. +--- + src/launch-uml.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/src/launch-uml.c b/src/launch-uml.c +index 0e2149e..38be7a8 100644 +--- a/src/launch-uml.c ++++ b/src/launch-uml.c +@@ -44,7 +44,9 @@ struct backend_uml_data { + char umid[UML_UMID_LEN+1]; /* umid=<...> unique ID. */ + }; + ++#if 0 + static void print_vmlinux_command_line (guestfs_h *g, char **argv); ++#endif + + /* 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) + return make_cow_overlay (g, drv->src.u.path); + } + ++#if 0 + /* 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) + + return true; + } ++#endif + + static int + launch_uml (guestfs_h *g, void *datav, const char *arg) + { ++ error (g, ++ "launch: In RHEL, only the 'libvirt' or 'direct' method is supported.\n" ++ "In particular, User-Mode Linux (UML) is not supported."); ++ return -1; ++ ++#if 0 + struct backend_uml_data *data = datav; + CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline); + int console_sock = -1, daemon_sock = -1; +@@ -488,8 +498,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) + } + g->state = CONFIG; + return -1; ++#endif + } + ++#if 0 + /* 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. +@@ -519,6 +531,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv) + + fputc ('\n', stderr); + } ++#endif + + static int + shutdown_uml (guestfs_h *g, void *datav, int check_for_errors) +-- +1.8.3.1 + diff --git a/SOURCES/0004-v2v-Handle-.vmdk.gz-compressed-files-RHBZ-1152998.patch b/SOURCES/0004-v2v-Handle-.vmdk.gz-compressed-files-RHBZ-1152998.patch deleted file mode 100644 index 6607f01..0000000 --- a/SOURCES/0004-v2v-Handle-.vmdk.gz-compressed-files-RHBZ-1152998.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 356511f6d9079bb121b211dae4a95a6127ce817f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 18 Oct 2014 18:54:12 +0100 -Subject: [PATCH] v2v: Handle *.vmdk.gz compressed files (RHBZ#1152998). - -The OVA spec allows the disk images to be gzipped within the OVA -container. - -(cherry picked from commit ede39a7591122abe29fc6de29aaa717ee9f8bb55) ---- - v2v/input_ova.ml | 26 ++++++++++++++++++++++++-- - 1 file changed, 24 insertions(+), 2 deletions(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 4ad38a0..001a579 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -181,14 +181,36 @@ object - let file_id = xpath_to_string "rasd:HostResource/text()" "" in - let rex = Str.regexp "^ovf:/disk/\\(.*\\)" in - if Str.string_match rex file_id 0 then ( -+ (* Chase the references through to the actual file name. *) - let file_id = Str.matched_group 1 file_id in - let expr = sprintf "/ovf:Envelope/ovf:DiskSection/ovf:Disk[@ovf:diskId='%s']/@ovf:fileRef" file_id in - let file_ref = xpath_to_string expr "" in - if file_ref == "" then error (f_"error parsing disk fileRef"); - let expr = sprintf "/ovf:Envelope/ovf:References/ovf:File[@ovf:id='%s']/@ovf:href" file_ref in -- let file_name = xpath_to_string expr "" in -+ let filename = xpath_to_string expr "" in -+ -+ (* Does the file exist and is it readable? *) -+ let filename = exploded // filename in -+ Unix.access filename [Unix.R_OK]; -+ -+ (* The spec allows the file to be gzip-compressed, in which case -+ * we must uncompress it into the tmpdir. -+ *) -+ let filename = -+ if detect_file_type filename = `GZip then ( -+ let new_filename = tmpdir // string_random8 () ^ ".vmdk" in -+ let cmd = -+ sprintf "zcat %s > %s" (quote filename) (quote new_filename) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ error (f_"error uncompressing %s, see earlier error messages") -+ filename; -+ new_filename -+ ) -+ else filename in -+ - let disk = { -- s_qemu_uri= exploded // file_name; -+ s_qemu_uri = filename; - s_format = Some "vmdk"; - s_target_dev = Some target_dev; - } in --- -1.8.3.1 - 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 new file mode 100644 index 0000000..65138cc --- /dev/null +++ b/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch @@ -0,0 +1,33 @@ +From dde41f2d45bcefb187d471deaf989a262a1f37f8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 28 Sep 2014 19:14:43 +0100 +Subject: [PATCH] RHEL 7: v2v: Select correct qemu binary for -o qemu mode + (RHBZ#1147313). + +RHEL 7 does not have qemu-system-x86_64 (etc), and in addition the +qemu binary is located in /usr/libexec. Encode the path to this +binary directly in the script. + +Note that we don't support people running qemu directly like this. +It's just for quick testing of converted VMs, and to help us with +support cases. +--- + 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 9bef83b..d079ccd 100644 +--- a/v2v/output_qemu.ml ++++ b/v2v/output_qemu.ml +@@ -76,7 +76,7 @@ object + fpf "\n" + ); + +- fpf "qemu-system-%s" guestcaps.gcaps_arch; ++ fpf "/usr/libexec/qemu-kvm"; + fpf "%s-no-user-config -nodefaults" nl; + fpf "%s-name %s" nl (quote source.s_name); + fpf "%s-machine accel=kvm:tcg" nl; +-- +1.8.3.1 + diff --git a/SOURCES/0005-v2v-i-ova-Add-a-test-for-ZIP-as-a-container-RHBZ-115.patch b/SOURCES/0005-v2v-i-ova-Add-a-test-for-ZIP-as-a-container-RHBZ-115.patch deleted file mode 100644 index 8d5199b..0000000 --- a/SOURCES/0005-v2v-i-ova-Add-a-test-for-ZIP-as-a-container-RHBZ-115.patch +++ /dev/null @@ -1,291 +0,0 @@ -From d6dd4275c08f7eafa71e97ac29c78f430d4dcaed Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 18 Oct 2014 21:45:10 +0100 -Subject: [PATCH] v2v: -i ova: Add a test for ZIP as a container - (RHBZ#1152998). - -(cherry picked from commit f27a582b6dd85a2810351cf7c2d2c98dc5ea6e9a) ---- - v2v/Makefile.am | 5 +- - v2v/test-v2v-i-ova-zip.expected | 15 +++++ - v2v/test-v2v-i-ova-zip.ovf | 138 ++++++++++++++++++++++++++++++++++++++++ - v2v/test-v2v-i-ova-zip.sh | 77 ++++++++++++++++++++++ - 4 files changed, 234 insertions(+), 1 deletion(-) - create mode 100644 v2v/test-v2v-i-ova-zip.expected - create mode 100644 v2v/test-v2v-i-ova-zip.ovf - create mode 100755 v2v/test-v2v-i-ova-zip.sh - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index 2092621..e9856fd 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -25,6 +25,8 @@ EXTRA_DIST = \ - test-v2v-i-ova.xml \ - test-v2v-i-ova-two-disks.expected \ - test-v2v-i-ova-two-disks.ovf \ -+ test-v2v-i-ova-zip.expected \ -+ test-v2v-i-ova-zip.ovf \ - test-v2v-networks-and-bridges-expected.xml \ - test-v2v-networks-and-bridges.xml.in \ - virt-v2v.pod -@@ -218,7 +220,8 @@ CLEANFILES += stamp-virt-v2v.pod - TESTS_ENVIRONMENT = $(top_builddir)/run --test - - TESTS = \ -- test-v2v-i-ova-two-disks.sh -+ test-v2v-i-ova-two-disks.sh \ -+ test-v2v-i-ova-zip.sh - - if ENABLE_APPLIANCE - TESTS += \ -diff --git a/v2v/test-v2v-i-ova-zip.expected b/v2v/test-v2v-i-ova-zip.expected -new file mode 100644 -index 0000000..a835f00 ---- /dev/null -+++ b/v2v/test-v2v-i-ova-zip.expected -@@ -0,0 +1,15 @@ -+Source guest information (--print-source option): -+ -+ source name: 2K8R2EESP1_2_Medium -+hypervisor type: vmware -+ memory: 1073741824 (bytes) -+ nr vCPUs: 1 -+ CPU features: -+ display: -+disks: -+ disk1.vmdk (vmdk) [hda] -+removable media: -+ CD-ROM [hda] -+NICs: -+ Network "Network adapter 1" -+ -diff --git a/v2v/test-v2v-i-ova-zip.ovf b/v2v/test-v2v-i-ova-zip.ovf -new file mode 100644 -index 0000000..3c685f4 ---- /dev/null -+++ b/v2v/test-v2v-i-ova-zip.ovf -@@ -0,0 +1,138 @@ -+ -+ -+ -+ -+ -+ -+ Virtual disk information -+ -+ -+ -+ The list of logical networks -+ -+ The PG-VLAN60 network -+ -+ -+ -+ A virtual machine -+ 2K8R2EESP1_2_Medium -+ -+ The kind of installed guest operating system -+ Microsoft Windows Server 2008 R2 (64-bit) -+ -+ -+ Virtual hardware requirements -+ -+ Virtual Hardware Family -+ 0 -+ 2K8R2EESP1_2_Medium -+ vmx-10 -+ -+ -+ hertz * 10^6 -+ Number of Virtual CPUs -+ 1 virtual CPU(s) -+ 1 -+ 3 -+ 1 -+ -+ -+ byte * 2^20 -+ Memory Size -+ 1024MB of memory -+ 2 -+ 4 -+ 1024 -+ -+ -+ 0 -+ SCSI Controller -+ SCSI controller 0 -+ 3 -+ lsilogicsas -+ 6 -+ -+ -+ -+ 1 -+ IDE Controller -+ IDE 1 -+ 4 -+ 5 -+ -+ -+ 0 -+ IDE Controller -+ IDE 0 -+ 5 -+ 5 -+ -+ -+ false -+ Video card -+ 6 -+ 24 -+ -+ -+ -+ -+ -+ -+ false -+ VMCI device -+ 7 -+ vmware.vmci -+ 1 -+ -+ -+ -+ -+ 0 -+ false -+ CD/DVD drive 1 -+ 8 -+ 4 -+ vmware.cdrom.atapi -+ 15 -+ -+ -+ 0 -+ Hard disk 1 -+ ovf:/disk/vmdisk1 -+ 9 -+ 3 -+ 17 -+ -+ -+ -+ 7 -+ true -+ PG-VLAN60 -+ E1000 ethernet adapter on "PG-VLAN60" -+ Network adapter 1 -+ 11 -+ E1000 -+ 10 -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/v2v/test-v2v-i-ova-zip.sh b/v2v/test-v2v-i-ova-zip.sh -new file mode 100755 -index 0000000..cd1e258 ---- /dev/null -+++ b/v2v/test-v2v-i-ova-zip.sh -@@ -0,0 +1,77 @@ -+#!/bin/bash - -+# libguestfs virt-v2v test script -+# Copyright (C) 2014 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 with a zip file. -+ -+unset CDPATH -+export LANG=C -+set -e -+ -+if [ -n "$SKIP_TEST_V2V_I_OVA_ZIP_SH" ]; then -+ echo "$0: test skipped because environment variable is set" -+ exit 77 -+fi -+ -+if ! zip --version >/dev/null 2>&1; then -+ echo "$0: test skipped because 'zip' utility is not available" -+ exit 77 -+fi -+ -+if ! unzip --help >/dev/null 2>&1; then -+ echo "$0: test skipped because 'unzip' utility is not available" -+ exit 77 -+fi -+ -+if [ "$(guestfish get-backend)" = "uml" ]; then -+ echo "$0: test skipped because UML backend does not support network" -+ exit 77 -+fi -+ -+virt_tools_data_dir=${VIRT_TOOLS_DATA_DIR:-/usr/share/virt-tools} -+if ! test -r $virt_tools_data_dir/rhsrvany.exe; then -+ echo "$0: test skipped because rhsrvany.exe is not installed" -+ exit 77 -+fi -+ -+d=test-v2v-i-ova-zip.d -+rm -rf $d -+mkdir $d -+ -+pushd $d -+ -+# Create a phony OVA. This is only a test of source parsing, not -+# conversion, so the contents of the disks doesn't matter. -+truncate -s 10k disk1.vmdk -+sha=`sha1sum disk1.vmdk | awk '{print $1}'` -+echo -e "SHA1(disk1.vmdk)=$sha\r" > disk1.mf -+ -+zip -r test ../test-v2v-i-ova-zip.ovf disk1.vmdk disk1.mf -+mv test.zip test.ova -+popd -+ -+# Run virt-v2v but only as far as the --print-source stage, and -+# normalize the output. -+$VG virt-v2v --debug-gc --quiet \ -+ -i ova $d/test.ova \ -+ --print-source | -+sed 's,[^ \t]*\(disk.*.vmdk\),\1,' > $d/source -+ -+# Check the parsed source is what we expect. -+diff -u test-v2v-i-ova-zip.expected $d/source -+ -+rm -rf $d --- -1.8.3.1 - 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 new file mode 100644 index 0000000..03d6b7d --- /dev/null +++ b/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch @@ -0,0 +1,77 @@ +From a613c11f034b736741b053e65823935161961ddd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Sep 2014 10:50:27 +0100 +Subject: [PATCH] RHEL 7: v2v: Disable the --qemu-boot option (RHBZ#1147313). + +This cannot work because there is no Gtk or SDL output mode +in RHEL 7's qemu-kvm. + +In addition you will have to edit the -display option in the +qemu script. +--- + v2v/cmdline.ml | 3 ++- + v2v/virt-v2v.pod | 13 ------------- + 2 files changed, 2 insertions(+), 14 deletions(-) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index e8785c4..32eb873 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -214,7 +214,6 @@ let parse_cmdline () = + "--password-file", Arg.String (set_string_option_once "--password-file" password_file), + "file " ^ s_"Use password from file"; + "--print-source", Arg.Set print_source, " " ^ s_"Print source and stop"; +- "--qemu-boot", Arg.Set qemu_boot, " " ^ s_"Boot in qemu (-o qemu only)"; + "--root", Arg.String set_root_choice,"ask|... " ^ s_"How to choose root filesystem"; + "--vdsm-image-uuid", Arg.String add_vdsm_image_uuid, "uuid " ^ s_"Output image UUID(s)"; + "--vdsm-vol-uuid", Arg.String add_vdsm_vol_uuid, "uuid " ^ s_"Output vol UUID(s)"; +@@ -416,6 +415,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 ++ if qemu_boot then ++ error (f_"-o qemu: the --qemu-boot option cannot be used in RHEL"); + Output_qemu.output_qemu os qemu_boot + + | `RHEV -> +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 0cde486..dcbaec2 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -145,11 +145,6 @@ Since F contains the path(s) to the guest disk + image(s) you do not need to specify the name of the disk image on the + command line. + +-To convert a local disk image and immediately boot it in local +-qemu, do: +- +- virt-v2v -i disk disk.img -o qemu -os /var/tmp --qemu-boot +- + =head1 SUPPORT MATRIX + + =head2 Hypervisors (Input) +@@ -478,9 +473,6 @@ This is similar to I<-o local>, except that a shell script is written + which you can use to boot the guest in qemu. The converted disks and + shell script are written to the directory specified by I<-os>. + +-When using this output mode, you can also specify the I<--qemu-boot> +-option which boots the guest under qemu immediately. +- + =item B<-o rhev> + + Set the output method to I. +@@ -566,11 +558,6 @@ Print information about the source guest and stop. This option is + useful when you are setting up network and bridge maps. + See L. + +-=item B<--qemu-boot> +- +-When using I<-o qemu> only, this boots the guest immediately after +-virt-v2v finishes. +- + =item B<-q> + + =item B<--quiet> +-- +1.8.3.1 + diff --git a/SOURCES/0006-v2v-i-ova-Add-a-test-for-.vmdk.gz-compressed-files-R.patch b/SOURCES/0006-v2v-i-ova-Add-a-test-for-.vmdk.gz-compressed-files-R.patch deleted file mode 100644 index bf2a0ac..0000000 --- a/SOURCES/0006-v2v-i-ova-Add-a-test-for-.vmdk.gz-compressed-files-R.patch +++ /dev/null @@ -1,277 +0,0 @@ -From a731003f6a9c28c5ccae79976580571bfff3912f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 18 Oct 2014 21:57:10 +0100 -Subject: [PATCH] v2v: -i ova: Add a test for *.vmdk.gz compressed files - (RHBZ#1152998). - -(cherry picked from commit 9019c4eb0621397163f0092c5c00ebb969d14152) ---- - v2v/Makefile.am | 3 + - v2v/test-v2v-i-ova-gz.expected | 15 +++++ - v2v/test-v2v-i-ova-gz.ovf | 138 +++++++++++++++++++++++++++++++++++++++++ - v2v/test-v2v-i-ova-gz.sh | 65 +++++++++++++++++++ - 4 files changed, 221 insertions(+) - create mode 100644 v2v/test-v2v-i-ova-gz.expected - create mode 100644 v2v/test-v2v-i-ova-gz.ovf - create mode 100755 v2v/test-v2v-i-ova-gz.sh - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index e9856fd..c311623 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -23,6 +23,8 @@ EXTRA_DIST = \ - HACKING README.RHEV-M \ - test-v2v-i-ova.ovf \ - test-v2v-i-ova.xml \ -+ test-v2v-i-ova-gz.expected \ -+ test-v2v-i-ova-gz.ovf \ - test-v2v-i-ova-two-disks.expected \ - test-v2v-i-ova-two-disks.ovf \ - test-v2v-i-ova-zip.expected \ -@@ -220,6 +222,7 @@ CLEANFILES += stamp-virt-v2v.pod - TESTS_ENVIRONMENT = $(top_builddir)/run --test - - TESTS = \ -+ test-v2v-i-ova-gz.sh \ - test-v2v-i-ova-two-disks.sh \ - test-v2v-i-ova-zip.sh - -diff --git a/v2v/test-v2v-i-ova-gz.expected b/v2v/test-v2v-i-ova-gz.expected -new file mode 100644 -index 0000000..7631534 ---- /dev/null -+++ b/v2v/test-v2v-i-ova-gz.expected -@@ -0,0 +1,15 @@ -+Source guest information (--print-source option): -+ -+ source name: 2K8R2EESP1_2_Medium -+hypervisor type: vmware -+ memory: 1073741824 (bytes) -+ nr vCPUs: 1 -+ CPU features: -+ display: -+disks: -+ .vmdk (vmdk) [hda] -+removable media: -+ CD-ROM [hda] -+NICs: -+ Network "Network adapter 1" -+ -diff --git a/v2v/test-v2v-i-ova-gz.ovf b/v2v/test-v2v-i-ova-gz.ovf -new file mode 100644 -index 0000000..e10ad2b ---- /dev/null -+++ b/v2v/test-v2v-i-ova-gz.ovf -@@ -0,0 +1,138 @@ -+ -+ -+ -+ -+ -+ -+ Virtual disk information -+ -+ -+ -+ The list of logical networks -+ -+ The PG-VLAN60 network -+ -+ -+ -+ A virtual machine -+ 2K8R2EESP1_2_Medium -+ -+ The kind of installed guest operating system -+ Microsoft Windows Server 2008 R2 (64-bit) -+ -+ -+ Virtual hardware requirements -+ -+ Virtual Hardware Family -+ 0 -+ 2K8R2EESP1_2_Medium -+ vmx-10 -+ -+ -+ hertz * 10^6 -+ Number of Virtual CPUs -+ 1 virtual CPU(s) -+ 1 -+ 3 -+ 1 -+ -+ -+ byte * 2^20 -+ Memory Size -+ 1024MB of memory -+ 2 -+ 4 -+ 1024 -+ -+ -+ 0 -+ SCSI Controller -+ SCSI controller 0 -+ 3 -+ lsilogicsas -+ 6 -+ -+ -+ -+ 1 -+ IDE Controller -+ IDE 1 -+ 4 -+ 5 -+ -+ -+ 0 -+ IDE Controller -+ IDE 0 -+ 5 -+ 5 -+ -+ -+ false -+ Video card -+ 6 -+ 24 -+ -+ -+ -+ -+ -+ -+ false -+ VMCI device -+ 7 -+ vmware.vmci -+ 1 -+ -+ -+ -+ -+ 0 -+ false -+ CD/DVD drive 1 -+ 8 -+ 4 -+ vmware.cdrom.atapi -+ 15 -+ -+ -+ 0 -+ Hard disk 1 -+ ovf:/disk/vmdisk1 -+ 9 -+ 3 -+ 17 -+ -+ -+ -+ 7 -+ true -+ PG-VLAN60 -+ E1000 ethernet adapter on "PG-VLAN60" -+ Network adapter 1 -+ 11 -+ E1000 -+ 10 -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/v2v/test-v2v-i-ova-gz.sh b/v2v/test-v2v-i-ova-gz.sh -new file mode 100755 -index 0000000..6c630fb ---- /dev/null -+++ b/v2v/test-v2v-i-ova-gz.sh -@@ -0,0 +1,65 @@ -+#!/bin/bash - -+# libguestfs virt-v2v test script -+# Copyright (C) 2014 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 with gzip-compressed disks. -+ -+unset CDPATH -+export LANG=C -+set -e -+ -+if [ -n "$SKIP_TEST_V2V_I_OVA_GZ_SH" ]; then -+ echo "$0: test skipped because environment variable is set" -+ exit 77 -+fi -+ -+if [ "$(guestfish get-backend)" = "uml" ]; then -+ echo "$0: test skipped because UML backend does not support network" -+ exit 77 -+fi -+ -+virt_tools_data_dir=${VIRT_TOOLS_DATA_DIR:-/usr/share/virt-tools} -+if ! test -r $virt_tools_data_dir/rhsrvany.exe; then -+ echo "$0: test skipped because rhsrvany.exe is not installed" -+ exit 77 -+fi -+ -+d=test-v2v-i-ova-gz.d -+rm -rf $d -+mkdir $d -+ -+pushd $d -+ -+truncate -s 10k disk1.vmdk -+gzip disk1.vmdk -+sha=`sha1sum disk1.vmdk | awk '{print $1}'` -+echo -e "SHA1(disk1.vmdk)=$sha\r" > disk1.mf -+ -+tar -cf test.ova ../test-v2v-i-ova-gz.ovf disk1.vmdk.gz disk1.mf -+popd -+ -+# Run virt-v2v but only as far as the --print-source stage, and -+# normalize the output. -+$VG virt-v2v --debug-gc --quiet \ -+ -i ova $d/test.ova \ -+ --print-source | -+sed 's,[^ \t]*\(\.vmdk\),\1,' > $d/source -+ -+# Check the parsed source is what we expect. -+diff -u test-v2v-i-ova-gz.expected $d/source -+ -+rm -rf $d --- -1.8.3.1 - 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 new file mode 100644 index 0000000..687cec7 --- /dev/null +++ b/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch @@ -0,0 +1,74 @@ +From bad8f20afb430335fe956354233dc5b7fc2d583c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Oct 2014 16:44:00 +0100 +Subject: [PATCH] RHEL 7: Revert "tests: rsync: Skip this test when the backend + is libvirt." + +This reverts commit 765dc6237ce7b93dd2f33d99be53eae92e048a7a. +--- + tests/rsync/test-rsync.sh | 35 +++++++---------------------------- + 1 file changed, 7 insertions(+), 28 deletions(-) + +diff --git a/tests/rsync/test-rsync.sh b/tests/rsync/test-rsync.sh +index c7bfa24..214b5cd 100755 +--- a/tests/rsync/test-rsync.sh ++++ b/tests/rsync/test-rsync.sh +@@ -33,33 +33,10 @@ if ! rsync --help >/dev/null 2>&1; then + exit 77 + fi + +-# Get host IP address. XXX Bit of a hack. +-backend="$(guestfish get-backend)" +-case "$backend" in +- direct) +- ip=169.254.2.2 +- listen_address=localhost +- ;; +- libvirt|libvirt:*) +- # This would work, except that the host firewall is effective +- # on virbr0, and that is likely to block the non-standard port +- # number that we listen on. +-# ip="$(ip -4 -o address show virbr0 | +-# awk '{print $4}' | +-# awk -F/ '{print $1}')" +-# listen_address="$ip" +- echo "$0: skipping test because host firewall will probably prevent this test from working" +- exit 77 +- ;; +- uml) +- echo "$0: skipping test because networking is not available in the UML backend" +- exit 77 +- ;; +- *) +- echo "$0: don't know how to get IP address of backend $backend" +- exit 77 +- ;; +-esac ++if [ "$(guestfish get-backend)" = "uml" ]; then ++ echo "$0: skipping test because networking is not available in the UML backend" ++ exit 77 ++fi + + # If rsync is not available, bail. + if ! guestfish -a /dev/null run : available rsync; then +@@ -79,7 +56,7 @@ port="$(awk 'BEGIN{srand(); print 65000+int(500*rand())}' rsyncd.conf < -Date: Mon, 13 Oct 2014 15:51:34 +0200 -Subject: [PATCH] ls: in CSV mode, always have a checksum field (RHBZ#1151900). - -Make sure to output the field for checksum even for non-regular files, -as empty, in CSV output mode. This ensures each line has the same number -of fields, regardless of the file type. - -(cherry picked from commit e5befcacc5f7c1a6bd67fcdb92afede1a82d50eb) ---- - cat/ls.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) - -diff --git a/cat/ls.c b/cat/ls.c -index de8248e..2cb4e74 100644 ---- a/cat/ls.c -+++ b/cat/ls.c -@@ -524,12 +524,15 @@ show_file (const char *dir, const char *name, - - path = full_path (dir, name); - -- if (checksum && is_reg (stat->st_mode)) { -- csum = guestfs_checksum (g, checksum, path); -- if (!csum) -- exit (EXIT_FAILURE); -+ if (checksum) { -+ if (is_reg (stat->st_mode)) { -+ csum = guestfs_checksum (g, checksum, path); -+ if (!csum) -+ exit (EXIT_FAILURE); - -- output_string (csum); -+ output_string (csum); -+ } else if (csv) -+ output_string (""); - } - - output_string (path); --- -1.8.3.1 - 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 new file mode 100644 index 0000000..85fe423 --- /dev/null +++ b/SOURCES/0008-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch @@ -0,0 +1,28 @@ +From 8ad3cf74a354bb5656c909f0ad6eba00895ea67c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Oct 2014 16:44:04 +0100 +Subject: [PATCH] RHEL 7: Revert "appliance: Change example ping lines to ping + 8.8.8.8." + +This reverts commit 07c0926b588db5c86214917b609c2f477c817c0e. +--- + appliance/init | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/appliance/init b/appliance/init +index 311a0d4..a36d52b 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -146,7 +146,8 @@ if test "$guestfs_verbose" = 1; then + date + echo -n "clocksource: " + cat /sys/devices/system/clocksource/clocksource0/current_clocksource +- #ping -n -v -c 5 8.8.8.8 ++ #ping -n -v -c 5 10.0.2.2 ++ #ping -n -v -c 5 10.0.2.4 + + echo -n "uptime: "; cat /proc/uptime + fi +-- +1.8.3.1 + diff --git a/SOURCES/0008-cat-diff-avoid-double-slashes-in-paths-RHBZ-1151910.patch b/SOURCES/0008-cat-diff-avoid-double-slashes-in-paths-RHBZ-1151910.patch deleted file mode 100644 index 6bcfcfa..0000000 --- a/SOURCES/0008-cat-diff-avoid-double-slashes-in-paths-RHBZ-1151910.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 970ac8e8d3b4add1c31086f211b8796365287bbc Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 13 Oct 2014 16:49:59 +0200 -Subject: [PATCH] cat, diff: avoid double slashes in paths (RHBZ#1151910). - -In full_path, skip the trailing slash in the base directory when -different than "/", as the slash will eventually be added when building -the resulting path. - -(cherry picked from commit 87941d183f4a96b4d936c2e94a79a60288f0dc74) ---- - cat/visit.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/cat/visit.c b/cat/visit.c -index 963beb8..49b779e 100644 ---- a/cat/visit.c -+++ b/cat/visit.c -@@ -138,13 +138,18 @@ full_path (const char *dir, const char *name) - { - int r; - char *path; -+ int len; -+ -+ len = strlen (dir); -+ if (len > 0 && dir[len - 1] == '/') -+ --len; - - if (STREQ (dir, "/")) - r = asprintf (&path, "/%s", name ? name : ""); - else if (name) -- r = asprintf (&path, "%s/%s", dir, name); -+ r = asprintf (&path, "%.*s/%s", len, dir, name); - else -- r = asprintf (&path, "%s", dir); -+ r = asprintf (&path, "%.*s", len, dir); - - if (r == -1) { - perror ("asprintf"); --- -1.8.3.1 - 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 new file mode 100644 index 0000000..7cd408b --- /dev/null +++ b/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch @@ -0,0 +1,119 @@ +From 59f2770eb35f03d61fc708a6241628c83c4f786a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Oct 2014 16:44:07 +0100 +Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Use qemu-bridge-helper to + implement a full network (RHBZ#1148012)." + +This reverts commit 224de20b9a8d5ea56f6337f19b4ca237bb88eca0. +--- + src/guestfs.pod | 10 ---------- + src/launch-libvirt.c | 44 +++++++++++++++++++++----------------------- + 2 files changed, 21 insertions(+), 33 deletions(-) + +diff --git a/src/guestfs.pod b/src/guestfs.pod +index 17d9a62..af30406 100644 +--- a/src/guestfs.pod ++++ b/src/guestfs.pod +@@ -1432,16 +1432,6 @@ On Fedora, install C for the C file + (containing symbols). Make sure the symbols precisely match the + kernel being used. + +-=head3 network_bridge +- +-The libvirt backend supports: +- +- export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=virbrX +- +-This allows you to override the bridge that is connected to when the +-network is enabled. The default is C. See also +-L. +- + =head2 ATTACHING TO RUNNING DAEMONS + + I This is B and has a tendency to eat +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index ec23fab..38ca4a5 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -115,7 +115,6 @@ struct backend_libvirt_data { + char *selinux_label; + char *selinux_imagelabel; + bool selinux_norelabel_disks; +- char *network_bridge; + char name[DOMAIN_NAME_LEN]; /* random name */ + bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/ + unsigned long libvirt_version; /* libvirt version */ +@@ -422,12 +421,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"); +- if (g->enable_network) { +- data->network_bridge = +- guestfs_get_backend_setting (g, "network_bridge"); +- if (!data->network_bridge) +- data->network_bridge = safe_strdup (g, "virbr0"); +- } + guestfs_pop_error_handler (g); + + if (g->enable_network && check_bridge_exists (g, data->network_bridge) == -1) +@@ -1366,19 +1359,6 @@ construct_libvirt_xml_devices (guestfs_h *g, + } end_element (); + } end_element (); + +- /* Connect to libvirt bridge (see: RHBZ#1148012). */ +- if (g->enable_network) { +- start_element ("interface") { +- attribute ("type", "bridge"); +- start_element ("source") { +- attribute ("bridge", params->data->network_bridge); +- } end_element (); +- start_element ("model") { +- attribute ("type", "virtio"); +- } end_element (); +- } end_element (); +- } +- + } end_element (); /* */ + + return 0; +@@ -1741,6 +1721,27 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, + attribute ("value", tmpdir); + } end_element (); + ++ /* Workaround because libvirt user networking cannot specify "net=" ++ * parameter. ++ */ ++ if (g->enable_network) { ++ start_element ("qemu:arg") { ++ attribute ("value", "-netdev"); ++ } end_element (); ++ ++ start_element ("qemu:arg") { ++ attribute ("value", "user,id=usernet,net=169.254.0.0/16"); ++ } end_element (); ++ ++ start_element ("qemu:arg") { ++ attribute ("value", "-device"); ++ } end_element (); ++ ++ start_element ("qemu:arg") { ++ attribute ("value", VIRTIO_NET ",netdev=usernet"); ++ } end_element (); ++ } ++ + /* The qemu command line arguments requested by the caller. */ + for (hp = g->hv_params; hp; hp = hp->next) { + start_element ("qemu:arg") { +@@ -2056,9 +2057,6 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) + free (data->selinux_imagelabel); + data->selinux_imagelabel = NULL; + +- free (data->network_bridge); +- data->network_bridge = NULL; +- + for (i = 0; i < data->nr_secrets; ++i) + free (data->secrets[i].secret); + free (data->secrets); +-- +1.8.3.1 + diff --git a/SOURCES/0009-diff-do-not-pad-uid-gid-in-CSV-mode.patch b/SOURCES/0009-diff-do-not-pad-uid-gid-in-CSV-mode.patch deleted file mode 100644 index 908c17d..0000000 --- a/SOURCES/0009-diff-do-not-pad-uid-gid-in-CSV-mode.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 5d1a88d2feae5c37adcfd50b7873b31019cfc4ed Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Oct 2014 11:10:22 +0200 -Subject: [PATCH] diff: do not pad uid/gid in CSV mode - -(cherry picked from commit 3276845df1847d037fc4a5bed24966e0f9a0d564) ---- - diff/diff.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/diff/diff.c b/diff/diff.c -index f4b25e9..ad371b0 100644 ---- a/diff/diff.c -+++ b/diff/diff.c -@@ -1108,7 +1108,7 @@ output_int64_uid (int64_t i) - { - next_field (); - /* csv doesn't need escaping */ -- if (printf ("%4" PRIi64, i) < 0) { -+ if (printf (csv ? "%" PRIi64 : "%4" PRIi64, i) < 0) { - perror ("printf"); - exit (EXIT_FAILURE); - } --- -1.8.3.1 - 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 new file mode 100644 index 0000000..ffb289b --- /dev/null +++ b/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch @@ -0,0 +1,86 @@ +From e43178e3a02b89cf7119be371c9eab4b8101bff3 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 21 Sep 2015 12:38:50 -0400 +Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Better error when bridge / + virbr0 doesn't exist (RHBZ#1262127)." + +This reverts commit edcd02a965ae6675c0ee9ecd8d98a1a641c6ef60. +--- + src/launch-libvirt.c | 47 ----------------------------------------------- + 1 file changed, 47 deletions(-) + +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index 38ca4a5..4b87301 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -156,7 +156,6 @@ static int is_blk (const char *path); + static void ignore_errors (void *ignore, virErrorPtr ignore2); + static void set_socket_create_context (guestfs_h *g); + static void clear_socket_create_context (guestfs_h *g); +-static int check_bridge_exists (guestfs_h *g, const char *brname); + + #if HAVE_LIBSELINUX + static void selinux_warning (guestfs_h *g, const char *func, const char *selinux_op, const char *data); +@@ -423,9 +422,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); + +- if (g->enable_network && check_bridge_exists (g, data->network_bridge) == -1) +- goto cleanup; +- + /* Locate and/or build the appliance. */ + TRACE0 (launch_build_libvirt_appliance_start); + +@@ -1979,49 +1975,6 @@ is_blk (const char *path) + return S_ISBLK (statbuf.st_mode); + } + +-static int +-is_dir (const char *path) +-{ +- struct stat statbuf; +- +- if (stat (path, &statbuf) == -1) +- return 0; +- return S_ISDIR (statbuf.st_mode); +-} +- +-/* Used to check the network_bridge exists, or give a useful error +- * message. +- */ +-static int +-check_bridge_exists (guestfs_h *g, const char *brname) +-{ +- CLEANUP_FREE char *path = NULL; +- +- /* If this doesn't look like Linux, give up. */ +- if (!is_dir ("/sys/class/net")) +- return 0; +- +- /* Does the interface exist and is it a bridge? */ +- path = safe_asprintf (g, "/sys/class/net/%s/bridge", brname); +- if (is_dir (path)) +- return 0; +- +- error (g, +- _("bridge '%s' not found. Try running:\n" +- "\n" +- " brctl show\n" +- "\n" +- "to get a list of bridges on the host, and then selecting the\n" +- "bridge you wish the appliance network to connect to using:\n" +- "\n" +- " export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=\n" +- "\n" +- "You may also need to allow the bridge in /etc/qemu/bridge.conf.\n" +- "For further information see guestfs(3)."), +- brname); +- return -1; +-} +- + static void + ignore_errors (void *ignore, virErrorPtr ignore2) + { +-- +1.8.3.1 + diff --git a/SOURCES/0010-appliance-Set-udev.event-timeout-to-override-default.patch b/SOURCES/0010-appliance-Set-udev.event-timeout-to-override-default.patch deleted file mode 100644 index 5767e95..0000000 --- a/SOURCES/0010-appliance-Set-udev.event-timeout-to-override-default.patch +++ /dev/null @@ -1,35 +0,0 @@ -From da3c6e70aa08edafcc8396a4c3e007a263d7d956 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 14:01:25 +0100 -Subject: [PATCH] appliance: Set udev.event-timeout to override default too low - udev setting. - -Unfortunately udev removed the udevtimeout setting on the kernel -command line. This means the default timeout was being set back to 30 -seconds, which is way too low for remote disks. - -However it was re-added (2014-07-29) as udev.event-timeout. Set both -to be sure. - -Note this requires systemd >= 216. - -(cherry picked from commit 0b49defc2b4307e1f9159b862637978129aaed29) ---- - src/launch.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/launch.c b/src/launch.c -index dba68fd..9fadce8 100644 ---- a/src/launch.c -+++ b/src/launch.c -@@ -353,6 +353,7 @@ guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev, - " efi-rtc=noprobe" - #endif - " udevtimeout=6000"/* for slow systems (RHBZ#480319, RHBZ#1096579) */ -+ " udev.event-timeout=6000" /* for newer udevd */ - " no_timer_check" /* fix for RHBZ#502058 */ - "%s" /* lpj */ - " acpi=off" /* we don't need ACPI, turn it off */ --- -1.8.3.1 - 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 new file mode 100644 index 0000000..d3bb8f4 --- /dev/null +++ b/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch @@ -0,0 +1,26 @@ +From 6d6400678ed8c13071ff78e955e811182757037c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 10 Oct 2014 17:45:39 +0100 +Subject: [PATCH] RHEL 7: Revert "appliance: add dhcp-client on Mageia" + +This reverts commit 8f3a2ca5358d5601be7a9247b6d08193c4e2da46. +--- + appliance/packagelist.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/appliance/packagelist.in b/appliance/packagelist.in +index 70af72d..4696a73 100644 +--- a/appliance/packagelist.in ++++ b/appliance/packagelist.in +@@ -184,7 +184,7 @@ ifelse(MAGEIA,1, + chkconfig /* for /etc/init.d */ + cdrkit-genisoimage + cdrkit-isotools +- dhcp-client ++ dhclient + extlinux + gfs2-utils + grub +-- +1.8.3.1 + diff --git a/SOURCES/0011-v2v-Increase-vCenter-https-timeout-to-10-minutes.patch b/SOURCES/0011-v2v-Increase-vCenter-https-timeout-to-10-minutes.patch deleted file mode 100644 index 9b954ab..0000000 --- a/SOURCES/0011-v2v-Increase-vCenter-https-timeout-to-10-minutes.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 53f2552c819ab29e00464cf140778df7e6c678ee Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 14:03:13 +0100 -Subject: [PATCH] v2v: Increase vCenter https timeout to 10 minutes. - -(cherry picked from commit 9ddfbad814e55553d9d1cea08134311c12923cfe) ---- - v2v/vCenter.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml -index d3869aa..c04247e 100644 ---- a/v2v/vCenter.ml -+++ b/v2v/vCenter.ml -@@ -83,7 +83,7 @@ let rec map_path_to_uri verbose uri scheme server path format = - let json_params = [ - "file.driver", JSON.String "https"; - "file.url", JSON.String url; -- "file.timeout", JSON.Int 60; -+ "file.timeout", JSON.Int 600; - (* Choose a large readahead. See: RHBZ#1151033 *) - "file.readahead", JSON.Int (64 * 1024 * 1024); - ] in --- -1.8.3.1 - 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 new file mode 100644 index 0000000..e3584f3 --- /dev/null +++ b/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch @@ -0,0 +1,28 @@ +From a9e90c5dd3b73d14f1312a8ee07b0eae795d0596 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 10 Oct 2014 17:45:48 +0100 +Subject: [PATCH] RHEL 7: Revert "appliance: add dhcpcd and gptfdisk on + Archlinux" + +This reverts commit 979e7a49147f4ef1387337db262bf7ea12f627e3. +--- + appliance/packagelist.in | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/appliance/packagelist.in b/appliance/packagelist.in +index 4696a73..306b920 100644 +--- a/appliance/packagelist.in ++++ b/appliance/packagelist.in +@@ -102,8 +102,7 @@ ifelse(ARCHLINUX,1, + augeas + cdrkit + cryptsetup +- dhcpcd +- gptfdisk ++ dhclient + grub + hivex + iproute2 +-- +1.8.3.1 + diff --git a/SOURCES/0012-v2v-i-libvirt-Create-three-specialized-subclasses-fo.patch b/SOURCES/0012-v2v-i-libvirt-Create-three-specialized-subclasses-fo.patch deleted file mode 100644 index e9f8f2d..0000000 --- a/SOURCES/0012-v2v-i-libvirt-Create-three-specialized-subclasses-fo.patch +++ /dev/null @@ -1,189 +0,0 @@ -From 98cff1393866cf8df62c559bbc8abdaed515b91c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 17:37:04 +0100 -Subject: [PATCH] v2v: -i libvirt: Create three specialized subclasses for - handling vCenter/Xen/other. - -Previously we had one class ('input_libvirt') which handled all three -cases. Now we have one superclass ('input_libvirt') and three -subclasses of that ('input_libvirt_vcenter_https', -'input_libvirt_xen_ssh', 'input_libvirt_other') which handle the three -cases separately. - -This is just code motion, and should be functionally equivalent to -what was here before. - -(cherry picked from commit 9596fc44ff522f5f993a3c5ef9bb24a9a1b4a996) ---- - v2v/input_libvirt.ml | 138 ++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 92 insertions(+), 46 deletions(-) - -diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml -index def58bd..e8b1345 100644 ---- a/v2v/input_libvirt.ml -+++ b/v2v/input_libvirt.ml -@@ -42,7 +42,8 @@ let error_if_no_ssh_agent () = - 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.") - --class input_libvirt verbose libvirt_uri guest = -+(* Superclass. *) -+class virtual input_libvirt verbose libvirt_uri guest = - object - inherit input verbose - -@@ -52,61 +53,106 @@ object - | None -> "" - | Some uri -> " -ic " ^ uri) - guest -+end -+ -+(* Subclass specialized for handling anything that's *not* VMware vCenter -+ * or Xen. -+ *) -+class input_libvirt_other verbose libvirt_uri guest = -+object -+ inherit input_libvirt verbose libvirt_uri guest - - method source () = -+ if verbose then printf "input_libvirt_other: source()\n%!"; -+ - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in - -- (* Depending on the libvirt URI we may need to convert -- * paths so we can access them remotely (if that is possible). This -- * is only true for remote, non-NULL URIs. (We assume the user -- * doesn't try setting $LIBVIRT_URI. If they do that then all bets -- * are off). -+ Input_libvirtxml.parse_libvirt_xml ~verbose xml -+end -+ -+(* Subclass specialized for handling VMware vCenter over https. *) -+class input_libvirt_vcenter_https -+ verbose libvirt_uri parsed_uri scheme server guest = -+object -+ inherit input_libvirt verbose libvirt_uri guest -+ -+ method source () = -+ if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; -+ -+ (* Get the libvirt XML. This also checks (as a side-effect) -+ * that the domain is not running. (RHBZ#1138586) - *) -- let map_source_file, map_source_dev = -- match libvirt_uri with -- | None -> None, None -- | Some orig_uri -> -- let { Xml.uri_server = server; uri_scheme = scheme } as uri = -- try Xml.parse_uri orig_uri -- with Invalid_argument msg -> -- 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. *) -- None, None -- -- | Some _, None (* No scheme? *) -- | Some _, Some "" -> -- None, None -- -- | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> (* ESX *) -- error_if_libvirt_backend (); -- let f = VCenter.map_path_to_uri verbose uri scheme server in -- Some f, Some f -- -- | Some server, Some ("xen+ssh" as scheme) -> (* Xen over SSH *) -- error_if_libvirt_backend (); -- error_if_no_ssh_agent (); -- let f = Xen.map_path_to_uri verbose uri scheme server in -- Some f, Some f -- -- (* Old virt-v2v also supported qemu+ssh://. However I am -- * deliberately not supporting this in new virt-v2v. Don't -- * use virt-v2v if a guest already runs on KVM. -- *) -- | Some _, Some _ -> (* Unknown remote scheme. *) -- warning ~prog (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.") -- orig_uri; -- None, None in -+ let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in - -+ error_if_libvirt_backend (); -+ -+ let mapf = VCenter.map_path_to_uri verbose parsed_uri scheme server in - Input_libvirtxml.parse_libvirt_xml ~verbose -- ?map_source_file ?map_source_dev xml -+ ~map_source_file:mapf ~map_source_dev:mapf xml - end - --let input_libvirt = new input_libvirt -+(* Subclass specialized for handling Xen over SSH. *) -+class input_libvirt_xen_ssh -+ verbose libvirt_uri parsed_uri scheme server guest = -+object -+ inherit input_libvirt verbose libvirt_uri guest -+ -+ method source () = -+ if verbose then printf "input_libvirt_xen_ssh: source()\n%!"; -+ -+ (* Get the libvirt XML. This also checks (as a side-effect) -+ * that the domain is not running. (RHBZ#1138586) -+ *) -+ let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ -+ error_if_libvirt_backend (); -+ error_if_no_ssh_agent (); -+ -+ let mapf = Xen.map_path_to_uri verbose parsed_uri scheme server in -+ Input_libvirtxml.parse_libvirt_xml ~verbose -+ ~map_source_file:mapf ~map_source_dev:mapf xml -+end -+ -+(* Choose the right subclass based on the URI. *) -+let input_libvirt verbose libvirt_uri guest = -+ match libvirt_uri with -+ | None -> -+ new input_libvirt_other verbose libvirt_uri guest -+ -+ | Some orig_uri -> -+ let { Xml.uri_server = server; uri_scheme = scheme } as parsed_uri = -+ try Xml.parse_uri orig_uri -+ with Invalid_argument msg -> -+ 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. *) -+ -+ | Some _, None (* No scheme? *) -+ | Some _, Some "" -> -+ new input_libvirt_other verbose libvirt_uri guest -+ -+ | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> (* vCenter over https *) -+ new input_libvirt_vcenter_https -+ verbose libvirt_uri parsed_uri scheme server guest -+ -+ | Some server, Some ("xen+ssh" as scheme) -> (* Xen over SSH *) -+ new input_libvirt_xen_ssh -+ verbose libvirt_uri parsed_uri scheme server guest -+ -+ (* Old virt-v2v also supported qemu+ssh://. However I am -+ * deliberately not supporting this in new virt-v2v. Don't -+ * use virt-v2v if a guest already runs on KVM. -+ *) -+ -+ | Some _, Some _ -> (* Unknown remote scheme. *) -+ warning ~prog (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.") -+ orig_uri; -+ new input_libvirt_other verbose libvirt_uri guest -+ - let () = Modules_list.register_input_module "libvirt" --- -1.8.3.1 - 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 new file mode 100644 index 0000000..9cee57f --- /dev/null +++ b/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch @@ -0,0 +1,94 @@ +From e2d8231c9ba4ac839f303b7e44f135506c4098fa Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 10 Oct 2014 17:46:02 +0100 +Subject: [PATCH] RHEL 7: Revert "appliance: Use dhclient or dhcpcd instead of + hard-coding IP address of appliance." + +This reverts commit 67e6f32a240c7c234e6af637c1cd324b36a82cd3. +--- + appliance/init | 15 ++++++--------- + appliance/packagelist.in | 7 ------- + 2 files changed, 6 insertions(+), 16 deletions(-) + +diff --git a/appliance/init b/appliance/init +index a36d52b..ff8f5df 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -109,15 +109,12 @@ eval `grep -Eo 'guestfs_channel=[^[:space:]]+' /proc/cmdline` + ip addr add 127.0.0.1/8 brd + dev lo scope host + ip link set dev lo up + +-if test "$guestfs_network" = 1; then +- iface=$(ls -I all -I default -I lo /proc/sys/net/ipv4/conf) +- touch /etc/fstab # Workaround for Ubuntu. +- if dhclient --version >/dev/null 2>&1; then +- dhclient $iface +- else +- dhcpcd $iface +- fi +-fi ++ip addr add 169.254.2.10/16 brd + dev eth0 scope global ++ip link set dev eth0 up ++ ++ip route add default via 169.254.2.2 ++ ++echo nameserver 169.254.2.3 > /etc/resolv.conf + + # Scan for MDs. + mdadm -As --auto=yes --run +diff --git a/appliance/packagelist.in b/appliance/packagelist.in +index 306b920..e93e5e8 100644 +--- a/appliance/packagelist.in ++++ b/appliance/packagelist.in +@@ -26,7 +26,6 @@ ifelse(REDHAT,1, + augeas-libs + cryptsetup + cryptsetup-luks dnl old name used before Fedora 17 +- dhclient + genisoimage + gfs-utils + gfs2-utils +@@ -72,7 +71,6 @@ dnl iproute has been renamed to iproute2 + iputils-ping + iputils-arping + iputils-tracepath +- isc-dhcp-client + libaugeas0 + libc-bin + libcap2 +@@ -102,7 +100,6 @@ ifelse(ARCHLINUX,1, + augeas + cdrkit + cryptsetup +- dhclient + grub + hivex + iproute2 +@@ -131,8 +128,6 @@ ifelse(SUSE,1, + augeas-lenses + btrfsprogs + cryptsetup +- dhcpcd +- dhcp-client + genisoimage + glibc-locale + gptfdisk +@@ -156,7 +151,6 @@ ifelse(FRUGALWARE,1, + augeas + cryptsetup-luks + cdrkit +- dhclient + grub2 + hfsplus + iproute2 +@@ -183,7 +177,6 @@ ifelse(MAGEIA,1, + chkconfig /* for /etc/init.d */ + cdrkit-genisoimage + cdrkit-isotools +- dhclient + extlinux + gfs2-utils + grub +-- +1.8.3.1 + diff --git a/SOURCES/0013-v2v-i-libvirt-Refactor-map_source-functions.patch b/SOURCES/0013-v2v-i-libvirt-Refactor-map_source-functions.patch deleted file mode 100644 index 42b1743..0000000 --- a/SOURCES/0013-v2v-i-libvirt-Refactor-map_source-functions.patch +++ /dev/null @@ -1,178 +0,0 @@ -From 179e2fe32705ecc34759630f72dcfdbcf076e526 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 18:02:57 +0100 -Subject: [PATCH] v2v: -i libvirt: Refactor map_source* functions. - -Get rid of the awkward map_source* functions, and replace it with -equivalent code which modifies the source disks objects coming back -from Input_libvirtxml.parse_libvirt_xml. - -This is just code refactoring. Apart from the order in which certain -tests are done, this should be equivalent to the previous code. - -(cherry picked from commit 3596165282ccf2c5896894ec4e9a71c6da788463) ---- - v2v/input_libvirt.ml | 36 +++++++++++++++++++++++++----------- - v2v/input_libvirtxml.ml | 31 ++++++++++++------------------- - v2v/input_libvirtxml.mli | 11 +---------- - 3 files changed, 38 insertions(+), 40 deletions(-) - -diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml -index e8b1345..9d2869f 100644 ---- a/v2v/input_libvirt.ml -+++ b/v2v/input_libvirt.ml -@@ -82,16 +82,23 @@ object - method source () = - if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; - -+ error_if_libvirt_backend (); -+ - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- -- error_if_libvirt_backend (); -+ let { s_disks = disks } as source = -+ Input_libvirtxml.parse_libvirt_xml ~verbose xml in - - let mapf = VCenter.map_path_to_uri verbose parsed_uri scheme server in -- Input_libvirtxml.parse_libvirt_xml ~verbose -- ~map_source_file:mapf ~map_source_dev:mapf xml -+ let disks = List.map ( -+ fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -+ let uri, format = mapf uri format in -+ { disk with s_qemu_uri = uri; s_format = format } -+ ) disks in -+ -+ { source with s_disks = disks } - end - - (* Subclass specialized for handling Xen over SSH. *) -@@ -103,17 +110,24 @@ object - method source () = - if verbose then printf "input_libvirt_xen_ssh: source()\n%!"; - -- (* Get the libvirt XML. This also checks (as a side-effect) -- * that the domain is not running. (RHBZ#1138586) -- *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- - error_if_libvirt_backend (); - error_if_no_ssh_agent (); - -+ (* Get the libvirt XML. This also checks (as a side-effect) -+ * that the domain is not running. (RHBZ#1138586) -+ *) -+ let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ let { s_disks = disks } as source = -+ Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ - let mapf = Xen.map_path_to_uri verbose parsed_uri scheme server in -- Input_libvirtxml.parse_libvirt_xml ~verbose -- ~map_source_file:mapf ~map_source_dev:mapf xml -+ let disks = List.map ( -+ fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -+ let uri, format = mapf uri format in -+ { disk with s_qemu_uri = uri; s_format = format } -+ ) disks in -+ -+ { source with s_disks = disks } - end - - (* Choose the right subclass based on the URI. *) -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 984db18..3b19685 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -24,13 +24,7 @@ open Common_utils - open Types - open Utils - --type map_source = string -> string option -> string * string option -- --let no_map : map_source = fun x y -> x, y -- --let parse_libvirt_xml ~verbose -- ?(map_source_file = no_map) ?(map_source_dev = no_map) -- xml = -+let parse_libvirt_xml ~verbose xml = - if verbose then - printf "libvirt xml is:\n%s\n" xml; - -@@ -144,16 +138,12 @@ let parse_libvirt_xml ~verbose - match xpath_to_string "@type" "" with - | "block" -> - let path = xpath_to_string "source/@dev" "" in -- if path <> "" then ( -- let path, format = map_source_dev path format in -+ if path <> "" then - add_disk path format target_dev -- ) - | "file" -> - let path = xpath_to_string "source/@file" "" in -- if path <> "" then ( -- let path, format = map_source_file path format in -+ if path <> "" then - add_disk path format target_dev -- ) - | "network" -> - (* We only handle here, and that is - * intended only for virt-p2v. Any other network disk is -@@ -265,6 +255,8 @@ object - method source () = - let xml = read_whole_file file in - -+ let { s_disks = disks } as source = parse_libvirt_xml ~verbose xml in -+ - (* When reading libvirt XML from a file (-i libvirtxml) we allow - * paths to disk images in the libvirt XML to be relative (to the XML - * file). Relative paths are in fact not permitted in real libvirt -@@ -272,13 +264,14 @@ object - * when writing the XML by hand. - *) - let dir = Filename.dirname (absolute_path file) in -- let map_source_file path format = -- let path = -- if not (Filename.is_relative path) then path else dir // path in -- path, format -- in -+ let disks = List.map ( -+ fun ({ s_qemu_uri = path } as disk) -> -+ let path = -+ if not (Filename.is_relative path) then path else dir // path in -+ { disk with s_qemu_uri = path } -+ ) disks in - -- parse_libvirt_xml ~verbose ~map_source_file xml -+ { source with s_disks = disks } - end - - let input_libvirtxml = new input_libvirtxml -diff --git a/v2v/input_libvirtxml.mli b/v2v/input_libvirtxml.mli -index d673150..5c10df0 100644 ---- a/v2v/input_libvirtxml.mli -+++ b/v2v/input_libvirtxml.mli -@@ -18,18 +18,9 @@ - - (** [-i libvirtxml] source. *) - --type map_source = string -> string option -> string * string option --(** Map function that takes [path] and [format] parameters, and -- returns the possibly rewritten [qemu_uri, format] pair. *) -- --val parse_libvirt_xml : verbose:bool -> ?map_source_file:map_source -> ?map_source_dev:map_source -> string -> Types.source -+val parse_libvirt_xml : verbose:bool -> string -> Types.source - (** Take libvirt XML and parse it into a {!Types.source} structure. - -- The optional [?map_source_file] and [?map_source_dev] functions -- are used to map [] and [] -- from the XML into QEMU URIs. If not given, then an identity -- mapping is used. -- - This function is also used by {!Input_libvirt}, hence it is - exported. *) - --- -1.8.3.1 - diff --git a/SOURCES/0014-RHEL-7-v2v-Disable-unconfiguration-of-VMware-drivers.patch b/SOURCES/0014-RHEL-7-v2v-Disable-unconfiguration-of-VMware-drivers.patch new file mode 100644 index 0000000..e4473b6 --- /dev/null +++ b/SOURCES/0014-RHEL-7-v2v-Disable-unconfiguration-of-VMware-drivers.patch @@ -0,0 +1,44 @@ +From 5af7ba1b2e7e833fc0cb1f0cbb6cbde0f4bb89fe Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Oct 2014 08:41:56 +0100 +Subject: [PATCH] RHEL 7: v2v: Disable unconfiguration of VMware drivers on + Linux (RHBZ#1155610). + +This is currently broken and breaks conversions. For details see: +https://bugzilla.redhat.com/show_bug.cgi?id=1155610 +--- + v2v/convert_linux.ml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml +index 17fda7c..bdbd06b 100644 +--- a/v2v/convert_linux.ml ++++ b/v2v/convert_linux.ml +@@ -540,6 +540,7 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source = + msg + ) + ++(* Disabled in RHEL 7.1: see https://bugzilla.redhat.com/show_bug.cgi?id=1155610 + and unconfigure_vmware () = + (* Look for any configured VMware yum repos and disable them. *) + let repos = +@@ -630,6 +631,7 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source = + warning (f_"VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)") + msg + ) ++*) + + and unconfigure_citrix () = + let pkgs = +@@ -1385,7 +1387,7 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source = + + unconfigure_xen (); + unconfigure_vbox (); +- unconfigure_vmware (); ++ (*unconfigure_vmware ();*) + unconfigure_citrix (); + unconfigure_kudzu (); + +-- +1.8.3.1 + diff --git a/SOURCES/0014-v2v-Add-a-unique-number-to-source-disks.patch b/SOURCES/0014-v2v-Add-a-unique-number-to-source-disks.patch deleted file mode 100644 index eb84565..0000000 --- a/SOURCES/0014-v2v-Add-a-unique-number-to-source-disks.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0d60372cb2b9f6afa92993cf3d4666e98296bf69 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 18:18:54 +0100 -Subject: [PATCH] v2v: Add a unique number to source disks. - -Note that it doesn't matter what the number is, as long as it's -different for each disk. - -The unique number lets us store extra data in input objects which is -associated with each disk. - -(cherry picked from commit 63387fd8d0d77f7fdaaad14e5053b86ae51cbd6e) ---- - v2v/input_disk.ml | 1 + - v2v/input_libvirtxml.ml | 6 ++++-- - v2v/input_ova.ml | 1 + - v2v/types.ml | 1 + - v2v/types.mli | 1 + - 5 files changed, 8 insertions(+), 2 deletions(-) - -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index 0b68ccf..ef28b43 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -66,6 +66,7 @@ class input_disk verbose input_format disk = object - | format -> format in - - let disk = { -+ s_disk_id = 0; - s_qemu_uri = disk_absolute; - s_format = Some format; - s_target_dev = None; -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 3b19685..0cfd75c 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -103,11 +103,13 @@ let parse_libvirt_xml ~verbose xml = - (* Non-removable disk devices. *) - let disks = - let get_disks, add_disk = -- let disks = ref [] in -+ let disks = ref [] and i = ref 0 in - let get_disks () = List.rev !disks in - let add_disk qemu_uri format target_dev = -+ incr i; - disks := -- { s_qemu_uri = qemu_uri; s_format = format; -+ { s_disk_id = !i; -+ s_qemu_uri = qemu_uri; s_format = format; - s_target_dev = target_dev } :: !disks - in - get_disks, add_disk -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 001a579..6349c76 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -210,6 +210,7 @@ object - else filename in - - let disk = { -+ s_disk_id = i; - s_qemu_uri = filename; - s_format = Some "vmdk"; - s_target_dev = Some target_dev; -diff --git a/v2v/types.ml b/v2v/types.ml -index ba04161..5124f3c 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -33,6 +33,7 @@ type source = { - s_nics : source_nic list; - } - and source_disk = { -+ s_disk_id : int; - s_qemu_uri : string; - s_format : string option; - s_target_dev : string option; -diff --git a/v2v/types.mli b/v2v/types.mli -index 863371c..c077dc2 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -35,6 +35,7 @@ type source = { - (** The source: metadata, disk images. *) - - and source_disk = { -+ s_disk_id : int; (** A unique ID for each source disk. *) - s_qemu_uri : string; (** QEMU URI of source disk. *) - s_format : string option; (** Format. *) - s_target_dev : string option; (** Target @dev from libvirt XML. *) --- -1.8.3.1 - diff --git a/SOURCES/0015-RHEL-7-Disable-alternate-Augeas-lenses.patch b/SOURCES/0015-RHEL-7-Disable-alternate-Augeas-lenses.patch new file mode 100644 index 0000000..4f83aa2 --- /dev/null +++ b/SOURCES/0015-RHEL-7-Disable-alternate-Augeas-lenses.patch @@ -0,0 +1,84 @@ +From 689121835dc22f576fa0182c6f0e94a27a24ba6a Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 24 Oct 2014 16:33:50 +0100 +Subject: [PATCH] RHEL 7: Disable alternate Augeas lenses. + +These are included in the RHEL 7.1 augeas package, and therefore +not required in RHEL. + +See: +https://www.redhat.com/archives/libguestfs/2014-October/msg00220.html +--- + appliance/Makefile.am | 2 -- + daemon/augeas.c | 5 ++++- + daemon/lvm-filter.c | 4 ++-- + 3 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/appliance/Makefile.am b/appliance/Makefile.am +index d8fb15b..56dffa6 100644 +--- a/appliance/Makefile.am ++++ b/appliance/Makefile.am +@@ -77,8 +77,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_lvm_conf.aug guestfs_shadow + 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 + mv $@-t $@ +diff --git a/daemon/augeas.c b/daemon/augeas.c +index 14cc0cf..fc13143 100644 +--- a/daemon/augeas.c ++++ b/daemon/augeas.c +@@ -134,7 +134,7 @@ do_aug_init (const char *root, int flags) + } + + /* Pass AUG_NO_ERR_CLOSE so we can display detailed errors. */ +- aug = aug_init (buf, "/usr/share/guestfs/", flags | AUG_NO_ERR_CLOSE); ++ aug = aug_init (buf, NULL, flags | AUG_NO_ERR_CLOSE); + + if (!aug) { + reply_with_error ("augeas initialization failed"); +@@ -148,6 +148,8 @@ do_aug_init (const char *root, int flags) + return -1; + } + ++ /* We already have the needed lenses in RHEL 7 */ ++#if 0 + if (!augeas_is_version (1, 2, 1)) { + int r = aug_transform (aug, "guestfs_shadow", "/etc/shadow", + 0 /* = included */); +@@ -166,6 +168,7 @@ do_aug_init (const char *root, int flags) + } + } + } ++#endif + + return 0; + } +diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c +index aa8fd59..83150d1 100644 +--- a/daemon/lvm-filter.c ++++ b/daemon/lvm-filter.c +@@ -122,7 +122,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; +@@ -133,7 +133,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"); +-- +1.8.3.1 + diff --git a/SOURCES/0015-v2v-Add-input-adjust_overlay_parameters-method.patch b/SOURCES/0015-v2v-Add-input-adjust_overlay_parameters-method.patch deleted file mode 100644 index c2d34bb..0000000 --- a/SOURCES/0015-v2v-Add-input-adjust_overlay_parameters-method.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 9b1984eb3ce4411b1a1882cddc263766b3984ba0 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 18:21:38 +0100 -Subject: [PATCH] v2v: Add input#adjust_overlay_parameters method. - -This is called before the copying phase to allow the input method to -adjust overlay/backing parameters. - -The default implementation does nothing, so this commit has no effect. - -(cherry picked from commit 0084736f5fe75f62f72f0014333b32ab753b1554) ---- - v2v/types.ml | 1 + - v2v/types.mli | 3 +++ - v2v/v2v.ml | 7 +++++++ - 3 files changed, 11 insertions(+) - -diff --git a/v2v/types.ml b/v2v/types.ml -index 5124f3c..c5a05f6 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -194,6 +194,7 @@ and guestcaps_video_type = QXL | Cirrus - class virtual input verbose = object - method virtual as_options : string - method virtual source : unit -> source -+ method adjust_overlay_parameters (_ : overlay) = () - end - - class virtual output verbose = object -diff --git a/v2v/types.mli b/v2v/types.mli -index c077dc2..2123a41 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -143,6 +143,9 @@ class virtual input : bool -> object - This is just used for pretty-printing log messages. *) - method virtual source : unit -> source - (** Examine the source hypervisor and create a source struct. *) -+ method adjust_overlay_parameters : overlay -> unit -+ (** Called just before copying to allow the input module to adjust -+ parameters of the overlay disk. *) - end - (** Encapsulates all [-i], etc input arguments as an object. *) - -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index 6bd2e2c..6f98a8c 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -307,6 +307,13 @@ let rec main () = - if not ((new G.guestfs ())#disk_has_backing_file overlay_file) then - error (f_"internal error: qemu corrupted the overlay file"); - -+ (* Give the input module a chance to adjust the parameters -+ * of the overlay/backing file. This allows us to increase -+ * the readahead parameter when copying (see RHBZ#1151033 and -+ * RHBZ#1153589 for the gruesome details). -+ *) -+ input#adjust_overlay_parameters t.target_overlay; -+ - (* It turns out that libguestfs's disk creation code is - * considerably more flexible and easier to use than - * qemu-img, so create the disk explicitly using libguestfs --- -1.8.3.1 - diff --git a/SOURCES/0016-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch b/SOURCES/0016-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch new file mode 100644 index 0000000..e0b3666 --- /dev/null +++ b/SOURCES/0016-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch @@ -0,0 +1,34 @@ +From f171a8a9df024c92e58d34c5b8aa6fed114f7cb4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Apr 2015 09:45:41 -0400 +Subject: [PATCH] RHEL 7: Fix list of supported sound cards to match RHEL qemu + (RHBZ#1176493). + +--- + v2v/utils.ml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/v2v/utils.ml b/v2v/utils.ml +index d1ef7b0..898b8d4 100644 +--- a/v2v/utils.ml ++++ b/v2v/utils.ml +@@ -73,13 +73,14 @@ let kvm_arch = function + (* Does qemu support the given sound card? *) + let qemu_supports_sound_card = function + | Types.AC97 +- | Types.ES1370 + | Types.ICH6 + | Types.ICH9 + | Types.PCSpeaker ++ -> true ++ | Types.ES1370 + | Types.SB16 + | Types.USBAudio +- -> true ++ -> false + + external ovmf_i386_firmware : unit -> (string * string) list = "v2v_utils_ovmf_i386_firmware" + external ovmf_x86_64_firmware : unit -> (string * string) list = "v2v_utils_ovmf_x86_64_firmware" +-- +1.8.3.1 + diff --git a/SOURCES/0016-v2v-vCenter-Adjust-readahead-parameter-between-conve.patch b/SOURCES/0016-v2v-vCenter-Adjust-readahead-parameter-between-conve.patch deleted file mode 100644 index 567841e..0000000 --- a/SOURCES/0016-v2v-vCenter-Adjust-readahead-parameter-between-conve.patch +++ /dev/null @@ -1,123 +0,0 @@ -From d783c57507d76ba18d61c3bfb7c867cf3d69d612 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 18:34:48 +0100 -Subject: [PATCH] v2v: vCenter: Adjust readahead parameter between conversion - and copying phases (RHBZ#1151033) (RHBZ#1153589). - -Previously we fixed RHBZ#1151033 by increasing the cURL readahead -parameter to a large value. Unfortunately this is too large -- and -hence slow -- for the conversion phase, which broke on slow vCenter -servers (RHBZ#1153589). - -What we do now is to perform the conversion phase with the default -readahead (2MB) to ensure stability, since performance of the -conversion phase is not critical. Then before copying we change the -readahead to the larger value (64MB) to ensure efficient copying. - -(cherry picked from commit 9281dc7d44b7b02c6470a61425aa177e6525ee88) ---- - v2v/input_libvirt.ml | 29 ++++++++++++++++++++++++++++- - v2v/vCenter.ml | 10 +++++++--- - v2v/vCenter.mli | 2 +- - 3 files changed, 36 insertions(+), 5 deletions(-) - -diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml -index 9d2869f..93d96b7 100644 ---- a/v2v/input_libvirt.ml -+++ b/v2v/input_libvirt.ml -@@ -79,6 +79,9 @@ class input_libvirt_vcenter_https - object - inherit input_libvirt verbose libvirt_uri guest - -+ val mutable mapf = fun ?readahead uri format -> uri, format -+ val saved_uri = Hashtbl.create 13 -+ - method source () = - if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; - -@@ -91,7 +94,15 @@ object - let { s_disks = disks } as source = - Input_libvirtxml.parse_libvirt_xml ~verbose xml in - -- let mapf = VCenter.map_path_to_uri verbose parsed_uri scheme server in -+ (* Save the mapf function and the original s_qemu_uri fields, so -+ * we can get them in the adjust_overlay_parameters method below. -+ *) -+ mapf <- VCenter.map_path_to_uri verbose parsed_uri scheme server; -+ List.iter ( -+ fun disk -> -+ Hashtbl.add saved_uri disk.s_disk_id (disk.s_qemu_uri, disk.s_format) -+ ) disks; -+ - let disks = List.map ( - fun ({ s_qemu_uri = uri; s_format = format } as disk) -> - let uri, format = mapf uri format in -@@ -99,6 +110,22 @@ object - ) disks in - - { source with s_disks = disks } -+ -+ (* See RHBZ#1151033 and RHBZ#1153589 for why this is necessary. *) -+ method adjust_overlay_parameters overlay = -+ let orig_uri, orig_format = -+ try Hashtbl.find saved_uri overlay.ov_source.s_disk_id -+ with Not_found -> failwith "internal error in adjust_overlay_parameters" in -+ let backing_file, _ = -+ mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format in -+ -+ (* Rebase the qcow2 overlay to adjust the readahead parameter. *) -+ let cmd = -+ sprintf "qemu-img rebase -u -b %s %s" -+ (quote backing_file) (quote overlay.ov_overlay_file) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ warning ~prog (f_"qemu-img rebase failed, see earlier errors") - end - - (* Subclass specialized for handling Xen over SSH. *) -diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml -index c04247e..dc29863 100644 ---- a/v2v/vCenter.ml -+++ b/v2v/vCenter.ml -@@ -44,7 +44,7 @@ let session_cookie = ref "" - * XXX Need to handle templates. The file is called "-delta.vmdk" in - * place of "-flat.vmdk". - *) --let rec map_path_to_uri verbose uri scheme server path format = -+let rec map_path_to_uri verbose uri scheme server ?readahead path format = - if not (Str.string_match esx_re path 0) then - path, format - else ( -@@ -84,11 +84,15 @@ let rec map_path_to_uri verbose uri scheme server path format = - "file.driver", JSON.String "https"; - "file.url", JSON.String url; - "file.timeout", JSON.Int 600; -- (* Choose a large readahead. See: RHBZ#1151033 *) -- "file.readahead", JSON.Int (64 * 1024 * 1024); - ] 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 - -diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli -index e504098..06ba452 100644 ---- a/v2v/vCenter.mli -+++ b/v2v/vCenter.mli -@@ -18,6 +18,6 @@ - - (** Functions for dealing with ESX. *) - --val map_path_to_uri : bool -> Xml.uri -> string -> string -> string -> string option -> string * string option -+val map_path_to_uri : bool -> Xml.uri -> string -> string -> ?readahead:int -> string -> string option -> string * string option - (** Map a VMware path like "[datastore1] guest/guest.vmdk" to the - URL where we can fetch the data. *) --- -1.8.3.1 - diff --git a/SOURCES/0017-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch b/SOURCES/0017-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch new file mode 100644 index 0000000..04b86c3 --- /dev/null +++ b/SOURCES/0017-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch @@ -0,0 +1,64 @@ +From 4449e2ac20e70e85533ce0bd38d53b9980a49cb5 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Apr 2015 17:20:26 -0400 +Subject: [PATCH] RHEL 7: v2v: efi: Remove references to Fedora / kraxel's OVMF + packages. + +--- + src/utils.c | 12 ------------ + v2v/utils.ml | 2 +- + 2 files changed, 1 insertion(+), 13 deletions(-) + +diff --git a/src/utils.c b/src/utils.c +index dbb9a44..8ffc1ed 100644 +--- a/src/utils.c ++++ b/src/utils.c +@@ -324,9 +324,6 @@ guestfs_int_is_true (const char *str) + /* See src/appliance.c:guestfs_int_get_uefi. */ + const char * + guestfs_int_ovmf_i386_firmware[] = { +- "/usr/share/edk2.git/ovmf-ia32/OVMF_CODE-pure-efi.fd", +- "/usr/share/edk2.git/ovmf-ia32/OVMF_VARS-pure-efi.fd", +- + NULL + }; + +@@ -335,12 +332,6 @@ guestfs_int_ovmf_x86_64_firmware[] = { + "/usr/share/OVMF/OVMF_CODE.fd", + "/usr/share/OVMF/OVMF_VARS.fd", + +- "/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd", +- "/usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd", +- +- "/usr/share/qemu/ovmf-x86_64-code.bin", +- "/usr/share/qemu/ovmf-x86_64-vars.bin", +- + NULL + }; + +@@ -349,9 +340,6 @@ guestfs_int_aavmf_firmware[] = { + "/usr/share/AAVMF/AAVMF_CODE.fd", + "/usr/share/AAVMF/AAVMF_VARS.fd", + +- "/usr/share/edk2.git/aarch64/QEMU_EFI-pflash.raw", +- "/usr/share/edk2.git/aarch64/vars-template-pflash.raw", +- + NULL + }; + +diff --git a/v2v/utils.ml b/v2v/utils.ml +index 898b8d4..d88f8ad 100644 +--- a/v2v/utils.ml ++++ b/v2v/utils.ml +@@ -99,7 +99,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)") + | ((code, vars_template) as ret) :: rest -> + if Sys.file_exists code && Sys.file_exists vars_template then ret + else loop rest +-- +1.8.3.1 + diff --git a/SOURCES/0017-v2v-Refactor-Xen-and-vCenter-code.patch b/SOURCES/0017-v2v-Refactor-Xen-and-vCenter-code.patch deleted file mode 100644 index ae32546..0000000 --- a/SOURCES/0017-v2v-Refactor-Xen-and-vCenter-code.patch +++ /dev/null @@ -1,1196 +0,0 @@ -From e95e92ff06a0ef9edb3d3107e8bbc9acc8748f18 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 19:35:23 +0100 -Subject: [PATCH] v2v: Refactor Xen and vCenter code. - -This refactors the code into more logical units, based on the previous -commits. So Xen + the input_libvirt Xen code is grouped and moved -into a new module called Input_libvirt_xen_ssh. Similarly VCenter + -input_libvirt vCenter code is moved to Input_libvirt_vcenter_https. - -There is no change here, purely code motion. - -(cherry picked from commit a468fde01687914de501f0a95cd5a40986daec29) ---- - po/POTFILES-ml | 5 +- - v2v/Makefile.am | 10 +- - v2v/input_libvirt.ml | 145 +------------------ - v2v/input_libvirt_other.ml | 76 ++++++++++ - v2v/input_libvirt_other.mli | 30 ++++ - v2v/input_libvirt_vcenter_https.ml | 270 ++++++++++++++++++++++++++++++++++++ - v2v/input_libvirt_vcenter_https.mli | 21 +++ - v2v/input_libvirt_xen_ssh.ml | 103 ++++++++++++++ - v2v/input_libvirt_xen_ssh.mli | 21 +++ - v2v/vCenter.ml | 211 ---------------------------- - v2v/vCenter.mli | 23 --- - v2v/xen.ml | 71 ---------- - v2v/xen.mli | 22 --- - 13 files changed, 537 insertions(+), 471 deletions(-) - create mode 100644 v2v/input_libvirt_other.ml - create mode 100644 v2v/input_libvirt_other.mli - create mode 100644 v2v/input_libvirt_vcenter_https.ml - create mode 100644 v2v/input_libvirt_vcenter_https.mli - create mode 100644 v2v/input_libvirt_xen_ssh.ml - create mode 100644 v2v/input_libvirt_xen_ssh.mli - delete mode 100644 v2v/vCenter.ml - delete mode 100644 v2v/vCenter.mli - delete mode 100644 v2v/xen.ml - delete mode 100644 v2v/xen.mli - -diff --git a/po/POTFILES-ml b/po/POTFILES-ml -index d919b6f..7403497 100644 ---- a/po/POTFILES-ml -+++ b/po/POTFILES-ml -@@ -91,6 +91,9 @@ v2v/convert_windows.ml - v2v/domainxml.ml - v2v/input_disk.ml - v2v/input_libvirt.ml -+v2v/input_libvirt_other.ml -+v2v/input_libvirt_vcenter_https.ml -+v2v/input_libvirt_xen_ssh.ml - v2v/input_libvirtxml.ml - v2v/input_ova.ml - v2v/kvmuid.ml -@@ -107,6 +110,4 @@ v2v/stringMap.ml - v2v/types.ml - v2v/utils.ml - v2v/v2v.ml --v2v/vCenter.ml --v2v/xen.ml - v2v/xml.ml -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index c311623..921fb93 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -42,6 +42,9 @@ SOURCES_MLI = \ - domainxml.mli \ - input_disk.mli \ - input_libvirt.mli \ -+ input_libvirt_other.mli \ -+ input_libvirt_vcenter_https.mli \ -+ input_libvirt_xen_ssh.mli \ - input_libvirtxml.mli \ - input_ova.mli \ - kvmuid.mli \ -@@ -57,8 +60,6 @@ SOURCES_MLI = \ - OVF.mli \ - stringMap.mli \ - types.mli \ -- vCenter.mli \ -- xen.mli \ - xml.mli - - SOURCES_ML = \ -@@ -69,13 +70,14 @@ SOURCES_ML = \ - domainxml.ml \ - DOM.ml \ - kvmuid.ml \ -- vCenter.ml \ -- xen.ml \ - OVF.ml \ - linux.ml \ - modules_list.ml \ - input_disk.ml \ - input_libvirtxml.ml \ -+ input_libvirt_other.ml \ -+ input_libvirt_vcenter_https.ml \ -+ input_libvirt_xen_ssh.ml \ - input_libvirt.ml \ - input_ova.ml \ - convert_linux.ml \ -diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml -index 93d96b7..60e88ac 100644 ---- a/v2v/input_libvirt.ml -+++ b/v2v/input_libvirt.ml -@@ -16,6 +16,8 @@ - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - *) - -+(** [-i libvirt] source. *) -+ - open Printf - - open Common_gettext.Gettext -@@ -24,144 +26,11 @@ open Common_utils - open Types - open Utils - --(* Check the backend is not libvirt. Works around a libvirt bug -- * (RHBZ#1134592). This can be removed once the libvirt bug is fixed. -- *) --let error_if_libvirt_backend () = -- let libguestfs_backend = (new Guestfs.guestfs ())#get_backend () in -- if libguestfs_backend = "libvirt" then ( -- error (f_"because of libvirt bug https://bugzilla.redhat.com/show_bug.cgi?id=1134592 you must 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 verbose libvirt_uri guest = --object -- inherit input verbose -- -- method as_options = -- sprintf "-i libvirt%s %s" -- (match libvirt_uri with -- | None -> "" -- | Some uri -> " -ic " ^ uri) -- guest --end -- --(* Subclass specialized for handling anything that's *not* VMware vCenter -- * or Xen. -- *) --class input_libvirt_other verbose libvirt_uri guest = --object -- inherit input_libvirt verbose libvirt_uri guest -- -- method source () = -- if verbose then printf "input_libvirt_other: source()\n%!"; -- -- (* Get the libvirt XML. This also checks (as a side-effect) -- * that the domain is not running. (RHBZ#1138586) -- *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- -- Input_libvirtxml.parse_libvirt_xml ~verbose xml --end -- --(* Subclass specialized for handling VMware vCenter over https. *) --class input_libvirt_vcenter_https -- verbose libvirt_uri parsed_uri scheme server guest = --object -- inherit input_libvirt verbose libvirt_uri guest -- -- val mutable mapf = fun ?readahead uri format -> uri, format -- val saved_uri = Hashtbl.create 13 -- -- method source () = -- if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; -- -- error_if_libvirt_backend (); -- -- (* Get the libvirt XML. This also checks (as a side-effect) -- * that the domain is not running. (RHBZ#1138586) -- *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- let { s_disks = disks } as source = -- Input_libvirtxml.parse_libvirt_xml ~verbose xml in -- -- (* Save the mapf function and the original s_qemu_uri fields, so -- * we can get them in the adjust_overlay_parameters method below. -- *) -- mapf <- VCenter.map_path_to_uri verbose parsed_uri scheme server; -- List.iter ( -- fun disk -> -- Hashtbl.add saved_uri disk.s_disk_id (disk.s_qemu_uri, disk.s_format) -- ) disks; -- -- let disks = List.map ( -- fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -- let uri, format = mapf uri format in -- { disk with s_qemu_uri = uri; s_format = format } -- ) disks in -- -- { source with s_disks = disks } -- -- (* See RHBZ#1151033 and RHBZ#1153589 for why this is necessary. *) -- method adjust_overlay_parameters overlay = -- let orig_uri, orig_format = -- try Hashtbl.find saved_uri overlay.ov_source.s_disk_id -- with Not_found -> failwith "internal error in adjust_overlay_parameters" in -- let backing_file, _ = -- mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format in -- -- (* Rebase the qcow2 overlay to adjust the readahead parameter. *) -- let cmd = -- sprintf "qemu-img rebase -u -b %s %s" -- (quote backing_file) (quote overlay.ov_overlay_file) in -- if verbose then printf "%s\n%!" cmd; -- if Sys.command cmd <> 0 then -- warning ~prog (f_"qemu-img rebase failed, see earlier errors") --end -- --(* Subclass specialized for handling Xen over SSH. *) --class input_libvirt_xen_ssh -- verbose libvirt_uri parsed_uri scheme server guest = --object -- inherit input_libvirt verbose libvirt_uri guest -- -- method source () = -- if verbose then printf "input_libvirt_xen_ssh: source()\n%!"; -- -- error_if_libvirt_backend (); -- error_if_no_ssh_agent (); -- -- (* Get the libvirt XML. This also checks (as a side-effect) -- * that the domain is not running. (RHBZ#1138586) -- *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- let { s_disks = disks } as source = -- Input_libvirtxml.parse_libvirt_xml ~verbose xml in -- -- let mapf = Xen.map_path_to_uri verbose parsed_uri scheme server in -- let disks = List.map ( -- fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -- let uri, format = mapf uri format in -- { disk with s_qemu_uri = uri; s_format = format } -- ) disks in -- -- { source with s_disks = disks } --end -- - (* Choose the right subclass based on the URI. *) - let input_libvirt verbose libvirt_uri guest = - match libvirt_uri with - | None -> -- new input_libvirt_other verbose libvirt_uri guest -+ Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest - - | Some orig_uri -> - let { Xml.uri_server = server; uri_scheme = scheme } as parsed_uri = -@@ -176,14 +45,14 @@ let input_libvirt verbose libvirt_uri guest = - - | Some _, None (* No scheme? *) - | Some _, Some "" -> -- new input_libvirt_other verbose libvirt_uri guest -+ Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest - - | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> (* vCenter over https *) -- new input_libvirt_vcenter_https -+ Input_libvirt_vcenter_https.input_libvirt_vcenter_https - verbose libvirt_uri parsed_uri scheme server guest - - | Some server, Some ("xen+ssh" as scheme) -> (* Xen over SSH *) -- new input_libvirt_xen_ssh -+ Input_libvirt_xen_ssh.input_libvirt_xen_ssh - verbose libvirt_uri parsed_uri scheme server guest - - (* Old virt-v2v also supported qemu+ssh://. However I am -@@ -194,6 +63,6 @@ let input_libvirt verbose libvirt_uri guest = - | Some _, Some _ -> (* Unknown remote scheme. *) - warning ~prog (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.") - orig_uri; -- new input_libvirt_other verbose libvirt_uri guest -+ Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest - - let () = Modules_list.register_input_module "libvirt" -diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml -new file mode 100644 -index 0000000..a771aa1 ---- /dev/null -+++ b/v2v/input_libvirt_other.ml -@@ -0,0 +1,76 @@ -+(* virt-v2v -+ * Copyright (C) 2009-2014 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_gettext.Gettext -+open Common_utils -+ -+open Types -+open Utils -+ -+(* Check the backend is not libvirt. Works around a libvirt bug -+ * (RHBZ#1134592). This can be removed once the libvirt bug is fixed. -+ *) -+let error_if_libvirt_backend () = -+ let libguestfs_backend = (new Guestfs.guestfs ())#get_backend () in -+ if libguestfs_backend = "libvirt" then ( -+ error (f_"because of libvirt bug https://bugzilla.redhat.com/show_bug.cgi?id=1134592 you must 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 verbose libvirt_uri guest = -+object -+ inherit input verbose -+ -+ method as_options = -+ sprintf "-i libvirt%s %s" -+ (match libvirt_uri with -+ | None -> "" -+ | Some uri -> " -ic " ^ uri) -+ guest -+end -+ -+(* Subclass specialized for handling anything that's *not* VMware vCenter -+ * or Xen. -+ *) -+class input_libvirt_other verbose libvirt_uri guest = -+object -+ inherit input_libvirt verbose libvirt_uri guest -+ -+ method source () = -+ if verbose then printf "input_libvirt_other: source()\n%!"; -+ -+ (* Get the libvirt XML. This also checks (as a side-effect) -+ * that the domain is not running. (RHBZ#1138586) -+ *) -+ let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ -+ Input_libvirtxml.parse_libvirt_xml ~verbose xml -+end -+ -+let input_libvirt_other = new input_libvirt_other -diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli -new file mode 100644 -index 0000000..013d3bb ---- /dev/null -+++ b/v2v/input_libvirt_other.mli -@@ -0,0 +1,30 @@ -+(* virt-v2v -+ * Copyright (C) 2009-2014 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] source. *) -+ -+val error_if_libvirt_backend : unit -> unit -+val error_if_no_ssh_agent : unit -> unit -+ -+class virtual input_libvirt : bool -> string option -> string -> object -+ method as_options : string -+ method virtual source : unit -> Types.source -+ method adjust_overlay_parameters : Types.overlay -> unit -+end -+ -+val input_libvirt_other : bool -> string option -> string -> Types.input -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -new file mode 100644 -index 0000000..7dde9be ---- /dev/null -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -0,0 +1,270 @@ -+(* virt-v2v -+ * Copyright (C) 2009-2014 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 vCenter *) -+ -+open Common_gettext.Gettext -+open Common_utils -+ -+open Types -+open Xml -+open Utils -+open Input_libvirt_other -+ -+open Printf -+ -+let esx_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" -+ -+let session_cookie = ref "" -+ -+(* Map an ESX to a qemu URI using the cURL driver -+ * in qemu. The 'path' will be something like -+ * -+ * "[datastore1] Fedora 20/Fedora 20.vmdk" -+ * -+ * including those literal spaces in the string. -+ * -+ * 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 rec map_path_to_uri verbose uri scheme server ?readahead path format = -+ if not (Str.string_match esx_re path 0) then -+ path, format -+ else ( -+ let datastore = Str.matched_group 1 path -+ and path = Str.matched_group 2 path in -+ -+ (* Get the datacenter. *) -+ let datacenter = get_datacenter uri scheme in -+ -+ let port = -+ match uri.uri_port with -+ | 443 -> "" -+ | n when n >= 1 -> ":" ^ string_of_int n -+ | _ -> "" in -+ -+ let url = -+ sprintf -+ "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" -+ server port -+ (uri_quote path) (uri_quote datacenter) (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 -+ -+ (* Now we have to query the server to get the session cookie. *) -+ let session_cookie = get_session_cookie verbose scheme uri sslverify url in -+ -+ (* Construct the JSON parameters. *) -+ let json_params = [ -+ "file.driver", JSON.String "https"; -+ "file.url", JSON.String url; -+ "file.timeout", JSON.Int 600; -+ ] 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 -+ -+ if verbose then -+ printf "esx: json parameters: %s\n" (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 -+ -+ (* The libvirt ESX driver doesn't normally specify a format, but -+ * the format of the -flat file is *always* raw, so force it here. -+ *) -+ qemu_uri, Some "raw" -+ ) -+ -+and get_datacenter uri scheme = -+ let default_dc = "ha-datacenter" in -+ match scheme with -+ | "vpx" -> (* Hopefully the first part of the path. *) -+ (match uri.uri_path with -+ | None -> -+ warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name"); -+ default_dc -+ | Some path -> -+ let path = -+ let len = String.length path in -+ if len > 0 && path.[0] = '/' then -+ String.sub path 1 (len-1) -+ else path in -+ let len = -+ try String.index 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 -+ -+and get_session_cookie verbose scheme uri sslverify url = -+ (* Memoize the session cookie. *) -+ if !session_cookie <> "" then -+ Some !session_cookie -+ else ( -+ let cmd = -+ sprintf "curl -s%s%s%s -I %s ||:" -+ (if not sslverify then " --insecure" else "") -+ (match uri.uri_user with Some _ -> " -u" | None -> "") -+ (match uri.uri_user with Some user -> " " ^ quote user | None -> "") -+ (quote url) in -+ let lines = external_command ~prog cmd in -+ -+ let dump_response chan = -+ fprintf chan "%s\n" cmd; -+ List.iter (fun x -> fprintf chan "%s\n" x) lines -+ in -+ -+ if verbose then dump_response stdout; -+ -+ (* 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_"esx: 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_"esx: incorrect username or password") -+ else -+ error (f_"esx: 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_"esx: URL not found: %s") url -+ ); -+ -+ if status <> "200" then ( -+ dump_response stderr; -+ error (f_"esx: 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 ~prog (f_"esx: 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 -+ ) -+ -+(* Subclass specialized for handling VMware vCenter over https. *) -+class input_libvirt_vcenter_https -+ verbose libvirt_uri parsed_uri scheme server guest = -+object -+ inherit input_libvirt verbose libvirt_uri guest -+ -+ val mutable mapf = fun ?readahead uri format -> uri, format -+ val saved_uri = Hashtbl.create 13 -+ -+ method source () = -+ if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; -+ -+ error_if_libvirt_backend (); -+ -+ (* Get the libvirt XML. This also checks (as a side-effect) -+ * that the domain is not running. (RHBZ#1138586) -+ *) -+ let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ let { s_disks = disks } as source = -+ Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ -+ (* Save the mapf function and the original s_qemu_uri fields, so -+ * we can get them in the adjust_overlay_parameters method below. -+ *) -+ mapf <- map_path_to_uri verbose parsed_uri scheme server; -+ List.iter ( -+ fun disk -> -+ Hashtbl.add saved_uri disk.s_disk_id (disk.s_qemu_uri, disk.s_format) -+ ) disks; -+ -+ let disks = List.map ( -+ fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -+ let uri, format = mapf uri format in -+ { disk with s_qemu_uri = uri; s_format = format } -+ ) disks in -+ -+ { source with s_disks = disks } -+ -+ (* See RHBZ#1151033 and RHBZ#1153589 for why this is necessary. *) -+ method adjust_overlay_parameters overlay = -+ let orig_uri, orig_format = -+ try Hashtbl.find saved_uri overlay.ov_source.s_disk_id -+ with Not_found -> failwith "internal error in adjust_overlay_parameters" in -+ let backing_file, _ = -+ mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format in -+ -+ (* Rebase the qcow2 overlay to adjust the readahead parameter. *) -+ let cmd = -+ sprintf "qemu-img rebase -u -b %s %s" -+ (quote backing_file) (quote overlay.ov_overlay_file) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ warning ~prog (f_"qemu-img rebase failed, see earlier errors") -+end -+ -+let input_libvirt_vcenter_https = new input_libvirt_vcenter_https -diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli -new file mode 100644 -index 0000000..82dce53 ---- /dev/null -+++ b/v2v/input_libvirt_vcenter_https.mli -@@ -0,0 +1,21 @@ -+(* virt-v2v -+ * Copyright (C) 2009-2014 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 vCenter *) -+ -+val input_libvirt_vcenter_https : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input -diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml -new file mode 100644 -index 0000000..081317d ---- /dev/null -+++ b/v2v/input_libvirt_xen_ssh.ml -@@ -0,0 +1,103 @@ -+(* virt-v2v -+ * Copyright (C) 2009-2014 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 Xen *) -+ -+open Common_gettext.Gettext -+open Common_utils -+ -+open Types -+open Xml -+open Utils -+open Input_libvirt_other -+ -+open Printf -+ -+(* Map a Xen to a qemu URI using the SSH driver in qemu. -+ * This code assumes (and the caller checks) that the Xen URI is -+ * remotely accessible over ssh, so we can map the path to the qemu -+ * URI: -+ * -+ * json: { -+ * "file.driver": "ssh", -+ * "file.user": "username", -+ * "file.host": "xen-host", -+ * "file.port": 123, -+ * "file.path": "path", -+ * "file.host_key_check": "no" -+ * } -+ *) -+let map_path_to_uri verbose uri scheme server path format = -+ (* Construct the JSON parameters. *) -+ let json_params = [ -+ "file.driver", JSON.String "ssh"; -+ "file.path", JSON.String path; -+ "file.host", JSON.String server; -+ "file.host_key_check", JSON.String "no"; -+ ] in -+ -+ let json_params = -+ match uri.uri_port with -+ | 0 | 22 -> json_params -+ (* qemu will actually assert-fail if you send the port number as a -+ * string ... -+ *) -+ | i -> ("file.port", JSON.Int i) :: json_params in -+ -+ let json_params = -+ match uri.uri_user with -+ | None -> json_params -+ | Some user -> ("file.user", JSON.String user) :: json_params in -+ -+ if verbose then -+ printf "ssh: json parameters: %s\n" (JSON.string_of_doc json_params); -+ -+ (* Turn the JSON parameters into a 'json:' protocol string. *) -+ let qemu_uri = "json: " ^ JSON.string_of_doc json_params in -+ -+ qemu_uri, format -+ -+(* Subclass specialized for handling Xen over SSH. *) -+class input_libvirt_xen_ssh verbose libvirt_uri parsed_uri scheme server guest = -+object -+ inherit input_libvirt verbose libvirt_uri guest -+ -+ method source () = -+ if verbose then printf "input_libvirt_xen_ssh: source()\n%!"; -+ -+ error_if_libvirt_backend (); -+ error_if_no_ssh_agent (); -+ -+ (* Get the libvirt XML. This also checks (as a side-effect) -+ * that the domain is not running. (RHBZ#1138586) -+ *) -+ let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ let { s_disks = disks } as source = -+ Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ -+ let mapf = map_path_to_uri verbose parsed_uri scheme server in -+ let disks = List.map ( -+ fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -+ let uri, format = mapf uri format in -+ { disk with s_qemu_uri = uri; s_format = format } -+ ) disks in -+ -+ { source with s_disks = disks } -+end -+ -+let input_libvirt_xen_ssh = new input_libvirt_xen_ssh -diff --git a/v2v/input_libvirt_xen_ssh.mli b/v2v/input_libvirt_xen_ssh.mli -new file mode 100644 -index 0000000..85473ed ---- /dev/null -+++ b/v2v/input_libvirt_xen_ssh.mli -@@ -0,0 +1,21 @@ -+(* virt-v2v -+ * Copyright (C) 2009-2014 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 Xen *) -+ -+val input_libvirt_xen_ssh : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input -diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml -deleted file mode 100644 -index dc29863..0000000 ---- a/v2v/vCenter.ml -+++ /dev/null -@@ -1,211 +0,0 @@ --(* virt-v2v -- * Copyright (C) 2009-2014 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. -- *) -- --(** Functions for dealing with ESX. *) -- --open Common_gettext.Gettext --open Common_utils -- --open Xml --open Utils -- --open Printf -- --let esx_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" -- --let session_cookie = ref "" -- --(* Map an ESX to a qemu URI using the cURL driver -- * in qemu. The 'path' will be something like -- * -- * "[datastore1] Fedora 20/Fedora 20.vmdk" -- * -- * including those literal spaces in the string. -- * -- * 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 rec map_path_to_uri verbose uri scheme server ?readahead path format = -- if not (Str.string_match esx_re path 0) then -- path, format -- else ( -- let datastore = Str.matched_group 1 path -- and path = Str.matched_group 2 path in -- -- (* Get the datacenter. *) -- let datacenter = get_datacenter uri scheme in -- -- let port = -- match uri.uri_port with -- | 443 -> "" -- | n when n >= 1 -> ":" ^ string_of_int n -- | _ -> "" in -- -- let url = -- sprintf -- "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" -- server port -- (uri_quote path) (uri_quote datacenter) (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 -- -- (* Now we have to query the server to get the session cookie. *) -- let session_cookie = get_session_cookie verbose scheme uri sslverify url in -- -- (* Construct the JSON parameters. *) -- let json_params = [ -- "file.driver", JSON.String "https"; -- "file.url", JSON.String url; -- "file.timeout", JSON.Int 600; -- ] 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 -- -- if verbose then -- printf "esx: json parameters: %s\n" (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 -- -- (* The libvirt ESX driver doesn't normally specify a format, but -- * the format of the -flat file is *always* raw, so force it here. -- *) -- qemu_uri, Some "raw" -- ) -- --and get_datacenter uri scheme = -- let default_dc = "ha-datacenter" in -- match scheme with -- | "vpx" -> (* Hopefully the first part of the path. *) -- (match uri.uri_path with -- | None -> -- warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name"); -- default_dc -- | Some path -> -- let path = -- let len = String.length path in -- if len > 0 && path.[0] = '/' then -- String.sub path 1 (len-1) -- else path in -- let len = -- try String.index 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 -- --and get_session_cookie verbose scheme uri sslverify url = -- (* Memoize the session cookie. *) -- if !session_cookie <> "" then -- Some !session_cookie -- else ( -- let cmd = -- sprintf "curl -s%s%s%s -I %s ||:" -- (if not sslverify then " --insecure" else "") -- (match uri.uri_user with Some _ -> " -u" | None -> "") -- (match uri.uri_user with Some user -> " " ^ quote user | None -> "") -- (quote url) in -- let lines = external_command ~prog cmd in -- -- let dump_response chan = -- fprintf chan "%s\n" cmd; -- List.iter (fun x -> fprintf chan "%s\n" x) lines -- in -- -- if verbose then dump_response stdout; -- -- (* 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_"esx: 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_"esx: incorrect username or password") -- else -- error (f_"esx: 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_"esx: URL not found: %s") url -- ); -- -- if status <> "200" then ( -- dump_response stderr; -- error (f_"esx: 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 ~prog (f_"esx: 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 -- ) -diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli -deleted file mode 100644 -index 06ba452..0000000 ---- a/v2v/vCenter.mli -+++ /dev/null -@@ -1,23 +0,0 @@ --(* virt-v2v -- * Copyright (C) 2009-2014 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. -- *) -- --(** Functions for dealing with ESX. *) -- --val map_path_to_uri : bool -> Xml.uri -> string -> string -> ?readahead:int -> string -> string option -> string * string option --(** Map a VMware path like "[datastore1] guest/guest.vmdk" to the -- URL where we can fetch the data. *) -diff --git a/v2v/xen.ml b/v2v/xen.ml -deleted file mode 100644 -index 332cdd6..0000000 ---- a/v2v/xen.ml -+++ /dev/null -@@ -1,71 +0,0 @@ --(* virt-v2v -- * Copyright (C) 2009-2014 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. -- *) -- --(** Functions for dealing with Xen. *) -- --open Common_gettext.Gettext --open Common_utils -- --open Xml --open Utils -- --open Printf -- --(* Map a Xen to a qemu URI using the SSH driver in qemu. -- * This code assumes (and the caller checks) that the Xen URI is -- * remotely accessible over ssh, so we can map the path to the qemu -- * URI: -- * -- * json: { -- * "file.driver": "ssh", -- * "file.user": "username", -- * "file.host": "xen-host", -- * "file.port": 123, -- * "file.path": "path", -- * "file.host_key_check": "no" -- * } -- *) --let rec map_path_to_uri verbose uri scheme server path format = -- (* Construct the JSON parameters. *) -- let json_params = [ -- "file.driver", JSON.String "ssh"; -- "file.path", JSON.String path; -- "file.host", JSON.String server; -- "file.host_key_check", JSON.String "no"; -- ] in -- -- let json_params = -- match uri.uri_port with -- | 0 | 22 -> json_params -- (* qemu will actually assert-fail if you send the port number as a -- * string ... -- *) -- | i -> ("file.port", JSON.Int i) :: json_params in -- -- let json_params = -- match uri.uri_user with -- | None -> json_params -- | Some user -> ("file.user", JSON.String user) :: json_params in -- -- if verbose then -- printf "ssh: json parameters: %s\n" (JSON.string_of_doc json_params); -- -- (* Turn the JSON parameters into a 'json:' protocol string. *) -- let qemu_uri = "json: " ^ JSON.string_of_doc json_params in -- -- qemu_uri, format -diff --git a/v2v/xen.mli b/v2v/xen.mli -deleted file mode 100644 -index 440d226..0000000 ---- a/v2v/xen.mli -+++ /dev/null -@@ -1,22 +0,0 @@ --(* virt-v2v -- * Copyright (C) 2009-2014 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. -- *) -- --(** Functions for dealing with Xen. *) -- --val map_path_to_uri : bool -> Xml.uri -> string -> string -> string -> string option -> string * string option --(** Map a Xen path to the SSH URL where we can fetch the data. *) --- -1.8.3.1 - diff --git a/SOURCES/0018-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch b/SOURCES/0018-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch new file mode 100644 index 0000000..f0d45a2 --- /dev/null +++ b/SOURCES/0018-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch @@ -0,0 +1,47 @@ +From 60d6a74fcc330c5910fa5fb64ac403e42b3b5c86 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Jul 2015 09:28:03 -0400 +Subject: [PATCH] RHEL 7: Reject use of libguestfs-winsupport features except + for virt-* tools (RHBZ#1240276). + +--- + generator/c.ml | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/generator/c.ml b/generator/c.ml +index 8dcdd67..5714900 100644 +--- a/generator/c.ml ++++ b/generator/c.ml +@@ -1857,12 +1857,29 @@ and generate_client_actions hash () = + pr " const uint64_t progress_hint = 0;\n"; + + pr "\n"; ++ + enter_event name; + check_null_strings c_name style; + reject_unknown_optargs c_name style; + check_args_validity c_name style; + trace_call name c_name style; + ++ (* RHEL 7 *) ++ if name = "mount" || name = "mount_ro" || name = "mount_options" || ++ name = "mount_vfs" then ( ++ pr " if (g->program && !STRPREFIX (g->program, \"virt-\")) {\n"; ++ pr " CLEANUP_FREE char *vfs_type = guestfs_vfs_type (g, mountable);\n"; ++ pr " if (vfs_type && STREQ (vfs_type, \"ntfs\")) {\n"; ++ pr " error (g, \"mount: unsupported filesystem type\");\n"; ++ pr " if (trace_flag)\n"; ++ pr " guestfs_int_trace (g, \"%%s = %%s (error)\",\n"; ++ pr " \"%s\", \"-1\");\n" name; ++ pr " return %s;\n" (string_of_errcode errcode); ++ pr " }\n"; ++ pr " }\n"; ++ pr "\n"; ++ ); ++ + (* Calculate the total size of all FileIn arguments to pass + * as a progress bar hint. + *) +-- +1.8.3.1 + diff --git a/SOURCES/0018-v2v-Inline-and-simplify-Xen-and-vCenter-input-method.patch b/SOURCES/0018-v2v-Inline-and-simplify-Xen-and-vCenter-input-method.patch deleted file mode 100644 index ec99ec3..0000000 --- a/SOURCES/0018-v2v-Inline-and-simplify-Xen-and-vCenter-input-method.patch +++ /dev/null @@ -1,447 +0,0 @@ -From 9583ab8900194694359cbefe403209f73fd08a47 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 20:41:29 +0100 -Subject: [PATCH] v2v: Inline and simplify Xen and vCenter input methods. - -Take the opportunity presented by the refactoring in the previous -commit to inline and simplify functions in these input subclasses. - -This finally removes the map_source* functions. - -(cherry picked from commit b8f826b7ac1e7f90f670f474c3582b56063cdef6) ---- - v2v/input_libvirt_vcenter_https.ml | 249 +++++++++++++++++++------------------ - v2v/input_libvirt_xen_ssh.ml | 93 +++++++------- - 2 files changed, 171 insertions(+), 171 deletions(-) - -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index 7dde9be..5d98a86 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -28,11 +28,107 @@ open Input_libvirt_other - - open Printf - --let esx_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" -+(* Return the session cookie. It is memoized, so you can call this -+ * as often as required. -+ *) -+let get_session_cookie = -+ let session_cookie = ref "" in -+ fun verbose scheme uri sslverify url -> -+ if !session_cookie <> "" then -+ Some !session_cookie -+ else ( -+ let cmd = -+ sprintf "curl -s%s%s%s -I %s ||:" -+ (if not sslverify then " --insecure" else "") -+ (match uri.uri_user with Some _ -> " -u" | None -> "") -+ (match uri.uri_user with Some user -> " " ^ quote user | None -> "") -+ (quote url) in -+ let lines = external_command ~prog cmd in - --let session_cookie = ref "" -+ let dump_response chan = -+ fprintf chan "%s\n" cmd; -+ List.iter (fun x -> fprintf chan "%s\n" x) lines -+ in - --(* Map an ESX to a qemu URI using the cURL driver -+ if verbose then dump_response stdout; -+ -+ (* 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_"esx: 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_"esx: incorrect username or password") -+ else -+ error (f_"esx: 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_"esx: URL not found: %s") url -+ ); -+ -+ if status <> "200" then ( -+ dump_response stderr; -+ error (f_"esx: 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 ~prog (f_"esx: 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 -+ ) -+ -+(* Helper function to extract the datacenter from a URI. *) -+let get_datacenter uri scheme = -+ let default_dc = "ha-datacenter" in -+ match scheme with -+ | "vpx" -> (* Hopefully the first part of the path. *) -+ (match uri.uri_path with -+ | None -> -+ warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name"); -+ default_dc -+ | Some path -> -+ let path = -+ let len = String.length path in -+ if len > 0 && path.[0] = '/' then -+ String.sub path 1 (len-1) -+ else path in -+ let len = -+ try String.index 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 -+ -+(* Map the string to a qemu URI using the cURL driver - * in qemu. The 'path' will be something like - * - * "[datastore1] Fedora 20/Fedora 20.vmdk" -@@ -46,9 +142,11 @@ let session_cookie = ref "" - * XXX Need to handle templates. The file is called "-delta.vmdk" in - * place of "-flat.vmdk". - *) --let rec map_path_to_uri verbose uri scheme server ?readahead path format = -- if not (Str.string_match esx_re path 0) then -- path, format -+let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" -+ -+let map_source_to_uri ?readahead verbose uri scheme 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 -@@ -111,105 +209,7 @@ let rec map_path_to_uri verbose uri scheme server ?readahead path format = - *) - let qemu_uri = "json: " ^ JSON.string_of_doc json_params 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. -- *) -- qemu_uri, Some "raw" -- ) -- --and get_datacenter uri scheme = -- let default_dc = "ha-datacenter" in -- match scheme with -- | "vpx" -> (* Hopefully the first part of the path. *) -- (match uri.uri_path with -- | None -> -- warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name"); -- default_dc -- | Some path -> -- let path = -- let len = String.length path in -- if len > 0 && path.[0] = '/' then -- String.sub path 1 (len-1) -- else path in -- let len = -- try String.index 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 -- --and get_session_cookie verbose scheme uri sslverify url = -- (* Memoize the session cookie. *) -- if !session_cookie <> "" then -- Some !session_cookie -- else ( -- let cmd = -- sprintf "curl -s%s%s%s -I %s ||:" -- (if not sslverify then " --insecure" else "") -- (match uri.uri_user with Some _ -> " -u" | None -> "") -- (match uri.uri_user with Some user -> " " ^ quote user | None -> "") -- (quote url) in -- let lines = external_command ~prog cmd in -- -- let dump_response chan = -- fprintf chan "%s\n" cmd; -- List.iter (fun x -> fprintf chan "%s\n" x) lines -- in -- -- if verbose then dump_response stdout; -- -- (* 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_"esx: 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_"esx: incorrect username or password") -- else -- error (f_"esx: 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_"esx: URL not found: %s") url -- ); -- -- if status <> "200" then ( -- dump_response stderr; -- error (f_"esx: 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 ~prog (f_"esx: 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 -+ qemu_uri - ) - - (* Subclass specialized for handling VMware vCenter over https. *) -@@ -218,11 +218,12 @@ class input_libvirt_vcenter_https - object - inherit input_libvirt verbose libvirt_uri guest - -- val mutable mapf = fun ?readahead uri format -> uri, format -- val saved_uri = Hashtbl.create 13 -+ val saved_source_paths = Hashtbl.create 13 - - method source () = -- if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; -+ if verbose then -+ printf "input_libvirt_vcenter_https: source: scheme %s server %s\n%!" -+ scheme server; - - error_if_libvirt_backend (); - -@@ -233,38 +234,42 @@ object - let { s_disks = disks } as source = - Input_libvirtxml.parse_libvirt_xml ~verbose xml in - -- (* Save the mapf function and the original s_qemu_uri fields, so -- * we can get them in the adjust_overlay_parameters method below. -+ (* Save the original source paths, so that we can remap them again -+ * in [#adjust_overlay_parameters]. - *) -- mapf <- map_path_to_uri verbose parsed_uri scheme server; - List.iter ( -- fun disk -> -- Hashtbl.add saved_uri disk.s_disk_id (disk.s_qemu_uri, disk.s_format) -+ fun { s_disk_id = id; s_qemu_uri = path } -> -+ Hashtbl.add saved_source_paths id path - ) disks; - - let disks = List.map ( -- fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -- let uri, format = mapf uri format in -- { disk with s_qemu_uri = uri; s_format = format } -+ fun ({ s_qemu_uri = path } as disk) -> -+ let qemu_uri = map_source_to_uri verbose 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. -+ *) -+ { disk with s_qemu_uri = qemu_uri; s_format = Some "raw" } - ) disks in - - { source with s_disks = disks } - - (* See RHBZ#1151033 and RHBZ#1153589 for why this is necessary. *) - method adjust_overlay_parameters overlay = -- let orig_uri, orig_format = -- try Hashtbl.find saved_uri overlay.ov_source.s_disk_id -+ let orig_path = -+ try Hashtbl.find saved_source_paths overlay.ov_source.s_disk_id - with Not_found -> failwith "internal error in adjust_overlay_parameters" in -- let backing_file, _ = -- mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format in -+ let backing_qemu_uri = -+ map_source_to_uri ~readahead:(64 * 1024 * 1024) -+ verbose parsed_uri scheme server orig_path in - - (* Rebase the qcow2 overlay to adjust the readahead parameter. *) - let cmd = - sprintf "qemu-img rebase -u -b %s %s" -- (quote backing_file) (quote overlay.ov_overlay_file) in -+ (quote backing_qemu_uri) (quote overlay.ov_overlay_file) in - if verbose then printf "%s\n%!" cmd; - if Sys.command cmd <> 0 then -- warning ~prog (f_"qemu-img rebase failed, see earlier errors") -+ warning ~prog (f_"qemu-img rebase failed (ignored)") - end - - let input_libvirt_vcenter_https = new input_libvirt_vcenter_https -diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml -index 081317d..8b836a5 100644 ---- a/v2v/input_libvirt_xen_ssh.ml -+++ b/v2v/input_libvirt_xen_ssh.ml -@@ -28,57 +28,15 @@ open Input_libvirt_other - - open Printf - --(* Map a Xen to a qemu URI using the SSH driver in qemu. -- * This code assumes (and the caller checks) that the Xen URI is -- * remotely accessible over ssh, so we can map the path to the qemu -- * URI: -- * -- * json: { -- * "file.driver": "ssh", -- * "file.user": "username", -- * "file.host": "xen-host", -- * "file.port": 123, -- * "file.path": "path", -- * "file.host_key_check": "no" -- * } -- *) --let map_path_to_uri verbose uri scheme server path format = -- (* Construct the JSON parameters. *) -- let json_params = [ -- "file.driver", JSON.String "ssh"; -- "file.path", JSON.String path; -- "file.host", JSON.String server; -- "file.host_key_check", JSON.String "no"; -- ] in -- -- let json_params = -- match uri.uri_port with -- | 0 | 22 -> json_params -- (* qemu will actually assert-fail if you send the port number as a -- * string ... -- *) -- | i -> ("file.port", JSON.Int i) :: json_params in -- -- let json_params = -- match uri.uri_user with -- | None -> json_params -- | Some user -> ("file.user", JSON.String user) :: json_params in -- -- if verbose then -- printf "ssh: json parameters: %s\n" (JSON.string_of_doc json_params); -- -- (* Turn the JSON parameters into a 'json:' protocol string. *) -- let qemu_uri = "json: " ^ JSON.string_of_doc json_params in -- -- qemu_uri, format -- - (* Subclass specialized for handling Xen over SSH. *) - class input_libvirt_xen_ssh verbose libvirt_uri parsed_uri scheme server guest = - object - inherit input_libvirt verbose libvirt_uri guest - - method source () = -- if verbose then printf "input_libvirt_xen_ssh: source()\n%!"; -+ if verbose then -+ printf "input_libvirt_xen_ssh: source: scheme %s server %s\n%!" -+ scheme server; - - error_if_libvirt_backend (); - error_if_no_ssh_agent (); -@@ -90,11 +48,48 @@ object - let { s_disks = disks } as source = - Input_libvirtxml.parse_libvirt_xml ~verbose xml in - -- let mapf = map_path_to_uri verbose parsed_uri scheme server in -+ (* Map the filename (which is relative to the remote -+ * Xen server) to an ssh URI. This is a JSON URI looking something -+ * like this: -+ * -+ * json: { -+ * "file.driver": "ssh", -+ * "file.user": "username", -+ * "file.host": "xen-host", -+ * "file.port": 1022, -+ * "file.path": "path", -+ * "file.host_key_check": "no" -+ *) - let disks = List.map ( -- fun ({ s_qemu_uri = uri; s_format = format } as disk) -> -- let uri, format = mapf uri format in -- { disk with s_qemu_uri = uri; s_format = format } -+ fun ({ s_qemu_uri = path } as disk) -> -+ (* Construct the JSON parameters. *) -+ let json_params = [ -+ "file.driver", JSON.String "ssh"; -+ "file.path", JSON.String path; -+ "file.host", JSON.String server; -+ "file.host_key_check", JSON.String "no"; -+ ] in -+ -+ let json_params = -+ match parsed_uri.uri_port with -+ | 0 | 22 -> json_params -+ (* qemu will actually assert-fail if you send the port -+ * number as a string ... -+ *) -+ | i -> ("file.port", JSON.Int i) :: json_params in -+ -+ let json_params = -+ match parsed_uri.uri_user with -+ | None -> json_params -+ | Some user -> ("file.user", JSON.String user) :: json_params in -+ -+ if verbose then -+ printf "ssh: json parameters: %s\n" (JSON.string_of_doc json_params); -+ -+ (* Turn the JSON parameters into a 'json:' protocol string. *) -+ let qemu_uri = "json: " ^ JSON.string_of_doc json_params in -+ -+ { disk with s_qemu_uri = qemu_uri } - ) disks in - - { source with s_disks = disks } --- -1.8.3.1 - diff --git a/SOURCES/0019-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch b/SOURCES/0019-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch new file mode 100644 index 0000000..fc82564 --- /dev/null +++ b/SOURCES/0019-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch @@ -0,0 +1,40 @@ +From 7e25abeffd2c7a68a06fa72fff274377637453ab Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jul 2015 18:15:36 -0400 +Subject: [PATCH] RHEL 7: daemon: umount-all: Hack to avoid umount: /sysroot: + target is busy (RHBZ#1246032). + +This bug is not properly understood (although readily reproducible). +However this hack makes it go away for now. + +https://bugzilla.redhat.com/show_bug.cgi?id=1246032 +--- + daemon/mount.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/daemon/mount.c b/daemon/mount.c +index 869c9b8..7903bc2 100644 +--- a/daemon/mount.c ++++ b/daemon/mount.c +@@ -26,6 +26,8 @@ + #include + #include + ++#include "ignore-value.h" ++ + #include "daemon.h" + #include "actions.h" + +@@ -414,6 +416,9 @@ do_umount_all (void) + if (mounts.size > 0) + qsort (mounts.argv, mounts.size, sizeof (char *), compare_longest_first); + ++ /* Hack to work around RHBZ#1246032. */ ++ ignore_value (system ("lsof /sysroot")); ++ + /* Unmount them. */ + for (i = 0; i < mounts.size; ++i) { + CLEANUP_FREE char *err = NULL; +-- +1.8.3.1 + diff --git a/SOURCES/0019-v2v-vcenter-Hoist-readahead-configurables-to-top-of-.patch b/SOURCES/0019-v2v-vcenter-Hoist-readahead-configurables-to-top-of-.patch deleted file mode 100644 index ab9f174..0000000 --- a/SOURCES/0019-v2v-vcenter-Hoist-readahead-configurables-to-top-of-.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 13eb44980b6d791d1e8264b84fb9dfcefd82577f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 20 Oct 2014 21:48:08 +0100 -Subject: [PATCH] v2v: vcenter: Hoist readahead configurables to top of file. - -No change, just code motion. - -(cherry picked from commit 496d0c45bc5e8c361d2cccb20b0f3a64443b05ab) ---- - v2v/input_libvirt_vcenter_https.ml | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index 5d98a86..71c2edd 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -28,6 +28,10 @@ open Input_libvirt_other - - open Printf - -+(* See RHBZ#1151033 and RHBZ#1153589. *) -+let readahead_for_conversion = None -+let readahead_for_copying = Some (64 * 1024 * 1024) -+ - (* Return the session cookie. It is memoized, so you can call this - * as often as required. - *) -@@ -244,7 +248,9 @@ object - - let disks = List.map ( - fun ({ s_qemu_uri = path } as disk) -> -- let qemu_uri = map_source_to_uri verbose parsed_uri scheme server path in -+ let readahead = readahead_for_conversion in -+ let qemu_uri = map_source_to_uri ?readahead -+ verbose 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. -@@ -260,7 +266,8 @@ object - try Hashtbl.find saved_source_paths overlay.ov_source.s_disk_id - with Not_found -> failwith "internal error in adjust_overlay_parameters" in - let backing_qemu_uri = -- map_source_to_uri ~readahead:(64 * 1024 * 1024) -+ let readahead = readahead_for_copying in -+ map_source_to_uri ?readahead - verbose parsed_uri scheme server orig_path in - - (* Rebase the qcow2 overlay to adjust the readahead parameter. *) --- -1.8.3.1 - diff --git a/SOURCES/0020-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch b/SOURCES/0020-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch new file mode 100644 index 0000000..9992bfd --- /dev/null +++ b/SOURCES/0020-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch @@ -0,0 +1,93 @@ +From e8784cd78f864c9d21eca6a3bccaa9d8cf8cefdf Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 30 Aug 2015 03:21:57 -0400 +Subject: [PATCH] RHEL 7: Fix tests for libguestfs-winsupport 7.2. + +It doesn't let us use guestfish for arbitrary Windows edits. +--- + test-data/phony-guests/make-windows-img.sh | 1 + + tests/charsets/test-charset-fidelity.c | 2 ++ + v2v/test-v2v-virtio-win-iso.sh | 8 +++++++- + v2v/test-v2v-windows-conversion.sh | 8 +++++++- + 4 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/test-data/phony-guests/make-windows-img.sh b/test-data/phony-guests/make-windows-img.sh +index d5c4501..9255b25 100755 +--- a/test-data/phony-guests/make-windows-img.sh ++++ b/test-data/phony-guests/make-windows-img.sh +@@ -37,6 +37,7 @@ fi + + # Create a disk image. + guestfish < "$script" + :> "$expected" + ++cat >> "$script" < "$response" ++guestfish --ro -a "$d/windows-sda" < "$script" > "$response" + diff -u "$expected" "$response" + + rm -r $d +diff --git a/v2v/test-v2v-windows-conversion.sh b/v2v/test-v2v-windows-conversion.sh +index 8406743..40f651e 100755 +--- a/v2v/test-v2v-windows-conversion.sh ++++ b/v2v/test-v2v-windows-conversion.sh +@@ -86,6 +86,12 @@ mktest () + :> "$script" + :> "$expected" + ++cat >> "$script" < "$response" ++guestfish --ro -a "$d/windows-sda" < "$script" > "$response" + diff -u "$expected" "$response" + + # We also update the Registry several times, for firstboot, and (ONLY +-- +1.8.3.1 + diff --git a/SOURCES/0020-v2v-Add-some-assertions-to-check-the-source-was-crea.patch b/SOURCES/0020-v2v-Add-some-assertions-to-check-the-source-was-crea.patch deleted file mode 100644 index a79a899..0000000 --- a/SOURCES/0020-v2v-Add-some-assertions-to-check-the-source-was-crea.patch +++ /dev/null @@ -1,36 +0,0 @@ -From d977ec8b1df84f390c5932f35feeb249baa7050b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 22 Oct 2014 12:35:53 +0100 -Subject: [PATCH] v2v: Add some assertions to check the source was created - correctly. - -(cherry picked from commit dbe35729a3fbb7150275584dd0c5aa7d86c8e03e) ---- - v2v/v2v.ml | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index 6f98a8c..48fb8c6 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -73,6 +73,17 @@ let rec main () = - - if verbose then printf "%s%!" (string_of_source source); - -+ assert (source.s_dom_type <> ""); -+ assert (source.s_name <> ""); -+ assert (source.s_memory > 0L); -+ assert (source.s_vcpu >= 1); -+ if source.s_disks = [] then -+ error (f_"source has no hard disks!"); -+ List.iter ( -+ fun disk -> -+ assert (disk.s_qemu_uri <> ""); -+ ) source.s_disks; -+ - (* Map source name. *) - let source = - match output_name with --- -1.8.3.1 - diff --git a/SOURCES/0021-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch b/SOURCES/0021-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch new file mode 100644 index 0000000..53f367a --- /dev/null +++ b/SOURCES/0021-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch @@ -0,0 +1,116 @@ +From 40e4e2a02cac87754cd734287c2eeeb7e31cc264 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 21 Sep 2015 15:49:17 +0100 +Subject: [PATCH] RHEL 7: Revert "v2v: Add a support matrix to the manual + page." + +This reverts commit a03bffa15a5357d5d0244595caf99607be1ec3ab. +--- + v2v/virt-v2v.pod | 91 -------------------------------------------------------- + 1 file changed, 91 deletions(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index dcbaec2..8e5cf1d 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -145,97 +145,6 @@ Since F contains the path(s) to the guest disk + image(s) you do not need to specify the name of the disk image on the + command line. + +-=head1 SUPPORT MATRIX +- +-=head2 Hypervisors (Input) +- +-=over 4 +- +-=item VMware ESXi +- +-Must be managed by VMware vCenter E 5.0. Unmanaged, direct input +-from ESXi is not supported. +- +-=item OVA exported from VMware +- +-OVAs from other hypervisors will not work. +- +-=item RHEL 5 Xen +- +-=item Citrix Xen +- +-Citrix Xen has not been recently tested. +- +-=item Hyper-V +- +-Not recently tested. Requires that you export the disk or use +-L on Hyper-V. +- +-=item Direct from disk images +- +-Only disk images exported from supported hypervisors, and using +-container formats supported by qemu. +- +-=item Physical machines +- +-Using the L tool. +- +-=back +- +-=head2 Hypervisors (Output) +- +-QEMU and KVM only. +- +-=head2 Virtualization management systems (Output) +- +-=over 4 +- +-=item OpenStack Glance +- +-=item Red Hat Enterprise Virtualization (RHEV) 2.2 and up +- +-=item Local libvirt +- +-And hence L, L, and similar tools. +- +-=item Local disk +- +-=back +- +-=head2 Guests +- +-=over 4 +- +-=item Red Hat Enterprise Linux 3, 4, 5, 6, 7 +- +-=item CentOS 3, 4, 5, 6, 7 +- +-=item Scientific Linux 3, 4, 5, 6, 7 +- +-=item Oracle Linux +- +-=item Fedora +- +-=item SLES 10 and up +- +-=item OpenSUSE 10 and up +- +-=item Windows XP to Windows 8.1 / Windows Server 2012 R2 +- +-We use Windows internal version numbers, see +-L +- +-Currently NT 5.2 to NT 6.3 are supported. +- +-See L below for additional notes on converting Windows +-guests. +- +-=back +- +-=head2 Guest firmware +- +-BIOS or UEFI for all guest types (but see L below). +- + =head1 OPTIONS + + =over 4 +-- +1.8.3.1 + diff --git a/SOURCES/0021-v2v-i-libvirtxml-Fix-handling-of-nbd-sources-RHBZ-11.patch b/SOURCES/0021-v2v-i-libvirtxml-Fix-handling-of-nbd-sources-RHBZ-11.patch deleted file mode 100644 index 08a46bc..0000000 --- a/SOURCES/0021-v2v-i-libvirtxml-Fix-handling-of-nbd-sources-RHBZ-11.patch +++ /dev/null @@ -1,293 +0,0 @@ -From ab0f4d6925bfac4cb65c6d6e6e050d5366a8163b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 22 Oct 2014 12:00:36 +0100 -Subject: [PATCH] v2v: -i libvirtxml: Fix handling of nbd sources - (RHBZ#1153589). - -Previously I modified the parse_libvirt_xml function to get rid of the -awkward 'map_source*' functions, and have the callers map over and -modify the source disks afterwards. However this broke the case where -an "nbd:..." URL was returned by parse_libvirt_xml, since the callers -might try to map this URL (eg. turning it into an absolute path). -This broke virt-p2v specifically. - -This commit changes parse_libvirt_xml to return a list of tuples -containing disk information, giving the callers more information with -which to do the mapping. - -This fixes commit 3596165282ccf2c5896894ec4e9a71c6da788463. - -(cherry picked from commit ad78d1492b02eaf5d810e2f9d012a5fed4f4124b) ---- - v2v/input_libvirt_other.ml | 5 ++++- - v2v/input_libvirt_vcenter_https.ml | 44 ++++++++++++++++++++++++-------------- - v2v/input_libvirt_xen_ssh.ml | 10 ++++++--- - v2v/input_libvirtxml.ml | 38 +++++++++++++++++++++----------- - v2v/input_libvirtxml.mli | 17 +++++++++++++-- - 5 files changed, 80 insertions(+), 34 deletions(-) - -diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml -index a771aa1..9f3eedb 100644 ---- a/v2v/input_libvirt_other.ml -+++ b/v2v/input_libvirt_other.ml -@@ -70,7 +70,10 @@ object - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in - -- Input_libvirtxml.parse_libvirt_xml ~verbose xml -+ let source, disks = Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ let disks = -+ List.map (fun { Input_libvirtxml.p_source_disk = disk } -> disk) disks in -+ { source with s_disks = disks } - end - - let input_libvirt_other = new input_libvirt_other -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index 71c2edd..56097e0 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -24,6 +24,7 @@ open Common_utils - open Types - open Xml - open Utils -+open Input_libvirtxml - open Input_libvirt_other - - open Printf -@@ -235,20 +236,28 @@ object - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- let { s_disks = disks } as source = -- Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ let source, disks = parse_libvirt_xml ~verbose xml in - - (* Save the original source paths, so that we can remap them again - * in [#adjust_overlay_parameters]. - *) - List.iter ( -- fun { s_disk_id = id; s_qemu_uri = path } -> -- Hashtbl.add saved_source_paths id path -+ function -+ | { p_source = P_source_dev _ } -> -+ (* Should never happen ... *) -+ error (f_"source disk has attribute in XML") -+ | { p_source_disk = { s_disk_id = id }; p_source = P_dont_rewrite } -> -+ Hashtbl.add saved_source_paths id None -+ | { p_source_disk = { s_disk_id = id }; p_source = P_source_file path } -> -+ Hashtbl.add saved_source_paths id (Some path) - ) disks; - -+ let readahead = readahead_for_conversion in - let disks = List.map ( -- fun ({ s_qemu_uri = path } as disk) -> -- let readahead = readahead_for_conversion in -+ function -+ | { 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 = map_source_to_uri ?readahead - verbose parsed_uri scheme server path in - -@@ -265,18 +274,21 @@ object - let orig_path = - try Hashtbl.find saved_source_paths overlay.ov_source.s_disk_id - with Not_found -> failwith "internal error in adjust_overlay_parameters" in -- let backing_qemu_uri = -+ match orig_path with -+ | None -> () -+ | Some orig_path -> - let readahead = readahead_for_copying in -- map_source_to_uri ?readahead -- verbose parsed_uri scheme server orig_path in -+ let backing_qemu_uri = -+ map_source_to_uri ?readahead -+ verbose parsed_uri scheme server orig_path in - -- (* Rebase the qcow2 overlay to adjust the readahead parameter. *) -- let cmd = -- sprintf "qemu-img rebase -u -b %s %s" -- (quote backing_qemu_uri) (quote overlay.ov_overlay_file) in -- if verbose then printf "%s\n%!" cmd; -- if Sys.command cmd <> 0 then -- warning ~prog (f_"qemu-img rebase failed (ignored)") -+ (* Rebase the qcow2 overlay to adjust the readahead parameter. *) -+ let cmd = -+ sprintf "qemu-img rebase -u -b %s %s" -+ (quote backing_qemu_uri) (quote overlay.ov_overlay_file) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ warning ~prog (f_"qemu-img rebase failed (ignored)") - end - - let input_libvirt_vcenter_https = new input_libvirt_vcenter_https -diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml -index 8b836a5..e1600a0 100644 ---- a/v2v/input_libvirt_xen_ssh.ml -+++ b/v2v/input_libvirt_xen_ssh.ml -@@ -24,6 +24,7 @@ open Common_utils - open Types - open Xml - open Utils -+open Input_libvirtxml - open Input_libvirt_other - - open Printf -@@ -45,8 +46,7 @@ object - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -- let { s_disks = disks } as source = -- Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ let source, disks = parse_libvirt_xml ~verbose xml in - - (* Map the filename (which is relative to the remote - * Xen server) to an ssh URI. This is a JSON URI looking something -@@ -61,7 +61,11 @@ object - * "file.host_key_check": "no" - *) - let disks = List.map ( -- fun ({ s_qemu_uri = path } as disk) -> -+ function -+ | { p_source_disk = disk; p_source = P_dont_rewrite } -> -+ disk -+ | { p_source_disk = disk; p_source = P_source_dev path } -+ | { p_source_disk = disk; p_source = P_source_file path } -> - (* Construct the JSON parameters. *) - let json_params = [ - "file.driver", JSON.String "ssh"; -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 0cfd75c..c71260f 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -24,6 +24,15 @@ open Common_utils - open Types - open Utils - -+type parsed_disk = { -+ p_source_disk : source_disk; -+ p_source : parsed_source; -+} -+and parsed_source = -+| P_source_dev of string -+| P_source_file of string -+| P_dont_rewrite -+ - let parse_libvirt_xml ~verbose xml = - if verbose then - printf "libvirt xml is:\n%s\n" xml; -@@ -105,12 +114,13 @@ let parse_libvirt_xml ~verbose xml = - let get_disks, add_disk = - let disks = ref [] and i = ref 0 in - let get_disks () = List.rev !disks in -- let add_disk qemu_uri format target_dev = -+ let add_disk qemu_uri format target_dev p_source = - incr i; - disks := -- { s_disk_id = !i; -- s_qemu_uri = qemu_uri; s_format = format; -- s_target_dev = target_dev } :: !disks -+ { p_source_disk = { s_disk_id = !i; -+ s_qemu_uri = qemu_uri; s_format = format; -+ s_target_dev = target_dev }; -+ p_source = p_source } :: !disks - in - get_disks, add_disk - in -@@ -141,11 +151,11 @@ let parse_libvirt_xml ~verbose xml = - | "block" -> - let path = xpath_to_string "source/@dev" "" in - if path <> "" then -- add_disk path format target_dev -+ add_disk path format target_dev (P_source_dev path) - | "file" -> - let path = xpath_to_string "source/@file" "" in - if path <> "" then -- add_disk path format target_dev -+ add_disk path format target_dev (P_source_file path) - | "network" -> - (* We only handle here, and that is - * intended only for virt-p2v. Any other network disk is -@@ -160,7 +170,7 @@ let parse_libvirt_xml ~verbose xml = - * XXX Quoting, although it's not needed for virt-p2v. - *) - let path = sprintf "nbd:%s:%d" host port in -- add_disk path format target_dev -+ add_disk path format target_dev (P_dont_rewrite) - ) - | "" -> () - | protocol -> -@@ -236,17 +246,18 @@ let parse_libvirt_xml ~verbose xml = - done; - List.rev !nics in - -- { -+ ({ - s_dom_type = dom_type; - s_name = name; s_orig_name = name; - s_memory = memory; - s_vcpu = vcpu; - s_features = features; - s_display = display; -- s_disks = disks; -+ s_disks = []; - s_removables = removables; - s_nics = nics; -- } -+ }, -+ disks) - - class input_libvirtxml verbose file = - object -@@ -257,7 +268,7 @@ object - method source () = - let xml = read_whole_file file in - -- let { s_disks = disks } as source = parse_libvirt_xml ~verbose xml in -+ let source, disks = parse_libvirt_xml ~verbose xml in - - (* When reading libvirt XML from a file (-i libvirtxml) we allow - * paths to disk images in the libvirt XML to be relative (to the XML -@@ -267,7 +278,10 @@ object - *) - let dir = Filename.dirname (absolute_path file) in - let disks = List.map ( -- fun ({ s_qemu_uri = path } as disk) -> -+ function -+ | { p_source_disk = disk; p_source = P_dont_rewrite } -> disk -+ | { p_source_disk = disk; p_source = P_source_dev _ } -> disk -+ | { p_source_disk = disk; p_source = P_source_file path } -> - let path = - if not (Filename.is_relative path) then path else dir // path in - { disk with s_qemu_uri = path } -diff --git a/v2v/input_libvirtxml.mli b/v2v/input_libvirtxml.mli -index 5c10df0..e450899 100644 ---- a/v2v/input_libvirtxml.mli -+++ b/v2v/input_libvirtxml.mli -@@ -18,8 +18,21 @@ - - (** [-i libvirtxml] source. *) - --val parse_libvirt_xml : verbose:bool -> string -> Types.source --(** Take libvirt XML and parse it into a {!Types.source} structure. -+type parsed_disk = { -+ p_source_disk : Types.source_disk; (** Source disk. *) -+ p_source : parsed_source; (** *) -+} -+and parsed_source = -+| P_source_dev of string (** *) -+| P_source_file of string (** *) -+| P_dont_rewrite (** s_qemu_uri is already set. *) -+ -+val parse_libvirt_xml : verbose:bool -> string -> Types.source * parsed_disk list -+(** Take libvirt XML and parse it into a {!Types.source} structure and a -+ list of source disks. -+ -+ {b Note} the [source.s_disks] field is an empty list. The caller -+ must map over the parsed disks and update the [source.s_disks] field. - - This function is also used by {!Input_libvirt}, hence it is - exported. *) --- -1.8.3.1 - diff --git a/SOURCES/0022-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch b/SOURCES/0022-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch new file mode 100644 index 0000000..1a78327 --- /dev/null +++ b/SOURCES/0022-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch @@ -0,0 +1,46 @@ +From 410fa0a977ce7d950c38b86361b3cf7d0e60c773 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 27 May 2015 10:03:00 -0400 +Subject: [PATCH] RHEL 7: All qemu-kvm in RHEL 7 supports discard of qcow2 + (RHBZ#1225467). + +For rationale behind this, see: + + https://bugzilla.redhat.com/show_bug.cgi?id=1225467#c2 +--- + src/launch-direct.c | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/src/launch-direct.c b/src/launch-direct.c +index 52f73ec..cbaf4f3 100644 +--- a/src/launch-direct.c ++++ b/src/launch-direct.c +@@ -1408,10 +1408,6 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, + * discard option on -drive at all. + */ + bool qemu15 = qemu_version >= 1005000; +- /* qemu >= 1.6. This was the first version that supported unmap on +- * qcow2 backing files. +- */ +- bool qemu16 = qemu_version >= 1006000; + + if (!qemu15) + NOT_SUPPORTED (g, false, +@@ -1436,12 +1432,8 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, + } + else if (STREQ (drv->src.format, "raw")) + /* OK */ ; +- else if (STREQ (drv->src.format, "qcow2")) { +- if (!qemu16) +- NOT_SUPPORTED (g, false, +- _("discard cannot be enabled on this drive: " +- "qemu < 1.6 cannot do discard on qcow2 files")); +- } ++ else if (STREQ (drv->src.format, "qcow2")) ++ /* OK */ ; + else { + /* It's possible in future other formats will support discard, but + * currently (qemu 1.7) none of them do. +-- +1.8.3.1 + diff --git a/SOURCES/0022-v2v-i-ova-Don-t-fail-when-given-a-relative-path-to-a.patch b/SOURCES/0022-v2v-i-ova-Don-t-fail-when-given-a-relative-path-to-a.patch deleted file mode 100644 index bf8beed..0000000 --- a/SOURCES/0022-v2v-i-ova-Don-t-fail-when-given-a-relative-path-to-a.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 4de6d5e94dd9b38c86aca5554a16488f9d3dee00 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 21 Oct 2014 13:36:55 +0100 -Subject: [PATCH] v2v: -i ova: Don't fail when given a relative path to an OVA - directory (RHBZ#1155121). - -(cherry picked from commit e1eccae2da3a670c1ef7626c8779b71fb1877f7d) ---- - v2v/input_ova.ml | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 6349c76..d9928de 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -66,6 +66,11 @@ object - error (f_"%s: unsupported file format") ova - ) in - -+ (* Exploded path must be absolute (RHBZ#1155121). *) -+ let exploded = -+ if not (Filename.is_relative exploded) then exploded -+ else Sys.getcwd () // exploded in -+ - let files = Sys.readdir exploded in - let ovf = ref "" in - (* Search for the ovf file. *) --- -1.8.3.1 - diff --git a/SOURCES/0023-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch b/SOURCES/0023-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch new file mode 100644 index 0000000..5226c27 --- /dev/null +++ b/SOURCES/0023-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch @@ -0,0 +1,28 @@ +From 11d82bf8764acb181364742eef6045aaef2fd711 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 21 Sep 2015 13:12:43 -0400 +Subject: [PATCH] RHEL 7: tests: Disable daemon tests that require the 'unix' + backend. + +--- + tests/daemon/Makefile.am | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/tests/daemon/Makefile.am b/tests/daemon/Makefile.am +index 053cad3..0d723fe 100644 +--- a/tests/daemon/Makefile.am ++++ b/tests/daemon/Makefile.am +@@ -23,9 +23,7 @@ include $(top_srcdir)/subdir-rules.mk + + check_DATA = captive-daemon.pm + +-TESTS = \ +- test-daemon-start.pl \ +- test-btrfs.pl ++TESTS = + + TESTS_ENVIRONMENT = $(top_builddir)/run --test + +-- +1.8.3.1 + diff --git a/SOURCES/0023-bash-completion-Replace-ln-sf-commands-with-rm-LN_S.patch b/SOURCES/0023-bash-completion-Replace-ln-sf-commands-with-rm-LN_S.patch deleted file mode 100644 index 80f0afc..0000000 --- a/SOURCES/0023-bash-completion-Replace-ln-sf-commands-with-rm-LN_S.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 8b486425c13d558742df915092d4b2c3a96a95b8 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 24 Oct 2014 09:12:56 +0100 -Subject: [PATCH] bash-completion: Replace 'ln -sf' commands with rm; $(LN_S). - -(cherry picked from commit 68ac0afc8d578bede4a80ebaab07bc54a535a4ef) ---- - bash/Makefile.am | 33 ++++++++++++++++++++++----------- - 1 file changed, 22 insertions(+), 11 deletions(-) - -diff --git a/bash/Makefile.am b/bash/Makefile.am -index 2da6726..e8c33d4 100644 ---- a/bash/Makefile.am -+++ b/bash/Makefile.am -@@ -41,28 +41,39 @@ EXTRA_DIST = \ - - # Some of the scripts are simply symbolic links. - virt-cat: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-df: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-edit: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-filesystems: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-format: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-inspector: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-log: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-ls: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - virt-sysprep: -- ln -sf virt-alignment-scan $@ -+ rm -f $@ -+ $(LN_S) virt-alignment-scan $@ - - virt-builder: -- ln -sf virt-resize $@ -+ rm -f $@ -+ $(LN_S) virt-resize $@ - virt-sparsify: -- ln -sf virt-resize $@ -+ rm -f $@ -+ $(LN_S) virt-resize $@ - - if HAVE_BASH_COMPLETION - --- -1.8.3.1 - diff --git a/SOURCES/0024-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch b/SOURCES/0024-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch new file mode 100644 index 0000000..2d4f370 --- /dev/null +++ b/SOURCES/0024-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch @@ -0,0 +1,224 @@ +From 7a19cd75929d88d5b3512895138e5bde6b92b157 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 14 Jan 2016 11:53:42 -0500 +Subject: [PATCH] RHEL 7: v2v: Disable the virt-v2v --in-place option. + +This disables the virt-v2v --in-place option which we do not +wish to support in RHEL. +(See commit d0069559a939e47e5f29973ed9a69a13f0b58301). +--- + v2v/Makefile.am | 1 - + v2v/cmdline.ml | 6 ++- + v2v/test-v2v-in-place.sh | 121 ----------------------------------------------- + v2v/virt-v2v.pod | 17 ------- + 4 files changed, 5 insertions(+), 140 deletions(-) + delete mode 100755 v2v/test-v2v-in-place.sh + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 8a79a6f..d9cf986 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -296,7 +296,6 @@ TESTS += \ + test-v2v-cdrom.sh \ + test-v2v-i-ova.sh \ + test-v2v-i-disk.sh \ +- test-v2v-in-place.sh \ + test-v2v-machine-readable.sh \ + test-v2v-networks-and-bridges.sh \ + test-v2v-no-copy.sh \ +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 32eb873..4623af9 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -194,7 +194,7 @@ let parse_cmdline () = + "uri " ^ s_"Libvirt URI"; + "-if", Arg.String (set_string_option_once "-if" input_format), + "format " ^ s_"Input format (for -i disk)"; +- "--in-place", Arg.Set in_place, " " ^ s_"Only tune the guest in the input VM"; ++ "--in-place", Arg.Set in_place, " " ^ s_"Unsupported option in RHEL 7"; + "--machine-readable", Arg.Set machine_readable, " " ^ s_"Make output machine readable"; + "-n", Arg.String add_network, "in:out " ^ s_"Map network 'in' to 'out'"; + "--network", Arg.String add_network, "in:out " ^ ditto; +@@ -352,6 +352,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 + ++ (* Prevent use of --in-place option in RHEL. *) ++ if in_place then ++ error (f_"--in-place cannot be used in RHEL 7"); ++ + (* Parse the output mode. *) + if output_mode <> `Not_set && in_place then + error (f_"-o and --in-place cannot be used at the same time"); +diff --git a/v2v/test-v2v-in-place.sh b/v2v/test-v2v-in-place.sh +deleted file mode 100755 +index e55daa0..0000000 +--- a/v2v/test-v2v-in-place.sh ++++ /dev/null +@@ -1,121 +0,0 @@ +-#!/bin/bash - +-# libguestfs virt-v2v test script +-# Copyright (C) 2014 Red Hat Inc. +-# Copyright (C) 2015 Parallels IP Holdings GmbH. +-# +-# 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 --in-place. +- +-unset CDPATH +-export LANG=C +-set -e +- +-if [ -n "$SKIP_TEST_V2V_IN_PLACE_SH" ]; then +- echo "$0: test skipped because environment variable is set" +- exit 77 +-fi +- +-if [ "$(guestfish get-backend)" = "uml" ]; then +- echo "$0: test skipped because UML backend does not support network" +- exit 77 +-fi +- +-abs_top_builddir="$(cd ..; pwd)" +- +-img_base="$abs_top_builddir/test-data/phony-guests/windows.img" +-if ! test -f $img_base || ! test -s $img_base; then +- echo "$0: test skipped because phony Windows image was not created" +- exit 77 +-fi +- +-export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" +-export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win" +- +-. $srcdir/../test-data/guestfs-hashsums.sh +- +-d=$PWD/test-v2v-in-place.d +-rm -rf $d +-mkdir $d +- +-img="$d/test.qcow2" +-rm -f $img +-qemu-img create -f qcow2 -b $img_base -o compat=1.1,backing_fmt=raw $img +-md5="$(do_md5 $img_base)" +- +-libvirt_xml="$d/test.xml" +-rm -f $libvirt_xml +-n=windows-overlay +-cat > $libvirt_xml < +- +- $n +- 1048576 +- +- hvm +- +- +- +- +- +- +- +- +- +- +- +-EOF +- +-$VG virt-v2v --debug-gc -i libvirt -ic "test://$libvirt_xml" $n --in-place +- +-# Test that the drivers have been copied over into the guest +-script="$d/test.fish" +-expected="$d/expected" +-response="$d/response" +- +-mktest () +-{ +- local cmd="$1" exp="$2" +- +- echo "echo '$cmd'" >> "$script" +- echo "$cmd" >> "$expected" +- +- echo "$cmd" >> "$script" +- echo "$exp" >> "$expected" +-} +- +-:> "$script" +-:> "$expected" +- +-firstboot_dir="/Program Files/Red Hat/Firstboot" +-mktest "is-dir \"$firstboot_dir\"" true +-mktest "is-file \"$firstboot_dir/firstboot.bat\"" true +-mktest "is-dir \"$firstboot_dir/scripts\"" true +-virtio_dir="/Windows/Drivers/VirtIO" +-mktest "is-dir \"$virtio_dir\"" true +-for drv in netkvm qxl vioscsi viostor; do +- for sfx in cat inf sys; do +- mktest "is-file \"$virtio_dir/$drv.$sfx\"" true +- done +-done +- +-guestfish --ro -a "$img" -i < "$script" > "$response" +-diff -u "$expected" "$response" +- +-# Test the base image remained untouched +-test "$md5" = "$(do_md5 $img_base)" +- +-# Clean up. +-rm -r $d +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 8e5cf1d..5800b34 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -15,8 +15,6 @@ virt-v2v - Convert a guest to use KVM + + virt-v2v -i disk disk.img -o glance + +- virt-v2v -ic qemu:///system qemu_guest --in-place +- + =head1 DESCRIPTION + + Virt-v2v converts guests from a foreign hypervisor to run on KVM. It +@@ -77,9 +75,6 @@ booting the guest directly in qemu (mainly for testing). + I<-o rhev> is used to write to a RHEV-M / oVirt target. I<-o vdsm> + is only used when virt-v2v runs under VDSM control. + +-I<--in-place> instructs virt-v2v to customize the guest OS in the input +-virtual machine, instead of creating a new VM in the target hypervisor. +- + =head1 EXAMPLES + + =head2 Convert from VMware vCenter server to local libvirt +@@ -248,18 +243,6 @@ 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<--in-place> +- +-Do not create an output virtual machine in the target hypervisor. +-Instead, adjust the guest OS in the source VM to run in the input +-hypervisor. +- +-This mode is meant for integration with other toolsets, which take the +-responsibility of converting the VM configuration, providing for +-rollback in case of errors, transforming the storage, etc. +- +-Conflicts with all I<-o *> options. +- + =item B<--machine-readable> + + This option is used to make the output more machine friendly +-- +1.8.3.1 + diff --git a/SOURCES/0024-bash-completion-Install-symbolic-links-instead-of-co.patch b/SOURCES/0024-bash-completion-Install-symbolic-links-instead-of-co.patch deleted file mode 100644 index b1e09e2..0000000 --- a/SOURCES/0024-bash-completion-Install-symbolic-links-instead-of-co.patch +++ /dev/null @@ -1,48 +0,0 @@ -From c4e4abe7b3e36a260685d258258122610eb9193e Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 24 Oct 2014 09:13:25 +0100 -Subject: [PATCH] bash-completion: Install symbolic links instead of copies of - files (RHBZ#1156298). - -(cherry picked from commit a5a0c2f3b047ebb064d54d5029b1d1e475375668) ---- - bash/Makefile.am | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/bash/Makefile.am b/bash/Makefile.am -index e8c33d4..10f0861 100644 ---- a/bash/Makefile.am -+++ b/bash/Makefile.am -@@ -35,9 +35,14 @@ scripts = \ - virt-sparsify \ - virt-sysprep - -+# Note: Don't distribute the symbolic links, only the real files. - EXTRA_DIST = \ - README \ -- $(scripts) -+ guestfish \ -+ guestmount \ -+ virt-alignment-scan \ -+ virt-rescue \ -+ virt-resize - - # Some of the scripts are simply symbolic links. - virt-cat: -@@ -80,6 +85,12 @@ if HAVE_BASH_COMPLETION - # Bash completion script. - - bashcompletiondir = $(BASH_COMPLETIONS_DIR) --bashcompletion_DATA = $(scripts) -+#bashcompletion_DATA = $(scripts) -+ -+all-local: $(scripts) -+ -+install-data-local: $(scripts) -+ $(mkdir_p) $(DESTDIR)$(bashcompletiondir) -+ cp -d $(scripts) $(DESTDIR)$(bashcompletiondir) - - endif --- -1.8.3.1 - diff --git a/SOURCES/0025-inspector-Document-that-a-option-can-take-a-URI-for-.patch b/SOURCES/0025-inspector-Document-that-a-option-can-take-a-URI-for-.patch deleted file mode 100644 index 938a87e..0000000 --- a/SOURCES/0025-inspector-Document-that-a-option-can-take-a-URI-for-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 99e1e58e719e14daa3023feee068ee1d97f09d51 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 24 Oct 2014 09:53:21 +0100 -Subject: [PATCH] inspector: Document that -a option can take a URI for remote - storage (RHBZ#1156301). - -(cherry picked from commit 62c84c6a551cccd2dfe6b1ca393504c5fea4b435) ---- - inspector/virt-inspector.pod | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/inspector/virt-inspector.pod b/inspector/virt-inspector.pod -index f8744b1..1282608 100644 ---- a/inspector/virt-inspector.pod -+++ b/inspector/virt-inspector.pod -@@ -68,6 +68,12 @@ them with separate I<-a> options. - The format of the disk image is auto-detected. To override this and - force a particular format use the I<--format=..> option. - -+=item B<-a> URI -+ -+=item B<--add> URI -+ -+Add a remote disk. See L. -+ - =item B<-c URI> - - =item B<--connect URI> --- -1.8.3.1 - diff --git a/SOURCES/0025-p2v-User-can-click-on-an-interface-name-to-identify-.patch b/SOURCES/0025-p2v-User-can-click-on-an-interface-name-to-identify-.patch new file mode 100644 index 0000000..254d8b7 --- /dev/null +++ b/SOURCES/0025-p2v-User-can-click-on-an-interface-name-to-identify-.patch @@ -0,0 +1,137 @@ +From a45d0183563fb3bb3b08d5d0a8ffcc5205d40a9b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 26 Jan 2016 15:34:09 +0000 +Subject: [PATCH] p2v: User can click on an interface name to identify the + physical interface. + +When the user clicks on the second column of the list of network +interfaces, run 'ethtool --identify 10', which (on supported +cards) flashes a light on the physical interface for 10 seconds, +allowing it to be identified by the operator. + +(cherry picked from commit 81ff8c5d23642667569833cd820e84814157580b) +--- + p2v/gui.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- + p2v/virt-p2v.pod | 4 ++++ + 2 files changed, 73 insertions(+), 1 deletion(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index c345e34..569a295 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -418,6 +418,7 @@ static void populate_removable (GtkTreeView *removable_list); + static void populate_interfaces (GtkTreeView *interfaces_list); + static void toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data); + static void network_edited_callback (GtkCellRendererToggle *cell, gchar *path_str, gchar *new_text, gpointer data); ++static gboolean maybe_identify_click (GtkWidget *interfaces_list, GdkEventButton *event, gpointer data); + static void set_disks_from_ui (struct config *); + static void set_removable_from_ui (struct config *); + static void set_interfaces_from_ui (struct config *); +@@ -653,6 +654,10 @@ create_conversion_dialog (struct config *config) + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (interfaces_sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + interfaces_list = gtk_tree_view_new (); ++ /* See maybe_identify_click below for what we're doing. */ ++ g_signal_connect (interfaces_list, "button-press-event", ++ G_CALLBACK (maybe_identify_click), NULL); ++ gtk_widget_set_tooltip_markup (interfaces_list, _("Left click on an interface name to flash the light on the physical interface.")); + populate_interfaces (GTK_TREE_VIEW (interfaces_list)); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (interfaces_sw), + interfaces_list); +@@ -944,7 +949,8 @@ populate_interfaces (GtkTreeView *interfaces_list) + "" + "%s\n" + "%s" +- "", ++ "\n" ++ "Identify interface", + if_name, + if_addr ? : _("Unknown"), + if_vendor ? : _("Unknown")) == -1) { +@@ -1034,6 +1040,68 @@ network_edited_callback (GtkCellRendererToggle *cell, gchar *path_str, + gtk_tree_path_free (path); + } + ++/* When the user clicks on the interface name on the list of ++ * interfaces, we want to run 'ethtool --identify', which usually ++ * makes some lights flash on the physical interface. We cannot catch ++ * clicks on the cell itself, so we have to go via a more obscure ++ * route. See http://stackoverflow.com/a/27207433 and ++ * https://en.wikibooks.org/wiki/GTK%2B_By_Example/Tree_View/Events ++ */ ++static gboolean ++maybe_identify_click (GtkWidget *interfaces_list, GdkEventButton *event, ++ gpointer data) ++{ ++ gboolean ret = FALSE; /* Did we handle this event? */ ++ ++ /* Single left click only. */ ++ if (event->type == GDK_BUTTON_PRESS && event->button == 1) { ++ GtkTreePath *path; ++ GtkTreeViewColumn *column; ++ ++ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (interfaces_list), ++ event->x, event->y, ++ &path, &column, NULL, NULL)) { ++ GList *cols; ++ gint column_index; ++ ++ /* Get column index. */ ++ cols = gtk_tree_view_get_columns (GTK_TREE_VIEW (interfaces_list)); ++ column_index = g_list_index (cols, (gpointer) column); ++ g_list_free (cols); ++ ++ if (column_index == INTERFACES_COL_DEVICE) { ++ const gint *indices; ++ gint row_index; ++ const char *if_name; ++ char *cmd; ++ ++ /* Get the row index. */ ++ indices = gtk_tree_path_get_indices (path); ++ row_index = indices[0]; ++ ++ /* And the interface name. */ ++ if_name = all_interfaces[row_index]; ++ ++ /* Issue the ethtool command in the background. */ ++ if (asprintf (&cmd, "ethtool --identify '%s' 10 &", if_name) == -1) { ++ perror ("asprintf"); ++ exit (EXIT_FAILURE); ++ } ++ printf ("%s\n", cmd); ++ ignore_value (system (cmd)); ++ ++ free (cmd); ++ ++ ret = TRUE; /* We handled this event. */ ++ } ++ ++ gtk_tree_path_free (path); ++ } ++ } ++ ++ return ret; ++} ++ + static void + set_from_ui_generic (char **all, char ***ret, GtkTreeView *list) + { +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index a3987f4..3e4ef99 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -232,6 +232,10 @@ should be created in the guest after conversion. You can also connect + these to target hypervisor networks (for further information about + this feature, see L). + ++On supported hardware, left-clicking on the device name (eg. C) ++causes a light to start flashing on the physical interface, allowing ++the interface to be identified by the operator. ++ + When you are ready to begin the conversion, press the + C button: + +-- +1.8.3.1 + diff --git a/SOURCES/0026-p2v-Add-Hardware-Support-group-to-the-P2V-images-RHB.patch b/SOURCES/0026-p2v-Add-Hardware-Support-group-to-the-P2V-images-RHB.patch deleted file mode 100644 index dc4683b..0000000 --- a/SOURCES/0026-p2v-Add-Hardware-Support-group-to-the-P2V-images-RHB.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 87979f276677b934e930e2cb78803715635e4496 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 27 Oct 2014 13:41:49 +0000 -Subject: [PATCH] p2v: Add "Hardware Support" group to the P2V images - (RHBZ#1157679). - -Thanks: Chris Adams -(cherry picked from commit 91788cd76f23227c102293a5dc5eef1c30cf7858) ---- - p2v/p2v.ks.in | 1 + - p2v/virt-p2v-make-disk.in | 3 ++- - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/p2v/p2v.ks.in b/p2v/p2v.ks.in -index 3019c4e..c21424f 100644 ---- a/p2v/p2v.ks.in -+++ b/p2v/p2v.ks.in -@@ -64,6 +64,7 @@ matchbox-window-manager - pcre - libxml2 - gtk2 -+@hardware-support --optional - - %end - -diff --git a/p2v/virt-p2v-make-disk.in b/p2v/virt-p2v-make-disk.in -index af1d6f4..c29af2c 100644 ---- a/p2v/virt-p2v-make-disk.in -+++ b/p2v/virt-p2v-make-disk.in -@@ -85,12 +85,13 @@ osversion="$1" - # - Xorg (or another X server, but only Xorg has been tested) - # - Xorg drivers - # - some fonts -+# - hardware support (firmware etc, RHBZ#1157679) - # - matchbox (window manager, another could be used) - # - # Note that libguestfs is NOT a dependency. - case "$osversion" in - centos-*|fedora-*|rhel-*|scientificlinux-*) -- deps=pcre,libxml2,gtk2,/usr/bin/xinit,/usr/bin/ssh,/usr/bin/qemu-nbd,/usr/bin/Xorg,xorg-x11-drivers,xorg-x11-fonts-Type1,matchbox-window-manager -+ deps=pcre,libxml2,gtk2,/usr/bin/xinit,/usr/bin/ssh,/usr/bin/qemu-nbd,/usr/bin/Xorg,xorg-x11-drivers,xorg-x11-fonts-Type1,matchbox-window-manager,@hardware-support - selinux_relabel=--selinux-relabel - ;; - debian-*|ubuntu-*) --- -1.8.3.1 - diff --git a/SOURCES/0026-p2v-virt-p2v-make-disk-Make-os-version-parameter-opt.patch b/SOURCES/0026-p2v-virt-p2v-make-disk-Make-os-version-parameter-opt.patch new file mode 100644 index 0000000..8366416 --- /dev/null +++ b/SOURCES/0026-p2v-virt-p2v-make-disk-Make-os-version-parameter-opt.patch @@ -0,0 +1,130 @@ +From 57b9f5b7827c0545ee286b3f0cfab7ae5fcadeb1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 27 Jan 2016 11:48:53 +0000 +Subject: [PATCH] p2v: virt-p2v-make-disk: Make os-version parameter optional. + +Having to choose the os-version of the virt-p2v disk was confusing. +Users thought it had something to do with the physical machine being +converted. + +In some cases, virt-p2v-make-disk can now choose a suitable os-version +for the user. Usually it's the latest numeric version of Fedora or +Debian, depending on the host distro. If we don't recognize the host +distro, we bail and ask the user to choose, but this is still an +improvement. + +(cherry picked from commit 3aaa4c9419d539dada31004b47121bbaac5241c6) +--- + p2v/virt-p2v-make-disk.in | 26 ++++++++++++++++++++++---- + p2v/virt-p2v-make-disk.pod | 30 ++++++++++++++++++------------ + 2 files changed, 40 insertions(+), 16 deletions(-) + +diff --git a/p2v/virt-p2v-make-disk.in b/p2v/virt-p2v-make-disk.in +index 6769707..88c171f 100644 +--- a/p2v/virt-p2v-make-disk.in ++++ b/p2v/virt-p2v-make-disk.in +@@ -38,7 +38,7 @@ upload= + usage () + { + echo "Usage:" +- echo " $program [--options] -o /dev/sdX os-version" ++ echo " $program [--options] -o /dev/sdX [os-version]" + echo + echo "Read $program(1) man page for more information." + exit $1 +@@ -71,12 +71,30 @@ if [ -z "$output" ]; then + exit 1 + fi + +-if [ $# -ne 1 ]; then +- echo "$program: Missing os-version. See $program(1)." ++if [ $# -gt 1 ]; then ++ echo "$program: Too many parameters. See $program(1)." + exit 1 + fi + +-osversion="$1" ++if [ $# -eq 1 ]; then ++ osversion="$1" ++else ++ # If osversion was not set, then we must guess a good value ++ # based on the host distro. ++ if test -f /etc/redhat-release; then ++ osversion="$(virt-builder -l | sort | ++ @AWK@ '/^fedora-[1-9]/ {print $1}' | tail -1)" ++ elif test -f /etc/debian_version; then ++ osversion="$(virt-builder -l | sort | ++ @AWK@ '/^debian-[1-9]/ {print $1}' | tail -1)" ++ fi ++ if [ "x$osversion" = "x" ]; then ++ echo "$program: unable to guess a suitable os-version." ++ echo "You must supply one on the command line and output of 'virt-builder -l'." ++ echo "See $program(1) for further details." ++ exit 1 ++ fi ++fi + + # Create a temporary directory and clean it up when we finish. + tmpdir="$(mktemp -d)" +diff --git a/p2v/virt-p2v-make-disk.pod b/p2v/virt-p2v-make-disk.pod +index d401097..79bf499 100644 +--- a/p2v/virt-p2v-make-disk.pod ++++ b/p2v/virt-p2v-make-disk.pod +@@ -4,7 +4,7 @@ virt-p2v-make-disk - Build the virt-p2v disk using virt-builder + + =head1 SYNOPSIS + +- virt-p2v-make-disk -o /dev/sdX os-version ++ virt-p2v-make-disk -o /dev/sdX [os-version] + + =head1 DESCRIPTION + +@@ -17,28 +17,34 @@ virt-p2v-make-disk is a script which creates a bootable disk image or + USB key containing virt-p2v. It uses L to do this, + and is just a small shell script around virt-builder. + +-virt-p2v-make-disk has two required parameters: ++The required I<-o> parameter specifies where the output should go, for ++example to a USB key (eg. C<-o /dev/sdX>) or to a file. If you pass a ++device name, then B. + +-The I<-o> parameter specifies where the output should go, for example +-to a USB key (eg. C<-o /dev/sdX>) or to a file. If you pass a device +-name, then B. ++=head2 C parameter + +-The C parameter is the base Linux distro to use for the +-operating system on the ISO. To list possible C +-combinations, do: ++The optional C parameter is the base Linux distro to use ++for the operating system on the ISO. If you don't set this parameter, ++the script tries to choose a suitable default for you. Most users ++should I use the C parameter. ++ ++The base OS selected for virt-p2v is not related in any way to the OS ++of the physical machine that you are trying to convert. ++ ++To list possible C combinations, do: + + virt-builder -l + +-=head2 EXAMPLES ++=head1 EXAMPLES + + Write a virt-p2v bootable USB key on F (any existing content +-is erased), using Fedora 20 as the base distribution: ++on F is erased): + +- virt-p2v-make-disk -o /dev/sdX fedora-20 ++ virt-p2v-make-disk -o /dev/sdX + + Write a virt-p2v bootable virtual disk image, and boot it under qemu: + +- virt-p2v-make-disk -o /var/tmp/p2v.img fedora-20 ++ virt-p2v-make-disk -o /var/tmp/p2v.img + qemu-kvm -m 1024 -boot c \ + -drive file=/var/tmp/p2v.img,if=virtio,index=0 \ + -drive file=/var/tmp/guest.img,if=virtio,index=1 +-- +1.8.3.1 + diff --git a/SOURCES/0027-daemon-glob-add-optarg-to-control-trailing-slash-for.patch b/SOURCES/0027-daemon-glob-add-optarg-to-control-trailing-slash-for.patch new file mode 100644 index 0000000..5d5ef7b --- /dev/null +++ b/SOURCES/0027-daemon-glob-add-optarg-to-control-trailing-slash-for.patch @@ -0,0 +1,138 @@ +From f0891277008c6535aa12e2e9b1b52eb8da6bc678 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 4 Feb 2016 10:45:20 +0100 +Subject: [PATCH] daemon: glob: add optarg to control trailing slash for dirs + +Add a new optional bool "directoryslash" to indicate whether the caller +wants trailing slashes in names of directories, defaulting to true (the +current behaviour); this helps with interoperability with other tools +(such as rm). + +Related to RHBZ#1293271. + +(cherry picked from commit 01f46e4e3128b8d8ab009ca198de440e776c2cd6) +--- + daemon/glob.c | 11 +++++++++-- + generator/actions.ml | 21 ++++++++++++++++----- + gobject/Makefile.inc | 2 ++ + po/POTFILES | 1 + + 4 files changed, 28 insertions(+), 7 deletions(-) + +diff --git a/daemon/glob.c b/daemon/glob.c +index 45fb30f..a22fd33 100644 +--- a/daemon/glob.c ++++ b/daemon/glob.c +@@ -26,14 +26,21 @@ + #include "actions.h" + + char ** +-do_glob_expand (const char *pattern) ++do_glob_expand (const char *pattern, int directoryslash) + { + int r; + glob_t buf = { .gl_pathc = 0, .gl_pathv = NULL, .gl_offs = 0 }; ++ int flags = GLOB_BRACE | GLOB_MARK; ++ ++ /* GLOB_MARK is default, unless the user explicitly disabled it. */ ++ if ((optargs_bitmask & GUESTFS_GLOB_EXPAND_DIRECTORYSLASH_BITMASK) ++ && !directoryslash) { ++ flags &= ~GLOB_MARK; ++ } + + /* glob(3) in glibc never calls chdir, so this seems to be safe: */ + CHROOT_IN; +- r = glob (pattern, GLOB_MARK|GLOB_BRACE, NULL, &buf); ++ r = glob (pattern, flags, NULL, &buf); + CHROOT_OUT; + + if (r == GLOB_NOMATCH) { /* Return an empty list instead of an error. */ +diff --git a/generator/actions.ml b/generator/actions.ml +index dfeb34c..998caa5 100644 +--- a/generator/actions.ml ++++ b/generator/actions.ml +@@ -5908,27 +5908,34 @@ See also: C" }; + * start with "/". There is no concept of "cwd" in libguestfs, + * hence no "."-relative names. + *) +- style = RStringList "paths", [Pathname "pattern"], []; ++ style = RStringList "paths", [Pathname "pattern"], [OBool "directoryslash"]; + proc_nr = Some 113; ++ once_had_no_optargs = true; + tests = [ + InitScratchFS, Always, TestResult ( + [["mkdir_p"; "/glob_expand/b/c"]; + ["touch"; "/glob_expand/b/c/d"]; + ["touch"; "/glob_expand/b/c/e"]; +- ["glob_expand"; "/glob_expand/b/c/*"]], ++ ["glob_expand"; "/glob_expand/b/c/*"; ""]], + "is_string_list (ret, 2, \"/glob_expand/b/c/d\", \"/glob_expand/b/c/e\")"), []; + InitScratchFS, Always, TestResult ( + [["mkdir_p"; "/glob_expand2/b/c"]; + ["touch"; "/glob_expand2/b/c/d"]; + ["touch"; "/glob_expand2/b/c/e"]; +- ["glob_expand"; "/glob_expand2/*/c/*"]], ++ ["glob_expand"; "/glob_expand2/*/c/*"; ""]], + "is_string_list (ret, 2, \"/glob_expand2/b/c/d\", \"/glob_expand2/b/c/e\")"), []; + InitScratchFS, Always, TestResult ( + [["mkdir_p"; "/glob_expand3/b/c"]; + ["touch"; "/glob_expand3/b/c/d"]; + ["touch"; "/glob_expand3/b/c/e"]; +- ["glob_expand"; "/glob_expand3/*/x/*"]], +- "is_string_list (ret, 0)"), [] ++ ["glob_expand"; "/glob_expand3/*/x/*"; ""]], ++ "is_string_list (ret, 0)"), []; ++ InitScratchFS, Always, TestResult ( ++ [["mkdir_p"; "/glob_expand4/b/c"]; ++ ["touch"; "/glob_expand4/b1"]; ++ ["touch"; "/glob_expand4/c1"]; ++ ["glob_expand"; "/glob_expand4/b*"; "false"]], ++ "is_string_list (ret, 2, \"/glob_expand4/b\", \"/glob_expand4/b1\")"), []; + ]; + shortdesc = "expand a wildcard path"; + longdesc = "\ +@@ -5943,6 +5950,10 @@ It is just a wrapper around the C L function + with flags C. + See that manual page for more details. + ++C controls whether use the C flag for ++L, and it defaults to true. It can be explicitly set as ++off to return no trailing slashes in filenames of directories. ++ + Notice that there is no equivalent command for expanding a device + name (eg. F). Use C, + C etc functions instead." }; +diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc +index 20c98ff..4b99a78 100644 +--- a/gobject/Makefile.inc ++++ b/gobject/Makefile.inc +@@ -69,6 +69,7 @@ guestfs_gobject_headers= \ + include/guestfs-gobject/optargs-disk_create.h \ + include/guestfs-gobject/optargs-e2fsck.h \ + include/guestfs-gobject/optargs-fstrim.h \ ++ include/guestfs-gobject/optargs-glob_expand.h \ + include/guestfs-gobject/optargs-grep.h \ + include/guestfs-gobject/optargs-hivex_open.h \ + include/guestfs-gobject/optargs-inspect_get_icon.h \ +@@ -154,6 +155,7 @@ guestfs_gobject_sources= \ + src/optargs-disk_create.c \ + src/optargs-e2fsck.c \ + src/optargs-fstrim.c \ ++ src/optargs-glob_expand.c \ + src/optargs-grep.c \ + src/optargs-hivex_open.c \ + src/optargs-inspect_get_icon.c \ +diff --git a/po/POTFILES b/po/POTFILES +index d4058ac..a5f3f9e 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -194,6 +194,7 @@ gobject/src/optargs-cpio_out.c + gobject/src/optargs-disk_create.c + gobject/src/optargs-e2fsck.c + gobject/src/optargs-fstrim.c ++gobject/src/optargs-glob_expand.c + gobject/src/optargs-grep.c + gobject/src/optargs-hivex_open.c + gobject/src/optargs-inspect_get_icon.c +-- +1.8.3.1 + diff --git a/SOURCES/0027-p2v-Add-usb-storage-module-and-rebuild-initrd-RHBZ-1.patch b/SOURCES/0027-p2v-Add-usb-storage-module-and-rebuild-initrd-RHBZ-1.patch deleted file mode 100644 index df3cc1a..0000000 --- a/SOURCES/0027-p2v-Add-usb-storage-module-and-rebuild-initrd-RHBZ-1.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 9480da99354f873916b19b07be649f5965bfe1f2 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 27 Oct 2014 15:42:02 +0000 -Subject: [PATCH] p2v: Add usb-storage module and rebuild initrd - (RHBZ#1157679). - -Include the usb-storage kernel module, to permit booting from USB -keys. - -Rerun dracut to rebuild the initramfs. This is complicated because by -default dracut will try to build an initramfs for the running -(ie. appliance) kernel, which is completely useless. We need to find -the latest installed kernel and rebuild the initramfs for that -instead, which is hairy. - -This also does a small refactoring of the distro-specific code, -removing the $selinux_relabel variable and replacing it with a generic -$extra_args variable. - -I only added this to the virt-builder script, since one assumes that -livecd-creator/whatever should make the kickstart ISO bootable by -installing whatever drivers and modules are necessary. - -(cherry picked from commit b09b60c987ff113bc4520ab994142da912ffa3d6) ---- - p2v/virt-p2v-make-disk.in | 30 +++++++++++++++++++++++++++--- - 1 file changed, 27 insertions(+), 3 deletions(-) - -diff --git a/p2v/virt-p2v-make-disk.in b/p2v/virt-p2v-make-disk.in -index c29af2c..fb02856 100644 ---- a/p2v/virt-p2v-make-disk.in -+++ b/p2v/virt-p2v-make-disk.in -@@ -74,6 +74,14 @@ fi - - osversion="$1" - -+# Create a temporary directory and clean it up when we finish. -+tmpdir="$(mktemp -d)" -+cleanup () -+{ -+ rm -rf $tmpdir -+} -+trap cleanup INT QUIT TERM EXIT ERR -+ - # The dependencies are: - # - # - pcre (library only) -@@ -92,7 +100,21 @@ osversion="$1" - case "$osversion" in - centos-*|fedora-*|rhel-*|scientificlinux-*) - deps=pcre,libxml2,gtk2,/usr/bin/xinit,/usr/bin/ssh,/usr/bin/qemu-nbd,/usr/bin/Xorg,xorg-x11-drivers,xorg-x11-fonts-Type1,matchbox-window-manager,@hardware-support -- selinux_relabel=--selinux-relabel -+ cat > $tmpdir/p2v.conf <<'EOF' -+add_drivers+=" usb-storage " -+EOF -+ cat > $tmpdir/post-install <<'EOF' -+#!/bin/bash -+# Rebuild the initramfs. -+version=` rpm -q kernel | sort -rV | head -1 | sed 's/kernel-//' ` -+dracut -f --kver $version -+EOF -+ # Double quotes because we want $tmpdir to be expanded: -+ extra_args=" -+ --selinux-relabel -+ --upload $tmpdir/p2v.conf:/etc/dracut.conf.d/ -+ --run $tmpdir/post-install -+ " - ;; - debian-*|ubuntu-*) - deps=libpcre3,libxml2,libgtk2.0-0,openssh-client,qemu-utils,xorg,xserver-xorg-video-all,matchbox-window-manager -@@ -123,7 +145,6 @@ fi - - # Run virt-builder. Note we controversially assume systemd here. We - # could provide a sysvinit fallback if required. --exec \ - virt-builder "$osversion" \ - --output "$output" \ - --update \ -@@ -145,4 +166,7 @@ virt-builder "$osversion" \ - --edit '/etc/systemd/logind.conf: - s/^[Login]/[Login]\nReserveVT=1\n/ - ' \ -- $selinux_relabel -+ $extra_args -+ -+# We have to do this so the cleanup() handler runs. -+exit $? --- -1.8.3.1 - diff --git a/SOURCES/0028-customize-add-globbing-for-delete.patch b/SOURCES/0028-customize-add-globbing-for-delete.patch new file mode 100644 index 0000000..4373004 --- /dev/null +++ b/SOURCES/0028-customize-add-globbing-for-delete.patch @@ -0,0 +1,50 @@ +From faa050d685a7c7005d683b716bcb657bdf958440 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 4 Feb 2016 10:49:31 +0100 +Subject: [PATCH] customize: add globbing for --delete + +Support globbing in paths passed to --delete, telling glob to not +return directories with leading slash. + +This re-adds back globbing for --delete in virt-sysprep, which was +available before the integration with common code from virt-customize. + +(cherry picked from commit 13c3698358a4de82179dba3c8855f56746525aa7) +--- + customize/customize_run.ml | 2 +- + generator/customize.ml | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/customize/customize_run.ml b/customize/customize_run.ml +index 2caaa98..8c38d62 100644 +--- a/customize/customize_run.ml ++++ b/customize/customize_run.ml +@@ -205,7 +205,7 @@ exec >>%s 2>&1 + + | `Delete path -> + message (f_"Deleting: %s") path; +- g#rm_rf path ++ Array.iter g#rm_rf (g#glob_expand ~directoryslash:false path) + + | `Edit (path, expr) -> + message (f_"Editing: %s") path; +diff --git a/generator/customize.ml b/generator/customize.ml +index 63e4246..403bb89 100644 +--- a/generator/customize.ml ++++ b/generator/customize.ml +@@ -117,6 +117,12 @@ Wildcards cannot be used."; + Delete a file from the guest. Or delete a directory (and all its + contents, recursively). + ++You can use shell glob characters in the specified path. Be careful ++to escape glob characters from the host shell, if that is required. ++For example: ++ ++ virt-customize --delete '/var/log/*.log'. ++ + See also: I<--upload>, I<--scrub>."; + }; + +-- +1.8.3.1 + diff --git a/SOURCES/0028-v2v-o-libvirt-Get-the-features-right-in-the-output-X.patch b/SOURCES/0028-v2v-o-libvirt-Get-the-features-right-in-the-output-X.patch deleted file mode 100644 index 0d2c0f0..0000000 --- a/SOURCES/0028-v2v-o-libvirt-Get-the-features-right-in-the-output-X.patch +++ /dev/null @@ -1,230 +0,0 @@ -From 97ad621955e5be3ef3f8bbfc373f31b0027e7d6c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 31 Oct 2014 14:16:36 +0000 -Subject: [PATCH] v2v: -o libvirt: Get the right in the output XML - (RHBZ#1159258). - -Implement what old virt-v2v did (from -lib/Sys/VirtConvert/Connection/LibVirtTarget.pm) - -Thanks: Tingting Zheng, Matthew Booth -(cherry picked from commit 68dc488a4476caf742d5342307258dd72d0e2256) ---- - v2v/output_libvirt.ml | 113 ++++++++++++++++++++++++++++++++++++++++++++++--- - v2v/output_libvirt.mli | 2 +- - v2v/output_local.ml | 13 +++++- - v2v/test-v2v-i-ova.xml | 5 ++- - 4 files changed, 123 insertions(+), 10 deletions(-) - -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index 59a390f..386d777 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -25,6 +25,42 @@ open Types - open Utils - open DOM - -+module StringSet = Set.Make (String) -+ -+let string_set_of_list = -+ List.fold_left (fun set x -> StringSet.add x set) StringSet.empty -+ -+let target_features_of_capabilities_doc doc arch = -+ let xpathctx = Xml.xpath_new_context doc in -+ let expr = -+ (* NB: Pay attention to the square brackets. This returns the -+ * nodes! -+ *) -+ sprintf "/capabilities/guest[arch[@name='%s']/domain/@type='kvm']" arch in -+ let obj = Xml.xpath_eval_expression xpathctx expr in -+ -+ if Xml.xpathobj_nr_nodes obj < 1 then ( -+ (* Old virt-v2v used to die here, but that seems unfair since the -+ * user has gone through conversion before we reach here. -+ *) -+ warning ~prog (f_"the target hypervisor does not support a %s KVM guest") arch; -+ [] -+ ) else ( -+ let node (* first matching *) = Xml.xpathobj_node doc obj 0 in -+ Xml.xpathctx_set_current_context xpathctx node; -+ -+ (* Get guest/features/* nodes. *) -+ let obj = Xml.xpath_eval_expression xpathctx "features/*" in -+ -+ let features = ref [] in -+ for i = 0 to Xml.xpathobj_nr_nodes obj - 1 do -+ let feature_node = Xml.xpathobj_node doc obj i in -+ let feature_name = Xml.node_name feature_node in -+ features := feature_name :: !features -+ done; -+ !features -+ ) -+ - let append_child child = function - | PCData _ | Comment _ -> assert false - | Element e -> e.e_children <- e.e_children @ [child] -@@ -33,15 +69,43 @@ let append_attr attr = function - | PCData _ | Comment _ -> assert false - | Element e -> e.e_attrs <- e.e_attrs @ [attr] - --let create_libvirt_xml ?pool source targets guestcaps = -+let create_libvirt_xml ?pool source targets guestcaps target_features = - let memory_k = source.s_memory /^ 1024L in - -+ (* We have the machine features of the guest when it was on the -+ * source hypervisor (source.s_features). We have the acpi flag -+ * which tells us whether acpi is required by this guest -+ * (guestcaps.gcaps_acpi). And we have the set of hypervisor -+ * features supported by the target (target_features). Combine all -+ * this into a final list of features. -+ *) -+ let features = string_set_of_list source.s_features in -+ let target_features = string_set_of_list target_features in -+ -+ (* If the guest supports ACPI, add it to the output XML. Conversely -+ * if the guest does not support ACPI, then we must drop it. -+ * (RHBZ#1159258) -+ *) - let features = -- List.filter ( -- fun feature -> -- (* drop acpi if the guest doesn't support it *) -- feature <> "acpi" || guestcaps.gcaps_acpi -- ) source.s_features in -+ if guestcaps.gcaps_acpi then -+ StringSet.add "acpi" features -+ else -+ StringSet.remove "acpi" features in -+ -+ (* Make sure we don't add any features which are not supported by -+ * the target hypervisor. -+ *) -+ let features = StringSet.inter(*section*) features target_features in -+ -+ (* But if the target supports apic or pae then we should add them -+ * anyway (old virt-v2v did this). -+ *) -+ let force_features = string_set_of_list ["apic"; "pae"] in -+ let force_features = -+ StringSet.inter(*section*) force_features target_features in -+ let features = StringSet.union features force_features in -+ -+ let features = List.sort compare (StringSet.elements features) in - - let disks = - let block_prefix = -@@ -202,12 +266,36 @@ let create_libvirt_xml ?pool source targets guestcaps = - class output_libvirt verbose oc output_pool = object - inherit output verbose - -+ val mutable capabilities_doc = None -+ - method as_options = - match oc with - | None -> sprintf "-o libvirt -os %s" output_pool - | Some uri -> sprintf "-o libvirt -oc %s -os %s" uri output_pool - - method prepare_targets source targets = -+ (* Get the capabilities from libvirt. *) -+ let cmd = -+ match oc with -+ | None -> "virsh capabilities" -+ | Some uri -> sprintf "virsh -c %s capabilities" (quote uri) in -+ if verbose then printf "%s\n%!" cmd; -+ let xml = external_command ~prog cmd in -+ let xml = String.concat "\n" xml in -+ -+ if verbose then printf "libvirt capabilities XML:\n%s\n%!" xml; -+ -+ (* This just checks that the capabilities XML is well-formed, -+ * early so that we catch parsing errors before conversion. -+ *) -+ let doc = Xml.parse_memory xml in -+ -+ (* Stash the capabilities XML, since we cannot get the bits we -+ * need from it until we know the guest architecture, which happens -+ * after conversion. -+ *) -+ capabilities_doc <- Some doc; -+ - (* Connect to output libvirt instance and check that the pool exists - * and dump out its XML. - *) -@@ -250,11 +338,22 @@ class output_libvirt verbose oc output_pool = object - | Some uri -> - sprintf "virsh -c %s pool-refresh %s" - (quote uri) (quote output_pool) in -+ if verbose then printf "%s\n%!" cmd; - if Sys.command cmd <> 0 then - warning ~prog (f_"could not refresh libvirt pool %s") output_pool; - -+ (* Parse the capabilities XML in order to get the supported features. *) -+ let doc = -+ match capabilities_doc with -+ | None -> assert false -+ | Some doc -> doc in -+ let target_features = -+ target_features_of_capabilities_doc doc guestcaps.gcaps_arch in -+ - (* Create the metadata. *) -- let doc = create_libvirt_xml ~pool:output_pool source targets guestcaps in -+ let doc = -+ create_libvirt_xml ~pool:output_pool source targets -+ guestcaps target_features in - - let tmpfile, chan = Filename.open_temp_file "v2vlibvirt" ".xml" in - DOM.doc_to_chan chan doc; -diff --git a/v2v/output_libvirt.mli b/v2v/output_libvirt.mli -index 25d4690..da41956 100644 ---- a/v2v/output_libvirt.mli -+++ b/v2v/output_libvirt.mli -@@ -23,5 +23,5 @@ val output_libvirt : bool -> string option -> string -> Types.output - {!Types.output} object specialized for writing output to - libvirt. *) - --val create_libvirt_xml : ?pool:string -> Types.source -> Types.target list -> Types.guestcaps -> DOM.doc -+val create_libvirt_xml : ?pool:string -> Types.source -> Types.target list -> Types.guestcaps -> string list -> DOM.doc - (** This is called from {!Output_local} to generate the libvirt XML. *) -diff --git a/v2v/output_local.ml b/v2v/output_local.ml -index db36f0e..ffcfad0 100644 ---- a/v2v/output_local.ml -+++ b/v2v/output_local.ml -@@ -37,7 +37,18 @@ class output_local verbose dir = object - ) targets - - method create_metadata source targets guestcaps _ = -- let doc = Output_libvirt.create_libvirt_xml source targets guestcaps in -+ (* We don't know what target features the hypervisor supports, but -+ * assume a common set that libvirt supports. -+ *) -+ let target_features = -+ match guestcaps.gcaps_arch with -+ | "i686" -> [ "acpi"; "apic"; "pae" ] -+ | "x86_64" -> [ "acpi"; "apic" ] -+ | _ -> [] in -+ -+ let doc = -+ Output_libvirt.create_libvirt_xml source targets -+ guestcaps target_features in - - let name = source.s_name in - let file = dir // name ^ ".xml" in -diff --git a/v2v/test-v2v-i-ova.xml b/v2v/test-v2v-i-ova.xml -index ff83285..2d611f9 100644 ---- a/v2v/test-v2v-i-ova.xml -+++ b/v2v/test-v2v-i-ova.xml -@@ -7,7 +7,10 @@ - - hvm - -- -+ -+ -+ -+ - destroy - restart - restart --- -1.8.3.1 - diff --git a/SOURCES/0029-fish-fix-dir-completion-on-filesystems-w-o-dirent.d_.patch b/SOURCES/0029-fish-fix-dir-completion-on-filesystems-w-o-dirent.d_.patch deleted file mode 100644 index 71f8a63..0000000 --- a/SOURCES/0029-fish-fix-dir-completion-on-filesystems-w-o-dirent.d_.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 07ac79e2f53f17e79977ea60e42441591e619879 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 31 Oct 2014 17:37:22 +0100 -Subject: [PATCH] fish: fix dir completion on filesystems w/o dirent.d_type - (RHBZ#1153844). - -On filesystems whose dirent.d_type is DT_UNKNOWN or some unknown value, -manually check whether an entry is a directory, thus completing in the -proper way. - -(cherry picked from commit a8b95a5535480c7b382fab82dcaf18eb67e5278a) ---- - fish/destpaths.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/fish/destpaths.c b/fish/destpaths.c -index f224106..df1ec00 100644 ---- a/fish/destpaths.c -+++ b/fish/destpaths.c -@@ -191,7 +191,13 @@ complete_dest_paths_generator (const char *text, int state) - else { - words = w; - words[nr_words].name = p; -- words[nr_words].is_dir = dirents->val[i].ftyp == 'd'; -+ if (dirents->val[i].ftyp == 'u' -+ || dirents->val[i].ftyp == '?') { -+ int is_dir = guestfs_is_dir_opts (g, words[nr_words].name, -+ GUESTFS_IS_DIR_OPTS_FOLLOWSYMLINKS, 1, -1); -+ words[nr_words].is_dir = is_dir; -+ } else -+ words[nr_words].is_dir = dirents->val[i].ftyp == 'd'; - nr_words++; - } - } --- -1.8.3.1 - diff --git a/SOURCES/0029-p2v-tests-Don-t-supply-os-version-in-test.patch b/SOURCES/0029-p2v-tests-Don-t-supply-os-version-in-test.patch new file mode 100644 index 0000000..fab8627 --- /dev/null +++ b/SOURCES/0029-p2v-tests-Don-t-supply-os-version-in-test.patch @@ -0,0 +1,27 @@ +From 903abf29254069bbc3f867b36f5d23b61a0be5a8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 27 Jan 2016 12:03:23 +0000 +Subject: [PATCH] p2v: tests: Don't supply os-version in test. + +(cherry picked from commit c323bb7db73a28f05d70fa774c702d48bd631bfa) +--- + p2v/Makefile.am | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/p2v/Makefile.am b/p2v/Makefile.am +index 17745b2..487e198 100644 +--- a/p2v/Makefile.am ++++ b/p2v/Makefile.am +@@ -204,8 +204,7 @@ test-virt-p2v-pxe.img: \ + virt-p2v-make-disk + $(top_builddir)/run virt-p2v-make-disk \ + --inject-ssh-identity=test-virt-p2v-pxe.id_rsa \ +- -o $@-t \ +- fedora-22 ++ -o $@-t + mv $@-t $@ + + test-virt-p2v-pxe.vmlinuz test-virt-p2v-pxe.initramfs: stamp-test-virt-p2v-pxe-kernel +-- +1.8.3.1 + diff --git a/SOURCES/0030-appliance-Pass-quiet-option-to-kernel-when-verbose.patch b/SOURCES/0030-appliance-Pass-quiet-option-to-kernel-when-verbose.patch new file mode 100644 index 0000000..1694abb --- /dev/null +++ b/SOURCES/0030-appliance-Pass-quiet-option-to-kernel-when-verbose.patch @@ -0,0 +1,73 @@ +From 26a13abce6cc73595eb2adf3db46d25c017c2e06 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 17 Mar 2016 08:35:54 +0000 +Subject: [PATCH] appliance: Pass "quiet" option to kernel when !verbose. + +The quiet option suppresses kernel messages. On my laptop it improves +appliance boot times by about 40% (3.5s -> 2.5s). + +The emulated UART is slow and has a fixed, small FIFO (16 bytes). But +it has the advantage of being a simple ISA device which is available +very early in boot, thus enabling us to diagnose early boot problems. +So the aim is to reduce our usage of this UART on fast paths. + +Of course when we are in verbose mode, we should not add this flag +because we want to see all the messages. + +This change is not entirely invisible: + +(1) Progress messages use the "Linux version ..." string from kernel +output in order to determine part of where we are in the boot process. +This string will no longer be detected. We should probably use a BIOS +message or maybe drop this altogether. I have added a comment to the +code. + +(2) It is possible for programs to be listening for +GUESTFS_EVENT_APPLIANCE events, and they will see fewer messages now +(although what kernel messages programs see is never defined). + +(cherry picked from commit ed739e71f634b363c3cf6a0a4eca559eaae7f7b3) +--- + src/launch.c | 4 ++-- + src/proto.c | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/launch.c b/src/launch.c +index de50774..229069f 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -359,7 +359,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + " cgroup_disable=memory" /* saves us about 5 MB of RAM */ + "%s" /* root=appliance_dev */ + " %s" /* selinux */ +- "%s" /* verbose */ ++ " %s" /* quiet/verbose */ + "%s" /* network */ + " TERM=%s" /* TERM environment variable */ + "%s%s" /* handle identifier */ +@@ -370,7 +370,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + lpj_s, + root, + g->selinux ? "selinux=1 enforcing=0" : "selinux=0", +- g->verbose ? " guestfs_verbose=1" : "", ++ g->verbose ? "guestfs_verbose=1" : "quiet", + g->enable_network ? " guestfs_network=1" : "", + term ? term : "linux", + STRNEQ (g->identifier, "") ? " guestfs_identifier=" : "", +diff --git a/src/proto.c b/src/proto.c +index a4fc987..1bc349a 100644 +--- a/src/proto.c ++++ b/src/proto.c +@@ -129,6 +129,9 @@ guestfs_int_log_message_callback (guestfs_h *g, const char *buf, size_t len) + const char *sentinel; + size_t slen; + ++ /* Since 2016-03, if !verbose, then we add the "quiet" flag to the ++ * kernel, so the following sentinel will never be produced. XXX ++ */ + sentinel = "Linux version"; /* kernel up */ + slen = strlen (sentinel); + if (memmem (buf, len, sentinel, slen) != NULL) +-- +1.8.3.1 + diff --git a/SOURCES/0030-v2v-vmware-Use-curl-config-to-pass-arguments-securel.patch b/SOURCES/0030-v2v-vmware-Use-curl-config-to-pass-arguments-securel.patch deleted file mode 100644 index 87a85c9..0000000 --- a/SOURCES/0030-v2v-vmware-Use-curl-config-to-pass-arguments-securel.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 322a146ddc69384255f0567a85e7db56a9e36454 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Oct 2014 09:02:00 +0000 -Subject: [PATCH] v2v: vmware: Use 'curl --config' to pass arguments securely - to curl. - -Instead of making up an ordinary curl command line, write a temporary -config file and use 'curl --config tmpfile' to pass the arguments. - -The advantage is that it's more secure if we want to supply passwords -to curl, since a '--user username:password' parameter on the command -line could be read (eg. by 'ps ax'), but the temporary file has mode -0600 and cannot be read by other users. - -This is mostly code motion, but it also passes the '-q' option to curl -to stop it from reading default configuration files. - -(cherry picked from commit b35b84684c845ceefd3c0ec519caf80366a798ea) ---- - v2v/input_libvirt_vcenter_https.ml | 75 +++++++++++++++++++++++++++++++++----- - 1 file changed, 65 insertions(+), 10 deletions(-) - -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index 56097e0..e514362 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -36,23 +36,45 @@ let readahead_for_copying = Some (64 * 1024 * 1024) - (* Return the session cookie. It is memoized, so you can call this - * as often as required. - *) --let get_session_cookie = -+let rec get_session_cookie = - let session_cookie = ref "" in - fun verbose scheme uri sslverify url -> - if !session_cookie <> "" then - Some !session_cookie - else ( -- let cmd = -- sprintf "curl -s%s%s%s -I %s ||:" -- (if not sslverify then " --insecure" else "") -- (match uri.uri_user with Some _ -> " -u" | None -> "") -- (match uri.uri_user with Some user -> " " ^ quote user | None -> "") -- (quote url) in -- let lines = external_command ~prog cmd in -+ let curl_args = [ -+ "head", None; -+ "silent", None; -+ "url", Some url; -+ ] in -+ let curl_args = -+ match uri.uri_user with -+ | Some user -> ("user", Some user) :: curl_args -+ | None -> curl_args in -+ let curl_args = -+ if not sslverify then ("insecure", None) :: curl_args else curl_args in -+ -+ let lines = run_curl_get_lines curl_args in - - let dump_response chan = -- fprintf chan "%s\n" cmd; -- List.iter (fun x -> fprintf chan "%s\n" x) lines -+ (* Don't print passwords in the debug output. *) -+ let curl_args = -+ List.map ( -+ function -+ | ("user", Some _) -> ("user", Some "") -+ | x -> x -+ ) curl_args in -+ (* Dump out the approximate curl command that was run. *) -+ fprintf chan "curl -q"; -+ List.iter ( -+ function -+ | name, None -> fprintf chan " --%s" name -+ | name, Some value -> fprintf chan " --%s %s" name (quote value) -+ ) curl_args; -+ fprintf chan "\n"; -+ (* 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 stdout; -@@ -109,6 +131,39 @@ let get_session_cookie = - Some !session_cookie - ) - -+(* Run 'curl' and pass the arguments securely through the --config -+ * option and an external file. -+ *) -+and run_curl_get_lines curl_args = -+ let config_file, chan = Filename.open_temp_file "v2vcurl" ".conf" in -+ List.iter ( -+ function -+ | name, None -> fprintf chan "%s\n" name -+ | name, Some value -> -+ fprintf chan "%s = \"" name; -+ (* Write the quoted value. See 'curl' man page for what is -+ * allowed here. -+ *) -+ let len = String.length value in -+ for i = 0 to len-1 do -+ match value.[i] with -+ | '\\' -> output_string chan "\\\\" -+ | '"' -> output_string chan "\\\"" -+ | '\t' -> output_string chan "\\t" -+ | '\n' -> output_string chan "\\n" -+ | '\r' -> output_string chan "\\r" -+ | '\x0b' -> output_string chan "\\v" -+ | c -> output_char chan c -+ done; -+ fprintf chan "\"\n" -+ ) curl_args; -+ close_out chan; -+ -+ let cmd = sprintf "curl -q --config %s" (quote config_file) in -+ let lines = external_command ~prog cmd in -+ Unix.unlink config_file; -+ lines -+ - (* Helper function to extract the datacenter from a URI. *) - let get_datacenter uri scheme = - let default_dc = "ha-datacenter" in --- -1.8.3.1 - diff --git a/SOURCES/0031-appliance-Quiet-some-warnings-about-missing-files.patch b/SOURCES/0031-appliance-Quiet-some-warnings-about-missing-files.patch new file mode 100644 index 0000000..00fdb9c --- /dev/null +++ b/SOURCES/0031-appliance-Quiet-some-warnings-about-missing-files.patch @@ -0,0 +1,32 @@ +From 1296acc7014092eb7765e3216ac5b18b4eb13db5 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 17 Mar 2016 10:05:00 +0000 +Subject: [PATCH] appliance: Quiet some warnings about missing files. + +Try to make the appliance script as quiet as possible along +the fast path. + +(cherry picked from commit 5897b3bbad8c234be2b20685c7714628ea5ec5a0) +--- + appliance/init | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/appliance/init b/appliance/init +index ff8f5df..3b76486 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -83,9 +83,11 @@ fi + + # Disk optimizations. + # Increase the SCSI timeout so we can read remote images. ++shopt -s nullglob + for f in /sys/block/sd*/device/timeout; do echo 300 > $f; done + # https://access.redhat.com/site/solutions/5427 + for f in /sys/block/{h,s,ub,v}d*/queue/scheduler; do echo noop > $f; done ++shopt -u nullglob + + # Update the system clock. + hwclock -u -s +-- +1.8.3.1 + diff --git a/SOURCES/0031-v2v-Add-password-file-parameter-RHBZ-1158526.patch b/SOURCES/0031-v2v-Add-password-file-parameter-RHBZ-1158526.patch deleted file mode 100644 index ee09354..0000000 --- a/SOURCES/0031-v2v-Add-password-file-parameter-RHBZ-1158526.patch +++ /dev/null @@ -1,458 +0,0 @@ -From f9146d6ccbaed3cc6e25f5c7c8462cb8d1514c28 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Oct 2014 13:34:12 +0000 -Subject: [PATCH] v2v: Add --password-file parameter (RHBZ#1158526). - -This allows you to send passwords to virt-v2v input modes without -being interactive. - -(cherry picked from commit 65abc4420325c1226b002f2304709b2040160877) ---- - v2v/cmdline.ml | 13 +++++++++- - v2v/domainxml-c.c | 52 ++++++++++++++++++++++++++++++++----- - v2v/domainxml.ml | 2 +- - v2v/domainxml.mli | 4 +-- - v2v/input_libvirt.ml | 12 ++++----- - v2v/input_libvirt.mli | 4 +-- - v2v/input_libvirt_other.ml | 8 +++--- - v2v/input_libvirt_other.mli | 4 +-- - v2v/input_libvirt_vcenter_https.ml | 29 +++++++++++++-------- - v2v/input_libvirt_vcenter_https.mli | 2 +- - v2v/input_libvirt_xen_ssh.ml | 6 ++--- - v2v/input_libvirt_xen_ssh.mli | 2 +- - v2v/virt-v2v.pod | 10 ++++++- - 13 files changed, 106 insertions(+), 42 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 6f8a964..9c3253e 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -42,6 +42,7 @@ let parse_cmdline () = - let output_format = ref "" in - let output_name = ref "" in - let output_storage = ref "" in -+ let password_file = ref "" in - let print_source = ref false in - let qemu_boot = ref false in - let quiet = ref false in -@@ -165,6 +166,7 @@ let parse_cmdline () = - "-of", Arg.Set_string output_format, "raw|qcow2 " ^ s_"Set output format"; - "-on", Arg.Set_string output_name, "name " ^ s_"Rename guest when converting"; - "-os", Arg.Set_string output_storage, "storage " ^ s_"Set output storage location"; -+ "--password-file", Arg.Set_string password_file, "file " ^ s_"Use password from file"; - "--print-source", Arg.Set print_source, " " ^ s_"Print source and stop"; - "--qemu-boot", Arg.Set qemu_boot, " " ^ s_"Boot in qemu (-o qemu only)"; - "-q", Arg.Set quiet, " " ^ s_"Quiet output"; -@@ -227,6 +229,7 @@ read the man page virt-v2v(1). - let output_mode = !output_mode in - let output_name = match !output_name with "" -> None | s -> Some s in - let output_storage = !output_storage in -+ let password_file = match !password_file with "" -> None | s -> Some s in - let print_source = !print_source in - let qemu_boot = !qemu_boot in - let quiet = !quiet in -@@ -256,6 +259,14 @@ read the man page virt-v2v(1). - exit 0 - ); - -+ (* Parse out the password from the password file. *) -+ let password = -+ match password_file with -+ | None -> None -+ | Some filename -> -+ let password = read_whole_file filename in -+ Some password in -+ - (* Parsing of the argument(s) depends on the input mode. *) - let input = - match input_mode with -@@ -278,7 +289,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 verbose input_conn guest -+ Input_libvirt.input_libvirt verbose password input_conn guest - - | `LibvirtXML -> - (* -i libvirtxml: Expecting a filename (XML file). *) -diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c -index 8a55030..6fa8270 100644 ---- a/v2v/domainxml-c.c -+++ b/v2v/domainxml-c.c -@@ -74,13 +74,47 @@ get_dom_state (virDomainPtr dom) - return -1; - } - -+/* See src/libvirt-auth.c for why we need this. */ -+static int -+libvirt_auth_default_wrapper (virConnectCredentialPtr cred, -+ unsigned int ncred, -+ void *passwordvp) -+{ -+ const char *password = passwordvp; -+ unsigned int i; -+ -+ if (password) { -+ /* If --password-file was specified on the command line, and the -+ * libvirt handler is asking for a password, return that. -+ */ -+ for (i = 0; i < ncred; ++i) { -+ if (cred[i].type == VIR_CRED_PASSPHRASE) { -+ cred[i].result = strdup (password); -+ cred[i].resultlen = strlen (password); -+ } -+ else { -+ cred[i].result = NULL; -+ cred[i].resultlen = 0; -+ } -+ } -+ return 0; -+ } -+ else { -+ /* No --password-file so call the default handler. */ -+ return virConnectAuthPtrDefault->cb (cred, ncred, -+ virConnectAuthPtrDefault->cbdata); -+ } -+} -+ - value --v2v_dumpxml (value connv, value domnamev) -+v2v_dumpxml (value passwordv, value connv, value domnamev) - { -- CAMLparam2 (connv, domnamev); -+ CAMLparam3 (passwordv, connv, domnamev); - CAMLlocal1 (retv); -+ const char *password = NULL; - const char *conn_uri = NULL; - const char *domname; -+ virConnectAuth authdata; - /* We have to assemble the error on the stack because a dynamic - * string couldn't be freed. - */ -@@ -91,16 +125,20 @@ v2v_dumpxml (value connv, value domnamev) - int is_test_uri = 0; - char *xml; - -+ if (passwordv != Val_int (0)) -+ password = String_val (Field (passwordv, 0)); /* Some password */ -+ - if (connv != Val_int (0)) { - conn_uri = String_val (Field (connv, 0)); /* Some conn */ - is_test_uri = STRPREFIX (conn_uri, "test:"); - } - -- /* We have to call the default authentication handler, not least -- * since it handles all the PolicyKit crap. However it also makes -- * coding this simpler. -- */ -- conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault, VIR_CONNECT_RO); -+ /* Set up authentication wrapper. */ -+ authdata = *virConnectAuthPtrDefault; -+ authdata.cb = libvirt_auth_default_wrapper; -+ authdata.cbdata = (void *) password; -+ -+ conn = virConnectOpenAuth (conn_uri, &authdata, VIR_CONNECT_RO); - if (conn == NULL) { - if (conn_uri) - snprintf (errmsg, sizeof errmsg, -diff --git a/v2v/domainxml.ml b/v2v/domainxml.ml -index d240918..61ed5e0 100644 ---- a/v2v/domainxml.ml -+++ b/v2v/domainxml.ml -@@ -18,5 +18,5 @@ - - (* [virsh dumpxml] but with non-broken authentication handling. *) - --external dumpxml : ?conn:string -> string -> string = "v2v_dumpxml" -+external dumpxml : ?password:string -> ?conn:string -> string -> string = "v2v_dumpxml" - external pool_dumpxml : ?conn:string -> string -> string = "v2v_pool_dumpxml" -diff --git a/v2v/domainxml.mli b/v2v/domainxml.mli -index ced55ce..ffb1c46 100644 ---- a/v2v/domainxml.mli -+++ b/v2v/domainxml.mli -@@ -23,8 +23,8 @@ - password prompt to stdout, which is the same place we would be - reading the XML from. This file works around this brokenness. *) - --val dumpxml : ?conn:string -> string -> string --(** [dumpxml ?conn dom] returns the libvirt XML of domain [dom]. -+val dumpxml : ?password:string -> ?conn:string -> string -> string -+(** [dumpxml ?password ?conn dom] returns the libvirt XML of domain [dom]. - The optional [?conn] parameter is the libvirt connection URI. - [dom] may be a guest name or UUID. *) - -diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml -index 60e88ac..aff97ac 100644 ---- a/v2v/input_libvirt.ml -+++ b/v2v/input_libvirt.ml -@@ -27,10 +27,10 @@ open Types - open Utils - - (* Choose the right subclass based on the URI. *) --let input_libvirt verbose libvirt_uri guest = -+let input_libvirt verbose password libvirt_uri guest = - match libvirt_uri with - | None -> -- Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest -+ Input_libvirt_other.input_libvirt_other verbose password libvirt_uri guest - - | Some orig_uri -> - let { Xml.uri_server = server; uri_scheme = scheme } as parsed_uri = -@@ -45,15 +45,15 @@ let input_libvirt verbose libvirt_uri guest = - - | Some _, None (* No scheme? *) - | Some _, Some "" -> -- Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest -+ Input_libvirt_other.input_libvirt_other verbose password libvirt_uri guest - - | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> (* vCenter over https *) - Input_libvirt_vcenter_https.input_libvirt_vcenter_https -- verbose libvirt_uri parsed_uri scheme server guest -+ verbose password libvirt_uri parsed_uri scheme server guest - - | Some server, Some ("xen+ssh" as scheme) -> (* Xen over SSH *) - Input_libvirt_xen_ssh.input_libvirt_xen_ssh -- verbose libvirt_uri parsed_uri scheme server guest -+ verbose password libvirt_uri parsed_uri scheme server guest - - (* Old virt-v2v also supported qemu+ssh://. However I am - * deliberately not supporting this in new virt-v2v. Don't -@@ -63,6 +63,6 @@ let input_libvirt verbose libvirt_uri guest = - | Some _, Some _ -> (* Unknown remote scheme. *) - warning ~prog (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 verbose libvirt_uri guest -+ Input_libvirt_other.input_libvirt_other verbose password libvirt_uri guest - - let () = Modules_list.register_input_module "libvirt" -diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli -index 1ed704b..bdd40b6 100644 ---- a/v2v/input_libvirt.mli -+++ b/v2v/input_libvirt.mli -@@ -18,7 +18,7 @@ - - (** [-i libvirt] source. *) - --val input_libvirt : bool -> string option -> string -> Types.input --(** [input_libvirt verbose libvirt_uri guest] creates and returns a -+val input_libvirt : bool -> string option -> string option -> string -> Types.input -+(** [input_libvirt verbose 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_other.ml b/v2v/input_libvirt_other.ml -index 9f3eedb..c704af6 100644 ---- a/v2v/input_libvirt_other.ml -+++ b/v2v/input_libvirt_other.ml -@@ -43,7 +43,7 @@ let error_if_no_ssh_agent () = - 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 verbose libvirt_uri guest = -+class virtual input_libvirt verbose password libvirt_uri guest = - object - inherit input verbose - -@@ -58,9 +58,9 @@ end - (* Subclass specialized for handling anything that's *not* VMware vCenter - * or Xen. - *) --class input_libvirt_other verbose libvirt_uri guest = -+class input_libvirt_other verbose password libvirt_uri guest = - object -- inherit input_libvirt verbose libvirt_uri guest -+ inherit input_libvirt verbose password libvirt_uri guest - - method source () = - if verbose then printf "input_libvirt_other: source()\n%!"; -@@ -68,7 +68,7 @@ object - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in - - let source, disks = Input_libvirtxml.parse_libvirt_xml ~verbose xml in - let disks = -diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli -index 013d3bb..3eb82cb 100644 ---- a/v2v/input_libvirt_other.mli -+++ b/v2v/input_libvirt_other.mli -@@ -21,10 +21,10 @@ - val error_if_libvirt_backend : unit -> unit - val error_if_no_ssh_agent : unit -> unit - --class virtual input_libvirt : bool -> string option -> string -> object -+class virtual input_libvirt : bool -> string option -> string option -> string -> object - method as_options : string - method virtual source : unit -> Types.source - method adjust_overlay_parameters : Types.overlay -> unit - end - --val input_libvirt_other : bool -> string option -> string -> Types.input -+val input_libvirt_other : bool -> string option -> string option -> string -> Types.input -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index e514362..3d14a27 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -38,7 +38,7 @@ let readahead_for_copying = Some (64 * 1024 * 1024) - *) - let rec get_session_cookie = - let session_cookie = ref "" in -- fun verbose scheme uri sslverify url -> -+ fun verbose password scheme uri sslverify url -> - if !session_cookie <> "" then - Some !session_cookie - else ( -@@ -48,9 +48,15 @@ let rec get_session_cookie = - "url", Some url; - ] in - let curl_args = -- match uri.uri_user with -- | Some user -> ("user", Some user) :: curl_args -- | None -> curl_args in -+ match uri.uri_user, password with -+ | None, None -> curl_args -+ | None, Some _ -> -+ warning ~prog (f_"--password-file parameter ignored because 'user@' was not given in the URL"); -+ curl_args -+ | Some user, None -> -+ ("user", Some user) :: curl_args -+ | Some user, Some password -> -+ ("user", Some (user ^ ":" ^ password)) :: curl_args in - let curl_args = - if not sslverify then ("insecure", None) :: curl_args else curl_args in - -@@ -204,7 +210,7 @@ let get_datacenter uri scheme = - *) - let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" - --let map_source_to_uri ?readahead verbose uri scheme server path = -+let map_source_to_uri ?readahead verbose password uri scheme server path = - if not (Str.string_match source_re path 0) then - path - else ( -@@ -237,7 +243,8 @@ let map_source_to_uri ?readahead verbose uri scheme server path = - string_find query "no_verify=1" = -1 in - - (* Now we have to query the server to get the session cookie. *) -- let session_cookie = get_session_cookie verbose scheme uri sslverify url in -+ let session_cookie = -+ get_session_cookie verbose password scheme uri sslverify url in - - (* Construct the JSON parameters. *) - let json_params = [ -@@ -274,9 +281,9 @@ let map_source_to_uri ?readahead verbose uri scheme server path = - - (* Subclass specialized for handling VMware vCenter over https. *) - class input_libvirt_vcenter_https -- verbose libvirt_uri parsed_uri scheme server guest = -+ verbose password libvirt_uri parsed_uri scheme server guest = - object -- inherit input_libvirt verbose libvirt_uri guest -+ inherit input_libvirt verbose password libvirt_uri guest - - val saved_source_paths = Hashtbl.create 13 - -@@ -290,7 +297,7 @@ object - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in - let source, disks = parse_libvirt_xml ~verbose xml in - - (* Save the original source paths, so that we can remap them again -@@ -314,7 +321,7 @@ object - | { p_source_disk = disk; p_source = P_dont_rewrite } -> disk - | { p_source_disk = disk; p_source = P_source_file path } -> - let qemu_uri = map_source_to_uri ?readahead -- verbose parsed_uri scheme server path in -+ verbose password 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. -@@ -335,7 +342,7 @@ object - let readahead = readahead_for_copying in - let backing_qemu_uri = - map_source_to_uri ?readahead -- verbose parsed_uri scheme server orig_path in -+ verbose password parsed_uri scheme server orig_path in - - (* Rebase the qcow2 overlay to adjust the readahead parameter. *) - let cmd = -diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli -index 82dce53..800c6ab 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 : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input -+val input_libvirt_vcenter_https : bool -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input -diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml -index e1600a0..cf5f1ae 100644 ---- a/v2v/input_libvirt_xen_ssh.ml -+++ b/v2v/input_libvirt_xen_ssh.ml -@@ -30,9 +30,9 @@ open Input_libvirt_other - open Printf - - (* Subclass specialized for handling Xen over SSH. *) --class input_libvirt_xen_ssh verbose libvirt_uri parsed_uri scheme server guest = -+class input_libvirt_xen_ssh verbose password libvirt_uri parsed_uri scheme server guest = - object -- inherit input_libvirt verbose libvirt_uri guest -+ inherit input_libvirt verbose password libvirt_uri guest - - method source () = - if verbose then -@@ -45,7 +45,7 @@ object - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) -- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in -+ let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in - let source, disks = parse_libvirt_xml ~verbose xml in - - (* Map the filename (which is relative to the remote -diff --git a/v2v/input_libvirt_xen_ssh.mli b/v2v/input_libvirt_xen_ssh.mli -index 85473ed..47eb62c 100644 ---- a/v2v/input_libvirt_xen_ssh.mli -+++ b/v2v/input_libvirt_xen_ssh.mli -@@ -18,4 +18,4 @@ - - (** [-i libvirt] when the source is Xen *) - --val input_libvirt_xen_ssh : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input -+val input_libvirt_xen_ssh : bool -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 6e449cf..bebe105 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -423,6 +423,13 @@ C. - You will get an error if virt-v2v is unable to mount/write to the - Export Storage Domain. - -+=item B<--password-file> file -+ -+Instead of asking for password(s) interactively, pass the password -+through a file. Note the file should contain the whole password, -+B, and for security the file should have -+mode C<0600> so that others cannot read it. -+ - =item B<--print-source> - - Print information about the source guest and stop. This option is -@@ -789,7 +796,8 @@ down). - - Note that you may be asked for the vCenter password I. This - happens once because libvirt needs it, and a second time because --virt-v2v itself connects directly to the server. -+virt-v2v itself connects directly to the server. Use -+I<--password-file> to supply a password via a file. - - In this case the output flags are set to write the converted guest to - a temporary directory as this is just an example, but you can also --- -1.8.3.1 - diff --git a/SOURCES/0032-appliance-use-bash-features-for-string-matching-in-f.patch b/SOURCES/0032-appliance-use-bash-features-for-string-matching-in-f.patch new file mode 100644 index 0000000..46a5c0f --- /dev/null +++ b/SOURCES/0032-appliance-use-bash-features-for-string-matching-in-f.patch @@ -0,0 +1,54 @@ +From a9ce8e635ebac7e3924757c93a84619943862167 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 22 Mar 2016 15:48:53 +0100 +Subject: [PATCH] appliance: use bash features for string matching in files + +Read the content of /proc/cmdline using bash features, and use its +[[ ... ]] expression to find texts in a variable. + +This shaves off 5 grep invocations. + +(cherry picked from commit bb5d30ab2af5720775c63179afdec3ad9efd510d) +--- + appliance/init | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/appliance/init b/appliance/init +index 3b76486..fd56033 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -77,7 +77,9 @@ $UDEVD --daemon #--debug + udevadm trigger + udevadm settle --timeout=600 + +-if grep -sq selinux=1 /proc/cmdline; then ++cmdline=$( -Date: Sun, 26 Oct 2014 19:35:36 +0000 -Subject: [PATCH] p2v: Explain in the man page why the virt-p2v ISO is used. - -(cherry picked from commit fab95a52bd307e6be699681de67134788687bf13) ---- - p2v/virt-p2v.pod | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod -index 2dfe0a4..6e7a77d 100644 ---- a/p2v/virt-p2v.pod -+++ b/p2v/virt-p2v.pod -@@ -18,7 +18,10 @@ L. - Normally you don't run the virt-p2v program directly. Instead you - have to boot the physical machine using the bootable CD-ROM, ISO or - PXE image. This bootable image contains the virt-p2v binary and runs --it automatically. -+it automatically. Booting from a CD-ROM/etc is required because the -+disks which are being converted must be quiescent. It is not safe to -+try to convert a running physical machine where other programs may be -+modifying the disk content at the same time. - - This manual page documents running the virt-p2v program. To create - the bootable image you should look at L or --- -1.8.3.1 - diff --git a/SOURCES/0033-launch-Factor-out-earlyprintk-from-the-command-line.patch b/SOURCES/0033-launch-Factor-out-earlyprintk-from-the-command-line.patch new file mode 100644 index 0000000..5795ed8 --- /dev/null +++ b/SOURCES/0033-launch-Factor-out-earlyprintk-from-the-command-line.patch @@ -0,0 +1,48 @@ +From f375978572e5be4edb0e84fcbb7ae5dd06e93163 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 22 Mar 2016 09:43:50 +0000 +Subject: [PATCH] launch: Factor out earlyprintk from the command line. + +Just code motion. + +In theory we could also add earlyprintk=ttyS0,115200 on x86, but I +cannot get it to work. + +(cherry picked from commit b3e843e5b471b1e6e72901a98b3aa39820edaa6a) +--- + src/launch.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/src/launch.c b/src/launch.c +index 229069f..40b4810 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -311,6 +311,12 @@ guestfs_impl_config (guestfs_h *g, + #define SERIAL_CONSOLE "console=ttyS0" + #endif + ++#if defined(__aarch64__) ++#define EARLYPRINTK " earlyprintk=pl011,0x9000000" ++#else ++#define EARLYPRINTK "" ++#endif ++ + char * + guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + int flags) +@@ -339,9 +345,10 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + #ifdef __i386__ + " noapic" /* workaround for RHBZ#857026 */ + #endif +- " " SERIAL_CONSOLE /* serial console */ ++ " " SERIAL_CONSOLE /* serial console */ ++ EARLYPRINTK /* get messages from early boot */ + #ifdef __aarch64__ +- " earlyprintk=pl011,0x9000000 ignore_loglevel" ++ " ignore_loglevel" + /* This option turns off the EFI RTC device. QEMU VMs don't + * currently provide EFI, and if the device is compiled in it + * will try to call the EFI function GetTime unconditionally +-- +1.8.3.1 + diff --git a/SOURCES/0033-p2v-Ensure-we-are-using-virt-v2v-1.28.patch b/SOURCES/0033-p2v-Ensure-we-are-using-virt-v2v-1.28.patch deleted file mode 100644 index 49f8fe3..0000000 --- a/SOURCES/0033-p2v-Ensure-we-are-using-virt-v2v-1.28.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 82435225e29889f0e84739e22703354e454860bd Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Oct 2014 08:51:06 +0000 -Subject: [PATCH] p2v: Ensure we are using virt-v2v >= 1.28. - -Must NOT use: - -- One of the interim versions of virt-v2v (1.27.x) that we published - during development. - -- Old virt-v2v (0.9.x). - -Also use the --version option (instead of -V) since old virt-v2v -required it: - - $ virt-v2v -V - Option v is ambiguous (version, vmtype) - Usage: - [...] - $ virt-v2v --version - 0.9.1 - -(cherry picked from commit cb291d7e4642547da5551f8686bbc46a911377af) ---- - p2v/ssh.c | 40 ++++++++++++++++++++++++++++++++++------ - 1 file changed, 34 insertions(+), 6 deletions(-) - -diff --git a/p2v/ssh.c b/p2v/ssh.c -index f3bfcf9..d593451 100644 ---- a/p2v/ssh.c -+++ b/p2v/ssh.c -@@ -345,8 +345,12 @@ test_connection (struct config *config) - if (h == NULL) - return -1; - -- /* Send 'virt-v2v -V' command and hope we get back a version string. */ -- if (mexp_printf (h, "%svirt-v2v -V\n", config->sudo ? "sudo " : "") == -1) { -+ /* Send 'virt-v2v --version' command and hope we get back a version string. -+ * Note old virt-v2v did not understand -V option. -+ */ -+ if (mexp_printf (h, -+ "%svirt-v2v --version\n", -+ config->sudo ? "sudo " : "") == -1) { - set_ssh_error ("mexp_printf: %m"); - mexp_close (h); - return -1; -@@ -370,9 +374,12 @@ test_connection (struct config *config) - fprintf (stderr, "%s: remote virt-v2v version: %d.%d.%d\n", - program_name, v2v_major, v2v_minor, v2v_release); - #endif -- if (v2v_major < 1 || v2v_major > 1) { -+ /* This is an internal error. Need to check this here so we -+ * don't confuse it with the no-version case below. -+ */ -+ if (v2v_major < 1) { - mexp_close (h); -- set_ssh_error ("invalid version major (%d)", v2v_major); -+ set_ssh_error ("could not parse version string"); - return -1; - } - break; -@@ -382,12 +389,12 @@ test_connection (struct config *config) - - case MEXP_EOF: - mexp_close (h); -- set_ssh_error ("unexpected end of file waiting virt-v2v -V output"); -+ set_ssh_error ("unexpected end of file waiting virt-v2v --version output"); - return -1; - - case MEXP_TIMEOUT: - mexp_close (h); -- set_ssh_error ("timeout waiting for virt-v2v -V output"); -+ set_ssh_error ("timeout waiting for virt-v2v --version output"); - return -1; - - case MEXP_ERROR: -@@ -411,6 +418,27 @@ test_connection (struct config *config) - return -1; - } - -+ /* The major version must always be 1. */ -+ if (v2v_major != 1) { -+ mexp_close (h); -+ set_ssh_error ("virt-v2v major version is not 1 (major = %d), " -+ "this version of virt-p2v is not compatible", v2v_major); -+ return -1; -+ } -+ -+ /* The version of virt-v2v must be >= 1.28, just to make sure -+ * someone isn't (a) using one of the experimental 1.27 releases -+ * that we published during development, nor (b) using old virt-v2v. -+ * We should remain compatible with any virt-v2v after 1.28. -+ */ -+ if (v2v_minor < 28) { -+ mexp_close (h); -+ set_ssh_error ("virt-v2v version is < 1.28 (major = %d, minor = %d), " -+ "you must upgrade to virt-v2v >= 1.28 on " -+ "the conversion server", v2v_major, v2v_minor); -+ return -1; -+ } -+ - /* Get virt-v2v features. See: v2v/cmdline.ml */ - if (mexp_printf (h, "%svirt-v2v --machine-readable\n", - config->sudo ? "sudo " : "") == -1) { --- -1.8.3.1 - diff --git a/SOURCES/0034-launch-direct-Don-t-run-qemu-version.patch b/SOURCES/0034-launch-direct-Don-t-run-qemu-version.patch new file mode 100644 index 0000000..c59ab6a --- /dev/null +++ b/SOURCES/0034-launch-direct-Don-t-run-qemu-version.patch @@ -0,0 +1,141 @@ +From c29743cdbdd8f5b526704705de7cc2ae3d0790c7 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 22 Mar 2016 14:04:26 +0000 +Subject: [PATCH] launch: direct: Don't run qemu -version. + +Dr. David Gilbert pointed out to me that the first line of the +qemu -help output includes the qemu version, so we don't need +to run qemu -version at all. + +This saves about 0.04s on the launch time when using the direct +backend. + +(cherry picked from commit b7b34119766349522528fdfe56237bede0794b6a) +--- + src/launch-direct.c | 54 +++++++++++++++++++---------------------------------- + 1 file changed, 19 insertions(+), 35 deletions(-) + +diff --git a/src/launch-direct.c b/src/launch-direct.c +index cbaf4f3..646f9c6 100644 +--- a/src/launch-direct.c ++++ b/src/launch-direct.c +@@ -61,7 +61,6 @@ struct backend_direct_data { + pid_t recoverypid; /* Recovery process PID. */ + + char *qemu_help; /* Output of qemu -help. */ +- char *qemu_version; /* Output of qemu -version. */ + char *qemu_devices; /* Output of qemu -device ? */ + + /* qemu version (0, 0 if unable to parse). */ +@@ -935,22 +934,18 @@ print_qemu_command_line (guestfs_h *g, char **argv) + static void parse_qemu_version (guestfs_h *g, struct backend_direct_data *data); + static void read_all (guestfs_h *g, void *retv, const char *buf, size_t len); + +-/* Test qemu binary (or wrapper) runs, and do 'qemu -help' and +- * 'qemu -version' so we know what options this qemu supports and +- * the version. ++/* Test qemu binary (or wrapper) runs, and do 'qemu -help' so we know ++ * the version of qemu what options this qemu supports. + */ + static int + test_qemu (guestfs_h *g, struct backend_direct_data *data) + { + CLEANUP_CMD_CLOSE struct command *cmd1 = guestfs_int_new_command (g); + CLEANUP_CMD_CLOSE struct command *cmd2 = guestfs_int_new_command (g); +- CLEANUP_CMD_CLOSE struct command *cmd3 = guestfs_int_new_command (g); + int r; + + free (data->qemu_help); + data->qemu_help = NULL; +- free (data->qemu_version); +- data->qemu_version = NULL; + free (data->qemu_devices); + data->qemu_devices = NULL; + +@@ -964,34 +959,24 @@ test_qemu (guestfs_h *g, struct backend_direct_data *data) + if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) + goto error; + ++ parse_qemu_version (g, data); ++ + guestfs_int_cmd_add_arg (cmd2, g->hv); + guestfs_int_cmd_add_arg (cmd2, "-display"); + guestfs_int_cmd_add_arg (cmd2, "none"); +- guestfs_int_cmd_add_arg (cmd2, "-version"); +- guestfs_int_cmd_set_stdout_callback (cmd2, read_all, &data->qemu_version, +- CMD_STDOUT_FLAG_WHOLE_BUFFER); +- r = guestfs_int_cmd_run (cmd2); +- if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) +- goto error; +- +- parse_qemu_version (g, data); +- +- guestfs_int_cmd_add_arg (cmd3, g->hv); +- guestfs_int_cmd_add_arg (cmd3, "-display"); +- guestfs_int_cmd_add_arg (cmd3, "none"); +- guestfs_int_cmd_add_arg (cmd3, "-machine"); +- guestfs_int_cmd_add_arg (cmd3, ++ guestfs_int_cmd_add_arg (cmd2, "-machine"); ++ guestfs_int_cmd_add_arg (cmd2, + #ifdef MACHINE_TYPE + MACHINE_TYPE "," + #endif + "accel=kvm:tcg"); +- guestfs_int_cmd_add_arg (cmd3, "-device"); +- guestfs_int_cmd_add_arg (cmd3, "?"); +- guestfs_int_cmd_clear_capture_errors (cmd3); +- guestfs_int_cmd_set_stderr_to_stdout (cmd3); +- guestfs_int_cmd_set_stdout_callback (cmd3, read_all, &data->qemu_devices, ++ guestfs_int_cmd_add_arg (cmd2, "-device"); ++ guestfs_int_cmd_add_arg (cmd2, "?"); ++ guestfs_int_cmd_clear_capture_errors (cmd2); ++ guestfs_int_cmd_set_stderr_to_stdout (cmd2); ++ guestfs_int_cmd_set_stdout_callback (cmd2, read_all, &data->qemu_devices, + CMD_STDOUT_FLAG_WHOLE_BUFFER); +- r = guestfs_int_cmd_run (cmd3); ++ r = guestfs_int_cmd_run (cmd2); + if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) + goto error; + +@@ -1005,8 +990,9 @@ test_qemu (guestfs_h *g, struct backend_direct_data *data) + return -1; + } + +-/* Parse data->qemu_version (if not NULL) into the major and minor +- * version of qemu, but don't fail if parsing is not possible. ++/* Parse the first line of data->qemu_help (if not NULL) into the ++ * major and minor version of qemu, but don't fail if parsing is not ++ * possible. + */ + static void + parse_qemu_version (guestfs_h *g, struct backend_direct_data *data) +@@ -1017,13 +1003,13 @@ parse_qemu_version (guestfs_h *g, struct backend_direct_data *data) + data->qemu_version_major = 0; + data->qemu_version_minor = 0; + +- if (!data->qemu_version) ++ if (!data->qemu_help) + return; + +- if (!match2 (g, data->qemu_version, re_major_minor, &major_s, &minor_s)) { ++ if (!match2 (g, data->qemu_help, re_major_minor, &major_s, &minor_s)) { + parse_failed: +- debug (g, "%s: failed to parse qemu version string '%s'", +- __func__, data->qemu_version); ++ debug (g, "%s: failed to parse qemu version string from the first line of the output of '%s -help'. When reporting this bug please include the -help output.", ++ __func__, g->hv); + return; + } + +@@ -1505,8 +1491,6 @@ shutdown_direct (guestfs_h *g, void *datav, int check_for_errors) + + free (data->qemu_help); + data->qemu_help = NULL; +- free (data->qemu_version); +- data->qemu_version = NULL; + free (data->qemu_devices); + data->qemu_devices = NULL; + +-- +1.8.3.1 + diff --git a/SOURCES/0034-v2v-Add-bounds-check-to-Xml.xpathobj_node-function.patch b/SOURCES/0034-v2v-Add-bounds-check-to-Xml.xpathobj_node-function.patch deleted file mode 100644 index 653086b..0000000 --- a/SOURCES/0034-v2v-Add-bounds-check-to-Xml.xpathobj_node-function.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 88927f4922aae25dda3a5cf42afada3edd8da0fc Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 31 Oct 2014 15:57:45 +0000 -Subject: [PATCH] v2v: Add bounds check to Xml.xpathobj_node function. - -I accidentally called it with an out-of-bounds index, and it caused a -core dump. Add a bounds check to stop this from happening in -production. - -(cherry picked from commit 1470be7f3b36b9ba6862fd04aa66446e89b108a7) ---- - v2v/xml-c.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/v2v/xml-c.c b/v2v/xml-c.c -index f26e362..0b619e5 100644 ---- a/v2v/xml-c.c -+++ b/v2v/xml-c.c -@@ -197,6 +197,9 @@ v2v_xml_xpathobj_get_node_ptr (value xpathobjv, value iv) - xmlXPathObjectPtr xpathobj = Xpathobj_val (xpathobjv); - int i = Int_val (iv); - -+ if (i < 0 || i >= xpathobj->nodesetval->nodeNr) -+ caml_invalid_argument ("get_node_ptr: node number out of range"); -+ - /* Because xmlNodePtrs are owned by the document, we don't want to - * wrap this up with a finalizer, so just pass the pointer straight - * back to OCaml as a value. OCaml will ignore it because it's --- -1.8.3.1 - diff --git a/SOURCES/0035-launch-Remove-guestfs_int_print_timestamped_message-.patch b/SOURCES/0035-launch-Remove-guestfs_int_print_timestamped_message-.patch new file mode 100644 index 0000000..41b671f --- /dev/null +++ b/SOURCES/0035-launch-Remove-guestfs_int_print_timestamped_message-.patch @@ -0,0 +1,250 @@ +From 076ecc7fd7987d9fd023a3b0e11bf15024b96957 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 19 Mar 2016 21:27:32 +0000 +Subject: [PATCH] launch: Remove guestfs_int_print_timestamped_message + function. + +This function was kind of like debug(), except that it didn't check +the g->verbose flag and it only worked in the library (it would crash +if used after fork). + +It also wasn't very useful. The sort of boot analysis done by +[forthcoming program] tests/qemu/boot-analysis.c means that +timestamping (some) messages is even less interesting than before. + +Remove it and replace calls with debug() instead. + +(cherry picked from commit e94e61f76f5b0dcdcb0d1b7c74e53c7e3d7da5b2) +--- + src/appliance.c | 9 +++------ + src/guestfs-internal.h | 1 - + src/launch-direct.c | 9 +++------ + src/launch-libvirt.c | 21 +++++++-------------- + src/launch-uml.c | 3 +-- + src/launch-unix.c | 6 ++---- + src/launch.c | 25 ------------------------- + 7 files changed, 16 insertions(+), 58 deletions(-) + +diff --git a/src/appliance.c b/src/appliance.c +index cf13091..1687a93 100644 +--- a/src/appliance.c ++++ b/src/appliance.c +@@ -220,18 +220,15 @@ build_supermin_appliance (guestfs_h *g, + appliancedir = safe_asprintf (g, "%s/appliance.d", cachedir); + lockfile = safe_asprintf (g, "%s/lock", cachedir); + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "begin building supermin appliance"); ++ debug (g, "begin building supermin appliance"); + + /* Build the appliance if it needs to be built. */ +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "run supermin"); ++ debug (g, "run supermin"); + + if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1) + return -1; + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "finished building supermin appliance"); ++ debug (g, "finished building supermin appliance"); + + /* Return the appliance filenames. */ + *kernel = safe_asprintf (g, "%s/kernel", appliancedir); +diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h +index 5dd0a32..44dae32 100644 +--- a/src/guestfs-internal.h ++++ b/src/guestfs-internal.h +@@ -760,7 +760,6 @@ extern int guestfs_int_get_uefi (guestfs_h *g, char **code, char **vars); + + /* launch.c */ + extern int64_t guestfs_int_timeval_diff (const struct timeval *x, const struct timeval *y); +-extern void guestfs_int_print_timestamped_message (guestfs_h *g, const char *fs, ...) __attribute__((format (printf,2,3))); + extern void guestfs_int_launch_send_progress (guestfs_h *g, int perdozen); + extern char *guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, int flags); + #define APPLIANCE_COMMAND_LINE_IS_TCG 1 +diff --git a/src/launch-direct.c b/src/launch-direct.c +index 646f9c6..8d99979 100644 +--- a/src/launch-direct.c ++++ b/src/launch-direct.c +@@ -290,8 +290,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + + guestfs_int_launch_send_progress (g, 3); + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "begin testing qemu features"); ++ debug (g, "begin testing qemu features"); + + /* Get qemu help text and version. */ + if (qemu_supports (g, data, NULL) == -1) +@@ -331,8 +330,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + } + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "finished testing qemu features"); ++ debug (g, "finished testing qemu features"); + + /* Construct the qemu command line. We have to do this before + * forking, because after fork we are not allowed to use +@@ -818,8 +816,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + goto cleanup1; + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "appliance is up"); ++ debug (g, "appliance is up"); + + /* This is possible in some really strange situations, such as + * guestfsd starts up OK but then qemu immediately exits. Check for +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index 4b87301..ceaa696 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -347,8 +347,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + } + debug (g, "guest random name = %s", data->name); + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "connect to libvirt"); ++ debug (g, "connect to libvirt"); + + /* Decode the URI string. */ + if (!libvirt_uri) { /* "libvirt" */ +@@ -387,8 +386,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + data->qemu_version = 0; + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "get libvirt capabilities"); ++ debug (g, "get libvirt capabilities"); + + capabilities_xml = virConnectGetCapabilities (conn); + if (!capabilities_xml) { +@@ -400,8 +398,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + * struct, and can also fail if we detect that the hypervisor cannot + * run qemu guests (RHBZ#886915). + */ +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "parsing capabilities XML"); ++ debug (g, "parsing capabilities XML"); + + if (parse_capabilities (g, capabilities_xml, data) == -1) + goto cleanup; +@@ -425,8 +422,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + /* Locate and/or build the appliance. */ + TRACE0 (launch_build_libvirt_appliance_start); + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "build appliance"); ++ debug (g, "build appliance"); + + if (guestfs_int_build_appliance (g, ¶ms.kernel, ¶ms.dtb, + ¶ms.initrd, &appliance) == -1) +@@ -555,8 +551,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + } + + /* Construct the libvirt XML. */ +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "create libvirt XML"); ++ debug (g, "create libvirt XML"); + + params.appliance_index = g->nr_drives; + strcpy (params.appliance_dev, "/dev/sd"); +@@ -574,8 +569,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + } + + /* Launch the libvirt guest. */ +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "launch libvirt guest"); ++ debug (g, "launch libvirt guest"); + + dom = virDomainCreateXML (conn, (char *) xml, VIR_DOMAIN_START_AUTODESTROY); + if (!dom) { +@@ -643,8 +637,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + goto cleanup; + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "appliance is up"); ++ debug (g, "appliance is up"); + + /* This is possible in some really strange situations, such as + * guestfsd starts up OK but then qemu immediately exits. Check for +diff --git a/src/launch-uml.c b/src/launch-uml.c +index 38be7a8..f6ed516 100644 +--- a/src/launch-uml.c ++++ b/src/launch-uml.c +@@ -456,8 +456,7 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) + goto cleanup1; + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "appliance is up"); ++ debug (g, "appliance is up"); + + /* This is possible in some really strange situations, such as + * guestfsd starts up OK but then vmlinux immediately exits. Check +diff --git a/src/launch-unix.c b/src/launch-unix.c +index 428fdc6..f44c746 100644 +--- a/src/launch-unix.c ++++ b/src/launch-unix.c +@@ -59,8 +59,7 @@ launch_unix (guestfs_h *g, void *datav, const char *sockpath) + return -1; + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "connecting to %s", sockpath); ++ debug (g, "connecting to %s", sockpath); + + daemon_sock = socket (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (daemon_sock == -1) { +@@ -96,8 +95,7 @@ launch_unix (guestfs_h *g, void *datav, const char *sockpath) + goto cleanup; + } + +- if (g->verbose) +- guestfs_int_print_timestamped_message (g, "connected"); ++ debug (g, "connected"); + + if (g->state != READY) { + error (g, _("contacted guestfsd, but state != READY")); +diff --git a/src/launch.c b/src/launch.c +index 40b4810..0eb7d18 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -127,31 +127,6 @@ guestfs_int_launch_send_progress (guestfs_h *g, int perdozen) + } + } + +-/* Note that since this calls 'debug' it should only be called +- * from the parent process. +- */ +-void +-guestfs_int_print_timestamped_message (guestfs_h *g, const char *fs, ...) +-{ +- va_list args; +- char *msg; +- int err; +- struct timeval tv; +- +- va_start (args, fs); +- err = vasprintf (&msg, fs, args); +- va_end (args); +- +- if (err < 0) return; +- +- gettimeofday (&tv, NULL); +- +- debug (g, "[%05" PRIi64 "ms] %s", +- guestfs_int_timeval_diff (&g->launch_t, &tv), msg); +- +- free (msg); +-} +- + /* Compute Y - X and return the result in milliseconds. + * Approximately the same as this code: + * http://www.mpp.mpg.de/~huber/util/timevaldiff.c +-- +1.8.3.1 + diff --git a/SOURCES/0035-v2v-Ensure-bridge-and-network-args-are-documented-co.patch b/SOURCES/0035-v2v-Ensure-bridge-and-network-args-are-documented-co.patch deleted file mode 100644 index cf9e03a..0000000 --- a/SOURCES/0035-v2v-Ensure-bridge-and-network-args-are-documented-co.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0d62524f6318979bdb5226c87bf0c7155d110879 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 3 Nov 2014 19:38:12 +0000 -Subject: [PATCH] v2v: Ensure --bridge and --network args are documented - correctly in --help output. - -(cherry picked from commit 39f524d79b10a3654ee4879951a3ef8dcc99a46f) ---- - v2v/cmdline.ml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 9c3253e..69a627f 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -144,7 +144,7 @@ let parse_cmdline () = - let ditto = " -\"-" in - let argspec = Arg.align [ - "-b", Arg.String add_bridge, "in:out " ^ s_"Map bridge 'in' to 'out'"; -- "--bridge", Arg.String add_bridge, ditto; -+ "--bridge", Arg.String add_bridge, "in:out " ^ ditto; - "--debug-gc",Arg.Set debug_gc, " " ^ s_"Debug GC and memory allocations"; - "--debug-overlay",Arg.Set debug_overlays, - " " ^ s_"Save overlay files"; -@@ -157,7 +157,7 @@ let parse_cmdline () = - "--long-options", Arg.Unit display_long_options, " " ^ s_"List long options"; - "--machine-readable", Arg.Set machine_readable, " " ^ s_"Make output machine readable"; - "-n", Arg.String add_network, "in:out " ^ s_"Map network 'in' to 'out'"; -- "--network", Arg.String add_network, ditto; -+ "--network", Arg.String add_network, "in:out " ^ ditto; - "--no-copy", Arg.Clear do_copy, " " ^ s_"Just write the metadata"; - "--no-trim", Arg.String set_no_trim, "all|mp,mp,.." ^ s_"Don't trim selected mounts"; - "-o", Arg.String set_output_mode, o_options ^ " " ^ s_"Set output mode (default: libvirt)"; --- -1.8.3.1 - diff --git a/SOURCES/0036-launch-Add-a-virtio-rng-device-to-the-guest.patch b/SOURCES/0036-launch-Add-a-virtio-rng-device-to-the-guest.patch new file mode 100644 index 0000000..25d9c58 --- /dev/null +++ b/SOURCES/0036-launch-Add-a-virtio-rng-device-to-the-guest.patch @@ -0,0 +1,61 @@ +From a8c286e9a7972833e1c8cf7da8d91406fa8d0f79 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 22 Mar 2016 14:51:19 +0000 +Subject: [PATCH] launch: Add a virtio-rng device to the guest. + +(cherry picked from commit 9423c16607259b30985c46d04db9958ec079aa42) +--- + src/launch-direct.c | 11 +++++++++++ + src/launch-libvirt.c | 14 ++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/src/launch-direct.c b/src/launch-direct.c +index 8d99979..25c97a7 100644 +--- a/src/launch-direct.c ++++ b/src/launch-direct.c +@@ -454,6 +454,17 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + ADD_CMDLINE ("-initrd"); + ADD_CMDLINE (initrd); + ++ /* Add a random number generator (backend for virtio-rng). This ++ * isn't strictly necessary but means we won't need to hang around ++ * when needing entropy. ++ */ ++ if (qemu_supports_device (g, data, "virtio-rng-pci")) { ++ ADD_CMDLINE ("-object"); ++ ADD_CMDLINE ("rng-random,filename=/dev/urandom,id=rng0"); ++ ADD_CMDLINE ("-device"); ++ ADD_CMDLINE ("virtio-rng-pci,rng=rng0"); ++ } ++ + /* Add drives */ + virtio_scsi = qemu_supports_virtio_scsi (g, data); + +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index ceaa696..3df1833 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -1304,6 +1304,20 @@ construct_libvirt_xml_devices (guestfs_h *g, + } + #endif + ++ /* Add a random number generator (backend for virtio-rng). */ ++ start_element ("rng") { ++ attribute ("model", "virtio"); ++ start_element ("backend") { ++ attribute ("model", "random"); ++ /* It'd be nice to do this, but libvirt says: ++ * file '/dev/urandom' is not a supported random source ++ * Let libvirt pick /dev/random automatically instead. ++ * See also: https://bugzilla.redhat.com/show_bug.cgi?id=1074464 ++ */ ++ //string ("/dev/urandom"); ++ } end_element (); ++ } end_element (); ++ + /* virtio-scsi controller. */ + start_element ("controller") { + attribute ("type", "scsi"); +-- +1.8.3.1 + diff --git a/SOURCES/0036-v2v-i-libvirt-vcenter-Change-esx-to-vcenter-in-error.patch b/SOURCES/0036-v2v-i-libvirt-vcenter-Change-esx-to-vcenter-in-error.patch deleted file mode 100644 index c59a6f8..0000000 --- a/SOURCES/0036-v2v-i-libvirt-vcenter-Change-esx-to-vcenter-in-error.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 97c8e2ecf7ac619d268c5b927d5fce44778c805c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 4 Nov 2014 21:21:20 +0000 -Subject: [PATCH] v2v: -i libvirt vcenter: Change 'esx:' to 'vcenter:' in - errors/warnings. - -'esx' is inaccurate. - -(cherry picked from commit c58d335952194b9556db78abde75637921ab4eca) ---- - v2v/input_libvirt_vcenter_https.ml | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index 3d14a27..783b630 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -96,26 +96,26 @@ let rec get_session_cookie = - let status = !status in - if status = "" then ( - dump_response stderr; -- error (f_"esx: no status code in output of 'curl' command. Is 'curl' installed?") -+ 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_"esx: incorrect username or password") -+ error (f_"vcenter: incorrect username or password") - else -- error (f_"esx: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]") -+ 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_"esx: URL not found: %s") url -+ error (f_"vcenter: URL not found: %s") url - ); - - if status <> "200" then ( - dump_response stderr; -- error (f_"esx: invalid response from server") -+ error (f_"vcenter: invalid response from server") - ); - - (* Get the cookie. *) -@@ -130,7 +130,7 @@ let rec get_session_cookie = - ) lines; - if !session_cookie = "" then ( - dump_response stderr; -- warning ~prog (f_"esx: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through"); -+ warning ~prog (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 -@@ -177,7 +177,7 @@ let get_datacenter uri scheme = - | "vpx" -> (* Hopefully the first part of the path. *) - (match uri.uri_path with - | None -> -- warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name"); -+ warning ~prog (f_"vcenter: URI (-ic parameter) contains no path, so we cannot determine the datacenter name"); - default_dc - | Some path -> - let path = -@@ -269,7 +269,7 @@ let map_source_to_uri ?readahead verbose password uri scheme server path = - | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in - - if verbose then -- printf "esx: json parameters: %s\n" (JSON.string_of_doc json_params); -+ printf "vcenter: json parameters: %s\n" (JSON.string_of_doc json_params); - - (* Turn the JSON parameters into a 'json:' protocol string. - * Note this requires qemu-img >= 2.1.0. --- -1.8.3.1 - diff --git a/SOURCES/0037-appliance-When-using-verbose-mode-set-x-in-the-appli.patch b/SOURCES/0037-appliance-When-using-verbose-mode-set-x-in-the-appli.patch new file mode 100644 index 0000000..e728121 --- /dev/null +++ b/SOURCES/0037-appliance-When-using-verbose-mode-set-x-in-the-appli.patch @@ -0,0 +1,26 @@ +From a2c3958c1487b9d3fe929498f53e71637ff8d53b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 19 Mar 2016 18:26:39 +0000 +Subject: [PATCH] appliance: When using verbose mode, 'set -x' in the appliance + init script. + +(cherry picked from commit d368fa08955a17feed39baaab990dae361fede13) +--- + appliance/init | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/appliance/init b/appliance/init +index fd56033..239b50e 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -97,6 +97,7 @@ hwclock -u -s + # Parse the kernel command line. + if [[ $cmdline == *guestfs_verbose=1* ]]; then + guestfs_verbose=1 ++ set -x + fi + if [[ $cmdline == *guestfs_network=1* ]]; then + guestfs_network=1 +-- +1.8.3.1 + diff --git a/SOURCES/0037-v2v-Ignore-small-filesystems-when-checking-for-suffi.patch b/SOURCES/0037-v2v-Ignore-small-filesystems-when-checking-for-suffi.patch deleted file mode 100644 index dc06f22..0000000 --- a/SOURCES/0037-v2v-Ignore-small-filesystems-when-checking-for-suffi.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 9849e04550f0b5a5c96972bfbe0933c5d57ebbc6 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 6 Nov 2014 09:47:21 +0000 -Subject: [PATCH] v2v: Ignore small filesystems when checking for sufficient - free space. - -(cherry picked from commit 918dd3705d3d34f28eb3cf30cd79d16358d525e3) ---- - v2v/v2v.ml | 48 +++++++++++++++++++++++++++--------------------- - 1 file changed, 27 insertions(+), 21 deletions(-) - -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index 48fb8c6..8639482 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -542,27 +542,33 @@ and inspect_source g root_choice = - *) - and check_free_space mpstats = - List.iter ( -- fun { mp_path = mp; mp_statvfs = { G.bfree = bfree; bsize = bsize } } -> -- (* bfree = free blocks for root user *) -- let free_bytes = bfree *^ bsize in -- let needed_bytes = -- match mp with -- | "/" -> -- (* We may install some packages, and they would usually go -- * on the root filesystem. -- *) -- 20_000_000L -- | "/boot" -> -- (* We usually regenerate the initramfs, which has a typical size -- * of 20-30MB. Hence: -- *) -- 50_000_000L -- | _ -> -- (* For everything else, just make sure there is some free space. *) -- 10_000_000L in -- if free_bytes < needed_bytes then -- error (f_"not enough free space for conversion on filesystem '%s'. %Ld bytes free < %Ld bytes needed") -- mp free_bytes needed_bytes -+ fun { mp_path = mp; -+ mp_statvfs = { G.bfree = bfree; blocks = blocks; bsize = bsize } } -> -+ (* Ignore small filesystems. *) -+ let total_size = blocks *^ bsize in -+ if total_size > 100_000_000L then ( -+ (* bfree = free blocks for root user *) -+ let free_bytes = bfree *^ bsize in -+ let needed_bytes = -+ match mp with -+ | "/" -> -+ (* We may install some packages, and they would usually go -+ * on the root filesystem. -+ *) -+ 20_000_000L -+ | "/boot" -> -+ (* We usually regenerate the initramfs, which has a -+ * typical size of 20-30MB. Hence: -+ *) -+ 50_000_000L -+ | _ -> -+ (* For everything else, just make sure there is some free space. *) -+ 10_000_000L in -+ -+ if free_bytes < needed_bytes then -+ error (f_"not enough free space for conversion on filesystem '%s'. %Ld bytes free < %Ld bytes needed") -+ mp free_bytes needed_bytes -+ ) - ) mpstats - - (* Perform the fstrim. The trimming bit is easy. Dealing with the --- -1.8.3.1 - diff --git a/SOURCES/0038-appliance-init-Move-cmdline-parsing-earlier.patch b/SOURCES/0038-appliance-init-Move-cmdline-parsing-earlier.patch new file mode 100644 index 0000000..a429161 --- /dev/null +++ b/SOURCES/0038-appliance-init-Move-cmdline-parsing-earlier.patch @@ -0,0 +1,96 @@ +From 2bb0c9f0596ef616992a248dec535c3dffc0337d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 19 Mar 2016 18:27:07 +0000 +Subject: [PATCH] appliance: init: Move cmdline parsing earlier. + +Since commit bb5d30ab2af5720775c63179afdec3ad9efd510d, we don't +require any external programs like grep to parse the command line. We +only use bash intrinsics. + +Therefore we can do it early (but after /proc is mounted). + +This allows verbose mode to enable set -x early on, so we can trace +most things that the init script does. + +(cherry picked from commit cb8f69e95929e512fcb8882ffb647dc72fc4a865) +--- + appliance/init | 39 +++++++++++++++++++++------------------ + 1 file changed, 21 insertions(+), 18 deletions(-) + +diff --git a/appliance/init b/appliance/init +index 239b50e..55b1a35 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -33,9 +33,29 @@ done + + mkdir -p /sysroot + ++# Mount /proc. + if [ ! -d /proc ]; then rm -f /proc; fi + mkdir -p /proc + mount -t proc /proc /proc ++ ++# Parse the kernel command line early (must be after /proc is mounted). ++cmdline=$( -Date: Thu, 6 Nov 2014 09:52:32 +0000 -Subject: [PATCH] v2v: Document minimum free filesystem space requirements. - -(cherry picked from commit 5de06a3571d20d0fd483d26099cc49bc0f08ecf0) ---- - v2v/virt-v2v.pod | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index bebe105..edfa5a0 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -1085,6 +1085,30 @@ same as the initial installation procedure. It is not necessary to - remove the recovery console first. Following re-installation, the - recovery console will work as intended. - -+=head1 FREE SPACE FOR CONVERSION -+ -+Virt-v2v checks there is sufficient free space in the guest filesystem -+to perform the conversion. Currently it checks: -+ -+=over 4 -+ -+=item Root filesystem or C -+ -+Minimum free space: 20 MB -+ -+=item C -+ -+Minimum free space: 50 MB -+ -+This is because we need to build a new initramfs for some Enterprise -+Linux conversions. -+ -+=item Any other mountable filesystem -+ -+Minimum free space: 10 MB -+ -+=back -+ - =head1 RUNNING VIRT-V2V AS ROOT OR NON-ROOT - - Nothing in virt-v2v inherently needs root access, and it will run just --- -1.8.3.1 - diff --git a/SOURCES/0039-appliance-init-Mount-selinuxfs-along-with-other-spec.patch b/SOURCES/0039-appliance-init-Mount-selinuxfs-along-with-other-spec.patch new file mode 100644 index 0000000..c65ec3e --- /dev/null +++ b/SOURCES/0039-appliance-init-Mount-selinuxfs-along-with-other-spec.patch @@ -0,0 +1,42 @@ +From 51917bc60573b85bc354e573a3d22e6dde2cec35 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 23 Mar 2016 12:13:03 +0000 +Subject: [PATCH] appliance: init: Mount selinuxfs along with other special + filesystems. + +Move this earlier. + +(cherry picked from commit 705b721b4224f43149e52d8741d2aa5c4a67b735) +--- + appliance/init | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/appliance/init b/appliance/init +index 55b1a35..6793d57 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -74,6 +74,10 @@ fi + # devtmpfs is required since udev 176 + mount -t devtmpfs /dev /dev + ++if [[ $cmdline == *selinux=1* ]]; then ++ mount -t selinuxfs none /sys/fs/selinux ++fi ++ + # Static nodes must happen before udev is started. + + # Set up kmod static-nodes (RHBZ#1011907). +@@ -97,10 +101,6 @@ $UDEVD --daemon #--debug + udevadm trigger + udevadm settle --timeout=600 + +-if [[ $cmdline == *selinux=1* ]]; then +- mount -t selinuxfs none /sys/fs/selinux +-fi +- + # Disk optimizations. + # Increase the SCSI timeout so we can read remote images. + shopt -s nullglob +-- +1.8.3.1 + diff --git a/SOURCES/0039-customize-firstboot-make-sure-to-run-Linux-scripts-o.patch b/SOURCES/0039-customize-firstboot-make-sure-to-run-Linux-scripts-o.patch deleted file mode 100644 index b707d5a..0000000 --- a/SOURCES/0039-customize-firstboot-make-sure-to-run-Linux-scripts-o.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 7b8b3767102ea1e2b1f47e20d1bdb0bb69e3626b Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 3 Nov 2014 21:15:59 +0100 -Subject: [PATCH] customize: firstboot: make sure to run Linux scripts only - once - -If a script does not finish, hangs, etc, it would be executed again at -the next boot, since the injected firstboot.sh helper removes it only -after it finished. - -Before executing a script, move it to another internal subdirectory -(scripts-done) and execute it from there, so it is not run again by -firstboot.sh. The downside is that now scripts are executed only once -at all, so if a script fails it will not be attempted at the next boot. - -Also, remove all the files found in scripts-done, as they have been run -(or at least attempted) in a previous boot. - -This fixes RHBZ#1159651. - -(cherry picked from commit f8ed15462fbb03c5b19972361f2a2e6fed4c5f02) ---- - customize/firstboot.ml | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/customize/firstboot.ml b/customize/firstboot.ml -index 142eab4..1b92194 100644 ---- a/customize/firstboot.ml -+++ b/customize/firstboot.ml -@@ -46,6 +46,7 @@ module Linux = struct - ### END INIT INFO - - d=%s/scripts -+d_done=%s/scripts-done - logfile=~root/virt-sysprep-firstboot.log - - echo \"$0\" \"$@\" 2>&1 | tee $logfile -@@ -53,16 +54,20 @@ echo \"Scripts dir: $d\" 2>&1 | tee $logfile - - if test \"$1\" = \"start\" - then -+ mkdir -p $d_done - for f in $d/* ; do - if test -x \"$f\" - then -+ # move the script to the 'scripts-done' directory, so it is not -+ # executed again at the next boot -+ mv $f $d_done - echo '=== Running' $f '===' 2>&1 | tee $logfile -- $f 2>&1 | tee $logfile -- rm -f $f -+ $d_done/$(basename $f) 2>&1 | tee $logfile - fi - done -+ rm -f $d_done/* - fi --" firstboot_dir -+" firstboot_dir firstboot_dir - - let firstboot_service = sprintf "\ - [Unit] --- -1.8.3.1 - diff --git a/SOURCES/0040-appliance-init-Don-t-run-hwclock-command.patch b/SOURCES/0040-appliance-init-Don-t-run-hwclock-command.patch new file mode 100644 index 0000000..cb8fe49 --- /dev/null +++ b/SOURCES/0040-appliance-init-Don-t-run-hwclock-command.patch @@ -0,0 +1,32 @@ +From 28b8442ec5aaf87b7937a1753c13af6f1ab6c8e1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 19 Mar 2016 20:13:49 +0000 +Subject: [PATCH] appliance: init: Don't run hwclock command. + +This command alone took 0.3 seconds which is about 10% of the current +launch time. It appears to be unnecessary. + +This reverts commit 508f1ee87e816bf6b6fc8e629ccbb2d61a971169. + +(cherry picked from commit f36ba3888654b55a25158edd23a40fd0e28545a8) +--- + appliance/init | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/appliance/init b/appliance/init +index 6793d57..4407bbb 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -109,9 +109,6 @@ for f in /sys/block/sd*/device/timeout; do echo 300 > $f; done + for f in /sys/block/{h,s,ub,v}d*/queue/scheduler; do echo noop > $f; done + shopt -u nullglob + +-# Update the system clock. +-hwclock -u -s +- + # Set up the network. + ip addr add 127.0.0.1/8 brd + dev lo scope host + ip link set dev lo up +-- +1.8.3.1 + diff --git a/SOURCES/0040-customize-firstboot-fix-Linux-log-output.patch b/SOURCES/0040-customize-firstboot-fix-Linux-log-output.patch deleted file mode 100644 index 4bfebb3..0000000 --- a/SOURCES/0040-customize-firstboot-fix-Linux-log-output.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 839b3d82f37159f02d5c188367dcb157f5b3da4e Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 4 Nov 2014 09:16:17 +0100 -Subject: [PATCH] customize: firstboot: fix Linux log output - -Pass -a to each tee invocation, otherwise just the last one (so only for -the last script executed) will appear in the log file. - -(cherry picked from commit 25cad1e62fa73e9cfd9a0e3d1d330165b19339ec) ---- - customize/firstboot.ml | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/customize/firstboot.ml b/customize/firstboot.ml -index 1b92194..594f5b8 100644 ---- a/customize/firstboot.ml -+++ b/customize/firstboot.ml -@@ -49,8 +49,8 @@ d=%s/scripts - d_done=%s/scripts-done - logfile=~root/virt-sysprep-firstboot.log - --echo \"$0\" \"$@\" 2>&1 | tee $logfile --echo \"Scripts dir: $d\" 2>&1 | tee $logfile -+echo \"$0\" \"$@\" 2>&1 | tee -a $logfile -+echo \"Scripts dir: $d\" 2>&1 | tee -a $logfile - - if test \"$1\" = \"start\" - then -@@ -61,8 +61,8 @@ then - # move the script to the 'scripts-done' directory, so it is not - # executed again at the next boot - mv $f $d_done -- echo '=== Running' $f '===' 2>&1 | tee $logfile -- $d_done/$(basename $f) 2>&1 | tee $logfile -+ echo '=== Running' $f '===' 2>&1 | tee -a $logfile -+ $d_done/$(basename $f) 2>&1 | tee -a $logfile - fi - done - rm -f $d_done/* --- -1.8.3.1 - diff --git a/SOURCES/0041-conn-Pretend-to-be-a-serial-terminal-so-sgabios-does.patch b/SOURCES/0041-conn-Pretend-to-be-a-serial-terminal-so-sgabios-does.patch new file mode 100644 index 0000000..000ae21 --- /dev/null +++ b/SOURCES/0041-conn-Pretend-to-be-a-serial-terminal-so-sgabios-does.patch @@ -0,0 +1,77 @@ +From 4f88b55bfad9d72675ef09480dd4d8ad96047842 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 20 Mar 2016 15:50:31 +0000 +Subject: [PATCH] conn: Pretend to be a serial terminal, so sgabios doesn't + hang. + +This tedious workaround avoids a 0.26 second pause when using sgabios +(the Serial Graphics Adapter). It's basically a workaround for buggy +code in sgabios, but much easier than fixing the assembler. + +(cherry picked from commit cd578510197eb87abf996a3a050779806682e83f) +--- + src/conn-socket.c | 34 +++++++++++++++++++++++++++++++++- + 1 file changed, 33 insertions(+), 1 deletion(-) + +diff --git a/src/conn-socket.c b/src/conn-socket.c +index 9db0bfd..8a4b9d0 100644 +--- a/src/conn-socket.c ++++ b/src/conn-socket.c +@@ -33,6 +33,8 @@ + #include + #include + ++#include "ignore-value.h" ++ + #include "guestfs.h" + #include "guestfs-internal.h" + +@@ -314,6 +316,9 @@ handle_log_message (guestfs_h *g, + { + char buf[BUFSIZ]; + ssize_t n; ++ const char dsr_request[] = "\033[6n"; ++ const char dsr_reply[] = "\033[24;80R"; ++ const char dsr_reply_padding[] = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; + + /* Carried over from ancient proto.c code. The comment there was: + * +@@ -341,7 +346,34 @@ handle_log_message (guestfs_h *g, + return -1; + } + +- /* It's an actual log message, send it upwards. */ ++ /* It's an actual log message. */ ++ ++ /* SGABIOS tries to query the "serial console" for its size using the ++ * ISO/IEC 6429 Device Status Report (ESC [ 6 n). If it doesn't ++ * read anything back, then it unfortunately hangs for 0.26 seconds. ++ * Therefore we detect this situation and send back a fake console ++ * size. ++ */ ++ if (memmem (buf, n, dsr_request, sizeof dsr_request - 1) != NULL) { ++ debug (g, "responding to serial console Device Status Report"); ++ ++ /* Ignore any error from this write, as it's just an optimization. ++ * We can't even be sure that console_sock is a socket or that ++ * it's writable. ++ */ ++ ignore_value (write (conn->console_sock, dsr_reply, ++ sizeof dsr_reply - 1)); ++ /* Additionally, because of a bug in sgabios, it will still pause ++ * unless you write at least 14 bytes, so we have to pad the ++ * reply. We can't pad with NULs since sgabios's input routine ++ * ignores these, so we have to use some other safe padding ++ * characters. Backspace seems innocuous. ++ */ ++ ignore_value (write (conn->console_sock, dsr_reply_padding, ++ sizeof dsr_reply_padding - 1)); ++ } ++ ++ /* Send it upwards. */ + guestfs_int_log_message_callback (g, buf, n); + + return 1; +-- +1.8.3.1 + diff --git a/SOURCES/0041-v2v-Fix-kernel-detection-when-multiple-kernels-are-i.patch b/SOURCES/0041-v2v-Fix-kernel-detection-when-multiple-kernels-are-i.patch deleted file mode 100644 index 45df0c3..0000000 --- a/SOURCES/0041-v2v-Fix-kernel-detection-when-multiple-kernels-are-i.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 76ebcac68d5e2da63494e94c6f6039677515ca7f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 6 Nov 2014 18:47:34 +0000 -Subject: [PATCH] v2v: Fix kernel detection when multiple kernels are installed - (RHBZ#1161250). - -Previously we used to try to find the 'vmlinuz' file by running 'rpm --ql kernel' and looking for any file called 'vmlinuz-*'. - -If there were multiple 'kernel' packages installed, the rpm command -would list files from all of them, resulting in a random 'vmlinuz-*' -being chosen, not necessarily the one corresponding to the kernel -package we were looking at. - -Use 'rpm -ql kernel--' instead so that we only look -for files in the right kernel package. - -Thanks: James Mighion -(cherry picked from commit 377bc302f11db3da4263f894c76a7d280fb25dbd) ---- - v2v/convert_linux.ml | 2 +- - v2v/linux.ml | 17 +++++++++++++++-- - v2v/linux.mli | 2 +- - 3 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 6c0c903..b6335d9 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -148,7 +148,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - when name = "kernel" || string_prefix name "kernel-" -> - (try - (* For each kernel, list the files directly owned by the kernel. *) -- let files = Linux.file_list_of_package verbose g inspect name in -+ let files = Linux.file_list_of_package verbose g inspect app in - - (* Which of these is the kernel itself? *) - let vmlinuz = List.find ( -diff --git a/v2v/linux.ml b/v2v/linux.ml -index 2c743e3..4287a4f 100644 ---- a/v2v/linux.ml -+++ b/v2v/linux.ml -@@ -24,6 +24,8 @@ open Common_utils - open Types - open Utils - -+module G = Guestfs -+ - (* Wrappers around aug_init & aug_load which can dump out full Augeas - * parsing problems when debugging is enabled. - *) -@@ -115,12 +117,23 @@ let remove verbose g inspect packages = - format (String.concat " " packages) - ) - --let file_list_of_package verbose (g : Guestfs.guestfs) inspect name = -+let file_list_of_package verbose (g : Guestfs.guestfs) inspect app = - let package_format = inspect.i_package_format in - - match package_format with - | "rpm" -> -- let cmd = [| "rpm"; "-ql"; name |] in -+ (* Since RPM allows multiple packages installed with the same -+ * name, always check the full ENVR here (RHBZ#1161250). -+ *) -+ let pkg_name = -+ sprintf "%s-%s-%s" app.G.app2_name -+ app.G.app2_version app.G.app2_release in -+ let pkg_name = -+ if app.G.app2_epoch > 0_l then -+ sprintf "%ld:%s" app.G.app2_epoch pkg_name -+ else -+ pkg_name in -+ let cmd = [| "rpm"; "-ql"; pkg_name |] in - if verbose then eprintf "%s\n%!" (String.concat " " (Array.to_list cmd)); - let files = g#command_lines cmd in - let files = Array.to_list files in -diff --git a/v2v/linux.mli b/v2v/linux.mli -index e5a3025..14e757b 100644 ---- a/v2v/linux.mli -+++ b/v2v/linux.mli -@@ -31,7 +31,7 @@ val install : bool -> Guestfs.guestfs -> Types.inspect -> string list -> unit - val remove : bool -> Guestfs.guestfs -> Types.inspect -> string list -> unit - (** Uninstall package(s). *) - --val file_list_of_package : bool -> Guestfs.guestfs -> Types.inspect -> string -> string list -+val file_list_of_package : bool -> Guestfs.guestfs -> Types.inspect -> Guestfs.application2 -> string list - (** Return list of files owned by package. *) - - val file_owner : bool -> Guestfs.guestfs -> Types.inspect -> string -> string --- -1.8.3.1 - diff --git a/SOURCES/0042-tests-qemu-Add-program-for-tracing-and-analyzing-boo.patch b/SOURCES/0042-tests-qemu-Add-program-for-tracing-and-analyzing-boo.patch new file mode 100644 index 0000000..16e010a --- /dev/null +++ b/SOURCES/0042-tests-qemu-Add-program-for-tracing-and-analyzing-boo.patch @@ -0,0 +1,1711 @@ +From 07954ad0663456014c56ed4db0c1ab3f71846678 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 18 Mar 2016 18:00:51 +0000 +Subject: [PATCH] tests/qemu: Add program for tracing and analyzing boot times. + +(cherry picked from commit 0ba59db611fc2620bf47b50c6d0a71242a0800d7) +--- + .gitignore | 1 + + appliance/init | 5 +- + tests/qemu/Makefile.am | 26 +- + tests/qemu/boot-analysis-timeline.c | 468 ++++++++++++++++ + tests/qemu/boot-analysis.c | 1030 +++++++++++++++++++++++++++++++++++ + tests/qemu/boot-analysis.h | 94 ++++ + 6 files changed, 1620 insertions(+), 4 deletions(-) + create mode 100644 tests/qemu/boot-analysis-timeline.c + create mode 100644 tests/qemu/boot-analysis.c + create mode 100644 tests/qemu/boot-analysis.h + +diff --git a/.gitignore b/.gitignore +index 6436eeb..9c45df7 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -509,6 +509,7 @@ Makefile.in + /tests/mountable/test-internal-parse-mountable + /tests/parallel/test-parallel + /tests/protocol/test-error-messages ++/tests/qemu/boot-analysis + /tests/qemu/qemu-boot + /tests/qemu/qemu-speed-test + /tests/regressions/rhbz501893 +diff --git a/appliance/init b/appliance/init +index 4407bbb..4a04bce 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -54,6 +54,9 @@ fi + if [[ $cmdline == *guestfs_noreboot=1* ]]; then + guestfs_noreboot=1 + fi ++if [[ $cmdline == *guestfs_boot_analysis=1* ]]; then ++ guestfs_boot_analysis=1 ++fi + + # Mount the other special filesystems. + if [ ! -d /sys ]; then rm -f /sys; fi +@@ -133,7 +136,7 @@ lvm vgchange -aay --sysinit + ldmtool create all + + # These are useful when debugging. +-if test "$guestfs_verbose" = 1; then ++if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then + uname -a + ls -lR /dev + cat /proc/mounts +diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am +index fe45d88..bea1c85 100644 +--- a/tests/qemu/Makefile.am ++++ b/tests/qemu/Makefile.am +@@ -33,10 +33,10 @@ EXTRA_DIST = \ + qemu-boot.c \ + qemu-speed-test.c + +-# qemu-boot & qemu-speed-test are built but not run by default as they +-# are mainly qemu & kernel diagnostic tools. ++# qemu-boot, qemu-speed-test and boot-analysis are built but not run ++# by default as they are mainly qemu & kernel diagnostic tools. + +-check_PROGRAMS = qemu-boot qemu-speed-test ++check_PROGRAMS = qemu-boot qemu-speed-test boot-analysis + + qemu_boot_SOURCES = \ + ../../df/estimate-max-threads.c \ +@@ -73,6 +73,26 @@ qemu_speed_test_LDADD = \ + $(LTLIBINTL) \ + $(top_builddir)/gnulib/lib/libgnu.la + ++boot_analysis_SOURCES = \ ++ boot-analysis.c \ ++ boot-analysis.h \ ++ boot-analysis-timeline.c ++boot_analysis_CPPFLAGS = \ ++ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ ++ -I$(top_srcdir)/src -I$(top_builddir)/src ++boot_analysis_CFLAGS = \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) \ ++ $(PCRE_CFLAGS) ++boot_analysis_LDADD = \ ++ $(top_builddir)/src/libutils.la \ ++ $(top_builddir)/src/libguestfs.la \ ++ $(PCRE_LIBS) \ ++ $(LIBXML2_LIBS) \ ++ $(LIBVIRT_LIBS) \ ++ $(LTLIBINTL) \ ++ $(top_builddir)/gnulib/lib/libgnu.la \ ++ -lm ++ + # Don't run these tests in parallel, since they are designed to check + # the integrity of qemu. + .NOTPARALLEL: +diff --git a/tests/qemu/boot-analysis-timeline.c b/tests/qemu/boot-analysis-timeline.c +new file mode 100644 +index 0000000..8753805 +--- /dev/null ++++ b/tests/qemu/boot-analysis-timeline.c +@@ -0,0 +1,468 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "ignore-value.h" ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis.h" ++ ++COMPILE_REGEXP(re_initcall_calling_module, ++ "calling ([_A-Za-z0-9]+)\\+.*\\[([_A-Za-z0-9]+)]", 0) ++COMPILE_REGEXP(re_initcall_calling, ++ "calling ([_A-Za-z0-9]+)\\+", 0) ++ ++static void construct_initcall_timeline (void); ++ ++/* "supermin: internal insmod xx.ko" -> "insmod xx.ko" */ ++static char * ++translate_supermin_insmod_message (const char *message) ++{ ++ char *ret; ++ ++ assert (STRPREFIX (message, "supermin: internal ")); ++ ++ ret = strdup (message + strlen ("supermin: internal ")); ++ if (ret == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ return ret; ++} ++ ++/* Analyze significant events from the events array, to form a ++ * timeline of activities. ++ */ ++void ++construct_timeline (void) ++{ ++ size_t i, j, k; ++ struct pass_data *data; ++ struct activity *activity; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ data = &pass_data[i]; ++ ++ /* Find an activity, by matching an event with the condition ++ * `begin_cond' through to the second event `end_cond'. Create an ++ * activity object in the timeline from the result. ++ */ ++#define FIND(name, flags, begin_cond, end_cond) \ ++ do { \ ++ activity = NULL; \ ++ for (j = 0; j < data->nr_events; ++j) { \ ++ if (begin_cond) { \ ++ for (k = j+1; k < data->nr_events; ++k) { \ ++ if (end_cond) { \ ++ if (i == 0) \ ++ activity = add_activity (name, flags); \ ++ else \ ++ activity = find_activity (name); \ ++ break; \ ++ } \ ++ } \ ++ break; \ ++ } \ ++ } \ ++ if (activity) { \ ++ activity->start_event[i] = j; \ ++ activity->end_event[i] = k; \ ++ } \ ++ else \ ++ error (EXIT_FAILURE, 0, "could not find activity '%s' in pass '%zu'", \ ++ name, i); \ ++ } while (0) ++ ++ /* Same as FIND() macro, but if no matching events are found, ++ * ignore it. ++ */ ++#define FIND_OPTIONAL(name, flags, begin_cond, end_cond) \ ++ do { \ ++ activity = NULL; \ ++ for (j = 0; j < data->nr_events; ++j) { \ ++ if (begin_cond) { \ ++ for (k = j+1; k < data->nr_events; ++k) { \ ++ if (end_cond) { \ ++ if (i == 0) \ ++ activity = add_activity (name, flags); \ ++ else \ ++ activity = find_activity (name); \ ++ break; \ ++ } \ ++ } \ ++ break; \ ++ } \ ++ } \ ++ if (activity) { \ ++ activity->start_event[i] = j; \ ++ activity->end_event[i] = k; \ ++ } \ ++ } while (0) ++ ++ /* Find multiple entries, where we check for: ++ * next_cond ++ * next_cond ++ * next_cond ++ * end_cond ++ */ ++#define FIND_MULTIPLE(debug_name, flags, next_cond, end_cond, translate_message) \ ++ do { \ ++ activity = NULL; \ ++ for (j = 0; j < data->nr_events; ++j) { \ ++ if (next_cond) { \ ++ CLEANUP_FREE char *message = translate_message (data->events[j].message); \ ++ if (activity) \ ++ activity->end_event[i] = j; \ ++ if (i == 0) \ ++ activity = add_activity (message, flags); \ ++ else \ ++ activity = find_activity (message); \ ++ activity->start_event[i] = j; \ ++ } \ ++ else if (end_cond) \ ++ break; \ ++ } \ ++ if (j < data->nr_events && activity) \ ++ activity->end_event[i] = j; \ ++ else \ ++ error (EXIT_FAILURE, 0, "could not find activity '%s' in pass '%zu'", \ ++ debug_name, i); \ ++ } while (0) ++ ++ /* Add one activity which is going to cover the whole process ++ * from launch to close. The launch event is always event 0. ++ * NB: This activity must be called "run" (see below). ++ */ ++ FIND ("run", LONG_ACTIVITY, ++ j == 0, data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++ /* Find where we invoke supermin --build. This should be a null ++ * operation, but it still takes time to run the external command. ++ */ ++ FIND ("supermin:build", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, ++ "begin building supermin appliance"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, ++ "finished building supermin appliance")); ++ ++ /* Find where we invoke qemu to test features. */ ++ FIND ("qemu:feature-detect", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, ++ "begin testing qemu features"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, ++ "finished testing qemu features")); ++ ++ /* Find where we run qemu. */ ++ FIND ("qemu", LONG_ACTIVITY, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "-nodefconfig"), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++#define SGABIOS_STRING "\033[1;256r\033[256;256H\033[6n" ++ ++ /* From starting qemu up to entering the BIOS is the qemu overhead. */ ++ FIND ("qemu:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "-nodefconfig"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, SGABIOS_STRING)); ++ ++ /* From entering the BIOS to starting the kernel is the BIOS overhead. */ ++ FIND_OPTIONAL ("bios:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, SGABIOS_STRING), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Probing EDD")); ++ ++ /* SGABIOS (option ROM). */ ++ FIND_OPTIONAL ("sgabios", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, SGABIOS_STRING), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "SeaBIOS (version")); ++ ++ /* SeaBIOS. */ ++ FIND ("seabios", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "SeaBIOS (version"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Probing EDD")); ++ ++ /* SeaBIOS - only available when using debug messages. */ ++ FIND_OPTIONAL ("seabios:pci-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Searching bootorder for: /pci@"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Scan for option roms")); ++ ++ /* Find where we run the guest kernel. */ ++ FIND ("kernel", LONG_ACTIVITY, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Probing EDD"), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++ /* Kernel startup to userspace. */ ++ FIND ("kernel:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Probing EDD"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "supermin:") && ++ strstr (data->events[k].message, "starting up")); ++ ++ /* The time taken to get into start_kernel function. */ ++ FIND ("kernel:entry", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Probing EDD"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Linux version")); ++ ++ /* Alternatives patching instructions (XXX not very accurate we ++ * really need some debug messages inserted into the code). ++ */ ++ FIND ("kernel:alternatives", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Last level dTLB entries"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Freeing SMP alternatives")); ++ ++ /* ftrace patching instructions. */ ++ FIND ("kernel:ftrace", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "ftrace: allocating"), ++ 1); ++ ++ /* Find where we run supermin mini-initrd. */ ++ FIND ("supermin:mini-initrd", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin:") && ++ strstr (data->events[j].message, "starting up"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "supermin: chroot")); ++ ++ /* Loading kernel modules from supermin initrd. */ ++ FIND_MULTIPLE ++ ("supermin insmod", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: internal insmod"), ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: picked"), ++ translate_supermin_insmod_message); ++ ++ /* Find where we run the /init script. */ ++ FIND ("/init", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: chroot"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "guestfsd --verbose")); ++ ++ /* Everything from the chroot to the first echo in the /init ++ * script counts as bash overhead. ++ */ ++ FIND ("bash:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: chroot"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Starting /init script")); ++ ++ /* /init: Mount special filesystems. */ ++ FIND ("/init:mount-special", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "*guestfs_boot_analysis=1*"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "kmod static-nodes")); ++ ++ /* /init: Run kmod static-nodes */ ++ FIND ("/init:kmod-static-nodes", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "kmod static-nodes"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "systemd-tmpfiles")); ++ ++ /* /init: systemd-tmpfiles. */ ++ FIND ("/init:systemd-tmpfiles", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "systemd-tmpfiles"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "udev")); ++ ++ /* /init: start udevd. */ ++ FIND ("/init:udev-overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "udevd --daemon"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "nullglob")); ++ ++ /* /init: set up network. */ ++ FIND ("/init:network-overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ ip addr"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ test")); ++ ++ /* /init: probe MD arrays. */ ++ FIND ("/init:md-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ mdadm"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ modprobe dm_mod")); ++ ++ /* /init: probe DM/LVM. */ ++ FIND ("/init:lvm-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ modprobe dm_mod"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ ldmtool")); ++ ++ /* /init: probe Windows dynamic disks. */ ++ FIND ("/init:windows-dynamic-disks-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ ldmtool"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ test")); ++ ++ /* Find where we run guestfsd. */ ++ FIND ("guestfsd", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "guestfsd --verbose"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "fsync /dev/sda")); ++ ++ /* Shutdown process. */ ++ FIND ("shutdown", 0, ++ data->events[j].source == GUESTFS_EVENT_TRACE && ++ STREQ (data->events[j].message, "close"), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ } ++ ++ construct_initcall_timeline (); ++} ++ ++/* Handling of initcall is so peculiar that we hide it in a separate ++ * function from the rest. ++ */ ++static void ++construct_initcall_timeline (void) ++{ ++ size_t i, j, k; ++ struct pass_data *data; ++ struct activity *activity; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ data = &pass_data[i]; ++ ++ /* Each kernel initcall is bracketed by: ++ * ++ * calling ehci_hcd_init+0x0/0xc1 @ 1" ++ * initcall ehci_hcd_init+0x0/0xc1 returned 0 after 420 usecs" ++ * ++ * For initcall functions in modules: ++ * ++ * calling virtio_mmio_init+0x0/0x1000 [virtio_mmio] @ 1" ++ * initcall virtio_mmio_init+0x0/0x1000 [virtio_mmio] returned 0 after 14 usecs" ++ * ++ * Initcall functions can be nested, and do not have unique names. ++ */ ++ for (j = 0; j < data->nr_events; ++j) { ++ int vec[30], r; ++ const char *message = data->events[j].message; ++ ++ if (data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ ((r = pcre_exec (re_initcall_calling_module, NULL, ++ message, strlen (message), ++ 0, 0, vec, sizeof vec / sizeof vec[0])) >= 1 || ++ (r = pcre_exec (re_initcall_calling, NULL, ++ message, strlen (message), ++ 0, 0, vec, sizeof vec / sizeof vec[0])) >= 1)) { ++ ++ CLEANUP_FREE char *fn_name = NULL, *module_name = NULL; ++ if (r >= 2) /* because pcre_exec returns 1 + number of captures */ ++ fn_name = strndup (message + vec[2], vec[3]-vec[2]); ++ if (r >= 3) ++ module_name = strndup (message + vec[4], vec[5]-vec[4]); ++ ++ CLEANUP_FREE char *fullname; ++ if (asprintf (&fullname, "%s.%s", ++ module_name ? module_name : "kernel", fn_name) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ CLEANUP_FREE char *initcall_match; ++ if (asprintf (&initcall_match, "initcall %s", fn_name) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ /* Get a unique name for this activity. Unfortunately ++ * kernel initcall function names are not unique! ++ */ ++ CLEANUP_FREE char *activity_name; ++ if (asprintf (&activity_name, "initcall %s", fullname) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ if (i == 0) { ++ int n = 1; ++ while (activity_exists (activity_name)) { ++ free (activity_name); ++ if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ n++; ++ } ++ } ++ else { ++ int n = 1; ++ while (!activity_exists_with_no_data (activity_name, i)) { ++ free (activity_name); ++ if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ n++; ++ } ++ } ++ ++ /* Find the matching end event. It might be some time later, ++ * since it appears initcalls can be nested. ++ */ ++ for (k = j+1; k < data->nr_events; ++k) { ++ if (data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, initcall_match)) { ++ if (i == 0) ++ activity = add_activity (activity_name, 0); ++ else ++ activity = find_activity (activity_name); ++ activity->start_event[i] = j; ++ activity->end_event[i] = k; ++ break; ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +new file mode 100644 +index 0000000..71b265a +--- /dev/null ++++ b/tests/qemu/boot-analysis.c +@@ -0,0 +1,1030 @@ ++/* libguestfs ++ * Copyright (C) 2016 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. ++ */ ++ ++/* Trace and analyze the appliance boot process to find out which ++ * steps are taking the most time. It is not part of the standard ++ * tests. ++ * ++ * This needs to be run on a quiet machine, so that other processes ++ * disturb the timing as little as possible. The program is ++ * completely safe to run at any time. It doesn't read or write any ++ * external files, and it doesn't require root. ++ * ++ * You can run it from the build directory like this: ++ * ++ * make ++ * make -C tests/qemu boot-analysis ++ * ./run tests/qemu/boot-analysis ++ * ++ * The way it works is roughly like this: ++ * ++ * We create a libguestfs handle and register callback handlers so we ++ * can see appliance messages, trace events and so on. ++ * ++ * We then launch the handle and shut it down as quickly as possible. ++ * ++ * While the handle is running, events (seen by the callback handlers) ++ * are written verbatim into an in-memory buffer, with timestamps. ++ * ++ * Afterwards we analyze the result using regular expressions to try ++ * to identify a "timeline" for the handle (eg. at what time did the ++ * BIOS hand control to the kernel). This analysis is done in ++ * 'boot-analysis-timeline.c'. ++ * ++ * The whole process is repeated across a few runs, and the final ++ * timeline (including statistical analysis of the variation between ++ * runs) gets printed. ++ * ++ * The program is very sensitive to the specific messages printed by ++ * BIOS/kernel/supermin/userspace, so it won't work on non-x86, and it ++ * will require periodic adjustment of the regular expressions in ++ * order to keep things up to date. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ignore-value.h" ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis.h" ++ ++/* Activities taking longer than this % of the total time, except ++ * those flagged as LONG_ACTIVITY, are highlighted in red. ++ */ ++#define WARNING_THRESHOLD 1.0 ++ ++struct pass_data pass_data[NR_TEST_PASSES]; ++size_t nr_activities; ++struct activity *activities; ++ ++static int force_colour = 0; ++static int verbose = 0; ++ ++static void run_test (void); ++static void get_time (struct timespec *ts); ++static int64_t timespec_diff (const struct timespec *x, const struct timespec *y); ++static struct event *add_event (struct pass_data *, uint64_t source); ++static guestfs_h *create_handle (void); ++static void set_up_event_handlers (guestfs_h *g, size_t pass); ++static void add_drive (guestfs_h *g); ++static void check_pass_data (void); ++static void dump_pass_data (void); ++static void analyze_timeline (void); ++static void dump_timeline (void); ++static void print_info (void); ++static void print_analysis (void); ++static void print_longest_to_shortest (void); ++static void free_pass_data (void); ++static void free_final_timeline (void); ++static void ansi_green (void); ++static void ansi_red (void); ++static void ansi_blue (void); ++static void ansi_magenta (void); ++static void ansi_restore (void); ++ ++static void ++usage (int exitcode) ++{ ++ fprintf (stderr, ++ "boot-analysis: Trace and analyze the appliance boot process.\n" ++ "Usage:\n" ++ " boot-analysis [--options]\n" ++ "Options:\n" ++ " --help Display this usage text and exit.\n" ++ " --colour Output colours, even if not a terminal.\n" ++ " -v|--verbose Verbose output, useful for debugging.\n"); ++ exit (exitcode); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ enum { HELP_OPTION = CHAR_MAX + 1 }; ++ static const char *options = "v"; ++ static const struct option long_options[] = { ++ { "help", 0, 0, HELP_OPTION }, ++ { "color", 0, 0, 0 }, ++ { "colour", 0, 0, 0 }, ++ { "verbose", 0, 0, 'v' }, ++ { 0, 0, 0, 0 } ++ }; ++ int c, option_index; ++ ++ for (;;) { ++ c = getopt_long (argc, argv, options, long_options, &option_index); ++ if (c == -1) break; ++ ++ switch (c) { ++ case 0: /* Options which are long only. */ ++ if (STREQ (long_options[option_index].name, "color") || ++ STREQ (long_options[option_index].name, "colour")) { ++ force_colour = 1; ++ break; ++ } ++ fprintf (stderr, "%s: unknown long option: %s (%d)\n", ++ guestfs_int_program_name, long_options[option_index].name, option_index); ++ exit (EXIT_FAILURE); ++ ++ case 'v': ++ verbose = 1; ++ break; ++ ++ case HELP_OPTION: ++ usage (EXIT_SUCCESS); ++ ++ default: ++ usage (EXIT_FAILURE); ++ } ++ } ++ ++ if (STRNEQ (host_cpu, "x86_64")) ++ fprintf (stderr, "WARNING: host_cpu != x86_64: This program may not work or give bogus results.\n"); ++ ++ run_test (); ++} ++ ++static void ++run_test (void) ++{ ++ guestfs_h *g; ++ size_t i; ++ ++ printf ("Warming up the libguestfs cache ...\n"); ++ for (i = 0; i < NR_WARMUP_PASSES; ++i) { ++ g = create_handle (); ++ add_drive (g); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ } ++ ++ printf ("Running the tests in %d passes ...\n", NR_TEST_PASSES); ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ g = create_handle (); ++ set_up_event_handlers (g, i); ++ add_drive (g); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ ++ printf (" pass %zu: %zu events collected in %" PRIi64 " ns\n", ++ i+1, pass_data[i].nr_events, pass_data[i].elapsed_ns); ++ } ++ ++ if (verbose) ++ dump_pass_data (); ++ ++ printf ("Analyzing the results ...\n"); ++ check_pass_data (); ++ construct_timeline (); ++ analyze_timeline (); ++ ++ if (verbose) ++ dump_timeline (); ++ ++ printf ("\n"); ++ print_info (); ++ printf ("\n"); ++ print_analysis (); ++ printf ("\n"); ++ printf ("Longest activities:\n"); ++ printf ("\n"); ++ print_longest_to_shortest (); ++ ++ free_pass_data (); ++ free_final_timeline (); ++} ++ ++static void ++get_time (struct timespec *ts) ++{ ++ if (clock_gettime (CLOCK_REALTIME, ts) == -1) ++ error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME"); ++} ++ ++/* Computes Y - X, returning nanoseconds. */ ++static int64_t ++timespec_diff (const struct timespec *x, const struct timespec *y) ++{ ++ int64_t nsec; ++ ++ nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000); ++ nsec += y->tv_nsec - x->tv_nsec; ++ return nsec; ++} ++ ++static struct event * ++add_event (struct pass_data *data, uint64_t source) ++{ ++ struct event *ret; ++ ++ data->nr_events++; ++ data->events = realloc (data->events, ++ sizeof (struct event) * data->nr_events); ++ if (data->events == NULL) ++ error (EXIT_FAILURE, errno, "realloc"); ++ ret = &data->events[data->nr_events-1]; ++ get_time (&ret->t); ++ ret->source = source; ++ ret->message = NULL; ++ return ret; ++} ++ ++/* Common function to create the handle and set various defaults. */ ++static guestfs_h * ++create_handle (void) ++{ ++ guestfs_h *g; ++ ++ g = guestfs_create (); ++ if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); ++ ++ /* We always run these tests using LIBGUESTFS_BACKEND=direct. It ++ * may be in future we need to test libvirt as well, in case ++ * performance issues are suspected there, but so far libvirt has ++ * not been a bottleneck. ++ */ ++ if (guestfs_set_backend (g, "direct") == -1) ++ exit (EXIT_FAILURE); ++ ++ /* This changes some details in appliance/init and enables a ++ * detailed trace of calls to initcall functions in the kernel. ++ */ ++ if (guestfs_set_append (g, ++ "guestfs_boot_analysis=1 " ++ "ignore_loglevel initcall_debug") == -1) ++ exit (EXIT_FAILURE); ++ ++ return g; ++} ++ ++/* Common function to add the /dev/null drive. */ ++static void ++add_drive (guestfs_h *g) ++{ ++ if (guestfs_add_drive_opts (g, "/dev/null", ++ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", ++ GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, ++ -1) == -1) ++ exit (EXIT_FAILURE); ++} ++ ++/* Called when the handle is closed. Perform any cleanups required in ++ * the pass_data here. ++ */ ++static void ++close_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strdup ("close callback"); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ ++ get_time (&data->end_t); ++ data->elapsed_ns = timespec_diff (&data->start_t, &data->end_t); ++} ++ ++/* Called when the qemu subprocess exits. ++ * XXX This is never called - why? ++ */ ++static void ++subprocess_quit_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strdup ("subprocess quit callback"); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++} ++ ++/* Called when the launch operation is complete (the library and the ++ * guestfs daemon and talking to each other). ++ */ ++static void ++launch_done_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strdup ("launch done callback"); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++} ++ ++/* Trim \r (multiple) from the end of a string. */ ++static void ++trim_r (char *message) ++{ ++ size_t len = strlen (message); ++ ++ while (len > 0 && message[len-1] == '\r') { ++ message[len-1] = '\0'; ++ len--; ++ } ++} ++ ++/* Called when we get (possibly part of) a log message (or more than ++ * one log message) from the appliance (which may include qemu, the ++ * BIOS, kernel, etc). ++ */ ++static void ++appliance_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ size_t i, len, slen; ++ ++ if (!data->seen_launch) ++ return; ++ ++ /* If the previous log message was incomplete, but time has moved on ++ * a lot, record a new log message anyway, so it gets a new ++ * timestamp. ++ */ ++ if (data->incomplete_log_message >= 0) { ++ struct timespec ts; ++ get_time (&ts); ++ if (timespec_diff (&data->events[data->incomplete_log_message].t, ++ &ts) >= 10000000 /* 10ms */) ++ data->incomplete_log_message = -1; ++ } ++ ++ /* If the previous log message was incomplete then we may need to ++ * append part of the current log message to a previous one. ++ */ ++ if (data->incomplete_log_message >= 0) { ++ len = buf_len; ++ for (i = 0; i < buf_len; ++i) { ++ if (buf[i] == '\n') { ++ len = i; ++ break; ++ } ++ } ++ ++ event = &data->events[data->incomplete_log_message]; ++ slen = strlen (event->message); ++ event->message = realloc (event->message, slen + len + 1); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "realloc"); ++ memcpy (event->message + slen, buf, len); ++ event->message[slen + len] = '\0'; ++ trim_r (event->message); ++ ++ /* Skip what we just added to the previous incomplete message. */ ++ buf += len; ++ buf_len -= len; ++ ++ if (buf_len == 0) /* still not complete, more to come! */ ++ return; ++ ++ /* Skip the \n in the buffer. */ ++ buf++; ++ buf_len--; ++ data->incomplete_log_message = -1; ++ } ++ ++ /* Add the event, or perhaps multiple events if the message ++ * contains \n characters. ++ */ ++ while (buf_len > 0) { ++ len = buf_len; ++ for (i = 0; i < buf_len; ++i) { ++ if (buf[i] == '\n') { ++ len = i; ++ break; ++ } ++ } ++ ++ event = add_event (data, source); ++ event->message = strndup (buf, len); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++ trim_r (event->message); ++ ++ /* Skip what we just added to the event. */ ++ buf += len; ++ buf_len -= len; ++ ++ if (buf_len == 0) { ++ /* Event is incomplete (doesn't end with \n). We'll finish it ++ * in the next callback. ++ */ ++ data->incomplete_log_message = event - data->events; ++ return; ++ } ++ ++ /* Skip the \n in the buffer. */ ++ buf++; ++ buf_len--; ++ } ++} ++ ++/* Called when we get a debug message from the library side. These ++ * are always delivered as complete messages. ++ */ ++static void ++library_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strndup (buf, buf_len); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++} ++ ++/* Called when we get a call trace message (a libguestfs API function ++ * has been called or is returning). These are always delivered as ++ * complete messages. ++ */ ++static void ++trace_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ char *message; ++ ++ message = strndup (buf, buf_len); ++ if (message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++ ++ if (STREQ (message, "launch")) ++ data->seen_launch = 1; ++ ++ if (!data->seen_launch) { ++ free (message); ++ return; ++ } ++ ++ event = add_event (data, source); ++ event->message = message; ++} ++ ++/* Common function to set up event callbacks and record data in memory ++ * for a particular pass (0 <= pass < NR_TEST_PASSES). ++ */ ++static void ++set_up_event_handlers (guestfs_h *g, size_t pass) ++{ ++ struct pass_data *data; ++ ++ assert (/* 0 <= pass && */ pass < NR_TEST_PASSES); ++ ++ data = &pass_data[pass]; ++ data->pass = pass; ++ data->nr_events = 0; ++ data->events = NULL; ++ get_time (&data->start_t); ++ data->incomplete_log_message = -1; ++ data->seen_launch = 0; ++ ++ guestfs_set_event_callback (g, close_callback, ++ GUESTFS_EVENT_CLOSE, 0, data); ++ guestfs_set_event_callback (g, subprocess_quit_callback, ++ GUESTFS_EVENT_SUBPROCESS_QUIT, 0, data); ++ guestfs_set_event_callback (g, launch_done_callback, ++ GUESTFS_EVENT_LAUNCH_DONE, 0, data); ++ guestfs_set_event_callback (g, appliance_callback, ++ GUESTFS_EVENT_APPLIANCE, 0, data); ++ guestfs_set_event_callback (g, library_callback, ++ GUESTFS_EVENT_LIBRARY, 0, data); ++ guestfs_set_event_callback (g, trace_callback, ++ GUESTFS_EVENT_TRACE, 0, data); ++ ++ guestfs_set_verbose (g, 1); ++ guestfs_set_trace (g, 1); ++} ++ ++/* Sanity check the collected events. */ ++static void ++check_pass_data (void) ++{ ++ size_t i, j, len; ++ int64_t ns; ++ const char *message; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ assert (pass_data[i].pass == i); ++ assert (pass_data[i].elapsed_ns > 1000); ++ assert (pass_data[i].nr_events > 0); ++ assert (pass_data[i].events != NULL); ++ ++ for (j = 0; j < pass_data[i].nr_events; ++j) { ++ assert (pass_data[i].events[j].t.tv_sec > 0); ++ if (j > 0) { ++ ns = timespec_diff (&pass_data[i].events[j-1].t, ++ &pass_data[i].events[j].t); ++ assert (ns >= 0); ++ } ++ assert (pass_data[i].events[j].source != 0); ++ message = pass_data[i].events[j].message; ++ assert (message != NULL); ++ assert (strchr (message, '\n') == NULL); ++ len = strlen (message); ++ assert (len == 0 || message[len-1] != '\r'); ++ } ++ } ++} ++ ++static void ++print_escaped_string (const char *message) ++{ ++ while (*message) { ++ if (isprint (*message)) ++ putchar (*message); ++ else ++ printf ("\\x%02x", (unsigned int) *message); ++ message++; ++ } ++} ++ ++/* Dump the events to stdout, if verbose is set. */ ++static void ++dump_pass_data (void) ++{ ++ size_t i, j; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ printf ("pass %zu\n", pass_data[i].pass); ++ printf (" number of events collected %zu\n", pass_data[i].nr_events); ++ printf (" elapsed time %" PRIi64 " ns\n", pass_data[i].elapsed_ns); ++ for (j = 0; j < pass_data[i].nr_events; ++j) { ++ int64_t ns; ++ CLEANUP_FREE char *event_str = NULL; ++ ++ ns = timespec_diff (&pass_data[i].start_t, &pass_data[i].events[j].t); ++ event_str = guestfs_event_to_string (pass_data[i].events[j].source); ++ printf (" #%zu: +%" PRIi64 " [%s] \"", j, ns, event_str); ++ print_escaped_string (pass_data[i].events[j].message); ++ printf ("\"\n"); ++ } ++ } ++} ++ ++int ++activity_exists (const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ if (STREQ (activities[i].name, name)) ++ return 1; ++ return 0; ++} ++ ++/* Add an activity to the global list. */ ++struct activity * ++add_activity (const char *name, int flags) ++{ ++ struct activity *ret; ++ size_t i; ++ ++ /* You shouldn't have two activities with the same name. */ ++ assert (!activity_exists (name)); ++ ++ nr_activities++; ++ activities = realloc (activities, sizeof (struct activity) * nr_activities); ++ if (activities == NULL) ++ error (EXIT_FAILURE, errno, "realloc"); ++ ret = &activities[nr_activities-1]; ++ ret->name = strdup (name); ++ if (ret->name == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ ret->flags = flags; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) ++ ret->start_event[i] = ret->end_event[i] = 0; ++ ++ return ret; ++} ++ ++struct activity * ++find_activity (const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ if (STREQ (activities[i].name, name)) ++ return &activities[i]; ++ error (EXIT_FAILURE, 0, ++ "internal error: could not find activity '%s'", name); ++ /*NOTREACHED*/ ++ abort (); ++} ++ ++int ++activity_exists_with_no_data (const char *name, size_t pass) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ if (STREQ (activities[i].name, name) && ++ activities[i].start_event[pass] == 0 && ++ activities[i].end_event[pass] == 0) ++ return 1; ++ return 0; ++} ++ ++static int ++compare_activities_by_t (const void *av, const void *bv) ++{ ++ const struct activity *a = av; ++ const struct activity *b = bv; ++ ++ return a->t - b->t; ++} ++ ++/* Go through the activities, computing the start and elapsed time. */ ++static void ++analyze_timeline (void) ++{ ++ struct activity *activity; ++ size_t i, j; ++ int64_t delta_ns; ++ ++ for (j = 0; j < nr_activities; ++j) { ++ activity = &activities[j]; ++ ++ activity->t = 0; ++ activity->mean = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ delta_ns = ++ timespec_diff (&pass_data[i].events[0].t, ++ &pass_data[i].events[activity->start_event[i]].t); ++ activity->t += delta_ns; ++ ++ delta_ns = ++ timespec_diff (&pass_data[i].events[activity->start_event[i]].t, ++ &pass_data[i].events[activity->end_event[i]].t); ++ activity->mean += delta_ns; ++ } ++ ++ /* Divide through to get real start time and mean of each activity. */ ++ activity->t /= NR_TEST_PASSES; ++ activity->mean /= NR_TEST_PASSES; ++ ++ /* Calculate the end time of this activity. It's convenient when ++ * drawing the timeline for one activity to finish just before the ++ * next activity starts, rather than having them end and start at ++ * the same time, hence ``- 1'' here. ++ */ ++ activity->end_t = activity->t + activity->mean - 1; ++ ++ /* The above only calculated mean. Now we are able to ++ * calculate from the mean the variance and the standard ++ * deviation. ++ */ ++ activity->variance = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ delta_ns = ++ timespec_diff (&pass_data[i].events[activity->start_event[i]].t, ++ &pass_data[i].events[activity->end_event[i]].t); ++ activity->variance += pow (delta_ns - activity->mean, 2); ++ } ++ activity->variance /= NR_TEST_PASSES; ++ ++ activity->sd = sqrt (activity->variance); ++ } ++ ++ /* Get the total mean elapsed time from the special "run" activity. */ ++ activity = find_activity ("run"); ++ for (j = 0; j < nr_activities; ++j) { ++ activities[j].percent = 100.0 * activities[j].mean / activity->mean; ++ ++ activities[j].warning = ++ !(activities[j].flags & LONG_ACTIVITY) && ++ activities[j].percent >= WARNING_THRESHOLD; ++ } ++ ++ /* Sort the activities by start time. */ ++ qsort (activities, nr_activities, sizeof (struct activity), ++ compare_activities_by_t); ++} ++ ++/* Dump the timeline to stdout, if verbose is set. */ ++static void ++dump_timeline (void) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) { ++ printf ("activity %zu:\n", i); ++ printf (" name = %s\n", activities[i].name); ++ printf (" start - end = %.1f - %.1f\n", ++ activities[i].t, activities[i].end_t); ++ printf (" mean elapsed = %.1f\n", activities[i].mean); ++ printf (" variance = %.1f\n", activities[i].variance); ++ printf (" s.d = %.1f\n", activities[i].sd); ++ printf (" percent = %.1f\n", activities[i].percent); ++ } ++} ++ ++/* Print some information that will allow us to determine the test ++ * system when reviewing the results in future. ++ */ ++static void ++print_info (void) ++{ ++ size_t i; ++ ++ printf ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION_FULL); ++ ++ printf ("Host:\n"); ++ ignore_value (system ("uname -a")); ++ ignore_value (system ("grep '^model name' /proc/cpuinfo | head -1")); ++ ++ /* We can dig some information about qemu and the appliance out of ++ * the events. ++ */ ++ printf ("Appliance:\n"); ++ assert (NR_TEST_PASSES > 0); ++ for (i = 0; i < pass_data[0].nr_events; ++i) { ++ const char *message = pass_data[0].events[i].message; ++ if (strstr (message, "qemu version") || ++ (strstr (message, "SeaBIOS") && strstr (message, "version")) || ++ strstr (message, "Linux version") || ++ (strstr (message, "supermin") && strstr (message, "starting up"))) { ++ print_escaped_string (message); ++ putchar ('\n'); ++ } ++ } ++} ++ ++static void ++print_activity (struct activity *activity) ++{ ++ if (activity->warning) ansi_red (); else ansi_green (); ++ print_escaped_string (activity->name); ++ ansi_restore (); ++ printf (" %1.6fs ±%.1fms ", ++ activity->mean / 1000000000, activity->sd / 1000000); ++ if (activity->warning) ansi_red (); else ansi_green (); ++ printf ("(%.1f%%) ", activity->percent); ++ ansi_restore (); ++} ++ ++static void ++print_analysis (void) ++{ ++ double t = -1; /* Current time. */ ++ /* Which columns contain activities that we are displaying now? ++ * -1 == unused column, else index of an activity ++ */ ++ CLEANUP_FREE ssize_t *columns = NULL; ++ const size_t nr_columns = nr_activities; ++ size_t last_free_column = 0; ++ ++ size_t i, j; ++ double last_t, smallest_next_t; ++ const double MAX_T = 1e20; ++ ++ columns = malloc (nr_columns * sizeof (ssize_t)); ++ if (columns == NULL) error (EXIT_FAILURE, errno, "malloc"); ++ for (j = 0; j < nr_columns; ++j) ++ columns[j] = -1; ++ ++ for (;;) { ++ /* Find the next significant time to display, which is a time when ++ * some activity started or ended. ++ */ ++ smallest_next_t = MAX_T; ++ for (i = 0; i < nr_activities; ++i) { ++ if (t < activities[i].t && activities[i].t < smallest_next_t) ++ smallest_next_t = activities[i].t; ++ else if (t < activities[i].end_t && activities[i].end_t < smallest_next_t) ++ smallest_next_t = activities[i].end_t; ++ } ++ if (smallest_next_t == MAX_T) ++ break; /* Finished. */ ++ ++ last_t = t; ++ t = smallest_next_t; ++ ++ /* Draw a spacer line, but only if last_t -> t is a large jump. */ ++ if (t - last_t >= 1000000 /* ns */) { ++ printf (" "); ++ ansi_magenta (); ++ for (j = 0; j < last_free_column; ++j) { ++ if (columns[j] >= 0 && ++ activities[columns[j]].end_t != last_t /* !▼ */) ++ printf ("│ "); ++ else ++ printf (" "); ++ } ++ ansi_restore (); ++ printf ("\n"); ++ } ++ ++ /* If there are any activities that ended before this time, drop ++ * them from the columns list. ++ */ ++ for (i = 0; i < nr_activities; ++i) { ++ if (activities[i].end_t < t) { ++ for (j = 0; j < nr_columns; ++j) ++ if (columns[j] == (ssize_t) i) { ++ columns[j] = -1; ++ break; ++ } ++ } ++ } ++ ++ /* May need to adjust last_free_column after previous operation. */ ++ while (last_free_column > 0 && columns[last_free_column-1] == -1) ++ last_free_column--; ++ ++ /* If there are any activities starting at this time, add them to ++ * the right hand end of the columns list. ++ */ ++ for (i = 0; i < nr_activities; ++i) { ++ if (activities[i].t == t) ++ columns[last_free_column++] = i; ++ } ++ ++ /* Draw the line. */ ++ ansi_blue (); ++ printf ("%1.6fs: ", t / 1000000000); ++ ++ ansi_magenta (); ++ for (j = 0; j < last_free_column; ++j) { ++ if (columns[j] >= 0) { ++ if (activities[columns[j]].t == t) ++ printf ("▲ "); ++ else if (activities[columns[j]].end_t == t) ++ printf ("▼ "); ++ else ++ printf ("│ "); ++ } ++ else ++ printf (" "); ++ } ++ ansi_restore (); ++ ++ for (j = 0; j < last_free_column; ++j) { ++ if (columns[j] >= 0 && activities[columns[j]].t == t) /* ▲ */ ++ print_activity (&activities[columns[j]]); ++ } ++ ++ printf ("\n"); ++ } ++} ++ ++static int ++compare_activities_pointers_by_mean (const void *av, const void *bv) ++{ ++ const struct activity * const *a = av; ++ const struct activity * const *b = bv; ++ ++ return (*b)->mean - (*a)->mean; ++} ++ ++static void ++print_longest_to_shortest (void) ++{ ++ size_t i; ++ CLEANUP_FREE struct activity **longest; ++ ++ /* Sort the activities longest first. In order not to affect the ++ * global activities array, sort an array of pointers to the ++ * activities instead. ++ */ ++ longest = malloc (sizeof (struct activity *) * nr_activities); ++ for (i = 0; i < nr_activities; ++i) ++ longest[i] = &activities[i]; ++ ++ qsort (longest, nr_activities, sizeof (struct activity *), ++ compare_activities_pointers_by_mean); ++ ++ /* Display the activities, longest first. */ ++ for (i = 0; i < nr_activities; ++i) { ++ print_activity (longest[i]); ++ printf ("\n"); ++ } ++} ++ ++/* Free the non-static part of the pass_data structures. */ ++static void ++free_pass_data (void) ++{ ++ size_t i, j; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ for (j = 0; j < pass_data[i].nr_events; ++j) ++ free (pass_data[i].events[j].message); ++ free (pass_data[i].events); ++ } ++} ++ ++static void ++free_final_timeline (void) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ free (activities[i].name); ++ free (activities); ++} ++ ++/* Colours. */ ++static void ++ansi_green (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[0;32m", stdout); ++} ++ ++static void ++ansi_red (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[1;31m", stdout); ++} ++ ++static void ++ansi_blue (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[1;34m", stdout); ++} ++ ++static void ++ansi_magenta (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[1;35m", stdout); ++} ++ ++static void ++ansi_restore (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[0m", stdout); ++} +diff --git a/tests/qemu/boot-analysis.h b/tests/qemu/boot-analysis.h +new file mode 100644 +index 0000000..86d403e +--- /dev/null ++++ b/tests/qemu/boot-analysis.h +@@ -0,0 +1,94 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 GUESTFS_BOOT_ANALYSIS_H_ ++#define GUESTFS_BOOT_ANALYSIS_H_ ++ ++#define NR_WARMUP_PASSES 3 ++#define NR_TEST_PASSES 5 ++ ++/* Per-pass data collected. */ ++struct pass_data { ++ size_t pass; ++ struct timespec start_t; ++ struct timespec end_t; ++ int64_t elapsed_ns; ++ ++ /* Array of timestamped events. */ ++ size_t nr_events; ++ struct event *events; ++ ++ /* Was the previous appliance log message incomplete? If so, this ++ * contains the index of that incomplete message in the events ++ * array. ++ */ ++ ssize_t incomplete_log_message; ++ ++ /* Have we seen the launch event yet? We don't record events until ++ * this one has been received. This makes it easy to base the ++ * timeline at event 0. ++ */ ++ int seen_launch; ++}; ++ ++struct event { ++ struct timespec t; ++ uint64_t source; ++ char *message; ++}; ++ ++extern struct pass_data pass_data[NR_TEST_PASSES]; ++ ++/* The final timeline consisting of various activities starting and ++ * ending. We're interested in when the activities start, and how ++ * long they take (mean, variance, standard deviation of length). ++ */ ++struct activity { ++ char *name; /* Name of this activity. */ ++ int flags; ++#define LONG_ACTIVITY 1 /* Expected to take a long time. */ ++ ++ /* For each pass, record the actual start & end events of this ++ * activity. ++ */ ++ size_t start_event[NR_TEST_PASSES]; ++ size_t end_event[NR_TEST_PASSES]; ++ ++ double t; /* Start (ns offset). */ ++ double end_t; /* t + mean - 1 */ ++ ++ /* Length of this activity. */ ++ double mean; /* Mean time elapsed (ns). */ ++ double variance; /* Variance. */ ++ double sd; /* Standard deviation. */ ++ double percent; /* Percent of total elapsed time. */ ++ ++ int warning; /* Appears in red. */ ++}; ++ ++extern size_t nr_activities; ++extern struct activity *activities; ++ ++extern int activity_exists (const char *name); ++extern struct activity *add_activity (const char *name, int flags); ++extern struct activity *find_activity (const char *name); ++extern int activity_exists_with_no_data (const char *name, size_t pass); ++ ++extern void construct_timeline (void); ++ ++#endif /* GUESTFS_BOOT_ANALYSIS_H_ */ +-- +1.8.3.1 + diff --git a/SOURCES/0042-v2v-o-glance-Fix-metadata-for-disk-type-and-NIC-RHBZ.patch b/SOURCES/0042-v2v-o-glance-Fix-metadata-for-disk-type-and-NIC-RHBZ.patch deleted file mode 100644 index 2160390..0000000 --- a/SOURCES/0042-v2v-o-glance-Fix-metadata-for-disk-type-and-NIC-RHBZ.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8163c1b8918f5bc4cbb2b3ccba2af1a4ea6dde9b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 7 Nov 2014 11:25:06 +0000 -Subject: [PATCH] v2v: -o glance: Fix metadata for disk type and NIC - (RHBZ#1161575). - -The labels 'hw_disk_bus' and 'hw_vif_model' were swapped. This -happened to work for virtio guests. For non-virtio guests you ended -up with absurdities like requiring an rtl8139 driver for the disk. - -Thanks: Junquin Zhou -(cherry picked from commit 7407c0ae14c382e11e93afe94c0fc37d16df6ae9) ---- - v2v/output_glance.ml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/output_glance.ml b/v2v/output_glance.ml -index c2b1a32..c2fb553 100644 ---- a/v2v/output_glance.ml -+++ b/v2v/output_glance.ml -@@ -74,11 +74,11 @@ object - (* Set the properties (ie. metadata). *) - let min_ram = source.s_memory /^ 1024L /^ 1024L in - let properties = [ -- "hw_vif_model", -+ "hw_disk_bus", - (match guestcaps.gcaps_block_bus with - | Virtio_blk -> "virtio" - | IDE -> "ide"); -- "hw_disk_bus", -+ "hw_vif_model", - (match guestcaps.gcaps_net_bus with - | Virtio_net -> "virtio" - | E1000 -> "e1000" --- -1.8.3.1 - diff --git a/SOURCES/0043-daemon-check-xfs-label-lengths-RHBZ-1162966.patch b/SOURCES/0043-daemon-check-xfs-label-lengths-RHBZ-1162966.patch deleted file mode 100644 index 4beb3ef..0000000 --- a/SOURCES/0043-daemon-check-xfs-label-lengths-RHBZ-1162966.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 9dc43745b5330e5cd56b882f72ba160ab80cf7b1 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 12 Nov 2014 09:50:59 +0100 -Subject: [PATCH] daemon: check xfs label lengths (RHBZ#1162966). - -Similar to commit 52f9cd4882135910ea06e1e50ac6441d455c9ab1, but for xfs -filesystems. - -(cherry picked from commit 57547dcdcfb27bdd988d8a561dc2178ea1d23517) ---- - daemon/daemon.h | 4 ++++ - daemon/labels.c | 6 ++++++ - daemon/xfs.c | 6 ++++++ - 3 files changed, 16 insertions(+) - -diff --git a/daemon/daemon.h b/daemon/daemon.h -index 0ccbc9e..f442efd 100644 ---- a/daemon/daemon.h -+++ b/daemon/daemon.h -@@ -253,6 +253,10 @@ extern void main_loop (int sock) __attribute__((noreturn)); - /*-- in xattr.c --*/ - extern int copy_xattrs (const char *src, const char *dest); - -+/*-- in xfs.c --*/ -+/* Documented in xfs_admin(8). */ -+#define XFS_LABEL_MAX 12 -+ - /* ordinary daemon functions use these to indicate errors - * NB: you don't need to prefix the string with the current command, - * it is added automatically by the client-side RPC stubs. -diff --git a/daemon/labels.c b/daemon/labels.c -index f417c57..cfcb4df 100644 ---- a/daemon/labels.c -+++ b/daemon/labels.c -@@ -118,6 +118,12 @@ xfslabel (const char *device, const char *label) - return -1; - } - -+ if (strlen (label) > XFS_LABEL_MAX) { -+ reply_with_error ("%s: xfs labels are limited to %d bytes", -+ label, XFS_LABEL_MAX); -+ return -1; -+ } -+ - r = command (NULL, &err, str_xfs_admin, "-L", label, device, NULL); - if (r == -1) { - reply_with_error ("%s", err); -diff --git a/daemon/xfs.c b/daemon/xfs.c -index 725f7b3..687013b 100644 ---- a/daemon/xfs.c -+++ b/daemon/xfs.c -@@ -498,6 +498,12 @@ do_xfs_admin (const char *device, - } - - if (optargs_bitmask & GUESTFS_XFS_ADMIN_LABEL_BITMASK) { -+ if (strlen (label) > XFS_LABEL_MAX) { -+ reply_with_error ("%s: xfs labels are limited to %d bytes", -+ label, XFS_LABEL_MAX); -+ return -1; -+ } -+ - ADD_ARG (argv, i, "-L"); - ADD_ARG (argv, i, label); - } --- -1.8.3.1 - diff --git a/SOURCES/0043-rescue-Suggest-using-recursive-bind-mounts.patch b/SOURCES/0043-rescue-Suggest-using-recursive-bind-mounts.patch new file mode 100644 index 0000000..69e3b01 --- /dev/null +++ b/SOURCES/0043-rescue-Suggest-using-recursive-bind-mounts.patch @@ -0,0 +1,35 @@ +From 5c9715d182c95601c63282050ddc9ae1d45a22ac Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 24 Mar 2016 10:46:31 +0000 +Subject: [PATCH] rescue: Suggest using recursive bind mounts. + +Since /dev and other directories contain sub-mounts, suggest using +--rbind instead of --bind. This also allows us to remove the /dev/pts +line. + +(cherry picked from commit 72fd0531ab8446dc00d565cf2f526f5c9bcee968) +--- + rescue/rescue.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/rescue/rescue.c b/rescue/rescue.c +index 08c8062..16028a7 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -461,10 +461,9 @@ do_suggestion (struct drv *drvs) + + /* If it's Linux, print the bind-mounts. */ + if (type && STREQ (type, "linux")) { +- printf ("mount --bind /dev /sysroot/dev\n"); +- printf ("mount --bind /dev/pts /sysroot/dev/pts\n"); +- printf ("mount --bind /proc /sysroot/proc\n"); +- printf ("mount --bind /sys /sysroot/sys\n"); ++ printf ("mount --rbind /dev /sysroot/dev\n"); ++ printf ("mount --rbind /proc /sysroot/proc\n"); ++ printf ("mount --rbind /sys /sysroot/sys\n"); + } + + printf ("\n"); +-- +1.8.3.1 + diff --git a/SOURCES/0044-inspection-Get-icons-from-RHEL-and-CentOS-7-RHBZ-116.patch b/SOURCES/0044-inspection-Get-icons-from-RHEL-and-CentOS-7-RHBZ-116.patch deleted file mode 100644 index 787226b..0000000 --- a/SOURCES/0044-inspection-Get-icons-from-RHEL-and-CentOS-7-RHBZ-116.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 82cac591adf3549b42390230816cc525962b4519 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 17 Nov 2014 10:25:33 +0000 -Subject: [PATCH] inspection: Get icons from RHEL and CentOS 7 (RHBZ#1164619). - -(cherry picked from commit c8a608ecf8576bb754749db982714fa35cedfbe4) ---- - src/inspect-icon.c | 22 +++++++++++++--------- - 1 file changed, 13 insertions(+), 9 deletions(-) - -diff --git a/src/inspect-icon.c b/src/inspect-icon.c -index 0ffca72..4f10dfb 100644 ---- a/src/inspect-icon.c -+++ b/src/inspect-icon.c -@@ -303,24 +303,28 @@ icon_fedora (guestfs_h *g, struct inspect_fs *fs, size_t *size_r) - * RHEL 5, 6: - * As above, but the file has been optimized to about 16K. - * -+ * In RHEL 7 the logos were completely broken (RHBZ#1063300). -+ * - * Conveniently the RHEL clones also have the same file with the - * same name, but containing their own logos. Sense prevails! - */ --#define SHADOWMAN_ICON "/usr/share/pixmaps/redhat/shadowman-transparent.png" -- - static char * - icon_rhel (guestfs_h *g, struct inspect_fs *fs, size_t *size_r) - { - size_t max_size = 0; -+ const char *shadowman; - -- if (fs->distro == OS_DISTRO_RHEL) { -- if (fs->major_version <= 4) -- max_size = 66000; -- else -- max_size = 17000; -- } -+ if (fs->major_version >= 5 && fs->major_version <= 6) -+ max_size = 17000; -+ else -+ max_size = 66000; - -- return get_png (g, fs, SHADOWMAN_ICON, size_r, max_size); -+ if (fs->major_version <= 6) -+ shadowman = "/usr/share/pixmaps/redhat/shadowman-transparent.png"; -+ else -+ shadowman = "/usr/share/pixmaps/fedora-logo-sprite.png"; -+ -+ return get_png (g, fs, shadowman, size_r, max_size); - } - - #define DEBIAN_ICON "/usr/share/pixmaps/debian-logo.png" --- -1.8.3.1 - diff --git a/SOURCES/0044-rescue-Print-chroot-suggestion-for-Linux-guests.patch b/SOURCES/0044-rescue-Print-chroot-suggestion-for-Linux-guests.patch new file mode 100644 index 0000000..3633323 --- /dev/null +++ b/SOURCES/0044-rescue-Print-chroot-suggestion-for-Linux-guests.patch @@ -0,0 +1,33 @@ +From f1f0123903cb2cfa66832284ca25424e903883f2 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 24 Mar 2016 10:48:03 +0000 +Subject: [PATCH] rescue: Print chroot suggestion for Linux guests. + +(cherry picked from commit a5507a16c68b6ee56258d44087b4e4529290934a) +--- + rescue/rescue.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/rescue/rescue.c b/rescue/rescue.c +index 16028a7..982f3c4 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -459,11 +459,14 @@ do_suggestion (struct drv *drvs) + 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. */ ++ /* 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"); +-- +1.8.3.1 + diff --git a/SOURCES/0045-inspection-Allow-etc-favicon.png-to-be-a-symbolic-li.patch b/SOURCES/0045-inspection-Allow-etc-favicon.png-to-be-a-symbolic-li.patch deleted file mode 100644 index 855f452..0000000 --- a/SOURCES/0045-inspection-Allow-etc-favicon.png-to-be-a-symbolic-li.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 9b73cc026b38e871ffd13892c6e9fe878ae47b07 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 17 Nov 2014 10:33:35 +0000 -Subject: [PATCH] inspection: Allow /etc/favicon.png to be a symbolic link - (RHBZ#1164619). - -If /etc/favicon.png is a symbolic link, follow it. - -Unfortunately RHEL 7 and Fedora have crappy 16x16 /etc/favicon.png -symlinks in the base distro. It would be nice to ignore this symlink, -but it's almost impossible to determine if the symlink is part of the -base distro or was added by the user. (This is a bug in those -distros.) virt-inspector and virt-mananger both ignore favicons. - -(cherry picked from commit 42391913287d935e582b0c67571a17e657aa8e2e) ---- - inspector/inspector.c | 4 +++- - src/inspect-icon.c | 12 ++++++++++-- - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/inspector/inspector.c b/inspector/inspector.c -index 8b2e578..71795ce 100644 ---- a/inspector/inspector.c -+++ b/inspector/inspector.c -@@ -480,7 +480,9 @@ output_root (xmlTextWriterPtr xo, char *root) - - output_applications (xo, root); - -- /* Don't return favicon. XXX Should we? */ -+ /* Don't return favicon. RHEL 7 and Fedora have crappy 16x16 -+ * favicons in the base distro. -+ */ - str = guestfs_inspect_get_icon (g, root, &size, - GUESTFS_INSPECT_GET_ICON_FAVICON, 0, - -1); -diff --git a/src/inspect-icon.c b/src/inspect-icon.c -index 4f10dfb..72d4bba 100644 ---- a/src/inspect-icon.c -+++ b/src/inspect-icon.c -@@ -223,6 +223,7 @@ get_png (guestfs_h *g, struct inspect_fs *fs, const char *filename, - size_t *size_r, size_t max_size) - { - char *ret; -+ CLEANUP_FREE char *real = NULL; - CLEANUP_FREE char *type = NULL; - CLEANUP_FREE char *local = NULL; - int r, w, h; -@@ -234,8 +235,15 @@ get_png (guestfs_h *g, struct inspect_fs *fs, const char *filename, - if (r == 0) - return NOT_FOUND; - -+ /* Resolve the path, in case it's a symbolic link (as in RHEL 7). */ -+ guestfs_push_error_handler (g, NULL, NULL); -+ real = guestfs_realpath (g, filename); -+ guestfs_pop_error_handler (g); -+ if (real == NULL) -+ return NOT_FOUND; /* could just be a broken link */ -+ - /* Check the file type and geometry. */ -- type = guestfs_file (g, filename); -+ type = guestfs_file (g, real); - if (!type) - return NOT_FOUND; - -@@ -252,7 +260,7 @@ get_png (guestfs_h *g, struct inspect_fs *fs, const char *filename, - if (max_size == 0) - max_size = 4 * w * h; - -- local = guestfs___download_to_tmp (g, fs, filename, "icon", max_size); -+ local = guestfs___download_to_tmp (g, fs, real, "icon", max_size); - if (!local) - return NOT_FOUND; - --- -1.8.3.1 - diff --git a/SOURCES/0045-rescue-Fix-test-to-deal-with-new-suggest-output.patch b/SOURCES/0045-rescue-Fix-test-to-deal-with-new-suggest-output.patch new file mode 100644 index 0000000..e8b9433 --- /dev/null +++ b/SOURCES/0045-rescue-Fix-test-to-deal-with-new-suggest-output.patch @@ -0,0 +1,33 @@ +From 74c5a924edaf9abdb1f6998658d2035f3c9496a8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 24 Mar 2016 17:58:42 +0000 +Subject: [PATCH] rescue: Fix test to deal with new --suggest output. + +Fixed commit 72fd0531ab8446dc00d565cf2f526f5c9bcee968. + +(cherry picked from commit c3fb5deab693c0e193a684f7aba21785a8795828) +--- + rescue/test-virt-rescue-suggest.sh | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/rescue/test-virt-rescue-suggest.sh b/rescue/test-virt-rescue-suggest.sh +index e3cb59d..a8b41e2 100755 +--- a/rescue/test-virt-rescue-suggest.sh ++++ b/rescue/test-virt-rescue-suggest.sh +@@ -34,10 +34,9 @@ $VG virt-rescue --suggest --format=raw -a "$guest" | + + if [ "$(cat virt-rescue-suggest.out)" != "mount /dev/VG/Root /sysroot/ + mount /dev/sda1 /sysroot/boot +-mount --bind /dev /sysroot/dev +-mount --bind /dev/pts /sysroot/dev/pts +-mount --bind /proc /sysroot/proc +-mount --bind /sys /sysroot/sys" ]; then ++mount --rbind /dev /sysroot/dev ++mount --rbind /proc /sysroot/proc ++mount --rbind /sys /sysroot/sys" ]; then + echo "$0: unexpected output from virt-rescue --suggest command:" + cat virt-rescue-suggest.out + exit 1 +-- +1.8.3.1 + diff --git a/SOURCES/0046-Fix-description-of-set_append-and-get_append-APIs-RH.patch b/SOURCES/0046-Fix-description-of-set_append-and-get_append-APIs-RH.patch deleted file mode 100644 index 0f24c54..0000000 --- a/SOURCES/0046-Fix-description-of-set_append-and-get_append-APIs-RH.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7d87f9e4a5e9e8a77a4750cec9c5fa7618e3aca1 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 17 Nov 2014 10:07:28 +0000 -Subject: [PATCH] Fix description of 'set_append' and 'get_append' APIs - (RHBZ#1164732). - -These should refer to the libguestfs appliance kernel command -line, not the guest kernel command line. - -Thanks: Lingfei Kong -(cherry picked from commit 6dd371f913332a840b34ad00d52e9fa52711fb0e) ---- - generator/actions.ml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/generator/actions.ml b/generator/actions.ml -index 4cfba0d..593e51b 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -398,7 +398,7 @@ return the default path." }; - shortdesc = "add options to kernel command line"; - longdesc = "\ - This function is used to add additional options to the --guest kernel command line. -+libguestfs appliance kernel command line. - - The default is C unless overridden by setting - C environment variable. -@@ -417,7 +417,7 @@ are passed (libguestfs always adds a few of its own)." }; - shortdesc = "get the additional kernel options"; - longdesc = "\ - Return the additional kernel options which are added to the --guest kernel command line. -+libguestfs appliance kernel command line. - - If C then no options are added." }; - --- -1.8.3.1 - diff --git a/SOURCES/0046-boot-analysis-Add-memsize-smp-and-append-options.patch b/SOURCES/0046-boot-analysis-Add-memsize-smp-and-append-options.patch new file mode 100644 index 0000000..b974b4d --- /dev/null +++ b/SOURCES/0046-boot-analysis-Add-memsize-smp-and-append-options.patch @@ -0,0 +1,158 @@ +From 66292c8c5f8b35ac5ce198cdc6996ba5c0cb3741 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 29 Mar 2016 11:59:36 +0100 +Subject: [PATCH] boot-analysis: Add --memsize, --smp and --append options. + +These options allow you to control the appliance memory size, number +of vCPUs, and extra kernel options respectively. + +Note that using --smp is not usually a good idea. Not only does it +slow down the appliance, but it tends to break the boot analysis +program because it makes runs (more) non-deterministic. + +(cherry picked from commit da7e22b648ce470980c17943efcc0c5c255c33bf) +--- + tests/qemu/boot-analysis.c | 72 ++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 63 insertions(+), 9 deletions(-) + +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index 71b265a..fc2c93b 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -89,7 +89,10 @@ struct pass_data pass_data[NR_TEST_PASSES]; + size_t nr_activities; + struct activity *activities; + ++static const char *append = NULL; + static int force_colour = 0; ++static int memsize = 0; ++static int smp = 1; + static int verbose = 0; + + static void run_test (void); +@@ -117,14 +120,28 @@ static void ansi_restore (void); + static void + usage (int exitcode) + { ++ guestfs_h *g; ++ int default_memsize = -1; ++ ++ g = guestfs_create (); ++ if (g) { ++ default_memsize = guestfs_get_memsize (g); ++ guestfs_close (g); ++ } ++ + fprintf (stderr, + "boot-analysis: Trace and analyze the appliance boot process.\n" + "Usage:\n" + " boot-analysis [--options]\n" + "Options:\n" +- " --help Display this usage text and exit.\n" +- " --colour Output colours, even if not a terminal.\n" +- " -v|--verbose Verbose output, useful for debugging.\n"); ++ " --help Display this usage text and exit.\n" ++ " --append OPTS Append OPTS to kernel command line.\n" ++ " --colour Output colours, even if not a terminal.\n" ++ " -m MB\n" ++ " --memsize MB Set memory size in MB (default: %d).\n" ++ " --smp N Enable N virtual CPUs (default: 1).\n" ++ " -v|--verbose Verbose output, useful for debugging.\n", ++ default_memsize); + exit (exitcode); + } + +@@ -132,11 +149,14 @@ int + main (int argc, char *argv[]) + { + enum { HELP_OPTION = CHAR_MAX + 1 }; +- static const char *options = "v"; ++ static const char *options = "m:v"; + static const struct option long_options[] = { + { "help", 0, 0, HELP_OPTION }, ++ { "append", 1, 0, 0 }, + { "color", 0, 0, 0 }, + { "colour", 0, 0, 0 }, ++ { "memsize", 1, 0, 'm' }, ++ { "smp", 1, 0, 0 }, + { "verbose", 0, 0, 'v' }, + { 0, 0, 0, 0 } + }; +@@ -148,15 +168,35 @@ main (int argc, char *argv[]) + + switch (c) { + case 0: /* Options which are long only. */ +- if (STREQ (long_options[option_index].name, "color") || +- STREQ (long_options[option_index].name, "colour")) { ++ if (STREQ (long_options[option_index].name, "append")) { ++ append = optarg; ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "color") || ++ STREQ (long_options[option_index].name, "colour")) { + force_colour = 1; + break; + } ++ else if (STREQ (long_options[option_index].name, "smp")) { ++ if (sscanf (optarg, "%d", &smp) != 1) { ++ fprintf (stderr, "%s: could not parse smp parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ } + fprintf (stderr, "%s: unknown long option: %s (%d)\n", + guestfs_int_program_name, long_options[option_index].name, option_index); + exit (EXIT_FAILURE); + ++ case 'm': ++ if (sscanf (optarg, "%d", &memsize) != 1) { ++ fprintf (stderr, "%s: could not parse memsize parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ + case 'v': + verbose = 1; + break; +@@ -267,6 +307,7 @@ static guestfs_h * + create_handle (void) + { + guestfs_h *g; ++ CLEANUP_FREE char *full_append = NULL; + + g = guestfs_create (); + if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); +@@ -279,12 +320,25 @@ create_handle (void) + if (guestfs_set_backend (g, "direct") == -1) + exit (EXIT_FAILURE); + ++ if (memsize != 0) ++ if (guestfs_set_memsize (g, memsize) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (smp >= 2) ++ if (guestfs_set_smp (g, smp) == -1) ++ exit (EXIT_FAILURE); ++ + /* This changes some details in appliance/init and enables a + * detailed trace of calls to initcall functions in the kernel. + */ +- if (guestfs_set_append (g, +- "guestfs_boot_analysis=1 " +- "ignore_loglevel initcall_debug") == -1) ++ if (asprintf (&full_append, ++ "guestfs_boot_analysis=1 " ++ "ignore_loglevel initcall_debug " ++ "%s", ++ append != NULL ? append : "") == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ if (guestfs_set_append (g, full_append) == -1) + exit (EXIT_FAILURE); + + return g; +-- +1.8.3.1 + diff --git a/SOURCES/0047-Fix-minor-typo-in-release-notes-RHBZ-1164697.patch b/SOURCES/0047-Fix-minor-typo-in-release-notes-RHBZ-1164697.patch deleted file mode 100644 index bdefb82..0000000 --- a/SOURCES/0047-Fix-minor-typo-in-release-notes-RHBZ-1164697.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 29ea861fd1b10c2ce3cc9e44de2d61fdc0346882 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 17 Nov 2014 09:31:55 +0000 -Subject: [PATCH] Fix minor typo in release notes (RHBZ#1164697). - -(cherry picked from commit 88f2bc1a7bf769424fc219dae925a70a04b19294) ---- - guestfs-release-notes.pod | 2 +- - guestfs-release-notes.txt | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/guestfs-release-notes.pod b/guestfs-release-notes.pod -index 87df533..3f85e2b 100644 ---- a/guestfs-release-notes.pod -+++ b/guestfs-release-notes.pod -@@ -338,7 +338,7 @@ Illegal command 'part-get-name /dev/sda1 1' cause libguestfs appliance crashed - - =item L - --virt-v2v prints waring:WARNING:/files/boot/grub/device.map references unknown device "xvda" -+virt-v2v prints warning:WARNING:/files/boot/grub/device.map references unknown device "xvda" - - =item L - -diff --git a/guestfs-release-notes.txt b/guestfs-release-notes.txt -index 03178aa..6778537 100644 ---- a/guestfs-release-notes.txt -+++ b/guestfs-release-notes.txt -@@ -322,8 +322,8 @@ RELEASE NOTES FOR LIBGUESTFS 1.28 - - https://bugzilla.redhat.com/1142004 - -- virt-v2v prints waring:WARNING:/files/boot/grub/device.map references -- unknown device "xvda" -+ virt-v2v prints warning:WARNING:/files/boot/grub/device.map -+ references unknown device "xvda" - - https://bugzilla.redhat.com/1141723 - --- -1.8.3.1 - diff --git a/SOURCES/0047-appliance-init-generate-etc-machine-id.patch b/SOURCES/0047-appliance-init-generate-etc-machine-id.patch new file mode 100644 index 0000000..8acb68a --- /dev/null +++ b/SOURCES/0047-appliance-init-generate-etc-machine-id.patch @@ -0,0 +1,38 @@ +From f7e32e558df19e875ecb5424903923160ed2da1c Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 30 Mar 2016 10:15:49 +0200 +Subject: [PATCH] appliance: init: generate /etc/machine-id + +Some of the systemd-tmpfiles snippets need the machine ID of the running +system; the current lack of this file produces warning messages during +the appliance boot like: + +[/usr/lib/tmpfiles.d/systemd.conf:26] Failed to replace specifiers: /run/log/journal/%m +[/usr/lib/tmpfiles.d/systemd.conf:28] Failed to replace specifiers: /run/log/journal/%m +[/usr/lib/tmpfiles.d/systemd.conf:29] Failed to replace specifiers: /run/log/journal/%m + +Thus create a new randomly-generated /etc/machine-id on boot. + +(cherry picked from commit 807433bc230987270680ad28643e9c1741790c29) +--- + appliance/init | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/appliance/init b/appliance/init +index 4a04bce..b05c0ed 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -87,6 +87,10 @@ fi + mkdir -p /run/tmpfiles.d + kmod static-nodes --format=tmpfiles --output=/run/tmpfiles.d/kmod.conf + ++# Create a machine-id with a random UUID ++machine_id=$(dd if=/dev/urandom bs=16 count=1 status=none | od -x -A n) ++echo "${machine_id// /}" > /etc/machine-id ++ + # Set up tmpfiles (must run after kmod.conf is created above). + systemd-tmpfiles --prefix=/dev --create --boot + +-- +1.8.3.1 + diff --git a/SOURCES/0048-launch-direct-Add-a-comment-about-use-of-display-non.patch b/SOURCES/0048-launch-direct-Add-a-comment-about-use-of-display-non.patch new file mode 100644 index 0000000..95be665 --- /dev/null +++ b/SOURCES/0048-launch-direct-Add-a-comment-about-use-of-display-non.patch @@ -0,0 +1,27 @@ +From 9c51d502dee18a07950fac664773993bcc2350af Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 1 Apr 2016 10:01:32 +0100 +Subject: [PATCH] launch: direct: Add a comment about use of -display none. + +No functional change. + +(cherry picked from commit 77e1ac5a9737d2bc6fc963baa2c2c8f1b8f1b92d) +--- + src/launch-direct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/launch-direct.c b/src/launch-direct.c +index 25c97a7..92b45fd 100644 +--- a/src/launch-direct.c ++++ b/src/launch-direct.c +@@ -376,6 +376,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + if (qemu_supports (g, data, "-nodefaults")) + ADD_CMDLINE ("-nodefaults"); + ++ /* This disables the host-side display (SDL, Gtk). */ + ADD_CMDLINE ("-display"); + ADD_CMDLINE ("none"); + +-- +1.8.3.1 + diff --git a/SOURCES/0048-v2v-i-ova-XML-is-case-sensitive-so-replace-InstanceI.patch b/SOURCES/0048-v2v-i-ova-XML-is-case-sensitive-so-replace-InstanceI.patch deleted file mode 100644 index a7536c4..0000000 --- a/SOURCES/0048-v2v-i-ova-XML-is-case-sensitive-so-replace-InstanceI.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 4ce3c8f8c9ce120dfe580402fe82663dc8d14f9a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 18 Nov 2014 12:35:38 +0000 -Subject: [PATCH] v2v: -i ova: XML is case-sensitive, so replace 'InstanceId' - with 'InstanceID'. - -(cherry picked from commit 78f6d3aff59ab0a539b8f2a90b88a2b6f7c994f6) ---- - v2v/input_ova.ml | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index d9928de..836b24e 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -171,9 +171,11 @@ object - Xml.xpathctx_set_current_context xpathctx n; - let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in - let parent_id = xpath_to_int "rasd:Parent/text()" 0 in -- (* Probably the parent controller. *) -- let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceId/text()=%d]/rasd:ResourceType/text()" parent_id in -+ -+ (* Find the parent controller. *) -+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceID/text()=%d]/rasd:ResourceType/text()" parent_id in - let controller = xpath_to_int expr 0 in -+ - (* 6: iscsi controller, 5: ide. assuming scsi or ide *) - let target_dev = - match controller with -@@ -243,9 +245,11 @@ object - assert (id = 14 || id = 15 || id = 16); - let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in - let parent_id = xpath_to_int "rasd:Parent/text()" 0 in -- (* Probably the parent controller. *) -- let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceId/text()=%d]/rasd:ResourceType/text()" parent_id in -+ -+ (* Find the parent controller. *) -+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceID/text()=%d]/rasd:ResourceType/text()" parent_id in - let controller = xpath_to_int expr 0 in -+ - (* 6: iscsi controller, 5: ide. assuming scsi or ide *) - let target_dev = - match controller with --- -1.8.3.1 - diff --git a/SOURCES/0049-launch-Only-use-sgabios-when-verbose-is-enabled.patch b/SOURCES/0049-launch-Only-use-sgabios-when-verbose-is-enabled.patch new file mode 100644 index 0000000..69b53ea --- /dev/null +++ b/SOURCES/0049-launch-Only-use-sgabios-when-verbose-is-enabled.patch @@ -0,0 +1,50 @@ +From 43c9804c2b433687b6ed31288be50d91d881c74a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 1 Apr 2016 10:05:59 +0100 +Subject: [PATCH] launch: Only use sgabios when verbose is enabled. + +The sgabios option ROM is slow. Only use it when we're debugging. + +Thanks: Paolo Bonzini. +(cherry picked from commit 6c99a17dc56ab0479b439dece549c89960b21ccc) +--- + src/launch-direct.c | 3 ++- + src/launch-libvirt.c | 8 +++++--- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/launch-direct.c b/src/launch-direct.c +index 92b45fd..1081445 100644 +--- a/src/launch-direct.c ++++ b/src/launch-direct.c +@@ -591,7 +591,8 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + ADD_CMDLINE ("-serial"); + ADD_CMDLINE ("stdio"); + +- if (qemu_supports_device (g, data, "Serial Graphics Adapter")) { ++ if (g->verbose && ++ qemu_supports_device (g, data, "Serial Graphics Adapter")) { + /* Use sgabios instead of vgabios. This means we'll see BIOS + * messages on the serial port, and also works around this bug + * in qemu 1.1.0: +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index 3df1833..f9edac0 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -1219,9 +1219,11 @@ construct_libvirt_xml_boot (guestfs_h *g, + } end_element (); + + #if defined(__i386__) || defined(__x86_64__) +- start_element ("bios") { +- attribute ("useserial", "yes"); +- } end_element (); ++ if (g->verbose) { ++ start_element ("bios") { ++ attribute ("useserial", "yes"); ++ } end_element (); ++ } + #endif + + } end_element (); +-- +1.8.3.1 + diff --git a/SOURCES/0049-v2v-Remove-useless-parentheses-around-expression.patch b/SOURCES/0049-v2v-Remove-useless-parentheses-around-expression.patch deleted file mode 100644 index 54190ba..0000000 --- a/SOURCES/0049-v2v-Remove-useless-parentheses-around-expression.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0b0d434a1b3563308fa0ec3724aaffe9516df452 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Oct 2014 13:47:23 +0000 -Subject: [PATCH] v2v: Remove useless parentheses around expression. - -(cherry picked from commit d82c5fb5a0c86345891ee191ae7d820361978643) ---- - v2v/input_libvirtxml.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index c71260f..f302b2c 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -170,7 +170,7 @@ let parse_libvirt_xml ~verbose xml = - * XXX Quoting, although it's not needed for virt-p2v. - *) - let path = sprintf "nbd:%s:%d" host port in -- add_disk path format target_dev (P_dont_rewrite) -+ add_disk path format target_dev P_dont_rewrite - ) - | "" -> () - | protocol -> --- -1.8.3.1 - diff --git a/SOURCES/0050-launch-Add-a-comment-about-why-acpi-off-because-it-s.patch b/SOURCES/0050-launch-Add-a-comment-about-why-acpi-off-because-it-s.patch new file mode 100644 index 0000000..29e9e69 --- /dev/null +++ b/SOURCES/0050-launch-Add-a-comment-about-why-acpi-off-because-it-s.patch @@ -0,0 +1,26 @@ +From 45589f477baba375e3a5caa39dea4526b0fe7cbf Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 1 Apr 2016 12:28:18 +0100 +Subject: [PATCH] launch: Add a comment about why acpi=off (because it's slow). + +(cherry picked from commit 2cc8a4c1ff2bca9df39db3401ffefaf1b603954c) +--- + src/launch.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/launch.c b/src/launch.c +index 0eb7d18..98eca07 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -336,7 +336,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + " udev.event-timeout=6000" /* for newer udevd */ + " no_timer_check" /* fix for RHBZ#502058 */ + "%s" /* lpj */ +- " acpi=off" /* we don't need ACPI, turn it off */ ++ " acpi=off" /* ACPI is slow - 150-200ms extra on my laptop */ + " printk.time=1" /* display timestamp before kernel messages */ + " cgroup_disable=memory" /* saves us about 5 MB of RAM */ + "%s" /* root=appliance_dev */ +-- +1.8.3.1 + diff --git a/SOURCES/0050-v2v-Don-t-use-target-dev-attribute-use-target-bus-in.patch b/SOURCES/0050-v2v-Don-t-use-target-dev-attribute-use-target-bus-in.patch deleted file mode 100644 index 8543aae..0000000 --- a/SOURCES/0050-v2v-Don-t-use-target-dev-attribute-use-target-bus-in.patch +++ /dev/null @@ -1,472 +0,0 @@ -From 645d7534bdd8947e22126f6033dbd329f1f9c59e Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 18 Nov 2014 13:07:42 +0000 -Subject: [PATCH] v2v: Don't use attribute, use - instead. - -The attribute in libvirt isn't very informative. What we -really want to know is whether the source disk used IDE or SCSI, as -that allows us to remap block devices accurately during conversion. -For example, if the source was IDE and RHEL 5, and after conversion -virtio will be supported, then we know that we need to remap -"/dev/hda" to "/dev/vda". - -Drop the s_target_dev and s_removable_target_dev fields and replace -them with s_controller and s_removable_controller. - -For -i libvirt, use the attribute to get this information. - -For -i ova, use the OVF disk controller's ResourceType. -(http://blogs.vmware.com/vapp/2009/11/virtual-hardware-in-ovf-part-1.html) - -(cherry picked from commit 9ebc12572317efe5c1ae83fcb61c7767dec40203) ---- - p2v/conversion.c | 1 + - v2v/convert_linux.ml | 43 ++++++++++++++++------------ - v2v/input_disk.ml | 2 +- - v2v/input_libvirtxml.ml | 34 ++++++++++++++-------- - v2v/input_ova.ml | 54 +++++++++++++++++++---------------- - v2v/output_libvirt.ml | 2 +- - v2v/test-v2v-i-ova-gz.expected | 4 +-- - v2v/test-v2v-i-ova-two-disks.expected | 6 ++-- - v2v/test-v2v-i-ova-zip.expected | 4 +-- - v2v/test-v2v-print-source.sh | 2 +- - v2v/types.ml | 22 ++++++++------ - v2v/types.mli | 11 +++++-- - 12 files changed, 111 insertions(+), 74 deletions(-) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index 26074b6..6f414de 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -561,6 +561,7 @@ generate_libvirt_xml (struct config *config, struct data_conn *data_conns) - } end_element (); - start_element ("target") { - attribute ("dev", target_dev); -+ /* XXX Need to set bus to "ide" or "scsi" here. */ - } end_element (); - } end_element (); - } -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index b6335d9..48f351c 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1219,26 +1219,33 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - * particular it assumes all non-removable source disks will be - * added to the target in the order they appear in the libvirt XML. - *) -- let block_prefix = -- if virtio then "vd" -- else -- match family, inspect.i_major_version with -- | `RHEL_family, v when v < 5 -> -- (* RHEL < 5 used old ide driver *) "hd" -- | `RHEL_family, 5 -> -- (* RHEL 5 uses libata, but udev still uses: *) "hd" -- | `SUSE_family, _ -> -- (* SUSE uses libata, but still presents IDE disks as: *) "hd" -- | _, _ -> -- (* All modern distros use libata: *) "sd" in -+ let ide_block_prefix = -+ match family, inspect.i_major_version with -+ | `RHEL_family, v when v < 5 -> -+ (* RHEL < 5 used old ide driver *) "hd" -+ | `RHEL_family, 5 -> -+ (* RHEL 5 uses libata, but udev still uses: *) "hd" -+ | `SUSE_family, _ -> -+ (* SUSE uses libata, but still presents IDE disks as: *) "hd" -+ | _, _ -> -+ (* All modern distros use libata: *) "sd" in -+ -+ let block_prefix_after_conversion = -+ if virtio then "vd" else ide_block_prefix in -+ - let map = - mapi ( - fun i disk -> -- let source_dev = -- match disk.s_target_dev with (* target/@dev in _source_ HV *) -- | Some dev -> dev -- | None -> (* ummm, what? *) block_prefix ^ drive_name i in -- let target_dev = block_prefix ^ drive_name i in -+ let block_prefix_before_conversion = -+ match disk.s_controller with -+ | Some `IDE -> ide_block_prefix -+ | Some `SCSI -> "sd" -+ | Some `Virtio_blk -> "vd" -+ | None -> -+ (* This is basically a guess. It assumes the source used IDE. *) -+ ide_block_prefix in -+ let source_dev = block_prefix_before_conversion ^ drive_name i in -+ let target_dev = block_prefix_after_conversion ^ drive_name i in - source_dev, target_dev - ) source.s_disks in - -@@ -1253,7 +1260,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - let map = map @ - mapi ( - fun i disk -> -- "xvd" ^ drive_name i, block_prefix ^ drive_name i -+ "xvd" ^ drive_name i, block_prefix_after_conversion ^ drive_name i - ) source.s_disks in - - (* Possible Augeas paths to search for device names. *) -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index ef28b43..8393786 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -69,7 +69,7 @@ class input_disk verbose input_format disk = object - s_disk_id = 0; - s_qemu_uri = disk_absolute; - s_format = Some format; -- s_target_dev = None; -+ s_controller = None; - } in - - (* Give the guest a simple generic network interface. *) -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index f302b2c..d1146f9 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -114,12 +114,12 @@ let parse_libvirt_xml ~verbose xml = - let get_disks, add_disk = - let disks = ref [] and i = ref 0 in - let get_disks () = List.rev !disks in -- let add_disk qemu_uri format target_dev p_source = -+ let add_disk qemu_uri format controller p_source = - incr i; - disks := - { p_source_disk = { s_disk_id = !i; - s_qemu_uri = qemu_uri; s_format = format; -- s_target_dev = target_dev }; -+ s_controller = controller }; - p_source = p_source } :: !disks - in - get_disks, add_disk -@@ -134,9 +134,14 @@ let parse_libvirt_xml ~verbose xml = - let node = Xml.xpathobj_node doc obj i in - Xml.xpathctx_set_current_context xpathctx node; - -- let target_dev = -- let target_dev = xpath_to_string "target/@dev" "" in -- if target_dev <> "" then Some target_dev else None in -+ let controller = -+ let target_bus = xpath_to_string "target/@bus" "" in -+ match target_bus with -+ | "" -> None -+ | "ide" -> Some `IDE -+ | "scsi" -> Some `SCSI -+ | "virtio" -> Some `Virtio_blk -+ | _ -> None in - - let format = - match xpath_to_string "driver/@type" "" with -@@ -151,11 +156,11 @@ let parse_libvirt_xml ~verbose xml = - | "block" -> - let path = xpath_to_string "source/@dev" "" in - if path <> "" then -- add_disk path format target_dev (P_source_dev path) -+ add_disk path format controller (P_source_dev path) - | "file" -> - let path = xpath_to_string "source/@file" "" in - if path <> "" then -- add_disk path format target_dev (P_source_file path) -+ add_disk path format controller (P_source_file path) - | "network" -> - (* We only handle here, and that is - * intended only for virt-p2v. Any other network disk is -@@ -170,7 +175,7 @@ let parse_libvirt_xml ~verbose xml = - * XXX Quoting, although it's not needed for virt-p2v. - *) - let path = sprintf "nbd:%s:%d" host port in -- add_disk path format target_dev P_dont_rewrite -+ add_disk path format controller P_dont_rewrite - ) - | "" -> () - | protocol -> -@@ -193,9 +198,14 @@ let parse_libvirt_xml ~verbose xml = - let node = Xml.xpathobj_node doc obj i in - Xml.xpathctx_set_current_context xpathctx node; - -- let target_dev = -- let target_dev = xpath_to_string "target/@dev" "" in -- if target_dev <> "" then Some target_dev else None in -+ let controller = -+ let target_bus = xpath_to_string "target/@bus" "" in -+ match target_bus with -+ | "" -> None -+ | "ide" -> Some `IDE -+ | "scsi" -> Some `SCSI -+ | "virtio" -> Some `Virtio_blk -+ | _ -> None in - - let typ = - match xpath_to_string "@device" "" with -@@ -204,7 +214,7 @@ let parse_libvirt_xml ~verbose xml = - | _ -> assert false (* libxml2 error? *) in - - let disk = -- { s_removable_type = typ; s_removable_target_dev = target_dev } in -+ { s_removable_type = typ; s_removable_controller = controller } in - disks := disk :: !disks - done; - List.rev !disks in -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 836b24e..fe71039 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -160,6 +160,24 @@ object - (* Search for number of vCPUs. *) - let vcpu = xpath_to_int "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=3]/rasd:VirtualQuantity/text()" 1 in - -+ (* Helper function to return the parent controller of a disk. *) -+ let parent_controller id = -+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceID/text()=%d]/rasd:ResourceType/text()" id in -+ let controller = xpath_to_int expr 0 in -+ -+ (* 6: iscsi controller, 5: ide *) -+ match controller with -+ | 6 -> Some `SCSI -+ | 5 -> Some `IDE -+ | 0 -> -+ warning ~prog (f_"ova hard disk has no parent controller, please report this as a bug supplying the *.ovf file extracted from the ova"); -+ None -+ | _ -> -+ warning ~prog (f_"ova hard disk has an unknown VMware controller type (%d), please report this as a bug supplying the *.ovf file extracted from the ova") -+ controller; -+ None -+ in -+ - (* Hard disks (ResourceType = 17). *) - let disks = ref [] in - let () = -@@ -169,20 +187,14 @@ object - for i = 0 to nr_nodes-1 do - let n = Xml.xpathobj_node doc obj i in - Xml.xpathctx_set_current_context xpathctx n; -- let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in - let parent_id = xpath_to_int "rasd:Parent/text()" 0 in - -+ (* XXX We assume the OVF lists these in order. -+ let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in -+ *) -+ - (* Find the parent controller. *) -- let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceID/text()=%d]/rasd:ResourceType/text()" parent_id in -- let controller = xpath_to_int expr 0 in -- -- (* 6: iscsi controller, 5: ide. assuming scsi or ide *) -- let target_dev = -- match controller with -- | 6 -> "sd" -- | 0 | 5 | _ (* XXX floppy should be 'fd'? *) -> "hd" in -- -- let target_dev = target_dev ^ drive_name address in -+ let controller = parent_controller parent_id in - - Xml.xpathctx_set_current_context xpathctx n; - let file_id = xpath_to_string "rasd:HostResource/text()" "" in -@@ -220,7 +232,7 @@ object - s_disk_id = i; - s_qemu_uri = filename; - s_format = Some "vmdk"; -- s_target_dev = Some target_dev; -+ s_controller = controller; - } in - disks := disk :: !disks; - ) else -@@ -243,20 +255,14 @@ object - Xml.xpathctx_set_current_context xpathctx n; - let id = xpath_to_int "rasd:ResourceType/text()" 0 in - assert (id = 14 || id = 15 || id = 16); -- let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in - let parent_id = xpath_to_int "rasd:Parent/text()" 0 in - -+ (* XXX We assume the OVF lists these in order. -+ let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in -+ *) -+ - (* Find the parent controller. *) -- let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceID/text()=%d]/rasd:ResourceType/text()" parent_id in -- let controller = xpath_to_int expr 0 in -- -- (* 6: iscsi controller, 5: ide. assuming scsi or ide *) -- let target_dev = -- match controller with -- | 6 -> "sd" -- | 0 | 5 | _ (* XXX floppy should be 'fd'? *) -> "hd" in -- -- let target_dev = target_dev ^ drive_name address in -+ let controller = parent_controller parent_id in - - let typ = - match id with -@@ -265,7 +271,7 @@ object - | _ -> assert false in - let disk = { - s_removable_type = typ; -- s_removable_target_dev = Some target_dev -+ s_removable_controller = controller; - } in - removables := disk :: !removables; - done in -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index 386d777..a27d3e5 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -146,7 +146,7 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - let removables = - (* CDs will be added as IDE devices if we're using virtio, else - * they will be added as the same as the disk bus. The original -- * s_removable_target_dev is ignored (same as old virt-v2v). -+ * s_removable_controller is ignored (same as old virt-v2v). - *) - let cdrom_bus, cdrom_block_prefix, cdrom_index = - match guestcaps.gcaps_block_bus with -diff --git a/v2v/test-v2v-i-ova-gz.expected b/v2v/test-v2v-i-ova-gz.expected -index 7631534..e605afa 100644 ---- a/v2v/test-v2v-i-ova-gz.expected -+++ b/v2v/test-v2v-i-ova-gz.expected -@@ -7,9 +7,9 @@ hypervisor type: vmware - CPU features: - display: - disks: -- .vmdk (vmdk) [hda] -+ .vmdk (vmdk) [scsi] - removable media: -- CD-ROM [hda] -+ CD-ROM [ide] - NICs: - Network "Network adapter 1" - -diff --git a/v2v/test-v2v-i-ova-two-disks.expected b/v2v/test-v2v-i-ova-two-disks.expected -index f2200d7..cd31898 100644 ---- a/v2v/test-v2v-i-ova-two-disks.expected -+++ b/v2v/test-v2v-i-ova-two-disks.expected -@@ -7,10 +7,10 @@ hypervisor type: vmware - CPU features: - display: - disks: -- disk1.vmdk (vmdk) [hda] -- disk2.vmdk (vmdk) [hdb] -+ disk1.vmdk (vmdk) [scsi] -+ disk2.vmdk (vmdk) [scsi] - removable media: -- CD-ROM [hda] -+ CD-ROM [ide] - NICs: - Network "Network adapter 1" - -diff --git a/v2v/test-v2v-i-ova-zip.expected b/v2v/test-v2v-i-ova-zip.expected -index a835f00..8b3d62c 100644 ---- a/v2v/test-v2v-i-ova-zip.expected -+++ b/v2v/test-v2v-i-ova-zip.expected -@@ -7,9 +7,9 @@ hypervisor type: vmware - CPU features: - display: - disks: -- disk1.vmdk (vmdk) [hda] -+ disk1.vmdk (vmdk) [scsi] - removable media: -- CD-ROM [hda] -+ CD-ROM [ide] - NICs: - Network "Network adapter 1" - -diff --git a/v2v/test-v2v-print-source.sh b/v2v/test-v2v-print-source.sh -index 82b2550..cd32db9 100755 ---- a/v2v/test-v2v-print-source.sh -+++ b/v2v/test-v2v-print-source.sh -@@ -60,7 +60,7 @@ hypervisor type: test - CPU features: - display: - disks: -- /windows.img (raw) [vda] -+ /windows.img (raw) [virtio] - removable media: - NICs:" ]; then - echo "$0: unexpected output from test:" -diff --git a/v2v/types.ml b/v2v/types.ml -index c5a05f6..28d62fc 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -36,11 +36,12 @@ and source_disk = { - s_disk_id : int; - s_qemu_uri : string; - s_format : string option; -- s_target_dev : string option; -+ s_controller : s_controller option; - } -+and s_controller = [`IDE | `SCSI | `Virtio_blk] - and source_removable = { - s_removable_type : [`CDROM|`Floppy]; -- s_removable_target_dev : string option; -+ s_removable_controller : s_controller option; - } - and source_nic = { - s_mac : string option; -@@ -82,23 +83,28 @@ NICs: - (String.concat "\n" (List.map string_of_source_nic s.s_nics)) - - and string_of_source_disk { s_qemu_uri = qemu_uri; s_format = format; -- s_target_dev = target_dev } = -+ s_controller = controller } = - sprintf "\t%s%s%s" - qemu_uri - (match format with - | None -> "" - | Some format -> " (" ^ format ^ ")") -- (match target_dev with -+ (match controller with - | None -> "" -- | Some target_dev -> " [" ^ target_dev ^ "]") -+ | Some controller -> " [" ^ string_of_controller controller ^ "]") -+ -+and string_of_controller = function -+ | `IDE -> "ide" -+ | `SCSI -> "scsi" -+ | `Virtio_blk -> "virtio" - - and string_of_source_removable { s_removable_type = typ; -- s_removable_target_dev = target_dev } = -+ s_removable_controller = controller } = - sprintf "\t%s%s" - (match typ with `CDROM -> "CD-ROM" | `Floppy -> "Floppy") -- (match target_dev with -+ (match controller with - | None -> "" -- | Some target_dev -> " [" ^ target_dev ^ "]") -+ | Some controller -> " [" ^ string_of_controller controller ^ "]") - - and string_of_source_nic { s_mac = mac; s_vnet = vnet; s_vnet_type = typ } = - sprintf "\t%s \"%s\"%s" -diff --git a/v2v/types.mli b/v2v/types.mli -index 2123a41..07eec98 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -38,13 +38,20 @@ and source_disk = { - s_disk_id : int; (** A unique ID for each source disk. *) - s_qemu_uri : string; (** QEMU URI of source disk. *) - s_format : string option; (** Format. *) -- s_target_dev : string option; (** Target @dev from libvirt XML. *) -+ s_controller : s_controller option; (** Controller, eg. IDE, SCSI. *) - } - (** A source disk. *) - -+and s_controller = [`IDE | `SCSI | `Virtio_blk] -+(** Source disk controller. -+ -+ For the purposes of this field, we can treat virtio-scsi as -+ [`SCSI]. However we don't support conversions from virtio in any -+ case so virtio is here only to make it work for testing. *) -+ - and source_removable = { - s_removable_type : [`CDROM|`Floppy]; (** Type. *) -- s_removable_target_dev : string option; (** Target @dev from libvirt XML. *) -+ s_removable_controller : s_controller option; (** Controller, eg. IDE, SCSI.*) - } - (** Removable media. *) - --- -1.8.3.1 - diff --git a/SOURCES/0051-docs-Link-to-boot-analysis-program-from-guestfs-perf.patch b/SOURCES/0051-docs-Link-to-boot-analysis-program-from-guestfs-perf.patch new file mode 100644 index 0000000..9b00034 --- /dev/null +++ b/SOURCES/0051-docs-Link-to-boot-analysis-program-from-guestfs-perf.patch @@ -0,0 +1,61 @@ +From 72a5b6bd7893c5c955a8c4e1957ac9453c71c285 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 1 Apr 2016 17:46:53 +0100 +Subject: [PATCH] docs: Link to boot-analysis program from + guestfs-performance(1). + +(cherry picked from commit 2e04be377a71e9e76d7c8483889a717e9d4f8ec9) +--- + docs/guestfs-performance.pod | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod +index 2a7a4a4..4ba6faf 100644 +--- a/docs/guestfs-performance.pod ++++ b/docs/guestfs-performance.pod +@@ -429,7 +429,23 @@ example). + In Xen, dom0 is a virtual machine, and so hardware virtualization is + not available. + +-=head1 DETAILED TIMINGS USING TS ++=head1 DETAILED ANALYSIS ++ ++=head2 Boot analysis ++ ++In the libguestfs source directory, in F is a program ++called C. This program is able to produce a very ++detailed breakdown of the boot steps (eg. qemu, BIOS, kernel, ++libguestfs init script), and can measure how long it takes to perform ++each step. ++ ++To run this program, do: ++ ++ make ++ make -C tests/qemu boot-analysis ++ ./run ./tests/qemu/boot-analysis ++ ++=head2 Detailed timings using ts + + Use the L command (from moreutils) to show detailed + timings: +@@ -450,7 +466,7 @@ timings: + + The timestamps are seconds (incrementally since the previous line). + +-=head1 DETAILED TIMINGS USING SYSTEMTAP ++=head2 Detailed timings using SystemTap + + You can use SystemTap (L) to get detailed timings from + libguestfs programs. +@@ -516,7 +532,7 @@ example: + You will need to consult, and even modify, the source to libguestfs to + fully understand the output. + +-=head1 DETAILED DEBUGGING USING GDB ++=head2 Detailed debugging using gdb + + You can attach to the appliance BIOS/kernel using gdb. If you know + what you're doing, this can be a useful way to diagnose boot +-- +1.8.3.1 + diff --git a/SOURCES/0051-v2v-Don-t-change-Augeas-device-entries-unless-the-va.patch b/SOURCES/0051-v2v-Don-t-change-Augeas-device-entries-unless-the-va.patch deleted file mode 100644 index 8b79af0..0000000 --- a/SOURCES/0051-v2v-Don-t-change-Augeas-device-entries-unless-the-va.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 1b03fad9aa7e51bb30911af192f0d4eaa859dcc2 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 18 Nov 2014 13:37:21 +0000 -Subject: [PATCH] v2v: Don't change Augeas device entries unless the value has - changed. - -When remapping block devices, don't change an entry unless its value -has changed. This avoids unnecessary Augeas writes. - -(cherry picked from commit 4c7026fb7a7514838a01771abb4c7e62a4e4485f) ---- - v2v/convert_linux.ml | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 48f351c..44b6c7f 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1332,7 +1332,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - fun path -> - let value = g#aug_get path in - -- let value = -+ let new_value = - (* Handle grub2 resume= specially. *) - if string_find path "GRUB_CMDLINE" >= 0 then ( - if Str.string_match rex_resume value 0 then ( -@@ -1346,8 +1346,10 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - ) - else replace_if_device path value in - -- g#aug_set path value; -- changed := true -+ if value <> new_value then ( -+ g#aug_set path new_value; -+ changed := true -+ ) - ) paths; - - if !changed then ( --- -1.8.3.1 - diff --git a/SOURCES/0052-tests-qemu-Add-boot-benchmark.patch b/SOURCES/0052-tests-qemu-Add-boot-benchmark.patch new file mode 100644 index 0000000..5957442 --- /dev/null +++ b/SOURCES/0052-tests-qemu-Add-boot-benchmark.patch @@ -0,0 +1,499 @@ +From 8a9557041411dbb6739fb81c7ea992ef4109aa22 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 1 Apr 2016 19:19:51 +0100 +Subject: [PATCH] tests/qemu: Add boot-benchmark. + +Add a new test program called 'boot-benchmark'. This is similar to +'boot-analysis' but it simply boots and shuts down the appliance +several times in a row and measures how long it takes, calculating +mean and standard deviation. + +(cherry picked from commit 96ce2f9afedc6a7ecb2f7781958c3940255f453b) +--- + .gitignore | 1 + + docs/guestfs-performance.pod | 15 ++- + tests/qemu/Makefile.am | 30 ++++- + tests/qemu/boot-analysis-utils.c | 47 ++++++++ + tests/qemu/boot-analysis-utils.h | 30 +++++ + tests/qemu/boot-analysis.c | 21 +--- + tests/qemu/boot-benchmark.c | 230 +++++++++++++++++++++++++++++++++++++++ + 7 files changed, 346 insertions(+), 28 deletions(-) + create mode 100644 tests/qemu/boot-analysis-utils.c + create mode 100644 tests/qemu/boot-analysis-utils.h + create mode 100644 tests/qemu/boot-benchmark.c + +diff --git a/.gitignore b/.gitignore +index 9c45df7..46a6e65 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -510,6 +510,7 @@ Makefile.in + /tests/parallel/test-parallel + /tests/protocol/test-error-messages + /tests/qemu/boot-analysis ++/tests/qemu/boot-benchmark + /tests/qemu/qemu-boot + /tests/qemu/qemu-speed-test + /tests/regressions/rhbz501893 +diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod +index 4ba6faf..cf30fdc 100644 +--- a/docs/guestfs-performance.pod ++++ b/docs/guestfs-performance.pod +@@ -29,11 +29,20 @@ appliance: + Run this command several times in a row and discard the first few + runs, so that you are measuring a typical "hot cache" case. + ++I If you are compiling libguestfs from ++source, there is a program called F which ++does the same thing, but performs multiple runs and prints the mean ++and standard deviation. To run it, do: ++ ++ make ++ make -C tests/qemu boot-benchmark ++ ./run ./tests/qemu/boot-benchmark ++ + =head3 Explanation + +-This command starts up the libguestfs appliance on a null disk, and +-then immediately shuts it down. The first time you run the command, +-it will create an appliance and cache it (usually under ++The guestfish command above starts up the libguestfs appliance on a ++null disk, and then immediately shuts it down. The first time you run ++the command, it will create an appliance and cache it (usually under + F). Subsequent runs should reuse the cached + appliance. + +diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am +index bea1c85..cc5cb6a 100644 +--- a/tests/qemu/Makefile.am ++++ b/tests/qemu/Makefile.am +@@ -1,5 +1,5 @@ + # libguestfs +-# Copyright (C) 2011 Red Hat Inc. ++# Copyright (C) 2011-2016 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 +@@ -33,10 +33,11 @@ EXTRA_DIST = \ + qemu-boot.c \ + qemu-speed-test.c + +-# qemu-boot, qemu-speed-test and boot-analysis are built but not run +-# by default as they are mainly qemu & kernel diagnostic tools. ++# qemu-boot, qemu-speed-test, boot-analysis and boot-benchmark are ++# built but not run by default as they are mainly qemu & kernel ++# diagnostic tools. + +-check_PROGRAMS = qemu-boot qemu-speed-test boot-analysis ++check_PROGRAMS = qemu-boot qemu-speed-test boot-analysis boot-benchmark + + qemu_boot_SOURCES = \ + ../../df/estimate-max-threads.c \ +@@ -76,7 +77,9 @@ qemu_speed_test_LDADD = \ + boot_analysis_SOURCES = \ + boot-analysis.c \ + boot-analysis.h \ +- boot-analysis-timeline.c ++ boot-analysis-timeline.c \ ++ boot-analysis-utils.c \ ++ boot-analysis-utils.h + boot_analysis_CPPFLAGS = \ + -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ + -I$(top_srcdir)/src -I$(top_builddir)/src +@@ -93,6 +96,23 @@ boot_analysis_LDADD = \ + $(top_builddir)/gnulib/lib/libgnu.la \ + -lm + ++boot_benchmark_SOURCES = \ ++ boot-benchmark.c \ ++ boot-analysis-utils.c \ ++ boot-analysis-utils.h ++boot_benchmark_CPPFLAGS = \ ++ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ ++ -I$(top_srcdir)/src -I$(top_builddir)/src ++boot_benchmark_CFLAGS = \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) ++boot_benchmark_LDADD = \ ++ $(top_builddir)/src/libutils.la \ ++ $(top_builddir)/src/libguestfs.la \ ++ $(LIBXML2_LIBS) \ ++ $(LTLIBINTL) \ ++ $(top_builddir)/gnulib/lib/libgnu.la \ ++ -lm ++ + # Don't run these tests in parallel, since they are designed to check + # the integrity of qemu. + .NOTPARALLEL: +diff --git a/tests/qemu/boot-analysis-utils.c b/tests/qemu/boot-analysis-utils.c +new file mode 100644 +index 0000000..e885f3b +--- /dev/null ++++ b/tests/qemu/boot-analysis-utils.c +@@ -0,0 +1,47 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis-utils.h" ++ ++void ++get_time (struct timespec *ts) ++{ ++ if (clock_gettime (CLOCK_REALTIME, ts) == -1) ++ error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME"); ++} ++ ++int64_t ++timespec_diff (const struct timespec *x, const struct timespec *y) ++{ ++ int64_t nsec; ++ ++ nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000); ++ nsec += y->tv_nsec - x->tv_nsec; ++ return nsec; ++} +diff --git a/tests/qemu/boot-analysis-utils.h b/tests/qemu/boot-analysis-utils.h +new file mode 100644 +index 0000000..83fc494 +--- /dev/null ++++ b/tests/qemu/boot-analysis-utils.h +@@ -0,0 +1,30 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 GUESTFS_BOOT_ANALYSIS_UTILS_H_ ++#define GUESTFS_BOOT_ANALYSIS_UTILS_H_ ++ ++/* Get current time, returning it in *ts. If there is a system call ++ * failure, this exits. ++ */ ++extern void get_time (struct timespec *ts); ++ ++/* Computes Y - X, returning nanoseconds. */ ++extern int64_t timespec_diff (const struct timespec *x, const struct timespec *y); ++ ++#endif /* GUESTFS_BOOT_ANALYSIS_UTILS_H_ */ +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index fc2c93b..022eaab 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -79,6 +79,7 @@ + #include "guestfs-internal-frontend.h" + + #include "boot-analysis.h" ++#include "boot-analysis-utils.h" + + /* Activities taking longer than this % of the total time, except + * those flagged as LONG_ACTIVITY, are highlighted in red. +@@ -96,8 +97,6 @@ static int smp = 1; + static int verbose = 0; + + static void run_test (void); +-static void get_time (struct timespec *ts); +-static int64_t timespec_diff (const struct timespec *x, const struct timespec *y); + static struct event *add_event (struct pass_data *, uint64_t source); + static guestfs_h *create_handle (void); + static void set_up_event_handlers (guestfs_h *g, size_t pass); +@@ -267,24 +266,6 @@ run_test (void) + free_final_timeline (); + } + +-static void +-get_time (struct timespec *ts) +-{ +- if (clock_gettime (CLOCK_REALTIME, ts) == -1) +- error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME"); +-} +- +-/* Computes Y - X, returning nanoseconds. */ +-static int64_t +-timespec_diff (const struct timespec *x, const struct timespec *y) +-{ +- int64_t nsec; +- +- nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000); +- nsec += y->tv_nsec - x->tv_nsec; +- return nsec; +-} +- + static struct event * + add_event (struct pass_data *data, uint64_t source) + { +diff --git a/tests/qemu/boot-benchmark.c b/tests/qemu/boot-benchmark.c +new file mode 100644 +index 0000000..2a6a038 +--- /dev/null ++++ b/tests/qemu/boot-benchmark.c +@@ -0,0 +1,230 @@ ++/* libguestfs ++ * Copyright (C) 2016 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. ++ */ ++ ++/* Benchmark the time taken to boot the libguestfs appliance. */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis-utils.h" ++ ++#define NR_WARMUP_PASSES 3 ++#define NR_TEST_PASSES 10 ++ ++static const char *append = NULL; ++static int memsize = 0; ++static int smp = 1; ++ ++static void run_test (void); ++static guestfs_h *create_handle (void); ++static void add_drive (guestfs_h *g); ++ ++static void ++usage (int exitcode) ++{ ++ guestfs_h *g; ++ int default_memsize = -1; ++ ++ g = guestfs_create (); ++ if (g) { ++ default_memsize = guestfs_get_memsize (g); ++ guestfs_close (g); ++ } ++ ++ fprintf (stderr, ++ "boot-benchmark: Benchmark the time taken to boot the libguestfs appliance.\n" ++ "Usage:\n" ++ " boot-benchmark [--options]\n" ++ "Options:\n" ++ " --help Display this usage text and exit.\n" ++ " --append OPTS Append OPTS to kernel command line.\n" ++ " -m MB\n" ++ " --memsize MB Set memory size in MB (default: %d).\n" ++ " --smp N Enable N virtual CPUs (default: 1).\n", ++ default_memsize); ++ exit (exitcode); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ enum { HELP_OPTION = CHAR_MAX + 1 }; ++ static const char *options = "m:"; ++ static const struct option long_options[] = { ++ { "help", 0, 0, HELP_OPTION }, ++ { "append", 1, 0, 0 }, ++ { "memsize", 1, 0, 'm' }, ++ { "smp", 1, 0, 0 }, ++ { 0, 0, 0, 0 } ++ }; ++ int c, option_index; ++ ++ for (;;) { ++ c = getopt_long (argc, argv, options, long_options, &option_index); ++ if (c == -1) break; ++ ++ switch (c) { ++ case 0: /* Options which are long only. */ ++ if (STREQ (long_options[option_index].name, "append")) { ++ append = optarg; ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "smp")) { ++ if (sscanf (optarg, "%d", &smp) != 1) { ++ fprintf (stderr, "%s: could not parse smp parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ } ++ fprintf (stderr, "%s: unknown long option: %s (%d)\n", ++ guestfs_int_program_name, long_options[option_index].name, option_index); ++ exit (EXIT_FAILURE); ++ ++ case 'm': ++ if (sscanf (optarg, "%d", &memsize) != 1) { ++ fprintf (stderr, "%s: could not parse memsize parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case HELP_OPTION: ++ usage (EXIT_SUCCESS); ++ ++ default: ++ usage (EXIT_FAILURE); ++ } ++ } ++ ++ run_test (); ++} ++ ++static void ++run_test (void) ++{ ++ guestfs_h *g; ++ size_t i; ++ int64_t ns[NR_TEST_PASSES]; ++ double mean; ++ double variance; ++ double sd; ++ ++ printf ("Warming up the libguestfs cache ...\n"); ++ for (i = 0; i < NR_WARMUP_PASSES; ++i) { ++ g = create_handle (); ++ add_drive (g); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ } ++ ++ printf ("Running the tests ...\n"); ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ struct timespec start_t, end_t; ++ ++ g = create_handle (); ++ add_drive (g); ++ get_time (&start_t); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ get_time (&end_t); ++ ++ ns[i] = timespec_diff (&start_t, &end_t); ++ } ++ ++ /* Calculate the mean. */ ++ mean = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) ++ mean += ns[i]; ++ mean /= NR_TEST_PASSES; ++ ++ /* Calculate the variance and standard deviation. */ ++ variance = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) ++ variance = pow (ns[i] - mean, 2); ++ variance /= NR_TEST_PASSES; ++ sd = sqrt (variance); ++ ++ /* Print the test parameters. */ ++ printf ("\n"); ++ printf (" passes %d\n", NR_TEST_PASSES); ++ g = create_handle (); ++ printf (" append %s\n", guestfs_get_append (g) ? : ""); ++ printf ("backend %s\n", guestfs_get_backend (g)); ++ printf (" hv %s\n", guestfs_get_hv (g)); ++ printf ("memsize %d\n", guestfs_get_memsize (g)); ++ printf (" smp %d\n", guestfs_get_smp (g)); ++ guestfs_close (g); ++ ++ /* Print the result. */ ++ printf ("\n"); ++ printf ("Result: %.1fms ±%.1fms\n", mean / 1000000, sd / 1000000); ++} ++ ++/* Common function to create the handle and set various defaults. */ ++static guestfs_h * ++create_handle (void) ++{ ++ guestfs_h *g; ++ CLEANUP_FREE char *full_append = NULL; ++ ++ g = guestfs_create (); ++ if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); ++ ++ if (memsize != 0) ++ if (guestfs_set_memsize (g, memsize) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (smp >= 2) ++ if (guestfs_set_smp (g, smp) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (append != NULL) ++ if (guestfs_set_append (g, full_append) == -1) ++ exit (EXIT_FAILURE); ++ ++ return g; ++} ++ ++/* Common function to add the /dev/null drive. */ ++static void ++add_drive (guestfs_h *g) ++{ ++ if (guestfs_add_drive_opts (g, "/dev/null", ++ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", ++ GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, ++ -1) == -1) ++ exit (EXIT_FAILURE); ++} +-- +1.8.3.1 + diff --git a/SOURCES/0052-v2v-linux-Print-block-device-map-in-verbose-mode.patch b/SOURCES/0052-v2v-linux-Print-block-device-map-in-verbose-mode.patch deleted file mode 100644 index 2a0de2c..0000000 --- a/SOURCES/0052-v2v-linux-Print-block-device-map-in-verbose-mode.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d79d6b9331e5ecbec35b001ab2127e11c55f1d05 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 18 Nov 2014 13:53:13 +0000 -Subject: [PATCH] v2v: linux: Print block device map in verbose mode. - -Very useful for debugging device mapping problems. - -(cherry picked from commit e25f68c47efaab886ada330b7ab596681705b02b) ---- - v2v/convert_linux.ml | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 44b6c7f..2f97ca1 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1263,6 +1263,15 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - "xvd" ^ drive_name i, block_prefix_after_conversion ^ drive_name i - ) source.s_disks in - -+ if verbose then ( -+ printf "block device map:\n"; -+ List.iter ( -+ fun (source_dev, target_dev) -> -+ printf "\t%s\t-> %s\n" source_dev target_dev -+ ) (List.sort (fun (a,_) (b,_) -> compare a b) map); -+ flush stdout -+ ); -+ - (* Possible Augeas paths to search for device names. *) - let paths = [ - (* /etc/fstab *) --- -1.8.3.1 - diff --git a/SOURCES/0053-tests-qemu-boot-analysis-Display-all-times-in-ms.patch b/SOURCES/0053-tests-qemu-boot-analysis-Display-all-times-in-ms.patch new file mode 100644 index 0000000..34911fc --- /dev/null +++ b/SOURCES/0053-tests-qemu-boot-analysis-Display-all-times-in-ms.patch @@ -0,0 +1,50 @@ +From 2e75e1584b4ad34df3999f9e0b270a0fdc246c67 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 2 Apr 2016 10:42:12 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Display all times in ms. + +It was confusing to have a mix of seconds and milliseconds. For all +upstream testing (eg. with SeaBIOS) we are discussing everything in +milliseconds, so use those exclusively. + +(cherry picked from commit d470480b3564b45301a79047f919051b4e2e58b4) +--- + tests/qemu/boot-analysis.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index 022eaab..9ab228a 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -860,8 +860,8 @@ print_activity (struct activity *activity) + if (activity->warning) ansi_red (); else ansi_green (); + print_escaped_string (activity->name); + ansi_restore (); +- printf (" %1.6fs ±%.1fms ", +- activity->mean / 1000000000, activity->sd / 1000000); ++ printf (" %.1fms ±%.1fms ", ++ activity->mean / 1000000, activity->sd / 1000000); + if (activity->warning) ansi_red (); else ansi_green (); + printf ("(%.1f%%) ", activity->percent); + ansi_restore (); +@@ -906,7 +906,7 @@ print_analysis (void) + + /* Draw a spacer line, but only if last_t -> t is a large jump. */ + if (t - last_t >= 1000000 /* ns */) { +- printf (" "); ++ printf (" "); + ansi_magenta (); + for (j = 0; j < last_free_column; ++j) { + if (columns[j] >= 0 && +@@ -946,7 +946,7 @@ print_analysis (void) + + /* Draw the line. */ + ansi_blue (); +- printf ("%1.6fs: ", t / 1000000000); ++ printf ("%6.1fms: ", t / 1000000); + + ansi_magenta (); + for (j = 0; j < last_free_column; ++j) { +-- +1.8.3.1 + diff --git a/SOURCES/0053-v2v-linux-Always-match-partition-number-in-regexp.patch b/SOURCES/0053-v2v-linux-Always-match-partition-number-in-regexp.patch deleted file mode 100644 index c2cb1db..0000000 --- a/SOURCES/0053-v2v-linux-Always-match-partition-number-in-regexp.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 59193f066dbf4318f95d5f4740df1374565e09e1 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 18 Nov 2014 14:16:39 +0000 -Subject: [PATCH] v2v: linux: Always match partition number in regexp. - -Change the rex_device_p regular expression to always include a -partition number. - -There should be no functional change here. - -(cherry picked from commit b1053150a2da121b3cb8ddc197d0d8e49d930130) ---- - v2v/convert_linux.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 2f97ca1..d094969 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1300,7 +1300,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - and rex_device_cciss = - Str.regexp "^/dev/\\(cciss/c[0-9]+d[0-9]+\\)$" - and rex_device_p = -- Str.regexp "^/dev/\\([a-z]+\\)\\([0-9]*\\)$" -+ Str.regexp "^/dev/\\([a-z]+\\)\\([0-9]+\\)$" - and rex_device = - Str.regexp "^/dev/\\([a-z]+\\)$" in - --- -1.8.3.1 - diff --git a/SOURCES/0054-tests-qemu-Standardize-test-info-printed-by-boot-tes.patch b/SOURCES/0054-tests-qemu-Standardize-test-info-printed-by-boot-tes.patch new file mode 100644 index 0000000..1455472 --- /dev/null +++ b/SOURCES/0054-tests-qemu-Standardize-test-info-printed-by-boot-tes.patch @@ -0,0 +1,185 @@ +From 900151dff1bbea9d37848143989583bf91c5d344 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 2 Apr 2016 11:01:30 +0100 +Subject: [PATCH] tests/qemu: Standardize test info printed by boot-* tests. + +It now looks like: + +test version: libguestfs 1.33.16 + test passes: 5 +host version: Linux moo 4.4.4-301.fc23.x86_64 #1 SMP Fri Mar 4 17:42:42 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux + host CPU: Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz + backend: direct + qemu: /home/rjones/d/qemu/x86_64-softmmu/qemu-system-x86_64 +qemu version: QEMU emulator version 2.5.90, Copyright (c) 2003-2008 Fabrice Bellard + smp: 1 + memsize: 500 + append: guestfs_boot_analysis=1 ignore_loglevel initcall_debug + +(cherry picked from commit 014b7c0ced2dc57ca2dda0c43873359497f8672b) +--- + tests/qemu/boot-analysis-utils.c | 37 +++++++++++++++++++++++++++++++++++++ + tests/qemu/boot-analysis-utils.h | 6 ++++++ + tests/qemu/boot-analysis.c | 38 +++----------------------------------- + tests/qemu/boot-benchmark.c | 7 +------ + 4 files changed, 47 insertions(+), 41 deletions(-) + +diff --git a/tests/qemu/boot-analysis-utils.c b/tests/qemu/boot-analysis-utils.c +index e885f3b..bcd470e 100644 +--- a/tests/qemu/boot-analysis-utils.c ++++ b/tests/qemu/boot-analysis-utils.c +@@ -24,6 +24,8 @@ + #include + #include + ++#include "ignore-value.h" ++ + #include "guestfs.h" + #include "guestfs-internal-frontend.h" + +@@ -45,3 +47,38 @@ timespec_diff (const struct timespec *x, const struct timespec *y) + nsec += y->tv_nsec - x->tv_nsec; + return nsec; + } ++ ++void ++test_info (guestfs_h *g, int nr_test_passes) ++{ ++ const char *qemu = guestfs_get_hv (g); ++ CLEANUP_FREE char *cmd = NULL; ++ ++ /* Related to the test program. */ ++ printf ("test version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION_FULL); ++ printf (" test passes: %d\n", nr_test_passes); ++ ++ /* Related to the host. */ ++ printf ("host version: "); ++ fflush (stdout); ++ ignore_value (system ("uname -a")); ++ printf (" host CPU: "); ++ fflush (stdout); ++ ignore_value (system ("perl -n -e 'if (/^model name.*: (.*)/) { print \"$1\\n\"; exit }' /proc/cpuinfo")); ++ ++ /* Related to qemu. */ ++ printf (" backend: %s\n", guestfs_get_backend (g)); ++ printf (" qemu: %s\n", qemu); ++ printf ("qemu version: "); ++ fflush (stdout); ++ if (asprintf (&cmd, "%s -version", qemu) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ignore_value (system (cmd)); ++ printf (" smp: %d\n", guestfs_get_smp (g)); ++ printf (" memsize: %d\n", guestfs_get_memsize (g)); ++ ++ /* Related to the guest kernel. Be nice to get the guest ++ * kernel version here somehow (XXX). ++ */ ++ printf (" append: %s\n", guestfs_get_append (g) ? : ""); ++} +diff --git a/tests/qemu/boot-analysis-utils.h b/tests/qemu/boot-analysis-utils.h +index 83fc494..95e4f06 100644 +--- a/tests/qemu/boot-analysis-utils.h ++++ b/tests/qemu/boot-analysis-utils.h +@@ -27,4 +27,10 @@ extern void get_time (struct timespec *ts); + /* Computes Y - X, returning nanoseconds. */ + extern int64_t timespec_diff (const struct timespec *x, const struct timespec *y); + ++/* Display host machine and test parameters (to stdout). 'g' should ++ * be an open libguestfs handle. It is used for reading hv, memsize ++ * etc. and is not modified. ++ */ ++extern void test_info (guestfs_h *g, int nr_test_passes); ++ + #endif /* GUESTFS_BOOT_ANALYSIS_UTILS_H_ */ +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index 9ab228a..f4c1d6c 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -73,8 +73,6 @@ + #include + #include + +-#include "ignore-value.h" +- + #include "guestfs.h" + #include "guestfs-internal-frontend.h" + +@@ -105,7 +103,6 @@ static void check_pass_data (void); + static void dump_pass_data (void); + static void analyze_timeline (void); + static void dump_timeline (void); +-static void print_info (void); + static void print_analysis (void); + static void print_longest_to_shortest (void); + static void free_pass_data (void); +@@ -254,7 +251,9 @@ run_test (void) + dump_timeline (); + + printf ("\n"); +- print_info (); ++ g = create_handle (); ++ test_info (g, NR_TEST_PASSES); ++ guestfs_close (g); + printf ("\n"); + print_analysis (); + printf ("\n"); +@@ -823,37 +822,6 @@ dump_timeline (void) + } + } + +-/* Print some information that will allow us to determine the test +- * system when reviewing the results in future. +- */ +-static void +-print_info (void) +-{ +- size_t i; +- +- printf ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION_FULL); +- +- printf ("Host:\n"); +- ignore_value (system ("uname -a")); +- ignore_value (system ("grep '^model name' /proc/cpuinfo | head -1")); +- +- /* We can dig some information about qemu and the appliance out of +- * the events. +- */ +- printf ("Appliance:\n"); +- assert (NR_TEST_PASSES > 0); +- for (i = 0; i < pass_data[0].nr_events; ++i) { +- const char *message = pass_data[0].events[i].message; +- if (strstr (message, "qemu version") || +- (strstr (message, "SeaBIOS") && strstr (message, "version")) || +- strstr (message, "Linux version") || +- (strstr (message, "supermin") && strstr (message, "starting up"))) { +- print_escaped_string (message); +- putchar ('\n'); +- } +- } +-} +- + static void + print_activity (struct activity *activity) + { +diff --git a/tests/qemu/boot-benchmark.c b/tests/qemu/boot-benchmark.c +index 2a6a038..0508ee9 100644 +--- a/tests/qemu/boot-benchmark.c ++++ b/tests/qemu/boot-benchmark.c +@@ -179,13 +179,8 @@ run_test (void) + + /* Print the test parameters. */ + printf ("\n"); +- printf (" passes %d\n", NR_TEST_PASSES); + g = create_handle (); +- printf (" append %s\n", guestfs_get_append (g) ? : ""); +- printf ("backend %s\n", guestfs_get_backend (g)); +- printf (" hv %s\n", guestfs_get_hv (g)); +- printf ("memsize %d\n", guestfs_get_memsize (g)); +- printf (" smp %d\n", guestfs_get_smp (g)); ++ test_info (g, NR_TEST_PASSES); + guestfs_close (g); + + /* Print the result. */ +-- +1.8.3.1 + diff --git a/SOURCES/0054-v2v-linux-Refactor-device-replacement-code.patch b/SOURCES/0054-v2v-linux-Refactor-device-replacement-code.patch deleted file mode 100644 index 12679b2..0000000 --- a/SOURCES/0054-v2v-linux-Refactor-device-replacement-code.patch +++ /dev/null @@ -1,102 +0,0 @@ -From b69454033c11c983b9546f9d2aa031c1594f0b79 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 18 Nov 2014 14:17:35 +0000 -Subject: [PATCH] v2v: linux: Refactor device replacement code. - -No functional change. This should be equivalent to previously. - -(cherry picked from commit 467bbf72f74527ca00678cfea80b1785868cd842) ---- - v2v/convert_linux.ml | 55 ++++++++++++++++++++++++++-------------------------- - 1 file changed, 27 insertions(+), 28 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index d094969..6c483c2 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1305,55 +1305,54 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - Str.regexp "^/dev/\\([a-z]+\\)$" in - - let rec replace_if_device path value = -- if Str.string_match rex_device_cciss_p value 0 then ( -+ let replace device = -+ try List.assoc device map -+ with Not_found -> -+ if string_find device "md" = -1 && string_find device "fd" = -1 && -+ device <> "cdrom" then -+ warning ~prog (f_"%s references unknown device \"%s\". You may have to fix this entry manually after conversion.") -+ path device; -+ device -+ in -+ -+ if string_find path "GRUB_CMDLINE" >= 0 then ( -+ (* Handle grub2 resume= specially. *) -+ if Str.string_match rex_resume value 0 then ( -+ let start = Str.matched_group 1 value -+ and device = Str.matched_group 2 value -+ and end_ = Str.matched_group 3 value in -+ let device = replace_if_device path device in -+ start ^ device ^ end_ -+ ) -+ else value -+ ) -+ else if Str.string_match rex_device_cciss_p value 0 then ( - let device = Str.matched_group 1 value - and part = Str.matched_group 2 value in -- "/dev/" ^ replace path device ^ part -+ "/dev/" ^ replace device ^ part - ) - else if Str.string_match rex_device_cciss value 0 then ( - let device = Str.matched_group 1 value in -- "/dev/" ^ replace path device -+ "/dev/" ^ replace device - ) - else if Str.string_match rex_device_p value 0 then ( - let device = Str.matched_group 1 value - and part = Str.matched_group 2 value in -- "/dev/" ^ replace path device ^ part -+ "/dev/" ^ replace device ^ part - ) - else if Str.string_match rex_device value 0 then ( - let device = Str.matched_group 1 value in -- "/dev/" ^ replace path device -+ "/dev/" ^ replace device - ) - else (* doesn't look like a known device name *) - value -- -- and replace path device = -- try List.assoc device map -- with Not_found -> -- if string_find device "md" = -1 && string_find device "fd" = -1 && -- device <> "cdrom" then -- warning ~prog (f_"%s references unknown device \"%s\". You may have to fix this entry manually after conversion.") -- path device; -- device - in - - let changed = ref false in - List.iter ( - fun path -> - let value = g#aug_get path in -- -- let new_value = -- (* Handle grub2 resume= specially. *) -- if string_find path "GRUB_CMDLINE" >= 0 then ( -- if Str.string_match rex_resume value 0 then ( -- let start = Str.matched_group 1 value -- and device = Str.matched_group 2 value -- and end_ = Str.matched_group 3 value in -- let device = replace_if_device path device in -- start ^ device ^ end_ -- ) -- else value -- ) -- else replace_if_device path value in -+ let new_value = replace_if_device path value in - - if value <> new_value then ( - g#aug_set path new_value; --- -1.8.3.1 - diff --git a/SOURCES/0055-tests-qemu-boot-analysis-Don-t-force-backend-direct.patch b/SOURCES/0055-tests-qemu-boot-analysis-Don-t-force-backend-direct.patch new file mode 100644 index 0000000..27d3194 --- /dev/null +++ b/SOURCES/0055-tests-qemu-boot-analysis-Don-t-force-backend-direct.patch @@ -0,0 +1,128 @@ +From 180a681da1f2ffa7be27a854b60a5c556288f567 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 2 Apr 2016 11:03:33 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Don't force backend direct. + +Current libvirt overhead is 220ms. That didn't matter when our launch +time was 4000ms. Now we're launching in 900ms, it really does. + +(cherry picked from commit 03b68d436c61e9e0baac7c4fb305b62f41185173) +--- + tests/qemu/boot-analysis-timeline.c | 65 ++++++++++++++++++++++++++++--------- + tests/qemu/boot-analysis.c | 11 ++----- + 2 files changed, 51 insertions(+), 25 deletions(-) + +diff --git a/tests/qemu/boot-analysis-timeline.c b/tests/qemu/boot-analysis-timeline.c +index 8753805..d35fb49 100644 +--- a/tests/qemu/boot-analysis-timeline.c ++++ b/tests/qemu/boot-analysis-timeline.c +@@ -176,28 +176,61 @@ construct_timeline (void) + "finished building supermin appliance")); + + /* Find where we invoke qemu to test features. */ +- FIND ("qemu:feature-detect", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, +- "begin testing qemu features"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, +- "finished testing qemu features")); ++ FIND_OPTIONAL ("qemu:feature-detect", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, ++ "begin testing qemu features"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, ++ "finished testing qemu features")); + + /* Find where we run qemu. */ +- FIND ("qemu", LONG_ACTIVITY, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "-nodefconfig"), +- data->events[k].source == GUESTFS_EVENT_CLOSE); ++ FIND_OPTIONAL ("qemu", LONG_ACTIVITY, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "-nodefconfig"), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++ /* For the libvirt backend, connecting to libvirt, getting ++ * capabilities, parsing capabilities etc. ++ */ ++ FIND_OPTIONAL ("libvirt:connect", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "connect to libvirt"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "successfully opened libvirt handle")); ++ FIND_OPTIONAL ("libvirt:get-libvirt-capabilities", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "get libvirt capabilities"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "parsing capabilities XML")); ++ ++ FIND_OPTIONAL ("libguestfs:parse-libvirt-capabilities", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "parsing capabilities XML"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "get_backend_setting")); ++ ++ FIND_OPTIONAL ("libguestfs:create-libvirt-xml", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "create libvirt XML"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "libvirt XML:")); + + #define SGABIOS_STRING "\033[1;256r\033[256;256H\033[6n" + ++ /* For the libvirt backend, find the overhead of libvirt. */ ++ FIND_OPTIONAL ("libvirt:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "launch libvirt guest"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, SGABIOS_STRING)); ++ + /* From starting qemu up to entering the BIOS is the qemu overhead. */ +- FIND ("qemu:overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "-nodefconfig"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, SGABIOS_STRING)); ++ FIND_OPTIONAL ("qemu:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "-nodefconfig"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, SGABIOS_STRING)); + + /* From entering the BIOS to starting the kernel is the BIOS overhead. */ + FIND_OPTIONAL ("bios:overhead", 0, +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index f4c1d6c..37d8b3c 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -292,14 +292,6 @@ create_handle (void) + g = guestfs_create (); + if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); + +- /* We always run these tests using LIBGUESTFS_BACKEND=direct. It +- * may be in future we need to test libvirt as well, in case +- * performance issues are suspected there, but so far libvirt has +- * not been a bottleneck. +- */ +- if (guestfs_set_backend (g, "direct") == -1) +- exit (EXIT_FAILURE); +- + if (memsize != 0) + if (guestfs_set_memsize (g, memsize) == -1) + exit (EXIT_FAILURE); +@@ -622,7 +614,8 @@ check_pass_data (void) + assert (pass_data[i].events[j].source != 0); + message = pass_data[i].events[j].message; + assert (message != NULL); +- assert (strchr (message, '\n') == NULL); ++ assert (pass_data[i].events[j].source != GUESTFS_EVENT_APPLIANCE || ++ strchr (message, '\n') == NULL); + len = strlen (message); + assert (len == 0 || message[len-1] != '\r'); + } +-- +1.8.3.1 + diff --git a/SOURCES/0055-v2v-linux-Remap-device-names-in-boot-grub2-device.ma.patch b/SOURCES/0055-v2v-linux-Remap-device-names-in-boot-grub2-device.ma.patch deleted file mode 100644 index f9b846a..0000000 --- a/SOURCES/0055-v2v-linux-Remap-device-names-in-boot-grub2-device.ma.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ff5f1cbfc2b9bc92454695313e2f28c832e2c880 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 10:08:51 +0000 -Subject: [PATCH] v2v: linux: Remap device names in /boot/grub2/device.map - (RHBZ#1165975). - -Thanks: Junquin Zhou -(cherry picked from commit 7b8c6e762e10033b174f8554145d48489718b8b5) ---- - v2v/convert_linux.ml | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 6c483c2..e85a0d5 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1287,6 +1287,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - "/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX"; - "/files/etc/default/grub/GRUB_CMDLINE_LINUX"; - "/files/etc/default/grub/GRUB_CMDLINE_LINUX_DEFAULT"; -+ "/files/boot/grub2/device.map/*[label() != \"#comment\"]"; - ] in - - (* Which of these paths actually exist? *) --- -1.8.3.1 - diff --git a/SOURCES/0056-launch-libvirt-Disable-virtio-rng-in-libvirt-backend.patch b/SOURCES/0056-launch-libvirt-Disable-virtio-rng-in-libvirt-backend.patch new file mode 100644 index 0000000..468de1e --- /dev/null +++ b/SOURCES/0056-launch-libvirt-Disable-virtio-rng-in-libvirt-backend.patch @@ -0,0 +1,41 @@ +From 19b262aeeb71b690099d5169eaea5d817674fdbe Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 5 Apr 2016 15:02:20 +0100 +Subject: [PATCH] launch: libvirt: Disable virtio-rng in libvirt backend until + we can use /dev/urandom. + +This updates commit 9423c16607259b30985c46d04db9958ec079aa42. + +(cherry picked from commit b2c845333f66d4d3135d3b6a8d4b992d6160bf0a) +--- + src/launch-libvirt.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index f9edac0..96c5913 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -1306,6 +1306,12 @@ construct_libvirt_xml_devices (guestfs_h *g, + } + #endif + ++#if 0 ++ /* This is disabled. Pulling random numbers from /dev/random ++ * causes the appliance to pause for long periods. We should ++ * use /dev/urandom, but for bogus reasons libvirt prevents that. ++ * https://bugzilla.redhat.com/show_bug.cgi?id=1074464#c7 ++ */ + /* Add a random number generator (backend for virtio-rng). */ + start_element ("rng") { + attribute ("model", "virtio"); +@@ -1319,6 +1325,7 @@ construct_libvirt_xml_devices (guestfs_h *g, + //string ("/dev/urandom"); + } end_element (); + } end_element (); ++#endif + + /* virtio-scsi controller. */ + start_element ("controller") { +-- +1.8.3.1 + diff --git a/SOURCES/0056-v2v-linux-Delete-the-LVM-cache-which-may-reference-o.patch b/SOURCES/0056-v2v-linux-Delete-the-LVM-cache-which-may-reference-o.patch deleted file mode 100644 index 2e6f845..0000000 --- a/SOURCES/0056-v2v-linux-Delete-the-LVM-cache-which-may-reference-o.patch +++ /dev/null @@ -1,35 +0,0 @@ -From a55c1655eb6115b5656a7c1c76246fa48f65a56d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 11:22:32 +0000 -Subject: [PATCH] v2v: linux: Delete the LVM cache which may reference old - devices (RHBZ#1164853). - -Thanks: Bryn M. Reeves -(cherry picked from commit 63d67ac8ac6ae609514c995704a4dbd6f5ff5647) ---- - v2v/convert_linux.ml | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index e85a0d5..6e45ac8 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1373,8 +1373,14 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - - (* Delete blkid caches if they exist, since they will refer to the old - * device names. blkid will rebuild these on demand. -+ * -+ * Delete the LVM cache since it will contain references to the -+ * old devices (RHBZ#1164853). - *) -- List.iter g#rm_f ["/etc/blkid/blkid.tab"; "/etc/blkid.tab"] -+ List.iter g#rm_f [ -+ "/etc/blkid/blkid.tab"; "/etc/blkid.tab"; -+ "/etc/lvm/cache/.cache" -+ ]; - in - - augeas_grub_configuration (); --- -1.8.3.1 - diff --git a/SOURCES/0057-p2v-Remove-fullscreen-option.patch b/SOURCES/0057-p2v-Remove-fullscreen-option.patch deleted file mode 100644 index 69c9cb1..0000000 --- a/SOURCES/0057-p2v-Remove-fullscreen-option.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 77107d9bc262ebae54dec9cff788ff1b7504c7d6 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 16:10:08 +0000 -Subject: [PATCH] p2v: Remove --fullscreen option. - -It did nothing and was left over from an earlier attempt to add -fullscreen mode. That is not needed any longer since we now run -virt-p2v under the matchbox window manager. - -(cherry picked from commit 11347db5762441cd97791367d3cdf7e0c5a0ddc5) ---- - p2v/main.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/p2v/main.c b/p2v/main.c -index 9c34413c..a93ca1c 100644 ---- a/p2v/main.c -+++ b/p2v/main.c -@@ -37,7 +37,6 @@ - - #include "p2v.h" - --int fullscreen; - char **all_disks; - char **all_removable; - char **all_interfaces; -@@ -54,7 +53,6 @@ static const struct option long_options[] = { - { "help", 0, 0, HELP_OPTION }, - { "cmdline", 1, 0, 0 }, - { "long-options", 0, 0, 0 }, -- { "fullscreen", 0, 0, 0 }, - { "verbose", 0, 0, 'v' }, - { "version", 0, 0, 'V' }, - { 0, 0, 0, 0 } -@@ -75,7 +73,6 @@ usage (int status) - "Options:\n" - " --help Display brief help\n" - " --cmdline=CMDLINE Used to debug command line parsing\n" -- " --fullscreen Run virt-p2v in full screen mode\n" - " -v|--verbose Verbose messages\n" - " -V|--version Display version and exit\n" - "For more information, see the manpage %s(1).\n"), --- -1.8.3.1 - diff --git a/SOURCES/0057-tests-qemu-Don-t-leak-backend-variable-in-boot-analy.patch b/SOURCES/0057-tests-qemu-Don-t-leak-backend-variable-in-boot-analy.patch new file mode 100644 index 0000000..134a40d --- /dev/null +++ b/SOURCES/0057-tests-qemu-Don-t-leak-backend-variable-in-boot-analy.patch @@ -0,0 +1,36 @@ +From 7f277fb1bbb480fdd616d0ac785a6e08b764b644 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 6 Apr 2016 10:42:21 +0100 +Subject: [PATCH] tests/qemu: Don't leak backend variable in + boot-analysis/boot-benchmark programs. + +(cherry picked from commit 0008d794cf00b07842bc5403b53684e2bad5053a) +--- + tests/qemu/boot-analysis-utils.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tests/qemu/boot-analysis-utils.c b/tests/qemu/boot-analysis-utils.c +index bcd470e..4ed2d48 100644 +--- a/tests/qemu/boot-analysis-utils.c ++++ b/tests/qemu/boot-analysis-utils.c +@@ -53,6 +53,7 @@ test_info (guestfs_h *g, int nr_test_passes) + { + const char *qemu = guestfs_get_hv (g); + CLEANUP_FREE char *cmd = NULL; ++ CLEANUP_FREE char *backend = NULL; + + /* Related to the test program. */ + printf ("test version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION_FULL); +@@ -67,7 +68,8 @@ test_info (guestfs_h *g, int nr_test_passes) + ignore_value (system ("perl -n -e 'if (/^model name.*: (.*)/) { print \"$1\\n\"; exit }' /proc/cpuinfo")); + + /* Related to qemu. */ +- printf (" backend: %s\n", guestfs_get_backend (g)); ++ backend = guestfs_get_backend (g); ++ printf (" backend: %s\n", backend); + printf (" qemu: %s\n", qemu); + printf ("qemu version: "); + fflush (stdout); +-- +1.8.3.1 + diff --git a/SOURCES/0058-p2v-gui-Get-the-correct-button-for-cancel_button.patch b/SOURCES/0058-p2v-gui-Get-the-correct-button-for-cancel_button.patch deleted file mode 100644 index 3176464..0000000 --- a/SOURCES/0058-p2v-gui-Get-the-correct-button-for-cancel_button.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 89bef8662be9ec004fd0c71f863025b2c9e0ee8c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 15:37:44 +0000 -Subject: [PATCH] p2v: gui: Get the correct button for cancel_button. - -I was fetching cancel_button from the wrong dialog (conv_dlg, not -run_dlg), and therefore getting the wrong button. - -This explains why the back button on the conversion dialog was always -insensitive. It's because cancel_button was assigned to this button, -and then I was setting cancel_button to insensitive. - -(cherry picked from commit 5d695d37a56a01b8f72a086eaa3bc9de94f6fe3c) ---- - p2v/gui.c | 2 +- - v2v/TODO | 1 - - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/p2v/gui.c b/p2v/gui.c -index 9a004b5..aa483db 100644 ---- a/p2v/gui.c -+++ b/p2v/gui.c -@@ -1093,7 +1093,7 @@ create_running_dialog (void) - gtk_dialog_add_buttons (GTK_DIALOG (run_dlg), - _("Cancel conversion"), 1, - NULL); -- cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (conv_dlg), 1); -+ cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (run_dlg), 1); - gtk_widget_set_sensitive (cancel_button, FALSE); - - /* Signals. */ -diff --git a/v2v/TODO b/v2v/TODO -index b2d3fbd..54a3610 100644 ---- a/v2v/TODO -+++ b/v2v/TODO -@@ -11,7 +11,6 @@ Proper progress bars when copying. - p2v: - - - network dialog and network configuration -- - why is the Back button insensitive? - - p2v/main.c:/* XXX Copied from fish/options.c. */ - v2v/convert_linux.ml: (* Get/construct the version. XXX Read this fro --- -1.8.3.1 - diff --git a/SOURCES/0058-tests-qemu-boot-analysis-Add-support-for-logging-lib.patch b/SOURCES/0058-tests-qemu-boot-analysis-Add-support-for-logging-lib.patch new file mode 100644 index 0000000..555225c --- /dev/null +++ b/SOURCES/0058-tests-qemu-boot-analysis-Add-support-for-logging-lib.patch @@ -0,0 +1,353 @@ +From f009e084782ac692ce1a519b5255e9abf4a79632 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 6 Apr 2016 10:43:00 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Add support for logging libvirt + events. + +(cherry picked from commit b332d91bc9685e8992ede2c8a10655f26fd0395e) +--- + tests/qemu/Makefile.am | 1 + + tests/qemu/boot-analysis.c | 236 +++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 227 insertions(+), 10 deletions(-) + +diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am +index cc5cb6a..fdf643f 100644 +--- a/tests/qemu/Makefile.am ++++ b/tests/qemu/Makefile.am +@@ -84,6 +84,7 @@ boot_analysis_CPPFLAGS = \ + -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ + -I$(top_srcdir)/src -I$(top_builddir)/src + boot_analysis_CFLAGS = \ ++ -pthread \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) \ + $(PCRE_CFLAGS) + boot_analysis_LDADD = \ +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index 37d8b3c..2a43976 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -64,6 +64,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -71,7 +72,10 @@ + #include + #include + #include ++#include ++#include + #include ++#include + + #include "guestfs.h" + #include "guestfs-internal-frontend.h" +@@ -84,20 +88,32 @@ + */ + #define WARNING_THRESHOLD 1.0 + +-struct pass_data pass_data[NR_TEST_PASSES]; +-size_t nr_activities; +-struct activity *activities; +- + static const char *append = NULL; + static int force_colour = 0; + static int memsize = 0; + static int smp = 1; + static int verbose = 0; + ++static int libvirt_pipe[2] = { -1, -1 }; ++static ssize_t libvirt_pass = -1; ++ ++/* Because there is a separate thread which collects libvirt log data, ++ * we must protect the pass_data struct with a mutex. This only ++ * applies during the data collection passes. ++ */ ++static pthread_mutex_t pass_data_lock = PTHREAD_MUTEX_INITIALIZER; ++struct pass_data pass_data[NR_TEST_PASSES]; ++ ++size_t nr_activities; ++struct activity *activities; ++ + static void run_test (void); + static struct event *add_event (struct pass_data *, uint64_t source); + static guestfs_h *create_handle (void); + static void set_up_event_handlers (guestfs_h *g, size_t pass); ++static void libvirt_log_hack (int argc, char **argv); ++static void start_libvirt_thread (size_t pass); ++static void stop_libvirt_thread (void); + static void add_drive (guestfs_h *g); + static void check_pass_data (void); + static void dump_pass_data (void); +@@ -152,6 +168,8 @@ main (int argc, char *argv[]) + { "color", 0, 0, 0 }, + { "colour", 0, 0, 0 }, + { "memsize", 1, 0, 'm' }, ++ { "libvirt-pipe-0", 1, 0, 0 }, /* see libvirt_log_hack */ ++ { "libvirt-pipe-1", 1, 0, 0 }, + { "smp", 1, 0, 0 }, + { "verbose", 0, 0, 'v' }, + { 0, 0, 0, 0 } +@@ -173,12 +191,22 @@ main (int argc, char *argv[]) + force_colour = 1; + break; + } ++ else if (STREQ (long_options[option_index].name, "libvirt-pipe-0")) { ++ if (sscanf (optarg, "%d", &libvirt_pipe[0]) != 1) ++ error (EXIT_FAILURE, 0, ++ "could not parse libvirt-pipe-0 parameter: %s", optarg); ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "libvirt-pipe-1")) { ++ if (sscanf (optarg, "%d", &libvirt_pipe[1]) != 1) ++ error (EXIT_FAILURE, 0, ++ "could not parse libvirt-pipe-1 parameter: %s", optarg); ++ break; ++ } + else if (STREQ (long_options[option_index].name, "smp")) { +- if (sscanf (optarg, "%d", &smp) != 1) { +- fprintf (stderr, "%s: could not parse smp parameter: %s\n", +- guestfs_int_program_name, optarg); +- exit (EXIT_FAILURE); +- } ++ if (sscanf (optarg, "%d", &smp) != 1) ++ error (EXIT_FAILURE, 0, ++ "could not parse smp parameter: %s", optarg); + break; + } + fprintf (stderr, "%s: unknown long option: %s (%d)\n", +@@ -205,6 +233,8 @@ main (int argc, char *argv[]) + } + } + ++ libvirt_log_hack (argc, argv); ++ + if (STRNEQ (host_cpu, "x86_64")) + fprintf (stderr, "WARNING: host_cpu != x86_64: This program may not work or give bogus results.\n"); + +@@ -230,10 +260,12 @@ run_test (void) + for (i = 0; i < NR_TEST_PASSES; ++i) { + g = create_handle (); + set_up_event_handlers (g, i); ++ start_libvirt_thread (i); + add_drive (g); + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + guestfs_close (g); ++ stop_libvirt_thread (); + + printf (" pass %zu: %zu events collected in %" PRIi64 " ns\n", + i+1, pass_data[i].nr_events, pass_data[i].elapsed_ns); +@@ -266,7 +298,7 @@ run_test (void) + } + + static struct event * +-add_event (struct pass_data *data, uint64_t source) ++add_event_unlocked (struct pass_data *data, uint64_t source) + { + struct event *ret; + +@@ -282,6 +314,17 @@ add_event (struct pass_data *data, uint64_t source) + return ret; + } + ++static struct event * ++add_event (struct pass_data *data, uint64_t source) ++{ ++ struct event *ret; ++ ++ pthread_mutex_lock (&pass_data_lock); ++ ret = add_event_unlocked (data, source); ++ pthread_mutex_unlock (&pass_data_lock); ++ return ret; ++} ++ + /* Common function to create the handle and set various defaults. */ + static guestfs_h * + create_handle (void) +@@ -590,6 +633,179 @@ set_up_event_handlers (guestfs_h *g, size_t pass) + guestfs_set_trace (g, 1); + } + ++/* libvirt debugging sucks in a number of concrete ways: ++ * ++ * - you can't get a synchronous callback from a log message ++ * - you can't enable logging per handle (only globally ++ * by setting environment variables) ++ * - you can't debug the daemon easily ++ * - it's very complex ++ * - it's very complex but not in ways that are practical or useful ++ * ++ * To get log messages at all, we need to create a pipe connected to a ++ * second thread, and when libvirt prints something to the pipe we log ++ * that. ++ * ++ * However that's not sufficient. Because logging is only enabled ++ * when libvirt examines environment variables at the start of the ++ * program, we need to create the pipe and then fork+exec a new ++ * instance of the whole program with the pipe and environment ++ * variables set up. ++ */ ++static int is_libvirt_backend (guestfs_h *g); ++static void *libvirt_log_thread (void *datavp); ++ ++static void ++libvirt_log_hack (int argc, char **argv) ++{ ++ guestfs_h *g; ++ ++ g = guestfs_create (); ++ if (!is_libvirt_backend (g)) { ++ guestfs_close (g); ++ return; ++ } ++ guestfs_close (g); ++ ++ /* Have we set up the pipes and environment and forked yet? If not, ++ * do that first. ++ */ ++ if (libvirt_pipe[0] == -1 || libvirt_pipe[1] == -1) { ++ char log_outputs[64]; ++ char **new_argv; ++ char param1[64], param2[64]; ++ size_t i; ++ pid_t pid; ++ int status; ++ ++ /* Create the pipe. NB: do NOT use O_CLOEXEC since we want to pass ++ * this pipe into a child process. ++ */ ++ if (pipe (libvirt_pipe) == -1) ++ error (EXIT_FAILURE, 0, "pipe2"); ++ ++ /* Create the environment variables to enable logging in libvirt. */ ++ setenv ("LIBVIRT_DEBUG", "1", 1); ++ snprintf (log_outputs, sizeof log_outputs, ++ "1:file:/dev/fd/%d", libvirt_pipe[1]); ++ setenv ("LIBVIRT_LOG_OUTPUTS", log_outputs, 1); ++ ++ /* Run self again. */ ++ new_argv = malloc ((argc+3) * sizeof (char *)); ++ if (new_argv == NULL) ++ error (EXIT_FAILURE, errno, "malloc"); ++ ++ for (i = 0; i < (size_t) argc; ++i) ++ new_argv[i] = argv[i]; ++ ++ snprintf (param1, sizeof param1, "--libvirt-pipe-0=%d", libvirt_pipe[0]); ++ new_argv[argc] = param1; ++ snprintf (param2, sizeof param2, "--libvirt-pipe-1=%d", libvirt_pipe[1]); ++ new_argv[argc+1] = param2; ++ new_argv[argc+2] = NULL; ++ ++ pid = fork (); ++ if (pid == -1) ++ error (EXIT_FAILURE, errno, "fork"); ++ if (pid == 0) { /* Child process. */ ++ execvp (argv[0], new_argv); ++ perror ("execvp"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ if (waitpid (pid, &status, 0) == -1) ++ error (EXIT_FAILURE, errno, "waitpid"); ++ if (WIFEXITED (status)) ++ exit (WEXITSTATUS (status)); ++ error (EXIT_FAILURE, 0, "unexpected exit status from process: %d", status); ++ } ++ ++ /* If we reach this else clause, then we have forked. Now we must ++ * create a thread to read events from the pipe. This must be ++ * constantly reading from the pipe, otherwise we will deadlock. ++ * During the warm-up phase we end up throwing away messages. ++ */ ++ else { ++ pthread_t thread; ++ pthread_attr_t attr; ++ int r; ++ ++ r = pthread_attr_init (&attr); ++ if (r != 0) ++ error (EXIT_FAILURE, r, "pthread_attr_init"); ++ r = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); ++ if (r != 0) ++ error (EXIT_FAILURE, r, "pthread_attr_setdetachstate"); ++ r = pthread_create (&thread, &attr, libvirt_log_thread, NULL); ++ if (r != 0) ++ error (EXIT_FAILURE, r, "pthread_create"); ++ pthread_attr_destroy (&attr); ++ } ++} ++ ++static void ++start_libvirt_thread (size_t pass) ++{ ++ /* In the non-libvirt case, this variable is ignored. */ ++ pthread_mutex_lock (&pass_data_lock); ++ libvirt_pass = pass; ++ pthread_mutex_unlock (&pass_data_lock); ++} ++ ++static void ++stop_libvirt_thread (void) ++{ ++ /* In the non-libvirt case, this variable is ignored. */ ++ pthread_mutex_lock (&pass_data_lock); ++ libvirt_pass = -1; ++ pthread_mutex_unlock (&pass_data_lock); ++} ++ ++/* The separate "libvirt thread". It loops reading debug messages ++ * printed by libvirt and adds them to the pass_data. ++ */ ++static void * ++libvirt_log_thread (void *arg) ++{ ++ struct event *event; ++ CLEANUP_FREE char *buf = NULL; ++ ssize_t r; ++ ++ buf = malloc (BUFSIZ); ++ if (buf == NULL) ++ error (EXIT_FAILURE, errno, "malloc"); ++ ++ while ((r = read (libvirt_pipe[0], buf, BUFSIZ)) > 0) { ++ pthread_mutex_lock (&pass_data_lock); ++ if (libvirt_pass == -1) goto discard; ++ event = ++ add_event_unlocked (&pass_data[libvirt_pass], GUESTFS_EVENT_LIBRARY); ++ event->message = strndup (buf, r); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++ discard: ++ pthread_mutex_unlock (&pass_data_lock); ++ } ++ ++ if (r == -1) ++ error (EXIT_FAILURE, errno, "libvirt_log_thread: read"); ++ ++ /* It's possible for the pipe to be closed (r == 0) if thread ++ * cancellation is delayed after the main thread exits, so just ++ * ignore that case and exit. ++ */ ++ pthread_exit (NULL); ++} ++ ++static int ++is_libvirt_backend (guestfs_h *g) ++{ ++ CLEANUP_FREE char *backend = guestfs_get_backend (g); ++ ++ return backend && ++ (STREQ (backend, "libvirt") || STRPREFIX (backend, "libvirt:")); ++} ++ + /* Sanity check the collected events. */ + static void + check_pass_data (void) +-- +1.8.3.1 + diff --git a/SOURCES/0059-p2v-Add-Reboot-button-to-the-GUI-RHBZ-1165564.patch b/SOURCES/0059-p2v-Add-Reboot-button-to-the-GUI-RHBZ-1165564.patch deleted file mode 100644 index d6e282c..0000000 --- a/SOURCES/0059-p2v-Add-Reboot-button-to-the-GUI-RHBZ-1165564.patch +++ /dev/null @@ -1,92 +0,0 @@ -From de9b7e8c97904533f429ede5d1348c9e2219d175 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 15:59:50 +0000 -Subject: [PATCH] p2v: Add 'Reboot' button to the GUI (RHBZ#1165564). - -(cherry picked from commit 141832e2b22267f8369693d5f4afb27747668889) ---- - p2v/gui.c | 22 +++++++++++++++++++++- - 1 file changed, 21 insertions(+), 1 deletion(-) - -diff --git a/p2v/gui.c b/p2v/gui.c -index aa483db..72838ea 100644 ---- a/p2v/gui.c -+++ b/p2v/gui.c -@@ -34,6 +34,8 @@ - #pragma GCC diagnostic ignored "-Wstrict-prototypes" /* error in */ - #include - -+#include "ignore-value.h" -+ - #include "p2v.h" - - /* Interactive GUI configuration. */ -@@ -65,7 +67,7 @@ static GtkWidget *conv_dlg, - /* The running dialog which is displayed when virt-v2v is running. */ - static GtkWidget *run_dlg, - *v2v_output_sw, *v2v_output, *log_label, *status_label, -- *cancel_button; -+ *cancel_button, *reboot_button; - - /* The entry point from the main program. - * Note that gtk_init etc have already been called in main(). -@@ -1056,6 +1058,7 @@ static void set_log_dir (const char *remote_dir); - static void set_status (const char *msg); - static void add_v2v_output (const char *msg); - static void *start_conversion_thread (void *data); -+static void reboot_clicked (GtkWidget *w, gpointer data); - - static void - create_running_dialog (void) -@@ -1092,13 +1095,18 @@ create_running_dialog (void) - /* Buttons. */ - gtk_dialog_add_buttons (GTK_DIALOG (run_dlg), - _("Cancel conversion"), 1, -+ _("Reboot"), 2, - NULL); - cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (run_dlg), 1); - gtk_widget_set_sensitive (cancel_button, FALSE); -+ reboot_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (run_dlg), 2); -+ gtk_widget_set_sensitive (reboot_button, FALSE); - - /* Signals. */ - g_signal_connect_swapped (G_OBJECT (run_dlg), "destroy", - G_CALLBACK (gtk_main_quit), NULL); -+ g_signal_connect (G_OBJECT (reboot_button), "clicked", -+ G_CALLBACK (reboot_clicked), NULL); - } - - static void -@@ -1111,6 +1119,7 @@ show_running_dialog (void) - /* Show the running dialog. */ - gtk_widget_show_all (run_dlg); - gtk_widget_set_sensitive (cancel_button, FALSE); -+ gtk_widget_set_sensitive (reboot_button, FALSE); - } - - static void -@@ -1315,6 +1324,9 @@ start_conversion_thread (void *data) - gtk_widget_destroy (dlg); - } - -+ /* Enable the reboot button. */ -+ gtk_widget_set_sensitive (reboot_button, TRUE); -+ - gdk_threads_leave (); - - /* Thread is detached anyway, so no one is waiting for the status. */ -@@ -1347,3 +1359,11 @@ notify_ui_callback (int type, const char *data) - - gdk_threads_leave (); - } -+ -+static void -+reboot_clicked (GtkWidget *w, gpointer data) -+{ -+ sync (); -+ sleep (2); -+ ignore_value (system ("/sbin/reboot")); -+} --- -1.8.3.1 - diff --git a/SOURCES/0059-tests-qemu-boot-analysis-Don-t-set-LIBVIRT_LOG_FILTE.patch b/SOURCES/0059-tests-qemu-boot-analysis-Don-t-set-LIBVIRT_LOG_FILTE.patch new file mode 100644 index 0000000..e665855 --- /dev/null +++ b/SOURCES/0059-tests-qemu-boot-analysis-Don-t-set-LIBVIRT_LOG_FILTE.patch @@ -0,0 +1,31 @@ +From 095179b51623522f35cc1a2f46dd01ddc5e8d685 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 6 Apr 2016 17:44:49 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: (Don't) set LIBVIRT_LOG_FILTERS. + +Setting LIBVIRT_LOG_FILTERS is supposed to be better than setting +LIBVIRT_DEBUG, but I couldn't get it to work. + +This updates commit b332d91bc9685e8992ede2c8a10655f26fd0395e. + +(cherry picked from commit f24753ebb01ac96c092ee11aaa3f08df40d7ca00) +--- + tests/qemu/boot-analysis.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index 2a43976..444226c 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -686,6 +686,8 @@ libvirt_log_hack (int argc, char **argv) + + /* Create the environment variables to enable logging in libvirt. */ + setenv ("LIBVIRT_DEBUG", "1", 1); ++ //setenv ("LIBVIRT_LOG_FILTERS", ++ // "1:qemu 1:securit 3:file 3:event 3:object 1:util", 1); + snprintf (log_outputs, sizeof log_outputs, + "1:file:/dev/fd/%d", libvirt_pipe[1]); + setenv ("LIBVIRT_LOG_OUTPUTS", log_outputs, 1); +-- +1.8.3.1 + diff --git a/SOURCES/0060-p2v-Allow-p2v-kernel-options-to-override-GUI-configu.patch b/SOURCES/0060-p2v-Allow-p2v-kernel-options-to-override-GUI-configu.patch new file mode 100644 index 0000000..e14721b --- /dev/null +++ b/SOURCES/0060-p2v-Allow-p2v-kernel-options-to-override-GUI-configu.patch @@ -0,0 +1,228 @@ +From fe1e9ab849a7443907dd1968b34e89c58dba91f8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 18 Apr 2016 14:40:29 +0100 +Subject: [PATCH] p2v: Allow p2v kernel options to override GUI configuration + (RHBZ#1327488). + +Allow kernel options such as p2v.o=libvirt to override internal +defaults, even for GUI configuration. + +The main change is to split up the kernel conversion into two steps: +reading the kernel command line configuration, and performing the +conversion. The kernel command line can then be read by the main +program and used to initialize the config structure for either kernel +conversion or GUI conversion. + +A small adjustment is required in the test because p2v.pre no longer +runs before kernel command line parsing. (The aim is to have +p2v.pre/post/fail still only run when doing a kernel conversion, not +in the GUI case.) + +(cherry picked from commit fb74a275c1438e6e0569b7fea85d2a4841a07a4e) +--- + p2v/gui.c | 2 +- + p2v/kernel.c | 57 +++++++++++++++++++++++++++----------------- + p2v/main.c | 27 +++++++++++---------- + p2v/p2v.h | 5 ++-- + p2v/test-virt-p2v-cmdline.sh | 4 +--- + 5 files changed, 54 insertions(+), 41 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 569a295..015fa21 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -75,7 +75,7 @@ static GtkWidget *run_dlg, + * Note that gtk_init etc have already been called in main. + */ + void +-gui_application (struct config *config) ++gui_conversion (struct config *config) + { + /* Create the dialogs. */ + create_connection_dialog (config); +diff --git a/p2v/kernel.c b/p2v/kernel.c +index e904502..6d9388b 100644 +--- a/p2v/kernel.c ++++ b/p2v/kernel.c +@@ -38,18 +38,19 @@ static void notify_ui_callback (int type, const char *data); + static void run_command (int verbose, const char *stage, const char *command); + + void +-kernel_configuration (struct config *config, char **cmdline, int cmdline_source) ++update_config_from_kernel_cmdline (struct config *config, char **cmdline) + { + const char *p; + +- p = get_cmdline_key (cmdline, "p2v.pre"); ++ p = get_cmdline_key (cmdline, "p2v.debug"); + if (p) +- run_command (config->verbose, "p2v.pre", p); ++ config->verbose = 1; + + p = get_cmdline_key (cmdline, "p2v.server"); +- assert (p); /* checked by caller */ +- free (config->server); +- config->server = strdup (p); ++ if (p) { ++ free (config->server); ++ config->server = strdup (p); ++ } + + p = get_cmdline_key (cmdline, "p2v.port"); + if (p) { +@@ -83,21 +84,6 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source) + if (p) + config->sudo = 1; + +- /* We should now be able to connect and interrogate virt-v2v +- * on the conversion server. +- */ +- p = get_cmdline_key (cmdline, "p2v.skip_test_connection"); +- if (!p) { +- wait_network_online (config); +- if (test_connection (config) == -1) { +- const char *err = get_ssh_error (); +- +- fprintf (stderr, "%s: error opening control connection to %s:%d: %s\n", +- guestfs_int_program_name, config->server, config->port, err); +- exit (EXIT_FAILURE); +- } +- } +- + p = get_cmdline_key (cmdline, "p2v.name"); + if (p) { + free (config->guestname); +@@ -207,12 +193,39 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source) + config->output_storage = strdup (p); + } + +- /* Undocumented command line tool used for testing command line parsing. */ ++ /* Undocumented command line parameter used for testing command line ++ * parsing. ++ */ + p = get_cmdline_key (cmdline, "p2v.dump_config_and_exit"); + if (p) { + print_config (config, stdout); + exit (EXIT_SUCCESS); + } ++} ++ ++/* Perform conversion using the kernel method. */ ++void ++kernel_conversion (struct config *config, char **cmdline, int cmdline_source) ++{ ++ const char *p; ++ ++ /* Pre-conversion command. */ ++ p = get_cmdline_key (cmdline, "p2v.pre"); ++ if (p) ++ run_command (config->verbose, "p2v.pre", p); ++ ++ /* Connect to and interrogate virt-v2v on the conversion server. */ ++ p = get_cmdline_key (cmdline, "p2v.skip_test_connection"); ++ if (!p) { ++ wait_network_online (config); ++ if (test_connection (config) == -1) { ++ const char *err = get_ssh_error (); ++ ++ error (EXIT_FAILURE, 0, ++ "error opening control connection to %s:%d: %s", ++ config->server, config->port, err); ++ } ++ } + + /* Some disks must have been specified for conversion. */ + if (config->disks == NULL || guestfs_int_count_strings (config->disks) == 0) { +diff --git a/p2v/main.c b/p2v/main.c +index f037716..99da3e4 100644 +--- a/p2v/main.c ++++ b/p2v/main.c +@@ -191,25 +191,26 @@ main (int argc, char *argv[]) + + set_config_defaults (config); + +- /* If /proc/cmdline exists and contains "p2v.server=" then we enable +- * non-interactive configuration. +- * If /proc/cmdline contains p2v.debug then we enable verbose mode +- * even for interactive configuration. ++ /* Parse /proc/cmdline (if it exists) or use the --cmdline parameter ++ * to initialize the configuration. This allows defaults to be pass ++ * using the kernel command line, with additional GUI configuration ++ * later. + */ + if (cmdline == NULL) { + cmdline = parse_proc_cmdline (); +- if (cmdline == NULL) +- goto gui; +- cmdline_source = CMDLINE_SOURCE_PROC_CMDLINE; ++ if (cmdline != NULL) ++ cmdline_source = CMDLINE_SOURCE_PROC_CMDLINE; + } + +- if (get_cmdline_key (cmdline, "p2v.debug") != NULL) +- config->verbose = 1; ++ if (cmdline) ++ update_config_from_kernel_cmdline (config, cmdline); + +- if (get_cmdline_key (cmdline, "p2v.server") != NULL) +- kernel_configuration (config, cmdline, cmdline_source); ++ /* If p2v.server exists, then we use the non-interactive kernel ++ * conversion. Otherwise we run the GUI. ++ */ ++ if (config->server != NULL) ++ kernel_conversion (config, cmdline, cmdline_source); + else { +- gui: + if (!gui_possible) { + fprintf (stderr, + _("%s: gtk_init_check returned false, indicating that\n" +@@ -217,7 +218,7 @@ main (int argc, char *argv[]) + guestfs_int_program_name); + exit (EXIT_FAILURE); + } +- gui_application (config); ++ gui_conversion (config); + } + + guestfs_int_free_string_list (cmdline); +diff --git a/p2v/p2v.h b/p2v/p2v.h +index 097f294..9ccaf0f 100644 +--- a/p2v/p2v.h ++++ b/p2v/p2v.h +@@ -106,10 +106,11 @@ extern const char *get_cmdline_key (char **cmdline, const char *key); + #define CMDLINE_SOURCE_PROC_CMDLINE 2 /* /proc/cmdline */ + + /* kernel.c */ +-extern void kernel_configuration (struct config *, char **cmdline, int cmdline_source); ++extern void update_config_from_kernel_cmdline (struct config *config, char **cmdline); ++extern void kernel_conversion (struct config *, char **cmdline, int cmdline_source); + + /* gui.c */ +-extern void gui_application (struct config *); ++extern void gui_conversion (struct config *); + + /* conversion.c */ + extern int start_conversion (struct config *, void (*notify_ui) (int type, const char *data)); +diff --git a/p2v/test-virt-p2v-cmdline.sh b/p2v/test-virt-p2v-cmdline.sh +index bdd51d3..9629a05 100755 +--- a/p2v/test-virt-p2v-cmdline.sh ++++ b/p2v/test-virt-p2v-cmdline.sh +@@ -31,14 +31,12 @@ out=test-virt-p2v-cmdline.out + rm -f $out + + # The Linux kernel command line. +-virt-p2v --cmdline='p2v.pre="echo 1 2 3" p2v.server=localhost p2v.port=123 p2v.username=user p2v.password=secret p2v.skip_test_connection p2v.name=test p2v.vcpus=4 p2v.memory=1G p2v.disks=sda,sdb,sdc p2v.removable=sdd p2v.interfaces=eth0,eth1 p2v.o=local p2v.oa=sparse p2v.oc=qemu:///session p2v.of=raw p2v.os=/var/tmp p2v.network=em1:wired,other p2v.dump_config_and_exit' > $out ++virt-p2v --cmdline='p2v.server=localhost p2v.port=123 p2v.username=user p2v.password=secret p2v.skip_test_connection p2v.name=test p2v.vcpus=4 p2v.memory=1G p2v.disks=sda,sdb,sdc p2v.removable=sdd p2v.interfaces=eth0,eth1 p2v.o=local p2v.oa=sparse p2v.oc=qemu:///session p2v.of=raw p2v.os=/var/tmp p2v.network=em1:wired,other p2v.dump_config_and_exit' > $out + + # For debugging purposes. + cat $out + + # Check the output contains what we expect. +-grep "^echo 1 2 3" $out +-grep "^1 2 3" $out + grep "^conversion server.*localhost" $out + grep "^port.*123" $out + grep "^username.*user" $out +-- +1.8.3.1 + diff --git a/SOURCES/0060-p2v-Disable-Cancel-Conversion-button-after-the-conve.patch b/SOURCES/0060-p2v-Disable-Cancel-Conversion-button-after-the-conve.patch deleted file mode 100644 index a2e1d8a..0000000 --- a/SOURCES/0060-p2v-Disable-Cancel-Conversion-button-after-the-conve.patch +++ /dev/null @@ -1,31 +0,0 @@ -From c341b85dd47b4442d5c7377d6e34f5a4189eac4f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 16:01:09 +0000 -Subject: [PATCH] p2v: Disable "Cancel Conversion" button after the conversion - (RHBZ#1165569). - -Actually this bug does nothing and remains cancelled all the -way through. The next commit makes it function. - -(cherry picked from commit 98dd01728f61bd810f6c65a6b9e52d78365b96bd) ---- - p2v/gui.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/p2v/gui.c b/p2v/gui.c -index 72838ea..523b028 100644 ---- a/p2v/gui.c -+++ b/p2v/gui.c -@@ -1324,6 +1324,9 @@ start_conversion_thread (void *data) - gtk_widget_destroy (dlg); - } - -+ /* Disable the cancel button. */ -+ gtk_widget_set_sensitive (cancel_button, FALSE); -+ - /* Enable the reboot button. */ - gtk_widget_set_sensitive (reboot_button, TRUE); - --- -1.8.3.1 - diff --git a/SOURCES/0061-p2v-Make-the-Cancel-Conversion-button-work-RHBZ-1165.patch b/SOURCES/0061-p2v-Make-the-Cancel-Conversion-button-work-RHBZ-1165.patch deleted file mode 100644 index ec5a1e8..0000000 --- a/SOURCES/0061-p2v-Make-the-Cancel-Conversion-button-work-RHBZ-1165.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 34bc94a474600195a8f0bd5450a5d7523afb86ee Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 16:08:43 +0000 -Subject: [PATCH] p2v: Make the "Cancel Conversion" button work (RHBZ#1165569). - -This relies on the remote to keep sending us data. If it hangs, then -the cancel button won't work. This could also be fixed by introducing -a timeout to the read syscall. - -(cherry picked from commit 25b979a0c4a5942aaf62fcbe0e48d7526bd5e9b0) ---- - p2v/conversion.c | 15 ++++++++++++++- - p2v/gui.c | 12 +++++++++++- - p2v/p2v.h | 1 + - 3 files changed, 26 insertions(+), 2 deletions(-) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index 6f414de..cb2deed 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -86,6 +86,8 @@ get_conversion_error (void) - return conversion_error; - } - -+static volatile sig_atomic_t stop = 0; -+ - #pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn" - int - start_conversion (struct config *config, -@@ -271,7 +273,7 @@ start_conversion (struct config *config, - /* Read output from the virt-v2v process and echo it through the - * notify function, until virt-v2v closes the connection. - */ -- for (;;) { -+ while (!stop) { - char buf[257]; - ssize_t r; - -@@ -290,6 +292,11 @@ start_conversion (struct config *config, - notify_ui (NOTIFY_REMOTE_MESSAGE, buf); - } - -+ if (stop) { -+ set_conversion_error ("cancelled by user"); -+ goto out; -+ } -+ - if (notify_ui) - notify_ui (NOTIFY_STATUS, _("Control connection closed by remote.")); - -@@ -301,6 +308,12 @@ start_conversion (struct config *config, - return ret; - } - -+void -+cancel_conversion (void) -+{ -+ stop = 1; -+} -+ - /* Send a shell-quoted string to remote. */ - static int - send_quoted (mexp_h *h, const char *s) -diff --git a/p2v/gui.c b/p2v/gui.c -index 523b028..194f9fb 100644 ---- a/p2v/gui.c -+++ b/p2v/gui.c -@@ -1058,6 +1058,7 @@ static void set_log_dir (const char *remote_dir); - static void set_status (const char *msg); - static void add_v2v_output (const char *msg); - static void *start_conversion_thread (void *data); -+static void cancel_conversion_clicked (GtkWidget *w, gpointer data); - static void reboot_clicked (GtkWidget *w, gpointer data); - - static void -@@ -1105,6 +1106,8 @@ create_running_dialog (void) - /* Signals. */ - g_signal_connect_swapped (G_OBJECT (run_dlg), "destroy", - G_CALLBACK (gtk_main_quit), NULL); -+ g_signal_connect (G_OBJECT (cancel_button), "clicked", -+ G_CALLBACK (cancel_conversion_clicked), NULL); - g_signal_connect (G_OBJECT (reboot_button), "clicked", - G_CALLBACK (reboot_clicked), NULL); - } -@@ -1118,7 +1121,7 @@ show_running_dialog (void) - - /* Show the running dialog. */ - gtk_widget_show_all (run_dlg); -- gtk_widget_set_sensitive (cancel_button, FALSE); -+ gtk_widget_set_sensitive (cancel_button, TRUE); - gtk_widget_set_sensitive (reboot_button, FALSE); - } - -@@ -1364,6 +1367,13 @@ notify_ui_callback (int type, const char *data) - } - - static void -+cancel_conversion_clicked (GtkWidget *w, gpointer data) -+{ -+ /* This makes start_conversion return an error (eventually). */ -+ cancel_conversion (); -+} -+ -+static void - reboot_clicked (GtkWidget *w, gpointer data) - { - sync (); -diff --git a/p2v/p2v.h b/p2v/p2v.h -index 6067d5f..c3ca0f6 100644 ---- a/p2v/p2v.h -+++ b/p2v/p2v.h -@@ -97,6 +97,7 @@ extern int start_conversion (struct config *, void (*notify_ui) (int type, const - #define NOTIFY_REMOTE_MESSAGE 2 /* log message from remote virt-v2v */ - #define NOTIFY_STATUS 3 /* stage in conversion process */ - extern const char *get_conversion_error (void); -+extern void cancel_conversion (void); - - /* ssh.c */ - extern int test_connection (struct config *); --- -1.8.3.1 - diff --git a/SOURCES/0061-tests-boot-analysis-Add-text-to-describe-how-to-chan.patch b/SOURCES/0061-tests-boot-analysis-Add-text-to-describe-how-to-chan.patch new file mode 100644 index 0000000..014d635 --- /dev/null +++ b/SOURCES/0061-tests-boot-analysis-Add-text-to-describe-how-to-chan.patch @@ -0,0 +1,46 @@ +From 13fc1ca307552c6a71c3fa28c7c1fbc846cc65dc Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 22 Apr 2016 14:52:03 +0100 +Subject: [PATCH] tests: boot analysis: Add text to describe how to change + settings. + +(cherry picked from commit 45f84601b05aef0408b55011fb02579c147ca853) +--- + tests/qemu/boot-analysis-utils.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/tests/qemu/boot-analysis-utils.c b/tests/qemu/boot-analysis-utils.c +index 4ed2d48..693b6f4 100644 +--- a/tests/qemu/boot-analysis-utils.c ++++ b/tests/qemu/boot-analysis-utils.c +@@ -69,18 +69,22 @@ test_info (guestfs_h *g, int nr_test_passes) + + /* Related to qemu. */ + backend = guestfs_get_backend (g); +- printf (" backend: %s\n", backend); +- printf (" qemu: %s\n", qemu); ++ printf (" backend: %-20s [to change set LIBGUESTFS_BACKEND]\n", ++ backend); ++ printf (" qemu: %-20s [to change set $LIBGUESTFS_HV]\n", qemu); + printf ("qemu version: "); + fflush (stdout); + if (asprintf (&cmd, "%s -version", qemu) == -1) + error (EXIT_FAILURE, errno, "asprintf"); + ignore_value (system (cmd)); +- printf (" smp: %d\n", guestfs_get_smp (g)); +- printf (" memsize: %d\n", guestfs_get_memsize (g)); ++ printf (" smp: %-20d [to change use --smp option]\n", ++ guestfs_get_smp (g)); ++ printf (" memsize: %-20d [to change use --memsize option]\n", ++ guestfs_get_memsize (g)); + + /* Related to the guest kernel. Be nice to get the guest + * kernel version here somehow (XXX). + */ +- printf (" append: %s\n", guestfs_get_append (g) ? : ""); ++ printf (" append: %-20s [to change use --append option]\n", ++ guestfs_get_append (g) ? : ""); + } +-- +1.8.3.1 + diff --git a/SOURCES/0062-tests-Add-boot-benchmark-range-script.patch b/SOURCES/0062-tests-Add-boot-benchmark-range-script.patch new file mode 100644 index 0000000..6f6500c --- /dev/null +++ b/SOURCES/0062-tests-Add-boot-benchmark-range-script.patch @@ -0,0 +1,289 @@ +From 7b8c5efa52161bcd99006e7986c6cb67f6475023 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 22 Apr 2016 16:32:24 +0100 +Subject: [PATCH] tests: Add boot-benchmark-range script. + +Add a script we can use to benchmark performance across a range of +commits in another project. + +(cherry picked from commit 8299d7087a6457828a57ecace54c01b73912a9c7) +--- + docs/guestfs-performance.pod | 14 +++ + tests/qemu/boot-benchmark-range.pl | 240 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 254 insertions(+) + create mode 100755 tests/qemu/boot-benchmark-range.pl + +diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod +index cf30fdc..d9c76ac 100644 +--- a/docs/guestfs-performance.pod ++++ b/docs/guestfs-performance.pod +@@ -589,6 +589,20 @@ breakpoints, etc. Note that when you are past the BIOS and into the + Linux kernel, you'll want to change the architecture back to 32 or 64 + bit. + ++=head1 PERFORMANCE REGRESSIONS IN OTHER PROGRAMS ++ ++Sometimes performance regressions happen in other programs (eg. qemu, ++the kernel) that cause problems for libguestfs. ++ ++In the libguestfs source, F is a ++script which can be used to benchmark libguestfs across a range of git ++commits in another project to find out if any commit is causing a ++slowdown (or speedup). ++ ++To find out how to use this script, consult the manual: ++ ++ ./tests/qemu/boot-benchmark-range.pl --man ++ + =head1 SEE ALSO + + L, +diff --git a/tests/qemu/boot-benchmark-range.pl b/tests/qemu/boot-benchmark-range.pl +new file mode 100755 +index 0000000..0e31c4d +--- /dev/null ++++ b/tests/qemu/boot-benchmark-range.pl +@@ -0,0 +1,240 @@ ++#!/usr/bin/env perl ++# Copyright (C) 2016 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. ++ ++use warnings; ++use strict; ++ ++use Pod::Usage; ++use Getopt::Long; ++ ++=head1 NAME ++ ++boot-benchmark-range.pl - Benchmark libguestfs across a range of commits ++from another project ++ ++=head1 SYNOPSIS ++ ++ LIBGUESTFS_BACKEND=direct \ ++ LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \ ++ ./run \ ++ tests/qemu/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD ++ ++=head1 ++ ++Run F across a range of commits in another ++project. This is useful for finding performance regressions in other ++programs such as qemu or the Linux kernel which might be affecting ++libguestfs. ++ ++For example, suppose you suspect there has been a performance ++regression in qemu, somewhere between C. You could run ++the script like this: ++ ++ LIBGUESTFS_BACKEND=direct \ ++ LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \ ++ ./run \ ++ tests/qemu/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD ++ ++where F is the path to the qemu git repository. ++ ++The output is a list of the qemu commits, annotated by the benchmark ++time and some other information about how the time compares to the ++previous commit. ++ ++You should run these tests on an unloaded machine. In particular ++running a desktop environment, web browser and so on can make the ++benchmarks useless. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=cut ++ ++my $help; ++ ++=item B<--help> ++ ++Display brief help. ++ ++=cut ++ ++my $man; ++ ++=item B<--man> ++ ++Display full documentation (man page). ++ ++=cut ++ ++my $benchmark_command; ++ ++=item B<--benchmark> C ++ ++Set the name of the benchmark to run. You only need to use this if ++the script cannot find the right path to the libguestfs ++F program. By default the script looks for ++this file in the same directory as its executable. ++ ++=cut ++ ++my $make_command = "make"; ++ ++=item B<--make> C ++ ++Set the command used to build the other project. The default is ++to run C. ++ ++If the command fails, then the commit is skipped. ++ ++=back ++ ++=cut ++ ++# Clean up the program name. ++my $progname = $0; ++$progname =~ s{.*/}{}; ++ ++# Parse options. ++GetOptions ("help|?" => \$help, ++ "man" => \$man, ++ "benchmark=s" => \$benchmark_command, ++ "make=s" => \$make_command, ++ ) or pod2usage (2); ++pod2usage (-exitval => 0) if $help; ++pod2usage (-exitval => 0, -verbose => 2) if $man; ++ ++die "$progname: missing argument: requires path to git repository and range of commits\n" unless @ARGV == 2; ++ ++my $dir = $ARGV[0]; ++my $range = $ARGV[1]; ++ ++die "$progname: $dir is not a git repository\n" ++ unless -d $dir && -d "$dir/.git"; ++ ++sub silently_run ++{ ++ open my $saveout, ">&STDOUT"; ++ open my $saveerr, ">&STDERR"; ++ open STDOUT, ">/dev/null"; ++ open STDERR, ">/dev/null"; ++ my $ret = system (@_); ++ open STDOUT, ">&", $saveout; ++ open STDERR, ">&", $saveerr; ++ return $ret; ++} ++ ++# Find the benchmark program and check it works. ++unless (defined $benchmark_command) { ++ $benchmark_command = $0; ++ $benchmark_command =~ s{/[^/]+$}{}; ++ $benchmark_command .= "/boot-benchmark"; ++ ++ my $r = silently_run ("$benchmark_command", "--help"); ++ die "$progname: cannot locate boot-benchmark program, try using --benchmark\n" unless $r == 0; ++} ++ ++# Get the top-most commit from the remote, and restore it on exit. ++my $top_commit = `git -C '$dir' rev-parse HEAD`; ++chomp $top_commit; ++ ++sub checkout ++{ ++ my $sha = shift; ++ my $ret = silently_run ("git", "-C", $dir, "checkout", $sha); ++ return $ret; ++} ++ ++END { ++ checkout ($top_commit); ++} ++ ++# Get the range of commits and log messages. ++my @range = (); ++open RANGE, "git -C '$dir' log --reverse --oneline $range |" or die; ++while () { ++ if (m/^([0-9a-f]+) (.*)/) { ++ my $sha = $1; ++ my $msg = $2; ++ push @range, [ $sha, $msg ]; ++ } ++} ++close RANGE or die; ++ ++# Run the test. ++my $prev_ms; ++foreach (@range) { ++ my ($sha, $msg) = @$_; ++ my $r; ++ ++ print "\n"; ++ print "$sha $msg\n"; ++ ++ # Checkout this commit in the other repo. ++ $r = checkout ($sha); ++ if ($r != 0) { ++ print "git checkout failed\n"; ++ next; ++ } ++ ++ # Build the repo, silently. ++ $r = silently_run ("cd $dir && $make_command"); ++ if ($r != 0) { ++ print "build failed\n"; ++ next; ++ } ++ ++ # Run the benchmark program and get the timing. ++ my ($time_ms, $time_str); ++ open BENCHMARK, "$benchmark_command | grep '^Result:' |" or die; ++ while () { ++ die unless m/^Result: (([\d.]+)ms ±[\d.]+ms)/; ++ $time_ms = $2; ++ $time_str = $1; ++ } ++ close BENCHMARK; ++ ++ print "\t", $time_str; ++ if (defined $prev_ms) { ++ if ($prev_ms > $time_ms) { ++ my $pc = 100 * ($prev_ms-$time_ms) / $time_ms; ++ if ($pc >= 1) { ++ printf (" ↑ improves performance by %0.1f%%", $pc); ++ } ++ } elsif ($prev_ms < $time_ms) { ++ my $pc = 100 * ($time_ms-$prev_ms) / $prev_ms; ++ if ($pc >= 1) { ++ printf (" ↓ degrades performance by %0.1f%%", $pc); ++ } ++ } ++ } ++ print "\n"; ++ $prev_ms = $time_ms; ++} ++ ++=head1 SEE ALSO ++ ++L, ++L. ++ ++=head1 AUTHOR ++ ++Richard W.M. Jones. ++ ++=head1 COPYRIGHT ++ ++Copyright (C) 2016 Red Hat Inc. +-- +1.8.3.1 + diff --git a/SOURCES/0062-v2v-i-ova-Remove-incorrect-warning-for-disks-that-ha.patch b/SOURCES/0062-v2v-i-ova-Remove-incorrect-warning-for-disks-that-ha.patch deleted file mode 100644 index 3d4951e..0000000 --- a/SOURCES/0062-v2v-i-ova-Remove-incorrect-warning-for-disks-that-ha.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 73eba667462773247bdfdcaaaaffcb140353c491 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 24 Nov 2014 15:59:36 +0000 -Subject: [PATCH] v2v: -i ova: Remove incorrect warning for disks that have no - parent controller (RHBZ#1167302). - -Don't assume every disk has a field. For floppy disks -this is not the case. - -Thanks: Junqin Zhou -(cherry picked from commit 79fb3debc42b02a7104041f3279ab81bfff03b90) ---- - v2v/input_ova.ml | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index fe71039..43e1499 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -187,14 +187,17 @@ object - for i = 0 to nr_nodes-1 do - let n = Xml.xpathobj_node doc obj i in - Xml.xpathctx_set_current_context xpathctx n; -- let parent_id = xpath_to_int "rasd:Parent/text()" 0 in - - (* XXX We assume the OVF lists these in order. - let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in - *) - - (* Find the parent controller. *) -- let controller = parent_controller parent_id in -+ let parent_id = xpath_to_int "rasd:Parent/text()" 0 in -+ let controller = -+ match parent_id with -+ | 0 -> None -+ | id -> parent_controller id in - - Xml.xpathctx_set_current_context xpathctx n; - let file_id = xpath_to_string "rasd:HostResource/text()" "" in -@@ -255,14 +258,17 @@ object - Xml.xpathctx_set_current_context xpathctx n; - let id = xpath_to_int "rasd:ResourceType/text()" 0 in - assert (id = 14 || id = 15 || id = 16); -- let parent_id = xpath_to_int "rasd:Parent/text()" 0 in - - (* XXX We assume the OVF lists these in order. - let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in - *) - - (* Find the parent controller. *) -- let controller = parent_controller parent_id in -+ let parent_id = xpath_to_int "rasd:Parent/text()" 0 in -+ let controller = -+ match parent_id with -+ | 0 -> None -+ | id -> parent_controller id in - - let typ = - match id with --- -1.8.3.1 - diff --git a/SOURCES/0063-ntfsresize-Capture-errors-sent-to-stdout-RHBZ-116661.patch b/SOURCES/0063-ntfsresize-Capture-errors-sent-to-stdout-RHBZ-116661.patch deleted file mode 100644 index 9617fd3..0000000 --- a/SOURCES/0063-ntfsresize-Capture-errors-sent-to-stdout-RHBZ-116661.patch +++ /dev/null @@ -1,29 +0,0 @@ -From e871083162bb0f42931b8f218d98f370f6c017d4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 24 Nov 2014 10:56:57 +0000 -Subject: [PATCH] ntfsresize: Capture errors sent to stdout (RHBZ#1166618). - -ntfsresize sends error messages to stdout. Capture those error -messages. - -(cherry picked from commit dc845c9a6694dc7f06894e0df137176a4da73c66) ---- - daemon/ntfs.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemon/ntfs.c b/daemon/ntfs.c -index aef45a2..762ca88 100644 ---- a/daemon/ntfs.c -+++ b/daemon/ntfs.c -@@ -94,7 +94,7 @@ do_ntfsresize (const char *device, int64_t size, int force) - ADD_ARG (argv, i, device); - ADD_ARG (argv, i, NULL); - -- r = commandv (NULL, &err, argv); -+ r = commandvf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, argv); - if (r == -1) { - reply_with_error ("%s: %s", device, err); - return -1; --- -1.8.3.1 - diff --git a/SOURCES/0063-v2v-Move-target_bus_assignment-to-separate-module.patch b/SOURCES/0063-v2v-Move-target_bus_assignment-to-separate-module.patch new file mode 100644 index 0000000..d564406 --- /dev/null +++ b/SOURCES/0063-v2v-Move-target_bus_assignment-to-separate-module.patch @@ -0,0 +1,277 @@ +From ea4e7be22f84cadf9418f8d031ed7cc7f6914908 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 23 Apr 2016 18:15:19 +0100 +Subject: [PATCH] v2v: Move target_bus_assignment to separate module. + +This is just code motion. + +(cherry picked from commit 9e3182b4c5fc3abb55e0fe072c5fa3af1ffb0ee3) +--- + po/POTFILES-ml | 1 + + v2v/Makefile.am | 2 + + v2v/target_bus_assignment.ml | 91 +++++++++++++++++++++++++++++++++++++++++++ + v2v/target_bus_assignment.mli | 24 ++++++++++++ + v2v/v2v.ml | 79 ++----------------------------------- + 5 files changed, 121 insertions(+), 76 deletions(-) + create mode 100644 v2v/target_bus_assignment.ml + create mode 100644 v2v/target_bus_assignment.mli + +diff --git a/po/POTFILES-ml b/po/POTFILES-ml +index b94d616..b7f3cc2 100644 +--- a/po/POTFILES-ml ++++ b/po/POTFILES-ml +@@ -122,6 +122,7 @@ v2v/output_qemu.ml + v2v/output_rhev.ml + v2v/output_vdsm.ml + v2v/stringMap.ml ++v2v/target_bus_assignment.ml + v2v/test-harness/v2v_test_harness.ml + v2v/types.ml + v2v/utils.ml +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index d9cf986..2d52ab8 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -67,6 +67,7 @@ SOURCES_MLI = \ + output_vdsm.mli \ + OVF.mli \ + stringMap.mli \ ++ target_bus_assignment.mli \ + types.mli \ + utils.mli \ + vCenter.mli \ +@@ -105,6 +106,7 @@ SOURCES_ML = \ + output_rhev.ml \ + output_vdsm.ml \ + inspect_source.ml \ ++ target_bus_assignment.ml \ + cmdline.ml \ + v2v.ml + +diff --git a/v2v/target_bus_assignment.ml b/v2v/target_bus_assignment.ml +new file mode 100644 +index 0000000..b82915b +--- /dev/null ++++ b/v2v/target_bus_assignment.ml +@@ -0,0 +1,91 @@ ++(* virt-v2v ++ * Copyright (C) 2009-2016 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 Common_utils ++open Common_gettext.Gettext ++ ++open Types ++ ++(* XXX This doesn't do the right thing for PC legacy floppy devices. ++ * XXX This could handle slot assignment better when we have a mix of ++ * devices desiring their own slot, and others that don't care. Allocate ++ * the first group in the first pass, then the second group afterwards. ++ *) ++let rec target_bus_assignment source targets guestcaps = ++ let virtio_blk_bus = ref [| |] ++ and ide_bus = ref [| |] ++ and scsi_bus = ref [| |] in ++ ++ (* Add the fixed disks (targets) to either the virtio-blk or IDE bus, ++ * depending on whether the guest has virtio drivers or not. ++ *) ++ iteri ( ++ fun i t -> ++ let t = BusSlotTarget t in ++ match guestcaps.gcaps_block_bus with ++ | Virtio_blk -> insert virtio_blk_bus i t ++ | IDE -> insert ide_bus i t ++ ) targets; ++ ++ (* Now try to add the removable disks to the bus at the same slot ++ * they originally occupied, but if the slot is occupied, emit a ++ * a warning and insert the disk in the next empty slot in that bus. ++ *) ++ List.iter ( ++ fun r -> ++ let bus = match r.s_removable_controller with ++ | None -> ide_bus (* Wild guess, but should be safe. *) ++ | Some Source_virtio_blk -> virtio_blk_bus ++ | Some Source_IDE -> ide_bus ++ | Some Source_SCSI -> scsi_bus in ++ match r.s_removable_slot with ++ | None -> ignore (insert_after bus 0 (BusSlotRemovable r)) ++ | Some desired_slot_nr -> ++ if not (insert_after bus desired_slot_nr (BusSlotRemovable r)) then ++ warning (f_"removable %s device in slot %d clashes with another disk, so it has been moved to a higher numbered slot on the same bus. This may mean that this removable device has a different name inside the guest (for example a CD-ROM originally called /dev/hdc might move to /dev/hdd, or from D: to E: on a Windows guest).") ++ (match r.s_removable_type with ++ | CDROM -> s_"CD-ROM" ++ | Floppy -> s_"floppy disk") ++ desired_slot_nr ++ ) source.s_removables; ++ ++ { target_virtio_blk_bus = !virtio_blk_bus; ++ target_ide_bus = !ide_bus; ++ target_scsi_bus = !scsi_bus } ++ ++(* Insert a slot into the bus array, making the array bigger if necessary. *) ++and insert bus i slot = ++ let oldbus = !bus in ++ let oldlen = Array.length oldbus in ++ if i >= oldlen then ( ++ bus := Array.make (i+1) BusSlotEmpty; ++ Array.blit oldbus 0 !bus 0 oldlen ++ ); ++ Array.set !bus i slot ++ ++(* Insert a slot into the bus, but if the desired slot is not empty, then ++ * increment the slot number until we find an empty one. Returns ++ * true if we got the desired slot. ++ *) ++and insert_after bus i slot = ++ let len = Array.length !bus in ++ if i >= len || Array.get !bus i = BusSlotEmpty then ( ++ insert bus i slot; true ++ ) else ( ++ ignore (insert_after bus (i+1) slot); false ++ ) +diff --git a/v2v/target_bus_assignment.mli b/v2v/target_bus_assignment.mli +new file mode 100644 +index 0000000..6a30b2c +--- /dev/null ++++ b/v2v/target_bus_assignment.mli +@@ -0,0 +1,24 @@ ++(* virt-v2v ++ * Copyright (C) 2009-2016 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. ++ *) ++ ++(** Assign fixed and removable disks to target buses. ++ ++ Do this as best we can. This is not solvable for all guests, ++ but at least avoid overlapping disks (RHBZ#1238053). *) ++ ++val target_bus_assignment : Types.source -> Types.target list -> Types.guestcaps -> Types.target_buses +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index c73482b..f2f1cff 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -118,7 +118,9 @@ let rec main () = + get_target_firmware inspect guestcaps source output in + + message (f_"Assigning disks to buses"); +- let target_buses = target_bus_assignment source targets guestcaps in ++ let target_buses = ++ Target_bus_assignment.target_bus_assignment source targets ++ guestcaps in + debug "%s" (string_of_target_buses target_buses); + + let targets = +@@ -716,81 +718,6 @@ and actual_target_size target = + with Failure _ | Invalid_argument _ -> None in + { target with target_actual_size = size } + +-(* Assign fixed and removable disks to target buses, as best we can. +- * This is not solvable for all guests, but at least avoid overlapping +- * disks (RHBZ#1238053). +- * +- * XXX This doesn't do the right thing for PC legacy floppy devices. +- * XXX This could handle slot assignment better when we have a mix of +- * devices desiring their own slot, and others that don't care. Allocate +- * the first group in the first pass, then the second group afterwards. +- *) +-and target_bus_assignment source targets guestcaps = +- let virtio_blk_bus = ref [| |] +- and ide_bus = ref [| |] +- and scsi_bus = ref [| |] in +- +- (* Insert a slot into the bus array, making the array bigger if necessary. *) +- let insert bus i slot = +- let oldbus = !bus in +- let oldlen = Array.length oldbus in +- if i >= oldlen then ( +- bus := Array.make (i+1) BusSlotEmpty; +- Array.blit oldbus 0 !bus 0 oldlen +- ); +- Array.set !bus i slot +- in +- +- (* Insert a slot into the bus, but if the desired slot is not empty, then +- * increment the slot number until we find an empty one. Returns +- * true if we got the desired slot. +- *) +- let rec insert_after bus i slot = +- let len = Array.length !bus in +- if i >= len || Array.get !bus i = BusSlotEmpty then ( +- insert bus i slot; true +- ) else ( +- ignore (insert_after bus (i+1) slot); false +- ) +- in +- +- (* Add the fixed disks (targets) to either the virtio-blk or IDE bus, +- * depending on whether the guest has virtio drivers or not. +- *) +- iteri ( +- fun i t -> +- let t = BusSlotTarget t in +- match guestcaps.gcaps_block_bus with +- | Virtio_blk -> insert virtio_blk_bus i t +- | IDE -> insert ide_bus i t +- ) targets; +- +- (* Now try to add the removable disks to the bus at the same slot +- * they originally occupied, but if the slot is occupied, emit a +- * a warning and insert the disk in the next empty slot in that bus. +- *) +- List.iter ( +- fun r -> +- let bus = match r.s_removable_controller with +- | None -> ide_bus (* Wild guess, but should be safe. *) +- | Some Source_virtio_blk -> virtio_blk_bus +- | Some Source_IDE -> ide_bus +- | Some Source_SCSI -> scsi_bus in +- match r.s_removable_slot with +- | None -> ignore (insert_after bus 0 (BusSlotRemovable r)) +- | Some desired_slot_nr -> +- if not (insert_after bus desired_slot_nr (BusSlotRemovable r)) then +- warning (f_"removable %s device in slot %d clashes with another disk, so it has been moved to a higher numbered slot on the same bus. This may mean that this removable device has a different name inside the guest (for example a CD-ROM originally called /dev/hdc might move to /dev/hdd, or from D: to E: on a Windows guest).") +- (match r.s_removable_type with +- | CDROM -> s_"CD-ROM" +- | Floppy -> s_"floppy disk") +- desired_slot_nr +- ) source.s_removables; +- +- { target_virtio_blk_bus = !virtio_blk_bus; +- target_ide_bus = !ide_bus; +- target_scsi_bus = !scsi_bus } +- + (* Save overlays if --debug-overlays option was used. *) + and preserve_overlays overlays src_name = + let overlay_dir = (open_guestfs ())#get_cachedir () in +-- +1.8.3.1 + diff --git a/SOURCES/0064-v2v-Assert-fail-if-we-overwrite-an-existing-disk-in-.patch b/SOURCES/0064-v2v-Assert-fail-if-we-overwrite-an-existing-disk-in-.patch new file mode 100644 index 0000000..2ff5502 --- /dev/null +++ b/SOURCES/0064-v2v-Assert-fail-if-we-overwrite-an-existing-disk-in-.patch @@ -0,0 +1,30 @@ +From be941dc3b54a4ff176a08ffdb635f6998621bbda Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Apr 2016 11:33:28 +0100 +Subject: [PATCH] v2v: Assert fail if we overwrite an existing disk in a bus + slot. + +Prevents us from accidentally "losing" a disk during conversion. I +believe from code inspection that this assertion is always true for +the current code, so this should have no effect. + +(cherry picked from commit 6193b2b273f603bbe7b361d858e5b2fca0082ef6) +--- + v2v/target_bus_assignment.ml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/v2v/target_bus_assignment.ml b/v2v/target_bus_assignment.ml +index b82915b..eb3ed58 100644 +--- a/v2v/target_bus_assignment.ml ++++ b/v2v/target_bus_assignment.ml +@@ -76,6 +76,7 @@ and insert bus i slot = + bus := Array.make (i+1) BusSlotEmpty; + Array.blit oldbus 0 !bus 0 oldlen + ); ++ assert (!bus.(i) = BusSlotEmpty); + Array.set !bus i slot + + (* Insert a slot into the bus, but if the desired slot is not empty, then +-- +1.8.3.1 + diff --git a/SOURCES/0064-v2v-i-ova-Small-correction-to-warning-message.patch b/SOURCES/0064-v2v-i-ova-Small-correction-to-warning-message.patch deleted file mode 100644 index 07c466e..0000000 --- a/SOURCES/0064-v2v-i-ova-Small-correction-to-warning-message.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 3f1b598dc776761ed83153f60281aec7425c1ad9 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 25 Nov 2014 14:33:55 +0000 -Subject: [PATCH] v2v: -i ova: Small correction to warning message. - -Thanks: Pino Toscano - -(cherry picked from commit 7030635e51050514b8a597911c9b1f9077d89a56) ---- - v2v/input_ova.ml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 43e1499..1ab0320 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -170,10 +170,10 @@ object - | 6 -> Some `SCSI - | 5 -> Some `IDE - | 0 -> -- warning ~prog (f_"ova hard disk has no parent controller, please report this as a bug supplying the *.ovf file extracted from the ova"); -+ warning ~prog (f_"ova disk has no parent controller, please report this as a bug supplying the *.ovf file extracted from the ova"); - None - | _ -> -- warning ~prog (f_"ova hard disk has an unknown VMware controller type (%d), please report this as a bug supplying the *.ovf file extracted from the ova") -+ warning ~prog (f_"ova disk has an unknown VMware controller type (%d), please report this as a bug supplying the *.ovf file extracted from the ova") - controller; - None - in --- -1.8.3.1 - diff --git a/SOURCES/0065-typo-fix-preceeding-preceding.patch b/SOURCES/0065-typo-fix-preceeding-preceding.patch deleted file mode 100644 index 8238610..0000000 --- a/SOURCES/0065-typo-fix-preceeding-preceding.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 59dcbd1cfbd98a289aae5aa357195eb7fab18257 Mon Sep 17 00:00:00 2001 -From: Hu Tao -Date: Wed, 26 Nov 2014 18:10:06 +0800 -Subject: [PATCH] typo fix: preceeding -> preceding - -Signed-off-by: Hu Tao -(cherry picked from commit b6f6454678d8d4ae567259985e079feac56384ea) ---- - daemon/available.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemon/available.c b/daemon/available.c -index 7a8ede0..54c6b9b 100644 ---- a/daemon/available.c -+++ b/daemon/available.c -@@ -166,7 +166,7 @@ do_filesystem_available (const char *filesystem) - r = filesystem_available (filesystem); - if (r == -1) { - reply_with_error ("error testing for filesystem availability; " -- "enable verbose mode and look at preceeding output"); -+ "enable verbose mode and look at preceding output"); - return -1; - } - --- -1.8.3.1 - diff --git a/SOURCES/0065-v2v-target_bus_assignment-Various-refactorings.patch b/SOURCES/0065-v2v-target_bus_assignment-Various-refactorings.patch new file mode 100644 index 0000000..62689cd --- /dev/null +++ b/SOURCES/0065-v2v-target_bus_assignment-Various-refactorings.patch @@ -0,0 +1,83 @@ +From 6d2cf9eebf4bddbf868aae7e80a2a0f3b22c4545 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Apr 2016 11:36:20 +0100 +Subject: [PATCH] v2v: target_bus_assignment: Various refactorings. + +No functional change. + +(cherry picked from commit c1adbe61dfd23ba28e286e0ecaf97bba6de9cdcd) +--- + v2v/target_bus_assignment.ml | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/v2v/target_bus_assignment.ml b/v2v/target_bus_assignment.ml +index eb3ed58..0546004 100644 +--- a/v2v/target_bus_assignment.ml ++++ b/v2v/target_bus_assignment.ml +@@ -34,13 +34,16 @@ let rec target_bus_assignment source targets guestcaps = + (* Add the fixed disks (targets) to either the virtio-blk or IDE bus, + * depending on whether the guest has virtio drivers or not. + *) +- iteri ( +- fun i t -> +- let t = BusSlotTarget t in ++ let () = ++ let bus = + match guestcaps.gcaps_block_bus with +- | Virtio_blk -> insert virtio_blk_bus i t +- | IDE -> insert ide_bus i t +- ) targets; ++ | Virtio_blk -> virtio_blk_bus ++ | IDE -> ide_bus in ++ iteri ( ++ fun i t -> ++ let t = BusSlotTarget t in ++ insert bus i t ++ ) targets in + + (* Now try to add the removable disks to the bus at the same slot + * they originally occupied, but if the slot is occupied, emit a +@@ -48,15 +51,16 @@ let rec target_bus_assignment source targets guestcaps = + *) + List.iter ( + fun r -> ++ let t = BusSlotRemovable r in + let bus = match r.s_removable_controller with + | None -> ide_bus (* Wild guess, but should be safe. *) + | Some Source_virtio_blk -> virtio_blk_bus + | Some Source_IDE -> ide_bus + | Some Source_SCSI -> scsi_bus in + match r.s_removable_slot with +- | None -> ignore (insert_after bus 0 (BusSlotRemovable r)) ++ | None -> ignore (insert_after bus 0 t) + | Some desired_slot_nr -> +- if not (insert_after bus desired_slot_nr (BusSlotRemovable r)) then ++ if not (insert_after bus desired_slot_nr t) then + warning (f_"removable %s device in slot %d clashes with another disk, so it has been moved to a higher numbered slot on the same bus. This may mean that this removable device has a different name inside the guest (for example a CD-ROM originally called /dev/hdc might move to /dev/hdd, or from D: to E: on a Windows guest).") + (match r.s_removable_type with + | CDROM -> s_"CD-ROM" +@@ -77,16 +81,18 @@ and insert bus i slot = + Array.blit oldbus 0 !bus 0 oldlen + ); + assert (!bus.(i) = BusSlotEmpty); +- Array.set !bus i slot ++ !bus.(i) <- slot + + (* Insert a slot into the bus, but if the desired slot is not empty, then + * increment the slot number until we find an empty one. Returns + * true if we got the desired slot. + *) + and insert_after bus i slot = +- let len = Array.length !bus in +- if i >= len || Array.get !bus i = BusSlotEmpty then ( ++ if slot_is_empty bus i then ( + insert bus i slot; true + ) else ( + ignore (insert_after bus (i+1) slot); false + ) ++ ++(* Return true if slot i is empty in the bus. *) ++and slot_is_empty bus i = i >= Array.length !bus || !bus.(i) = BusSlotEmpty +-- +1.8.3.1 + diff --git a/SOURCES/0066-typo-fix-commmand-command.patch b/SOURCES/0066-typo-fix-commmand-command.patch deleted file mode 100644 index cf95579..0000000 --- a/SOURCES/0066-typo-fix-commmand-command.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 9b26f208ea3baa08511a5b79d3a4cbd666a806ea Mon Sep 17 00:00:00 2001 -From: Hu Tao -Date: Wed, 26 Nov 2014 18:10:07 +0800 -Subject: [PATCH] typo fix: commmand -> command - -Signed-off-by: Hu Tao -(cherry picked from commit dc1f15aa3e1e9be57334b36c95600a3c3e0c2c62) ---- - daemon/guestfsd.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c -index 3616f3a..181754d 100644 ---- a/daemon/guestfsd.c -+++ b/daemon/guestfsd.c -@@ -220,7 +220,7 @@ main (int argc, char *argv[]) - - if (verbose) { - if (cmdline) -- printf ("linux commmand line: %s\n", cmdline); -+ printf ("linux command line: %s\n", cmdline); - else - printf ("could not read linux command line\n"); - } --- -1.8.3.1 - diff --git a/SOURCES/0066-v2v-target_bus_assignment-Assign-removables-with-slo.patch b/SOURCES/0066-v2v-target_bus_assignment-Assign-removables-with-slo.patch new file mode 100644 index 0000000..73d905f --- /dev/null +++ b/SOURCES/0066-v2v-target_bus_assignment-Assign-removables-with-slo.patch @@ -0,0 +1,103 @@ +From 4bcb2ea57c7e06fe88306e34e1ae34caa4a563c4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Apr 2016 12:00:10 +0100 +Subject: [PATCH] v2v: target_bus_assignment: Assign removables with slot pref + first. + +(cherry picked from commit 672eff4a34a962293e3c3d6ac8b61d5abd28f747) +--- + v2v/target_bus_assignment.ml | 70 ++++++++++++++++++++++++++++---------------- + 1 file changed, 44 insertions(+), 26 deletions(-) + +diff --git a/v2v/target_bus_assignment.ml b/v2v/target_bus_assignment.ml +index 0546004..5ad8582 100644 +--- a/v2v/target_bus_assignment.ml ++++ b/v2v/target_bus_assignment.ml +@@ -21,11 +21,7 @@ open Common_gettext.Gettext + + open Types + +-(* XXX This doesn't do the right thing for PC legacy floppy devices. +- * XXX This could handle slot assignment better when we have a mix of +- * devices desiring their own slot, and others that don't care. Allocate +- * the first group in the first pass, then the second group afterwards. +- *) ++(* XXX This doesn't do the right thing for PC legacy floppy devices. *) + let rec target_bus_assignment source targets guestcaps = + let virtio_blk_bus = ref [| |] + and ide_bus = ref [| |] +@@ -45,28 +41,50 @@ let rec target_bus_assignment source targets guestcaps = + insert bus i t + ) targets in + +- (* Now try to add the removable disks to the bus at the same slot +- * they originally occupied, but if the slot is occupied, emit a +- * a warning and insert the disk in the next empty slot in that bus. ++ (* Now we have to assign the removable disks. These go in the ++ * same slot they originally occupied, except in two cases: (1) That ++ * slot is now occupied by a target disk, or (2) we don't ++ * have information about the original slot. In these cases ++ * insert the disk in the next empty slot in that bus. + *) +- List.iter ( +- fun r -> +- let t = BusSlotRemovable r in +- let bus = match r.s_removable_controller with +- | None -> ide_bus (* Wild guess, but should be safe. *) +- | Some Source_virtio_blk -> virtio_blk_bus +- | Some Source_IDE -> ide_bus +- | Some Source_SCSI -> scsi_bus in +- match r.s_removable_slot with +- | None -> ignore (insert_after bus 0 t) +- | Some desired_slot_nr -> +- if not (insert_after bus desired_slot_nr t) then +- warning (f_"removable %s device in slot %d clashes with another disk, so it has been moved to a higher numbered slot on the same bus. This may mean that this removable device has a different name inside the guest (for example a CD-ROM originally called /dev/hdc might move to /dev/hdd, or from D: to E: on a Windows guest).") +- (match r.s_removable_type with +- | CDROM -> s_"CD-ROM" +- | Floppy -> s_"floppy disk") +- desired_slot_nr +- ) source.s_removables; ++ ++ (* Split the removables into a list of devices that desire a ++ * particular slot, and those that don't care. Assign the first ++ * group first so they have a greater chance of getting the ++ * desired slot. ++ *) ++ let removables_desire, removables_no_desire = ++ List.partition ( ++ function ++ | { s_removable_slot = Some _ } -> true ++ | { s_removable_slot = None } -> false ++ ) source.s_removables in ++ ++ let assign_removables removables = ++ List.iter ( ++ fun r -> ++ let t = BusSlotRemovable r in ++ let bus = ++ match r.s_removable_controller with ++ | None -> ide_bus (* Wild guess, but should be safe. *) ++ | Some Source_virtio_blk -> virtio_blk_bus ++ | Some Source_IDE -> ide_bus ++ | Some Source_SCSI -> scsi_bus in ++ ++ match r.s_removable_slot with ++ | None -> ++ ignore (insert_after bus 0 t) ++ | Some desired_slot_nr -> ++ if not (insert_after bus desired_slot_nr t) then ++ warning (f_"removable %s device in slot %d clashes with another disk, so it has been moved to a higher numbered slot on the same bus. This may mean that this removable device has a different name inside the guest (for example a CD-ROM originally called /dev/hdc might move to /dev/hdd, or from D: to E: on a Windows guest).") ++ (match r.s_removable_type with ++ | CDROM -> s_"CD-ROM" ++ | Floppy -> s_"floppy disk") ++ desired_slot_nr ++ ) removables ++ in ++ assign_removables removables_desire; ++ assign_removables removables_no_desire; + + { target_virtio_blk_bus = !virtio_blk_bus; + target_ide_bus = !ide_bus; +-- +1.8.3.1 + diff --git a/SOURCES/0067-tests-Add-tests-qemu-boot-benchmark-range.pl-to-EXTR.patch b/SOURCES/0067-tests-Add-tests-qemu-boot-benchmark-range.pl-to-EXTR.patch new file mode 100644 index 0000000..91ab11a --- /dev/null +++ b/SOURCES/0067-tests-Add-tests-qemu-boot-benchmark-range.pl-to-EXTR.patch @@ -0,0 +1,27 @@ +From a52f3154da33115580953e5fc1abc0dfa062743e Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Apr 2016 19:00:03 +0100 +Subject: [PATCH] tests: Add tests/qemu/boot-benchmark-range.pl to EXTRA_DIST. + +Updates commit 8299d7087a6457828a57ecace54c01b73912a9c7. + +(cherry picked from commit 7f572434f0acc47b5091eb4fd12bd1936198bec8) +--- + tests/qemu/Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am +index fdf643f..f2171cd 100644 +--- a/tests/qemu/Makefile.am ++++ b/tests/qemu/Makefile.am +@@ -30,6 +30,7 @@ TESTS_ENVIRONMENT = $(top_builddir)/run --test + + EXTRA_DIST = \ + $(TESTS) \ ++ boot-benchmark-range.pl \ + qemu-boot.c \ + qemu-speed-test.c + +-- +1.8.3.1 + diff --git a/SOURCES/0067-v2v-Fix-command-line-help-output-for-no-trim-option.patch b/SOURCES/0067-v2v-Fix-command-line-help-output-for-no-trim-option.patch deleted file mode 100644 index 324df8b..0000000 --- a/SOURCES/0067-v2v-Fix-command-line-help-output-for-no-trim-option.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 89b5f3263f16a21a64b48cb361a9031d8980df71 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 27 Nov 2014 17:40:52 +0000 -Subject: [PATCH] v2v: Fix command line --help output for --no-trim option. - -(cherry picked from commit 196813ea7466c54d26f71ff1760b433bdc29c081) ---- - v2v/cmdline.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 69a627f..01f3335 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -159,7 +159,7 @@ let parse_cmdline () = - "-n", Arg.String add_network, "in:out " ^ s_"Map network 'in' to 'out'"; - "--network", Arg.String add_network, "in:out " ^ ditto; - "--no-copy", Arg.Clear do_copy, " " ^ s_"Just write the metadata"; -- "--no-trim", Arg.String set_no_trim, "all|mp,mp,.." ^ s_"Don't trim selected mounts"; -+ "--no-trim", Arg.String set_no_trim, "all|mp,mp,.." ^ " " ^ s_"Don't trim selected mounts"; - "-o", Arg.String set_output_mode, o_options ^ " " ^ s_"Set output mode (default: libvirt)"; - "-oa", Arg.String set_output_alloc, "sparse|preallocated " ^ s_"Set output allocation mode"; - "-oc", Arg.Set_string output_conn, "uri " ^ s_"Libvirt URI"; --- -1.8.3.1 - diff --git a/SOURCES/0068-p2v-kickstart-Name-the-ISO-virt-p2v.patch b/SOURCES/0068-p2v-kickstart-Name-the-ISO-virt-p2v.patch deleted file mode 100644 index 0f02f22..0000000 --- a/SOURCES/0068-p2v-kickstart-Name-the-ISO-virt-p2v.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 3b116d205d47388844ebc3cc1facfc5d91255b54 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Oct 2014 08:55:46 +0000 -Subject: [PATCH] p2v: kickstart: Name the ISO 'virt-p2v'. - -(cherry picked from commit 439bf5e42ac5396eed8911e2d2698ceb4603f0a8) ---- - p2v/virt-p2v-make-kickstart.pod | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/p2v/virt-p2v-make-kickstart.pod b/p2v/virt-p2v-make-kickstart.pod -index 8517313..a17c34c 100644 ---- a/p2v/virt-p2v-make-kickstart.pod -+++ b/p2v/virt-p2v-make-kickstart.pod -@@ -74,7 +74,7 @@ out usually, even to Fedora packagers. However assuming you have been - given these permissions (or have your own Koji instance, I guess), - then you can do: - -- koji spin-livecd [--scratch] p2v 1.XX.YY rawhide x86_64 p2v.ks -+ koji spin-livecd [--scratch] virt-p2v 1.XX.YY rawhide x86_64 p2v.ks - - =over 4 - --- -1.8.3.1 - diff --git a/SOURCES/0068-tests-qemu-boot-analysis-Add-analysis-of-initcalls-b.patch b/SOURCES/0068-tests-qemu-boot-analysis-Add-analysis-of-initcalls-b.patch new file mode 100644 index 0000000..4f83085 --- /dev/null +++ b/SOURCES/0068-tests-qemu-boot-analysis-Add-analysis-of-initcalls-b.patch @@ -0,0 +1,32 @@ +From 6143e307900ba1484c5768da05d98b88a83a8a1a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 28 Apr 2016 13:33:51 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Add analysis of initcalls before + entering userspace. + +(cherry picked from commit 606f1586064ed5b45b9d25dc9bf2e518dd910ba7) +--- + tests/qemu/boot-analysis-timeline.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/tests/qemu/boot-analysis-timeline.c b/tests/qemu/boot-analysis-timeline.c +index d35fb49..1c57d05 100644 +--- a/tests/qemu/boot-analysis-timeline.c ++++ b/tests/qemu/boot-analysis-timeline.c +@@ -296,6 +296,13 @@ construct_timeline (void) + strstr (data->events[j].message, "ftrace: allocating"), + 1); + ++ /* All initcall functions, before we enter userspace. */ ++ FIND ("kernel:initcalls-before-userspace", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "calling "), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Freeing unused kernel memory")); ++ + /* Find where we run supermin mini-initrd. */ + FIND ("supermin:mini-initrd", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +-- +1.8.3.1 + diff --git a/SOURCES/0069-p2v-kickstart-Add-firewalld-to-the-ISO-to-allow-fire.patch b/SOURCES/0069-p2v-kickstart-Add-firewalld-to-the-ISO-to-allow-fire.patch deleted file mode 100644 index caed441..0000000 --- a/SOURCES/0069-p2v-kickstart-Add-firewalld-to-the-ISO-to-allow-fire.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 511c72ef7e27db9c9bac650292347f42e354eca7 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Oct 2014 09:00:29 +0000 -Subject: [PATCH] p2v: kickstart: Add firewalld to the ISO to allow firewall to - be enabled. - -(cherry picked from commit c48114cd24d630ac66bd683c3593c33d43f712a6) ---- - p2v/p2v.ks.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/p2v/p2v.ks.in b/p2v/p2v.ks.in -index c21424f..077db04 100644 ---- a/p2v/p2v.ks.in -+++ b/p2v/p2v.ks.in -@@ -49,6 +49,9 @@ __REPOS__ - # Note you must have a kernel, else the boot menu won't work: - kernel - -+# Required to run firewall --enabled kickstart command: -+firewalld -+ - # Needed by post script to unpack the blobs. - /usr/bin/base64 - /usr/bin/gzip --- -1.8.3.1 - diff --git a/SOURCES/0069-tests-qemu-boot-analysis-Port-this-program-to-aarch6.patch b/SOURCES/0069-tests-qemu-boot-analysis-Port-this-program-to-aarch6.patch new file mode 100644 index 0000000..ac1523f --- /dev/null +++ b/SOURCES/0069-tests-qemu-boot-analysis-Port-this-program-to-aarch6.patch @@ -0,0 +1,136 @@ +From f86fc53b962ba7d6383561162ce5a96560dca7af Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 30 Apr 2016 12:45:54 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Port this program to aarch64 + (using UEFI). + +(cherry picked from commit d5c40262fa80cebcc48a73c04a22cf4a635dcb7b) +--- + tests/qemu/boot-analysis-timeline.c | 31 +++++++++++++++++++++++-------- + tests/qemu/boot-analysis.c | 4 ++-- + 2 files changed, 25 insertions(+), 10 deletions(-) + +diff --git a/tests/qemu/boot-analysis-timeline.c b/tests/qemu/boot-analysis-timeline.c +index 1c57d05..09a78ef 100644 +--- a/tests/qemu/boot-analysis-timeline.c ++++ b/tests/qemu/boot-analysis-timeline.c +@@ -216,60 +216,73 @@ construct_timeline (void) + data->events[k].source == GUESTFS_EVENT_LIBRARY && + strstr (data->events[k].message, "libvirt XML:")); + ++#if defined(__aarch64__) ++#define FIRST_KERNEL_MESSAGE "Booting Linux on physical CPU" ++#define FIRST_FIRMWARE_MESSAGE "UEFI firmware starting" ++#else + #define SGABIOS_STRING "\033[1;256r\033[256;256H\033[6n" ++#define FIRST_KERNEL_MESSAGE "Probing EDD" ++#define FIRST_FIRMWARE_MESSAGE SGABIOS_STRING ++#endif + + /* For the libvirt backend, find the overhead of libvirt. */ + FIND_OPTIONAL ("libvirt:overhead", 0, + data->events[j].source == GUESTFS_EVENT_LIBRARY && + strstr (data->events[j].message, "launch libvirt guest"), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, SGABIOS_STRING)); ++ strstr (data->events[k].message, FIRST_FIRMWARE_MESSAGE)); + + /* From starting qemu up to entering the BIOS is the qemu overhead. */ + FIND_OPTIONAL ("qemu:overhead", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, "-nodefconfig"), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, SGABIOS_STRING)); ++ strstr (data->events[k].message, FIRST_FIRMWARE_MESSAGE)); + + /* From entering the BIOS to starting the kernel is the BIOS overhead. */ + FIND_OPTIONAL ("bios:overhead", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, SGABIOS_STRING), ++ strstr (data->events[j].message, FIRST_FIRMWARE_MESSAGE), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Probing EDD")); ++ strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); + ++#if defined(__i386__) || defined(__x86_64__) + /* SGABIOS (option ROM). */ + FIND_OPTIONAL ("sgabios", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, SGABIOS_STRING), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[k].message, "SeaBIOS (version")); ++#endif + ++#if defined(__i386__) || defined(__x86_64__) + /* SeaBIOS. */ + FIND ("seabios", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, "SeaBIOS (version"), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Probing EDD")); ++ strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); ++#endif + ++#if defined(__i386__) || defined(__x86_64__) + /* SeaBIOS - only available when using debug messages. */ + FIND_OPTIONAL ("seabios:pci-probe", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, "Searching bootorder for: /pci@"), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[k].message, "Scan for option roms")); ++#endif + + /* Find where we run the guest kernel. */ + FIND ("kernel", LONG_ACTIVITY, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "Probing EDD"), ++ strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), + data->events[k].source == GUESTFS_EVENT_CLOSE); + + /* Kernel startup to userspace. */ + FIND ("kernel:overhead", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "Probing EDD"), ++ strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[k].message, "supermin:") && + strstr (data->events[k].message, "starting up")); +@@ -277,10 +290,11 @@ construct_timeline (void) + /* The time taken to get into start_kernel function. */ + FIND ("kernel:entry", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "Probing EDD"), ++ strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[k].message, "Linux version")); + ++#if defined(__i386__) || defined(__x86_64__) + /* Alternatives patching instructions (XXX not very accurate we + * really need some debug messages inserted into the code). + */ +@@ -289,6 +303,7 @@ construct_timeline (void) + strstr (data->events[j].message, "Last level dTLB entries"), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[k].message, "Freeing SMP alternatives")); ++#endif + + /* ftrace patching instructions. */ + FIND ("kernel:ftrace", 0, +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index 444226c..ace4653 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -235,8 +235,8 @@ main (int argc, char *argv[]) + + libvirt_log_hack (argc, argv); + +- if (STRNEQ (host_cpu, "x86_64")) +- fprintf (stderr, "WARNING: host_cpu != x86_64: This program may not work or give bogus results.\n"); ++ if (STRNEQ (host_cpu, "x86_64") && STRNEQ (host_cpu, "aarch64")) ++ fprintf (stderr, "WARNING: host_cpu != x86_64|aarch64: This program may not work or give bogus results.\n"); + + run_test (); + } +-- +1.8.3.1 + diff --git a/SOURCES/0070-p2v-kickstart-Remove-install-line.patch b/SOURCES/0070-p2v-kickstart-Remove-install-line.patch deleted file mode 100644 index fff15ac..0000000 --- a/SOURCES/0070-p2v-kickstart-Remove-install-line.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ece5b3cd9e10844dbf41c733a14de4cb17cd3d85 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Oct 2014 11:20:30 +0000 -Subject: [PATCH] p2v: kickstart: Remove 'install' line. - -'install' is the default operation, it doesn't have to be specified. - -(cherry picked from commit 26952db56ffab1bc93c7f57c43e785f62d44854f) ---- - p2v/p2v.ks.in | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/p2v/p2v.ks.in b/p2v/p2v.ks.in -index 077db04..4173975 100644 ---- a/p2v/p2v.ks.in -+++ b/p2v/p2v.ks.in -@@ -17,7 +17,6 @@ - - # Generated by virt-p2v-make-kickstart. - --install - lang en_US.UTF-8 - keyboard us - timezone --utc GMT --- -1.8.3.1 - diff --git a/SOURCES/0070-v2v-OVF-Better-mapping-for-inspection-data-to-vmtype.patch b/SOURCES/0070-v2v-OVF-Better-mapping-for-inspection-data-to-vmtype.patch new file mode 100644 index 0000000..fc9c868 --- /dev/null +++ b/SOURCES/0070-v2v-OVF-Better-mapping-for-inspection-data-to-vmtype.patch @@ -0,0 +1,108 @@ +From 165d9fbc3bb53daff1c1e1336610fba672a9412a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 26 Apr 2016 12:27:14 +0100 +Subject: [PATCH] v2v: OVF: Better mapping for inspection data to vmtype. + +The old mapping code was directly copied from old virt-v2v, translated +from Perl to OCaml. + +The new mapping code does a few things more accurately: + + - Use the i_product_variant field (Windows InstallationType) if available. + + - Simplify rules, so there is only one special case needed for RHEL 3/4. + + - Don't assume Fedora == Desktop. + + - Don't assume all later Windows variants are server. + + - Works for Windows > 7. + +(cherry picked from commit 5ec42a62384f87a4de841d202e31d0337c64f5af) +--- + v2v/OVF.ml | 61 ++++++++++++++++++++----------------------------------------- + 1 file changed, 20 insertions(+), 41 deletions(-) + +diff --git a/v2v/OVF.ml b/v2v/OVF.ml +index 8dc3fea..f1d8de5 100644 +--- a/v2v/OVF.ml ++++ b/v2v/OVF.ml +@@ -46,55 +46,34 @@ let iso_time = + * when the [--vmtype] parameter is NOT passed. + *) + let get_vmtype = function +- | { i_type = "linux"; i_distro = "rhel"; i_major_version = major; ++ (* Special cases for RHEL 3 & RHEL 4. *) ++ | { i_type = "linux"; i_distro = "rhel"; i_major_version = (3|4); + i_product_name = product } +- when major >= 5 && String.find product "Server" >= 0 -> +- Server ++ when String.find product "ES" >= 0 -> ++ Server + +- | { i_type = "linux"; i_distro = "rhel"; i_major_version = major } +- when major >= 5 -> +- Desktop +- +- | { i_type = "linux"; i_distro = "rhel"; i_major_version = major; +- i_product_name = product } +- when major >= 3 && String.find product "ES" >= 0 -> +- Server +- +- | { i_type = "linux"; i_distro = "rhel"; i_major_version = major; ++ | { i_type = "linux"; i_distro = "rhel"; i_major_version = (3|4); + i_product_name = product } +- when major >= 3 && String.find product "AS" >= 0 -> +- Server +- +- | { i_type = "linux"; i_distro = "rhel"; i_major_version = major } +- when major >= 3 -> +- Desktop +- +- | { i_type = "linux"; i_distro = "fedora" } -> Desktop +- +- | { i_type = "windows"; i_major_version = 5; i_minor_version = 1 } -> +- Desktop (* Windows XP *) +- +- | { i_type = "windows"; i_major_version = 5; i_minor_version = 2; +- i_product_name = product } when String.find product "XP" >= 0 -> +- Desktop (* Windows XP *) +- +- | { i_type = "windows"; i_major_version = 5; i_minor_version = 2 } -> +- Server (* Windows 2003 *) ++ when String.find product "AS" >= 0 -> ++ Server + +- | { i_type = "windows"; i_major_version = 6; i_minor_version = 0; +- i_product_name = product } when String.find product "Server" >= 0 -> +- Server (* Windows 2008 *) ++ | { i_type = "linux"; i_distro = "rhel"; i_major_version = (3|4) } -> ++ Desktop + +- | { i_type = "windows"; i_major_version = 6; i_minor_version = 0 } -> +- Desktop (* Vista *) ++ (* For Windows (and maybe Linux in future, but it is not set now), ++ * use the i_product_variant field. ++ *) ++ | { i_product_variant = ("Server"|"Server Core"|"Embedded") } -> Server ++ | { i_product_variant = "Client" } -> Desktop + +- | { i_type = "windows"; i_major_version = 6; i_minor_version = 1; +- i_product_name = product } when String.find product "Server" >= 0 -> +- Server (* Windows 2008R2 *) ++ (* If the product name has "Server" or "Desktop" in it, use that. *) ++ | { i_product_name = product } when String.find product "Server" >= 0 -> ++ Server + +- | { i_type = "windows"; i_major_version = 6; i_minor_version = 1 } -> +- Server (* Windows 7 *) ++ | { i_product_name = product } when String.find product "Desktop" >= 0 -> ++ Desktop + ++ (* Otherwise return server, a safe choice. *) + | _ -> Server + + (* Determine the ovf:OperatingSystemSection_Type from libguestfs +-- +1.8.3.1 + diff --git a/SOURCES/0071-launch-Disable-USB-in-the-appliance.patch b/SOURCES/0071-launch-Disable-USB-in-the-appliance.patch new file mode 100644 index 0000000..09b9d83 --- /dev/null +++ b/SOURCES/0071-launch-Disable-USB-in-the-appliance.patch @@ -0,0 +1,28 @@ +From 7aa71ddf263e09afdcb75013b8582aafd9ca00d4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 28 Apr 2016 14:12:23 +0100 +Subject: [PATCH] launch: Disable USB in the appliance. + +Only saves a tiny amount of time, but as we don't use USB +we might as well disable it. + +(cherry picked from commit 29cb8d60d25f650b077e631269ee05c3e4441d75) +--- + src/launch.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/launch.c b/src/launch.c +index 98eca07..9f5b14f 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -339,6 +339,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + " acpi=off" /* ACPI is slow - 150-200ms extra on my laptop */ + " printk.time=1" /* display timestamp before kernel messages */ + " cgroup_disable=memory" /* saves us about 5 MB of RAM */ ++ " usbcore.nousb" /* disable USB, only saves about 1ms */ + "%s" /* root=appliance_dev */ + " %s" /* selinux */ + " %s" /* quiet/verbose */ +-- +1.8.3.1 + diff --git a/SOURCES/0071-p2v-kickstart-Add-rpm-to-list-of-packages.patch b/SOURCES/0071-p2v-kickstart-Add-rpm-to-list-of-packages.patch deleted file mode 100644 index e28e1c4..0000000 --- a/SOURCES/0071-p2v-kickstart-Add-rpm-to-list-of-packages.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 19883e24c18210a4a483cabb0c3cdcaae55e1a3d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Oct 2014 11:21:08 +0000 -Subject: [PATCH] p2v: kickstart: Add rpm to list of packages. - -Avoids RHBZ#1089566. - -(cherry picked from commit 8efbe49df6d53666bd5a6031f45f45ceb1408fb8) ---- - p2v/p2v.ks.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/p2v/p2v.ks.in b/p2v/p2v.ks.in -index 4173975..9f55e18 100644 ---- a/p2v/p2v.ks.in -+++ b/p2v/p2v.ks.in -@@ -45,6 +45,9 @@ __REPOS__ - - @core - -+# rpm must be installed, else you'll hit RHBZ#1089566. -+rpm -+ - # Note you must have a kernel, else the boot menu won't work: - kernel - --- -1.8.3.1 - diff --git a/SOURCES/0072-launch-libvirt-Add-a-dev-urandom-based-virtio-rng-de.patch b/SOURCES/0072-launch-libvirt-Add-a-dev-urandom-based-virtio-rng-de.patch new file mode 100644 index 0000000..7bdc845 --- /dev/null +++ b/SOURCES/0072-launch-libvirt-Add-a-dev-urandom-based-virtio-rng-de.patch @@ -0,0 +1,63 @@ +From 3281d502733b198697bd076ae71d278c0e8b1912 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 28 Apr 2016 15:58:05 +0100 +Subject: [PATCH] launch: libvirt: Add a /dev/urandom-based virtio-rng device + to the appliance. + +It is safe to use /dev/urandom to seed the guest. In libvirt 1.3.4 +this silly restriction has been lifted. + +This restores commit b2c845333f66d4d3135d3b6a8d4b992d6160bf0a. +See also commit 9423c16607259b30985c46d04db9958ec079aa42. + +Thanks: Cole Robinson for doing the libvirt implementation. +(cherry picked from commit 2b9f58f87b0dc2553061b4d8b301ff8e08121cb7) +--- + src/launch-libvirt.c | 29 +++++++++++------------------ + 1 file changed, 11 insertions(+), 18 deletions(-) + +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index 96c5913..4c29409 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -1306,26 +1306,19 @@ construct_libvirt_xml_devices (guestfs_h *g, + } + #endif + +-#if 0 +- /* This is disabled. Pulling random numbers from /dev/random +- * causes the appliance to pause for long periods. We should +- * use /dev/urandom, but for bogus reasons libvirt prevents that. +- * https://bugzilla.redhat.com/show_bug.cgi?id=1074464#c7 ++ /* Add a random number generator (backend for virtio-rng). This ++ * requires Cole Robinson's patch to permit /dev/urandom to be ++ * used, which was added in libvirt 1.3.4. + */ +- /* Add a random number generator (backend for virtio-rng). */ +- start_element ("rng") { +- attribute ("model", "virtio"); +- start_element ("backend") { +- attribute ("model", "random"); +- /* It'd be nice to do this, but libvirt says: +- * file '/dev/urandom' is not a supported random source +- * Let libvirt pick /dev/random automatically instead. +- * See also: https://bugzilla.redhat.com/show_bug.cgi?id=1074464 +- */ +- //string ("/dev/urandom"); ++ if (params->data->libvirt_version >= 1003004) { ++ start_element ("rng") { ++ attribute ("model", "virtio"); ++ start_element ("backend") { ++ attribute ("model", "random"); ++ string ("/dev/urandom"); ++ } end_element (); + } end_element (); +- } end_element (); +-#endif ++ } + + /* virtio-scsi controller. */ + start_element ("controller") { +-- +1.8.3.1 + diff --git a/SOURCES/0072-p2v-Include-version-and-md5sum-in-kickstart.patch b/SOURCES/0072-p2v-Include-version-and-md5sum-in-kickstart.patch deleted file mode 100644 index f1ff815..0000000 --- a/SOURCES/0072-p2v-Include-version-and-md5sum-in-kickstart.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 4107d367a686622974660c1dc45bc8e40d50624d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 20 Nov 2014 22:22:49 +0000 -Subject: [PATCH] p2v: Include version and md5sum in kickstart. - -Include the version of virt-p2v and its MD5 checksum in the source -kickstart. This is useful for working out which version of virt-p2v -the kickstart corresponds to. - -(cherry picked from commit c64467a4c1a31de1134084a15a4acb841557140f) ---- - p2v/p2v.ks.in | 3 ++- - p2v/virt-p2v-make-kickstart.in | 3 +++ - 2 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/p2v/p2v.ks.in b/p2v/p2v.ks.in -index 9f55e18..26bb925 100644 ---- a/p2v/p2v.ks.in -+++ b/p2v/p2v.ks.in -@@ -15,7 +15,7 @@ - # along with this program; if not, write to the Free Software - # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - --# Generated by virt-p2v-make-kickstart. -+# Generated by virt-p2v-make-kickstart __PACKAGE_VERSION__. - - lang en_US.UTF-8 - keyboard us -@@ -102,6 +102,7 @@ EOF - systemctl enable p2v.service - - # Base64-decoding of virt-p2v binary -+# md5(virt-p2v) = __MD5SUM_VIRT_P2V__ - - base64 -d < __LIBEXECDIR__/virt-p2v - __BASE64_VIRT_P2V__ -diff --git a/p2v/virt-p2v-make-kickstart.in b/p2v/virt-p2v-make-kickstart.in -index a2937b3..22a4eaa 100644 ---- a/p2v/virt-p2v-make-kickstart.in -+++ b/p2v/virt-p2v-make-kickstart.in -@@ -97,6 +97,7 @@ base64_p2v_service="$(base64 $datadir/p2v.service)" - # virt-p2v binary is too large unless we strip it and compress it. - tmpfile="$(mktemp -u)" - cp $host_libexecdir/virt-p2v $tmpfile -+md5sum_virt_p2v="$(md5sum $tmpfile | @AWK@ '{print $1}')" - strip --strip-all $tmpfile - gzip -9 $tmpfile - base64_virt_p2v="$(base64 $tmpfile.gz)" -@@ -139,6 +140,7 @@ done - -v "base64_launch_virt_p2v=$base64_launch_virt_p2v" \ - -v "base64_p2v_service=$base64_p2v_service" \ - -v "base64_virt_p2v=$base64_virt_p2v" \ -+ -v "md5sum_virt_p2v=$md5sum_virt_p2v" \ - -v "repos=$repos" \ - -v "libexecdir=$libexecdir" \ - '{ -@@ -148,6 +150,7 @@ done - gsub (/__BASE64_LAUNCH_VIRT_P2V__/, base64_launch_virt_p2v); - gsub (/__BASE64_P2V_SERVICE__/, base64_p2v_service); - gsub (/__BASE64_VIRT_P2V__/, base64_virt_p2v); -+ gsub (/__MD5SUM_VIRT_P2V__/, md5sum_virt_p2v); - gsub (/__REPOS__/, repos); - gsub (/__LIBEXECDIR__/, libexecdir); - print; --- -1.8.3.1 - diff --git a/SOURCES/0073-launch-Don-t-initialize-all-UARTs-serial-ports.patch b/SOURCES/0073-launch-Don-t-initialize-all-UARTs-serial-ports.patch new file mode 100644 index 0000000..a3a134b --- /dev/null +++ b/SOURCES/0073-launch-Don-t-initialize-all-UARTs-serial-ports.patch @@ -0,0 +1,28 @@ +From d4a8bb04cc7fd7dbab6501e16b2f4d8a9a92acac Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 28 Apr 2016 22:37:04 +0100 +Subject: [PATCH] launch: Don't initialize all UARTs (serial ports). + +This doesn't save very much time, perhaps under 1ms, but it avoids +some useless scanning. + +(cherry picked from commit d76129aa0cca856994c1a65b55dc18d2a2049d34) +--- + src/launch.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/launch.c b/src/launch.c +index 9f5b14f..04b0e94 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -340,6 +340,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + " printk.time=1" /* display timestamp before kernel messages */ + " cgroup_disable=memory" /* saves us about 5 MB of RAM */ + " usbcore.nousb" /* disable USB, only saves about 1ms */ ++ " 8250.nr_uarts=1" /* don't scan all 8250 UARTS */ + "%s" /* root=appliance_dev */ + " %s" /* selinux */ + " %s" /* quiet/verbose */ +-- +1.8.3.1 + diff --git a/SOURCES/0073-p2v-Mention-sshd_config-setting-in-the-manual-page.patch b/SOURCES/0073-p2v-Mention-sshd_config-setting-in-the-manual-page.patch deleted file mode 100644 index 0f86e5c..0000000 --- a/SOURCES/0073-p2v-Mention-sshd_config-setting-in-the-manual-page.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 3ed08c2dbe46cf084b4865a5029b79fddcdcd780 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 29 Nov 2014 18:20:00 +0000 -Subject: [PATCH] p2v: Mention sshd_config setting in the manual page. - -The precise sshd configuration has confused some users of virt-p2v. -Only one setting (AllowTcpForwarding=yes) is required, so document it. - -(cherry picked from commit 1b52139339caaf8cdc347f05b559128b08fcee39) ---- - p2v/virt-p2v.pod | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod -index 6e7a77d..1ff1130 100644 ---- a/p2v/virt-p2v.pod -+++ b/p2v/virt-p2v.pod -@@ -53,7 +53,8 @@ during the conversion process. - - The reverse port forwarding feature of ssh (ie. C) is required - by virt-p2v, and it will not work if this is disabled on the --conversion server. -+conversion server. (C must be C in the -+L file on the conversion server). - - The conversion server does not need to be a physical machine. It - could be a virtual machine, as long as it has sufficient memory and -@@ -586,6 +587,8 @@ L, - L, - L, - L, -+L, -+L, - L. - - =head1 AUTHORS --- -1.8.3.1 - diff --git a/SOURCES/0074-appliance-Add-pciutils-to-the-appliance.patch b/SOURCES/0074-appliance-Add-pciutils-to-the-appliance.patch new file mode 100644 index 0000000..539652d --- /dev/null +++ b/SOURCES/0074-appliance-Add-pciutils-to-the-appliance.patch @@ -0,0 +1,28 @@ +From 6be1f908d1e39c702b35966c5617ace37a187d61 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 30 Apr 2016 12:48:42 +0100 +Subject: [PATCH] appliance: Add pciutils to the appliance. + +This adds the 'lspci' program, useful for debugging +appliance / qemu problems. + +(cherry picked from commit 03e2d000360ad4e496e8ce6c1b9b01086a2d2aac) +--- + appliance/packagelist.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/appliance/packagelist.in b/appliance/packagelist.in +index e93e5e8..6349922 100644 +--- a/appliance/packagelist.in ++++ b/appliance/packagelist.in +@@ -232,6 +232,7 @@ dnl Enabling this pulls out 140 extra packages + dnl into the appliance: + dnl ocfs2-tools + parted ++pciutils + procps + procps-ng + psmisc +-- +1.8.3.1 + diff --git a/SOURCES/0074-p2v-Refer-to-virt-v2v-resource-requirements-in-virt-.patch b/SOURCES/0074-p2v-Refer-to-virt-v2v-resource-requirements-in-virt-.patch deleted file mode 100644 index 6e7a164..0000000 --- a/SOURCES/0074-p2v-Refer-to-virt-v2v-resource-requirements-in-virt-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From d36f16809954ab7af7e2c9f0662abeda8d47ce98 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 29 Nov 2014 18:20:52 +0000 -Subject: [PATCH] p2v: Refer to virt-v2v resource requirements in virt-p2v man - page. - -(cherry picked from commit 391d90d9e7b86890c3de3cd5fc200375fb8c6b0a) ---- - p2v/virt-p2v.pod | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod -index 1ff1130..744e8d4 100644 ---- a/p2v/virt-p2v.pod -+++ b/p2v/virt-p2v.pod -@@ -59,7 +59,8 @@ L file on the conversion server). - The conversion server does not need to be a physical machine. It - could be a virtual machine, as long as it has sufficient memory and - disk space to do the conversion, and as long as the physical machine --can connect directly to its SSH port. -+can connect directly to its SSH port. (See also -+L). - - Because all of the data on the physical server's hard drive(s) has to - be copied over the network, the speed of conversion is largely --- -1.8.3.1 - diff --git a/SOURCES/0075-tests-qemu-boot-analysis-Dump-pass-data-times-in-ms-.patch b/SOURCES/0075-tests-qemu-boot-analysis-Dump-pass-data-times-in-ms-.patch new file mode 100644 index 0000000..4efbe60 --- /dev/null +++ b/SOURCES/0075-tests-qemu-boot-analysis-Dump-pass-data-times-in-ms-.patch @@ -0,0 +1,45 @@ +From 4248b89b10c88503e6a2c1e3a476571973b309d6 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 30 Apr 2016 16:02:30 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Dump pass data times in ms, with + diffs. + +When (in --verbose mode) we dump the pass data, dump the times in +milliseconds (instead of nanoseconds) so they are consistent with +other output. Also dump the time difference from the previous event. + +Useful for detailed debugging/analysis of problems. + +(cherry picked from commit 2fd05203e461445c8053116b4276beb81b4d95d8) +--- + tests/qemu/boot-analysis.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index ace4653..a203f94 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -863,12 +863,18 @@ dump_pass_data (void) + printf (" number of events collected %zu\n", pass_data[i].nr_events); + printf (" elapsed time %" PRIi64 " ns\n", pass_data[i].elapsed_ns); + for (j = 0; j < pass_data[i].nr_events; ++j) { +- int64_t ns; ++ int64_t ns, diff_ns; + CLEANUP_FREE char *event_str = NULL; + + ns = timespec_diff (&pass_data[i].start_t, &pass_data[i].events[j].t); + event_str = guestfs_event_to_string (pass_data[i].events[j].source); +- printf (" #%zu: +%" PRIi64 " [%s] \"", j, ns, event_str); ++ printf (" %.1fms ", ns / 1000000.0); ++ if (j > 0) { ++ diff_ns = timespec_diff (&pass_data[i].events[j-1].t, ++ &pass_data[i].events[j].t); ++ printf ("(+%.1f) ", diff_ns / 1000000.0); ++ } ++ printf ("[%s] \"", event_str); + print_escaped_string (pass_data[i].events[j].message); + printf ("\"\n"); + } +-- +1.8.3.1 + diff --git a/SOURCES/0075-v2v-Disable-autoreboot-when-converting-Windows-guest.patch b/SOURCES/0075-v2v-Disable-autoreboot-when-converting-Windows-guest.patch deleted file mode 100644 index 03c288b..0000000 --- a/SOURCES/0075-v2v-Disable-autoreboot-when-converting-Windows-guest.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 745cb07a0d0090283383a35656bd0af36c446377 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 4 Dec 2014 09:12:27 +0000 -Subject: [PATCH] v2v: Disable autoreboot when converting Windows guests. - -This allows users to see stop errors, so we can get an accurate report -when things go wrong. - -(cherry picked from commit 39d64121ec809076703b109053e12a3c91b9c2ea) ---- - v2v/convert_windows.ml | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml -index beca99c..1605a91 100644 ---- a/v2v/convert_windows.ml -+++ b/v2v/convert_windows.ml -@@ -191,6 +191,7 @@ echo uninstalling Xen PV driver - if verbose then printf "current ControlSet is %s\n%!" current_cs; - - disable_services root current_cs; -+ disable_autoreboot root current_cs; - install_virtio_drivers root current_cs - - and disable_services root current_cs = -@@ -212,6 +213,17 @@ echo uninstalling Xen PV driver - ) - ) disable - -+ and disable_autoreboot root current_cs = -+ (* If the guest reboots after a crash, it's hard to see the original -+ * error (eg. the infamous 0x0000007B). Turn off autoreboot. -+ *) -+ try -+ let crash_control = -+ get_node root [current_cs; "Control"; "CrashControl"] in -+ g#hivex_node_set_value crash_control "AutoReboot" 4_L (le32_of_int 0_L) -+ with -+ Not_found -> () -+ - and install_virtio_drivers root current_cs = - (* Copy the virtio drivers to the guest. *) - let driverdir = sprintf "%s/Drivers/VirtIO" systemroot in --- -1.8.3.1 - diff --git a/SOURCES/0076-mllib-Add-Common_utils.string_suffix-function-and-ex.patch b/SOURCES/0076-mllib-Add-Common_utils.string_suffix-function-and-ex.patch deleted file mode 100644 index 124e029..0000000 --- a/SOURCES/0076-mllib-Add-Common_utils.string_suffix-function-and-ex.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 91b771d57ef671253ce336d7ccb74e5c3ff08404 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 4 Dec 2014 22:00:35 +0000 -Subject: [PATCH] mllib: Add Common_utils.string_suffix function and extend - test coverage. - -(cherry picked from commit c712f880db640163a0ce913e42115ecf4f6aa0c2) ---- - mllib/common_utils.ml | 5 +++++ - mllib/common_utils.mli | 1 + - mllib/common_utils_tests.ml | 21 +++++++++++++++++++++ - 3 files changed, 27 insertions(+) - -diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml -index 295981c..7c64ad0 100644 ---- a/mllib/common_utils.ml -+++ b/mllib/common_utils.ml -@@ -98,6 +98,11 @@ let string_prefix str prefix = - let n = String.length prefix in - String.length str >= n && String.sub str 0 n = prefix - -+let string_suffix str suffix = -+ let sufflen = String.length suffix -+ and len = String.length str in -+ len >= sufflen && String.sub str (len - sufflen) sufflen = suffix -+ - let rec string_find s sub = - let len = String.length s in - let sublen = String.length sub in -diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli -index 112648a..6d0a0fc 100644 ---- a/mllib/common_utils.mli -+++ b/mllib/common_utils.mli -@@ -39,6 +39,7 @@ val output_spaces : out_channel -> int -> unit - (** Write [n] spaces to [out_channel]. *) - - val string_prefix : string -> string -> bool -+val string_suffix : string -> string -> bool - val string_find : string -> string -> int - val replace_str : string -> string -> string -> string - val string_nsplit : string -> string -> string list -diff --git a/mllib/common_utils_tests.ml b/mllib/common_utils_tests.ml -index e06b3a4..e12297a 100644 ---- a/mllib/common_utils_tests.ml -+++ b/mllib/common_utils_tests.ml -@@ -78,3 +78,24 @@ let () = - assert (human_size (-1363149_L) = "-1.3M"); - assert (human_size 3650722201_L = "3.4G"); - assert (human_size (-3650722201_L) = "-3.4G") -+ -+(* Test Common_utils.string_prefix, string_suffix, string_find. *) -+let () = -+ assert (string_prefix "" ""); -+ assert (string_prefix "foo" ""); -+ assert (string_prefix "foo" "foo"); -+ assert (string_prefix "foo123" "foo"); -+ assert (not (string_prefix "" "foo")); -+ -+ assert (string_suffix "" ""); -+ assert (string_suffix "foo" ""); -+ assert (string_suffix "foo" "foo"); -+ assert (string_suffix "123foo" "foo"); -+ assert (not (string_suffix "" "foo")); -+ -+ assert (string_find "" "" = 0); -+ assert (string_find "foo" "" = 0); -+ assert (string_find "foo" "o" = 1); -+ assert (string_find "foobar" "bar" = 3); -+ assert (string_find "" "baz" = -1); -+ assert (string_find "foobar" "baz" = -1) --- -1.8.3.1 - diff --git a/SOURCES/0076-tests-qemu-boot-analysis-Display-libvirt-as-distinct.patch b/SOURCES/0076-tests-qemu-boot-analysis-Display-libvirt-as-distinct.patch new file mode 100644 index 0000000..6173437 --- /dev/null +++ b/SOURCES/0076-tests-qemu-boot-analysis-Display-libvirt-as-distinct.patch @@ -0,0 +1,95 @@ +From 3c45504da7143d54820cf2b375ed151553c06a4c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 30 Apr 2016 16:41:31 +0100 +Subject: [PATCH] tests/qemu: boot-analysis: Display libvirt as distinct + source. + +Don't display libvirt events as '[library]', but as '[libvirt]'. + +(cherry picked from commit 9cd00805b06528f99c9a986195cc46b787541d11) +--- + tests/qemu/boot-analysis.c | 27 +++++++++++++++++++++++---- + tests/qemu/boot-analysis.h | 8 ++++++++ + 2 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +index a203f94..2067dfc 100644 +--- a/tests/qemu/boot-analysis.c ++++ b/tests/qemu/boot-analysis.c +@@ -781,7 +781,7 @@ libvirt_log_thread (void *arg) + pthread_mutex_lock (&pass_data_lock); + if (libvirt_pass == -1) goto discard; + event = +- add_event_unlocked (&pass_data[libvirt_pass], GUESTFS_EVENT_LIBRARY); ++ add_event_unlocked (&pass_data[libvirt_pass], SOURCE_LIBVIRT); + event->message = strndup (buf, r); + if (event->message == NULL) + error (EXIT_FAILURE, errno, "strndup"); +@@ -864,23 +864,42 @@ dump_pass_data (void) + printf (" elapsed time %" PRIi64 " ns\n", pass_data[i].elapsed_ns); + for (j = 0; j < pass_data[i].nr_events; ++j) { + int64_t ns, diff_ns; +- CLEANUP_FREE char *event_str = NULL; ++ CLEANUP_FREE char *source_str = NULL; + + ns = timespec_diff (&pass_data[i].start_t, &pass_data[i].events[j].t); +- event_str = guestfs_event_to_string (pass_data[i].events[j].source); ++ source_str = source_to_string (pass_data[i].events[j].source); + printf (" %.1fms ", ns / 1000000.0); + if (j > 0) { + diff_ns = timespec_diff (&pass_data[i].events[j-1].t, + &pass_data[i].events[j].t); + printf ("(+%.1f) ", diff_ns / 1000000.0); + } +- printf ("[%s] \"", event_str); ++ printf ("[%s] \"", source_str); + print_escaped_string (pass_data[i].events[j].message); + printf ("\"\n"); + } + } + } + ++/* Convert source to a printable string. The caller must free the ++ * returned string. ++ */ ++char * ++source_to_string (uint64_t source) ++{ ++ char *ret; ++ ++ if (source == SOURCE_LIBVIRT) { ++ ret = strdup ("libvirt"); ++ if (ret == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ } ++ else ++ ret = guestfs_event_to_string (source); ++ ++ return ret; /* caller frees */ ++} ++ + int + activity_exists (const char *name) + { +diff --git a/tests/qemu/boot-analysis.h b/tests/qemu/boot-analysis.h +index 86d403e..a07f12e 100644 +--- a/tests/qemu/boot-analysis.h ++++ b/tests/qemu/boot-analysis.h +@@ -46,6 +46,14 @@ struct pass_data { + int seen_launch; + }; + ++/* The 'source' field in the event is a guestfs event ++ * (GUESTFS_EVENT_*). We also wish to encode libvirt as a source, so ++ * we use a magic/impossible value for that here. Note that events ++ * are bitmasks, and normally no more than one bit may be set. ++ */ ++#define SOURCE_LIBVIRT ((uint64_t)~0) ++extern char *source_to_string (uint64_t source); ++ + struct event { + struct timespec t; + uint64_t source; +-- +1.8.3.1 + diff --git a/SOURCES/0077-launch-Add-cryptomgr.notests-to-the-appliance-comman.patch b/SOURCES/0077-launch-Add-cryptomgr.notests-to-the-appliance-comman.patch new file mode 100644 index 0000000..feadbd8 --- /dev/null +++ b/SOURCES/0077-launch-Add-cryptomgr.notests-to-the-appliance-comman.patch @@ -0,0 +1,27 @@ +From 9d72134f9b6c1b2391ee75973971f414eb2c83a1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 30 Apr 2016 12:49:00 +0100 +Subject: [PATCH] launch: Add cryptomgr.notests to the appliance command line. + +Save 28ms by not running the crypto self-tests when Linux boots. + +(cherry picked from commit c34995c6b3a60c78aefd12ad73f6c453a127a8ad) +--- + src/launch.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/launch.c b/src/launch.c +index 04b0e94..e7cb325 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -340,6 +340,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + " printk.time=1" /* display timestamp before kernel messages */ + " cgroup_disable=memory" /* saves us about 5 MB of RAM */ + " usbcore.nousb" /* disable USB, only saves about 1ms */ ++ " cryptomgr.notests" /* disable crypto tests, saves 28ms */ + " 8250.nr_uarts=1" /* don't scan all 8250 UARTS */ + "%s" /* root=appliance_dev */ + " %s" /* selinux */ +-- +1.8.3.1 + diff --git a/SOURCES/0077-v2v-When-picking-a-default-kernel-favour-non-debug-k.patch b/SOURCES/0077-v2v-When-picking-a-default-kernel-favour-non-debug-k.patch deleted file mode 100644 index 69034a7..0000000 --- a/SOURCES/0077-v2v-When-picking-a-default-kernel-favour-non-debug-k.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 1edc8185581110a862e17f74414b9caca17ffeb6 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 4 Dec 2014 09:13:23 +0000 -Subject: [PATCH] v2v: When picking a default kernel, favour non-debug kernels - over debug kernels (RHBZ#1170073). - -(cherry picked from commit 0c2e676f6c92efce890006903585dabd1f72f3b1) ---- - v2v/convert_linux.ml | 20 +++++++++++++++++--- - 1 file changed, 17 insertions(+), 3 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 6e45ac8..5852022 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -49,13 +49,14 @@ type kernel_info = { - ki_modules : string list; (* The list of module names. *) - ki_supports_virtio : bool; (* Kernel has virtio drivers? *) - ki_is_xen_kernel : bool; (* Is a Xen paravirt kernel? *) -+ ki_is_debug : bool; (* Is debug kernel? *) - } - - let string_of_kernel_info ki = -- sprintf "(%s, %s, %s, %s, %s, virtio=%b, xen=%b)" -+ sprintf "(%s, %s, %s, %s, %s, virtio=%b, xen=%b, debug=%b)" - ki.ki_name ki.ki_version ki.ki_arch ki.ki_vmlinuz - (match ki.ki_initrd with None -> "None" | Some f -> f) -- ki.ki_supports_virtio ki.ki_is_xen_kernel -+ ki.ki_supports_virtio ki.ki_is_xen_kernel ki.ki_is_debug - - (* The conversion function. *) - let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = -@@ -236,6 +237,13 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - let supports_virtio = List.mem "virtio_net" modules in - let is_xen_kernel = List.mem "xennet" modules in - -+ (* If the package name is like "kernel-debug", then it's -+ * a debug kernel. -+ *) -+ let is_debug = -+ string_suffix app.G.app2_name "-debug" || -+ string_suffix app.G.app2_name "-dbg" in -+ - Some { - ki_app = app; - ki_name = name; -@@ -248,6 +256,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - ki_modules = modules; - ki_supports_virtio = supports_virtio; - ki_is_xen_kernel = is_xen_kernel; -+ ki_is_debug = is_debug; - } - - with Not_found -> None -@@ -739,7 +748,12 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - let compare_best_kernels k1 k2 = - let i = compare k1.ki_supports_virtio k2.ki_supports_virtio in - if i <> 0 then i -- else compare_app2_versions k1.ki_app k2.ki_app -+ else ( -+ let i = compare_app2_versions k1.ki_app k2.ki_app in -+ if i <> 0 then i -+ (* Favour non-debug kernels over debug kernels (RHBZ#1170073). *) -+ else compare k2.ki_is_debug k1.ki_is_debug -+ ) - in - let kernels = grub_kernels in - let kernels = List.filter (fun { ki_is_xen_kernel = is_xen_kernel } -> not is_xen_kernel) kernels in --- -1.8.3.1 - diff --git a/SOURCES/0078-utils-Move-tests-qemu-boot-analysis-etc-tools-to-new.patch b/SOURCES/0078-utils-Move-tests-qemu-boot-analysis-etc-tools-to-new.patch new file mode 100644 index 0000000..351ace5 --- /dev/null +++ b/SOURCES/0078-utils-Move-tests-qemu-boot-analysis-etc-tools-to-new.patch @@ -0,0 +1,7329 @@ +From 5b03f23e01dfeb68846fcd280ba6ee9d4dd6113a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 3 May 2016 11:53:57 +0100 +Subject: [PATCH] utils: Move tests/qemu/ boot-analysis etc tools to new utils + top level directory. + +Create a new top level directory called 'utils' and move the +following programs there: + + tests/qemu/boot-analysis -> utils/boot-analysis/ + tests/qemu/boot-benchmark -> utils/boot-benchmark/ + tests/qemu/qemu-boot -> utils/qemu-boot/ + tests/qemu/qemu-speed-test -> utils/qemu-speed-test/ + +Also we only build the boot-analysis program on x86-64 and aarch64, +since it requires custom porting to each architecture. + +(cherry picked from commit 3b581a727c9e906f9d9b10e2f73ed853ab324fd0) +--- + .gitignore | 8 +- + Makefile.am | 9 + + configure.ac | 10 +- + docs/guestfs-hacking.pod | 4 + + docs/guestfs-performance.pod | 30 +- + m4/guestfs_misc.m4 | 28 + + po/POTFILES | 7 + + tests/qemu/Makefile.am | 87 +- + tests/qemu/boot-analysis-timeline.c | 523 ----------- + tests/qemu/boot-analysis-utils.c | 90 -- + tests/qemu/boot-analysis-utils.h | 36 - + tests/qemu/boot-analysis.c | 1269 -------------------------- + tests/qemu/boot-analysis.h | 102 --- + tests/qemu/boot-benchmark-range.pl | 240 ----- + tests/qemu/boot-benchmark.c | 225 ----- + tests/qemu/qemu-boot.c | 362 -------- + tests/qemu/qemu-speed-test.c | 480 ---------- + utils/boot-analysis/Makefile.am | 43 + + utils/boot-analysis/boot-analysis-timeline.c | 523 +++++++++++ + utils/boot-analysis/boot-analysis-utils.c | 90 ++ + utils/boot-analysis/boot-analysis-utils.h | 36 + + utils/boot-analysis/boot-analysis.c | 1268 +++++++++++++++++++++++++ + utils/boot-analysis/boot-analysis.h | 102 +++ + utils/boot-benchmark/Makefile.am | 44 + + utils/boot-benchmark/boot-benchmark-range.pl | 240 +++++ + utils/boot-benchmark/boot-benchmark.c | 225 +++++ + utils/qemu-boot/Makefile.am | 39 + + utils/qemu-boot/qemu-boot.c | 362 ++++++++ + utils/qemu-speed-test/Makefile.am | 36 + + utils/qemu-speed-test/qemu-speed-test.c | 480 ++++++++++ + 30 files changed, 3562 insertions(+), 3436 deletions(-) + create mode 100644 m4/guestfs_misc.m4 + delete mode 100644 tests/qemu/boot-analysis-timeline.c + delete mode 100644 tests/qemu/boot-analysis-utils.c + delete mode 100644 tests/qemu/boot-analysis-utils.h + delete mode 100644 tests/qemu/boot-analysis.c + delete mode 100644 tests/qemu/boot-analysis.h + delete mode 100755 tests/qemu/boot-benchmark-range.pl + delete mode 100644 tests/qemu/boot-benchmark.c + delete mode 100644 tests/qemu/qemu-boot.c + delete mode 100644 tests/qemu/qemu-speed-test.c + create mode 100644 utils/boot-analysis/Makefile.am + create mode 100644 utils/boot-analysis/boot-analysis-timeline.c + create mode 100644 utils/boot-analysis/boot-analysis-utils.c + create mode 100644 utils/boot-analysis/boot-analysis-utils.h + create mode 100644 utils/boot-analysis/boot-analysis.c + create mode 100644 utils/boot-analysis/boot-analysis.h + create mode 100644 utils/boot-benchmark/Makefile.am + create mode 100755 utils/boot-benchmark/boot-benchmark-range.pl + create mode 100644 utils/boot-benchmark/boot-benchmark.c + create mode 100644 utils/qemu-boot/Makefile.am + create mode 100644 utils/qemu-boot/qemu-boot.c + create mode 100644 utils/qemu-speed-test/Makefile.am + create mode 100644 utils/qemu-speed-test/qemu-speed-test.c + +diff --git a/.gitignore b/.gitignore +index 46a6e65..d79dc98 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -509,10 +509,6 @@ Makefile.in + /tests/mountable/test-internal-parse-mountable + /tests/parallel/test-parallel + /tests/protocol/test-error-messages +-/tests/qemu/boot-analysis +-/tests/qemu/boot-benchmark +-/tests/qemu/qemu-boot +-/tests/qemu/qemu-speed-test + /tests/regressions/rhbz501893 + /tests/regressions/rhbz790721 + /tests/regressions/rhbz914931 +@@ -561,6 +557,10 @@ Makefile.in + /test-tool/stamp-libguestfs-test-tool.pod + /tools/stamp-virt-*.pod + /tools/virt-*.1 ++/utils/boot-analysis/boot-analysis ++/utils/boot-benchmark/boot-benchmark ++/utils/qemu-boot/qemu-boot ++/utils/qemu-speed-test/qemu-speed-test + /v2v/.depend + /v2v/centos-6.img + /v2v/centos-7.0.img +diff --git a/Makefile.am b/Makefile.am +index c77fc34..079aa7d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -165,6 +165,15 @@ if HAVE_FUSE + SUBDIRS += fuse + endif + ++# Miscellaneous utilities. ++if HAVE_BOOT_ANALYSIS ++SUBDIRS += utils/boot-analysis ++endif ++SUBDIRS += \ ++ utils/boot-benchmark \ ++ utils/qemu-boot \ ++ utils/qemu-speed-test ++ + # po-docs must come after tools, inspector. + if HAVE_PO4A + SUBDIRS += po-docs +diff --git a/configure.ac b/configure.ac +index 6cef0a7..0bff74f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -124,10 +124,8 @@ m4_include([m4/guestfs_gobject.m4]) + dnl Bash completion. + m4_include([m4/guestfs_bash_completion.m4]) + +-dnl Replace libtool with a wrapper that clobbers dependency_libs in *.la files +-dnl http://lists.fedoraproject.org/pipermail/devel/2010-November/146343.html +-LIBTOOL='bash $(top_srcdir)/libtool-kill-dependency_libs.sh $(top_builddir)/libtool' +-AC_SUBST([LIBTOOL]) ++dnl Miscellaneous configuration that doesn't fit anywhere else. ++m4_include([m4/guestfs_misc.m4]) + + dnl Work around autoconf's lack of expanded variables. + eval my_sysconfdir="\"[$]sysconfdir\"" +@@ -283,6 +281,10 @@ AC_CONFIG_FILES([Makefile + tests/xfs/Makefile + tests/xml/Makefile + tools/Makefile ++ utils/boot-analysis/Makefile ++ utils/boot-benchmark/Makefile ++ utils/qemu-boot/Makefile ++ utils/qemu-speed-test/Makefile + v2v/Makefile + v2v/test-harness/Makefile + v2v/test-harness/META +diff --git a/docs/guestfs-hacking.pod b/docs/guestfs-hacking.pod +index 756c6f2..f2f8207 100644 +--- a/docs/guestfs-hacking.pod ++++ b/docs/guestfs-hacking.pod +@@ -694,6 +694,10 @@ created by another. + + Command line tools written in Perl (L and many others). + ++=item F ++ ++Miscellaneous utilities, such as C. ++ + =item F + + L command and documentation. +diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod +index d9c76ac..7304b63 100644 +--- a/docs/guestfs-performance.pod ++++ b/docs/guestfs-performance.pod +@@ -30,13 +30,13 @@ Run this command several times in a row and discard the first few + runs, so that you are measuring a typical "hot cache" case. + + I If you are compiling libguestfs from +-source, there is a program called F which +-does the same thing, but performs multiple runs and prints the mean +-and standard deviation. To run it, do: ++source, there is a program called ++F which does the same thing, but ++performs multiple runs and prints the mean and standard deviation. To ++run it, do: + + make +- make -C tests/qemu boot-benchmark +- ./run ./tests/qemu/boot-benchmark ++ ./run utils/boot-benchmark/boot-benchmark + + =head3 Explanation + +@@ -442,17 +442,16 @@ not available. + + =head2 Boot analysis + +-In the libguestfs source directory, in F is a program +-called C. This program is able to produce a very +-detailed breakdown of the boot steps (eg. qemu, BIOS, kernel, ++In the libguestfs source directory, in F is a ++program called C. This program is able to produce a ++very detailed breakdown of the boot steps (eg. qemu, BIOS, kernel, + libguestfs init script), and can measure how long it takes to perform + each step. + + To run this program, do: + + make +- make -C tests/qemu boot-analysis +- ./run ./tests/qemu/boot-analysis ++ ./run utils/boot-analysis/boot-analysis + + =head2 Detailed timings using ts + +@@ -594,14 +593,15 @@ bit. + Sometimes performance regressions happen in other programs (eg. qemu, + the kernel) that cause problems for libguestfs. + +-In the libguestfs source, F is a +-script which can be used to benchmark libguestfs across a range of git +-commits in another project to find out if any commit is causing a +-slowdown (or speedup). ++In the libguestfs source, ++F is a script which can ++be used to benchmark libguestfs across a range of git commits in ++another project to find out if any commit is causing a slowdown (or ++speedup). + + To find out how to use this script, consult the manual: + +- ./tests/qemu/boot-benchmark-range.pl --man ++ ./utils/boot-benchmark/boot-benchmark-range.pl --man + + =head1 SEE ALSO + +diff --git a/m4/guestfs_misc.m4 b/m4/guestfs_misc.m4 +new file mode 100644 +index 0000000..e6f4b05 +--- /dev/null ++++ b/m4/guestfs_misc.m4 +@@ -0,0 +1,28 @@ ++# libguestfs ++# Copyright (C) 2009-2016 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. ++ ++dnl Miscellaneous configuration that doesn't fit anywhere else. ++ ++dnl Replace libtool with a wrapper that clobbers dependency_libs in *.la files ++dnl http://lists.fedoraproject.org/pipermail/devel/2010-November/146343.html ++LIBTOOL='bash $(top_srcdir)/libtool-kill-dependency_libs.sh $(top_builddir)/libtool' ++AC_SUBST([LIBTOOL]) ++ ++dnl Only build boot-analysis program on x86-64 and aarch64. It ++dnl requires custom work to port to each architecture. ++AM_CONDITIONAL([HAVE_BOOT_ANALYSIS], ++ [test "$host_cpu" = "x86_64" || test "$host_cpu" = "aarch64"]) +diff --git a/po/POTFILES b/po/POTFILES +index a5f3f9e..ebee244 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -359,6 +359,13 @@ src/utils.c + src/wait.c + src/whole-file.c + test-tool/test-tool.c ++utils/boot-analysis/boot-analysis-timeline.c ++utils/boot-analysis/boot-analysis-utils.c ++utils/boot-analysis/boot-analysis.c ++utils/boot-benchmark/boot-benchmark-range.pl ++utils/boot-benchmark/boot-benchmark.c ++utils/qemu-boot/qemu-boot.c ++utils/qemu-speed-test/qemu-speed-test.c + v2v/changeuid-c.c + v2v/domainxml-c.c + v2v/utils-c.c +diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am +index f2171cd..472788a 100644 +--- a/tests/qemu/Makefile.am ++++ b/tests/qemu/Makefile.am +@@ -28,92 +28,7 @@ TESTS = \ + + TESTS_ENVIRONMENT = $(top_builddir)/run --test + +-EXTRA_DIST = \ +- $(TESTS) \ +- boot-benchmark-range.pl \ +- qemu-boot.c \ +- qemu-speed-test.c +- +-# qemu-boot, qemu-speed-test, boot-analysis and boot-benchmark are +-# built but not run by default as they are mainly qemu & kernel +-# diagnostic tools. +- +-check_PROGRAMS = qemu-boot qemu-speed-test boot-analysis boot-benchmark +- +-qemu_boot_SOURCES = \ +- ../../df/estimate-max-threads.c \ +- ../../df/estimate-max-threads.h \ +- qemu-boot.c +-qemu_boot_CPPFLAGS = \ +- -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ +- -I$(top_srcdir)/src -I$(top_builddir)/src \ +- -I$(top_srcdir)/df +-qemu_boot_CFLAGS = \ +- -pthread \ +- $(WARN_CFLAGS) $(WERROR_CFLAGS) +-qemu_boot_LDADD = \ +- $(top_builddir)/src/libutils.la \ +- $(top_builddir)/src/libguestfs.la \ +- $(LIBXML2_LIBS) \ +- $(LIBVIRT_LIBS) \ +- $(LTLIBINTL) \ +- $(top_builddir)/gnulib/lib/libgnu.la +- +-qemu_speed_test_SOURCES = \ +- qemu-speed-test.c +-qemu_speed_test_CPPFLAGS = \ +- -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ +- -I$(top_srcdir)/src -I$(top_builddir)/src \ +- -I$(top_srcdir)/df +-qemu_speed_test_CFLAGS = \ +- $(WARN_CFLAGS) $(WERROR_CFLAGS) +-qemu_speed_test_LDADD = \ +- $(top_builddir)/src/libutils.la \ +- $(top_builddir)/src/libguestfs.la \ +- $(LIBXML2_LIBS) \ +- $(LIBVIRT_LIBS) \ +- $(LTLIBINTL) \ +- $(top_builddir)/gnulib/lib/libgnu.la +- +-boot_analysis_SOURCES = \ +- boot-analysis.c \ +- boot-analysis.h \ +- boot-analysis-timeline.c \ +- boot-analysis-utils.c \ +- boot-analysis-utils.h +-boot_analysis_CPPFLAGS = \ +- -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ +- -I$(top_srcdir)/src -I$(top_builddir)/src +-boot_analysis_CFLAGS = \ +- -pthread \ +- $(WARN_CFLAGS) $(WERROR_CFLAGS) \ +- $(PCRE_CFLAGS) +-boot_analysis_LDADD = \ +- $(top_builddir)/src/libutils.la \ +- $(top_builddir)/src/libguestfs.la \ +- $(PCRE_LIBS) \ +- $(LIBXML2_LIBS) \ +- $(LIBVIRT_LIBS) \ +- $(LTLIBINTL) \ +- $(top_builddir)/gnulib/lib/libgnu.la \ +- -lm +- +-boot_benchmark_SOURCES = \ +- boot-benchmark.c \ +- boot-analysis-utils.c \ +- boot-analysis-utils.h +-boot_benchmark_CPPFLAGS = \ +- -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ +- -I$(top_srcdir)/src -I$(top_builddir)/src +-boot_benchmark_CFLAGS = \ +- $(WARN_CFLAGS) $(WERROR_CFLAGS) +-boot_benchmark_LDADD = \ +- $(top_builddir)/src/libutils.la \ +- $(top_builddir)/src/libguestfs.la \ +- $(LIBXML2_LIBS) \ +- $(LTLIBINTL) \ +- $(top_builddir)/gnulib/lib/libgnu.la \ +- -lm ++EXTRA_DIST = $(TESTS) + + # Don't run these tests in parallel, since they are designed to check + # the integrity of qemu. +diff --git a/tests/qemu/boot-analysis-timeline.c b/tests/qemu/boot-analysis-timeline.c +deleted file mode 100644 +index 09a78ef..0000000 +--- a/tests/qemu/boot-analysis-timeline.c ++++ /dev/null +@@ -1,523 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2016 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 +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include "ignore-value.h" +- +-#include "guestfs.h" +-#include "guestfs-internal-frontend.h" +- +-#include "boot-analysis.h" +- +-COMPILE_REGEXP(re_initcall_calling_module, +- "calling ([_A-Za-z0-9]+)\\+.*\\[([_A-Za-z0-9]+)]", 0) +-COMPILE_REGEXP(re_initcall_calling, +- "calling ([_A-Za-z0-9]+)\\+", 0) +- +-static void construct_initcall_timeline (void); +- +-/* "supermin: internal insmod xx.ko" -> "insmod xx.ko" */ +-static char * +-translate_supermin_insmod_message (const char *message) +-{ +- char *ret; +- +- assert (STRPREFIX (message, "supermin: internal ")); +- +- ret = strdup (message + strlen ("supermin: internal ")); +- if (ret == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +- return ret; +-} +- +-/* Analyze significant events from the events array, to form a +- * timeline of activities. +- */ +-void +-construct_timeline (void) +-{ +- size_t i, j, k; +- struct pass_data *data; +- struct activity *activity; +- +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- data = &pass_data[i]; +- +- /* Find an activity, by matching an event with the condition +- * `begin_cond' through to the second event `end_cond'. Create an +- * activity object in the timeline from the result. +- */ +-#define FIND(name, flags, begin_cond, end_cond) \ +- do { \ +- activity = NULL; \ +- for (j = 0; j < data->nr_events; ++j) { \ +- if (begin_cond) { \ +- for (k = j+1; k < data->nr_events; ++k) { \ +- if (end_cond) { \ +- if (i == 0) \ +- activity = add_activity (name, flags); \ +- else \ +- activity = find_activity (name); \ +- break; \ +- } \ +- } \ +- break; \ +- } \ +- } \ +- if (activity) { \ +- activity->start_event[i] = j; \ +- activity->end_event[i] = k; \ +- } \ +- else \ +- error (EXIT_FAILURE, 0, "could not find activity '%s' in pass '%zu'", \ +- name, i); \ +- } while (0) +- +- /* Same as FIND() macro, but if no matching events are found, +- * ignore it. +- */ +-#define FIND_OPTIONAL(name, flags, begin_cond, end_cond) \ +- do { \ +- activity = NULL; \ +- for (j = 0; j < data->nr_events; ++j) { \ +- if (begin_cond) { \ +- for (k = j+1; k < data->nr_events; ++k) { \ +- if (end_cond) { \ +- if (i == 0) \ +- activity = add_activity (name, flags); \ +- else \ +- activity = find_activity (name); \ +- break; \ +- } \ +- } \ +- break; \ +- } \ +- } \ +- if (activity) { \ +- activity->start_event[i] = j; \ +- activity->end_event[i] = k; \ +- } \ +- } while (0) +- +- /* Find multiple entries, where we check for: +- * next_cond +- * next_cond +- * next_cond +- * end_cond +- */ +-#define FIND_MULTIPLE(debug_name, flags, next_cond, end_cond, translate_message) \ +- do { \ +- activity = NULL; \ +- for (j = 0; j < data->nr_events; ++j) { \ +- if (next_cond) { \ +- CLEANUP_FREE char *message = translate_message (data->events[j].message); \ +- if (activity) \ +- activity->end_event[i] = j; \ +- if (i == 0) \ +- activity = add_activity (message, flags); \ +- else \ +- activity = find_activity (message); \ +- activity->start_event[i] = j; \ +- } \ +- else if (end_cond) \ +- break; \ +- } \ +- if (j < data->nr_events && activity) \ +- activity->end_event[i] = j; \ +- else \ +- error (EXIT_FAILURE, 0, "could not find activity '%s' in pass '%zu'", \ +- debug_name, i); \ +- } while (0) +- +- /* Add one activity which is going to cover the whole process +- * from launch to close. The launch event is always event 0. +- * NB: This activity must be called "run" (see below). +- */ +- FIND ("run", LONG_ACTIVITY, +- j == 0, data->events[k].source == GUESTFS_EVENT_CLOSE); +- +- /* Find where we invoke supermin --build. This should be a null +- * operation, but it still takes time to run the external command. +- */ +- FIND ("supermin:build", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, +- "begin building supermin appliance"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, +- "finished building supermin appliance")); +- +- /* Find where we invoke qemu to test features. */ +- FIND_OPTIONAL ("qemu:feature-detect", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, +- "begin testing qemu features"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, +- "finished testing qemu features")); +- +- /* Find where we run qemu. */ +- FIND_OPTIONAL ("qemu", LONG_ACTIVITY, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "-nodefconfig"), +- data->events[k].source == GUESTFS_EVENT_CLOSE); +- +- /* For the libvirt backend, connecting to libvirt, getting +- * capabilities, parsing capabilities etc. +- */ +- FIND_OPTIONAL ("libvirt:connect", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, "connect to libvirt"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, "successfully opened libvirt handle")); +- FIND_OPTIONAL ("libvirt:get-libvirt-capabilities", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, "get libvirt capabilities"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, "parsing capabilities XML")); +- +- FIND_OPTIONAL ("libguestfs:parse-libvirt-capabilities", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, "parsing capabilities XML"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, "get_backend_setting")); +- +- FIND_OPTIONAL ("libguestfs:create-libvirt-xml", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, "create libvirt XML"), +- data->events[k].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[k].message, "libvirt XML:")); +- +-#if defined(__aarch64__) +-#define FIRST_KERNEL_MESSAGE "Booting Linux on physical CPU" +-#define FIRST_FIRMWARE_MESSAGE "UEFI firmware starting" +-#else +-#define SGABIOS_STRING "\033[1;256r\033[256;256H\033[6n" +-#define FIRST_KERNEL_MESSAGE "Probing EDD" +-#define FIRST_FIRMWARE_MESSAGE SGABIOS_STRING +-#endif +- +- /* For the libvirt backend, find the overhead of libvirt. */ +- FIND_OPTIONAL ("libvirt:overhead", 0, +- data->events[j].source == GUESTFS_EVENT_LIBRARY && +- strstr (data->events[j].message, "launch libvirt guest"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, FIRST_FIRMWARE_MESSAGE)); +- +- /* From starting qemu up to entering the BIOS is the qemu overhead. */ +- FIND_OPTIONAL ("qemu:overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "-nodefconfig"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, FIRST_FIRMWARE_MESSAGE)); +- +- /* From entering the BIOS to starting the kernel is the BIOS overhead. */ +- FIND_OPTIONAL ("bios:overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_FIRMWARE_MESSAGE), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); +- +-#if defined(__i386__) || defined(__x86_64__) +- /* SGABIOS (option ROM). */ +- FIND_OPTIONAL ("sgabios", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, SGABIOS_STRING), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "SeaBIOS (version")); +-#endif +- +-#if defined(__i386__) || defined(__x86_64__) +- /* SeaBIOS. */ +- FIND ("seabios", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "SeaBIOS (version"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); +-#endif +- +-#if defined(__i386__) || defined(__x86_64__) +- /* SeaBIOS - only available when using debug messages. */ +- FIND_OPTIONAL ("seabios:pci-probe", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "Searching bootorder for: /pci@"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Scan for option roms")); +-#endif +- +- /* Find where we run the guest kernel. */ +- FIND ("kernel", LONG_ACTIVITY, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), +- data->events[k].source == GUESTFS_EVENT_CLOSE); +- +- /* Kernel startup to userspace. */ +- FIND ("kernel:overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "supermin:") && +- strstr (data->events[k].message, "starting up")); +- +- /* The time taken to get into start_kernel function. */ +- FIND ("kernel:entry", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Linux version")); +- +-#if defined(__i386__) || defined(__x86_64__) +- /* Alternatives patching instructions (XXX not very accurate we +- * really need some debug messages inserted into the code). +- */ +- FIND ("kernel:alternatives", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "Last level dTLB entries"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Freeing SMP alternatives")); +-#endif +- +- /* ftrace patching instructions. */ +- FIND ("kernel:ftrace", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "ftrace: allocating"), +- 1); +- +- /* All initcall functions, before we enter userspace. */ +- FIND ("kernel:initcalls-before-userspace", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "calling "), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Freeing unused kernel memory")); +- +- /* Find where we run supermin mini-initrd. */ +- FIND ("supermin:mini-initrd", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "supermin:") && +- strstr (data->events[j].message, "starting up"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "supermin: chroot")); +- +- /* Loading kernel modules from supermin initrd. */ +- FIND_MULTIPLE +- ("supermin insmod", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "supermin: internal insmod"), +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "supermin: picked"), +- translate_supermin_insmod_message); +- +- /* Find where we run the /init script. */ +- FIND ("/init", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "supermin: chroot"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "guestfsd --verbose")); +- +- /* Everything from the chroot to the first echo in the /init +- * script counts as bash overhead. +- */ +- FIND ("bash:overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "supermin: chroot"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Starting /init script")); +- +- /* /init: Mount special filesystems. */ +- FIND ("/init:mount-special", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "*guestfs_boot_analysis=1*"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "kmod static-nodes")); +- +- /* /init: Run kmod static-nodes */ +- FIND ("/init:kmod-static-nodes", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "kmod static-nodes"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "systemd-tmpfiles")); +- +- /* /init: systemd-tmpfiles. */ +- FIND ("/init:systemd-tmpfiles", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "systemd-tmpfiles"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "udev")); +- +- /* /init: start udevd. */ +- FIND ("/init:udev-overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "udevd --daemon"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "nullglob")); +- +- /* /init: set up network. */ +- FIND ("/init:network-overhead", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "+ ip addr"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "+ test")); +- +- /* /init: probe MD arrays. */ +- FIND ("/init:md-probe", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "+ mdadm"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "+ modprobe dm_mod")); +- +- /* /init: probe DM/LVM. */ +- FIND ("/init:lvm-probe", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "+ modprobe dm_mod"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "+ ldmtool")); +- +- /* /init: probe Windows dynamic disks. */ +- FIND ("/init:windows-dynamic-disks-probe", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "+ ldmtool"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "+ test")); +- +- /* Find where we run guestfsd. */ +- FIND ("guestfsd", 0, +- data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, "guestfsd --verbose"), +- data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "fsync /dev/sda")); +- +- /* Shutdown process. */ +- FIND ("shutdown", 0, +- data->events[j].source == GUESTFS_EVENT_TRACE && +- STREQ (data->events[j].message, "close"), +- data->events[k].source == GUESTFS_EVENT_CLOSE); +- } +- +- construct_initcall_timeline (); +-} +- +-/* Handling of initcall is so peculiar that we hide it in a separate +- * function from the rest. +- */ +-static void +-construct_initcall_timeline (void) +-{ +- size_t i, j, k; +- struct pass_data *data; +- struct activity *activity; +- +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- data = &pass_data[i]; +- +- /* Each kernel initcall is bracketed by: +- * +- * calling ehci_hcd_init+0x0/0xc1 @ 1" +- * initcall ehci_hcd_init+0x0/0xc1 returned 0 after 420 usecs" +- * +- * For initcall functions in modules: +- * +- * calling virtio_mmio_init+0x0/0x1000 [virtio_mmio] @ 1" +- * initcall virtio_mmio_init+0x0/0x1000 [virtio_mmio] returned 0 after 14 usecs" +- * +- * Initcall functions can be nested, and do not have unique names. +- */ +- for (j = 0; j < data->nr_events; ++j) { +- int vec[30], r; +- const char *message = data->events[j].message; +- +- if (data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- ((r = pcre_exec (re_initcall_calling_module, NULL, +- message, strlen (message), +- 0, 0, vec, sizeof vec / sizeof vec[0])) >= 1 || +- (r = pcre_exec (re_initcall_calling, NULL, +- message, strlen (message), +- 0, 0, vec, sizeof vec / sizeof vec[0])) >= 1)) { +- +- CLEANUP_FREE char *fn_name = NULL, *module_name = NULL; +- if (r >= 2) /* because pcre_exec returns 1 + number of captures */ +- fn_name = strndup (message + vec[2], vec[3]-vec[2]); +- if (r >= 3) +- module_name = strndup (message + vec[4], vec[5]-vec[4]); +- +- CLEANUP_FREE char *fullname; +- if (asprintf (&fullname, "%s.%s", +- module_name ? module_name : "kernel", fn_name) == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- +- CLEANUP_FREE char *initcall_match; +- if (asprintf (&initcall_match, "initcall %s", fn_name) == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- +- /* Get a unique name for this activity. Unfortunately +- * kernel initcall function names are not unique! +- */ +- CLEANUP_FREE char *activity_name; +- if (asprintf (&activity_name, "initcall %s", fullname) == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- +- if (i == 0) { +- int n = 1; +- while (activity_exists (activity_name)) { +- free (activity_name); +- if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- n++; +- } +- } +- else { +- int n = 1; +- while (!activity_exists_with_no_data (activity_name, i)) { +- free (activity_name); +- if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- n++; +- } +- } +- +- /* Find the matching end event. It might be some time later, +- * since it appears initcalls can be nested. +- */ +- for (k = j+1; k < data->nr_events; ++k) { +- if (data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, initcall_match)) { +- if (i == 0) +- activity = add_activity (activity_name, 0); +- else +- activity = find_activity (activity_name); +- activity->start_event[i] = j; +- activity->end_event[i] = k; +- break; +- } +- } +- } +- } +- } +-} +diff --git a/tests/qemu/boot-analysis-utils.c b/tests/qemu/boot-analysis-utils.c +deleted file mode 100644 +index 693b6f4..0000000 +--- a/tests/qemu/boot-analysis-utils.c ++++ /dev/null +@@ -1,90 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2016 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 +- +-#include +-#include +-#include +-#include +-#include +- +-#include "ignore-value.h" +- +-#include "guestfs.h" +-#include "guestfs-internal-frontend.h" +- +-#include "boot-analysis-utils.h" +- +-void +-get_time (struct timespec *ts) +-{ +- if (clock_gettime (CLOCK_REALTIME, ts) == -1) +- error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME"); +-} +- +-int64_t +-timespec_diff (const struct timespec *x, const struct timespec *y) +-{ +- int64_t nsec; +- +- nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000); +- nsec += y->tv_nsec - x->tv_nsec; +- return nsec; +-} +- +-void +-test_info (guestfs_h *g, int nr_test_passes) +-{ +- const char *qemu = guestfs_get_hv (g); +- CLEANUP_FREE char *cmd = NULL; +- CLEANUP_FREE char *backend = NULL; +- +- /* Related to the test program. */ +- printf ("test version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION_FULL); +- printf (" test passes: %d\n", nr_test_passes); +- +- /* Related to the host. */ +- printf ("host version: "); +- fflush (stdout); +- ignore_value (system ("uname -a")); +- printf (" host CPU: "); +- fflush (stdout); +- ignore_value (system ("perl -n -e 'if (/^model name.*: (.*)/) { print \"$1\\n\"; exit }' /proc/cpuinfo")); +- +- /* Related to qemu. */ +- backend = guestfs_get_backend (g); +- printf (" backend: %-20s [to change set LIBGUESTFS_BACKEND]\n", +- backend); +- printf (" qemu: %-20s [to change set $LIBGUESTFS_HV]\n", qemu); +- printf ("qemu version: "); +- fflush (stdout); +- if (asprintf (&cmd, "%s -version", qemu) == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- ignore_value (system (cmd)); +- printf (" smp: %-20d [to change use --smp option]\n", +- guestfs_get_smp (g)); +- printf (" memsize: %-20d [to change use --memsize option]\n", +- guestfs_get_memsize (g)); +- +- /* Related to the guest kernel. Be nice to get the guest +- * kernel version here somehow (XXX). +- */ +- printf (" append: %-20s [to change use --append option]\n", +- guestfs_get_append (g) ? : ""); +-} +diff --git a/tests/qemu/boot-analysis-utils.h b/tests/qemu/boot-analysis-utils.h +deleted file mode 100644 +index 95e4f06..0000000 +--- a/tests/qemu/boot-analysis-utils.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2016 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 GUESTFS_BOOT_ANALYSIS_UTILS_H_ +-#define GUESTFS_BOOT_ANALYSIS_UTILS_H_ +- +-/* Get current time, returning it in *ts. If there is a system call +- * failure, this exits. +- */ +-extern void get_time (struct timespec *ts); +- +-/* Computes Y - X, returning nanoseconds. */ +-extern int64_t timespec_diff (const struct timespec *x, const struct timespec *y); +- +-/* Display host machine and test parameters (to stdout). 'g' should +- * be an open libguestfs handle. It is used for reading hv, memsize +- * etc. and is not modified. +- */ +-extern void test_info (guestfs_h *g, int nr_test_passes); +- +-#endif /* GUESTFS_BOOT_ANALYSIS_UTILS_H_ */ +diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c +deleted file mode 100644 +index 2067dfc..0000000 +--- a/tests/qemu/boot-analysis.c ++++ /dev/null +@@ -1,1269 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2016 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. +- */ +- +-/* Trace and analyze the appliance boot process to find out which +- * steps are taking the most time. It is not part of the standard +- * tests. +- * +- * This needs to be run on a quiet machine, so that other processes +- * disturb the timing as little as possible. The program is +- * completely safe to run at any time. It doesn't read or write any +- * external files, and it doesn't require root. +- * +- * You can run it from the build directory like this: +- * +- * make +- * make -C tests/qemu boot-analysis +- * ./run tests/qemu/boot-analysis +- * +- * The way it works is roughly like this: +- * +- * We create a libguestfs handle and register callback handlers so we +- * can see appliance messages, trace events and so on. +- * +- * We then launch the handle and shut it down as quickly as possible. +- * +- * While the handle is running, events (seen by the callback handlers) +- * are written verbatim into an in-memory buffer, with timestamps. +- * +- * Afterwards we analyze the result using regular expressions to try +- * to identify a "timeline" for the handle (eg. at what time did the +- * BIOS hand control to the kernel). This analysis is done in +- * 'boot-analysis-timeline.c'. +- * +- * The whole process is repeated across a few runs, and the final +- * timeline (including statistical analysis of the variation between +- * runs) gets printed. +- * +- * The program is very sensitive to the specific messages printed by +- * BIOS/kernel/supermin/userspace, so it won't work on non-x86, and it +- * will require periodic adjustment of the regular expressions in +- * order to keep things up to date. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "guestfs.h" +-#include "guestfs-internal-frontend.h" +- +-#include "boot-analysis.h" +-#include "boot-analysis-utils.h" +- +-/* Activities taking longer than this % of the total time, except +- * those flagged as LONG_ACTIVITY, are highlighted in red. +- */ +-#define WARNING_THRESHOLD 1.0 +- +-static const char *append = NULL; +-static int force_colour = 0; +-static int memsize = 0; +-static int smp = 1; +-static int verbose = 0; +- +-static int libvirt_pipe[2] = { -1, -1 }; +-static ssize_t libvirt_pass = -1; +- +-/* Because there is a separate thread which collects libvirt log data, +- * we must protect the pass_data struct with a mutex. This only +- * applies during the data collection passes. +- */ +-static pthread_mutex_t pass_data_lock = PTHREAD_MUTEX_INITIALIZER; +-struct pass_data pass_data[NR_TEST_PASSES]; +- +-size_t nr_activities; +-struct activity *activities; +- +-static void run_test (void); +-static struct event *add_event (struct pass_data *, uint64_t source); +-static guestfs_h *create_handle (void); +-static void set_up_event_handlers (guestfs_h *g, size_t pass); +-static void libvirt_log_hack (int argc, char **argv); +-static void start_libvirt_thread (size_t pass); +-static void stop_libvirt_thread (void); +-static void add_drive (guestfs_h *g); +-static void check_pass_data (void); +-static void dump_pass_data (void); +-static void analyze_timeline (void); +-static void dump_timeline (void); +-static void print_analysis (void); +-static void print_longest_to_shortest (void); +-static void free_pass_data (void); +-static void free_final_timeline (void); +-static void ansi_green (void); +-static void ansi_red (void); +-static void ansi_blue (void); +-static void ansi_magenta (void); +-static void ansi_restore (void); +- +-static void +-usage (int exitcode) +-{ +- guestfs_h *g; +- int default_memsize = -1; +- +- g = guestfs_create (); +- if (g) { +- default_memsize = guestfs_get_memsize (g); +- guestfs_close (g); +- } +- +- fprintf (stderr, +- "boot-analysis: Trace and analyze the appliance boot process.\n" +- "Usage:\n" +- " boot-analysis [--options]\n" +- "Options:\n" +- " --help Display this usage text and exit.\n" +- " --append OPTS Append OPTS to kernel command line.\n" +- " --colour Output colours, even if not a terminal.\n" +- " -m MB\n" +- " --memsize MB Set memory size in MB (default: %d).\n" +- " --smp N Enable N virtual CPUs (default: 1).\n" +- " -v|--verbose Verbose output, useful for debugging.\n", +- default_memsize); +- exit (exitcode); +-} +- +-int +-main (int argc, char *argv[]) +-{ +- enum { HELP_OPTION = CHAR_MAX + 1 }; +- static const char *options = "m:v"; +- static const struct option long_options[] = { +- { "help", 0, 0, HELP_OPTION }, +- { "append", 1, 0, 0 }, +- { "color", 0, 0, 0 }, +- { "colour", 0, 0, 0 }, +- { "memsize", 1, 0, 'm' }, +- { "libvirt-pipe-0", 1, 0, 0 }, /* see libvirt_log_hack */ +- { "libvirt-pipe-1", 1, 0, 0 }, +- { "smp", 1, 0, 0 }, +- { "verbose", 0, 0, 'v' }, +- { 0, 0, 0, 0 } +- }; +- int c, option_index; +- +- for (;;) { +- c = getopt_long (argc, argv, options, long_options, &option_index); +- if (c == -1) break; +- +- switch (c) { +- case 0: /* Options which are long only. */ +- if (STREQ (long_options[option_index].name, "append")) { +- append = optarg; +- break; +- } +- else if (STREQ (long_options[option_index].name, "color") || +- STREQ (long_options[option_index].name, "colour")) { +- force_colour = 1; +- break; +- } +- else if (STREQ (long_options[option_index].name, "libvirt-pipe-0")) { +- if (sscanf (optarg, "%d", &libvirt_pipe[0]) != 1) +- error (EXIT_FAILURE, 0, +- "could not parse libvirt-pipe-0 parameter: %s", optarg); +- break; +- } +- else if (STREQ (long_options[option_index].name, "libvirt-pipe-1")) { +- if (sscanf (optarg, "%d", &libvirt_pipe[1]) != 1) +- error (EXIT_FAILURE, 0, +- "could not parse libvirt-pipe-1 parameter: %s", optarg); +- break; +- } +- else if (STREQ (long_options[option_index].name, "smp")) { +- if (sscanf (optarg, "%d", &smp) != 1) +- error (EXIT_FAILURE, 0, +- "could not parse smp parameter: %s", optarg); +- break; +- } +- fprintf (stderr, "%s: unknown long option: %s (%d)\n", +- guestfs_int_program_name, long_options[option_index].name, option_index); +- exit (EXIT_FAILURE); +- +- case 'm': +- if (sscanf (optarg, "%d", &memsize) != 1) { +- fprintf (stderr, "%s: could not parse memsize parameter: %s\n", +- guestfs_int_program_name, optarg); +- exit (EXIT_FAILURE); +- } +- break; +- +- case 'v': +- verbose = 1; +- break; +- +- case HELP_OPTION: +- usage (EXIT_SUCCESS); +- +- default: +- usage (EXIT_FAILURE); +- } +- } +- +- libvirt_log_hack (argc, argv); +- +- if (STRNEQ (host_cpu, "x86_64") && STRNEQ (host_cpu, "aarch64")) +- fprintf (stderr, "WARNING: host_cpu != x86_64|aarch64: This program may not work or give bogus results.\n"); +- +- run_test (); +-} +- +-static void +-run_test (void) +-{ +- guestfs_h *g; +- size_t i; +- +- printf ("Warming up the libguestfs cache ...\n"); +- for (i = 0; i < NR_WARMUP_PASSES; ++i) { +- g = create_handle (); +- add_drive (g); +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- guestfs_close (g); +- } +- +- printf ("Running the tests in %d passes ...\n", NR_TEST_PASSES); +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- g = create_handle (); +- set_up_event_handlers (g, i); +- start_libvirt_thread (i); +- add_drive (g); +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- guestfs_close (g); +- stop_libvirt_thread (); +- +- printf (" pass %zu: %zu events collected in %" PRIi64 " ns\n", +- i+1, pass_data[i].nr_events, pass_data[i].elapsed_ns); +- } +- +- if (verbose) +- dump_pass_data (); +- +- printf ("Analyzing the results ...\n"); +- check_pass_data (); +- construct_timeline (); +- analyze_timeline (); +- +- if (verbose) +- dump_timeline (); +- +- printf ("\n"); +- g = create_handle (); +- test_info (g, NR_TEST_PASSES); +- guestfs_close (g); +- printf ("\n"); +- print_analysis (); +- printf ("\n"); +- printf ("Longest activities:\n"); +- printf ("\n"); +- print_longest_to_shortest (); +- +- free_pass_data (); +- free_final_timeline (); +-} +- +-static struct event * +-add_event_unlocked (struct pass_data *data, uint64_t source) +-{ +- struct event *ret; +- +- data->nr_events++; +- data->events = realloc (data->events, +- sizeof (struct event) * data->nr_events); +- if (data->events == NULL) +- error (EXIT_FAILURE, errno, "realloc"); +- ret = &data->events[data->nr_events-1]; +- get_time (&ret->t); +- ret->source = source; +- ret->message = NULL; +- return ret; +-} +- +-static struct event * +-add_event (struct pass_data *data, uint64_t source) +-{ +- struct event *ret; +- +- pthread_mutex_lock (&pass_data_lock); +- ret = add_event_unlocked (data, source); +- pthread_mutex_unlock (&pass_data_lock); +- return ret; +-} +- +-/* Common function to create the handle and set various defaults. */ +-static guestfs_h * +-create_handle (void) +-{ +- guestfs_h *g; +- CLEANUP_FREE char *full_append = NULL; +- +- g = guestfs_create (); +- if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); +- +- if (memsize != 0) +- if (guestfs_set_memsize (g, memsize) == -1) +- exit (EXIT_FAILURE); +- +- if (smp >= 2) +- if (guestfs_set_smp (g, smp) == -1) +- exit (EXIT_FAILURE); +- +- /* This changes some details in appliance/init and enables a +- * detailed trace of calls to initcall functions in the kernel. +- */ +- if (asprintf (&full_append, +- "guestfs_boot_analysis=1 " +- "ignore_loglevel initcall_debug " +- "%s", +- append != NULL ? append : "") == -1) +- error (EXIT_FAILURE, errno, "asprintf"); +- +- if (guestfs_set_append (g, full_append) == -1) +- exit (EXIT_FAILURE); +- +- return g; +-} +- +-/* Common function to add the /dev/null drive. */ +-static void +-add_drive (guestfs_h *g) +-{ +- if (guestfs_add_drive_opts (g, "/dev/null", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, +- -1) == -1) +- exit (EXIT_FAILURE); +-} +- +-/* Called when the handle is closed. Perform any cleanups required in +- * the pass_data here. +- */ +-static void +-close_callback (guestfs_h *g, void *datavp, uint64_t source, +- int eh, int flags, +- const char *buf, size_t buf_len, +- const uint64_t *array, size_t array_len) +-{ +- struct pass_data *data = datavp; +- struct event *event; +- +- if (!data->seen_launch) +- return; +- +- event = add_event (data, source); +- event->message = strdup ("close callback"); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +- +- get_time (&data->end_t); +- data->elapsed_ns = timespec_diff (&data->start_t, &data->end_t); +-} +- +-/* Called when the qemu subprocess exits. +- * XXX This is never called - why? +- */ +-static void +-subprocess_quit_callback (guestfs_h *g, void *datavp, uint64_t source, +- int eh, int flags, +- const char *buf, size_t buf_len, +- const uint64_t *array, size_t array_len) +-{ +- struct pass_data *data = datavp; +- struct event *event; +- +- if (!data->seen_launch) +- return; +- +- event = add_event (data, source); +- event->message = strdup ("subprocess quit callback"); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +-} +- +-/* Called when the launch operation is complete (the library and the +- * guestfs daemon and talking to each other). +- */ +-static void +-launch_done_callback (guestfs_h *g, void *datavp, uint64_t source, +- int eh, int flags, +- const char *buf, size_t buf_len, +- const uint64_t *array, size_t array_len) +-{ +- struct pass_data *data = datavp; +- struct event *event; +- +- if (!data->seen_launch) +- return; +- +- event = add_event (data, source); +- event->message = strdup ("launch done callback"); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +-} +- +-/* Trim \r (multiple) from the end of a string. */ +-static void +-trim_r (char *message) +-{ +- size_t len = strlen (message); +- +- while (len > 0 && message[len-1] == '\r') { +- message[len-1] = '\0'; +- len--; +- } +-} +- +-/* Called when we get (possibly part of) a log message (or more than +- * one log message) from the appliance (which may include qemu, the +- * BIOS, kernel, etc). +- */ +-static void +-appliance_callback (guestfs_h *g, void *datavp, uint64_t source, +- int eh, int flags, +- const char *buf, size_t buf_len, +- const uint64_t *array, size_t array_len) +-{ +- struct pass_data *data = datavp; +- struct event *event; +- size_t i, len, slen; +- +- if (!data->seen_launch) +- return; +- +- /* If the previous log message was incomplete, but time has moved on +- * a lot, record a new log message anyway, so it gets a new +- * timestamp. +- */ +- if (data->incomplete_log_message >= 0) { +- struct timespec ts; +- get_time (&ts); +- if (timespec_diff (&data->events[data->incomplete_log_message].t, +- &ts) >= 10000000 /* 10ms */) +- data->incomplete_log_message = -1; +- } +- +- /* If the previous log message was incomplete then we may need to +- * append part of the current log message to a previous one. +- */ +- if (data->incomplete_log_message >= 0) { +- len = buf_len; +- for (i = 0; i < buf_len; ++i) { +- if (buf[i] == '\n') { +- len = i; +- break; +- } +- } +- +- event = &data->events[data->incomplete_log_message]; +- slen = strlen (event->message); +- event->message = realloc (event->message, slen + len + 1); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "realloc"); +- memcpy (event->message + slen, buf, len); +- event->message[slen + len] = '\0'; +- trim_r (event->message); +- +- /* Skip what we just added to the previous incomplete message. */ +- buf += len; +- buf_len -= len; +- +- if (buf_len == 0) /* still not complete, more to come! */ +- return; +- +- /* Skip the \n in the buffer. */ +- buf++; +- buf_len--; +- data->incomplete_log_message = -1; +- } +- +- /* Add the event, or perhaps multiple events if the message +- * contains \n characters. +- */ +- while (buf_len > 0) { +- len = buf_len; +- for (i = 0; i < buf_len; ++i) { +- if (buf[i] == '\n') { +- len = i; +- break; +- } +- } +- +- event = add_event (data, source); +- event->message = strndup (buf, len); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "strndup"); +- trim_r (event->message); +- +- /* Skip what we just added to the event. */ +- buf += len; +- buf_len -= len; +- +- if (buf_len == 0) { +- /* Event is incomplete (doesn't end with \n). We'll finish it +- * in the next callback. +- */ +- data->incomplete_log_message = event - data->events; +- return; +- } +- +- /* Skip the \n in the buffer. */ +- buf++; +- buf_len--; +- } +-} +- +-/* Called when we get a debug message from the library side. These +- * are always delivered as complete messages. +- */ +-static void +-library_callback (guestfs_h *g, void *datavp, uint64_t source, +- int eh, int flags, +- const char *buf, size_t buf_len, +- const uint64_t *array, size_t array_len) +-{ +- struct pass_data *data = datavp; +- struct event *event; +- +- if (!data->seen_launch) +- return; +- +- event = add_event (data, source); +- event->message = strndup (buf, buf_len); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "strndup"); +-} +- +-/* Called when we get a call trace message (a libguestfs API function +- * has been called or is returning). These are always delivered as +- * complete messages. +- */ +-static void +-trace_callback (guestfs_h *g, void *datavp, uint64_t source, +- int eh, int flags, +- const char *buf, size_t buf_len, +- const uint64_t *array, size_t array_len) +-{ +- struct pass_data *data = datavp; +- struct event *event; +- char *message; +- +- message = strndup (buf, buf_len); +- if (message == NULL) +- error (EXIT_FAILURE, errno, "strndup"); +- +- if (STREQ (message, "launch")) +- data->seen_launch = 1; +- +- if (!data->seen_launch) { +- free (message); +- return; +- } +- +- event = add_event (data, source); +- event->message = message; +-} +- +-/* Common function to set up event callbacks and record data in memory +- * for a particular pass (0 <= pass < NR_TEST_PASSES). +- */ +-static void +-set_up_event_handlers (guestfs_h *g, size_t pass) +-{ +- struct pass_data *data; +- +- assert (/* 0 <= pass && */ pass < NR_TEST_PASSES); +- +- data = &pass_data[pass]; +- data->pass = pass; +- data->nr_events = 0; +- data->events = NULL; +- get_time (&data->start_t); +- data->incomplete_log_message = -1; +- data->seen_launch = 0; +- +- guestfs_set_event_callback (g, close_callback, +- GUESTFS_EVENT_CLOSE, 0, data); +- guestfs_set_event_callback (g, subprocess_quit_callback, +- GUESTFS_EVENT_SUBPROCESS_QUIT, 0, data); +- guestfs_set_event_callback (g, launch_done_callback, +- GUESTFS_EVENT_LAUNCH_DONE, 0, data); +- guestfs_set_event_callback (g, appliance_callback, +- GUESTFS_EVENT_APPLIANCE, 0, data); +- guestfs_set_event_callback (g, library_callback, +- GUESTFS_EVENT_LIBRARY, 0, data); +- guestfs_set_event_callback (g, trace_callback, +- GUESTFS_EVENT_TRACE, 0, data); +- +- guestfs_set_verbose (g, 1); +- guestfs_set_trace (g, 1); +-} +- +-/* libvirt debugging sucks in a number of concrete ways: +- * +- * - you can't get a synchronous callback from a log message +- * - you can't enable logging per handle (only globally +- * by setting environment variables) +- * - you can't debug the daemon easily +- * - it's very complex +- * - it's very complex but not in ways that are practical or useful +- * +- * To get log messages at all, we need to create a pipe connected to a +- * second thread, and when libvirt prints something to the pipe we log +- * that. +- * +- * However that's not sufficient. Because logging is only enabled +- * when libvirt examines environment variables at the start of the +- * program, we need to create the pipe and then fork+exec a new +- * instance of the whole program with the pipe and environment +- * variables set up. +- */ +-static int is_libvirt_backend (guestfs_h *g); +-static void *libvirt_log_thread (void *datavp); +- +-static void +-libvirt_log_hack (int argc, char **argv) +-{ +- guestfs_h *g; +- +- g = guestfs_create (); +- if (!is_libvirt_backend (g)) { +- guestfs_close (g); +- return; +- } +- guestfs_close (g); +- +- /* Have we set up the pipes and environment and forked yet? If not, +- * do that first. +- */ +- if (libvirt_pipe[0] == -1 || libvirt_pipe[1] == -1) { +- char log_outputs[64]; +- char **new_argv; +- char param1[64], param2[64]; +- size_t i; +- pid_t pid; +- int status; +- +- /* Create the pipe. NB: do NOT use O_CLOEXEC since we want to pass +- * this pipe into a child process. +- */ +- if (pipe (libvirt_pipe) == -1) +- error (EXIT_FAILURE, 0, "pipe2"); +- +- /* Create the environment variables to enable logging in libvirt. */ +- setenv ("LIBVIRT_DEBUG", "1", 1); +- //setenv ("LIBVIRT_LOG_FILTERS", +- // "1:qemu 1:securit 3:file 3:event 3:object 1:util", 1); +- snprintf (log_outputs, sizeof log_outputs, +- "1:file:/dev/fd/%d", libvirt_pipe[1]); +- setenv ("LIBVIRT_LOG_OUTPUTS", log_outputs, 1); +- +- /* Run self again. */ +- new_argv = malloc ((argc+3) * sizeof (char *)); +- if (new_argv == NULL) +- error (EXIT_FAILURE, errno, "malloc"); +- +- for (i = 0; i < (size_t) argc; ++i) +- new_argv[i] = argv[i]; +- +- snprintf (param1, sizeof param1, "--libvirt-pipe-0=%d", libvirt_pipe[0]); +- new_argv[argc] = param1; +- snprintf (param2, sizeof param2, "--libvirt-pipe-1=%d", libvirt_pipe[1]); +- new_argv[argc+1] = param2; +- new_argv[argc+2] = NULL; +- +- pid = fork (); +- if (pid == -1) +- error (EXIT_FAILURE, errno, "fork"); +- if (pid == 0) { /* Child process. */ +- execvp (argv[0], new_argv); +- perror ("execvp"); +- _exit (EXIT_FAILURE); +- } +- +- if (waitpid (pid, &status, 0) == -1) +- error (EXIT_FAILURE, errno, "waitpid"); +- if (WIFEXITED (status)) +- exit (WEXITSTATUS (status)); +- error (EXIT_FAILURE, 0, "unexpected exit status from process: %d", status); +- } +- +- /* If we reach this else clause, then we have forked. Now we must +- * create a thread to read events from the pipe. This must be +- * constantly reading from the pipe, otherwise we will deadlock. +- * During the warm-up phase we end up throwing away messages. +- */ +- else { +- pthread_t thread; +- pthread_attr_t attr; +- int r; +- +- r = pthread_attr_init (&attr); +- if (r != 0) +- error (EXIT_FAILURE, r, "pthread_attr_init"); +- r = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); +- if (r != 0) +- error (EXIT_FAILURE, r, "pthread_attr_setdetachstate"); +- r = pthread_create (&thread, &attr, libvirt_log_thread, NULL); +- if (r != 0) +- error (EXIT_FAILURE, r, "pthread_create"); +- pthread_attr_destroy (&attr); +- } +-} +- +-static void +-start_libvirt_thread (size_t pass) +-{ +- /* In the non-libvirt case, this variable is ignored. */ +- pthread_mutex_lock (&pass_data_lock); +- libvirt_pass = pass; +- pthread_mutex_unlock (&pass_data_lock); +-} +- +-static void +-stop_libvirt_thread (void) +-{ +- /* In the non-libvirt case, this variable is ignored. */ +- pthread_mutex_lock (&pass_data_lock); +- libvirt_pass = -1; +- pthread_mutex_unlock (&pass_data_lock); +-} +- +-/* The separate "libvirt thread". It loops reading debug messages +- * printed by libvirt and adds them to the pass_data. +- */ +-static void * +-libvirt_log_thread (void *arg) +-{ +- struct event *event; +- CLEANUP_FREE char *buf = NULL; +- ssize_t r; +- +- buf = malloc (BUFSIZ); +- if (buf == NULL) +- error (EXIT_FAILURE, errno, "malloc"); +- +- while ((r = read (libvirt_pipe[0], buf, BUFSIZ)) > 0) { +- pthread_mutex_lock (&pass_data_lock); +- if (libvirt_pass == -1) goto discard; +- event = +- add_event_unlocked (&pass_data[libvirt_pass], SOURCE_LIBVIRT); +- event->message = strndup (buf, r); +- if (event->message == NULL) +- error (EXIT_FAILURE, errno, "strndup"); +- discard: +- pthread_mutex_unlock (&pass_data_lock); +- } +- +- if (r == -1) +- error (EXIT_FAILURE, errno, "libvirt_log_thread: read"); +- +- /* It's possible for the pipe to be closed (r == 0) if thread +- * cancellation is delayed after the main thread exits, so just +- * ignore that case and exit. +- */ +- pthread_exit (NULL); +-} +- +-static int +-is_libvirt_backend (guestfs_h *g) +-{ +- CLEANUP_FREE char *backend = guestfs_get_backend (g); +- +- return backend && +- (STREQ (backend, "libvirt") || STRPREFIX (backend, "libvirt:")); +-} +- +-/* Sanity check the collected events. */ +-static void +-check_pass_data (void) +-{ +- size_t i, j, len; +- int64_t ns; +- const char *message; +- +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- assert (pass_data[i].pass == i); +- assert (pass_data[i].elapsed_ns > 1000); +- assert (pass_data[i].nr_events > 0); +- assert (pass_data[i].events != NULL); +- +- for (j = 0; j < pass_data[i].nr_events; ++j) { +- assert (pass_data[i].events[j].t.tv_sec > 0); +- if (j > 0) { +- ns = timespec_diff (&pass_data[i].events[j-1].t, +- &pass_data[i].events[j].t); +- assert (ns >= 0); +- } +- assert (pass_data[i].events[j].source != 0); +- message = pass_data[i].events[j].message; +- assert (message != NULL); +- assert (pass_data[i].events[j].source != GUESTFS_EVENT_APPLIANCE || +- strchr (message, '\n') == NULL); +- len = strlen (message); +- assert (len == 0 || message[len-1] != '\r'); +- } +- } +-} +- +-static void +-print_escaped_string (const char *message) +-{ +- while (*message) { +- if (isprint (*message)) +- putchar (*message); +- else +- printf ("\\x%02x", (unsigned int) *message); +- message++; +- } +-} +- +-/* Dump the events to stdout, if verbose is set. */ +-static void +-dump_pass_data (void) +-{ +- size_t i, j; +- +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- printf ("pass %zu\n", pass_data[i].pass); +- printf (" number of events collected %zu\n", pass_data[i].nr_events); +- printf (" elapsed time %" PRIi64 " ns\n", pass_data[i].elapsed_ns); +- for (j = 0; j < pass_data[i].nr_events; ++j) { +- int64_t ns, diff_ns; +- CLEANUP_FREE char *source_str = NULL; +- +- ns = timespec_diff (&pass_data[i].start_t, &pass_data[i].events[j].t); +- source_str = source_to_string (pass_data[i].events[j].source); +- printf (" %.1fms ", ns / 1000000.0); +- if (j > 0) { +- diff_ns = timespec_diff (&pass_data[i].events[j-1].t, +- &pass_data[i].events[j].t); +- printf ("(+%.1f) ", diff_ns / 1000000.0); +- } +- printf ("[%s] \"", source_str); +- print_escaped_string (pass_data[i].events[j].message); +- printf ("\"\n"); +- } +- } +-} +- +-/* Convert source to a printable string. The caller must free the +- * returned string. +- */ +-char * +-source_to_string (uint64_t source) +-{ +- char *ret; +- +- if (source == SOURCE_LIBVIRT) { +- ret = strdup ("libvirt"); +- if (ret == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +- } +- else +- ret = guestfs_event_to_string (source); +- +- return ret; /* caller frees */ +-} +- +-int +-activity_exists (const char *name) +-{ +- size_t i; +- +- for (i = 0; i < nr_activities; ++i) +- if (STREQ (activities[i].name, name)) +- return 1; +- return 0; +-} +- +-/* Add an activity to the global list. */ +-struct activity * +-add_activity (const char *name, int flags) +-{ +- struct activity *ret; +- size_t i; +- +- /* You shouldn't have two activities with the same name. */ +- assert (!activity_exists (name)); +- +- nr_activities++; +- activities = realloc (activities, sizeof (struct activity) * nr_activities); +- if (activities == NULL) +- error (EXIT_FAILURE, errno, "realloc"); +- ret = &activities[nr_activities-1]; +- ret->name = strdup (name); +- if (ret->name == NULL) +- error (EXIT_FAILURE, errno, "strdup"); +- ret->flags = flags; +- +- for (i = 0; i < NR_TEST_PASSES; ++i) +- ret->start_event[i] = ret->end_event[i] = 0; +- +- return ret; +-} +- +-struct activity * +-find_activity (const char *name) +-{ +- size_t i; +- +- for (i = 0; i < nr_activities; ++i) +- if (STREQ (activities[i].name, name)) +- return &activities[i]; +- error (EXIT_FAILURE, 0, +- "internal error: could not find activity '%s'", name); +- /*NOTREACHED*/ +- abort (); +-} +- +-int +-activity_exists_with_no_data (const char *name, size_t pass) +-{ +- size_t i; +- +- for (i = 0; i < nr_activities; ++i) +- if (STREQ (activities[i].name, name) && +- activities[i].start_event[pass] == 0 && +- activities[i].end_event[pass] == 0) +- return 1; +- return 0; +-} +- +-static int +-compare_activities_by_t (const void *av, const void *bv) +-{ +- const struct activity *a = av; +- const struct activity *b = bv; +- +- return a->t - b->t; +-} +- +-/* Go through the activities, computing the start and elapsed time. */ +-static void +-analyze_timeline (void) +-{ +- struct activity *activity; +- size_t i, j; +- int64_t delta_ns; +- +- for (j = 0; j < nr_activities; ++j) { +- activity = &activities[j]; +- +- activity->t = 0; +- activity->mean = 0; +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- delta_ns = +- timespec_diff (&pass_data[i].events[0].t, +- &pass_data[i].events[activity->start_event[i]].t); +- activity->t += delta_ns; +- +- delta_ns = +- timespec_diff (&pass_data[i].events[activity->start_event[i]].t, +- &pass_data[i].events[activity->end_event[i]].t); +- activity->mean += delta_ns; +- } +- +- /* Divide through to get real start time and mean of each activity. */ +- activity->t /= NR_TEST_PASSES; +- activity->mean /= NR_TEST_PASSES; +- +- /* Calculate the end time of this activity. It's convenient when +- * drawing the timeline for one activity to finish just before the +- * next activity starts, rather than having them end and start at +- * the same time, hence ``- 1'' here. +- */ +- activity->end_t = activity->t + activity->mean - 1; +- +- /* The above only calculated mean. Now we are able to +- * calculate from the mean the variance and the standard +- * deviation. +- */ +- activity->variance = 0; +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- delta_ns = +- timespec_diff (&pass_data[i].events[activity->start_event[i]].t, +- &pass_data[i].events[activity->end_event[i]].t); +- activity->variance += pow (delta_ns - activity->mean, 2); +- } +- activity->variance /= NR_TEST_PASSES; +- +- activity->sd = sqrt (activity->variance); +- } +- +- /* Get the total mean elapsed time from the special "run" activity. */ +- activity = find_activity ("run"); +- for (j = 0; j < nr_activities; ++j) { +- activities[j].percent = 100.0 * activities[j].mean / activity->mean; +- +- activities[j].warning = +- !(activities[j].flags & LONG_ACTIVITY) && +- activities[j].percent >= WARNING_THRESHOLD; +- } +- +- /* Sort the activities by start time. */ +- qsort (activities, nr_activities, sizeof (struct activity), +- compare_activities_by_t); +-} +- +-/* Dump the timeline to stdout, if verbose is set. */ +-static void +-dump_timeline (void) +-{ +- size_t i; +- +- for (i = 0; i < nr_activities; ++i) { +- printf ("activity %zu:\n", i); +- printf (" name = %s\n", activities[i].name); +- printf (" start - end = %.1f - %.1f\n", +- activities[i].t, activities[i].end_t); +- printf (" mean elapsed = %.1f\n", activities[i].mean); +- printf (" variance = %.1f\n", activities[i].variance); +- printf (" s.d = %.1f\n", activities[i].sd); +- printf (" percent = %.1f\n", activities[i].percent); +- } +-} +- +-static void +-print_activity (struct activity *activity) +-{ +- if (activity->warning) ansi_red (); else ansi_green (); +- print_escaped_string (activity->name); +- ansi_restore (); +- printf (" %.1fms ±%.1fms ", +- activity->mean / 1000000, activity->sd / 1000000); +- if (activity->warning) ansi_red (); else ansi_green (); +- printf ("(%.1f%%) ", activity->percent); +- ansi_restore (); +-} +- +-static void +-print_analysis (void) +-{ +- double t = -1; /* Current time. */ +- /* Which columns contain activities that we are displaying now? +- * -1 == unused column, else index of an activity +- */ +- CLEANUP_FREE ssize_t *columns = NULL; +- const size_t nr_columns = nr_activities; +- size_t last_free_column = 0; +- +- size_t i, j; +- double last_t, smallest_next_t; +- const double MAX_T = 1e20; +- +- columns = malloc (nr_columns * sizeof (ssize_t)); +- if (columns == NULL) error (EXIT_FAILURE, errno, "malloc"); +- for (j = 0; j < nr_columns; ++j) +- columns[j] = -1; +- +- for (;;) { +- /* Find the next significant time to display, which is a time when +- * some activity started or ended. +- */ +- smallest_next_t = MAX_T; +- for (i = 0; i < nr_activities; ++i) { +- if (t < activities[i].t && activities[i].t < smallest_next_t) +- smallest_next_t = activities[i].t; +- else if (t < activities[i].end_t && activities[i].end_t < smallest_next_t) +- smallest_next_t = activities[i].end_t; +- } +- if (smallest_next_t == MAX_T) +- break; /* Finished. */ +- +- last_t = t; +- t = smallest_next_t; +- +- /* Draw a spacer line, but only if last_t -> t is a large jump. */ +- if (t - last_t >= 1000000 /* ns */) { +- printf (" "); +- ansi_magenta (); +- for (j = 0; j < last_free_column; ++j) { +- if (columns[j] >= 0 && +- activities[columns[j]].end_t != last_t /* !▼ */) +- printf ("│ "); +- else +- printf (" "); +- } +- ansi_restore (); +- printf ("\n"); +- } +- +- /* If there are any activities that ended before this time, drop +- * them from the columns list. +- */ +- for (i = 0; i < nr_activities; ++i) { +- if (activities[i].end_t < t) { +- for (j = 0; j < nr_columns; ++j) +- if (columns[j] == (ssize_t) i) { +- columns[j] = -1; +- break; +- } +- } +- } +- +- /* May need to adjust last_free_column after previous operation. */ +- while (last_free_column > 0 && columns[last_free_column-1] == -1) +- last_free_column--; +- +- /* If there are any activities starting at this time, add them to +- * the right hand end of the columns list. +- */ +- for (i = 0; i < nr_activities; ++i) { +- if (activities[i].t == t) +- columns[last_free_column++] = i; +- } +- +- /* Draw the line. */ +- ansi_blue (); +- printf ("%6.1fms: ", t / 1000000); +- +- ansi_magenta (); +- for (j = 0; j < last_free_column; ++j) { +- if (columns[j] >= 0) { +- if (activities[columns[j]].t == t) +- printf ("▲ "); +- else if (activities[columns[j]].end_t == t) +- printf ("▼ "); +- else +- printf ("│ "); +- } +- else +- printf (" "); +- } +- ansi_restore (); +- +- for (j = 0; j < last_free_column; ++j) { +- if (columns[j] >= 0 && activities[columns[j]].t == t) /* ▲ */ +- print_activity (&activities[columns[j]]); +- } +- +- printf ("\n"); +- } +-} +- +-static int +-compare_activities_pointers_by_mean (const void *av, const void *bv) +-{ +- const struct activity * const *a = av; +- const struct activity * const *b = bv; +- +- return (*b)->mean - (*a)->mean; +-} +- +-static void +-print_longest_to_shortest (void) +-{ +- size_t i; +- CLEANUP_FREE struct activity **longest; +- +- /* Sort the activities longest first. In order not to affect the +- * global activities array, sort an array of pointers to the +- * activities instead. +- */ +- longest = malloc (sizeof (struct activity *) * nr_activities); +- for (i = 0; i < nr_activities; ++i) +- longest[i] = &activities[i]; +- +- qsort (longest, nr_activities, sizeof (struct activity *), +- compare_activities_pointers_by_mean); +- +- /* Display the activities, longest first. */ +- for (i = 0; i < nr_activities; ++i) { +- print_activity (longest[i]); +- printf ("\n"); +- } +-} +- +-/* Free the non-static part of the pass_data structures. */ +-static void +-free_pass_data (void) +-{ +- size_t i, j; +- +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- for (j = 0; j < pass_data[i].nr_events; ++j) +- free (pass_data[i].events[j].message); +- free (pass_data[i].events); +- } +-} +- +-static void +-free_final_timeline (void) +-{ +- size_t i; +- +- for (i = 0; i < nr_activities; ++i) +- free (activities[i].name); +- free (activities); +-} +- +-/* Colours. */ +-static void +-ansi_green (void) +-{ +- if (force_colour || isatty (1)) +- fputs ("\033[0;32m", stdout); +-} +- +-static void +-ansi_red (void) +-{ +- if (force_colour || isatty (1)) +- fputs ("\033[1;31m", stdout); +-} +- +-static void +-ansi_blue (void) +-{ +- if (force_colour || isatty (1)) +- fputs ("\033[1;34m", stdout); +-} +- +-static void +-ansi_magenta (void) +-{ +- if (force_colour || isatty (1)) +- fputs ("\033[1;35m", stdout); +-} +- +-static void +-ansi_restore (void) +-{ +- if (force_colour || isatty (1)) +- fputs ("\033[0m", stdout); +-} +diff --git a/tests/qemu/boot-analysis.h b/tests/qemu/boot-analysis.h +deleted file mode 100644 +index a07f12e..0000000 +--- a/tests/qemu/boot-analysis.h ++++ /dev/null +@@ -1,102 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2016 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 GUESTFS_BOOT_ANALYSIS_H_ +-#define GUESTFS_BOOT_ANALYSIS_H_ +- +-#define NR_WARMUP_PASSES 3 +-#define NR_TEST_PASSES 5 +- +-/* Per-pass data collected. */ +-struct pass_data { +- size_t pass; +- struct timespec start_t; +- struct timespec end_t; +- int64_t elapsed_ns; +- +- /* Array of timestamped events. */ +- size_t nr_events; +- struct event *events; +- +- /* Was the previous appliance log message incomplete? If so, this +- * contains the index of that incomplete message in the events +- * array. +- */ +- ssize_t incomplete_log_message; +- +- /* Have we seen the launch event yet? We don't record events until +- * this one has been received. This makes it easy to base the +- * timeline at event 0. +- */ +- int seen_launch; +-}; +- +-/* The 'source' field in the event is a guestfs event +- * (GUESTFS_EVENT_*). We also wish to encode libvirt as a source, so +- * we use a magic/impossible value for that here. Note that events +- * are bitmasks, and normally no more than one bit may be set. +- */ +-#define SOURCE_LIBVIRT ((uint64_t)~0) +-extern char *source_to_string (uint64_t source); +- +-struct event { +- struct timespec t; +- uint64_t source; +- char *message; +-}; +- +-extern struct pass_data pass_data[NR_TEST_PASSES]; +- +-/* The final timeline consisting of various activities starting and +- * ending. We're interested in when the activities start, and how +- * long they take (mean, variance, standard deviation of length). +- */ +-struct activity { +- char *name; /* Name of this activity. */ +- int flags; +-#define LONG_ACTIVITY 1 /* Expected to take a long time. */ +- +- /* For each pass, record the actual start & end events of this +- * activity. +- */ +- size_t start_event[NR_TEST_PASSES]; +- size_t end_event[NR_TEST_PASSES]; +- +- double t; /* Start (ns offset). */ +- double end_t; /* t + mean - 1 */ +- +- /* Length of this activity. */ +- double mean; /* Mean time elapsed (ns). */ +- double variance; /* Variance. */ +- double sd; /* Standard deviation. */ +- double percent; /* Percent of total elapsed time. */ +- +- int warning; /* Appears in red. */ +-}; +- +-extern size_t nr_activities; +-extern struct activity *activities; +- +-extern int activity_exists (const char *name); +-extern struct activity *add_activity (const char *name, int flags); +-extern struct activity *find_activity (const char *name); +-extern int activity_exists_with_no_data (const char *name, size_t pass); +- +-extern void construct_timeline (void); +- +-#endif /* GUESTFS_BOOT_ANALYSIS_H_ */ +diff --git a/tests/qemu/boot-benchmark-range.pl b/tests/qemu/boot-benchmark-range.pl +deleted file mode 100755 +index 0e31c4d..0000000 +--- a/tests/qemu/boot-benchmark-range.pl ++++ /dev/null +@@ -1,240 +0,0 @@ +-#!/usr/bin/env perl +-# Copyright (C) 2016 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. +- +-use warnings; +-use strict; +- +-use Pod::Usage; +-use Getopt::Long; +- +-=head1 NAME +- +-boot-benchmark-range.pl - Benchmark libguestfs across a range of commits +-from another project +- +-=head1 SYNOPSIS +- +- LIBGUESTFS_BACKEND=direct \ +- LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \ +- ./run \ +- tests/qemu/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD +- +-=head1 +- +-Run F across a range of commits in another +-project. This is useful for finding performance regressions in other +-programs such as qemu or the Linux kernel which might be affecting +-libguestfs. +- +-For example, suppose you suspect there has been a performance +-regression in qemu, somewhere between C. You could run +-the script like this: +- +- LIBGUESTFS_BACKEND=direct \ +- LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \ +- ./run \ +- tests/qemu/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD +- +-where F is the path to the qemu git repository. +- +-The output is a list of the qemu commits, annotated by the benchmark +-time and some other information about how the time compares to the +-previous commit. +- +-You should run these tests on an unloaded machine. In particular +-running a desktop environment, web browser and so on can make the +-benchmarks useless. +- +-=head1 OPTIONS +- +-=over 4 +- +-=cut +- +-my $help; +- +-=item B<--help> +- +-Display brief help. +- +-=cut +- +-my $man; +- +-=item B<--man> +- +-Display full documentation (man page). +- +-=cut +- +-my $benchmark_command; +- +-=item B<--benchmark> C +- +-Set the name of the benchmark to run. You only need to use this if +-the script cannot find the right path to the libguestfs +-F program. By default the script looks for +-this file in the same directory as its executable. +- +-=cut +- +-my $make_command = "make"; +- +-=item B<--make> C +- +-Set the command used to build the other project. The default is +-to run C. +- +-If the command fails, then the commit is skipped. +- +-=back +- +-=cut +- +-# Clean up the program name. +-my $progname = $0; +-$progname =~ s{.*/}{}; +- +-# Parse options. +-GetOptions ("help|?" => \$help, +- "man" => \$man, +- "benchmark=s" => \$benchmark_command, +- "make=s" => \$make_command, +- ) or pod2usage (2); +-pod2usage (-exitval => 0) if $help; +-pod2usage (-exitval => 0, -verbose => 2) if $man; +- +-die "$progname: missing argument: requires path to git repository and range of commits\n" unless @ARGV == 2; +- +-my $dir = $ARGV[0]; +-my $range = $ARGV[1]; +- +-die "$progname: $dir is not a git repository\n" +- unless -d $dir && -d "$dir/.git"; +- +-sub silently_run +-{ +- open my $saveout, ">&STDOUT"; +- open my $saveerr, ">&STDERR"; +- open STDOUT, ">/dev/null"; +- open STDERR, ">/dev/null"; +- my $ret = system (@_); +- open STDOUT, ">&", $saveout; +- open STDERR, ">&", $saveerr; +- return $ret; +-} +- +-# Find the benchmark program and check it works. +-unless (defined $benchmark_command) { +- $benchmark_command = $0; +- $benchmark_command =~ s{/[^/]+$}{}; +- $benchmark_command .= "/boot-benchmark"; +- +- my $r = silently_run ("$benchmark_command", "--help"); +- die "$progname: cannot locate boot-benchmark program, try using --benchmark\n" unless $r == 0; +-} +- +-# Get the top-most commit from the remote, and restore it on exit. +-my $top_commit = `git -C '$dir' rev-parse HEAD`; +-chomp $top_commit; +- +-sub checkout +-{ +- my $sha = shift; +- my $ret = silently_run ("git", "-C", $dir, "checkout", $sha); +- return $ret; +-} +- +-END { +- checkout ($top_commit); +-} +- +-# Get the range of commits and log messages. +-my @range = (); +-open RANGE, "git -C '$dir' log --reverse --oneline $range |" or die; +-while () { +- if (m/^([0-9a-f]+) (.*)/) { +- my $sha = $1; +- my $msg = $2; +- push @range, [ $sha, $msg ]; +- } +-} +-close RANGE or die; +- +-# Run the test. +-my $prev_ms; +-foreach (@range) { +- my ($sha, $msg) = @$_; +- my $r; +- +- print "\n"; +- print "$sha $msg\n"; +- +- # Checkout this commit in the other repo. +- $r = checkout ($sha); +- if ($r != 0) { +- print "git checkout failed\n"; +- next; +- } +- +- # Build the repo, silently. +- $r = silently_run ("cd $dir && $make_command"); +- if ($r != 0) { +- print "build failed\n"; +- next; +- } +- +- # Run the benchmark program and get the timing. +- my ($time_ms, $time_str); +- open BENCHMARK, "$benchmark_command | grep '^Result:' |" or die; +- while () { +- die unless m/^Result: (([\d.]+)ms ±[\d.]+ms)/; +- $time_ms = $2; +- $time_str = $1; +- } +- close BENCHMARK; +- +- print "\t", $time_str; +- if (defined $prev_ms) { +- if ($prev_ms > $time_ms) { +- my $pc = 100 * ($prev_ms-$time_ms) / $time_ms; +- if ($pc >= 1) { +- printf (" ↑ improves performance by %0.1f%%", $pc); +- } +- } elsif ($prev_ms < $time_ms) { +- my $pc = 100 * ($time_ms-$prev_ms) / $prev_ms; +- if ($pc >= 1) { +- printf (" ↓ degrades performance by %0.1f%%", $pc); +- } +- } +- } +- print "\n"; +- $prev_ms = $time_ms; +-} +- +-=head1 SEE ALSO +- +-L, +-L. +- +-=head1 AUTHOR +- +-Richard W.M. Jones. +- +-=head1 COPYRIGHT +- +-Copyright (C) 2016 Red Hat Inc. +diff --git a/tests/qemu/boot-benchmark.c b/tests/qemu/boot-benchmark.c +deleted file mode 100644 +index 0508ee9..0000000 +--- a/tests/qemu/boot-benchmark.c ++++ /dev/null +@@ -1,225 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2016 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. +- */ +- +-/* Benchmark the time taken to boot the libguestfs appliance. */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "guestfs.h" +-#include "guestfs-internal-frontend.h" +- +-#include "boot-analysis-utils.h" +- +-#define NR_WARMUP_PASSES 3 +-#define NR_TEST_PASSES 10 +- +-static const char *append = NULL; +-static int memsize = 0; +-static int smp = 1; +- +-static void run_test (void); +-static guestfs_h *create_handle (void); +-static void add_drive (guestfs_h *g); +- +-static void +-usage (int exitcode) +-{ +- guestfs_h *g; +- int default_memsize = -1; +- +- g = guestfs_create (); +- if (g) { +- default_memsize = guestfs_get_memsize (g); +- guestfs_close (g); +- } +- +- fprintf (stderr, +- "boot-benchmark: Benchmark the time taken to boot the libguestfs appliance.\n" +- "Usage:\n" +- " boot-benchmark [--options]\n" +- "Options:\n" +- " --help Display this usage text and exit.\n" +- " --append OPTS Append OPTS to kernel command line.\n" +- " -m MB\n" +- " --memsize MB Set memory size in MB (default: %d).\n" +- " --smp N Enable N virtual CPUs (default: 1).\n", +- default_memsize); +- exit (exitcode); +-} +- +-int +-main (int argc, char *argv[]) +-{ +- enum { HELP_OPTION = CHAR_MAX + 1 }; +- static const char *options = "m:"; +- static const struct option long_options[] = { +- { "help", 0, 0, HELP_OPTION }, +- { "append", 1, 0, 0 }, +- { "memsize", 1, 0, 'm' }, +- { "smp", 1, 0, 0 }, +- { 0, 0, 0, 0 } +- }; +- int c, option_index; +- +- for (;;) { +- c = getopt_long (argc, argv, options, long_options, &option_index); +- if (c == -1) break; +- +- switch (c) { +- case 0: /* Options which are long only. */ +- if (STREQ (long_options[option_index].name, "append")) { +- append = optarg; +- break; +- } +- else if (STREQ (long_options[option_index].name, "smp")) { +- if (sscanf (optarg, "%d", &smp) != 1) { +- fprintf (stderr, "%s: could not parse smp parameter: %s\n", +- guestfs_int_program_name, optarg); +- exit (EXIT_FAILURE); +- } +- break; +- } +- fprintf (stderr, "%s: unknown long option: %s (%d)\n", +- guestfs_int_program_name, long_options[option_index].name, option_index); +- exit (EXIT_FAILURE); +- +- case 'm': +- if (sscanf (optarg, "%d", &memsize) != 1) { +- fprintf (stderr, "%s: could not parse memsize parameter: %s\n", +- guestfs_int_program_name, optarg); +- exit (EXIT_FAILURE); +- } +- break; +- +- case HELP_OPTION: +- usage (EXIT_SUCCESS); +- +- default: +- usage (EXIT_FAILURE); +- } +- } +- +- run_test (); +-} +- +-static void +-run_test (void) +-{ +- guestfs_h *g; +- size_t i; +- int64_t ns[NR_TEST_PASSES]; +- double mean; +- double variance; +- double sd; +- +- printf ("Warming up the libguestfs cache ...\n"); +- for (i = 0; i < NR_WARMUP_PASSES; ++i) { +- g = create_handle (); +- add_drive (g); +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- guestfs_close (g); +- } +- +- printf ("Running the tests ...\n"); +- for (i = 0; i < NR_TEST_PASSES; ++i) { +- struct timespec start_t, end_t; +- +- g = create_handle (); +- add_drive (g); +- get_time (&start_t); +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- guestfs_close (g); +- get_time (&end_t); +- +- ns[i] = timespec_diff (&start_t, &end_t); +- } +- +- /* Calculate the mean. */ +- mean = 0; +- for (i = 0; i < NR_TEST_PASSES; ++i) +- mean += ns[i]; +- mean /= NR_TEST_PASSES; +- +- /* Calculate the variance and standard deviation. */ +- variance = 0; +- for (i = 0; i < NR_TEST_PASSES; ++i) +- variance = pow (ns[i] - mean, 2); +- variance /= NR_TEST_PASSES; +- sd = sqrt (variance); +- +- /* Print the test parameters. */ +- printf ("\n"); +- g = create_handle (); +- test_info (g, NR_TEST_PASSES); +- guestfs_close (g); +- +- /* Print the result. */ +- printf ("\n"); +- printf ("Result: %.1fms ±%.1fms\n", mean / 1000000, sd / 1000000); +-} +- +-/* Common function to create the handle and set various defaults. */ +-static guestfs_h * +-create_handle (void) +-{ +- guestfs_h *g; +- CLEANUP_FREE char *full_append = NULL; +- +- g = guestfs_create (); +- if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); +- +- if (memsize != 0) +- if (guestfs_set_memsize (g, memsize) == -1) +- exit (EXIT_FAILURE); +- +- if (smp >= 2) +- if (guestfs_set_smp (g, smp) == -1) +- exit (EXIT_FAILURE); +- +- if (append != NULL) +- if (guestfs_set_append (g, full_append) == -1) +- exit (EXIT_FAILURE); +- +- return g; +-} +- +-/* Common function to add the /dev/null drive. */ +-static void +-add_drive (guestfs_h *g) +-{ +- if (guestfs_add_drive_opts (g, "/dev/null", +- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", +- GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, +- -1) == -1) +- exit (EXIT_FAILURE); +-} +diff --git a/tests/qemu/qemu-boot.c b/tests/qemu/qemu-boot.c +deleted file mode 100644 +index 336c26e..0000000 +--- a/tests/qemu/qemu-boot.c ++++ /dev/null +@@ -1,362 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2014-2016 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. +- */ +- +-/* Ancient libguestfs had a script called test-bootbootboot which just +- * booted up the appliance in a loop. This was necessary back in the +- * bad old days when qemu was not very reliable. This is the +- * spiritual successor of that script, designed to find bugs in +- * aarch64 KVM. You can control the number of boots that are done and +- * the amount of parallelism. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "guestfs.h" +-#include "guestfs-internal-frontend.h" +-#include "estimate-max-threads.h" +- +-#define MIN(a,b) ((a)<(b)?(a):(b)) +- +-/* Maximum number of threads we would ever run. Note this should not +- * be > 20, unless libvirt is modified to increase the maximum number +- * of clients. User can override this limit using -P. +- */ +-#define MAX_THREADS 12 +- +-static size_t n; /* Number of qemu processes to run in total. */ +-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +- +-static int ignore_errors = 0; +-static const char *log_template = NULL; +-static size_t log_file_size; +-static int trace = 0; +-static int verbose = 0; +- +-/* Events captured by the --log option. */ +-static const uint64_t event_bitmask = +- GUESTFS_EVENT_LIBRARY | +- GUESTFS_EVENT_WARNING | +- GUESTFS_EVENT_APPLIANCE | +- GUESTFS_EVENT_TRACE; +- +-struct thread_data { +- int thread_num; +- int r; +-}; +- +-static void *start_thread (void *thread_data_vp); +-static void 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 +-usage (int exitcode) +-{ +- fprintf (stderr, +- "qemu-boot: A program for repeatedly running the libguestfs appliance.\n" +- "qemu-boot [-i] [--log output.%%] [-P ] -n \n" +- " -i Ignore errors\n" +- " --log \n" +- " Write per-appliance logs to file (%% in name replaced by boot number)\n" +- " -P Set number of parallel threads\n" +- " (default is based on the amount of free memory)\n" +- " -n Set number of appliances to run before exiting\n" +- " -v Verbose appliance\n" +- " -x Enable libguestfs tracing\n"); +- exit (exitcode); +-} +- +-int +-main (int argc, char *argv[]) +-{ +- enum { HELP_OPTION = CHAR_MAX + 1 }; +- static const char options[] = "in:P:vx"; +- static const struct option long_options[] = { +- { "help", 0, 0, HELP_OPTION }, +- { "ignore", 0, 0, 'i' }, +- { "log", 1, 0, 0 }, +- { "number", 1, 0, 'n' }, +- { "processes", 1, 0, 'P' }, +- { "trace", 0, 0, 'x' }, +- { "verbose", 0, 0, 'v' }, +- { 0, 0, 0, 0 } +- }; +- size_t P = 0, i, errors; +- int c, option_index; +- int err; +- void *status; +- +- for (;;) { +- c = getopt_long (argc, argv, options, long_options, &option_index); +- if (c == -1) break; +- +- switch (c) { +- case 0: +- /* Options which are long only. */ +- if (STREQ (long_options[option_index].name, "log")) { +- log_template = optarg; +- log_file_size = strlen (log_template); +- for (i = 0; i < strlen (log_template); ++i) { +- if (log_template[i] == '%') +- log_file_size += 64; +- } +- } +- else { +- fprintf (stderr, "%s: unknown long option: %s (%d)\n", +- guestfs_int_program_name, long_options[option_index].name, option_index); +- exit (EXIT_FAILURE); +- } +- break; +- +- case 'i': +- ignore_errors = 1; +- break; +- +- case 'n': +- if (sscanf (optarg, "%zu", &n) != 1 || n == 0) { +- fprintf (stderr, "%s: -n option not numeric and greater than 0\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- break; +- +- case 'P': +- if (sscanf (optarg, "%zu", &P) != 1) { +- fprintf (stderr, "%s: -P option not numeric\n", guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- break; +- +- case 'v': +- verbose = 1; +- break; +- +- case 'x': +- trace = 1; +- break; +- +- case HELP_OPTION: +- usage (EXIT_SUCCESS); +- +- default: +- usage (EXIT_FAILURE); +- } +- } +- +- if (n == 0) { +- fprintf (stderr, +- "%s: must specify number of processes to run (-n option)\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- +- if (optind != argc) { +- fprintf (stderr, "%s: extra arguments found on the command line\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- +- /* Calculate the number of threads to use. */ +- if (P > 0) +- P = MIN (n, P); +- else +- P = MIN (n, MIN (MAX_THREADS, estimate_max_threads ())); +- +- /* Start the worker threads. */ +- struct thread_data thread_data[P]; +- pthread_t threads[P]; +- +- for (i = 0; i < P; ++i) { +- thread_data[i].thread_num = i; +- err = pthread_create (&threads[i], NULL, start_thread, &thread_data[i]); +- if (err != 0) { +- fprintf (stderr, "%s: pthread_create[%zu]: %s\n", +- guestfs_int_program_name, i, strerror (err)); +- exit (EXIT_FAILURE); +- } +- } +- +- /* Wait for the threads to exit. */ +- errors = 0; +- for (i = 0; i < P; ++i) { +- err = pthread_join (threads[i], &status); +- if (err != 0) { +- fprintf (stderr, "%s: pthread_join[%zu]: %s\n", +- guestfs_int_program_name, i, strerror (err)); +- errors++; +- } +- if (*(int *)status == -1) +- errors++; +- } +- +- exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +-} +- +-/* Worker thread. */ +-static void * +-start_thread (void *thread_data_vp) +-{ +- struct thread_data *thread_data = thread_data_vp; +- int quit = 0; +- int err; +- size_t i; +- guestfs_h *g; +- unsigned errors = 0; +- char id[64]; +- +- for (;;) { +- CLEANUP_FREE char *log_file = NULL; +- CLEANUP_FCLOSE FILE *log_fp = NULL; +- +- /* Take the next process. */ +- err = pthread_mutex_lock (&mutex); +- if (err != 0) { +- fprintf (stderr, "%s: pthread_mutex_lock: %s", +- guestfs_int_program_name, strerror (err)); +- goto error; +- } +- +- i = n; +- if (i > 0) { +- printf ("%zu to go ... \r", n); +- fflush (stdout); +- +- n--; +- } +- else +- quit = 1; +- +- err = pthread_mutex_unlock (&mutex); +- if (err != 0) { +- fprintf (stderr, "%s: pthread_mutex_unlock: %s", +- guestfs_int_program_name, strerror (err)); +- goto error; +- } +- +- if (quit) /* Work finished. */ +- break; +- +- g = guestfs_create (); +- if (g == NULL) { +- perror ("guestfs_create"); +- errors++; +- if (!ignore_errors) +- goto error; +- } +- +- /* Only if using --log, set up a callback. See examples/debug-logging.c */ +- if (log_template != NULL) { +- size_t j, k; +- +- log_file = malloc (log_file_size + 1); +- if (log_file == NULL) abort (); +- for (j = 0, k = 0; j < strlen (log_template); ++j) { +- if (log_template[j] == '%') { +- snprintf (&log_file[k], log_file_size - k, "%zu", i); +- k += strlen (&log_file[k]); +- } +- else +- log_file[k++] = log_template[j]; +- } +- log_file[k] = '\0'; +- log_fp = fopen (log_file, "w"); +- if (log_fp == NULL) { +- perror (log_file); +- abort (); +- } +- guestfs_set_event_callback (g, message_callback, +- event_bitmask, 0, log_fp); +- } +- +- snprintf (id, sizeof id, "%zu", i); +- guestfs_set_identifier (g, id); +- +- guestfs_set_trace (g, trace); +- guestfs_set_verbose (g, verbose); +- +- if (guestfs_add_drive_ro (g, "/dev/null") == -1) { +- errors++; +- if (!ignore_errors) +- goto error; +- } +- +- if (guestfs_launch (g) == -1) { +- errors++; +- if (!ignore_errors) +- goto error; +- } +- +- if (guestfs_shutdown (g) == -1) { +- errors++; +- if (!ignore_errors) +- goto error; +- } +- +- guestfs_close (g); +- } +- +- if (errors > 0) { +- fprintf (stderr, "%s: thread %d: %u errors were ignored\n", +- guestfs_int_program_name, thread_data->thread_num, errors); +- goto error; +- } +- +- thread_data->r = 0; +- return &thread_data->r; +- +- error: +- thread_data->r = -1; +- return &thread_data->r; +-} +- +-/* If using --log, this is called to write messages to the log file. */ +-static void +-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) +-{ +- FILE *fp = opaque; +- +- if (buf_len > 0) { +- CLEANUP_FREE char *msg = strndup (buf, buf_len); +- +- switch (event) { +- case GUESTFS_EVENT_APPLIANCE: +- fprintf (fp, "%s", msg); +- break; +- case GUESTFS_EVENT_LIBRARY: +- fprintf (fp, "libguestfs: %s\n", msg); +- break; +- case GUESTFS_EVENT_WARNING: +- fprintf (fp, "libguestfs: warning: %s\n", msg); +- break; +- case GUESTFS_EVENT_TRACE: +- fprintf (fp, "libguestfs: trace: %s\n", msg); +- break; +- } +- fflush (fp); +- } +-} +diff --git a/tests/qemu/qemu-speed-test.c b/tests/qemu/qemu-speed-test.c +deleted file mode 100644 +index d5e34c3..0000000 +--- a/tests/qemu/qemu-speed-test.c ++++ /dev/null +@@ -1,480 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2014 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 the speed of various qemu features. Currently tested are: +- * - virtio-serial upload +- * - virtio-serial download +- * - block device read +- * - block device write +- * More to come in future. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "guestfs.h" +-#include "guestfs-internal-frontend.h" +- +-static void test_virtio_serial (void); +-static void test_block_device (void); +- +-/* Which tests are enabled? -- All by default. */ +-static int virtio_serial_upload = 1; +-static int virtio_serial_download = 1; +-static int block_device_write = 1; +-static int block_device_read = 1; +- +-static int max_time_override = 0; +- +-static void +-reset_default_tests (int *flag) +-{ +- if (*flag) { +- virtio_serial_upload = 0; +- virtio_serial_download = 0; +- block_device_write = 0; +- block_device_read = 0; +- *flag = 0; +- } +-} +- +-static void +-usage (int exitcode) +-{ +- fprintf (stderr, +- "qemu-speed-test: Test the speed of qemu features.\n" +- "\n" +- "To run all tests (recommended), do:\n" +- " qemu-speed-test\n" +- "\n" +- "To run only specific tests, do:\n" +- " qemu-speed-test --option [--option ...]\n" +- "where the test options are:\n" +- " --virtio-serial-upload\n" +- " --virtio-serial-download\n" +- " --block-device-write\n" +- " --block-device-read\n" +- "\n" +- "Other options:\n" +- " --help Display help output and exit\n" +- " -t | --time= Set max length of test in seconds\n" +- ); +- exit (exitcode); +-} +- +-int +-main (int argc, char *argv[]) +-{ +- enum { HELP_OPTION = CHAR_MAX + 1 }; +- static const char options[] = "t:"; +- static const struct option long_options[] = { +- { "help", 0, 0, HELP_OPTION }, +- { "time", 1, 0, 't' }, +- +- /* Tests. */ +- { "virtio-serial-upload", 0, 0, 0 }, +- { "virtio-serial-download", 0, 0, 0 }, +- { "block-device-write", 0, 0, 0 }, +- { "block-device-read", 0, 0, 0 }, +- +- { 0, 0, 0, 0 } +- }; +- int c, option_index; +- int reset_flag = 1; +- +- for (;;) { +- c = getopt_long (argc, argv, options, long_options, &option_index); +- if (c == -1) break; +- +- switch (c) { +- case 0: +- /* Options which are long only. */ +- if (STREQ (long_options[option_index].name, "virtio-serial-upload")) { +- reset_default_tests (&reset_flag); +- virtio_serial_upload = 1; +- } +- else if (STREQ (long_options[option_index].name, "virtio-serial-download")) { +- reset_default_tests (&reset_flag); +- virtio_serial_download = 1; +- } +- else if (STREQ (long_options[option_index].name, "block-device-write")) { +- reset_default_tests (&reset_flag); +- block_device_write = 1; +- } +- else if (STREQ (long_options[option_index].name, "block-device-read")) { +- reset_default_tests (&reset_flag); +- block_device_read = 1; +- } +- else { +- fprintf (stderr, "%s: unknown long option: %s (%d)\n", +- guestfs_int_program_name, long_options[option_index].name, option_index); +- exit (EXIT_FAILURE); +- } +- break; +- +- case 't': +- if (sscanf (optarg, "%d", &max_time_override) != 1 || +- max_time_override < 0) { +- fprintf (stderr, "%s: -t: argument is not a positive integer\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- break; +- +- case HELP_OPTION: +- usage (EXIT_SUCCESS); +- +- default: +- usage (EXIT_FAILURE); +- } +- } +- +- if (optind != argc) { +- fprintf (stderr, "%s: extra arguments found on the command line\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- +- test_virtio_serial (); +- test_block_device (); +- +- exit (EXIT_SUCCESS); +-} +- +-static void +-print_rate (const char *msg, int64_t rate) +-{ +- printf ("%-40s %" PRIi64 " bytes/sec (%" PRIi64 " Mbytes/sec)\n", +- msg, rate, rate / 1024 / 1024); +- fflush (stdout); +-} +- +-/* The maximum time we will spend running the test (seconds). */ +-#define TEST_SERIAL_MAX_TIME 30 +- +-/* The maximum amount of data to copy. You can safely make this very +- * large because it's only making sparse files. +- */ +-#define TEST_SERIAL_MAX_SIZE \ +- (INT64_C(1024) * INT64_C(1024) * INT64_C(1024) * INT64_C(1024)) +- +-static guestfs_h *g; +-static struct timeval start; +-static const char *operation; +-static int64_t rate; +- +-static void +-stop_transfer (int sig) +-{ +- guestfs_user_cancel (g); +-} +- +-/* Compute Y - X and return the result in milliseconds. +- * Approximately the same as this code: +- * http://www.mpp.mpg.de/~huber/util/timevaldiff.c +- */ +-static int64_t +-timeval_diff (const struct timeval *x, const struct timeval *y) +-{ +- int64_t msec; +- +- msec = (y->tv_sec - x->tv_sec) * 1000; +- msec += (y->tv_usec - x->tv_usec) / 1000; +- return msec; +-} +- +-static void +-progress_cb (guestfs_h *g, void *vp, uint64_t event, +- int eh, int flags, +- const char *buf, size_t buflen, +- const uint64_t *array, size_t arraylen) +-{ +- uint64_t transferred; +- struct timeval now; +- int64_t millis; +- +- assert (event == GUESTFS_EVENT_PROGRESS); +- assert (arraylen >= 4); +- +- gettimeofday (&now, NULL); +- +- /* Bytes transferred. */ +- transferred = array[2]; +- +- /* Calculate the speed of the upload or download. */ +- millis = timeval_diff (&start, &now); +- assert (millis >= 0); +- +- if (millis != 0) { +- rate = 1000 * transferred / millis; +- printf ("%s: %" PRIi64 " bytes/sec \r", +- operation, rate); +- fflush (stdout); +- } +-} +- +-static void +-test_virtio_serial (void) +-{ +- int fd, r, eh; +- char tmpfile[] = "/tmp/speedtestXXXXXX"; +- struct sigaction sa, old_sa; +- +- if (!virtio_serial_upload && !virtio_serial_download) +- return; +- +- /* Create a sparse file. We could upload from /dev/zero, but we +- * won't get progress messages because libguestfs tests if the +- * source file is a regular file. +- */ +- fd = mkstemp (tmpfile); +- if (fd == -1) { +- perror ("mkstemp"); +- exit (EXIT_FAILURE); +- } +- if (ftruncate (fd, TEST_SERIAL_MAX_SIZE) == -1) { +- perror ("ftruncate"); +- exit (EXIT_FAILURE); +- } +- if (close (fd) == -1) { +- perror ("close"); +- exit (EXIT_FAILURE); +- } +- +- g = guestfs_create (); +- if (!g) { +- perror ("guestfs_create"); +- exit (EXIT_FAILURE); +- } +- +- if (guestfs_add_drive_scratch (g, INT64_C (100*1024*1024), -1) == -1) +- exit (EXIT_FAILURE); +- +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- +- /* Make and mount a filesystem which will be used by the download test. */ +- if (guestfs_mkfs (g, "ext4", "/dev/sda") == -1) +- exit (EXIT_FAILURE); +- if (guestfs_mount (g, "/dev/sda", "/") == -1) +- exit (EXIT_FAILURE); +- +- /* Time out the upload after TEST_SERIAL_MAX_TIME seconds have passed. */ +- memset (&sa, 0, sizeof sa); +- sa.sa_handler = stop_transfer; +- sa.sa_flags = SA_RESTART; +- sigaction (SIGALRM, &sa, &old_sa); +- +- /* Get progress messages, which will tell us how much data has been +- * transferred. +- */ +- eh = guestfs_set_event_callback (g, progress_cb, GUESTFS_EVENT_PROGRESS, +- 0, NULL); +- if (eh == -1) +- exit (EXIT_FAILURE); +- +- if (virtio_serial_upload) { +- gettimeofday (&start, NULL); +- rate = -1; +- operation = "upload"; +- alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME); +- +- /* For the upload test, upload the sparse file to /dev/null in the +- * appliance. Hopefully this is mostly testing just virtio-serial. +- */ +- guestfs_push_error_handler (g, NULL, NULL); +- r = guestfs_upload (g, tmpfile, "/dev/null"); +- alarm (0); +- unlink (tmpfile); +- guestfs_pop_error_handler (g); +- +- /* It's possible that the upload will finish before the alarm fires, +- * or that the upload will be stopped by the alarm. +- */ +- if (r == -1 && guestfs_last_errno (g) != EINTR) { +- fprintf (stderr, +- "%s: expecting upload command to return EINTR\n%s\n", +- guestfs_int_program_name, guestfs_last_error (g)); +- exit (EXIT_FAILURE); +- } +- +- if (rate == -1) { +- rate_error: +- fprintf (stderr, "%s: internal error: progress callback was not called! (r=%d, errno=%d)\n", +- guestfs_int_program_name, +- r, guestfs_last_errno (g)); +- exit (EXIT_FAILURE); +- } +- +- print_rate ("virtio-serial upload rate:", rate); +- } +- +- if (virtio_serial_download) { +- /* For the download test, download a sparse file within the +- * appliance to /dev/null on the host. +- */ +- if (guestfs_touch (g, "/sparse") == -1) +- exit (EXIT_FAILURE); +- if (guestfs_truncate_size (g, "/sparse", TEST_SERIAL_MAX_SIZE) == -1) +- exit (EXIT_FAILURE); +- +- gettimeofday (&start, NULL); +- rate = -1; +- operation = "download"; +- alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME); +- guestfs_push_error_handler (g, NULL, NULL); +- r = guestfs_download (g, "/sparse", "/dev/null"); +- alarm (0); +- guestfs_pop_error_handler (g); +- +- if (r == -1 && guestfs_last_errno (g) != EINTR) { +- fprintf (stderr, +- "%s: expecting download command to return EINTR\n%s\n", +- guestfs_int_program_name, guestfs_last_error (g)); +- exit (EXIT_FAILURE); +- } +- +- if (rate == -1) +- goto rate_error; +- +- print_rate ("virtio-serial download rate:", rate); +- } +- +- if (guestfs_shutdown (g) == -1) +- exit (EXIT_FAILURE); +- +- guestfs_close (g); +- +- /* Restore SIGALRM signal handler. */ +- sigaction (SIGALRM, &old_sa, NULL); +-} +- +-/* The time we will spend running the test (seconds). */ +-#define TEST_BLOCK_DEVICE_TIME 30 +- +-static void +-test_block_device (void) +-{ +- int fd; +- char tmpfile[] = "/tmp/speedtestXXXXXX"; +- CLEANUP_FREE char **devices = NULL; +- char *r; +- const char *argv[4]; +- const int t = +- max_time_override > 0 ? max_time_override : TEST_BLOCK_DEVICE_TIME; +- char tbuf[64]; +- int64_t bytes_written, bytes_read; +- +- if (!block_device_write && !block_device_read) +- return; +- +- snprintf (tbuf, sizeof tbuf, "%d", t); +- +- g = guestfs_create (); +- if (!g) { +- perror ("guestfs_create"); +- exit (EXIT_FAILURE); +- } +- +- /* Create a fully allocated backing file. Note we are not testing +- * the speed of allocation on the host. +- */ +- fd = mkstemp (tmpfile); +- if (fd == -1) { +- perror ("mkstemp"); +- exit (EXIT_FAILURE); +- } +- close (fd); +- +- if (guestfs_disk_create (g, tmpfile, "raw", +- INT64_C (1024*1024*1024), +- GUESTFS_DISK_CREATE_PREALLOCATION, "full", +- -1) == -1) +- exit (EXIT_FAILURE); +- +- if (guestfs_add_drive (g, tmpfile) == -1) +- exit (EXIT_FAILURE); +- +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- +- devices = guestfs_list_devices (g); +- if (devices == NULL) +- exit (EXIT_FAILURE); +- if (devices[0] == NULL) { +- fprintf (stderr, "%s: expected guestfs_list_devices to return at least 1 device\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- +- if (block_device_write) { +- /* Test write speed. */ +- argv[0] = devices[0]; +- argv[1] = "w"; +- argv[2] = tbuf; +- argv[3] = NULL; +- r = guestfs_debug (g, "device_speed", (char **) argv); +- if (r == NULL) +- exit (EXIT_FAILURE); +- +- if (sscanf (r, "%" SCNi64, &bytes_written) != 1) { +- fprintf (stderr, "%s: could not parse device_speed output\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- +- print_rate ("block device writes:", bytes_written / t); +- } +- +- if (block_device_read) { +- /* Test read speed. */ +- argv[0] = devices[0]; +- argv[1] = "r"; +- argv[2] = tbuf; +- argv[3] = NULL; +- r = guestfs_debug (g, "device_speed", (char **) argv); +- if (r == NULL) +- exit (EXIT_FAILURE); +- +- if (sscanf (r, "%" SCNi64, &bytes_read) != 1) { +- fprintf (stderr, "%s: could not parse device_speed output\n", +- guestfs_int_program_name); +- exit (EXIT_FAILURE); +- } +- +- print_rate ("block device reads:", bytes_read / t); +- } +- +- if (guestfs_shutdown (g) == -1) +- exit (EXIT_FAILURE); +- +- guestfs_close (g); +- +- /* Remove temporary file. */ +- unlink (tmpfile); +-} +diff --git a/utils/boot-analysis/Makefile.am b/utils/boot-analysis/Makefile.am +new file mode 100644 +index 0000000..ef9b2cb +--- /dev/null ++++ b/utils/boot-analysis/Makefile.am +@@ -0,0 +1,43 @@ ++# libguestfs ++# Copyright (C) 2011-2016 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 $(top_srcdir)/subdir-rules.mk ++ ++noinst_PROGRAMS = boot-analysis ++ ++boot_analysis_SOURCES = \ ++ boot-analysis.c \ ++ boot-analysis.h \ ++ boot-analysis-timeline.c \ ++ boot-analysis-utils.c \ ++ boot-analysis-utils.h ++boot_analysis_CPPFLAGS = \ ++ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ ++ -I$(top_srcdir)/src -I$(top_builddir)/src ++boot_analysis_CFLAGS = \ ++ -pthread \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) \ ++ $(PCRE_CFLAGS) ++boot_analysis_LDADD = \ ++ $(top_builddir)/src/libutils.la \ ++ $(top_builddir)/src/libguestfs.la \ ++ $(PCRE_LIBS) \ ++ $(LIBXML2_LIBS) \ ++ $(LIBVIRT_LIBS) \ ++ $(LTLIBINTL) \ ++ $(top_builddir)/gnulib/lib/libgnu.la \ ++ -lm +diff --git a/utils/boot-analysis/boot-analysis-timeline.c b/utils/boot-analysis/boot-analysis-timeline.c +new file mode 100644 +index 0000000..09a78ef +--- /dev/null ++++ b/utils/boot-analysis/boot-analysis-timeline.c +@@ -0,0 +1,523 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "ignore-value.h" ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis.h" ++ ++COMPILE_REGEXP(re_initcall_calling_module, ++ "calling ([_A-Za-z0-9]+)\\+.*\\[([_A-Za-z0-9]+)]", 0) ++COMPILE_REGEXP(re_initcall_calling, ++ "calling ([_A-Za-z0-9]+)\\+", 0) ++ ++static void construct_initcall_timeline (void); ++ ++/* "supermin: internal insmod xx.ko" -> "insmod xx.ko" */ ++static char * ++translate_supermin_insmod_message (const char *message) ++{ ++ char *ret; ++ ++ assert (STRPREFIX (message, "supermin: internal ")); ++ ++ ret = strdup (message + strlen ("supermin: internal ")); ++ if (ret == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ return ret; ++} ++ ++/* Analyze significant events from the events array, to form a ++ * timeline of activities. ++ */ ++void ++construct_timeline (void) ++{ ++ size_t i, j, k; ++ struct pass_data *data; ++ struct activity *activity; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ data = &pass_data[i]; ++ ++ /* Find an activity, by matching an event with the condition ++ * `begin_cond' through to the second event `end_cond'. Create an ++ * activity object in the timeline from the result. ++ */ ++#define FIND(name, flags, begin_cond, end_cond) \ ++ do { \ ++ activity = NULL; \ ++ for (j = 0; j < data->nr_events; ++j) { \ ++ if (begin_cond) { \ ++ for (k = j+1; k < data->nr_events; ++k) { \ ++ if (end_cond) { \ ++ if (i == 0) \ ++ activity = add_activity (name, flags); \ ++ else \ ++ activity = find_activity (name); \ ++ break; \ ++ } \ ++ } \ ++ break; \ ++ } \ ++ } \ ++ if (activity) { \ ++ activity->start_event[i] = j; \ ++ activity->end_event[i] = k; \ ++ } \ ++ else \ ++ error (EXIT_FAILURE, 0, "could not find activity '%s' in pass '%zu'", \ ++ name, i); \ ++ } while (0) ++ ++ /* Same as FIND() macro, but if no matching events are found, ++ * ignore it. ++ */ ++#define FIND_OPTIONAL(name, flags, begin_cond, end_cond) \ ++ do { \ ++ activity = NULL; \ ++ for (j = 0; j < data->nr_events; ++j) { \ ++ if (begin_cond) { \ ++ for (k = j+1; k < data->nr_events; ++k) { \ ++ if (end_cond) { \ ++ if (i == 0) \ ++ activity = add_activity (name, flags); \ ++ else \ ++ activity = find_activity (name); \ ++ break; \ ++ } \ ++ } \ ++ break; \ ++ } \ ++ } \ ++ if (activity) { \ ++ activity->start_event[i] = j; \ ++ activity->end_event[i] = k; \ ++ } \ ++ } while (0) ++ ++ /* Find multiple entries, where we check for: ++ * next_cond ++ * next_cond ++ * next_cond ++ * end_cond ++ */ ++#define FIND_MULTIPLE(debug_name, flags, next_cond, end_cond, translate_message) \ ++ do { \ ++ activity = NULL; \ ++ for (j = 0; j < data->nr_events; ++j) { \ ++ if (next_cond) { \ ++ CLEANUP_FREE char *message = translate_message (data->events[j].message); \ ++ if (activity) \ ++ activity->end_event[i] = j; \ ++ if (i == 0) \ ++ activity = add_activity (message, flags); \ ++ else \ ++ activity = find_activity (message); \ ++ activity->start_event[i] = j; \ ++ } \ ++ else if (end_cond) \ ++ break; \ ++ } \ ++ if (j < data->nr_events && activity) \ ++ activity->end_event[i] = j; \ ++ else \ ++ error (EXIT_FAILURE, 0, "could not find activity '%s' in pass '%zu'", \ ++ debug_name, i); \ ++ } while (0) ++ ++ /* Add one activity which is going to cover the whole process ++ * from launch to close. The launch event is always event 0. ++ * NB: This activity must be called "run" (see below). ++ */ ++ FIND ("run", LONG_ACTIVITY, ++ j == 0, data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++ /* Find where we invoke supermin --build. This should be a null ++ * operation, but it still takes time to run the external command. ++ */ ++ FIND ("supermin:build", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, ++ "begin building supermin appliance"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, ++ "finished building supermin appliance")); ++ ++ /* Find where we invoke qemu to test features. */ ++ FIND_OPTIONAL ("qemu:feature-detect", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, ++ "begin testing qemu features"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, ++ "finished testing qemu features")); ++ ++ /* Find where we run qemu. */ ++ FIND_OPTIONAL ("qemu", LONG_ACTIVITY, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "-nodefconfig"), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++ /* For the libvirt backend, connecting to libvirt, getting ++ * capabilities, parsing capabilities etc. ++ */ ++ FIND_OPTIONAL ("libvirt:connect", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "connect to libvirt"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "successfully opened libvirt handle")); ++ FIND_OPTIONAL ("libvirt:get-libvirt-capabilities", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "get libvirt capabilities"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "parsing capabilities XML")); ++ ++ FIND_OPTIONAL ("libguestfs:parse-libvirt-capabilities", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "parsing capabilities XML"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "get_backend_setting")); ++ ++ FIND_OPTIONAL ("libguestfs:create-libvirt-xml", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "create libvirt XML"), ++ data->events[k].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[k].message, "libvirt XML:")); ++ ++#if defined(__aarch64__) ++#define FIRST_KERNEL_MESSAGE "Booting Linux on physical CPU" ++#define FIRST_FIRMWARE_MESSAGE "UEFI firmware starting" ++#else ++#define SGABIOS_STRING "\033[1;256r\033[256;256H\033[6n" ++#define FIRST_KERNEL_MESSAGE "Probing EDD" ++#define FIRST_FIRMWARE_MESSAGE SGABIOS_STRING ++#endif ++ ++ /* For the libvirt backend, find the overhead of libvirt. */ ++ FIND_OPTIONAL ("libvirt:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_LIBRARY && ++ strstr (data->events[j].message, "launch libvirt guest"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, FIRST_FIRMWARE_MESSAGE)); ++ ++ /* From starting qemu up to entering the BIOS is the qemu overhead. */ ++ FIND_OPTIONAL ("qemu:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "-nodefconfig"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, FIRST_FIRMWARE_MESSAGE)); ++ ++ /* From entering the BIOS to starting the kernel is the BIOS overhead. */ ++ FIND_OPTIONAL ("bios:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, FIRST_FIRMWARE_MESSAGE), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); ++ ++#if defined(__i386__) || defined(__x86_64__) ++ /* SGABIOS (option ROM). */ ++ FIND_OPTIONAL ("sgabios", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, SGABIOS_STRING), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "SeaBIOS (version")); ++#endif ++ ++#if defined(__i386__) || defined(__x86_64__) ++ /* SeaBIOS. */ ++ FIND ("seabios", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "SeaBIOS (version"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); ++#endif ++ ++#if defined(__i386__) || defined(__x86_64__) ++ /* SeaBIOS - only available when using debug messages. */ ++ FIND_OPTIONAL ("seabios:pci-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Searching bootorder for: /pci@"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Scan for option roms")); ++#endif ++ ++ /* Find where we run the guest kernel. */ ++ FIND ("kernel", LONG_ACTIVITY, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ ++ /* Kernel startup to userspace. */ ++ FIND ("kernel:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "supermin:") && ++ strstr (data->events[k].message, "starting up")); ++ ++ /* The time taken to get into start_kernel function. */ ++ FIND ("kernel:entry", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Linux version")); ++ ++#if defined(__i386__) || defined(__x86_64__) ++ /* Alternatives patching instructions (XXX not very accurate we ++ * really need some debug messages inserted into the code). ++ */ ++ FIND ("kernel:alternatives", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "Last level dTLB entries"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Freeing SMP alternatives")); ++#endif ++ ++ /* ftrace patching instructions. */ ++ FIND ("kernel:ftrace", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "ftrace: allocating"), ++ 1); ++ ++ /* All initcall functions, before we enter userspace. */ ++ FIND ("kernel:initcalls-before-userspace", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "calling "), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Freeing unused kernel memory")); ++ ++ /* Find where we run supermin mini-initrd. */ ++ FIND ("supermin:mini-initrd", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin:") && ++ strstr (data->events[j].message, "starting up"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "supermin: chroot")); ++ ++ /* Loading kernel modules from supermin initrd. */ ++ FIND_MULTIPLE ++ ("supermin insmod", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: internal insmod"), ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: picked"), ++ translate_supermin_insmod_message); ++ ++ /* Find where we run the /init script. */ ++ FIND ("/init", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: chroot"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "guestfsd --verbose")); ++ ++ /* Everything from the chroot to the first echo in the /init ++ * script counts as bash overhead. ++ */ ++ FIND ("bash:overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "supermin: chroot"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "Starting /init script")); ++ ++ /* /init: Mount special filesystems. */ ++ FIND ("/init:mount-special", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "*guestfs_boot_analysis=1*"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "kmod static-nodes")); ++ ++ /* /init: Run kmod static-nodes */ ++ FIND ("/init:kmod-static-nodes", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "kmod static-nodes"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "systemd-tmpfiles")); ++ ++ /* /init: systemd-tmpfiles. */ ++ FIND ("/init:systemd-tmpfiles", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "systemd-tmpfiles"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "udev")); ++ ++ /* /init: start udevd. */ ++ FIND ("/init:udev-overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "udevd --daemon"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "nullglob")); ++ ++ /* /init: set up network. */ ++ FIND ("/init:network-overhead", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ ip addr"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ test")); ++ ++ /* /init: probe MD arrays. */ ++ FIND ("/init:md-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ mdadm"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ modprobe dm_mod")); ++ ++ /* /init: probe DM/LVM. */ ++ FIND ("/init:lvm-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ modprobe dm_mod"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ ldmtool")); ++ ++ /* /init: probe Windows dynamic disks. */ ++ FIND ("/init:windows-dynamic-disks-probe", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "+ ldmtool"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "+ test")); ++ ++ /* Find where we run guestfsd. */ ++ FIND ("guestfsd", 0, ++ data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, "guestfsd --verbose"), ++ data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, "fsync /dev/sda")); ++ ++ /* Shutdown process. */ ++ FIND ("shutdown", 0, ++ data->events[j].source == GUESTFS_EVENT_TRACE && ++ STREQ (data->events[j].message, "close"), ++ data->events[k].source == GUESTFS_EVENT_CLOSE); ++ } ++ ++ construct_initcall_timeline (); ++} ++ ++/* Handling of initcall is so peculiar that we hide it in a separate ++ * function from the rest. ++ */ ++static void ++construct_initcall_timeline (void) ++{ ++ size_t i, j, k; ++ struct pass_data *data; ++ struct activity *activity; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ data = &pass_data[i]; ++ ++ /* Each kernel initcall is bracketed by: ++ * ++ * calling ehci_hcd_init+0x0/0xc1 @ 1" ++ * initcall ehci_hcd_init+0x0/0xc1 returned 0 after 420 usecs" ++ * ++ * For initcall functions in modules: ++ * ++ * calling virtio_mmio_init+0x0/0x1000 [virtio_mmio] @ 1" ++ * initcall virtio_mmio_init+0x0/0x1000 [virtio_mmio] returned 0 after 14 usecs" ++ * ++ * Initcall functions can be nested, and do not have unique names. ++ */ ++ for (j = 0; j < data->nr_events; ++j) { ++ int vec[30], r; ++ const char *message = data->events[j].message; ++ ++ if (data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ ((r = pcre_exec (re_initcall_calling_module, NULL, ++ message, strlen (message), ++ 0, 0, vec, sizeof vec / sizeof vec[0])) >= 1 || ++ (r = pcre_exec (re_initcall_calling, NULL, ++ message, strlen (message), ++ 0, 0, vec, sizeof vec / sizeof vec[0])) >= 1)) { ++ ++ CLEANUP_FREE char *fn_name = NULL, *module_name = NULL; ++ if (r >= 2) /* because pcre_exec returns 1 + number of captures */ ++ fn_name = strndup (message + vec[2], vec[3]-vec[2]); ++ if (r >= 3) ++ module_name = strndup (message + vec[4], vec[5]-vec[4]); ++ ++ CLEANUP_FREE char *fullname; ++ if (asprintf (&fullname, "%s.%s", ++ module_name ? module_name : "kernel", fn_name) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ CLEANUP_FREE char *initcall_match; ++ if (asprintf (&initcall_match, "initcall %s", fn_name) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ /* Get a unique name for this activity. Unfortunately ++ * kernel initcall function names are not unique! ++ */ ++ CLEANUP_FREE char *activity_name; ++ if (asprintf (&activity_name, "initcall %s", fullname) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ if (i == 0) { ++ int n = 1; ++ while (activity_exists (activity_name)) { ++ free (activity_name); ++ if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ n++; ++ } ++ } ++ else { ++ int n = 1; ++ while (!activity_exists_with_no_data (activity_name, i)) { ++ free (activity_name); ++ if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ n++; ++ } ++ } ++ ++ /* Find the matching end event. It might be some time later, ++ * since it appears initcalls can be nested. ++ */ ++ for (k = j+1; k < data->nr_events; ++k) { ++ if (data->events[k].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[k].message, initcall_match)) { ++ if (i == 0) ++ activity = add_activity (activity_name, 0); ++ else ++ activity = find_activity (activity_name); ++ activity->start_event[i] = j; ++ activity->end_event[i] = k; ++ break; ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/utils/boot-analysis/boot-analysis-utils.c b/utils/boot-analysis/boot-analysis-utils.c +new file mode 100644 +index 0000000..693b6f4 +--- /dev/null ++++ b/utils/boot-analysis/boot-analysis-utils.c +@@ -0,0 +1,90 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "ignore-value.h" ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis-utils.h" ++ ++void ++get_time (struct timespec *ts) ++{ ++ if (clock_gettime (CLOCK_REALTIME, ts) == -1) ++ error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME"); ++} ++ ++int64_t ++timespec_diff (const struct timespec *x, const struct timespec *y) ++{ ++ int64_t nsec; ++ ++ nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000); ++ nsec += y->tv_nsec - x->tv_nsec; ++ return nsec; ++} ++ ++void ++test_info (guestfs_h *g, int nr_test_passes) ++{ ++ const char *qemu = guestfs_get_hv (g); ++ CLEANUP_FREE char *cmd = NULL; ++ CLEANUP_FREE char *backend = NULL; ++ ++ /* Related to the test program. */ ++ printf ("test version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION_FULL); ++ printf (" test passes: %d\n", nr_test_passes); ++ ++ /* Related to the host. */ ++ printf ("host version: "); ++ fflush (stdout); ++ ignore_value (system ("uname -a")); ++ printf (" host CPU: "); ++ fflush (stdout); ++ ignore_value (system ("perl -n -e 'if (/^model name.*: (.*)/) { print \"$1\\n\"; exit }' /proc/cpuinfo")); ++ ++ /* Related to qemu. */ ++ backend = guestfs_get_backend (g); ++ printf (" backend: %-20s [to change set LIBGUESTFS_BACKEND]\n", ++ backend); ++ printf (" qemu: %-20s [to change set $LIBGUESTFS_HV]\n", qemu); ++ printf ("qemu version: "); ++ fflush (stdout); ++ if (asprintf (&cmd, "%s -version", qemu) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ignore_value (system (cmd)); ++ printf (" smp: %-20d [to change use --smp option]\n", ++ guestfs_get_smp (g)); ++ printf (" memsize: %-20d [to change use --memsize option]\n", ++ guestfs_get_memsize (g)); ++ ++ /* Related to the guest kernel. Be nice to get the guest ++ * kernel version here somehow (XXX). ++ */ ++ printf (" append: %-20s [to change use --append option]\n", ++ guestfs_get_append (g) ? : ""); ++} +diff --git a/utils/boot-analysis/boot-analysis-utils.h b/utils/boot-analysis/boot-analysis-utils.h +new file mode 100644 +index 0000000..95e4f06 +--- /dev/null ++++ b/utils/boot-analysis/boot-analysis-utils.h +@@ -0,0 +1,36 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 GUESTFS_BOOT_ANALYSIS_UTILS_H_ ++#define GUESTFS_BOOT_ANALYSIS_UTILS_H_ ++ ++/* Get current time, returning it in *ts. If there is a system call ++ * failure, this exits. ++ */ ++extern void get_time (struct timespec *ts); ++ ++/* Computes Y - X, returning nanoseconds. */ ++extern int64_t timespec_diff (const struct timespec *x, const struct timespec *y); ++ ++/* Display host machine and test parameters (to stdout). 'g' should ++ * be an open libguestfs handle. It is used for reading hv, memsize ++ * etc. and is not modified. ++ */ ++extern void test_info (guestfs_h *g, int nr_test_passes); ++ ++#endif /* GUESTFS_BOOT_ANALYSIS_UTILS_H_ */ +diff --git a/utils/boot-analysis/boot-analysis.c b/utils/boot-analysis/boot-analysis.c +new file mode 100644 +index 0000000..b90806b +--- /dev/null ++++ b/utils/boot-analysis/boot-analysis.c +@@ -0,0 +1,1268 @@ ++/* libguestfs ++ * Copyright (C) 2016 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. ++ */ ++ ++/* Trace and analyze the appliance boot process to find out which ++ * steps are taking the most time. It is not part of the standard ++ * tests. ++ * ++ * This needs to be run on a quiet machine, so that other processes ++ * disturb the timing as little as possible. The program is ++ * completely safe to run at any time. It doesn't read or write any ++ * external files, and it doesn't require root. ++ * ++ * You can run it from the build directory like this: ++ * ++ * make ++ * ./run utils/boot-analysis/boot-analysis ++ * ++ * The way it works is roughly like this: ++ * ++ * We create a libguestfs handle and register callback handlers so we ++ * can see appliance messages, trace events and so on. ++ * ++ * We then launch the handle and shut it down as quickly as possible. ++ * ++ * While the handle is running, events (seen by the callback handlers) ++ * are written verbatim into an in-memory buffer, with timestamps. ++ * ++ * Afterwards we analyze the result using regular expressions to try ++ * to identify a "timeline" for the handle (eg. at what time did the ++ * BIOS hand control to the kernel). This analysis is done in ++ * 'boot-analysis-timeline.c'. ++ * ++ * The whole process is repeated across a few runs, and the final ++ * timeline (including statistical analysis of the variation between ++ * runs) gets printed. ++ * ++ * The program is very sensitive to the specific messages printed by ++ * BIOS/kernel/supermin/userspace, so it won't work on non-x86, and it ++ * will require periodic adjustment of the regular expressions in ++ * order to keep things up to date. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis.h" ++#include "boot-analysis-utils.h" ++ ++/* Activities taking longer than this % of the total time, except ++ * those flagged as LONG_ACTIVITY, are highlighted in red. ++ */ ++#define WARNING_THRESHOLD 1.0 ++ ++static const char *append = NULL; ++static int force_colour = 0; ++static int memsize = 0; ++static int smp = 1; ++static int verbose = 0; ++ ++static int libvirt_pipe[2] = { -1, -1 }; ++static ssize_t libvirt_pass = -1; ++ ++/* Because there is a separate thread which collects libvirt log data, ++ * we must protect the pass_data struct with a mutex. This only ++ * applies during the data collection passes. ++ */ ++static pthread_mutex_t pass_data_lock = PTHREAD_MUTEX_INITIALIZER; ++struct pass_data pass_data[NR_TEST_PASSES]; ++ ++size_t nr_activities; ++struct activity *activities; ++ ++static void run_test (void); ++static struct event *add_event (struct pass_data *, uint64_t source); ++static guestfs_h *create_handle (void); ++static void set_up_event_handlers (guestfs_h *g, size_t pass); ++static void libvirt_log_hack (int argc, char **argv); ++static void start_libvirt_thread (size_t pass); ++static void stop_libvirt_thread (void); ++static void add_drive (guestfs_h *g); ++static void check_pass_data (void); ++static void dump_pass_data (void); ++static void analyze_timeline (void); ++static void dump_timeline (void); ++static void print_analysis (void); ++static void print_longest_to_shortest (void); ++static void free_pass_data (void); ++static void free_final_timeline (void); ++static void ansi_green (void); ++static void ansi_red (void); ++static void ansi_blue (void); ++static void ansi_magenta (void); ++static void ansi_restore (void); ++ ++static void ++usage (int exitcode) ++{ ++ guestfs_h *g; ++ int default_memsize = -1; ++ ++ g = guestfs_create (); ++ if (g) { ++ default_memsize = guestfs_get_memsize (g); ++ guestfs_close (g); ++ } ++ ++ fprintf (stderr, ++ "boot-analysis: Trace and analyze the appliance boot process.\n" ++ "Usage:\n" ++ " boot-analysis [--options]\n" ++ "Options:\n" ++ " --help Display this usage text and exit.\n" ++ " --append OPTS Append OPTS to kernel command line.\n" ++ " --colour Output colours, even if not a terminal.\n" ++ " -m MB\n" ++ " --memsize MB Set memory size in MB (default: %d).\n" ++ " --smp N Enable N virtual CPUs (default: 1).\n" ++ " -v|--verbose Verbose output, useful for debugging.\n", ++ default_memsize); ++ exit (exitcode); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ enum { HELP_OPTION = CHAR_MAX + 1 }; ++ static const char *options = "m:v"; ++ static const struct option long_options[] = { ++ { "help", 0, 0, HELP_OPTION }, ++ { "append", 1, 0, 0 }, ++ { "color", 0, 0, 0 }, ++ { "colour", 0, 0, 0 }, ++ { "memsize", 1, 0, 'm' }, ++ { "libvirt-pipe-0", 1, 0, 0 }, /* see libvirt_log_hack */ ++ { "libvirt-pipe-1", 1, 0, 0 }, ++ { "smp", 1, 0, 0 }, ++ { "verbose", 0, 0, 'v' }, ++ { 0, 0, 0, 0 } ++ }; ++ int c, option_index; ++ ++ for (;;) { ++ c = getopt_long (argc, argv, options, long_options, &option_index); ++ if (c == -1) break; ++ ++ switch (c) { ++ case 0: /* Options which are long only. */ ++ if (STREQ (long_options[option_index].name, "append")) { ++ append = optarg; ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "color") || ++ STREQ (long_options[option_index].name, "colour")) { ++ force_colour = 1; ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "libvirt-pipe-0")) { ++ if (sscanf (optarg, "%d", &libvirt_pipe[0]) != 1) ++ error (EXIT_FAILURE, 0, ++ "could not parse libvirt-pipe-0 parameter: %s", optarg); ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "libvirt-pipe-1")) { ++ if (sscanf (optarg, "%d", &libvirt_pipe[1]) != 1) ++ error (EXIT_FAILURE, 0, ++ "could not parse libvirt-pipe-1 parameter: %s", optarg); ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "smp")) { ++ if (sscanf (optarg, "%d", &smp) != 1) ++ error (EXIT_FAILURE, 0, ++ "could not parse smp parameter: %s", optarg); ++ break; ++ } ++ fprintf (stderr, "%s: unknown long option: %s (%d)\n", ++ guestfs_int_program_name, long_options[option_index].name, option_index); ++ exit (EXIT_FAILURE); ++ ++ case 'm': ++ if (sscanf (optarg, "%d", &memsize) != 1) { ++ fprintf (stderr, "%s: could not parse memsize parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case 'v': ++ verbose = 1; ++ break; ++ ++ case HELP_OPTION: ++ usage (EXIT_SUCCESS); ++ ++ default: ++ usage (EXIT_FAILURE); ++ } ++ } ++ ++ libvirt_log_hack (argc, argv); ++ ++ if (STRNEQ (host_cpu, "x86_64") && STRNEQ (host_cpu, "aarch64")) ++ fprintf (stderr, "WARNING: host_cpu != x86_64|aarch64: This program may not work or give bogus results.\n"); ++ ++ run_test (); ++} ++ ++static void ++run_test (void) ++{ ++ guestfs_h *g; ++ size_t i; ++ ++ printf ("Warming up the libguestfs cache ...\n"); ++ for (i = 0; i < NR_WARMUP_PASSES; ++i) { ++ g = create_handle (); ++ add_drive (g); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ } ++ ++ printf ("Running the tests in %d passes ...\n", NR_TEST_PASSES); ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ g = create_handle (); ++ set_up_event_handlers (g, i); ++ start_libvirt_thread (i); ++ add_drive (g); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ stop_libvirt_thread (); ++ ++ printf (" pass %zu: %zu events collected in %" PRIi64 " ns\n", ++ i+1, pass_data[i].nr_events, pass_data[i].elapsed_ns); ++ } ++ ++ if (verbose) ++ dump_pass_data (); ++ ++ printf ("Analyzing the results ...\n"); ++ check_pass_data (); ++ construct_timeline (); ++ analyze_timeline (); ++ ++ if (verbose) ++ dump_timeline (); ++ ++ printf ("\n"); ++ g = create_handle (); ++ test_info (g, NR_TEST_PASSES); ++ guestfs_close (g); ++ printf ("\n"); ++ print_analysis (); ++ printf ("\n"); ++ printf ("Longest activities:\n"); ++ printf ("\n"); ++ print_longest_to_shortest (); ++ ++ free_pass_data (); ++ free_final_timeline (); ++} ++ ++static struct event * ++add_event_unlocked (struct pass_data *data, uint64_t source) ++{ ++ struct event *ret; ++ ++ data->nr_events++; ++ data->events = realloc (data->events, ++ sizeof (struct event) * data->nr_events); ++ if (data->events == NULL) ++ error (EXIT_FAILURE, errno, "realloc"); ++ ret = &data->events[data->nr_events-1]; ++ get_time (&ret->t); ++ ret->source = source; ++ ret->message = NULL; ++ return ret; ++} ++ ++static struct event * ++add_event (struct pass_data *data, uint64_t source) ++{ ++ struct event *ret; ++ ++ pthread_mutex_lock (&pass_data_lock); ++ ret = add_event_unlocked (data, source); ++ pthread_mutex_unlock (&pass_data_lock); ++ return ret; ++} ++ ++/* Common function to create the handle and set various defaults. */ ++static guestfs_h * ++create_handle (void) ++{ ++ guestfs_h *g; ++ CLEANUP_FREE char *full_append = NULL; ++ ++ g = guestfs_create (); ++ if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); ++ ++ if (memsize != 0) ++ if (guestfs_set_memsize (g, memsize) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (smp >= 2) ++ if (guestfs_set_smp (g, smp) == -1) ++ exit (EXIT_FAILURE); ++ ++ /* This changes some details in appliance/init and enables a ++ * detailed trace of calls to initcall functions in the kernel. ++ */ ++ if (asprintf (&full_append, ++ "guestfs_boot_analysis=1 " ++ "ignore_loglevel initcall_debug " ++ "%s", ++ append != NULL ? append : "") == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ if (guestfs_set_append (g, full_append) == -1) ++ exit (EXIT_FAILURE); ++ ++ return g; ++} ++ ++/* Common function to add the /dev/null drive. */ ++static void ++add_drive (guestfs_h *g) ++{ ++ if (guestfs_add_drive_opts (g, "/dev/null", ++ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", ++ GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, ++ -1) == -1) ++ exit (EXIT_FAILURE); ++} ++ ++/* Called when the handle is closed. Perform any cleanups required in ++ * the pass_data here. ++ */ ++static void ++close_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strdup ("close callback"); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ ++ get_time (&data->end_t); ++ data->elapsed_ns = timespec_diff (&data->start_t, &data->end_t); ++} ++ ++/* Called when the qemu subprocess exits. ++ * XXX This is never called - why? ++ */ ++static void ++subprocess_quit_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strdup ("subprocess quit callback"); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++} ++ ++/* Called when the launch operation is complete (the library and the ++ * guestfs daemon and talking to each other). ++ */ ++static void ++launch_done_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strdup ("launch done callback"); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++} ++ ++/* Trim \r (multiple) from the end of a string. */ ++static void ++trim_r (char *message) ++{ ++ size_t len = strlen (message); ++ ++ while (len > 0 && message[len-1] == '\r') { ++ message[len-1] = '\0'; ++ len--; ++ } ++} ++ ++/* Called when we get (possibly part of) a log message (or more than ++ * one log message) from the appliance (which may include qemu, the ++ * BIOS, kernel, etc). ++ */ ++static void ++appliance_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ size_t i, len, slen; ++ ++ if (!data->seen_launch) ++ return; ++ ++ /* If the previous log message was incomplete, but time has moved on ++ * a lot, record a new log message anyway, so it gets a new ++ * timestamp. ++ */ ++ if (data->incomplete_log_message >= 0) { ++ struct timespec ts; ++ get_time (&ts); ++ if (timespec_diff (&data->events[data->incomplete_log_message].t, ++ &ts) >= 10000000 /* 10ms */) ++ data->incomplete_log_message = -1; ++ } ++ ++ /* If the previous log message was incomplete then we may need to ++ * append part of the current log message to a previous one. ++ */ ++ if (data->incomplete_log_message >= 0) { ++ len = buf_len; ++ for (i = 0; i < buf_len; ++i) { ++ if (buf[i] == '\n') { ++ len = i; ++ break; ++ } ++ } ++ ++ event = &data->events[data->incomplete_log_message]; ++ slen = strlen (event->message); ++ event->message = realloc (event->message, slen + len + 1); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "realloc"); ++ memcpy (event->message + slen, buf, len); ++ event->message[slen + len] = '\0'; ++ trim_r (event->message); ++ ++ /* Skip what we just added to the previous incomplete message. */ ++ buf += len; ++ buf_len -= len; ++ ++ if (buf_len == 0) /* still not complete, more to come! */ ++ return; ++ ++ /* Skip the \n in the buffer. */ ++ buf++; ++ buf_len--; ++ data->incomplete_log_message = -1; ++ } ++ ++ /* Add the event, or perhaps multiple events if the message ++ * contains \n characters. ++ */ ++ while (buf_len > 0) { ++ len = buf_len; ++ for (i = 0; i < buf_len; ++i) { ++ if (buf[i] == '\n') { ++ len = i; ++ break; ++ } ++ } ++ ++ event = add_event (data, source); ++ event->message = strndup (buf, len); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++ trim_r (event->message); ++ ++ /* Skip what we just added to the event. */ ++ buf += len; ++ buf_len -= len; ++ ++ if (buf_len == 0) { ++ /* Event is incomplete (doesn't end with \n). We'll finish it ++ * in the next callback. ++ */ ++ data->incomplete_log_message = event - data->events; ++ return; ++ } ++ ++ /* Skip the \n in the buffer. */ ++ buf++; ++ buf_len--; ++ } ++} ++ ++/* Called when we get a debug message from the library side. These ++ * are always delivered as complete messages. ++ */ ++static void ++library_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ ++ if (!data->seen_launch) ++ return; ++ ++ event = add_event (data, source); ++ event->message = strndup (buf, buf_len); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++} ++ ++/* Called when we get a call trace message (a libguestfs API function ++ * has been called or is returning). These are always delivered as ++ * complete messages. ++ */ ++static void ++trace_callback (guestfs_h *g, void *datavp, uint64_t source, ++ int eh, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ struct pass_data *data = datavp; ++ struct event *event; ++ char *message; ++ ++ message = strndup (buf, buf_len); ++ if (message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++ ++ if (STREQ (message, "launch")) ++ data->seen_launch = 1; ++ ++ if (!data->seen_launch) { ++ free (message); ++ return; ++ } ++ ++ event = add_event (data, source); ++ event->message = message; ++} ++ ++/* Common function to set up event callbacks and record data in memory ++ * for a particular pass (0 <= pass < NR_TEST_PASSES). ++ */ ++static void ++set_up_event_handlers (guestfs_h *g, size_t pass) ++{ ++ struct pass_data *data; ++ ++ assert (/* 0 <= pass && */ pass < NR_TEST_PASSES); ++ ++ data = &pass_data[pass]; ++ data->pass = pass; ++ data->nr_events = 0; ++ data->events = NULL; ++ get_time (&data->start_t); ++ data->incomplete_log_message = -1; ++ data->seen_launch = 0; ++ ++ guestfs_set_event_callback (g, close_callback, ++ GUESTFS_EVENT_CLOSE, 0, data); ++ guestfs_set_event_callback (g, subprocess_quit_callback, ++ GUESTFS_EVENT_SUBPROCESS_QUIT, 0, data); ++ guestfs_set_event_callback (g, launch_done_callback, ++ GUESTFS_EVENT_LAUNCH_DONE, 0, data); ++ guestfs_set_event_callback (g, appliance_callback, ++ GUESTFS_EVENT_APPLIANCE, 0, data); ++ guestfs_set_event_callback (g, library_callback, ++ GUESTFS_EVENT_LIBRARY, 0, data); ++ guestfs_set_event_callback (g, trace_callback, ++ GUESTFS_EVENT_TRACE, 0, data); ++ ++ guestfs_set_verbose (g, 1); ++ guestfs_set_trace (g, 1); ++} ++ ++/* libvirt debugging sucks in a number of concrete ways: ++ * ++ * - you can't get a synchronous callback from a log message ++ * - you can't enable logging per handle (only globally ++ * by setting environment variables) ++ * - you can't debug the daemon easily ++ * - it's very complex ++ * - it's very complex but not in ways that are practical or useful ++ * ++ * To get log messages at all, we need to create a pipe connected to a ++ * second thread, and when libvirt prints something to the pipe we log ++ * that. ++ * ++ * However that's not sufficient. Because logging is only enabled ++ * when libvirt examines environment variables at the start of the ++ * program, we need to create the pipe and then fork+exec a new ++ * instance of the whole program with the pipe and environment ++ * variables set up. ++ */ ++static int is_libvirt_backend (guestfs_h *g); ++static void *libvirt_log_thread (void *datavp); ++ ++static void ++libvirt_log_hack (int argc, char **argv) ++{ ++ guestfs_h *g; ++ ++ g = guestfs_create (); ++ if (!is_libvirt_backend (g)) { ++ guestfs_close (g); ++ return; ++ } ++ guestfs_close (g); ++ ++ /* Have we set up the pipes and environment and forked yet? If not, ++ * do that first. ++ */ ++ if (libvirt_pipe[0] == -1 || libvirt_pipe[1] == -1) { ++ char log_outputs[64]; ++ char **new_argv; ++ char param1[64], param2[64]; ++ size_t i; ++ pid_t pid; ++ int status; ++ ++ /* Create the pipe. NB: do NOT use O_CLOEXEC since we want to pass ++ * this pipe into a child process. ++ */ ++ if (pipe (libvirt_pipe) == -1) ++ error (EXIT_FAILURE, 0, "pipe2"); ++ ++ /* Create the environment variables to enable logging in libvirt. */ ++ setenv ("LIBVIRT_DEBUG", "1", 1); ++ //setenv ("LIBVIRT_LOG_FILTERS", ++ // "1:qemu 1:securit 3:file 3:event 3:object 1:util", 1); ++ snprintf (log_outputs, sizeof log_outputs, ++ "1:file:/dev/fd/%d", libvirt_pipe[1]); ++ setenv ("LIBVIRT_LOG_OUTPUTS", log_outputs, 1); ++ ++ /* Run self again. */ ++ new_argv = malloc ((argc+3) * sizeof (char *)); ++ if (new_argv == NULL) ++ error (EXIT_FAILURE, errno, "malloc"); ++ ++ for (i = 0; i < (size_t) argc; ++i) ++ new_argv[i] = argv[i]; ++ ++ snprintf (param1, sizeof param1, "--libvirt-pipe-0=%d", libvirt_pipe[0]); ++ new_argv[argc] = param1; ++ snprintf (param2, sizeof param2, "--libvirt-pipe-1=%d", libvirt_pipe[1]); ++ new_argv[argc+1] = param2; ++ new_argv[argc+2] = NULL; ++ ++ pid = fork (); ++ if (pid == -1) ++ error (EXIT_FAILURE, errno, "fork"); ++ if (pid == 0) { /* Child process. */ ++ execvp (argv[0], new_argv); ++ perror ("execvp"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ if (waitpid (pid, &status, 0) == -1) ++ error (EXIT_FAILURE, errno, "waitpid"); ++ if (WIFEXITED (status)) ++ exit (WEXITSTATUS (status)); ++ error (EXIT_FAILURE, 0, "unexpected exit status from process: %d", status); ++ } ++ ++ /* If we reach this else clause, then we have forked. Now we must ++ * create a thread to read events from the pipe. This must be ++ * constantly reading from the pipe, otherwise we will deadlock. ++ * During the warm-up phase we end up throwing away messages. ++ */ ++ else { ++ pthread_t thread; ++ pthread_attr_t attr; ++ int r; ++ ++ r = pthread_attr_init (&attr); ++ if (r != 0) ++ error (EXIT_FAILURE, r, "pthread_attr_init"); ++ r = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); ++ if (r != 0) ++ error (EXIT_FAILURE, r, "pthread_attr_setdetachstate"); ++ r = pthread_create (&thread, &attr, libvirt_log_thread, NULL); ++ if (r != 0) ++ error (EXIT_FAILURE, r, "pthread_create"); ++ pthread_attr_destroy (&attr); ++ } ++} ++ ++static void ++start_libvirt_thread (size_t pass) ++{ ++ /* In the non-libvirt case, this variable is ignored. */ ++ pthread_mutex_lock (&pass_data_lock); ++ libvirt_pass = pass; ++ pthread_mutex_unlock (&pass_data_lock); ++} ++ ++static void ++stop_libvirt_thread (void) ++{ ++ /* In the non-libvirt case, this variable is ignored. */ ++ pthread_mutex_lock (&pass_data_lock); ++ libvirt_pass = -1; ++ pthread_mutex_unlock (&pass_data_lock); ++} ++ ++/* The separate "libvirt thread". It loops reading debug messages ++ * printed by libvirt and adds them to the pass_data. ++ */ ++static void * ++libvirt_log_thread (void *arg) ++{ ++ struct event *event; ++ CLEANUP_FREE char *buf = NULL; ++ ssize_t r; ++ ++ buf = malloc (BUFSIZ); ++ if (buf == NULL) ++ error (EXIT_FAILURE, errno, "malloc"); ++ ++ while ((r = read (libvirt_pipe[0], buf, BUFSIZ)) > 0) { ++ pthread_mutex_lock (&pass_data_lock); ++ if (libvirt_pass == -1) goto discard; ++ event = ++ add_event_unlocked (&pass_data[libvirt_pass], SOURCE_LIBVIRT); ++ event->message = strndup (buf, r); ++ if (event->message == NULL) ++ error (EXIT_FAILURE, errno, "strndup"); ++ discard: ++ pthread_mutex_unlock (&pass_data_lock); ++ } ++ ++ if (r == -1) ++ error (EXIT_FAILURE, errno, "libvirt_log_thread: read"); ++ ++ /* It's possible for the pipe to be closed (r == 0) if thread ++ * cancellation is delayed after the main thread exits, so just ++ * ignore that case and exit. ++ */ ++ pthread_exit (NULL); ++} ++ ++static int ++is_libvirt_backend (guestfs_h *g) ++{ ++ CLEANUP_FREE char *backend = guestfs_get_backend (g); ++ ++ return backend && ++ (STREQ (backend, "libvirt") || STRPREFIX (backend, "libvirt:")); ++} ++ ++/* Sanity check the collected events. */ ++static void ++check_pass_data (void) ++{ ++ size_t i, j, len; ++ int64_t ns; ++ const char *message; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ assert (pass_data[i].pass == i); ++ assert (pass_data[i].elapsed_ns > 1000); ++ assert (pass_data[i].nr_events > 0); ++ assert (pass_data[i].events != NULL); ++ ++ for (j = 0; j < pass_data[i].nr_events; ++j) { ++ assert (pass_data[i].events[j].t.tv_sec > 0); ++ if (j > 0) { ++ ns = timespec_diff (&pass_data[i].events[j-1].t, ++ &pass_data[i].events[j].t); ++ assert (ns >= 0); ++ } ++ assert (pass_data[i].events[j].source != 0); ++ message = pass_data[i].events[j].message; ++ assert (message != NULL); ++ assert (pass_data[i].events[j].source != GUESTFS_EVENT_APPLIANCE || ++ strchr (message, '\n') == NULL); ++ len = strlen (message); ++ assert (len == 0 || message[len-1] != '\r'); ++ } ++ } ++} ++ ++static void ++print_escaped_string (const char *message) ++{ ++ while (*message) { ++ if (isprint (*message)) ++ putchar (*message); ++ else ++ printf ("\\x%02x", (unsigned int) *message); ++ message++; ++ } ++} ++ ++/* Dump the events to stdout, if verbose is set. */ ++static void ++dump_pass_data (void) ++{ ++ size_t i, j; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ printf ("pass %zu\n", pass_data[i].pass); ++ printf (" number of events collected %zu\n", pass_data[i].nr_events); ++ printf (" elapsed time %" PRIi64 " ns\n", pass_data[i].elapsed_ns); ++ for (j = 0; j < pass_data[i].nr_events; ++j) { ++ int64_t ns, diff_ns; ++ CLEANUP_FREE char *source_str = NULL; ++ ++ ns = timespec_diff (&pass_data[i].start_t, &pass_data[i].events[j].t); ++ source_str = source_to_string (pass_data[i].events[j].source); ++ printf (" %.1fms ", ns / 1000000.0); ++ if (j > 0) { ++ diff_ns = timespec_diff (&pass_data[i].events[j-1].t, ++ &pass_data[i].events[j].t); ++ printf ("(+%.1f) ", diff_ns / 1000000.0); ++ } ++ printf ("[%s] \"", source_str); ++ print_escaped_string (pass_data[i].events[j].message); ++ printf ("\"\n"); ++ } ++ } ++} ++ ++/* Convert source to a printable string. The caller must free the ++ * returned string. ++ */ ++char * ++source_to_string (uint64_t source) ++{ ++ char *ret; ++ ++ if (source == SOURCE_LIBVIRT) { ++ ret = strdup ("libvirt"); ++ if (ret == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ } ++ else ++ ret = guestfs_event_to_string (source); ++ ++ return ret; /* caller frees */ ++} ++ ++int ++activity_exists (const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ if (STREQ (activities[i].name, name)) ++ return 1; ++ return 0; ++} ++ ++/* Add an activity to the global list. */ ++struct activity * ++add_activity (const char *name, int flags) ++{ ++ struct activity *ret; ++ size_t i; ++ ++ /* You shouldn't have two activities with the same name. */ ++ assert (!activity_exists (name)); ++ ++ nr_activities++; ++ activities = realloc (activities, sizeof (struct activity) * nr_activities); ++ if (activities == NULL) ++ error (EXIT_FAILURE, errno, "realloc"); ++ ret = &activities[nr_activities-1]; ++ ret->name = strdup (name); ++ if (ret->name == NULL) ++ error (EXIT_FAILURE, errno, "strdup"); ++ ret->flags = flags; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) ++ ret->start_event[i] = ret->end_event[i] = 0; ++ ++ return ret; ++} ++ ++struct activity * ++find_activity (const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ if (STREQ (activities[i].name, name)) ++ return &activities[i]; ++ error (EXIT_FAILURE, 0, ++ "internal error: could not find activity '%s'", name); ++ /*NOTREACHED*/ ++ abort (); ++} ++ ++int ++activity_exists_with_no_data (const char *name, size_t pass) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ if (STREQ (activities[i].name, name) && ++ activities[i].start_event[pass] == 0 && ++ activities[i].end_event[pass] == 0) ++ return 1; ++ return 0; ++} ++ ++static int ++compare_activities_by_t (const void *av, const void *bv) ++{ ++ const struct activity *a = av; ++ const struct activity *b = bv; ++ ++ return a->t - b->t; ++} ++ ++/* Go through the activities, computing the start and elapsed time. */ ++static void ++analyze_timeline (void) ++{ ++ struct activity *activity; ++ size_t i, j; ++ int64_t delta_ns; ++ ++ for (j = 0; j < nr_activities; ++j) { ++ activity = &activities[j]; ++ ++ activity->t = 0; ++ activity->mean = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ delta_ns = ++ timespec_diff (&pass_data[i].events[0].t, ++ &pass_data[i].events[activity->start_event[i]].t); ++ activity->t += delta_ns; ++ ++ delta_ns = ++ timespec_diff (&pass_data[i].events[activity->start_event[i]].t, ++ &pass_data[i].events[activity->end_event[i]].t); ++ activity->mean += delta_ns; ++ } ++ ++ /* Divide through to get real start time and mean of each activity. */ ++ activity->t /= NR_TEST_PASSES; ++ activity->mean /= NR_TEST_PASSES; ++ ++ /* Calculate the end time of this activity. It's convenient when ++ * drawing the timeline for one activity to finish just before the ++ * next activity starts, rather than having them end and start at ++ * the same time, hence ``- 1'' here. ++ */ ++ activity->end_t = activity->t + activity->mean - 1; ++ ++ /* The above only calculated mean. Now we are able to ++ * calculate from the mean the variance and the standard ++ * deviation. ++ */ ++ activity->variance = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ delta_ns = ++ timespec_diff (&pass_data[i].events[activity->start_event[i]].t, ++ &pass_data[i].events[activity->end_event[i]].t); ++ activity->variance += pow (delta_ns - activity->mean, 2); ++ } ++ activity->variance /= NR_TEST_PASSES; ++ ++ activity->sd = sqrt (activity->variance); ++ } ++ ++ /* Get the total mean elapsed time from the special "run" activity. */ ++ activity = find_activity ("run"); ++ for (j = 0; j < nr_activities; ++j) { ++ activities[j].percent = 100.0 * activities[j].mean / activity->mean; ++ ++ activities[j].warning = ++ !(activities[j].flags & LONG_ACTIVITY) && ++ activities[j].percent >= WARNING_THRESHOLD; ++ } ++ ++ /* Sort the activities by start time. */ ++ qsort (activities, nr_activities, sizeof (struct activity), ++ compare_activities_by_t); ++} ++ ++/* Dump the timeline to stdout, if verbose is set. */ ++static void ++dump_timeline (void) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) { ++ printf ("activity %zu:\n", i); ++ printf (" name = %s\n", activities[i].name); ++ printf (" start - end = %.1f - %.1f\n", ++ activities[i].t, activities[i].end_t); ++ printf (" mean elapsed = %.1f\n", activities[i].mean); ++ printf (" variance = %.1f\n", activities[i].variance); ++ printf (" s.d = %.1f\n", activities[i].sd); ++ printf (" percent = %.1f\n", activities[i].percent); ++ } ++} ++ ++static void ++print_activity (struct activity *activity) ++{ ++ if (activity->warning) ansi_red (); else ansi_green (); ++ print_escaped_string (activity->name); ++ ansi_restore (); ++ printf (" %.1fms ±%.1fms ", ++ activity->mean / 1000000, activity->sd / 1000000); ++ if (activity->warning) ansi_red (); else ansi_green (); ++ printf ("(%.1f%%) ", activity->percent); ++ ansi_restore (); ++} ++ ++static void ++print_analysis (void) ++{ ++ double t = -1; /* Current time. */ ++ /* Which columns contain activities that we are displaying now? ++ * -1 == unused column, else index of an activity ++ */ ++ CLEANUP_FREE ssize_t *columns = NULL; ++ const size_t nr_columns = nr_activities; ++ size_t last_free_column = 0; ++ ++ size_t i, j; ++ double last_t, smallest_next_t; ++ const double MAX_T = 1e20; ++ ++ columns = malloc (nr_columns * sizeof (ssize_t)); ++ if (columns == NULL) error (EXIT_FAILURE, errno, "malloc"); ++ for (j = 0; j < nr_columns; ++j) ++ columns[j] = -1; ++ ++ for (;;) { ++ /* Find the next significant time to display, which is a time when ++ * some activity started or ended. ++ */ ++ smallest_next_t = MAX_T; ++ for (i = 0; i < nr_activities; ++i) { ++ if (t < activities[i].t && activities[i].t < smallest_next_t) ++ smallest_next_t = activities[i].t; ++ else if (t < activities[i].end_t && activities[i].end_t < smallest_next_t) ++ smallest_next_t = activities[i].end_t; ++ } ++ if (smallest_next_t == MAX_T) ++ break; /* Finished. */ ++ ++ last_t = t; ++ t = smallest_next_t; ++ ++ /* Draw a spacer line, but only if last_t -> t is a large jump. */ ++ if (t - last_t >= 1000000 /* ns */) { ++ printf (" "); ++ ansi_magenta (); ++ for (j = 0; j < last_free_column; ++j) { ++ if (columns[j] >= 0 && ++ activities[columns[j]].end_t != last_t /* !▼ */) ++ printf ("│ "); ++ else ++ printf (" "); ++ } ++ ansi_restore (); ++ printf ("\n"); ++ } ++ ++ /* If there are any activities that ended before this time, drop ++ * them from the columns list. ++ */ ++ for (i = 0; i < nr_activities; ++i) { ++ if (activities[i].end_t < t) { ++ for (j = 0; j < nr_columns; ++j) ++ if (columns[j] == (ssize_t) i) { ++ columns[j] = -1; ++ break; ++ } ++ } ++ } ++ ++ /* May need to adjust last_free_column after previous operation. */ ++ while (last_free_column > 0 && columns[last_free_column-1] == -1) ++ last_free_column--; ++ ++ /* If there are any activities starting at this time, add them to ++ * the right hand end of the columns list. ++ */ ++ for (i = 0; i < nr_activities; ++i) { ++ if (activities[i].t == t) ++ columns[last_free_column++] = i; ++ } ++ ++ /* Draw the line. */ ++ ansi_blue (); ++ printf ("%6.1fms: ", t / 1000000); ++ ++ ansi_magenta (); ++ for (j = 0; j < last_free_column; ++j) { ++ if (columns[j] >= 0) { ++ if (activities[columns[j]].t == t) ++ printf ("▲ "); ++ else if (activities[columns[j]].end_t == t) ++ printf ("▼ "); ++ else ++ printf ("│ "); ++ } ++ else ++ printf (" "); ++ } ++ ansi_restore (); ++ ++ for (j = 0; j < last_free_column; ++j) { ++ if (columns[j] >= 0 && activities[columns[j]].t == t) /* ▲ */ ++ print_activity (&activities[columns[j]]); ++ } ++ ++ printf ("\n"); ++ } ++} ++ ++static int ++compare_activities_pointers_by_mean (const void *av, const void *bv) ++{ ++ const struct activity * const *a = av; ++ const struct activity * const *b = bv; ++ ++ return (*b)->mean - (*a)->mean; ++} ++ ++static void ++print_longest_to_shortest (void) ++{ ++ size_t i; ++ CLEANUP_FREE struct activity **longest; ++ ++ /* Sort the activities longest first. In order not to affect the ++ * global activities array, sort an array of pointers to the ++ * activities instead. ++ */ ++ longest = malloc (sizeof (struct activity *) * nr_activities); ++ for (i = 0; i < nr_activities; ++i) ++ longest[i] = &activities[i]; ++ ++ qsort (longest, nr_activities, sizeof (struct activity *), ++ compare_activities_pointers_by_mean); ++ ++ /* Display the activities, longest first. */ ++ for (i = 0; i < nr_activities; ++i) { ++ print_activity (longest[i]); ++ printf ("\n"); ++ } ++} ++ ++/* Free the non-static part of the pass_data structures. */ ++static void ++free_pass_data (void) ++{ ++ size_t i, j; ++ ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ for (j = 0; j < pass_data[i].nr_events; ++j) ++ free (pass_data[i].events[j].message); ++ free (pass_data[i].events); ++ } ++} ++ ++static void ++free_final_timeline (void) ++{ ++ size_t i; ++ ++ for (i = 0; i < nr_activities; ++i) ++ free (activities[i].name); ++ free (activities); ++} ++ ++/* Colours. */ ++static void ++ansi_green (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[0;32m", stdout); ++} ++ ++static void ++ansi_red (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[1;31m", stdout); ++} ++ ++static void ++ansi_blue (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[1;34m", stdout); ++} ++ ++static void ++ansi_magenta (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[1;35m", stdout); ++} ++ ++static void ++ansi_restore (void) ++{ ++ if (force_colour || isatty (1)) ++ fputs ("\033[0m", stdout); ++} +diff --git a/utils/boot-analysis/boot-analysis.h b/utils/boot-analysis/boot-analysis.h +new file mode 100644 +index 0000000..a07f12e +--- /dev/null ++++ b/utils/boot-analysis/boot-analysis.h +@@ -0,0 +1,102 @@ ++/* libguestfs ++ * Copyright (C) 2016 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 GUESTFS_BOOT_ANALYSIS_H_ ++#define GUESTFS_BOOT_ANALYSIS_H_ ++ ++#define NR_WARMUP_PASSES 3 ++#define NR_TEST_PASSES 5 ++ ++/* Per-pass data collected. */ ++struct pass_data { ++ size_t pass; ++ struct timespec start_t; ++ struct timespec end_t; ++ int64_t elapsed_ns; ++ ++ /* Array of timestamped events. */ ++ size_t nr_events; ++ struct event *events; ++ ++ /* Was the previous appliance log message incomplete? If so, this ++ * contains the index of that incomplete message in the events ++ * array. ++ */ ++ ssize_t incomplete_log_message; ++ ++ /* Have we seen the launch event yet? We don't record events until ++ * this one has been received. This makes it easy to base the ++ * timeline at event 0. ++ */ ++ int seen_launch; ++}; ++ ++/* The 'source' field in the event is a guestfs event ++ * (GUESTFS_EVENT_*). We also wish to encode libvirt as a source, so ++ * we use a magic/impossible value for that here. Note that events ++ * are bitmasks, and normally no more than one bit may be set. ++ */ ++#define SOURCE_LIBVIRT ((uint64_t)~0) ++extern char *source_to_string (uint64_t source); ++ ++struct event { ++ struct timespec t; ++ uint64_t source; ++ char *message; ++}; ++ ++extern struct pass_data pass_data[NR_TEST_PASSES]; ++ ++/* The final timeline consisting of various activities starting and ++ * ending. We're interested in when the activities start, and how ++ * long they take (mean, variance, standard deviation of length). ++ */ ++struct activity { ++ char *name; /* Name of this activity. */ ++ int flags; ++#define LONG_ACTIVITY 1 /* Expected to take a long time. */ ++ ++ /* For each pass, record the actual start & end events of this ++ * activity. ++ */ ++ size_t start_event[NR_TEST_PASSES]; ++ size_t end_event[NR_TEST_PASSES]; ++ ++ double t; /* Start (ns offset). */ ++ double end_t; /* t + mean - 1 */ ++ ++ /* Length of this activity. */ ++ double mean; /* Mean time elapsed (ns). */ ++ double variance; /* Variance. */ ++ double sd; /* Standard deviation. */ ++ double percent; /* Percent of total elapsed time. */ ++ ++ int warning; /* Appears in red. */ ++}; ++ ++extern size_t nr_activities; ++extern struct activity *activities; ++ ++extern int activity_exists (const char *name); ++extern struct activity *add_activity (const char *name, int flags); ++extern struct activity *find_activity (const char *name); ++extern int activity_exists_with_no_data (const char *name, size_t pass); ++ ++extern void construct_timeline (void); ++ ++#endif /* GUESTFS_BOOT_ANALYSIS_H_ */ +diff --git a/utils/boot-benchmark/Makefile.am b/utils/boot-benchmark/Makefile.am +new file mode 100644 +index 0000000..429832a +--- /dev/null ++++ b/utils/boot-benchmark/Makefile.am +@@ -0,0 +1,44 @@ ++# libguestfs ++# Copyright (C) 2011-2016 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. ++ ++# Safety and liveness tests of components that libguestfs depends upon ++# (not of libguestfs itself). Mainly this is for qemu and the kernel. ++# This test is the first to run. ++ ++include $(top_srcdir)/subdir-rules.mk ++ ++noinst_PROGRAMS = boot-benchmark ++ ++boot_benchmark_SOURCES = \ ++ boot-benchmark.c \ ++ ../boot-analysis/boot-analysis-utils.c \ ++ ../boot-analysis/boot-analysis-utils.h ++boot_benchmark_CPPFLAGS = \ ++ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ ++ -I$(top_srcdir)/src -I$(top_builddir)/src \ ++ -I$(top_srcdir)/utils/boot-analysis ++boot_benchmark_CFLAGS = \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) ++boot_benchmark_LDADD = \ ++ $(top_builddir)/src/libutils.la \ ++ $(top_builddir)/src/libguestfs.la \ ++ $(LIBXML2_LIBS) \ ++ $(LTLIBINTL) \ ++ $(top_builddir)/gnulib/lib/libgnu.la \ ++ -lm ++ ++EXTRA_DIST = boot-benchmark-range.pl +diff --git a/utils/boot-benchmark/boot-benchmark-range.pl b/utils/boot-benchmark/boot-benchmark-range.pl +new file mode 100755 +index 0000000..b69a835 +--- /dev/null ++++ b/utils/boot-benchmark/boot-benchmark-range.pl +@@ -0,0 +1,240 @@ ++#!/usr/bin/env perl ++# Copyright (C) 2016 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. ++ ++use warnings; ++use strict; ++ ++use Pod::Usage; ++use Getopt::Long; ++ ++=head1 NAME ++ ++boot-benchmark-range.pl - Benchmark libguestfs across a range of commits ++from another project ++ ++=head1 SYNOPSIS ++ ++ LIBGUESTFS_BACKEND=direct \ ++ LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \ ++ ./run \ ++ utils/boot-benchmark/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD ++ ++=head1 ++ ++Run F across a range of commits ++in another project. This is useful for finding performance ++regressions in other programs such as qemu or the Linux kernel which ++might be affecting libguestfs. ++ ++For example, suppose you suspect there has been a performance ++regression in qemu, somewhere between C. You could run ++the script like this: ++ ++ LIBGUESTFS_BACKEND=direct \ ++ LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \ ++ ./run \ ++ utils/boot-benchmark/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD ++ ++where F is the path to the qemu git repository. ++ ++The output is a list of the qemu commits, annotated by the benchmark ++time and some other information about how the time compares to the ++previous commit. ++ ++You should run these tests on an unloaded machine. In particular ++running a desktop environment, web browser and so on can make the ++benchmarks useless. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=cut ++ ++my $help; ++ ++=item B<--help> ++ ++Display brief help. ++ ++=cut ++ ++my $man; ++ ++=item B<--man> ++ ++Display full documentation (man page). ++ ++=cut ++ ++my $benchmark_command; ++ ++=item B<--benchmark> C ++ ++Set the name of the benchmark to run. You only need to use this if ++the script cannot find the right path to the libguestfs ++F program. By default the script ++looks for this file in the same directory as its executable. ++ ++=cut ++ ++my $make_command = "make"; ++ ++=item B<--make> C ++ ++Set the command used to build the other project. The default is ++to run C. ++ ++If the command fails, then the commit is skipped. ++ ++=back ++ ++=cut ++ ++# Clean up the program name. ++my $progname = $0; ++$progname =~ s{.*/}{}; ++ ++# Parse options. ++GetOptions ("help|?" => \$help, ++ "man" => \$man, ++ "benchmark=s" => \$benchmark_command, ++ "make=s" => \$make_command, ++ ) or pod2usage (2); ++pod2usage (-exitval => 0) if $help; ++pod2usage (-exitval => 0, -verbose => 2) if $man; ++ ++die "$progname: missing argument: requires path to git repository and range of commits\n" unless @ARGV == 2; ++ ++my $dir = $ARGV[0]; ++my $range = $ARGV[1]; ++ ++die "$progname: $dir is not a git repository\n" ++ unless -d $dir && -d "$dir/.git"; ++ ++sub silently_run ++{ ++ open my $saveout, ">&STDOUT"; ++ open my $saveerr, ">&STDERR"; ++ open STDOUT, ">/dev/null"; ++ open STDERR, ">/dev/null"; ++ my $ret = system (@_); ++ open STDOUT, ">&", $saveout; ++ open STDERR, ">&", $saveerr; ++ return $ret; ++} ++ ++# Find the benchmark program and check it works. ++unless (defined $benchmark_command) { ++ $benchmark_command = $0; ++ $benchmark_command =~ s{/[^/]+$}{}; ++ $benchmark_command .= "/boot-benchmark"; ++ ++ my $r = silently_run ("$benchmark_command", "--help"); ++ die "$progname: cannot locate boot-benchmark program, try using --benchmark\n" unless $r == 0; ++} ++ ++# Get the top-most commit from the remote, and restore it on exit. ++my $top_commit = `git -C '$dir' rev-parse HEAD`; ++chomp $top_commit; ++ ++sub checkout ++{ ++ my $sha = shift; ++ my $ret = silently_run ("git", "-C", $dir, "checkout", $sha); ++ return $ret; ++} ++ ++END { ++ checkout ($top_commit); ++} ++ ++# Get the range of commits and log messages. ++my @range = (); ++open RANGE, "git -C '$dir' log --reverse --oneline $range |" or die; ++while () { ++ if (m/^([0-9a-f]+) (.*)/) { ++ my $sha = $1; ++ my $msg = $2; ++ push @range, [ $sha, $msg ]; ++ } ++} ++close RANGE or die; ++ ++# Run the test. ++my $prev_ms; ++foreach (@range) { ++ my ($sha, $msg) = @$_; ++ my $r; ++ ++ print "\n"; ++ print "$sha $msg\n"; ++ ++ # Checkout this commit in the other repo. ++ $r = checkout ($sha); ++ if ($r != 0) { ++ print "git checkout failed\n"; ++ next; ++ } ++ ++ # Build the repo, silently. ++ $r = silently_run ("cd $dir && $make_command"); ++ if ($r != 0) { ++ print "build failed\n"; ++ next; ++ } ++ ++ # Run the benchmark program and get the timing. ++ my ($time_ms, $time_str); ++ open BENCHMARK, "$benchmark_command | grep '^Result:' |" or die; ++ while () { ++ die unless m/^Result: (([\d.]+)ms ±[\d.]+ms)/; ++ $time_ms = $2; ++ $time_str = $1; ++ } ++ close BENCHMARK; ++ ++ print "\t", $time_str; ++ if (defined $prev_ms) { ++ if ($prev_ms > $time_ms) { ++ my $pc = 100 * ($prev_ms-$time_ms) / $time_ms; ++ if ($pc >= 1) { ++ printf (" ↑ improves performance by %0.1f%%", $pc); ++ } ++ } elsif ($prev_ms < $time_ms) { ++ my $pc = 100 * ($time_ms-$prev_ms) / $prev_ms; ++ if ($pc >= 1) { ++ printf (" ↓ degrades performance by %0.1f%%", $pc); ++ } ++ } ++ } ++ print "\n"; ++ $prev_ms = $time_ms; ++} ++ ++=head1 SEE ALSO ++ ++L, ++L. ++ ++=head1 AUTHOR ++ ++Richard W.M. Jones. ++ ++=head1 COPYRIGHT ++ ++Copyright (C) 2016 Red Hat Inc. +diff --git a/utils/boot-benchmark/boot-benchmark.c b/utils/boot-benchmark/boot-benchmark.c +new file mode 100644 +index 0000000..0508ee9 +--- /dev/null ++++ b/utils/boot-benchmark/boot-benchmark.c +@@ -0,0 +1,225 @@ ++/* libguestfs ++ * Copyright (C) 2016 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. ++ */ ++ ++/* Benchmark the time taken to boot the libguestfs appliance. */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "boot-analysis-utils.h" ++ ++#define NR_WARMUP_PASSES 3 ++#define NR_TEST_PASSES 10 ++ ++static const char *append = NULL; ++static int memsize = 0; ++static int smp = 1; ++ ++static void run_test (void); ++static guestfs_h *create_handle (void); ++static void add_drive (guestfs_h *g); ++ ++static void ++usage (int exitcode) ++{ ++ guestfs_h *g; ++ int default_memsize = -1; ++ ++ g = guestfs_create (); ++ if (g) { ++ default_memsize = guestfs_get_memsize (g); ++ guestfs_close (g); ++ } ++ ++ fprintf (stderr, ++ "boot-benchmark: Benchmark the time taken to boot the libguestfs appliance.\n" ++ "Usage:\n" ++ " boot-benchmark [--options]\n" ++ "Options:\n" ++ " --help Display this usage text and exit.\n" ++ " --append OPTS Append OPTS to kernel command line.\n" ++ " -m MB\n" ++ " --memsize MB Set memory size in MB (default: %d).\n" ++ " --smp N Enable N virtual CPUs (default: 1).\n", ++ default_memsize); ++ exit (exitcode); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ enum { HELP_OPTION = CHAR_MAX + 1 }; ++ static const char *options = "m:"; ++ static const struct option long_options[] = { ++ { "help", 0, 0, HELP_OPTION }, ++ { "append", 1, 0, 0 }, ++ { "memsize", 1, 0, 'm' }, ++ { "smp", 1, 0, 0 }, ++ { 0, 0, 0, 0 } ++ }; ++ int c, option_index; ++ ++ for (;;) { ++ c = getopt_long (argc, argv, options, long_options, &option_index); ++ if (c == -1) break; ++ ++ switch (c) { ++ case 0: /* Options which are long only. */ ++ if (STREQ (long_options[option_index].name, "append")) { ++ append = optarg; ++ break; ++ } ++ else if (STREQ (long_options[option_index].name, "smp")) { ++ if (sscanf (optarg, "%d", &smp) != 1) { ++ fprintf (stderr, "%s: could not parse smp parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ } ++ fprintf (stderr, "%s: unknown long option: %s (%d)\n", ++ guestfs_int_program_name, long_options[option_index].name, option_index); ++ exit (EXIT_FAILURE); ++ ++ case 'm': ++ if (sscanf (optarg, "%d", &memsize) != 1) { ++ fprintf (stderr, "%s: could not parse memsize parameter: %s\n", ++ guestfs_int_program_name, optarg); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case HELP_OPTION: ++ usage (EXIT_SUCCESS); ++ ++ default: ++ usage (EXIT_FAILURE); ++ } ++ } ++ ++ run_test (); ++} ++ ++static void ++run_test (void) ++{ ++ guestfs_h *g; ++ size_t i; ++ int64_t ns[NR_TEST_PASSES]; ++ double mean; ++ double variance; ++ double sd; ++ ++ printf ("Warming up the libguestfs cache ...\n"); ++ for (i = 0; i < NR_WARMUP_PASSES; ++i) { ++ g = create_handle (); ++ add_drive (g); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ } ++ ++ printf ("Running the tests ...\n"); ++ for (i = 0; i < NR_TEST_PASSES; ++i) { ++ struct timespec start_t, end_t; ++ ++ g = create_handle (); ++ add_drive (g); ++ get_time (&start_t); ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ guestfs_close (g); ++ get_time (&end_t); ++ ++ ns[i] = timespec_diff (&start_t, &end_t); ++ } ++ ++ /* Calculate the mean. */ ++ mean = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) ++ mean += ns[i]; ++ mean /= NR_TEST_PASSES; ++ ++ /* Calculate the variance and standard deviation. */ ++ variance = 0; ++ for (i = 0; i < NR_TEST_PASSES; ++i) ++ variance = pow (ns[i] - mean, 2); ++ variance /= NR_TEST_PASSES; ++ sd = sqrt (variance); ++ ++ /* Print the test parameters. */ ++ printf ("\n"); ++ g = create_handle (); ++ test_info (g, NR_TEST_PASSES); ++ guestfs_close (g); ++ ++ /* Print the result. */ ++ printf ("\n"); ++ printf ("Result: %.1fms ±%.1fms\n", mean / 1000000, sd / 1000000); ++} ++ ++/* Common function to create the handle and set various defaults. */ ++static guestfs_h * ++create_handle (void) ++{ ++ guestfs_h *g; ++ CLEANUP_FREE char *full_append = NULL; ++ ++ g = guestfs_create (); ++ if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); ++ ++ if (memsize != 0) ++ if (guestfs_set_memsize (g, memsize) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (smp >= 2) ++ if (guestfs_set_smp (g, smp) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (append != NULL) ++ if (guestfs_set_append (g, full_append) == -1) ++ exit (EXIT_FAILURE); ++ ++ return g; ++} ++ ++/* Common function to add the /dev/null drive. */ ++static void ++add_drive (guestfs_h *g) ++{ ++ if (guestfs_add_drive_opts (g, "/dev/null", ++ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", ++ GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, ++ -1) == -1) ++ exit (EXIT_FAILURE); ++} +diff --git a/utils/qemu-boot/Makefile.am b/utils/qemu-boot/Makefile.am +new file mode 100644 +index 0000000..d4716cc +--- /dev/null ++++ b/utils/qemu-boot/Makefile.am +@@ -0,0 +1,39 @@ ++# libguestfs ++# Copyright (C) 2011-2016 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 $(top_srcdir)/subdir-rules.mk ++ ++noinst_PROGRAMS = qemu-boot ++ ++qemu_boot_SOURCES = \ ++ ../../df/estimate-max-threads.c \ ++ ../../df/estimate-max-threads.h \ ++ qemu-boot.c ++qemu_boot_CPPFLAGS = \ ++ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ ++ -I$(top_srcdir)/src -I$(top_builddir)/src \ ++ -I$(top_srcdir)/df ++qemu_boot_CFLAGS = \ ++ -pthread \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) ++qemu_boot_LDADD = \ ++ $(top_builddir)/src/libutils.la \ ++ $(top_builddir)/src/libguestfs.la \ ++ $(LIBXML2_LIBS) \ ++ $(LIBVIRT_LIBS) \ ++ $(LTLIBINTL) \ ++ $(top_builddir)/gnulib/lib/libgnu.la +diff --git a/utils/qemu-boot/qemu-boot.c b/utils/qemu-boot/qemu-boot.c +new file mode 100644 +index 0000000..336c26e +--- /dev/null ++++ b/utils/qemu-boot/qemu-boot.c +@@ -0,0 +1,362 @@ ++/* libguestfs ++ * Copyright (C) 2014-2016 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. ++ */ ++ ++/* Ancient libguestfs had a script called test-bootbootboot which just ++ * booted up the appliance in a loop. This was necessary back in the ++ * bad old days when qemu was not very reliable. This is the ++ * spiritual successor of that script, designed to find bugs in ++ * aarch64 KVM. You can control the number of boots that are done and ++ * the amount of parallelism. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++#include "estimate-max-threads.h" ++ ++#define MIN(a,b) ((a)<(b)?(a):(b)) ++ ++/* Maximum number of threads we would ever run. Note this should not ++ * be > 20, unless libvirt is modified to increase the maximum number ++ * of clients. User can override this limit using -P. ++ */ ++#define MAX_THREADS 12 ++ ++static size_t n; /* Number of qemu processes to run in total. */ ++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static int ignore_errors = 0; ++static const char *log_template = NULL; ++static size_t log_file_size; ++static int trace = 0; ++static int verbose = 0; ++ ++/* Events captured by the --log option. */ ++static const uint64_t event_bitmask = ++ GUESTFS_EVENT_LIBRARY | ++ GUESTFS_EVENT_WARNING | ++ GUESTFS_EVENT_APPLIANCE | ++ GUESTFS_EVENT_TRACE; ++ ++struct thread_data { ++ int thread_num; ++ int r; ++}; ++ ++static void *start_thread (void *thread_data_vp); ++static void 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 ++usage (int exitcode) ++{ ++ fprintf (stderr, ++ "qemu-boot: A program for repeatedly running the libguestfs appliance.\n" ++ "qemu-boot [-i] [--log output.%%] [-P ] -n \n" ++ " -i Ignore errors\n" ++ " --log \n" ++ " Write per-appliance logs to file (%% in name replaced by boot number)\n" ++ " -P Set number of parallel threads\n" ++ " (default is based on the amount of free memory)\n" ++ " -n Set number of appliances to run before exiting\n" ++ " -v Verbose appliance\n" ++ " -x Enable libguestfs tracing\n"); ++ exit (exitcode); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ enum { HELP_OPTION = CHAR_MAX + 1 }; ++ static const char options[] = "in:P:vx"; ++ static const struct option long_options[] = { ++ { "help", 0, 0, HELP_OPTION }, ++ { "ignore", 0, 0, 'i' }, ++ { "log", 1, 0, 0 }, ++ { "number", 1, 0, 'n' }, ++ { "processes", 1, 0, 'P' }, ++ { "trace", 0, 0, 'x' }, ++ { "verbose", 0, 0, 'v' }, ++ { 0, 0, 0, 0 } ++ }; ++ size_t P = 0, i, errors; ++ int c, option_index; ++ int err; ++ void *status; ++ ++ for (;;) { ++ c = getopt_long (argc, argv, options, long_options, &option_index); ++ if (c == -1) break; ++ ++ switch (c) { ++ case 0: ++ /* Options which are long only. */ ++ if (STREQ (long_options[option_index].name, "log")) { ++ log_template = optarg; ++ log_file_size = strlen (log_template); ++ for (i = 0; i < strlen (log_template); ++i) { ++ if (log_template[i] == '%') ++ log_file_size += 64; ++ } ++ } ++ else { ++ fprintf (stderr, "%s: unknown long option: %s (%d)\n", ++ guestfs_int_program_name, long_options[option_index].name, option_index); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case 'i': ++ ignore_errors = 1; ++ break; ++ ++ case 'n': ++ if (sscanf (optarg, "%zu", &n) != 1 || n == 0) { ++ fprintf (stderr, "%s: -n option not numeric and greater than 0\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case 'P': ++ if (sscanf (optarg, "%zu", &P) != 1) { ++ fprintf (stderr, "%s: -P option not numeric\n", guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case 'v': ++ verbose = 1; ++ break; ++ ++ case 'x': ++ trace = 1; ++ break; ++ ++ case HELP_OPTION: ++ usage (EXIT_SUCCESS); ++ ++ default: ++ usage (EXIT_FAILURE); ++ } ++ } ++ ++ if (n == 0) { ++ fprintf (stderr, ++ "%s: must specify number of processes to run (-n option)\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ ++ if (optind != argc) { ++ fprintf (stderr, "%s: extra arguments found on the command line\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ ++ /* Calculate the number of threads to use. */ ++ if (P > 0) ++ P = MIN (n, P); ++ else ++ P = MIN (n, MIN (MAX_THREADS, estimate_max_threads ())); ++ ++ /* Start the worker threads. */ ++ struct thread_data thread_data[P]; ++ pthread_t threads[P]; ++ ++ for (i = 0; i < P; ++i) { ++ thread_data[i].thread_num = i; ++ err = pthread_create (&threads[i], NULL, start_thread, &thread_data[i]); ++ if (err != 0) { ++ fprintf (stderr, "%s: pthread_create[%zu]: %s\n", ++ guestfs_int_program_name, i, strerror (err)); ++ exit (EXIT_FAILURE); ++ } ++ } ++ ++ /* Wait for the threads to exit. */ ++ errors = 0; ++ for (i = 0; i < P; ++i) { ++ err = pthread_join (threads[i], &status); ++ if (err != 0) { ++ fprintf (stderr, "%s: pthread_join[%zu]: %s\n", ++ guestfs_int_program_name, i, strerror (err)); ++ errors++; ++ } ++ if (*(int *)status == -1) ++ errors++; ++ } ++ ++ exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); ++} ++ ++/* Worker thread. */ ++static void * ++start_thread (void *thread_data_vp) ++{ ++ struct thread_data *thread_data = thread_data_vp; ++ int quit = 0; ++ int err; ++ size_t i; ++ guestfs_h *g; ++ unsigned errors = 0; ++ char id[64]; ++ ++ for (;;) { ++ CLEANUP_FREE char *log_file = NULL; ++ CLEANUP_FCLOSE FILE *log_fp = NULL; ++ ++ /* Take the next process. */ ++ err = pthread_mutex_lock (&mutex); ++ if (err != 0) { ++ fprintf (stderr, "%s: pthread_mutex_lock: %s", ++ guestfs_int_program_name, strerror (err)); ++ goto error; ++ } ++ ++ i = n; ++ if (i > 0) { ++ printf ("%zu to go ... \r", n); ++ fflush (stdout); ++ ++ n--; ++ } ++ else ++ quit = 1; ++ ++ err = pthread_mutex_unlock (&mutex); ++ if (err != 0) { ++ fprintf (stderr, "%s: pthread_mutex_unlock: %s", ++ guestfs_int_program_name, strerror (err)); ++ goto error; ++ } ++ ++ if (quit) /* Work finished. */ ++ break; ++ ++ g = guestfs_create (); ++ if (g == NULL) { ++ perror ("guestfs_create"); ++ errors++; ++ if (!ignore_errors) ++ goto error; ++ } ++ ++ /* Only if using --log, set up a callback. See examples/debug-logging.c */ ++ if (log_template != NULL) { ++ size_t j, k; ++ ++ log_file = malloc (log_file_size + 1); ++ if (log_file == NULL) abort (); ++ for (j = 0, k = 0; j < strlen (log_template); ++j) { ++ if (log_template[j] == '%') { ++ snprintf (&log_file[k], log_file_size - k, "%zu", i); ++ k += strlen (&log_file[k]); ++ } ++ else ++ log_file[k++] = log_template[j]; ++ } ++ log_file[k] = '\0'; ++ log_fp = fopen (log_file, "w"); ++ if (log_fp == NULL) { ++ perror (log_file); ++ abort (); ++ } ++ guestfs_set_event_callback (g, message_callback, ++ event_bitmask, 0, log_fp); ++ } ++ ++ snprintf (id, sizeof id, "%zu", i); ++ guestfs_set_identifier (g, id); ++ ++ guestfs_set_trace (g, trace); ++ guestfs_set_verbose (g, verbose); ++ ++ if (guestfs_add_drive_ro (g, "/dev/null") == -1) { ++ errors++; ++ if (!ignore_errors) ++ goto error; ++ } ++ ++ if (guestfs_launch (g) == -1) { ++ errors++; ++ if (!ignore_errors) ++ goto error; ++ } ++ ++ if (guestfs_shutdown (g) == -1) { ++ errors++; ++ if (!ignore_errors) ++ goto error; ++ } ++ ++ guestfs_close (g); ++ } ++ ++ if (errors > 0) { ++ fprintf (stderr, "%s: thread %d: %u errors were ignored\n", ++ guestfs_int_program_name, thread_data->thread_num, errors); ++ goto error; ++ } ++ ++ thread_data->r = 0; ++ return &thread_data->r; ++ ++ error: ++ thread_data->r = -1; ++ return &thread_data->r; ++} ++ ++/* If using --log, this is called to write messages to the log file. */ ++static void ++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) ++{ ++ FILE *fp = opaque; ++ ++ if (buf_len > 0) { ++ CLEANUP_FREE char *msg = strndup (buf, buf_len); ++ ++ switch (event) { ++ case GUESTFS_EVENT_APPLIANCE: ++ fprintf (fp, "%s", msg); ++ break; ++ case GUESTFS_EVENT_LIBRARY: ++ fprintf (fp, "libguestfs: %s\n", msg); ++ break; ++ case GUESTFS_EVENT_WARNING: ++ fprintf (fp, "libguestfs: warning: %s\n", msg); ++ break; ++ case GUESTFS_EVENT_TRACE: ++ fprintf (fp, "libguestfs: trace: %s\n", msg); ++ break; ++ } ++ fflush (fp); ++ } ++} +diff --git a/utils/qemu-speed-test/Makefile.am b/utils/qemu-speed-test/Makefile.am +new file mode 100644 +index 0000000..bf1c915 +--- /dev/null ++++ b/utils/qemu-speed-test/Makefile.am +@@ -0,0 +1,36 @@ ++# libguestfs ++# Copyright (C) 2011-2016 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 $(top_srcdir)/subdir-rules.mk ++ ++noinst_PROGRAMS = qemu-speed-test ++ ++qemu_speed_test_SOURCES = \ ++ qemu-speed-test.c ++qemu_speed_test_CPPFLAGS = \ ++ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ ++ -I$(top_srcdir)/src -I$(top_builddir)/src \ ++ -I$(top_srcdir)/df ++qemu_speed_test_CFLAGS = \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) ++qemu_speed_test_LDADD = \ ++ $(top_builddir)/src/libutils.la \ ++ $(top_builddir)/src/libguestfs.la \ ++ $(LIBXML2_LIBS) \ ++ $(LIBVIRT_LIBS) \ ++ $(LTLIBINTL) \ ++ $(top_builddir)/gnulib/lib/libgnu.la +diff --git a/utils/qemu-speed-test/qemu-speed-test.c b/utils/qemu-speed-test/qemu-speed-test.c +new file mode 100644 +index 0000000..d5e34c3 +--- /dev/null ++++ b/utils/qemu-speed-test/qemu-speed-test.c +@@ -0,0 +1,480 @@ ++/* libguestfs ++ * Copyright (C) 2014 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 the speed of various qemu features. Currently tested are: ++ * - virtio-serial upload ++ * - virtio-serial download ++ * - block device read ++ * - block device write ++ * More to come in future. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++static void test_virtio_serial (void); ++static void test_block_device (void); ++ ++/* Which tests are enabled? -- All by default. */ ++static int virtio_serial_upload = 1; ++static int virtio_serial_download = 1; ++static int block_device_write = 1; ++static int block_device_read = 1; ++ ++static int max_time_override = 0; ++ ++static void ++reset_default_tests (int *flag) ++{ ++ if (*flag) { ++ virtio_serial_upload = 0; ++ virtio_serial_download = 0; ++ block_device_write = 0; ++ block_device_read = 0; ++ *flag = 0; ++ } ++} ++ ++static void ++usage (int exitcode) ++{ ++ fprintf (stderr, ++ "qemu-speed-test: Test the speed of qemu features.\n" ++ "\n" ++ "To run all tests (recommended), do:\n" ++ " qemu-speed-test\n" ++ "\n" ++ "To run only specific tests, do:\n" ++ " qemu-speed-test --option [--option ...]\n" ++ "where the test options are:\n" ++ " --virtio-serial-upload\n" ++ " --virtio-serial-download\n" ++ " --block-device-write\n" ++ " --block-device-read\n" ++ "\n" ++ "Other options:\n" ++ " --help Display help output and exit\n" ++ " -t | --time= Set max length of test in seconds\n" ++ ); ++ exit (exitcode); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ enum { HELP_OPTION = CHAR_MAX + 1 }; ++ static const char options[] = "t:"; ++ static const struct option long_options[] = { ++ { "help", 0, 0, HELP_OPTION }, ++ { "time", 1, 0, 't' }, ++ ++ /* Tests. */ ++ { "virtio-serial-upload", 0, 0, 0 }, ++ { "virtio-serial-download", 0, 0, 0 }, ++ { "block-device-write", 0, 0, 0 }, ++ { "block-device-read", 0, 0, 0 }, ++ ++ { 0, 0, 0, 0 } ++ }; ++ int c, option_index; ++ int reset_flag = 1; ++ ++ for (;;) { ++ c = getopt_long (argc, argv, options, long_options, &option_index); ++ if (c == -1) break; ++ ++ switch (c) { ++ case 0: ++ /* Options which are long only. */ ++ if (STREQ (long_options[option_index].name, "virtio-serial-upload")) { ++ reset_default_tests (&reset_flag); ++ virtio_serial_upload = 1; ++ } ++ else if (STREQ (long_options[option_index].name, "virtio-serial-download")) { ++ reset_default_tests (&reset_flag); ++ virtio_serial_download = 1; ++ } ++ else if (STREQ (long_options[option_index].name, "block-device-write")) { ++ reset_default_tests (&reset_flag); ++ block_device_write = 1; ++ } ++ else if (STREQ (long_options[option_index].name, "block-device-read")) { ++ reset_default_tests (&reset_flag); ++ block_device_read = 1; ++ } ++ else { ++ fprintf (stderr, "%s: unknown long option: %s (%d)\n", ++ guestfs_int_program_name, long_options[option_index].name, option_index); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case 't': ++ if (sscanf (optarg, "%d", &max_time_override) != 1 || ++ max_time_override < 0) { ++ fprintf (stderr, "%s: -t: argument is not a positive integer\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ break; ++ ++ case HELP_OPTION: ++ usage (EXIT_SUCCESS); ++ ++ default: ++ usage (EXIT_FAILURE); ++ } ++ } ++ ++ if (optind != argc) { ++ fprintf (stderr, "%s: extra arguments found on the command line\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ ++ test_virtio_serial (); ++ test_block_device (); ++ ++ exit (EXIT_SUCCESS); ++} ++ ++static void ++print_rate (const char *msg, int64_t rate) ++{ ++ printf ("%-40s %" PRIi64 " bytes/sec (%" PRIi64 " Mbytes/sec)\n", ++ msg, rate, rate / 1024 / 1024); ++ fflush (stdout); ++} ++ ++/* The maximum time we will spend running the test (seconds). */ ++#define TEST_SERIAL_MAX_TIME 30 ++ ++/* The maximum amount of data to copy. You can safely make this very ++ * large because it's only making sparse files. ++ */ ++#define TEST_SERIAL_MAX_SIZE \ ++ (INT64_C(1024) * INT64_C(1024) * INT64_C(1024) * INT64_C(1024)) ++ ++static guestfs_h *g; ++static struct timeval start; ++static const char *operation; ++static int64_t rate; ++ ++static void ++stop_transfer (int sig) ++{ ++ guestfs_user_cancel (g); ++} ++ ++/* Compute Y - X and return the result in milliseconds. ++ * Approximately the same as this code: ++ * http://www.mpp.mpg.de/~huber/util/timevaldiff.c ++ */ ++static int64_t ++timeval_diff (const struct timeval *x, const struct timeval *y) ++{ ++ int64_t msec; ++ ++ msec = (y->tv_sec - x->tv_sec) * 1000; ++ msec += (y->tv_usec - x->tv_usec) / 1000; ++ return msec; ++} ++ ++static void ++progress_cb (guestfs_h *g, void *vp, uint64_t event, ++ int eh, int flags, ++ const char *buf, size_t buflen, ++ const uint64_t *array, size_t arraylen) ++{ ++ uint64_t transferred; ++ struct timeval now; ++ int64_t millis; ++ ++ assert (event == GUESTFS_EVENT_PROGRESS); ++ assert (arraylen >= 4); ++ ++ gettimeofday (&now, NULL); ++ ++ /* Bytes transferred. */ ++ transferred = array[2]; ++ ++ /* Calculate the speed of the upload or download. */ ++ millis = timeval_diff (&start, &now); ++ assert (millis >= 0); ++ ++ if (millis != 0) { ++ rate = 1000 * transferred / millis; ++ printf ("%s: %" PRIi64 " bytes/sec \r", ++ operation, rate); ++ fflush (stdout); ++ } ++} ++ ++static void ++test_virtio_serial (void) ++{ ++ int fd, r, eh; ++ char tmpfile[] = "/tmp/speedtestXXXXXX"; ++ struct sigaction sa, old_sa; ++ ++ if (!virtio_serial_upload && !virtio_serial_download) ++ return; ++ ++ /* Create a sparse file. We could upload from /dev/zero, but we ++ * won't get progress messages because libguestfs tests if the ++ * source file is a regular file. ++ */ ++ fd = mkstemp (tmpfile); ++ if (fd == -1) { ++ perror ("mkstemp"); ++ exit (EXIT_FAILURE); ++ } ++ if (ftruncate (fd, TEST_SERIAL_MAX_SIZE) == -1) { ++ perror ("ftruncate"); ++ exit (EXIT_FAILURE); ++ } ++ if (close (fd) == -1) { ++ perror ("close"); ++ exit (EXIT_FAILURE); ++ } ++ ++ g = guestfs_create (); ++ if (!g) { ++ perror ("guestfs_create"); ++ exit (EXIT_FAILURE); ++ } ++ ++ if (guestfs_add_drive_scratch (g, INT64_C (100*1024*1024), -1) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ ++ /* Make and mount a filesystem which will be used by the download test. */ ++ if (guestfs_mkfs (g, "ext4", "/dev/sda") == -1) ++ exit (EXIT_FAILURE); ++ if (guestfs_mount (g, "/dev/sda", "/") == -1) ++ exit (EXIT_FAILURE); ++ ++ /* Time out the upload after TEST_SERIAL_MAX_TIME seconds have passed. */ ++ memset (&sa, 0, sizeof sa); ++ sa.sa_handler = stop_transfer; ++ sa.sa_flags = SA_RESTART; ++ sigaction (SIGALRM, &sa, &old_sa); ++ ++ /* Get progress messages, which will tell us how much data has been ++ * transferred. ++ */ ++ eh = guestfs_set_event_callback (g, progress_cb, GUESTFS_EVENT_PROGRESS, ++ 0, NULL); ++ if (eh == -1) ++ exit (EXIT_FAILURE); ++ ++ if (virtio_serial_upload) { ++ gettimeofday (&start, NULL); ++ rate = -1; ++ operation = "upload"; ++ alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME); ++ ++ /* For the upload test, upload the sparse file to /dev/null in the ++ * appliance. Hopefully this is mostly testing just virtio-serial. ++ */ ++ guestfs_push_error_handler (g, NULL, NULL); ++ r = guestfs_upload (g, tmpfile, "/dev/null"); ++ alarm (0); ++ unlink (tmpfile); ++ guestfs_pop_error_handler (g); ++ ++ /* It's possible that the upload will finish before the alarm fires, ++ * or that the upload will be stopped by the alarm. ++ */ ++ if (r == -1 && guestfs_last_errno (g) != EINTR) { ++ fprintf (stderr, ++ "%s: expecting upload command to return EINTR\n%s\n", ++ guestfs_int_program_name, guestfs_last_error (g)); ++ exit (EXIT_FAILURE); ++ } ++ ++ if (rate == -1) { ++ rate_error: ++ fprintf (stderr, "%s: internal error: progress callback was not called! (r=%d, errno=%d)\n", ++ guestfs_int_program_name, ++ r, guestfs_last_errno (g)); ++ exit (EXIT_FAILURE); ++ } ++ ++ print_rate ("virtio-serial upload rate:", rate); ++ } ++ ++ if (virtio_serial_download) { ++ /* For the download test, download a sparse file within the ++ * appliance to /dev/null on the host. ++ */ ++ if (guestfs_touch (g, "/sparse") == -1) ++ exit (EXIT_FAILURE); ++ if (guestfs_truncate_size (g, "/sparse", TEST_SERIAL_MAX_SIZE) == -1) ++ exit (EXIT_FAILURE); ++ ++ gettimeofday (&start, NULL); ++ rate = -1; ++ operation = "download"; ++ alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME); ++ guestfs_push_error_handler (g, NULL, NULL); ++ r = guestfs_download (g, "/sparse", "/dev/null"); ++ alarm (0); ++ guestfs_pop_error_handler (g); ++ ++ if (r == -1 && guestfs_last_errno (g) != EINTR) { ++ fprintf (stderr, ++ "%s: expecting download command to return EINTR\n%s\n", ++ guestfs_int_program_name, guestfs_last_error (g)); ++ exit (EXIT_FAILURE); ++ } ++ ++ if (rate == -1) ++ goto rate_error; ++ ++ print_rate ("virtio-serial download rate:", rate); ++ } ++ ++ if (guestfs_shutdown (g) == -1) ++ exit (EXIT_FAILURE); ++ ++ guestfs_close (g); ++ ++ /* Restore SIGALRM signal handler. */ ++ sigaction (SIGALRM, &old_sa, NULL); ++} ++ ++/* The time we will spend running the test (seconds). */ ++#define TEST_BLOCK_DEVICE_TIME 30 ++ ++static void ++test_block_device (void) ++{ ++ int fd; ++ char tmpfile[] = "/tmp/speedtestXXXXXX"; ++ CLEANUP_FREE char **devices = NULL; ++ char *r; ++ const char *argv[4]; ++ const int t = ++ max_time_override > 0 ? max_time_override : TEST_BLOCK_DEVICE_TIME; ++ char tbuf[64]; ++ int64_t bytes_written, bytes_read; ++ ++ if (!block_device_write && !block_device_read) ++ return; ++ ++ snprintf (tbuf, sizeof tbuf, "%d", t); ++ ++ g = guestfs_create (); ++ if (!g) { ++ perror ("guestfs_create"); ++ exit (EXIT_FAILURE); ++ } ++ ++ /* Create a fully allocated backing file. Note we are not testing ++ * the speed of allocation on the host. ++ */ ++ fd = mkstemp (tmpfile); ++ if (fd == -1) { ++ perror ("mkstemp"); ++ exit (EXIT_FAILURE); ++ } ++ close (fd); ++ ++ if (guestfs_disk_create (g, tmpfile, "raw", ++ INT64_C (1024*1024*1024), ++ GUESTFS_DISK_CREATE_PREALLOCATION, "full", ++ -1) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (guestfs_add_drive (g, tmpfile) == -1) ++ exit (EXIT_FAILURE); ++ ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ ++ devices = guestfs_list_devices (g); ++ if (devices == NULL) ++ exit (EXIT_FAILURE); ++ if (devices[0] == NULL) { ++ fprintf (stderr, "%s: expected guestfs_list_devices to return at least 1 device\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ ++ if (block_device_write) { ++ /* Test write speed. */ ++ argv[0] = devices[0]; ++ argv[1] = "w"; ++ argv[2] = tbuf; ++ argv[3] = NULL; ++ r = guestfs_debug (g, "device_speed", (char **) argv); ++ if (r == NULL) ++ exit (EXIT_FAILURE); ++ ++ if (sscanf (r, "%" SCNi64, &bytes_written) != 1) { ++ fprintf (stderr, "%s: could not parse device_speed output\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ ++ print_rate ("block device writes:", bytes_written / t); ++ } ++ ++ if (block_device_read) { ++ /* Test read speed. */ ++ argv[0] = devices[0]; ++ argv[1] = "r"; ++ argv[2] = tbuf; ++ argv[3] = NULL; ++ r = guestfs_debug (g, "device_speed", (char **) argv); ++ if (r == NULL) ++ exit (EXIT_FAILURE); ++ ++ if (sscanf (r, "%" SCNi64, &bytes_read) != 1) { ++ fprintf (stderr, "%s: could not parse device_speed output\n", ++ guestfs_int_program_name); ++ exit (EXIT_FAILURE); ++ } ++ ++ print_rate ("block device reads:", bytes_read / t); ++ } ++ ++ if (guestfs_shutdown (g) == -1) ++ exit (EXIT_FAILURE); ++ ++ guestfs_close (g); ++ ++ /* Remove temporary file. */ ++ unlink (tmpfile); ++} +-- +1.8.3.1 + diff --git a/SOURCES/0078-v2v-Don-t-use-epoch-prefix-on-RPM-command-line-for-R.patch b/SOURCES/0078-v2v-Don-t-use-epoch-prefix-on-RPM-command-line-for-R.patch deleted file mode 100644 index 578be9f..0000000 --- a/SOURCES/0078-v2v-Don-t-use-epoch-prefix-on-RPM-command-line-for-R.patch +++ /dev/null @@ -1,47 +0,0 @@ -From e3bdd5ea6af8c44ec5338b43f91d49518f604d3a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 5 Dec 2014 13:09:10 +0000 -Subject: [PATCH] v2v: Don't use epoch prefix on RPM command line for RHEL <= 4 - (RHBZ#1170685). - -See the explanation here: -https://bugzilla.redhat.com/show_bug.cgi?id=1170685#c7 - -(cherry picked from commit 205a8c7ca1ed1d66bef56d75c3c244e726e3bbbf) ---- - v2v/linux.ml | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/v2v/linux.ml b/v2v/linux.ml -index 4287a4f..32a4a21 100644 ---- a/v2v/linux.ml -+++ b/v2v/linux.ml -@@ -129,9 +129,22 @@ let file_list_of_package verbose (g : Guestfs.guestfs) inspect app = - sprintf "%s-%s-%s" app.G.app2_name - app.G.app2_version app.G.app2_release in - let pkg_name = -- if app.G.app2_epoch > 0_l then -- sprintf "%ld:%s" app.G.app2_epoch pkg_name -- else -+ if app.G.app2_epoch > 0_l then ( -+ (* RHEL 3/4 'rpm' does not support using the epoch prefix. -+ * (RHBZ#1170685). -+ *) -+ let is_rhel_lt_5 = -+ match inspect with -+ | { i_type = "linux"; -+ i_distro = "rhel" | "centos" | "scientificlinux" | -+ "redhat-based"; -+ i_major_version = v } when v < 5 -> true -+ | _ -> false in -+ if is_rhel_lt_5 then -+ pkg_name -+ else -+ sprintf "%ld:%s" app.G.app2_epoch pkg_name -+ ) else - pkg_name in - let cmd = [| "rpm"; "-ql"; pkg_name |] in - if verbose then eprintf "%s\n%!" (String.concat " " (Array.to_list cmd)); --- -1.8.3.1 - diff --git a/SOURCES/0079-utils-boot-analysis-utils-boot-benchmark-Add-manual-.patch b/SOURCES/0079-utils-boot-analysis-utils-boot-benchmark-Add-manual-.patch new file mode 100644 index 0000000..5de75e7 --- /dev/null +++ b/SOURCES/0079-utils-boot-analysis-utils-boot-benchmark-Add-manual-.patch @@ -0,0 +1,356 @@ +From 915d73995f518d7592dbbca8776ddbfcb3f205de Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 3 May 2016 13:05:54 +0100 +Subject: [PATCH] utils/boot-analysis, utils/boot-benchmark: Add manual pages. + +(cherry picked from commit 98b28b15c61e871c3b3c5efdf4387e570133c4f9) +--- + .gitignore | 2 + + docs/guestfs-performance.pod | 4 ++ + utils/boot-analysis/Makefile.am | 13 +++++ + utils/boot-analysis/boot-analysis.c | 39 +------------ + utils/boot-analysis/boot-analysis.pod | 99 +++++++++++++++++++++++++++++++++ + utils/boot-benchmark/Makefile.am | 13 ++++- + utils/boot-benchmark/boot-benchmark.c | 2 +- + utils/boot-benchmark/boot-benchmark.pod | 68 ++++++++++++++++++++++ + 8 files changed, 200 insertions(+), 40 deletions(-) + create mode 100644 utils/boot-analysis/boot-analysis.pod + create mode 100644 utils/boot-benchmark/boot-benchmark.pod + +diff --git a/.gitignore b/.gitignore +index d79dc98..85b19d4 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -558,7 +558,9 @@ Makefile.in + /tools/stamp-virt-*.pod + /tools/virt-*.1 + /utils/boot-analysis/boot-analysis ++/utils/boot-analysis/boot-analysis.1 + /utils/boot-benchmark/boot-benchmark ++/utils/boot-benchmark/boot-benchmark.1 + /utils/qemu-boot/qemu-boot + /utils/qemu-speed-test/qemu-speed-test + /v2v/.depend +diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod +index 7304b63..b6c25e1 100644 +--- a/docs/guestfs-performance.pod ++++ b/docs/guestfs-performance.pod +@@ -38,6 +38,8 @@ run it, do: + make + ./run utils/boot-benchmark/boot-benchmark + ++There is a manual page F ++ + =head3 Explanation + + The guestfish command above starts up the libguestfs appliance on a +@@ -453,6 +455,8 @@ To run this program, do: + make + ./run utils/boot-analysis/boot-analysis + ++There is a manual page F ++ + =head2 Detailed timings using ts + + Use the L command (from moreutils) to show detailed +diff --git a/utils/boot-analysis/Makefile.am b/utils/boot-analysis/Makefile.am +index ef9b2cb..d708de2 100644 +--- a/utils/boot-analysis/Makefile.am ++++ b/utils/boot-analysis/Makefile.am +@@ -17,6 +17,8 @@ + + include $(top_srcdir)/subdir-rules.mk + ++EXTRA_DIST = boot-analysis.pod ++ + noinst_PROGRAMS = boot-analysis + + boot_analysis_SOURCES = \ +@@ -41,3 +43,14 @@ boot_analysis_LDADD = \ + $(LTLIBINTL) \ + $(top_builddir)/gnulib/lib/libgnu.la \ + -lm ++ ++# Manual page. ++# It should be noinst_MANS but that doesn't work. ++noinst_DATA = boot-analysis.1 ++ ++boot-analysis.1: boot-analysis.pod ++ $(PODWRAPPER) \ ++ --man $@ \ ++ --license GPLv2+ \ ++ --warning safe \ ++ $< +diff --git a/utils/boot-analysis/boot-analysis.c b/utils/boot-analysis/boot-analysis.c +index b90806b..461c69e 100644 +--- a/utils/boot-analysis/boot-analysis.c ++++ b/utils/boot-analysis/boot-analysis.c +@@ -16,44 +16,7 @@ + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +-/* Trace and analyze the appliance boot process to find out which +- * steps are taking the most time. It is not part of the standard +- * tests. +- * +- * This needs to be run on a quiet machine, so that other processes +- * disturb the timing as little as possible. The program is +- * completely safe to run at any time. It doesn't read or write any +- * external files, and it doesn't require root. +- * +- * You can run it from the build directory like this: +- * +- * make +- * ./run utils/boot-analysis/boot-analysis +- * +- * The way it works is roughly like this: +- * +- * We create a libguestfs handle and register callback handlers so we +- * can see appliance messages, trace events and so on. +- * +- * We then launch the handle and shut it down as quickly as possible. +- * +- * While the handle is running, events (seen by the callback handlers) +- * are written verbatim into an in-memory buffer, with timestamps. +- * +- * Afterwards we analyze the result using regular expressions to try +- * to identify a "timeline" for the handle (eg. at what time did the +- * BIOS hand control to the kernel). This analysis is done in +- * 'boot-analysis-timeline.c'. +- * +- * The whole process is repeated across a few runs, and the final +- * timeline (including statistical analysis of the variation between +- * runs) gets printed. +- * +- * The program is very sensitive to the specific messages printed by +- * BIOS/kernel/supermin/userspace, so it won't work on non-x86, and it +- * will require periodic adjustment of the regular expressions in +- * order to keep things up to date. +- */ ++/* See instructions in boot-analysis.1 */ + + #include + +diff --git a/utils/boot-analysis/boot-analysis.pod b/utils/boot-analysis/boot-analysis.pod +new file mode 100644 +index 0000000..07cc801 +--- /dev/null ++++ b/utils/boot-analysis/boot-analysis.pod +@@ -0,0 +1,99 @@ ++=head1 NAME ++ ++boot-analysis - Trace and analyze the appliance boot process ++ ++=head1 SYNOPSIS ++ ++ ./run utils/boot-analysis/boot-analysis ++ ++=head1 DESCRIPTION ++ ++Trace and analyze the appliance boot process to find out which steps ++are taking the most time. It is not part of the standard tests. ++ ++This needs to be run on a quiet machine, so that other processes ++disturb the timing as little as possible. The program is completely ++safe to run at any time. It doesn't read or write any external files, ++and it doesn't require root. ++ ++You can run it from the build directory on the built copy of ++libguestfs like this: ++ ++ make ++ ./run utils/boot-analysis/boot-analysis ++ ++If you omit C<./run> then it is run on the installed copy of libguestfs. ++ ++=head2 How it works ++ ++We create a libguestfs handle and register callback handlers so we ++can see appliance messages, trace events and so on. ++ ++We then launch the handle and shut it down as quickly as possible. ++ ++While the handle is running, events (seen by the callback handlers) ++are written verbatim into an in-memory buffer, with timestamps. ++ ++Afterwards we analyze the result using regular expressions to try to ++identify a "timeline" for the handle (eg. at what time did the BIOS ++hand control to the kernel). This analysis is done in ++F. ++ ++The whole process is repeated across a few runs, and the final ++timeline (including statistical analysis of the variation between ++runs) gets printed. ++ ++The program is very sensitive to the specific messages printed by ++BIOS/kernel/supermin/userspace. It only works on x86-64 or aarch64. ++It will require periodic adjustment of the regular expressions in ++order to keep things up to date. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=item B<--help> ++ ++Display brief help. ++ ++=item B<--append> "OPTIONS" ++ ++Append C to the kernel command line. ++ ++=item B<--color> ++ ++=item B<--colour> ++ ++Output colours (as ANSI escape sequences), even if the output is not a ++terminal. ++ ++=item B<-m> MB ++ ++=item B<--memsize> MB ++ ++Set the appliance memory size in MB. ++ ++=item B<--smp> N ++ ++Enable C virtual CPUs. ++ ++=item B<-v> ++ ++=item B<--verbose> ++ ++More verbose output, useful for debugging problems. ++ ++=back ++ ++=head1 SEE ALSO ++ ++L, ++L. ++ ++=head1 AUTHOR ++ ++Richard W.M. Jones L ++ ++=head1 COPYRIGHT ++ ++Copyright (C) 2016 Red Hat Inc. +diff --git a/utils/boot-benchmark/Makefile.am b/utils/boot-benchmark/Makefile.am +index 429832a..fed2428 100644 +--- a/utils/boot-benchmark/Makefile.am ++++ b/utils/boot-benchmark/Makefile.am +@@ -21,6 +21,8 @@ + + include $(top_srcdir)/subdir-rules.mk + ++EXTRA_DIST = boot-benchmark.pod boot-benchmark-range.pl ++ + noinst_PROGRAMS = boot-benchmark + + boot_benchmark_SOURCES = \ +@@ -41,4 +43,13 @@ boot_benchmark_LDADD = \ + $(top_builddir)/gnulib/lib/libgnu.la \ + -lm + +-EXTRA_DIST = boot-benchmark-range.pl ++# Manual page. ++# It should be noinst_MANS but that doesn't work. ++noinst_DATA = boot-benchmark.1 ++ ++boot-benchmark.1: boot-benchmark.pod ++ $(PODWRAPPER) \ ++ --man $@ \ ++ --license GPLv2+ \ ++ --warning safe \ ++ $< +diff --git a/utils/boot-benchmark/boot-benchmark.c b/utils/boot-benchmark/boot-benchmark.c +index 0508ee9..05cab50 100644 +--- a/utils/boot-benchmark/boot-benchmark.c ++++ b/utils/boot-benchmark/boot-benchmark.c +@@ -16,7 +16,7 @@ + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +-/* Benchmark the time taken to boot the libguestfs appliance. */ ++/* See instructions in boot-benchmark.1 */ + + #include + +diff --git a/utils/boot-benchmark/boot-benchmark.pod b/utils/boot-benchmark/boot-benchmark.pod +new file mode 100644 +index 0000000..b34546a +--- /dev/null ++++ b/utils/boot-benchmark/boot-benchmark.pod +@@ -0,0 +1,68 @@ ++=head1 NAME ++ ++boot-benchmark - Benchmark the time taken to boot the libguestfs appliance ++ ++=head1 SYNOPSIS ++ ++ ./run utils/boot-benchmark/boot-benchmark ++ ++=head1 DESCRIPTION ++ ++Benchmark the time taken to boot the libguestfs appliance. ++ ++It is essentially the same as doing: ++ ++ time guestfish -a /dev/null run ++ ++except that it warms up the caches and repeats the test many times, ++printing out the mean time and standard deviation. ++ ++This needs to be run on a quiet machine, so that other processes ++disturb the timing as little as possible. The program is completely ++safe to run at any time. It doesn't read or write any external files, ++and it doesn't require root. ++ ++You can run it from the build directory on the built copy of ++libguestfs like this: ++ ++ make ++ ./run utils/boot-benchmark/boot-benchmark ++ ++If you omit C<./run> then it is run on the installed copy of libguestfs. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=item B<--help> ++ ++Display brief help. ++ ++=item B<--append> "OPTIONS" ++ ++Append C to the kernel command line. ++ ++=item B<-m> MB ++ ++=item B<--memsize> MB ++ ++Set the appliance memory size in MB. ++ ++=item B<--smp> N ++ ++Enable C virtual CPUs. ++ ++=back ++ ++=head1 SEE ALSO ++ ++L, ++L. ++ ++=head1 AUTHOR ++ ++Richard W.M. Jones L ++ ++=head1 COPYRIGHT ++ ++Copyright (C) 2016 Red Hat Inc. +-- +1.8.3.1 + diff --git a/SOURCES/0079-v2v-Fix-missing-loop-device-which-breaks-conversion-.patch b/SOURCES/0079-v2v-Fix-missing-loop-device-which-breaks-conversion-.patch deleted file mode 100644 index 67e1b97..0000000 --- a/SOURCES/0079-v2v-Fix-missing-loop-device-which-breaks-conversion-.patch +++ /dev/null @@ -1,54 +0,0 @@ -From ea14134fc6b3305d28f317170e3c0daec00628ac Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 5 Dec 2014 13:52:25 +0000 -Subject: [PATCH] v2v: Fix missing loop device which breaks conversion of RHEL - 3 guests (RHBZ#1171130). - -(cherry picked from commit 1bd779c983d62f36bf50ad613928cf209f98fbce) ---- - v2v/convert_linux.ml | 26 +++++++++++++++++++++----- - 1 file changed, 21 insertions(+), 5 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 5852022..a4897ca 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -883,14 +883,30 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - (* loop is a module in RHEL 5. Try to load it. Doesn't matter - * for other OSs if it doesn't exist, but RHEL 5 will complain: - * "All of your loopback devices are in use." -- * -- * XXX RHEL 3 unfortunately will give this error anyway. -- * mkinitrd runs the nash command `findlodev' which is -- * essentially incompatible with modern kernels that don't -- * have fixed /dev/loopN devices. - *) - (try g#modprobe "loop" with G.Error _ -> ()); - -+ (* On RHEL 3 we have to take extra gritty to get a working -+ * loopdev. mkinitrd runs the nash command `findlodev' -+ * which does this: -+ * -+ * for (devNum = 0; devNum < 256; devNum++) { -+ * sprintf(devName, "/dev/loop%s%d", separator, devNum); -+ * if ((fd = open(devName, O_RDONLY)) < 0) return 0; -+ * if (ioctl(fd, LOOP_GET_STATUS, &loopInfo)) { -+ * close(fd); -+ * printf("%s\n", devName); -+ * return 0; -+ * // etc -+ * -+ * In a modern kernel, /dev/loop isn't created until it is -+ * used. But we can create /dev/loop0 manually. Note we have -+ * to do this in the appliance /dev. (RHBZ#1171130) -+ *) -+ if family = `RHEL_family && inspect.i_major_version = 3 then -+ ignore (g#debug "sh" [| "mknod"; "-m"; "0666"; -+ "/dev/loop0"; "b"; "7"; "0" |]); -+ - (* RHEL 4 mkinitrd determines if the root filesystem is on LVM - * by checking if the device name (after following symlinks) - * starts with /dev/mapper. However, on recent kernels/udevs, --- -1.8.3.1 - diff --git a/SOURCES/0080-utils-Add-a-README-file-describing-briefly-the-purpo.patch b/SOURCES/0080-utils-Add-a-README-file-describing-briefly-the-purpo.patch new file mode 100644 index 0000000..135a0e3 --- /dev/null +++ b/SOURCES/0080-utils-Add-a-README-file-describing-briefly-the-purpo.patch @@ -0,0 +1,32 @@ +From 506b831d7993cf5074195c749f594d5d06c4a147 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 3 May 2016 21:47:11 +0100 +Subject: [PATCH] utils: Add a README file describing briefly the purpose of + this directory. + +.. and where to find the real documentation. + +Updates commit 3b581a727c9e906f9d9b10e2f73ed853ab324fd0. + +(cherry picked from commit bbec1b570b8b1edff7f2a39b0b86d625445dbaf2) +--- + utils/README | 7 +++++++ + 1 file changed, 7 insertions(+) + create mode 100644 utils/README + +diff --git a/utils/README b/utils/README +new file mode 100644 +index 0000000..ceaaadd +--- /dev/null ++++ b/utils/README +@@ -0,0 +1,7 @@ ++This directory contains miscellaneous utilities for profiling and ++testing libguestfs. For more information see guestfs-performance(1). ++ ++For libguestfs tools you should look in the specific tool directories ++such as cat/, df/, etc. ++ ++For an overview of libguestfs directories, see guestfs-hacking(1). +-- +1.8.3.1 + diff --git a/SOURCES/0080-v2v-Remove-documentation-about-Windows-Recovery-Cons.patch b/SOURCES/0080-v2v-Remove-documentation-about-Windows-Recovery-Cons.patch deleted file mode 100644 index a0a30aa..0000000 --- a/SOURCES/0080-v2v-Remove-documentation-about-Windows-Recovery-Cons.patch +++ /dev/null @@ -1,43 +0,0 @@ -From b8b1840641e271969eb588684ffc602aa522a93f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 5 Dec 2014 14:29:26 +0000 -Subject: [PATCH] v2v: Remove documentation about Windows Recovery Console not - supported. - -We have now successfully converted guests using WRC, so this statement -is no longer necessary. - -(cherry picked from commit a5423897677ff813baf708e28a53347ecfda33d2) ---- - v2v/virt-v2v.pod | 15 --------------- - 1 file changed, 15 deletions(-) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index edfa5a0..5c97984 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -1070,21 +1070,6 @@ B Take care not to interrupt the automatic driver installation - process when logging in to the guest for the first time, as this may - prevent the guest from subsequently booting correctly. - --=head2 Windows Recovery Console -- --Virt-v2v does not support conversion of the Windows Recovery Console. --If a guest has a recovery console installed and VirtIO was enabled --during conversion, attempting to boot the recovery console will result --in a BSOD. -- --Windows XP x86 does not support the Windows Recovery Console on VirtIO --systems, so there is no resolution to this. However, on Windows XP --AMD64 and Windows 2003 (x86 and AMD64), the recovery console can be --re-installed after conversion. The re-installation procedure is the --same as the initial installation procedure. It is not necessary to --remove the recovery console first. Following re-installation, the --recovery console will work as intended. -- - =head1 FREE SPACE FOR CONVERSION - - Virt-v2v checks there is sufficient free space in the guest filesystem --- -1.8.3.1 - diff --git a/SOURCES/0081-utils-Add-README-to-EXTRA_DIST.patch b/SOURCES/0081-utils-Add-README-to-EXTRA_DIST.patch new file mode 100644 index 0000000..d717d51 --- /dev/null +++ b/SOURCES/0081-utils-Add-README-to-EXTRA_DIST.patch @@ -0,0 +1,28 @@ +From 0f11af1c633ede0bf8efe6aa057b6500178c25fb Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 4 May 2016 18:16:26 +0100 +Subject: [PATCH] utils: Add README to EXTRA_DIST. + +Updates commit 3b581a727c9e906f9d9b10e2f73ed853ab324fd0 +and commit bbec1b570b8b1edff7f2a39b0b86d625445dbaf2. + +(cherry picked from commit ff7e755f954d1385d0d352d38f5d34c0e426972e) +--- + Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Makefile.am b/Makefile.am +index 079aa7d..5be6876 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -222,6 +222,7 @@ EXTRA_DIST = \ + tests/automake2junit.ml \ + tmp/.gitignore \ + update-bugs.sh \ ++ utils/README \ + valgrind-suppressions \ + website/bugs.png \ + website/communicate.png \ +-- +1.8.3.1 + diff --git a/SOURCES/0081-v2v-Add-documentation-about-what-to-do-about-BSOD-0x.patch b/SOURCES/0081-v2v-Add-documentation-about-what-to-do-about-BSOD-0x.patch deleted file mode 100644 index b78b2c3..0000000 --- a/SOURCES/0081-v2v-Add-documentation-about-what-to-do-about-BSOD-0x.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 81928e20d592ff7a30caf4c636cb851965a39b31 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 5 Dec 2014 15:04:03 +0000 -Subject: [PATCH] v2v: Add documentation about what to do about BSOD 0x0000007B - (RHBZ#1161333). - -After a very long and trying episode with a Windows guest that refused -to boot after conversion, we managed to successfully boot it by -disabling Windows Group Policy. It appears that Group Policy -prevented the virtio driver from being used. - -Document this in the manual. - -(cherry picked from commit be73b1750f3ce52ea137014083ed51d3b64f53a5) ---- - v2v/virt-v2v.pod | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 56 insertions(+) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 5c97984..5f4d42e 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -623,6 +623,62 @@ below. - Windows Drivers are installed from /usr/share/virtio-win - if present - -+=head1 WINDOWS -+ -+=head2 Boot failure: 0x0000007B -+ -+This boot failure is caused by Windows being unable to find or load -+the right disk driver (eg. C). If you experience this -+error, here are some things to check: -+ -+=over 4 -+ -+=item * -+ -+First ensure that the guest boots on the source hypervisor before -+conversion. -+ -+=item * -+ -+Check you have the Windows virtio drivers available in -+C, and that virt-v2v did not print any warning -+about not being able to install virtio drivers. -+ -+On S, you will need to install the signed -+drivers available in the C package. If you do not have -+access to the signed drivers, then you will probably need to disable -+driver signing in the boot menus. -+ -+=item * -+ -+Check that you are presenting a virtio-blk interface (B -+virtio-scsi and B ide) to the guest. On the qemu/KVM command -+line you should see something similar to this: -+ -+ ... -drive file=windows-sda,if=virtio ... -+ -+In libvirt XML, you should see: -+ -+ -+ -+=item * -+ -+Check that Windows Group Policy does not prevent the driver from being -+installed or used. Try deleting Windows Group Policy before -+conversion. -+ -+=item * -+ -+Check there is no anti-virus or other software which implements Group -+Policy-like prohibitions on installing or using new drivers. -+ -+=item * -+ -+Enable boot debugging and check the C driver is being -+loaded. -+ -+=back -+ - =head1 NETWORKS AND BRIDGES - - Guests are usually connected to one or more networks, and when --- -1.8.3.1 - diff --git a/SOURCES/0082-p2v-wait-for-qemu-nbd-before-starting-conversion-RHB.patch b/SOURCES/0082-p2v-wait-for-qemu-nbd-before-starting-conversion-RHB.patch deleted file mode 100644 index 844d095..0000000 --- a/SOURCES/0082-p2v-wait-for-qemu-nbd-before-starting-conversion-RHB.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 770be29b68b151964aff988de606963eaf04dbe3 Mon Sep 17 00:00:00 2001 -From: John Eckersberg -Date: Fri, 5 Dec 2014 16:58:13 -0500 -Subject: [PATCH] p2v: wait for qemu-nbd before starting conversion - (RHBZ#1167774) - -Wait up to 10 seconds for qemu-nbd to start up and respond to clients. -Otherwise the conversion server may attempt to connect before qemu-nbd -is ready to serve it. - -(cherry picked from commit 33098d23020bd3824a2954823a0dbaff751c814d) ---- - p2v/conversion.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 76 insertions(+) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index cb2deed..9f5a3ad 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -31,6 +31,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -39,6 +41,9 @@ - #include "miniexpect.h" - #include "p2v.h" - -+/* How long to wait for qemu-nbd to start (seconds). */ -+#define WAIT_QEMU_NBD_TIMEOUT 10 -+ - /* Data per NBD connection / physical disk. */ - struct data_conn { - mexp_h *h; /* miniexpect handle to ssh */ -@@ -49,6 +54,7 @@ struct data_conn { - - static int send_quoted (mexp_h *, const char *s); - static pid_t start_qemu_nbd (int nbd_local_port, const char *device); -+static int wait_qemu_nbd (int nbd_local_port, int timeout_seconds); - static void cleanup_data_conns (struct data_conn *data_conns, size_t nr); - static char *generate_libvirt_xml (struct config *, struct data_conn *); - static const char *map_interface_to_network (struct config *, const char *interface); -@@ -156,6 +162,11 @@ start_conversion (struct config *config, - if (data_conns[i].nbd_pid == 0) - goto out; - -+ /* Wait for qemu-nbd to listen */ -+ if (wait_qemu_nbd (data_conns[i].nbd_local_port, -+ WAIT_QEMU_NBD_TIMEOUT) == -1) -+ goto out; -+ - #if DEBUG_STDERR - fprintf (stderr, - "%s: data connection for %s: SSH remote port %d, local port %d\n", -@@ -371,6 +382,71 @@ start_qemu_nbd (int port, const char *device) - return pid; - } - -+static int -+wait_qemu_nbd (int nbd_local_port, int timeout_seconds) -+{ -+ int sockfd; -+ int result = -1; -+ struct sockaddr_in addr; -+ time_t start_t, now_t; -+ struct timeval timeout = { .tv_usec = 0 }; -+ char magic[8]; /* NBDMAGIC */ -+ size_t bytes_read = 0; -+ ssize_t recvd; -+ -+ time (&start_t); -+ -+ sockfd = socket (AF_INET, SOCK_STREAM, 0); -+ if (sockfd == -1) { -+ perror ("socket"); -+ return -1; -+ } -+ -+ memset (&addr, 0, sizeof addr); -+ addr.sin_family = AF_INET; -+ addr.sin_port = htons (nbd_local_port); -+ inet_pton (AF_INET, "localhost", &addr.sin_addr); -+ -+ for (;;) { -+ time (&now_t); -+ -+ if (now_t - start_t >= timeout_seconds) { -+ set_conversion_error ("waiting for qemu-nbd to start: connect: %m"); -+ goto cleanup; -+ } -+ -+ if (connect (sockfd, (struct sockaddr *) &addr, sizeof addr) == 0) -+ break; -+ } -+ -+ time (&now_t); -+ timeout.tv_sec = (start_t + timeout_seconds) - now_t; -+ setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout); -+ -+ do { -+ recvd = recv (sockfd, magic, sizeof magic - bytes_read, 0); -+ -+ if (recvd == -1) { -+ set_conversion_error ("waiting for qemu-nbd to start: recv: %m"); -+ goto cleanup; -+ } -+ -+ bytes_read += recvd; -+ } while (bytes_read < sizeof magic); -+ -+ if (memcmp (magic, "NBDMAGIC", sizeof magic) != 0) { -+ set_conversion_error ("waiting for qemu-nbd to start: " -+ "'NBDMAGIC' was not received from qemu-nbd"); -+ goto cleanup; -+ } -+ -+ result = 0; -+cleanup: -+ close (sockfd); -+ -+ return result; -+} -+ - static void - cleanup_data_conns (struct data_conn *data_conns, size_t nr) - { --- -1.8.3.1 - diff --git a/SOURCES/0082-utils-boot-analysis-Fix-minor-typo-in-string.patch b/SOURCES/0082-utils-boot-analysis-Fix-minor-typo-in-string.patch new file mode 100644 index 0000000..c6e7284 --- /dev/null +++ b/SOURCES/0082-utils-boot-analysis-Fix-minor-typo-in-string.patch @@ -0,0 +1,26 @@ +From b107e5b149b871caf80ce765c11b87c69fa86359 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 9 May 2016 12:19:16 +0100 +Subject: [PATCH] utils: boot-analysis: Fix minor typo in string. + +(cherry picked from commit 320b0faeaf67d80bccf8f81b9ebfcbcb68516fa1) +--- + utils/boot-analysis/boot-analysis-utils.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/utils/boot-analysis/boot-analysis-utils.c b/utils/boot-analysis/boot-analysis-utils.c +index 693b6f4..4308bea 100644 +--- a/utils/boot-analysis/boot-analysis-utils.c ++++ b/utils/boot-analysis/boot-analysis-utils.c +@@ -69,7 +69,7 @@ test_info (guestfs_h *g, int nr_test_passes) + + /* Related to qemu. */ + backend = guestfs_get_backend (g); +- printf (" backend: %-20s [to change set LIBGUESTFS_BACKEND]\n", ++ printf (" backend: %-20s [to change set $LIBGUESTFS_BACKEND]\n", + backend); + printf (" qemu: %-20s [to change set $LIBGUESTFS_HV]\n", qemu); + printf ("qemu version: "); +-- +1.8.3.1 + diff --git a/SOURCES/0083-boot-analysis-Make-ftrace-optional-in-the-timeline.patch b/SOURCES/0083-boot-analysis-Make-ftrace-optional-in-the-timeline.patch new file mode 100644 index 0000000..66c61de --- /dev/null +++ b/SOURCES/0083-boot-analysis-Make-ftrace-optional-in-the-timeline.patch @@ -0,0 +1,29 @@ +From a5d102f5b31dc98373bc73f2a1ea261d14baac73 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 10 May 2016 12:16:36 +0100 +Subject: [PATCH] boot-analysis: Make ftrace optional in the timeline. + +This allows me to test minimal kernels with ftrace disabled at +compile time. + +(cherry picked from commit e4edede3641f3c8d3ac729c1a6c871f532b2b996) +--- + utils/boot-analysis/boot-analysis-timeline.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/utils/boot-analysis/boot-analysis-timeline.c b/utils/boot-analysis/boot-analysis-timeline.c +index 09a78ef..905d1e3 100644 +--- a/utils/boot-analysis/boot-analysis-timeline.c ++++ b/utils/boot-analysis/boot-analysis-timeline.c +@@ -306,7 +306,7 @@ construct_timeline (void) + #endif + + /* ftrace patching instructions. */ +- FIND ("kernel:ftrace", 0, ++ FIND_OPTIONAL ("kernel:ftrace", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, "ftrace: allocating"), + 1); +-- +1.8.3.1 + diff --git a/SOURCES/0083-v2v-linux-Fix-modifications-to-default-kernel-for-le.patch b/SOURCES/0083-v2v-linux-Fix-modifications-to-default-kernel-for-le.patch deleted file mode 100644 index f074c49..0000000 --- a/SOURCES/0083-v2v-linux-Fix-modifications-to-default-kernel-for-le.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 574481cdd1ccef9e2cba8d8f44a26a538158803b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 10 Dec 2014 13:03:55 +0000 -Subject: [PATCH] v2v: linux: Fix modifications to default kernel for legacy - grub. - -This didn't work at all because the regular expression did not match -the returned Augeas path. - -In future if the regular expression doesn't match, this will give an -internal error instead of continuing with a bogus value. - -Thanks: Junqin Zhou for providing the test case and debug information. -(cherry picked from commit e1fd9615cc4a9ceb68f4a47a289712fc31a0af5e) ---- - v2v/convert_linux.ml | 11 +++++------ - 1 file changed, 5 insertions(+), 6 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index a4897ca..709b4b9 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -786,12 +786,11 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - if paths = [] then - error (f_"didn't find grub entry for kernel %s") kernel.ki_vmlinuz; - let path = List.hd paths in -- let rex = Str.regexp "/title\\[\\([1-9][0-9]*\\)\\]/kernel" in -- let index = -- if Str.string_match rex path 0 then -- (int_of_string (Str.matched_group 1 path) - 1) -- else -- 0 in -+ let rex = Str.regexp ".*/title\\[\\([1-9][0-9]*\\)\\]/kernel" in -+ if not (Str.string_match rex path 0) then -+ error (f_"internal error: regular expression did not match '%s'") -+ path; -+ let index = int_of_string (Str.matched_group 1 path) - 1 in - g#aug_set (sprintf "/files%s/default" grub_config) (string_of_int index); - g#aug_save () - --- -1.8.3.1 - diff --git a/SOURCES/0084-boot-analysis-Flush-out-debug-data-after-printing-it.patch b/SOURCES/0084-boot-analysis-Flush-out-debug-data-after-printing-it.patch new file mode 100644 index 0000000..b0a60e1 --- /dev/null +++ b/SOURCES/0084-boot-analysis-Flush-out-debug-data-after-printing-it.patch @@ -0,0 +1,38 @@ +From e8c04a323238bf2838520ae44a1d930b5d777bc7 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 10 May 2016 12:17:28 +0100 +Subject: [PATCH] boot-analysis: Flush out debug data after printing it. + +Just makes it easier to see bugs causing the analysis stage to +hang / infinite loop. + +(cherry picked from commit 754b8f5ef391ec4ee1b39db66b4923f9a8aa5cd9) +--- + utils/boot-analysis/boot-analysis.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/utils/boot-analysis/boot-analysis.c b/utils/boot-analysis/boot-analysis.c +index 461c69e..3d38fe2 100644 +--- a/utils/boot-analysis/boot-analysis.c ++++ b/utils/boot-analysis/boot-analysis.c +@@ -841,6 +841,8 @@ dump_pass_data (void) + printf ("\"\n"); + } + } ++ ++ fflush (stdout); + } + + /* Convert source to a printable string. The caller must free the +@@ -1018,6 +1020,8 @@ dump_timeline (void) + printf (" s.d = %.1f\n", activities[i].sd); + printf (" percent = %.1f\n", activities[i].percent); + } ++ ++ fflush (stdout); + } + + static void +-- +1.8.3.1 + diff --git a/SOURCES/0084-p2v-show-error-dialog-if-virt-v2v-fails-RHBZ-1167601.patch b/SOURCES/0084-p2v-show-error-dialog-if-virt-v2v-fails-RHBZ-1167601.patch deleted file mode 100644 index bc7ff57..0000000 --- a/SOURCES/0084-p2v-show-error-dialog-if-virt-v2v-fails-RHBZ-1167601.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 8e1ea1e5471bb96f8bd38e24da38f8d18effd1df Mon Sep 17 00:00:00 2001 -From: John Eckersberg -Date: Thu, 11 Dec 2014 08:38:49 -0500 -Subject: [PATCH] p2v: show error dialog if virt-v2v fails (RHBZ#1167601) - -Ensure the control connection exits with the same status code as -virt-v2v, and return an error from start_conversion if virt-v2v -failed. - -(cherry picked from commit 841aa0faf3b1495fd167e32b8105b0bc6faaea60) ---- - p2v/conversion.c | 17 ++++++++++++++--- - 1 file changed, 14 insertions(+), 3 deletions(-) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index 9f5a3ad..4ff7ecc 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -100,6 +100,7 @@ start_conversion (struct config *config, - void (*notify_ui) (int type, const char *data)) - { - int ret = -1; -+ int status; - size_t i, len; - size_t nr_disks = guestfs___count_strings (config->disks); - struct data_conn data_conns[nr_disks]; -@@ -276,7 +277,7 @@ start_conversion (struct config *config, - if (mexp_printf (control_h, " ) | tee %s/virt-v2v-conversion-log.txt", - remote_dir) == -1) - goto printf_fail; -- if (mexp_printf (control_h, "; exit") == -1) -+ if (mexp_printf (control_h, "; exit $(< %s/status)", remote_dir) == -1) - goto printf_fail; - if (mexp_printf (control_h, "\n") == -1) - goto printf_fail; -@@ -313,8 +314,18 @@ start_conversion (struct config *config, - - ret = 0; - out: -- if (control_h) -- mexp_close (control_h); -+ if (control_h) { -+ if ((status = mexp_close (control_h)) == -1) { -+ set_conversion_error ("mexp_close: %m"); -+ ret = -1; -+ } else if (ret == 0 && -+ WIFEXITED (status) && -+ WEXITSTATUS (status) != 0) { -+ set_conversion_error ("virt-v2v exited with status %d", -+ WEXITSTATUS (status)); -+ ret = -1; -+ } -+ } - cleanup_data_conns (data_conns, nr_disks); - return ret; - } --- -1.8.3.1 - diff --git a/SOURCES/0085-Revert-appliance-init-run-ldconfig.patch b/SOURCES/0085-Revert-appliance-init-run-ldconfig.patch new file mode 100644 index 0000000..26801c3 --- /dev/null +++ b/SOURCES/0085-Revert-appliance-init-run-ldconfig.patch @@ -0,0 +1,36 @@ +From 16ac3aa74628ceb63b9cbc995300f9107cd48a0c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 12 May 2016 16:24:10 +0100 +Subject: [PATCH] Revert "appliance: init: run ldconfig" + +Running ldconfig adds about 100ms to the boot time. I would prefer +that we understood which libraries need ldconfig to be run, and fix +that. We could also consider running ldconfig in parallel, but since +it might be required by just about any binary that the init script +runs it's not clear what benefit that gives. + +This reverts commit 66aa98265dd215dcd4c717e7ef6845fbac859e54. + +(cherry picked from commit ba8e8d277daba14ea8e33faee7dfb6ddb613bb07) +--- + appliance/init | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/appliance/init b/appliance/init +index b05c0ed..d168b5e 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -17,10 +17,6 @@ if [ ! -d /tmp ] || [ ! -d /var/tmp ]; then + chmod 1777 /tmp /var/tmp + fi + +-# Make sure to find all the libraries, also those in non-standard place +-# but with a proper ld.so configuration pointing at them +-ldconfig +- + # Try to print a stack trace for segfaults inside the appliance. + for d in /lib64 /lib; do + f=$d/libSegFault.so +-- +1.8.3.1 + diff --git a/SOURCES/0085-v2v-Whitespace-change.patch b/SOURCES/0085-v2v-Whitespace-change.patch deleted file mode 100644 index a8c91d4..0000000 --- a/SOURCES/0085-v2v-Whitespace-change.patch +++ /dev/null @@ -1,27 +0,0 @@ -From b09d873ea2c26557490ccca0765fe2fc2aa2a415 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 15 Dec 2014 08:54:59 +0000 -Subject: [PATCH] v2v: Whitespace change. - -(cherry picked from commit 9c4af17add53b50ce0b6756c6216380862f10631) ---- - v2v/domainxml-c.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c -index 6fa8270..b57440c 100644 ---- a/v2v/domainxml-c.c -+++ b/v2v/domainxml-c.c -@@ -230,7 +230,8 @@ v2v_pool_dumpxml (value connv, value poolnamev) - * since it handles all the PolicyKit crap. However it also makes - * coding this simpler. - */ -- conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault, VIR_CONNECT_RO); -+ conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault, -+ VIR_CONNECT_RO); - if (conn == NULL) { - if (conn_uri) - snprintf (errmsg, sizeof errmsg, --- -1.8.3.1 - diff --git a/SOURCES/0086-appliance-Copy-etc-ld.so.cache-from-the-host-into-th.patch b/SOURCES/0086-appliance-Copy-etc-ld.so.cache-from-the-host-into-th.patch new file mode 100644 index 0000000..3fa0a3a --- /dev/null +++ b/SOURCES/0086-appliance-Copy-etc-ld.so.cache-from-the-host-into-th.patch @@ -0,0 +1,38 @@ +From 470d49add9f9b75f963b5cd523950541d9fa3bee Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 12 May 2016 16:51:53 +0100 +Subject: [PATCH] appliance: Copy /etc/ld.so.cache from the host into the + appliance. + +Previously we were running ldconfig to create /etc/ld.so.cache. + +This is required, at least on Fedora, if we need to run any binary +that uses a library with a weird path. libiscsi (a dependency of +qemu-img, used by virt-dib) is an example of such a weird library, +since it puts its single library into /usr/lib64/iscsi for no readily +understandable reason, and drops a configuration file into +/etc/ld.so.conf.d/ so that this new directory gets picked up. + +By copying the /etc/ld.so.cache from the host we get an already +configured cache which should contain every library on the host, so +there is no need to run ldconfig. + +(cherry picked from commit 634f47e6d4f1cf7ce343789d8b6257d89001f74f) +--- + appliance/hostfiles.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/appliance/hostfiles.in b/appliance/hostfiles.in +index 8ff53b5..268d712 100644 +--- a/appliance/hostfiles.in ++++ b/appliance/hostfiles.in +@@ -13,5 +13,6 @@ dnl SUSE=1 For OpenSUSE. + dnl FRUGALWARE=1 For Frugalware. + dnl MAGEIA=1 For Mageia. + ++/etc/ld.so.cache + /lib/lsb/* + /usr/share/augeas/lenses/*.aug +-- +1.8.3.1 + diff --git a/SOURCES/0086-v2v-Get-passwords-in-domain-XML-RHBZ-1174123.patch b/SOURCES/0086-v2v-Get-passwords-in-domain-XML-RHBZ-1174123.patch deleted file mode 100644 index 73d5d7e..0000000 --- a/SOURCES/0086-v2v-Get-passwords-in-domain-XML-RHBZ-1174123.patch +++ /dev/null @@ -1,40 +0,0 @@ -From a1d1b87d1d574f7bfbd95681cb8e456cec18b33b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 15 Dec 2014 08:55:12 +0000 -Subject: [PATCH] v2v: Get passwords in domain XML (RHBZ#1174123). - -Thanks: Tingting Zheng -(cherry picked from commit dfded7c94118e8888dec38f11c2af62d8156a59e) ---- - v2v/domainxml-c.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c -index b57440c..c9ed8c5 100644 ---- a/v2v/domainxml-c.c -+++ b/v2v/domainxml-c.c -@@ -138,7 +138,10 @@ v2v_dumpxml (value passwordv, value connv, value domnamev) - authdata.cb = libvirt_auth_default_wrapper; - authdata.cbdata = (void *) password; - -- conn = virConnectOpenAuth (conn_uri, &authdata, VIR_CONNECT_RO); -+ /* Note this cannot be a read-only connection since we need to use -+ * the VIR_DOMAIN_XML_SECURE flag below. -+ */ -+ conn = virConnectOpenAuth (conn_uri, &authdata, 0); - if (conn == NULL) { - if (conn_uri) - snprintf (errmsg, sizeof errmsg, -@@ -188,7 +191,8 @@ v2v_dumpxml (value passwordv, value connv, value domnamev) - } - } - -- xml = virDomainGetXMLDesc (dom, 0); -+ /* Use VIR_DOMAIN_XML_SECURE to get passwords (RHBZ#1174123). */ -+ xml = virDomainGetXMLDesc (dom, VIR_DOMAIN_XML_SECURE); - if (xml == NULL) { - err = virGetLastError (); - snprintf (errmsg, sizeof errmsg, --- -1.8.3.1 - diff --git a/SOURCES/0087-utils-boot-analysis-Make-handling-of-first-kernel-me.patch b/SOURCES/0087-utils-boot-analysis-Make-handling-of-first-kernel-me.patch new file mode 100644 index 0000000..aa78e1d --- /dev/null +++ b/SOURCES/0087-utils-boot-analysis-Make-handling-of-first-kernel-me.patch @@ -0,0 +1,108 @@ +From 88f2135d9b788cdeec7dff8ac9c2b882f314009d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 10 May 2016 21:53:59 +0100 +Subject: [PATCH] utils: boot-analysis: Make handling of first kernel message + more flexible. + +Allows us to disable EDD completely, and still have boot-analysis work. + +(cherry picked from commit b6f5a0cd90c356ab1d7e519c0e24e66bfe33cfcc) +--- + utils/boot-analysis/boot-analysis-timeline.c | 35 +++++++++++++++++++++------- + 1 file changed, 26 insertions(+), 9 deletions(-) + +diff --git a/utils/boot-analysis/boot-analysis-timeline.c b/utils/boot-analysis/boot-analysis-timeline.c +index 905d1e3..a4b71a1 100644 +--- a/utils/boot-analysis/boot-analysis-timeline.c ++++ b/utils/boot-analysis/boot-analysis-timeline.c +@@ -67,6 +67,7 @@ construct_timeline (void) + size_t i, j, k; + struct pass_data *data; + struct activity *activity; ++ const char *first_kernel_message; + + for (i = 0; i < NR_TEST_PASSES; ++i) { + data = &pass_data[i]; +@@ -217,14 +218,30 @@ construct_timeline (void) + strstr (data->events[k].message, "libvirt XML:")); + + #if defined(__aarch64__) +-#define FIRST_KERNEL_MESSAGE "Booting Linux on physical CPU" + #define FIRST_FIRMWARE_MESSAGE "UEFI firmware starting" + #else + #define SGABIOS_STRING "\033[1;256r\033[256;256H\033[6n" +-#define FIRST_KERNEL_MESSAGE "Probing EDD" + #define FIRST_FIRMWARE_MESSAGE SGABIOS_STRING + #endif + ++ /* Try to determine the first message that the kernel prints. */ ++#if defined(__aarch64__) ++ first_kernel_message = "Booting Linux on physical CPU"; ++#else ++ first_kernel_message = "Probing EDD"; ++ for (j = 0; j < data->nr_events; ++j) ++ if (data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, first_kernel_message)) ++ goto found_first_kernel_message; ++ first_kernel_message = "Linux version "; ++ for (j = 0; j < data->nr_events; ++j) ++ if (data->events[j].source == GUESTFS_EVENT_APPLIANCE && ++ strstr (data->events[j].message, first_kernel_message)) ++ goto found_first_kernel_message; ++ error (EXIT_FAILURE, 0, "could not determine first message printed by the kernel"); ++ found_first_kernel_message: ++#endif ++ + /* For the libvirt backend, find the overhead of libvirt. */ + FIND_OPTIONAL ("libvirt:overhead", 0, + data->events[j].source == GUESTFS_EVENT_LIBRARY && +@@ -244,7 +261,7 @@ construct_timeline (void) + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, FIRST_FIRMWARE_MESSAGE), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); ++ strstr (data->events[k].message, first_kernel_message)); + + #if defined(__i386__) || defined(__x86_64__) + /* SGABIOS (option ROM). */ +@@ -261,7 +278,7 @@ construct_timeline (void) + data->events[j].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[j].message, "SeaBIOS (version"), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, FIRST_KERNEL_MESSAGE)); ++ strstr (data->events[k].message, first_kernel_message)); + #endif + + #if defined(__i386__) || defined(__x86_64__) +@@ -276,23 +293,23 @@ construct_timeline (void) + /* Find where we run the guest kernel. */ + FIND ("kernel", LONG_ACTIVITY, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), ++ strstr (data->events[j].message, first_kernel_message), + data->events[k].source == GUESTFS_EVENT_CLOSE); + + /* Kernel startup to userspace. */ + FIND ("kernel:overhead", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), ++ strstr (data->events[j].message, first_kernel_message), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && + strstr (data->events[k].message, "supermin:") && + strstr (data->events[k].message, "starting up")); + + /* The time taken to get into start_kernel function. */ +- FIND ("kernel:entry", 0, ++ FIND_OPTIONAL ("kernel:entry", 0, + data->events[j].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[j].message, FIRST_KERNEL_MESSAGE), ++ strstr (data->events[j].message, first_kernel_message), + data->events[k].source == GUESTFS_EVENT_APPLIANCE && +- strstr (data->events[k].message, "Linux version")); ++ strstr (data->events[k].message, "Linux version ")); + + #if defined(__i386__) || defined(__x86_64__) + /* Alternatives patching instructions (XXX not very accurate we +-- +1.8.3.1 + diff --git a/SOURCES/0087-v2v-Password-attr-in-domain-XML-should-be-passwd-RHB.patch b/SOURCES/0087-v2v-Password-attr-in-domain-XML-should-be-passwd-RHB.patch deleted file mode 100644 index cf47079..0000000 --- a/SOURCES/0087-v2v-Password-attr-in-domain-XML-should-be-passwd-RHB.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ebddbb3a7283e013f551063dc8ac53b2d2ee9ead Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 15 Dec 2014 13:43:34 +0000 -Subject: [PATCH] v2v: Password attr in domain XML should be 'passwd=' - (RHBZ#1174123). - -(cherry picked from commit 7a218cbdf635af543479256593e448100406ea1e) ---- - v2v/output_libvirt.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index a27d3e5..dc9466c 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -229,7 +229,7 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - | Some { s_keymap = Some km } -> append_attr ("keymap", km) graphics - | _ -> ()); - (match source.s_display with -- | Some { s_password = Some pw } -> append_attr ("password", pw) graphics -+ | Some { s_password = Some pw } -> append_attr ("passwd", pw) graphics - | _ -> ()); - - video, graphics in --- -1.8.3.1 - diff --git a/SOURCES/0088-p2v-avoid-connecting-to-ourself-while-probing-qemu-n.patch b/SOURCES/0088-p2v-avoid-connecting-to-ourself-while-probing-qemu-n.patch deleted file mode 100644 index 611e98a..0000000 --- a/SOURCES/0088-p2v-avoid-connecting-to-ourself-while-probing-qemu-n.patch +++ /dev/null @@ -1,82 +0,0 @@ -From f0e55ad5672f8c8425cef1a355ef330e4e2bf8d0 Mon Sep 17 00:00:00 2001 -From: John Eckersberg -Date: Mon, 15 Dec 2014 13:19:06 -0500 -Subject: [PATCH] p2v: avoid connecting to ourself while probing qemu-nbd - (RHBZ#1167774) - -(cherry picked from commit 09080a28878a17b991c812e2b93a8d8394383d04) ---- - p2v/conversion.c | 43 +++++++++++++++++++++++++++++++++++++------ - 1 file changed, 37 insertions(+), 6 deletions(-) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index 4ff7ecc..14e7b3b 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -398,7 +398,8 @@ wait_qemu_nbd (int nbd_local_port, int timeout_seconds) - { - int sockfd; - int result = -1; -- struct sockaddr_in addr; -+ int reuseaddr = 1; -+ struct sockaddr_in src_addr, dst_addr; - time_t start_t, now_t; - struct timeval timeout = { .tv_usec = 0 }; - char magic[8]; /* NBDMAGIC */ -@@ -413,10 +414,40 @@ wait_qemu_nbd (int nbd_local_port, int timeout_seconds) - return -1; - } - -- memset (&addr, 0, sizeof addr); -- addr.sin_family = AF_INET; -- addr.sin_port = htons (nbd_local_port); -- inet_pton (AF_INET, "localhost", &addr.sin_addr); -+ memset (&src_addr, 0, sizeof src_addr); -+ src_addr.sin_family = AF_INET; -+ /* Source port for probing qemu-nbd should be one greater than -+ * nbd_local_port. It's not guaranteed to always bind to this port, -+ * but it will hint the kernel to start there and try incrementally -+ * higher ports if needed. This avoids the case where the kernel -+ * selects nbd_local_port as our source port, and we immediately -+ * connect to ourself. See: -+ * https://bugzilla.redhat.com/show_bug.cgi?id=1167774#c9 -+ */ -+ src_addr.sin_port = htons (nbd_local_port+1); -+ inet_pton (AF_INET, "localhost", &src_addr.sin_addr); -+ -+ memset (&dst_addr, 0, sizeof dst_addr); -+ dst_addr.sin_family = AF_INET; -+ dst_addr.sin_port = htons (nbd_local_port); -+ inet_pton (AF_INET, "localhost", &dst_addr.sin_addr); -+ -+ /* If we run p2v repeatedly (say, running the tests in a loop), -+ * there's a decent chance we'll end up trying to bind() to a port -+ * that is in TIME_WAIT from a prior run. Handle that gracefully -+ * with SO_REUSEADDR. -+ */ -+ if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, -+ &reuseaddr, sizeof reuseaddr) == -1) { -+ set_conversion_error ("waiting for qemu-nbd to start: setsockopt: %m"); -+ goto cleanup; -+ } -+ -+ if (bind (sockfd, (struct sockaddr *) &src_addr, sizeof src_addr) == -1) { -+ set_conversion_error ("waiting for qemu-nbd to start: bind(%d): %m", -+ ntohs (src_addr.sin_port)); -+ goto cleanup; -+ } - - for (;;) { - time (&now_t); -@@ -426,7 +457,7 @@ wait_qemu_nbd (int nbd_local_port, int timeout_seconds) - goto cleanup; - } - -- if (connect (sockfd, (struct sockaddr *) &addr, sizeof addr) == 0) -+ if (connect (sockfd, (struct sockaddr *) &dst_addr, sizeof dst_addr) == 0) - break; - } - --- -1.8.3.1 - diff --git a/SOURCES/0088-utils-boot-analysis-Add-magic-asserts-to-some-struct.patch b/SOURCES/0088-utils-boot-analysis-Add-magic-asserts-to-some-struct.patch new file mode 100644 index 0000000..d0afac3 --- /dev/null +++ b/SOURCES/0088-utils-boot-analysis-Add-magic-asserts-to-some-struct.patch @@ -0,0 +1,97 @@ +From 3b2ac7b9ac4d8a40c17ae28e255f50704180782b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 14 May 2016 18:45:25 +0100 +Subject: [PATCH] utils: boot-analysis: Add magic & asserts to some structs. + +I suspected data corruption (but didn't prove it). This commit just +adds some magic numbers to the structs so we will see data corruption +quickly if it happens again. + +(cherry picked from commit bf80587367d5f01e493426bbb2cda6099a15e7ab) +--- + utils/boot-analysis/boot-analysis.c | 9 +++++++++ + utils/boot-analysis/boot-analysis.h | 6 ++++++ + 2 files changed, 15 insertions(+) + +diff --git a/utils/boot-analysis/boot-analysis.c b/utils/boot-analysis/boot-analysis.c +index 3d38fe2..3690ed4 100644 +--- a/utils/boot-analysis/boot-analysis.c ++++ b/utils/boot-analysis/boot-analysis.c +@@ -571,6 +571,7 @@ set_up_event_handlers (guestfs_h *g, size_t pass) + assert (/* 0 <= pass && */ pass < NR_TEST_PASSES); + + data = &pass_data[pass]; ++ data->magic = PASS_MAGIC; + data->pass = pass; + data->nr_events = 0; + data->events = NULL; +@@ -779,6 +780,7 @@ check_pass_data (void) + const char *message; + + for (i = 0; i < NR_TEST_PASSES; ++i) { ++ assert (pass_data[i].magic == PASS_MAGIC); + assert (pass_data[i].pass == i); + assert (pass_data[i].elapsed_ns > 1000); + assert (pass_data[i].nr_events > 0); +@@ -890,6 +892,7 @@ add_activity (const char *name, int flags) + if (activities == NULL) + error (EXIT_FAILURE, errno, "realloc"); + ret = &activities[nr_activities-1]; ++ ret->magic = ACTIVITY_MAGIC; + ret->name = strdup (name); + if (ret->name == NULL) + error (EXIT_FAILURE, errno, "strdup"); +@@ -934,6 +937,9 @@ compare_activities_by_t (const void *av, const void *bv) + const struct activity *a = av; + const struct activity *b = bv; + ++ assert (a->magic == ACTIVITY_MAGIC); ++ assert (b->magic == ACTIVITY_MAGIC); ++ + return a->t - b->t; + } + +@@ -1028,6 +1034,7 @@ static void + print_activity (struct activity *activity) + { + if (activity->warning) ansi_red (); else ansi_green (); ++ assert (activity->magic == ACTIVITY_MAGIC); + print_escaped_string (activity->name); + ansi_restore (); + printf (" %.1fms ±%.1fms ", +@@ -1148,6 +1155,8 @@ compare_activities_pointers_by_mean (const void *av, const void *bv) + const struct activity * const *a = av; + const struct activity * const *b = bv; + ++ assert ((*a)->magic == ACTIVITY_MAGIC); ++ assert ((*b)->magic == ACTIVITY_MAGIC); + return (*b)->mean - (*a)->mean; + } + +diff --git a/utils/boot-analysis/boot-analysis.h b/utils/boot-analysis/boot-analysis.h +index a07f12e..38cd339 100644 +--- a/utils/boot-analysis/boot-analysis.h ++++ b/utils/boot-analysis/boot-analysis.h +@@ -24,6 +24,9 @@ + + /* Per-pass data collected. */ + struct pass_data { ++#define PASS_MAGIC 0x45545545 ++ uint32_t magic; /* Struct magic. */ ++ + size_t pass; + struct timespec start_t; + struct timespec end_t; +@@ -67,6 +70,9 @@ extern struct pass_data pass_data[NR_TEST_PASSES]; + * long they take (mean, variance, standard deviation of length). + */ + struct activity { ++#define ACTIVITY_MAGIC 0xAC1AC1AC ++ uint32_t magic; /* Struct magic. */ ++ + char *name; /* Name of this activity. */ + int flags; + #define LONG_ACTIVITY 1 /* Expected to take a long time. */ +-- +1.8.3.1 + diff --git a/SOURCES/0089-aarch64-appliance-Use-AAVMF-UEFI-if-available-for-ru.patch b/SOURCES/0089-aarch64-appliance-Use-AAVMF-UEFI-if-available-for-ru.patch deleted file mode 100644 index 3485d97..0000000 --- a/SOURCES/0089-aarch64-appliance-Use-AAVMF-UEFI-if-available-for-ru.patch +++ /dev/null @@ -1,208 +0,0 @@ -From eb3c98e28ad33606f70602834e455d7e0789153e Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 21 Jan 2015 05:10:37 -0500 -Subject: [PATCH] aarch64: appliance: Use AAVMF (UEFI) if available for running - the appliance. - -AAVMF is an open source UEFI implementation for aarch64 based on OVMF. -As aarch64 is heading for requiring UEFI even inside guests, if the -AAVMF firmware is installed on the host, use it as a hint that we -should boot the guest using AAVMF instead of the default "empty -machine". - -Note this requires very recent AAVMF, libvirt, qemu. However that's -OK since it's only applicable to aarch64. On non-aarch64, this patch -does nothing. - -Thanks: Laszlo Ersek for a lot of help getting this right. -(cherry picked from commit 7dc837c7be84936690f4f613fea82dba4787ceec) ---- - src/appliance.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++- - src/guestfs-internal.h | 1 + - src/launch-direct.c | 14 +++++++++++ - src/launch-libvirt.c | 25 +++++++++++++++++++ - 4 files changed, 105 insertions(+), 1 deletion(-) - -diff --git a/src/appliance.c b/src/appliance.c -index d7aa6b1..5fa47f2 100644 ---- a/src/appliance.c -+++ b/src/appliance.c -@@ -1,5 +1,5 @@ - /* libguestfs -- * Copyright (C) 2010-2012 Red Hat Inc. -+ * Copyright (C) 2010-2014 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 -@@ -459,3 +459,67 @@ dir_contains_files (const char *dir, ...) - va_end (args); - return 1; - } -+ -+#ifdef __aarch64__ -+ -+#define AAVMF_DIR "/usr/share/AAVMF" -+ -+/* Return the location of firmware needed to boot the appliance. This -+ * is aarch64 only currently, since that's the only architecture where -+ * UEFI is mandatory (and that only for RHEL). -+ * -+ * '*code' is initialized with the path to the read-only UEFI code -+ * file. '*vars' is initialized with the path to a copy of the UEFI -+ * vars file (which is cleaned up automatically on exit). -+ * -+ * If *code == *vars == NULL then no UEFI firmware is available. -+ * -+ * '*code' and '*vars' should be freed by the caller. -+ * -+ * If the function returns -1 then there was a real error which should -+ * cause appliance building to fail (no UEFI firmware is not an -+ * error). -+ */ -+int -+guestfs___get_uefi (guestfs_h *g, char **code, char **vars) -+{ -+ if (access (AAVMF_DIR "/AAVMF_CODE.fd", R_OK) == 0 && -+ access (AAVMF_DIR "/AAVMF_VARS.fd", R_OK) == 0) { -+ CLEANUP_CMD_CLOSE struct command *copycmd = guestfs___new_command (g); -+ char *varst; -+ int r; -+ -+ /* Make a copy of AAVMF_VARS.fd. You can't just map it into the -+ * address space read-only as that triggers a different path -+ * inside UEFI. -+ */ -+ varst = safe_asprintf (g, "%s/AAVMF_VARS.fd.%d", g->tmpdir, ++g->unique); -+ guestfs___cmd_add_arg (copycmd, "cp"); -+ guestfs___cmd_add_arg (copycmd, AAVMF_DIR "/AAVMF_VARS.fd"); -+ guestfs___cmd_add_arg (copycmd, varst); -+ r = guestfs___cmd_run (copycmd); -+ if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) { -+ free (varst); -+ return -1; -+ } -+ -+ /* Caller frees. */ -+ *code = safe_strdup (g, AAVMF_DIR "/AAVMF_CODE.fd"); -+ *vars = varst; -+ return 0; -+ } -+ -+ *code = *vars = NULL; -+ return 0; -+} -+ -+#else /* !__aarch64__ */ -+ -+int -+guestfs___get_uefi (guestfs_h *g, char **code, char **vars) -+{ -+ *code = *vars = NULL; -+ return 0; -+} -+ -+#endif /* !__aarch64__ */ -diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h -index fd0c4a1..d5de345 100644 ---- a/src/guestfs-internal.h -+++ b/src/guestfs-internal.h -@@ -725,6 +725,7 @@ extern const char *guestfs___drive_protocol_to_string (enum drive_protocol proto - - /* appliance.c */ - extern int guestfs___build_appliance (guestfs_h *g, char **kernel, char **dtb, char **initrd, char **appliance); -+extern int guestfs___get_uefi (guestfs_h *g, char **code, char **vars); - - /* launch.c */ - extern int64_t guestfs___timeval_diff (const struct timeval *x, const struct timeval *y); -diff --git a/src/launch-direct.c b/src/launch-direct.c -index 5301176..2834967 100644 ---- a/src/launch-direct.c -+++ b/src/launch-direct.c -@@ -267,6 +267,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) - int sv[2]; - char guestfsd_sock[256]; - struct sockaddr_un addr; -+ CLEANUP_FREE char *uefi_code = NULL, *uefi_vars = NULL; - CLEANUP_FREE char *kernel = NULL, *dtb = NULL, - *initrd = NULL, *appliance = NULL; - int has_appliance_drive; -@@ -474,6 +475,19 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) - ADD_CMDLINE ("kvm-pit.lost_tick_policy=discard"); - } - -+ /* UEFI (firmware) if required. */ -+ if (guestfs___get_uefi (g, &uefi_code, &uefi_vars) == -1) -+ goto cleanup0; -+ if (uefi_code) { -+ ADD_CMDLINE ("-drive"); -+ ADD_CMDLINE_PRINTF ("if=pflash,format=raw,file=%s,readonly", uefi_code); -+ if (uefi_vars) { -+ ADD_CMDLINE ("-drive"); -+ ADD_CMDLINE_PRINTF ("if=pflash,format=raw,file=%s", uefi_vars); -+ } -+ } -+ -+ /* Kernel, DTB and initrd. */ - ADD_CMDLINE ("-kernel"); - ADD_CMDLINE (kernel); - if (dtb) { -diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c -index f8f818a..e6899ac 100644 ---- a/src/launch-libvirt.c -+++ b/src/launch-libvirt.c -@@ -109,6 +109,8 @@ struct backend_libvirt_data { - char name[DOMAIN_NAME_LEN]; /* random name */ - bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/ - unsigned long qemu_version; /* qemu version (from libvirt) */ -+ char *uefi_code; /* UEFI (firmware) code and variables. */ -+ char *uefi_vars; - }; - - /* Parameters passed to construct_libvirt_xml and subfunctions. We -@@ -318,6 +320,10 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) - if (parse_capabilities (g, capabilities_xml, data) == -1) - goto cleanup; - -+ /* UEFI code and variables, on architectures where that is required. */ -+ if (guestfs___get_uefi (g, &data->uefi_code, &data->uefi_vars) == -1) -+ goto cleanup; -+ - /* Misc backend settings. */ - guestfs_push_error_handler (g, NULL, NULL); - data->selinux_label = -@@ -1095,6 +1101,20 @@ construct_libvirt_xml_boot (guestfs_h *g, - string ("hvm"); - } end_element (); - -+ if (params->data->uefi_code) { -+ start_element ("loader") { -+ attribute ("readonly", "yes"); -+ attribute ("type", "pflash"); -+ string (params->data->uefi_code); -+ } end_element (); -+ -+ if (params->data->uefi_vars) { -+ start_element ("nvram") { -+ string (params->data->uefi_vars); -+ } end_element (); -+ } -+ } -+ - start_element ("kernel") { - string (params->kernel); - } end_element (); -@@ -1709,6 +1729,11 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) - free (data->network_bridge); - data->network_bridge = NULL; - -+ free (data->uefi_code); -+ data->uefi_code = NULL; -+ free (data->uefi_vars); -+ data->uefi_vars = NULL; -+ - return ret; - } - --- -1.8.3.1 - diff --git a/SOURCES/0089-utils-boot-analysis-Avoid-overflow-when-comparing-la.patch b/SOURCES/0089-utils-boot-analysis-Avoid-overflow-when-comparing-la.patch new file mode 100644 index 0000000..33459f2 --- /dev/null +++ b/SOURCES/0089-utils-boot-analysis-Avoid-overflow-when-comparing-la.patch @@ -0,0 +1,36 @@ +From 832609cc5f16a955648880ebc69b8f226f8782bb Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 14 May 2016 19:22:49 +0100 +Subject: [PATCH] utils: boot-analysis: Avoid overflow when comparing large + doubles. + +(cherry picked from commit 1f4a0bd90df35df56eb86c2386d801b51828cb22) +--- + utils/boot-analysis/boot-analysis.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/utils/boot-analysis/boot-analysis.c b/utils/boot-analysis/boot-analysis.c +index 3690ed4..d06d9a1 100644 +--- a/utils/boot-analysis/boot-analysis.c ++++ b/utils/boot-analysis/boot-analysis.c +@@ -1157,7 +1157,16 @@ compare_activities_pointers_by_mean (const void *av, const void *bv) + + assert ((*a)->magic == ACTIVITY_MAGIC); + assert ((*b)->magic == ACTIVITY_MAGIC); +- return (*b)->mean - (*a)->mean; ++ ++ /* The mean field is a double in nanoseconds. For the result of the ++ * comparison we want an integer. If it is larger than around 2^32, ++ * the following will produce an incorrect result. Therefore we use ++ * this trick. Note we want to return largest first. ++ */ ++ double a_mean = (*a)->mean; ++ double b_mean = (*b)->mean; ++ ++ return (b_mean > a_mean) - (b_mean < a_mean); + } + + static void +-- +1.8.3.1 + diff --git a/SOURCES/0090-aarch64-launch-libvirt-As-a-workaround-pass-cpu-para.patch b/SOURCES/0090-aarch64-launch-libvirt-As-a-workaround-pass-cpu-para.patch deleted file mode 100644 index a98c75d..0000000 --- a/SOURCES/0090-aarch64-launch-libvirt-As-a-workaround-pass-cpu-para.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 240cd5f90c83bcd0441d8ea079c3e5f6508d1202 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 21 Jan 2015 05:37:56 -0500 -Subject: [PATCH] aarch64: launch: libvirt: As a workaround, pass -cpu - parameter to qemu. - -When libguestfs is running using TCG on aarch64, we need to pass the --cpu cortex-a57 parameter to qemu. Libvirt doesn't let us do this, -complaining "Unable to find CPU definition". - -As a temporary workaround only, use to pass this -argument directly to qemu. When libvirt is fixed we can remove this -hack. - -This is a workaround for libvirt bug RHBZ#1184411. - -See: -https://www.redhat.com/archives/libvirt-users/2014-August/msg00043.html -https://bugzilla.redhat.com/show_bug.cgi?id=1184411 -(cherry picked from commit 7e4b7a346a4558a02aeb58f82d518509ce6e5d03) ---- - src/launch-libvirt.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c -index e6899ac..79bc6fd 100644 ---- a/src/launch-libvirt.c -+++ b/src/launch-libvirt.c -@@ -1035,12 +1035,16 @@ construct_libvirt_xml_cpu (guestfs_h *g, - } end_element (); - } - else { -- /* XXX This does not work, see: -+ /* XXX This does not work on aarch64, see: - * https://www.redhat.com/archives/libvirt-users/2014-August/msg00043.html -+ * https://bugzilla.redhat.com/show_bug.cgi?id=1184411 -+ * Instead we hack around it using below. - */ -+#ifndef __aarch64__ - start_element ("model") { - string (cpu_model); - } end_element (); -+#endif - } - } end_element (); - } -@@ -1670,6 +1674,21 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, - } - } - -+#ifdef __aarch64__ -+ /* This is a temporary hack until RHBZ#1184411 is resolved. -+ * See comments above about cpu model and aarch64. -+ */ -+ const char *cpu_model = guestfs___get_cpu_model (params->data->is_kvm); -+ if (STRNEQ (cpu_model, "host")) { -+ start_element ("qemu:arg") { -+ attribute ("value", "-cpu"); -+ } end_element (); -+ start_element ("qemu:arg") { -+ attribute ("value", cpu_model); -+ } end_element (); -+ } -+#endif -+ - } end_element (); /* */ - - return 0; --- -1.8.3.1 - diff --git a/SOURCES/0090-appliance-Reenable-ACPI.patch b/SOURCES/0090-appliance-Reenable-ACPI.patch new file mode 100644 index 0000000..b460467 --- /dev/null +++ b/SOURCES/0090-appliance-Reenable-ACPI.patch @@ -0,0 +1,35 @@ +From 8ebb42e25a62bf587c84c109e5e4efe722b35881 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 16 May 2016 22:29:58 +0100 +Subject: [PATCH] appliance: Reenable ACPI. + +Previously I disabled ACPI because it was not necessary and was slow. +However measuring it again now, I can see no significant difference in +performance, and it is necessary if we are going to use DAX. + +It's also useful to keep the appliance kernel state as similar to the +ordinary state, and setting acpi=off is a massive change to the way +that the kernel boots. + +Therefore, reenable it. + +(cherry picked from commit db1f811b29b055625ae1b03cf0daa9fed0d443ac) +--- + src/launch.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/launch.c b/src/launch.c +index e7cb325..269eeca 100644 +--- a/src/launch.c ++++ b/src/launch.c +@@ -336,7 +336,6 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, + " udev.event-timeout=6000" /* for newer udevd */ + " no_timer_check" /* fix for RHBZ#502058 */ + "%s" /* lpj */ +- " acpi=off" /* ACPI is slow - 150-200ms extra on my laptop */ + " printk.time=1" /* display timestamp before kernel messages */ + " cgroup_disable=memory" /* saves us about 5 MB of RAM */ + " usbcore.nousb" /* disable USB, only saves about 1ms */ +-- +1.8.3.1 + diff --git a/SOURCES/0091-aarch64-Increase-default-appliance-memory-size-on-aa.patch b/SOURCES/0091-aarch64-Increase-default-appliance-memory-size-on-aa.patch deleted file mode 100644 index cfe6713..0000000 --- a/SOURCES/0091-aarch64-Increase-default-appliance-memory-size-on-aa.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 28ca86d12286aad430378cbf416c966cdfddfbdf Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 24 Jan 2015 15:40:05 +0000 -Subject: [PATCH] aarch64: Increase default appliance memory size on aarch64. - -Kernel 3.19 has problems uncompressing the RAM disk with <= 500 MB. -(This is likely to be a kernel bug) - -64 KB pages are common on aarch64, so treat this case the same as ppc, -and use a larger default appliance memory size. - -Thanks: Laszlo Ersek for help and reproducing the bug. -(cherry picked from commit c24f242521e882380c28d0952007d8462040d998) ---- - src/guestfs-internal.h | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h -index d5de345..d9ccf5f 100644 ---- a/src/guestfs-internal.h -+++ b/src/guestfs-internal.h -@@ -68,6 +68,16 @@ - # define MIN_MEMSIZE 256 - #endif - -+/* Kernel 3.19 is unable to uncompress the initramfs on aarch64 unless -+ * we have > 500 MB of space. This looks like a kernel bug (earlier -+ * kernels have no problems). However since 64 KB pages are also -+ * common on aarch64, treat this like the ppc case above. -+ */ -+#ifdef __aarch64__ -+# define DEFAULT_MEMSIZE 768 -+# define MIN_MEMSIZE 256 -+#endif -+ - /* Valgrind has a fairly hefty memory overhead. Using the defaults - * caused the C API tests to fail. - */ --- -1.8.3.1 - diff --git a/SOURCES/0091-appliance-Find-udevd-a-bit-faster.patch b/SOURCES/0091-appliance-Find-udevd-a-bit-faster.patch new file mode 100644 index 0000000..20b0925 --- /dev/null +++ b/SOURCES/0091-appliance-Find-udevd-a-bit-faster.patch @@ -0,0 +1,38 @@ +From aac825766ceab91e5d234fba83d03dc25b1de882 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 17 May 2016 13:20:14 +0100 +Subject: [PATCH] appliance: Find udevd a bit faster. + +Rearrange the paths that we check for udevd so that the systemd paths +are first. Break from the loop as soon as we find udevd. + +(cherry picked from commit 8a4dcde16accef1a2e1a1bc5a71146295ed6a214) +--- + appliance/init | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/appliance/init b/appliance/init +index d168b5e..1f38a0e 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -91,13 +91,13 @@ echo "${machine_id// /}" > /etc/machine-id + systemd-tmpfiles --prefix=/dev --create --boot + + # Find udevd and run it directly. +-for f in /sbin/udevd /lib/udev/udevd \ +- /lib/systemd/systemd-udevd /usr/lib/systemd/systemd-udevd \ ++for f in /lib/systemd/systemd-udevd /usr/lib/systemd/systemd-udevd \ ++ /sbin/udevd /lib/udev/udevd \ + /usr/lib/udev/udevd; do +- if [ -x "$f" ]; then UDEVD="$f"; fi ++ if [ -x "$f" ]; then UDEVD="$f"; break; fi + done + if [ -z "$UDEVD" ]; then +- echo "udev not found! Things will probably not work ..." ++ echo "error: udev not found! Things will probably not work ..." + fi + + $UDEVD --daemon #--debug +-- +1.8.3.1 + diff --git a/SOURCES/0092-inspection-Not-an-installer-if-there-are-multiple-pa.patch b/SOURCES/0092-inspection-Not-an-installer-if-there-are-multiple-pa.patch deleted file mode 100644 index e73fa0c..0000000 --- a/SOURCES/0092-inspection-Not-an-installer-if-there-are-multiple-pa.patch +++ /dev/null @@ -1,227 +0,0 @@ -From 83c910778cc461dd72421b52d4fae7df7426bff6 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 9 Dec 2014 14:06:18 +0000 -Subject: [PATCH] inspection: Not an installer if there are multiple partitions - (RHBZ#1171666). - -Regular EFI disks have /EFI on the first (VFAT) partition, but they -are not installers. - -Fix this by only considering something to be an installer if it has a -single partition (or whole disks like ISOs). - -Implementing this is quite complex since when checking a filesystem, -we don't have information about whether we are even looking at a -partition, nor about whether it's the first partition out of how many. -The majority of the commit is changing the code to collect that -information. - -(cherry picked from commit bdf772db3286487adefa56b966435f2dd638e0a8) ---- - src/guestfs-internal.h | 1 + - src/inspect-fs-unix.c | 31 ++++--------------------------- - src/inspect-fs.c | 44 ++++++++++++++++++++++++++++++++++++++------ - src/inspect.c | 22 ++++++++++++++++++++++ - 4 files changed, 65 insertions(+), 33 deletions(-) - -diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h -index d9ccf5f..65f3388 100644 ---- a/src/guestfs-internal.h -+++ b/src/guestfs-internal.h -@@ -751,6 +751,7 @@ extern int guestfs___set_backend (guestfs_h *g, const char *method); - extern void guestfs___free_inspect_info (guestfs_h *g); - extern char *guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs, const char *filename, const char *basename, uint64_t max_size); - extern struct inspect_fs *guestfs___search_for_root (guestfs_h *g, const char *root); -+extern int guestfs___is_partition (guestfs_h *g, const char *partition); - - /* inspect-fs.c */ - extern int guestfs___is_file_nocase (guestfs_h *g, const char *); -diff --git a/src/inspect-fs-unix.c b/src/inspect-fs-unix.c -index fb5cc1a..8778e92 100644 ---- a/src/inspect-fs-unix.c -+++ b/src/inspect-fs-unix.c -@@ -185,7 +185,6 @@ static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs, - static char *resolve_fstab_device (guestfs_h *g, const char *spec, - Hash_table *md_map); - static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char **configfiles, int (*f) (guestfs_h *, struct inspect_fs *)); --static int is_partition (guestfs_h *g, const char *partition); - - /* Hash structure for uuid->path lookups */ - typedef struct md_uuid { -@@ -1436,7 +1435,7 @@ resolve_fstab_device_xdev (guestfs_h *g, const char *type, const char *disk, - ITER_DRIVES (g, i, drv) { - if (drv->name && STREQ (drv->name, name)) { - device = safe_asprintf (g, "%s%s", devices[i], part); -- if (!is_partition (g, device)) { -+ if (!guestfs___is_partition (g, device)) { - free (device); - return 0; - } -@@ -1463,7 +1462,7 @@ resolve_fstab_device_xdev (guestfs_h *g, const char *type, const char *disk, - */ - if (i < count) { - device = safe_asprintf (g, "%s%s", devices[i], part); -- if (!is_partition (g, device)) { -+ if (!guestfs___is_partition (g, device)) { - free (device); - return 0; - } -@@ -1496,7 +1495,7 @@ resolve_fstab_device_cciss (guestfs_h *g, const char *disk, const char *part, - if (drv->name && STREQ (drv->name, disk)) { - if (part) { - device = safe_asprintf (g, "%s%s", devices[i], part); -- if (!is_partition (g, device)) { -+ if (!guestfs___is_partition (g, device)) { - free (device); - return 0; - } -@@ -1541,7 +1540,7 @@ resolve_fstab_device_diskbyid (guestfs_h *g, const char *part, - - /* Make the partition name and check it exists. */ - device = safe_asprintf (g, "/dev/sda%s", part); -- if (!is_partition (g, device)) { -+ if (!guestfs___is_partition (g, device)) { - free (device); - return 0; - } -@@ -1753,25 +1752,3 @@ make_augeas_path_expression (guestfs_h *g, const char **configfiles) - debug (g, "augeas pathexpr = %s", ret); - return ret; - } -- --static int --is_partition (guestfs_h *g, const char *partition) --{ -- CLEANUP_FREE char *device = NULL; -- -- guestfs_push_error_handler (g, NULL, NULL); -- -- if ((device = guestfs_part_to_dev (g, partition)) == NULL) { -- guestfs_pop_error_handler (g); -- return 0; -- } -- -- if (guestfs_device_index (g, device) == -1) { -- guestfs_pop_error_handler (g); -- return 0; -- } -- -- guestfs_pop_error_handler (g); -- -- return 1; --} -diff --git a/src/inspect-fs.c b/src/inspect-fs.c -index 539d814..686d1ae 100644 ---- a/src/inspect-fs.c -+++ b/src/inspect-fs.c -@@ -83,6 +83,7 @@ static int check_filesystem (guestfs_h *g, const char *mountable, - const struct guestfs_internal_mountable *m, - int whole_device); - static int extend_fses (guestfs_h *g); -+static int get_partition_context (guestfs_h *g, const char *partition, int *partnum_ret, int *nr_partitions_ret); - - /* Find out if 'device' contains a filesystem. If it does, add - * another entry in g->fses. -@@ -175,17 +176,18 @@ check_filesystem (guestfs_h *g, const char *mountable, - const struct guestfs_internal_mountable *m, - int whole_device) - { -+ int partnum = -1, nr_partitions = -1; - /* Not CLEANUP_FREE, as it will be cleaned up with inspection info */ - char *windows_systemroot = NULL; - - if (extend_fses (g) == -1) - return -1; - -- int partnum = -1; -- if (!whole_device && m->im_type == MOUNTABLE_DEVICE) { -- guestfs_push_error_handler (g, NULL, NULL); -- partnum = guestfs_part_to_partnum (g, m->im_device); -- guestfs_pop_error_handler (g); -+ if (!whole_device && m->im_type == MOUNTABLE_DEVICE && -+ guestfs___is_partition (g, m->im_device)) { -+ if (get_partition_context (g, m->im_device, -+ &partnum, &nr_partitions) == -1) -+ return -1; - } - - struct inspect_fs *fs = &g->fses[g->nr_fses-1]; -@@ -324,7 +326,7 @@ check_filesystem (guestfs_h *g, const char *mountable, - * Skip these checks if it's not a whole device (eg. CD) or the - * first partition (eg. bootable USB key). - */ -- else if ((whole_device || partnum == 1) && -+ else if ((whole_device || (partnum == 1 && nr_partitions == 1)) && - (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 || - guestfs_is_dir (g, "/EFI/BOOT") > 0 || - guestfs_is_file (g, "/images/install.img") > 0 || -@@ -369,6 +371,36 @@ extend_fses (guestfs_h *g) - return 0; - } - -+/* Given a partition (eg. /dev/sda2) then return the partition number -+ * (eg. 2) and the total number of other partitions. -+ */ -+static int -+get_partition_context (guestfs_h *g, const char *partition, -+ int *partnum_ret, int *nr_partitions_ret) -+{ -+ int partnum, nr_partitions; -+ CLEANUP_FREE char *device = NULL; -+ CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *partitions = NULL; -+ -+ partnum = guestfs_part_to_partnum (g, partition); -+ if (partnum == -1) -+ return -1; -+ -+ device = guestfs_part_to_dev (g, partition); -+ if (device == NULL) -+ return -1; -+ -+ partitions = guestfs_part_list (g, device); -+ if (partitions == NULL) -+ return -1; -+ -+ nr_partitions = partitions->len; -+ -+ *partnum_ret = partnum; -+ *nr_partitions_ret = nr_partitions; -+ return 0; -+} -+ - int - guestfs___is_file_nocase (guestfs_h *g, const char *path) - { -diff --git a/src/inspect.c b/src/inspect.c -index 9248b06..03d870f 100644 ---- a/src/inspect.c -+++ b/src/inspect.c -@@ -590,3 +590,25 @@ guestfs___search_for_root (guestfs_h *g, const char *root) - root); - return NULL; - } -+ -+int -+guestfs___is_partition (guestfs_h *g, const char *partition) -+{ -+ CLEANUP_FREE char *device = NULL; -+ -+ guestfs_push_error_handler (g, NULL, NULL); -+ -+ if ((device = guestfs_part_to_dev (g, partition)) == NULL) { -+ guestfs_pop_error_handler (g); -+ return 0; -+ } -+ -+ if (guestfs_device_index (g, device) == -1) { -+ guestfs_pop_error_handler (g); -+ return 0; -+ } -+ -+ guestfs_pop_error_handler (g); -+ -+ return 1; -+} --- -1.8.3.1 - diff --git a/SOURCES/0092-utils-boot-analysis-Make-insmod-message-handling-a-b.patch b/SOURCES/0092-utils-boot-analysis-Make-insmod-message-handling-a-b.patch new file mode 100644 index 0000000..1952b77 --- /dev/null +++ b/SOURCES/0092-utils-boot-analysis-Make-insmod-message-handling-a-b.patch @@ -0,0 +1,41 @@ +From 50bcb7aa73d899dda1a994d3ed8e4cab83c6678a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 17 May 2016 15:34:42 +0100 +Subject: [PATCH] utils: boot-analysis: Make insmod message handling a bit more + robust. + +(cherry picked from commit 613fe4c089d132d63edddf1ccb53c082c20aded3) +--- + utils/boot-analysis/boot-analysis-timeline.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/utils/boot-analysis/boot-analysis-timeline.c b/utils/boot-analysis/boot-analysis-timeline.c +index a4b71a1..8198c56 100644 +--- a/utils/boot-analysis/boot-analysis-timeline.c ++++ b/utils/boot-analysis/boot-analysis-timeline.c +@@ -48,13 +48,20 @@ static void construct_initcall_timeline (void); + static char * + translate_supermin_insmod_message (const char *message) + { ++ const char *p, *q; + char *ret; + + assert (STRPREFIX (message, "supermin: internal ")); ++ p = message + strlen ("supermin: internal "); + +- ret = strdup (message + strlen ("supermin: internal ")); ++ /* Strip off the .ko and anything that follows. */ ++ q = strstr (p, ".ko"); ++ if (q == NULL) ++ error (EXIT_FAILURE, 0, "cannot find '.ko' suffix in '%s'", message); ++ ++ ret = strndup (p, q-p); + if (ret == NULL) +- error (EXIT_FAILURE, errno, "strdup"); ++ error (EXIT_FAILURE, errno, "strndup"); + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0093-daemon-Fix-whitespace.patch b/SOURCES/0093-daemon-Fix-whitespace.patch deleted file mode 100644 index 1f20159..0000000 --- a/SOURCES/0093-daemon-Fix-whitespace.patch +++ /dev/null @@ -1,26 +0,0 @@ -From db9bfb914f0510baadea3752b3b0faee6d1ce46a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 5 Feb 2015 08:01:48 +0000 -Subject: [PATCH] daemon: Fix whitespace. - -(cherry picked from commit b3e3750b13a96fb6d1b79f7c0dabb4eeb37de5ef) ---- - daemon/parted.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemon/parted.c b/daemon/parted.c -index a730477..76c0ce9 100644 ---- a/daemon/parted.c -+++ b/daemon/parted.c -@@ -759,7 +759,7 @@ optgroup_gdisk_available (void) - } - - int --do_part_set_gpt_type(const char *device, int partnum, const char *guid) -+do_part_set_gpt_type (const char *device, int partnum, const char *guid) - { - if (partnum <= 0) { - reply_with_error ("partition number must be >= 1"); --- -1.8.3.1 - diff --git a/SOURCES/0093-v2v-handle-subfolders-in-ova-files.patch b/SOURCES/0093-v2v-handle-subfolders-in-ova-files.patch new file mode 100644 index 0000000..a4bb5a0 --- /dev/null +++ b/SOURCES/0093-v2v-handle-subfolders-in-ova-files.patch @@ -0,0 +1,312 @@ +From a9c07400e8ac1bca21f6d55c311b2e64f12c27eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Mon, 23 May 2016 15:31:46 +0200 +Subject: [PATCH] v2v: handle subfolders in ova files + +Some ova files like those produced by SUSE Studio have their ovf, mf +and other files inside a folder rather than at the root of the +tarball. Consider the paths relative to the ovf and mf files to cover +this case too. + +(cherry picked from commit 9de9300e8b7a99fa06e290f20ef1aaa1eb6f7431) +--- + v2v/Makefile.am | 1 + + v2v/input_ova.ml | 6 +- + v2v/test-v2v-i-ova-subfolders.expected | 17 ++++ + v2v/test-v2v-i-ova-subfolders.ovf | 138 +++++++++++++++++++++++++++++++++ + v2v/test-v2v-i-ova-subfolders.sh | 65 ++++++++++++++++ + 5 files changed, 225 insertions(+), 2 deletions(-) + create mode 100644 v2v/test-v2v-i-ova-subfolders.expected + create mode 100644 v2v/test-v2v-i-ova-subfolders.ovf + create mode 100755 v2v/test-v2v-i-ova-subfolders.sh + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 2d52ab8..8354560 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -285,6 +285,7 @@ TESTS_ENVIRONMENT = $(top_builddir)/run --test + TESTS = \ + test-v2v-i-ova-formats.sh \ + test-v2v-i-ova-gz.sh \ ++ test-v2v-i-ova-subfolders.sh \ + test-v2v-i-ova-two-disks.sh \ + test-v2v-copy-to-local.sh \ + test-v2v-bad-networks-and-bridges.sh +diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml +index 28dafe6..0a4dfd5 100644 +--- a/v2v/input_ova.ml ++++ b/v2v/input_ova.ml +@@ -134,13 +134,14 @@ object + let rex = Str.regexp "SHA1(\\(.*\\))=\\([0-9a-fA-F]+\\)\r?" in + List.iter ( + fun mf -> ++ let mf_folder = Filename.dirname mf in + let chan = open_in mf in + let rec loop () = + let line = input_line chan in + if Str.string_match rex line 0 then ( + let disk = Str.matched_group 1 line in + let expected = Str.matched_group 2 line in +- let cmd = sprintf "sha1sum %s" (quote (exploded // disk)) in ++ let cmd = sprintf "sha1sum %s" (quote (mf_folder // disk)) in + let out = external_command cmd in + match out with + | [] -> +@@ -159,6 +160,7 @@ object + ) mf; + + (* Parse the ovf file. *) ++ let ovf_folder = Filename.dirname ovf in + let xml = read_whole_file ovf in + let doc = Xml.parse_memory xml in + +@@ -259,7 +261,7 @@ object + | Some s -> s in + + (* Does the file exist and is it readable? *) +- let filename = exploded // filename in ++ let filename = ovf_folder // filename in + Unix.access filename [Unix.R_OK]; + + (* The spec allows the file to be gzip-compressed, in which case +diff --git a/v2v/test-v2v-i-ova-subfolders.expected b/v2v/test-v2v-i-ova-subfolders.expected +new file mode 100644 +index 0000000..7037b9e +--- /dev/null ++++ b/v2v/test-v2v-i-ova-subfolders.expected +@@ -0,0 +1,17 @@ ++Source guest information (--print-source option): ++ ++ source name: 2K8R2EESP1_2_Medium ++hypervisor type: vmware ++ memory: 1073741824 (bytes) ++ nr vCPUs: 1 ++ CPU features: ++ firmware: uefi ++ display: ++ sound: ++disks: ++ subfolder/disk1.vmdk (vmdk) [scsi] ++removable media: ++ CD-ROM [ide] in slot 0 ++NICs: ++ Network "Network adapter 1" ++ +diff --git a/v2v/test-v2v-i-ova-subfolders.ovf b/v2v/test-v2v-i-ova-subfolders.ovf +new file mode 100644 +index 0000000..4827c7e +--- /dev/null ++++ b/v2v/test-v2v-i-ova-subfolders.ovf +@@ -0,0 +1,138 @@ ++ ++ ++ ++ ++ ++ ++ Virtual disk information ++ ++ ++ ++ The list of logical networks ++ ++ The PG-VLAN60 network ++ ++ ++ ++ A virtual machine ++ 2K8R2EESP1_2_Medium ++ ++ The kind of installed guest operating system ++ Microsoft Windows Server 2008 R2 (64-bit) ++ ++ ++ Virtual hardware requirements ++ ++ Virtual Hardware Family ++ 0 ++ 2K8R2EESP1_2_Medium ++ vmx-10 ++ ++ ++ hertz * 10^6 ++ Number of Virtual CPUs ++ 1 virtual CPU(s) ++ 1 ++ 3 ++ 1 ++ ++ ++ byte * 2^20 ++ Memory Size ++ 1024MB of memory ++ 2 ++ 4 ++ 1024 ++ ++ ++ 0 ++ SCSI Controller ++ SCSI controller 0 ++ 3 ++ lsilogicsas ++ 6 ++ ++ ++ ++ 1 ++ IDE Controller ++ IDE 1 ++ 4 ++ 5 ++ ++ ++ 0 ++ IDE Controller ++ IDE 0 ++ 5 ++ 5 ++ ++ ++ false ++ Video card ++ 6 ++ 24 ++ ++ ++ ++ ++ ++ ++ false ++ VMCI device ++ 7 ++ vmware.vmci ++ 1 ++ ++ ++ ++ ++ 0 ++ false ++ CD/DVD drive 1 ++ 8 ++ 4 ++ vmware.cdrom.atapi ++ 15 ++ ++ ++ 0 ++ Hard disk 1 ++ ovf:/disk/vmdisk1 ++ 9 ++ 3 ++ 17 ++ ++ ++ ++ 7 ++ true ++ PG-VLAN60 ++ E1000 ethernet adapter on "PG-VLAN60" ++ Network adapter 1 ++ 11 ++ E1000 ++ 10 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/v2v/test-v2v-i-ova-subfolders.sh b/v2v/test-v2v-i-ova-subfolders.sh +new file mode 100755 +index 0000000..a590fcc +--- /dev/null ++++ b/v2v/test-v2v-i-ova-subfolders.sh +@@ -0,0 +1,65 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2014 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 with files located in a subfolder. ++ ++unset CDPATH ++export LANG=C ++set -e ++ ++if [ -n "$SKIP_TEST_V2V_I_OVA_SUBFOLDERS_SH" ]; then ++ echo "$0: test skipped because environment variable is set" ++ exit 77 ++fi ++ ++if [ "$(guestfish get-backend)" = "uml" ]; then ++ echo "$0: test skipped because UML backend does not support network" ++ exit 77 ++fi ++ ++export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" ++ ++. $srcdir/../test-data/guestfs-hashsums.sh ++ ++d=test-v2v-i-ova-subfolders.d ++rm -rf $d ++mkdir -p $d/subfolder ++ ++cp test-v2v-i-ova-subfolders.ovf $d/subfolder/ ++ ++pushd $d/subfolder ++ ++truncate -s 10k disk1.vmdk ++sha=`do_sha1 disk1.vmdk` ++echo -e "SHA1(disk1.vmdk)=$sha\r" > disk1.mf ++ ++cd .. ++tar -cf test.ova subfolder ++popd ++ ++# Run virt-v2v but only as far as the --print-source stage, and ++# normalize the output. ++$VG virt-v2v --debug-gc --quiet \ ++ -i ova $d/test.ova \ ++ --print-source | ++sed 's,[^ \t]*\(subfolder/disk.*\.vmdk\),\1,' > $d/source ++ ++# Check the parsed source is what we expect. ++diff -u test-v2v-i-ova-subfolders.expected $d/source ++ ++rm -rf $d +-- +1.8.3.1 + diff --git a/SOURCES/0094-New-APIs-part-set-gpt-guid-and-part-get-gpt-guid.patch b/SOURCES/0094-New-APIs-part-set-gpt-guid-and-part-get-gpt-guid.patch deleted file mode 100644 index 37bba84..0000000 --- a/SOURCES/0094-New-APIs-part-set-gpt-guid-and-part-get-gpt-guid.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 3aab860529f7d13b00b3689fa79c72b12d2f9770 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 5 Feb 2015 08:08:06 +0000 -Subject: [PATCH] New APIs: part-set-gpt-guid and part-get-gpt-guid - -In GPT, each partition has a GUID assigned randomly. Allow this GUID -to be written and read. - -Note this is different from the GUID type code which is used to -identify the type of the partition. - -(cherry picked from commit 40c133b2c81666f6dde43704e66bf59206d5c111) ---- - daemon/parted.c | 33 +++++++++++++++++++++++++++++++++ - generator/actions.ml | 36 ++++++++++++++++++++++++++++++++++++ - src/MAX_PROC_NR | 2 +- - 3 files changed, 70 insertions(+), 1 deletion(-) - -diff --git a/daemon/parted.c b/daemon/parted.c -index 76c0ce9..36844b8 100644 ---- a/daemon/parted.c -+++ b/daemon/parted.c -@@ -784,6 +784,32 @@ do_part_set_gpt_type (const char *device, int partnum, const char *guid) - return 0; - } - -+int -+do_part_set_gpt_guid (const char *device, int partnum, const char *guid) -+{ -+ if (partnum <= 0) { -+ reply_with_error ("partition number must be >= 1"); -+ return -1; -+ } -+ -+ CLEANUP_FREE char *typecode = NULL; -+ if (asprintf (&typecode, "%i:%s", partnum, guid) == -1) { -+ reply_with_perror ("asprintf"); -+ return -1; -+ } -+ -+ CLEANUP_FREE char *err = NULL; -+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, -+ str_sgdisk, device, "-u", typecode, NULL); -+ -+ if (r == -1) { -+ reply_with_error ("%s %s -u %s: %s", str_sgdisk, device, typecode, err); -+ return -1; -+ } -+ -+ return 0; -+} -+ - static char * - sgdisk_info_extract_field (const char *device, int partnum, const char *field, - char *(*extract) (const char *path)) -@@ -894,6 +920,13 @@ do_part_get_gpt_type (const char *device, int partnum) - } - - char * -+do_part_get_gpt_guid (const char *device, int partnum) -+{ -+ return sgdisk_info_extract_field (device, partnum, -+ "Partition unique GUID", extract_uuid); -+} -+ -+char * - do_part_get_name (const char *device, int partnum) - { - CLEANUP_FREE char *parttype; -diff --git a/generator/actions.ml b/generator/actions.ml -index 593e51b..825acf9 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -11995,6 +11995,42 @@ This is the same as the C system call." }; - longdesc = "\ - This is the internal call which implements C." }; - -+ { defaults with -+ name = "part_set_gpt_guid"; -+ style = RErr, [Device "device"; Int "partnum"; GUID "guid"], []; -+ proc_nr = Some 446; -+ optional = Some "gdisk"; -+ tests = [ -+ InitGPT, Always, TestLastFail ( -+ [["part_set_gpt_guid"; "/dev/sda"; "1"; "f"]]), []; -+ InitGPT, Always, TestResultString ( -+ [["part_set_gpt_guid"; "/dev/sda"; "1"; -+ "01234567-89AB-CDEF-0123-456789ABCDEF"]; -+ ["part_get_gpt_guid"; "/dev/sda"; "1"]], -+ "01234567-89AB-CDEF-0123-456789ABCDEF"), []; -+ ]; -+ shortdesc = "set the GUID of a GPT partition"; -+ longdesc = "\ -+Set the GUID of numbered GPT partition C to C. Return an -+error if the partition table of C isn't GPT, or if C is not a -+valid GUID." }; -+ -+ { defaults with -+ name = "part_get_gpt_guid"; -+ style = RString "guid", [Device "device"; Int "partnum"], []; -+ proc_nr = Some 447; -+ optional = Some "gdisk"; -+ tests = [ -+ InitGPT, Always, TestResultString ( -+ [["part_set_gpt_guid"; "/dev/sda"; "1"; -+ "01234567-89AB-CDEF-0123-456789ABCDEF"]; -+ ["part_get_gpt_guid"; "/dev/sda"; "1"]], -+ "01234567-89AB-CDEF-0123-456789ABCDEF"), []; -+ ]; -+ shortdesc = "get the GUID of a GPT partition"; -+ longdesc = "\ -+Return the GUID of numbered GPT partition C." }; -+ - ] - - (* Non-API meta-commands available only in guestfish. -diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR -index 5721413..e9b7520 100644 ---- a/src/MAX_PROC_NR -+++ b/src/MAX_PROC_NR -@@ -1 +1 @@ --423 -+447 --- -1.8.3.1 - diff --git a/SOURCES/0094-v2v-Add-test-v2v-i-ova-subfolders-test-files-to-EXTR.patch b/SOURCES/0094-v2v-Add-test-v2v-i-ova-subfolders-test-files-to-EXTR.patch new file mode 100644 index 0000000..6436599 --- /dev/null +++ b/SOURCES/0094-v2v-Add-test-v2v-i-ova-subfolders-test-files-to-EXTR.patch @@ -0,0 +1,28 @@ +From 78e75d5bbbd2230d1052356fee097bacceba875b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 26 May 2016 12:54:08 +0100 +Subject: [PATCH] v2v: Add test-v2v-i-ova-subfolders test files to EXTRA_DIST. + +Fixes commit 9de9300e8b7a99fa06e290f20ef1aaa1eb6f7431. + +(cherry picked from commit e516b85bd72986568690db0169516923297c6918) +--- + v2v/Makefile.am | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 8354560..5d0ce95 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -31,6 +31,8 @@ EXTRA_DIST = \ + test-v2v-i-ova-formats.ovf \ + test-v2v-i-ova-gz.expected \ + test-v2v-i-ova-gz.ovf \ ++ test-v2v-i-ova-subfolders.expected \ ++ test-v2v-i-ova-subfolders.ovf \ + test-v2v-i-ova-two-disks.expected \ + test-v2v-i-ova-two-disks.ovf \ + test-v2v-networks-and-bridges-expected.xml \ +-- +1.8.3.1 + diff --git a/SOURCES/0095-p2v-Add-xterm-to-the-virt-p2v-ISO.patch b/SOURCES/0095-p2v-Add-xterm-to-the-virt-p2v-ISO.patch new file mode 100644 index 0000000..01f339f --- /dev/null +++ b/SOURCES/0095-p2v-Add-xterm-to-the-virt-p2v-ISO.patch @@ -0,0 +1,55 @@ +From 2212f2464c070f8117d4723cc668c081d5330a90 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 28 May 2016 22:45:41 +0100 +Subject: [PATCH] p2v: Add xterm to the virt-p2v ISO. + +You can run `xterm -display :0' at the virtual console in order to get +a shell in the graphical environment. + +This is useful for debugging and doesn't have much overhead unlike +other terminals. + +(cherry picked from commit d3b2a5bbd2491808148b10dba966d1e898078bf8) +--- + p2v/dependencies.m4 | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/p2v/dependencies.m4 b/p2v/dependencies.m4 +index 7acccaa..6cf2961 100644 +--- a/p2v/dependencies.m4 ++++ b/p2v/dependencies.m4 +@@ -42,6 +42,7 @@ ifelse(REDHAT,1, + util-linux + + dnl X11 environment ++ xterm + /usr/bin/xinit + /usr/bin/Xorg + xorg-x11-drivers +@@ -77,6 +78,7 @@ ifelse(DEBIAN,1, + smartmontools + util-linux + xorg ++ xterm + xserver-xorg-video-all + fonts-dejavu + metacity +@@ -100,6 +102,7 @@ ifelse(ARCHLINUX,1, + hdparm + smartmontools + util-linux ++ xterm + xorg-xinit + xorg-server + xf86-video-* +@@ -127,6 +130,7 @@ ifelse(SUSE,1, + util-linux + xinit + xorg-x11-server ++ xterm + xf86-video-* + dejavu-fonts + NetworkManager +-- +1.8.3.1 + diff --git a/SOURCES/0095-resize-Preserve-GPT-GUID-so-we-don-t-break-EFI-bootl.patch b/SOURCES/0095-resize-Preserve-GPT-GUID-so-we-don-t-break-EFI-bootl.patch deleted file mode 100644 index 66e31ff..0000000 --- a/SOURCES/0095-resize-Preserve-GPT-GUID-so-we-don-t-break-EFI-bootl.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 2149aa86bc0b0484e2144c9c441926eab52bd102 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 5 Feb 2015 08:13:05 +0000 -Subject: [PATCH] resize: Preserve GPT GUID so we don't break EFI bootloaders - (RHBZ#1189284). - -When copying disks that use EFI, we created a new partition table, -randomizing the GPT GUID of the first partition. Since EFI may store -the GUID in its NVRAM variables, this could make the guest unbootable. - -(cherry picked from commit f630677c14c7d5528e1ab39e4f805e0957b2ee3e) ---- - resize/resize.ml | 22 ++++++++++++++++++++-- - 1 file changed, 20 insertions(+), 2 deletions(-) - -diff --git a/resize/resize.ml b/resize/resize.ml -index 2090675..b581b39 100644 ---- a/resize/resize.ml -+++ b/resize/resize.ml -@@ -50,6 +50,7 @@ type partition = { - p_id : partition_id; (* Partition (MBR/GPT) ID. *) - p_type : partition_content; (* Content type and content size. *) - p_label : string option; (* Label/name. *) -+ p_guid : string option; (* Partition GUID (GPT only). *) - - (* What we're going to do: *) - mutable p_operation : partition_operation; -@@ -93,6 +94,11 @@ let rec debug_partition p = - (match p.p_label with - | Some label -> label - | None -> "(none)" -+ ); -+ printf "\tGUID: %s\n" -+ (match p.p_guid with -+ | Some guid -> guid -+ | None -> "(none)" - ) - and string_of_partition_content = function - | ContentUnknown -> "unknown data" -@@ -478,10 +484,16 @@ read the man page virt-resize(1). - let label = - try Some (g#part_get_name "/dev/sda" part_num) - with G.Error _ -> None in -+ let guid = -+ match parttype with -+ | MBR -> None -+ | GPT -> -+ try Some (g#part_get_gpt_guid "/dev/sda" part_num) -+ with G.Error _ -> None in - - { p_name = name; p_part = part; - p_bootable = bootable; p_id = id; p_type = typ; -- p_label = label; -+ p_label = label; p_guid = guid; - p_operation = OpCopy; p_target_partnum = 0; - p_target_start = 0L; p_target_end = 0L } - ) parts in -@@ -1068,7 +1080,7 @@ read the man page virt-resize(1). - p_part = { G.part_num = 0l; part_start = 0L; part_end = 0L; - part_size = 0L }; - p_bootable = false; p_id = No_ID; p_type = ContentUnknown; -- p_label = None; -+ p_label = None; p_guid = None; - - (* Target information is meaningful. *) - p_operation = OpIgnore; -@@ -1162,6 +1174,12 @@ read the man page virt-resize(1). - | None -> () - ); - -+ (match p.p_guid with -+ | Some guid -> -+ g#part_set_gpt_guid "/dev/sdb" p.p_target_partnum guid; -+ | None -> () -+ ); -+ - match parttype, p.p_id with - | GPT, GPT_Type gpt_type -> - g#part_set_gpt_type "/dev/sdb" p.p_target_partnum gpt_type --- -1.8.3.1 - diff --git a/SOURCES/0096-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch b/SOURCES/0096-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch deleted file mode 100644 index d434ece..0000000 --- a/SOURCES/0096-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch +++ /dev/null @@ -1,38 +0,0 @@ -From db9af482e1afb7b776de08084c3e6c491ca6937f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 21 Dec 2012 15:50:11 +0000 -Subject: [PATCH] RHEL 7: Remove libguestfs live (RHBZ#798980). - -This isn't supported in RHEL 7. ---- - src/launch-unix.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/launch-unix.c b/src/launch-unix.c -index 489a046..7956bed 100644 ---- a/src/launch-unix.c -+++ b/src/launch-unix.c -@@ -37,6 +37,12 @@ - static int - launch_unix (guestfs_h *g, void *datav, const char *sockpath) - { -+ error (g, -+ "launch: In RHEL, only the 'libvirt' or 'direct' method is supported.\n" -+ "In particular, \"libguestfs live\" is not supported."); -+ return -1; -+ -+#if 0 - int r, daemon_sock = -1; - struct sockaddr_un addr; - uint32_t size; -@@ -102,6 +108,7 @@ launch_unix (guestfs_h *g, void *datav, const char *sockpath) - g->conn = NULL; - } - return -1; -+#endif - } - - static int --- -1.8.3.1 - diff --git a/SOURCES/0096-p2v-Add-verbose-option-to-virt-p2v-make-disk-kicksta.patch b/SOURCES/0096-p2v-Add-verbose-option-to-virt-p2v-make-disk-kicksta.patch new file mode 100644 index 0000000..d0b5333 --- /dev/null +++ b/SOURCES/0096-p2v-Add-verbose-option-to-virt-p2v-make-disk-kicksta.patch @@ -0,0 +1,139 @@ +From 34ab1cf2d4f849b69a01ddb2eb7e87c80523f03f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Jun 2016 13:53:37 +0100 +Subject: [PATCH] p2v: Add --verbose option to virt-p2v-make-{disk,kickstart}. + +For virt-p2v-make-kickstart this doesn't do very much. But for +virt-p2v-make-disk it enables verbose mode in virt-builder which is +extremely useful for debugging problems. + +Thanks: Ming Xie. +(cherry picked from commit 6358633bf22d19c1bc9b9638dfff8e5ac50a37eb) +--- + p2v/virt-p2v-make-disk.in | 13 ++++++++++++- + p2v/virt-p2v-make-disk.pod | 7 +++++++ + p2v/virt-p2v-make-kickstart.in | 9 +++++++-- + p2v/virt-p2v-make-kickstart.pod | 7 +++++++ + 4 files changed, 33 insertions(+), 3 deletions(-) + +diff --git a/p2v/virt-p2v-make-disk.in b/p2v/virt-p2v-make-disk.in +index 88c171f..d58e7f1 100644 +--- a/p2v/virt-p2v-make-disk.in ++++ b/p2v/virt-p2v-make-disk.in +@@ -24,7 +24,7 @@ version="@PACKAGE_VERSION@" + + TEMP=`getopt \ + -o o:V \ +- --long help,inject-ssh-identity:,output:,version \ ++ --long help,inject-ssh-identity:,output:,verbose,version \ + -n $program -- "$@"` + if [ $? != 0 ]; then + echo "$program: problem parsing the command line arguments" +@@ -34,6 +34,7 @@ eval set -- "$TEMP" + + output= + upload= ++verbose= + + usage () + { +@@ -52,6 +53,10 @@ while true; do + -o|--output) + output="$2" + shift 2;; ++ -v|--verbose) ++ set +x ++ verbose=1 ++ shift;; + -V|--version) + echo "$program $version" + exit 0;; +@@ -170,9 +175,15 @@ while read line; do + fi + done < $depsfile + ++# Add -v -x if we're in verbose mode. ++if [ "x$verbose" = "x1" ]; then ++ verbose_option="-v -x" ++fi ++ + # Run virt-builder. Note we controversially assume systemd here. We + # could provide a sysvinit fallback if required. + virt-builder "$osversion" \ ++ $verbose_option \ + --output "$output" \ + --update \ + --install "$install" \ +diff --git a/p2v/virt-p2v-make-disk.pod b/p2v/virt-p2v-make-disk.pod +index 79bf499..d5a5db5 100644 +--- a/p2v/virt-p2v-make-disk.pod ++++ b/p2v/virt-p2v-make-disk.pod +@@ -106,6 +106,13 @@ See L above. + Write output to C, which can be a local file or block device. + B. + ++=item B<-v> ++ ++=item B<--verbose> ++ ++Enable verbose output. Use this if you need to debug problems with ++the script or if you are filing a bug. ++ + =item B<-V> + + =item B<--version> +diff --git a/p2v/virt-p2v-make-kickstart.in b/p2v/virt-p2v-make-kickstart.in +index 74bee61..8a6e4d8 100644 +--- a/p2v/virt-p2v-make-kickstart.in ++++ b/p2v/virt-p2v-make-kickstart.in +@@ -23,8 +23,8 @@ program="virt-p2v-make-kickstart" + version="@PACKAGE_VERSION@" + + TEMP=`getopt \ +- -o o:V \ +- --long help,inject-ssh-identity:,output:,proxy:,version \ ++ -o o:vV \ ++ --long help,inject-ssh-identity:,output:,proxy:,verbose,version \ + -n $program -- "$@"` + if [ $? != 0 ]; then + echo "$program: problem parsing the command line arguments" +@@ -44,6 +44,7 @@ usage () + output=p2v.ks + proxy= + ssh_identity= ++verbose= + + while true; do + case "$1" in +@@ -59,6 +60,10 @@ while true; do + --repo) + repo="$2" + shift 2;; ++ -v|--verbose) ++ set +x ++ verbose=1 ++ shift;; + -V|--version) + echo "$program $version" + exit 0;; +diff --git a/p2v/virt-p2v-make-kickstart.pod b/p2v/virt-p2v-make-kickstart.pod +index 6e65c07..cea3787 100644 +--- a/p2v/virt-p2v-make-kickstart.pod ++++ b/p2v/virt-p2v-make-kickstart.pod +@@ -254,6 +254,13 @@ F in the current directory. + + Tell the kickstart to use a proxy server or web cache for downloads. + ++=item B<-v> ++ ++=item B<--verbose> ++ ++Enable verbose output. Use this if you need to debug problems with ++the script or if you are filing a bug. ++ + =item B<-V> + + =item B<--version> +-- +1.8.3.1 + diff --git a/SOURCES/0097-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch b/SOURCES/0097-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch deleted file mode 100644 index fec8b9b..0000000 --- a/SOURCES/0097-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch +++ /dev/null @@ -1,346 +0,0 @@ -From 12e1dd161e5283e8f0790ed93ad05b40ddcd860f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 18 Jul 2013 18:31:53 +0100 -Subject: [PATCH] RHEL 7: Remove 9p APIs from RHEL (RHBZ#921710). - ---- - Makefile.am | 2 +- - daemon/9p.c | 223 --------------------------------------------------- - daemon/Makefile.am | 1 - - generator/actions.ml | 23 ------ - gobject/Makefile.inc | 2 - - po/POTFILES | 2 - - 6 files changed, 1 insertion(+), 252 deletions(-) - delete mode 100644 daemon/9p.c - -diff --git a/Makefile.am b/Makefile.am -index d55d8d6..207bcb1 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -59,7 +59,7 @@ SUBDIRS += tests/xfs - SUBDIRS += tests/charsets - SUBDIRS += tests/xml - SUBDIRS += tests/mount-local --SUBDIRS += tests/9p -+#SUBDIRS += tests/9p - SUBDIRS += tests/rsync - SUBDIRS += tests/bigdirs - SUBDIRS += tests/disk-labels -diff --git a/daemon/9p.c b/daemon/9p.c -deleted file mode 100644 -index fefbb71..0000000 ---- a/daemon/9p.c -+++ /dev/null -@@ -1,223 +0,0 @@ --/* libguestfs - the guestfsd daemon -- * Copyright (C) 2011 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 -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "daemon.h" --#include "actions.h" -- --#define BUS_PATH "/sys/bus/virtio/drivers/9pnet_virtio" --GUESTFSD_EXT_CMD(str_mount, mount); -- --static char *read_whole_file (const char *filename); -- --/* https://bugzilla.redhat.com/show_bug.cgi?id=714981#c1 */ --char ** --do_list_9p (void) --{ -- DECLARE_STRINGSBUF (r); -- -- DIR *dir; -- -- dir = opendir (BUS_PATH); -- if (!dir) { -- perror ("opendir: " BUS_PATH); -- if (errno != ENOENT) { -- reply_with_perror ("opendir: " BUS_PATH); -- return NULL; -- } -- -- /* If this directory doesn't exist, it probably means that -- * the virtio driver isn't loaded. Don't return an error -- * in this case, but return an empty list. -- */ -- if (end_stringsbuf (&r) == -1) -- return NULL; -- -- return r.argv; -- } -- -- while (1) { -- struct dirent *d; -- -- errno = 0; -- d = readdir (dir); -- if (d == NULL) break; -- -- if (STRPREFIX (d->d_name, "virtio")) { -- char mount_tag_path[256]; -- snprintf (mount_tag_path, sizeof mount_tag_path, -- BUS_PATH "/%s/mount_tag", d->d_name); -- -- /* A bit unclear, but it looks like the virtio transport allows -- * the mount tag length to be unlimited (or up to 65536 bytes). -- * See: linux/include/linux/virtio_9p.h -- */ -- CLEANUP_FREE char *mount_tag = read_whole_file (mount_tag_path); -- if (mount_tag == 0) -- continue; -- -- if (add_string (&r, mount_tag) == -1) { -- closedir (dir); -- return NULL; -- } -- } -- } -- -- /* Check readdir didn't fail */ -- if (errno != 0) { -- reply_with_perror ("readdir: /sys/block"); -- free_stringslen (r.argv, r.size); -- closedir (dir); -- return NULL; -- } -- -- /* Close the directory handle */ -- if (closedir (dir) == -1) { -- reply_with_perror ("closedir: /sys/block"); -- free_stringslen (r.argv, r.size); -- return NULL; -- } -- -- /* Sort the tags. */ -- if (r.size > 0) -- sort_strings (r.argv, r.size); -- -- /* NULL terminate the list */ -- if (end_stringsbuf (&r) == -1) -- return NULL; -- -- return r.argv; --} -- --/* Read whole file into dynamically allocated array. If there is an -- * error, DON'T call reply_with_perror, just return NULL. Returns a -- * \0-terminated string. -- */ --static char * --read_whole_file (const char *filename) --{ -- char *r = NULL; -- size_t alloc = 0, size = 0; -- int fd; -- -- fd = open (filename, O_RDONLY|O_CLOEXEC); -- if (fd == -1) { -- perror (filename); -- return NULL; -- } -- -- while (1) { -- alloc += 256; -- char *r2 = realloc (r, alloc); -- if (r2 == NULL) { -- perror ("realloc"); -- free (r); -- close (fd); -- return NULL; -- } -- r = r2; -- -- /* The '- 1' in the size calculation ensures there is space below -- * to add \0 to the end of the input. -- */ -- ssize_t n = read (fd, r + size, alloc - size - 1); -- if (n == -1) { -- fprintf (stderr, "read: %s: %m\n", filename); -- free (r); -- close (fd); -- return NULL; -- } -- if (n == 0) -- break; -- size += n; -- } -- -- if (close (fd) == -1) { -- fprintf (stderr, "close: %s: %m\n", filename); -- free (r); -- return NULL; -- } -- -- r[size] = '\0'; -- -- return r; --} -- --/* Takes optional arguments, consult optargs_bitmask. */ --int --do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options) --{ -- CLEANUP_FREE char *mp = NULL, *opts = NULL, *err = NULL; -- struct stat statbuf; -- int r; -- -- ABS_PATH (mountpoint, , return -1); -- -- mp = sysroot_path (mountpoint); -- if (!mp) { -- reply_with_perror ("malloc"); -- return -1; -- } -- -- /* Check the mountpoint exists and is a directory. */ -- if (stat (mp, &statbuf) == -1) { -- reply_with_perror ("%s", mountpoint); -- return -1; -- } -- if (!S_ISDIR (statbuf.st_mode)) { -- reply_with_perror ("%s: mount point is not a directory", mountpoint); -- return -1; -- } -- -- /* Add trans=virtio to the options. */ -- if ((optargs_bitmask & GUESTFS_MOUNT_9P_OPTIONS_BITMASK) && -- STRNEQ (options, "")) { -- if (asprintf (&opts, "trans=virtio,%s", options) == -1) { -- reply_with_perror ("asprintf"); -- return -1; -- } -- } -- else { -- opts = strdup ("trans=virtio"); -- if (opts == NULL) { -- reply_with_perror ("strdup"); -- return -1; -- } -- } -- -- r = command (NULL, &err, -- str_mount, "-o", opts, "-t", "9p", mount_tag, mp, NULL); -- if (r == -1) { -- reply_with_error ("%s on %s: %s", mount_tag, mountpoint, err); -- return -1; -- } -- -- return 0; --} -diff --git a/daemon/Makefile.am b/daemon/Makefile.am -index 8ccf322..ec6fc6f 100644 ---- a/daemon/Makefile.am -+++ b/daemon/Makefile.am -@@ -77,7 +77,6 @@ noinst_PROGRAMS = guestfsd - endif - - guestfsd_SOURCES = \ -- 9p.c \ - acl.c \ - actions.h \ - available.c \ -diff --git a/generator/actions.ml b/generator/actions.ml -index 825acf9..2f2ab66 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -9150,29 +9150,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 -- name = "list_9p"; -- style = RStringList "mounttags", [], []; -- proc_nr = Some 285; -- shortdesc = "list 9p filesystems"; -- longdesc = "\ --List all 9p filesystems attached to the guest. A list of --mount tags is returned." }; -- -- { defaults with -- name = "mount_9p"; -- style = RErr, [String "mounttag"; String "mountpoint"], [OString "options"]; -- proc_nr = Some 286; -- camel_name = "Mount9P"; -- shortdesc = "mount 9p filesystem"; -- longdesc = "\ --Mount the virtio-9p filesystem with the tag C on the --directory C. -- --If required, C will be automatically added to the options. --Any other options required can be passed in the optional C --parameter." }; -- -- { defaults with - name = "list_dm_devices"; - style = RStringList "devices", [], []; - proc_nr = Some 287; -diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc -index c93dace..f2152f2 100644 ---- a/gobject/Makefile.inc -+++ b/gobject/Makefile.inc -@@ -78,7 +78,6 @@ guestfs_gobject_headers= \ - include/guestfs-gobject/optargs-mkfs_btrfs.h \ - include/guestfs-gobject/optargs-mkswap.h \ - include/guestfs-gobject/optargs-mktemp.h \ -- include/guestfs-gobject/optargs-mount_9p.h \ - include/guestfs-gobject/optargs-mount_local.h \ - include/guestfs-gobject/optargs-ntfsclone_out.h \ - include/guestfs-gobject/optargs-ntfsfix.h \ -@@ -156,7 +155,6 @@ guestfs_gobject_sources= \ - src/optargs-mkfs_btrfs.c \ - src/optargs-mkswap.c \ - src/optargs-mktemp.c \ -- src/optargs-mount_9p.c \ - src/optargs-mount_local.c \ - src/optargs-ntfsclone_out.c \ - src/optargs-ntfsfix.c \ -diff --git a/po/POTFILES b/po/POTFILES -index 1a088f5..7f3365c 100644 ---- a/po/POTFILES -+++ b/po/POTFILES -@@ -14,7 +14,6 @@ cat/ls.c - cat/visit.c - customize/crypt-c.c - customize/perl_edit-c.c --daemon/9p.c - daemon/acl.c - daemon/augeas.c - daemon/available.c -@@ -203,7 +202,6 @@ gobject/src/optargs-mkfs.c - gobject/src/optargs-mkfs_btrfs.c - gobject/src/optargs-mkswap.c - gobject/src/optargs-mktemp.c --gobject/src/optargs-mount_9p.c - gobject/src/optargs-mount_local.c - gobject/src/optargs-ntfsclone_out.c - gobject/src/optargs-ntfsfix.c --- -1.8.3.1 - diff --git a/SOURCES/0097-mllib-Add-bindings-for-makedev-3-major-3-and-minor-3.patch b/SOURCES/0097-mllib-Add-bindings-for-makedev-3-major-3-and-minor-3.patch new file mode 100644 index 0000000..5898e8b --- /dev/null +++ b/SOURCES/0097-mllib-Add-bindings-for-makedev-3-major-3-and-minor-3.patch @@ -0,0 +1,192 @@ +From 18c35c397d37144d4ec0e2815dc6333977397b91 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Jun 2016 14:50:44 +0100 +Subject: [PATCH] mllib: Add bindings for makedev(3), major(3) and minor(3). + +(cherry picked from commit dd2ce98d242c0598a3bd484110f8cb0f9e88ec54) +--- + mllib/Makefile.am | 3 +++ + mllib/dev_t-c.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + mllib/dev_t.ml | 21 +++++++++++++++++++++ + mllib/dev_t.mli | 28 ++++++++++++++++++++++++++++ + po/POTFILES | 1 + + po/POTFILES-ml | 1 + + 6 files changed, 106 insertions(+) + create mode 100644 mllib/dev_t-c.c + create mode 100644 mllib/dev_t.ml + create mode 100644 mllib/dev_t.mli + +diff --git a/mllib/Makefile.am b/mllib/Makefile.am +index fc4dd95..e44abed 100644 +--- a/mllib/Makefile.am ++++ b/mllib/Makefile.am +@@ -29,6 +29,7 @@ CLEANFILES = *~ *.annot *.cmi *.cmo *.cmx *.cmxa *.o + SOURCES_MLI = \ + common_utils.mli \ + curl.mli \ ++ dev_t.mli \ + fsync.mli \ + JSON.mli \ + mkdtemp.mli \ +@@ -41,6 +42,7 @@ SOURCES_ML = \ + guestfs_config.ml \ + libdir.ml \ + common_gettext.ml \ ++ dev_t.ml \ + common_utils.ml \ + fsync.ml \ + progress.ml \ +@@ -54,6 +56,7 @@ SOURCES_ML = \ + SOURCES_C = \ + ../fish/progress.c \ + ../fish/uri.c \ ++ dev_t-c.c \ + fsync-c.c \ + mkdtemp-c.c \ + progress-c.c \ +diff --git a/mllib/dev_t-c.c b/mllib/dev_t-c.c +new file mode 100644 +index 0000000..036b60d +--- /dev/null ++++ b/mllib/dev_t-c.c +@@ -0,0 +1,52 @@ ++/* libguestfs OCaml tools common code ++ * Copyright (C) 2016 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 ++ ++#include ++#include ++#include ++ ++#include ++ ++/* OCaml doesn't bind the dev_t calls makedev, major and minor. */ ++ ++extern value guestfs_int_mllib_dev_t_makedev (value majv, value minv); ++extern value guestfs_int_mllib_dev_t_major (value devv); ++extern value guestfs_int_mllib_dev_t_minor (value devv); ++ ++/* NB: This is a "noalloc" call. */ ++value ++guestfs_int_mllib_dev_t_makedev (value majv, value minv) ++{ ++ return Val_int (makedev (Int_val (majv), Int_val (minv))); ++} ++ ++/* NB: This is a "noalloc" call. */ ++value ++guestfs_int_mllib_dev_t_major (value devv) ++{ ++ return Val_int (major (Int_val (devv))); ++} ++ ++/* NB: This is a "noalloc" call. */ ++value ++guestfs_int_mllib_dev_t_minor (value devv) ++{ ++ return Val_int (minor (Int_val (devv))); ++} +diff --git a/mllib/dev_t.ml b/mllib/dev_t.ml +new file mode 100644 +index 0000000..143954a +--- /dev/null ++++ b/mllib/dev_t.ml +@@ -0,0 +1,21 @@ ++(* libguestfs OCaml tools common code ++ * Copyright (C) 2016 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. ++ *) ++ ++external makedev : int -> int -> int = "guestfs_int_mllib_dev_t_makedev" "noalloc" ++external major : int -> int = "guestfs_int_mllib_dev_t_major" "noalloc" ++external minor : int -> int = "guestfs_int_mllib_dev_t_minor" "noalloc" +diff --git a/mllib/dev_t.mli b/mllib/dev_t.mli +new file mode 100644 +index 0000000..340ead0 +--- /dev/null ++++ b/mllib/dev_t.mli +@@ -0,0 +1,28 @@ ++(* virt-resize ++ * Copyright (C) 2016 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. ++ *) ++ ++(** Bindings for [dev_t] related functions [makedev], [major] and [minor]. *) ++ ++val makedev : int -> int -> int ++(** makedev(3) *) ++ ++val major : int -> int ++(** major(3) *) ++ ++val minor : int -> int ++(** minor(3) *) +diff --git a/po/POTFILES b/po/POTFILES +index ebee244..1252d8b 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -261,6 +261,7 @@ inspector/inspector.c + java/com_redhat_et_libguestfs_GuestFS.c + lua/lua-guestfs.c + make-fs/make-fs.c ++mllib/dev_t-c.c + mllib/dummy.c + mllib/fsync-c.c + mllib/mkdtemp-c.c +diff --git a/po/POTFILES-ml b/po/POTFILES-ml +index b7f3cc2..2b9bba1 100644 +--- a/po/POTFILES-ml ++++ b/po/POTFILES-ml +@@ -43,6 +43,7 @@ mllib/common_gettext.ml + mllib/common_utils.ml + mllib/common_utils_tests.ml + mllib/curl.ml ++mllib/dev_t.ml + mllib/fsync.ml + mllib/guestfs_config.ml + mllib/libdir.ml +-- +1.8.3.1 + diff --git a/SOURCES/0098-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch b/SOURCES/0098-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch deleted file mode 100644 index 5e3dfc6..0000000 --- a/SOURCES/0098-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch +++ /dev/null @@ -1,586 +0,0 @@ -From f55cbd578c873ad815bd3f8915a49be430b35b72 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 29 Jul 2013 14:47:56 +0100 -Subject: [PATCH] RHEL 7: Disable unsupported remote drive protocols - (RHBZ#962113). - -This disables support for unsupported remote drive protocols: - - * ftp - * ftps - * http - * https - * tftp - * gluster - * iscsi - * sheepdog - * ssh - -Note 'nbd' is not disabled, and of course 'file' works. - -We hope to gradually add some of these back over the lifetime of RHEL 7. - -In RHEL 7.2: rbd (Ceph) support was enabled. ---- - examples/guestfs-testing.pod | 21 ------- - fish/guestfish.pod | 64 ++------------------- - fish/test-add-uri.sh | 25 --------- - generator/actions.ml | 48 +--------------- - src/drives.c | 8 +++ - src/guestfs.pod | 100 --------------------------------- - tests/disks/test-qemu-drive-libvirt.sh | 28 --------- - tests/disks/test-qemu-drive.sh | 51 ----------------- - 8 files changed, 15 insertions(+), 330 deletions(-) - -diff --git a/examples/guestfs-testing.pod b/examples/guestfs-testing.pod -index 2186ed3..ae23b59 100644 ---- a/examples/guestfs-testing.pod -+++ b/examples/guestfs-testing.pod -@@ -117,27 +117,6 @@ image. To exit, type C. - If you get an error, try enabling debugging (add C<-v> to the command - line). Also make sure that L succeeds. - --=head2 Try to open a remote guest image with guestfish. -- --B this test requires S 1.22> and S 1.5>. --You may also have to disable libvirt by setting this: -- -- export LIBGUESTFS_BACKEND=direct -- --If you have a disk image available over HTTP/FTP, try to open it. -- -- guestfish --ro -i --format=raw -a http://www.example.com/disk.img -- --For SSH you will need to make sure that ssh-agent is set up so you --don't need a password to log in to the remote machine. Then a command --similar to this should work: -- -- guestfish --ro -i --format=raw \ -- -a ssh://remote.example.com/path/to/disk.img -- --If you get an error, try enabling debugging (add C<-v> to the command --line). Also make sure that L succeeds. -- - =head2 Run virt-alignment-scan on all your guests. - - Run L on guests or disk images: -diff --git a/fish/guestfish.pod b/fish/guestfish.pod -index 12bf243..e7423a6 100644 ---- a/fish/guestfish.pod -+++ b/fish/guestfish.pod -@@ -138,9 +138,9 @@ To list what is available do: - - =head2 Remote drives - --Access a remote disk using ssh: -+Access a remote disk using NBD: - -- guestfish -a ssh://example.com/path/to/disk.img -+ guestfish -a nbd://example.com - - =head2 Remote control - -@@ -1125,12 +1125,12 @@ L>. - On the command line, you can use the I<-a> option to add network - block devices using a URI-style format, for example: - -- guestfish -a ssh://root@example.com/disk.img -+ guestfish -a nbd://example.com - - URIs I be used with the L command. The equivalent - command using the API directly is: - -- > add /disk.img protocol:ssh server:tcp:example.com username:root -+ > add /disk.img protocol:nbd server:tcp:example.com - - The possible I<-a URI> formats are described below. - -@@ -1140,40 +1140,6 @@ The possible I<-a URI> formats are described below. - - Add the local disk image (or device) called C. - --=head2 B<-a ftp://[user@]example.com[:port]/disk.img> -- --=head2 B<-a ftps://[user@]example.com[:port]/disk.img> -- --=head2 B<-a http://[user@]example.com[:port]/disk.img> -- --=head2 B<-a https://[user@]example.com[:port]/disk.img> -- --=head2 B<-a tftp://[user@]example.com[:port]/disk.img> -- --Add a disk located on a remote FTP, HTTP or TFTP server. -- --The equivalent API command would be: -- -- > add /disk.img protocol:(ftp|...) server:tcp:example.com -- --=head2 B<-a gluster://example.com[:port]/volname/image> -- --Add a disk image located on GlusterFS storage. -- --The server is the one running C, and may be C. -- --The equivalent API command would be: -- -- > add volname/image protocol:gluster server:tcp:example.com -- --=head2 B<-a iscsi://example.com[:port]/target-iqn-name[/lun]> -- --Add a disk located on an iSCSI server. -- --The equivalent API command would be: -- -- > add target-iqn-name/lun protocol:iscsi server:tcp:example.com -- - =head2 B<-a nbd://example.com[:port]> - - =head2 B<-a nbd://example.com[:port]/exportname> -@@ -1208,28 +1174,6 @@ The equivalent API command would be: - - > add pool/disk protocol:rbd server:tcp:example.com:port - --=head2 B<-a sheepdog://[example.com[:port]]/volume/image> -- --Add a disk image located on a Sheepdog volume. -- --The server name is optional. Although libguestfs and Sheepdog --supports multiple servers, only at most one server can be specified --when using this URI syntax. -- --The equivalent API command would be: -- -- > add volume protocol:sheepdog [server:tcp:example.com] -- --=head2 B<-a ssh://[user@]example.com[:port]/disk.img> -- --Add a disk image located on a remote server, accessed using the Secure --Shell (ssh) SFTP protocol. SFTP is supported out of the box by all --major SSH servers. -- --The equivalent API command would be: -- -- > add /disk protocol:ssh server:tcp:example.com [username:user] -- - =head1 PROGRESS BARS - - Some (not all) long-running commands send progress notification -diff --git a/fish/test-add-uri.sh b/fish/test-add-uri.sh -index 2f83754..48c12b8 100755 ---- a/fish/test-add-uri.sh -+++ b/fish/test-add-uri.sh -@@ -37,14 +37,6 @@ function fail () - $VG guestfish -x -a file://$(pwd)/test-add-uri.img test-add-uri.out 2>&1 - grep -sq 'add_drive ".*/test-add-uri.img"' test-add-uri.out || fail - --# curl --$VG guestfish -x -a ftp://user@example.com/disk.img test-add-uri.out 2>&1 --grep -sq 'add_drive "/disk.img" "protocol:ftp" "server:tcp:example.com" "username:user"' test-add-uri.out || fail -- --# gluster --$VG guestfish -x -a gluster://example.com/disk test-add-uri.out 2>&1 --grep -sq 'add_drive "disk" "protocol:gluster" "server:tcp:example.com"' test-add-uri.out || fail -- - # NBD - $VG guestfish -x -a nbd://example.com test-add-uri.out 2>&1 - grep -sq 'add_drive "" "protocol:nbd" "server:tcp:example.com"' test-add-uri.out || fail -@@ -64,22 +56,5 @@ grep -sq 'add_drive "pool/disk" "protocol:rbd" "server:tcp:example.com:6789"' te - $VG guestfish -x -a rbd:///pool/disk test-add-uri.out 2>&1 - grep -sq 'add_drive "pool/disk" "protocol:rbd"' test-add-uri.out || fail - --# sheepdog --$VG guestfish -x -a sheepdog:///volume/image test-add-uri.out 2>&1 --grep -sq 'add_drive "volume/image" "protocol:sheepdog"' test-add-uri.out || fail -- --$VG guestfish -x -a sheepdog://example.com:3000/volume/image test-add-uri.out 2>&1 --grep -sq 'add_drive "volume/image" "protocol:sheepdog" "server:tcp:example.com:3000"' test-add-uri.out || fail -- --# ssh --$VG guestfish -x -a ssh://example.com/disk.img test-add-uri.out 2>&1 --grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com"' test-add-uri.out || fail -- --$VG guestfish -x -a ssh://user@example.com/disk.img test-add-uri.out 2>&1 --grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com" "username:user"' test-add-uri.out || fail -- --$VG guestfish -x -a ssh://user@example.com:2000/disk.img test-add-uri.out 2>&1 --grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com:2000" "username:user"' test-add-uri.out || fail -- - rm test-add-uri.out - rm test-add-uri.img -diff --git a/generator/actions.ml b/generator/actions.ml -index 2f2ab66..ea715d0 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -1397,27 +1397,6 @@ C is interpreted as a local file or device. - This is the default if the optional protocol parameter - is omitted. - --=item C -- --Connect to a remote FTP, HTTP or TFTP server. --The C parameter must also be supplied - see below. -- --See also: L -- --=item C -- --Connect to the GlusterFS server. --The C parameter must also be supplied - see below. -- --See also: L -- --=item C -- --Connect to the iSCSI server. --The C parameter must also be supplied - see below. -- --See also: L. -- - =item C - - Connect to the Network Block Device server. -@@ -1434,22 +1413,6 @@ The C parameter may be supplied. See below. - - See also: L. - --=item C -- --Connect to the Sheepdog server. --The C parameter may also be supplied - see below. -- --See also: L. -- --=item C -- --Connect to the Secure Shell (ssh) server. -- --The C parameter must be supplied. --The C parameter may be supplied. See below. -- --See also: L. -- - =back - - =item C -@@ -1460,13 +1423,8 @@ is a list of server(s). - Protocol Number of servers required - -------- -------------------------- - file List must be empty or param not used at all -- ftp|ftps|http|https|tftp Exactly one -- gluster Exactly one -- iscsi Exactly one - nbd Exactly one - rbd Zero or more -- sheepdog Zero or more -- ssh Exactly one - - Each list element is a string specifying a server. The string must be - in one of the following formats: -@@ -1482,10 +1440,10 @@ for the protocol is used (see C). - - =item C - --For the C, C, C, C, C, C, C --and C protocols, this specifies the remote username. -+For the C -+protocol, this specifies the remote username. - --If not given, then the local username is used for C, and no authentication -+If not given, then no authentication - is attempted for ceph. But note this sometimes may give unexpected results, for - 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. If in doubt, -diff --git a/src/drives.c b/src/drives.c -index 307f267..34cf07a 100644 ---- a/src/drives.c -+++ b/src/drives.c -@@ -199,6 +199,7 @@ create_drive_non_file (guestfs_h *g, - return drv; - } - -+#if 0 /* DISABLED IN RHEL 7 */ - static struct drive * - create_drive_curl (guestfs_h *g, - const struct drive_create_data *data) -@@ -257,6 +258,7 @@ create_drive_gluster (guestfs_h *g, - - return create_drive_non_file (g, data); - } -+#endif /* DISABLED IN RHEL 7 */ - - static int - nbd_port (void) -@@ -325,6 +327,7 @@ create_drive_rbd (guestfs_h *g, - return create_drive_non_file (g, data); - } - -+#if 0 /* DISABLED IN RHEL 7 */ - static struct drive * - create_drive_sheepdog (guestfs_h *g, - const struct drive_create_data *data) -@@ -435,6 +438,7 @@ create_drive_iscsi (guestfs_h *g, - - return create_drive_non_file (g, data); - } -+#endif /* DISABLED IN RHEL 7 */ - - /* Traditionally you have been able to use /dev/null as a filename, as - * many times as you like. Ancient KVM (RHEL 5) cannot handle adding -@@ -882,6 +886,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, - drv = create_drive_file (g, &data); - } - } -+#if 0 /* DISABLED IN RHEL 7 */ - else if (STREQ (protocol, "ftp")) { - data.protocol = drive_protocol_ftp; - drv = create_drive_curl (g, &data); -@@ -906,6 +911,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, - data.protocol = drive_protocol_iscsi; - drv = create_drive_iscsi (g, &data); - } -+#endif /* DISABLED IN RHEL 7 */ - else if (STREQ (protocol, "nbd")) { - data.protocol = drive_protocol_nbd; - drv = create_drive_nbd (g, &data); -@@ -914,6 +920,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, - data.protocol = drive_protocol_rbd; - drv = create_drive_rbd (g, &data); - } -+#if 0 /* DISABLED IN RHEL 7 */ - else if (STREQ (protocol, "sheepdog")) { - data.protocol = drive_protocol_sheepdog; - drv = create_drive_sheepdog (g, &data); -@@ -926,6 +933,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, - data.protocol = drive_protocol_tftp; - drv = create_drive_curl (g, &data); - } -+#endif /* DISABLED IN RHEL 7 */ - else { - error (g, _("unknown protocol '%s'"), protocol); - drv = NULL; /*FALLTHROUGH*/ -diff --git a/src/guestfs.pod b/src/guestfs.pod -index c9ac1fa..3c1ad46 100644 ---- a/src/guestfs.pod -+++ b/src/guestfs.pod -@@ -695,70 +695,6 @@ servers. The server string is documented in - L. The C and C parameters are - also optional, and if not given, then no authentication will be used. - --=head3 FTP, HTTP AND TFTP -- --Libguestfs can access remote disks over FTP, FTPS, HTTP, HTTPS --or TFTP protocols. -- --To do this, set the optional C and C parameters of --L like this: -- -- char **servers = { "www.example.org", NULL }; -- guestfs_add_drive_opts (g, "/disk.img", -- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", -- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "http", -- GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, -- -1); -- --The C can be one of C<"ftp">, C<"ftps">, C<"http">, --C<"https"> or C<"tftp">. -- --C (the C parameter) is a list which must have a --single element. The single element is a string defining the web, --FTP or TFTP server. The format of this string is documented in --L. -- --=head3 GLUSTER -- --Libguestfs can access Gluster disks. -- --To do this, set the optional C and C parameters of --L like this: -- -- char **servers = { "gluster.example.org:24007", NULL }; -- guestfs_add_drive_opts (g, "volname/image", -- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", -- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "gluster", -- GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, -- -1); -- --C (the C parameter) is a list which must have a --single element. The single element is a string defining the Gluster --server. The format of this string is documented in --L. -- --Note that gluster usually requires the client process (ie. libguestfs) --to run as B and will give unfathomable errors if it is not --(eg. "No data available"). -- --=head3 ISCSI -- --Libguestfs can access iSCSI disks remotely. -- --To do this, set the optional C and C parameters like --this: -- -- char **server = { "iscsi.example.org:3000", NULL }; -- guestfs_add_drive_opts (g, "target-iqn-name/lun", -- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", -- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "iscsi", -- GUESTFS_ADD_DRIVE_OPTS_SERVER, server, -- -1); -- --The C parameter is a list which must have a single element. --The single element is a string defining the iSCSI server. The format --of this string is documented in L. -- - =head3 NETWORK BLOCK DEVICE - - Libguestfs can access Network Block Device (NBD) disks remotely. -@@ -821,42 +757,6 @@ L - - =back - --=head3 SHEEPDOG -- --Libguestfs can access Sheepdog disks. -- --To do this, set the optional C and C parameters of --L like this: -- -- char **servers = { /* optional servers ... */ NULL }; -- guestfs_add_drive_opts (g, "volume", -- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", -- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "sheepdog", -- GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, -- -1); -- --The optional list of C may be zero or more server addresses --(C<"hostname:port">). The format of the server strings is documented --in L. -- --=head3 SSH -- --Libguestfs can access disks over a Secure Shell (SSH) connection. -- --To do this, set the C and C and (optionally) --C parameters of L like this: -- -- char **server = { "remote.example.com", NULL }; -- guestfs_add_drive_opts (g, "/path/to/disk.img", -- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", -- GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "ssh", -- GUESTFS_ADD_DRIVE_OPTS_SERVER, server, -- GUESTFS_ADD_DRIVE_OPTS_USERNAME, "remoteuser", -- -1); -- --The format of the server string is documented in --L. -- - =head2 INSPECTION - - 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 9930865..1367079 100755 ---- a/tests/disks/test-qemu-drive-libvirt.sh -+++ b/tests/disks/test-qemu-drive-libvirt.sh -@@ -76,34 +76,6 @@ check_output - grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail - 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 --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 --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 --rm "$DEBUG_QEMU_FILE" -- --# Sheepdog. -- --$guestfish -d sheepdog run ||: --check_output --grep -sq -- '-drive file=sheepdog:volume,' "$DEBUG_QEMU_FILE" || fail --rm "$DEBUG_QEMU_FILE" -- - # To do: - - # HTTP - curl not yet supported by libvirt -diff --git a/tests/disks/test-qemu-drive.sh b/tests/disks/test-qemu-drive.sh -index b530e7d..c0239ff 100755 ---- a/tests/disks/test-qemu-drive.sh -+++ b/tests/disks/test-qemu-drive.sh -@@ -61,36 +61,6 @@ check_output - grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail - rm "$DEBUG_QEMU_FILE" - --# HTTP. -- --guestfish < +Date: Thu, 2 Jun 2016 15:10:04 +0100 +Subject: [PATCH] mllib: Add Common_utils.is_partition function. + +Returns true if the device is a host partition. + +The only tedious bit of this patch is that now Common_utils depends on +Dev_t so we have to add extra objects every time something links with +Common_utils. + +(cherry picked from commit df7a33768eab2381b958ede2c8a40bc9cbc87928) +--- + builder/Makefile.am | 2 ++ + customize/Makefile.am | 2 ++ + dib/Makefile.am | 2 ++ + get-kernel/Makefile.am | 2 ++ + mllib/common_utils.ml | 13 +++++++++++++ + mllib/common_utils.mli | 4 ++++ + resize/Makefile.am | 2 ++ + sparsify/Makefile.am | 2 ++ + sysprep/Makefile.am | 2 ++ + v2v/Makefile.am | 5 +++++ + 10 files changed, 36 insertions(+) + +diff --git a/builder/Makefile.am b/builder/Makefile.am +index f31aef9..54aa10b 100644 +--- a/builder/Makefile.am ++++ b/builder/Makefile.am +@@ -89,6 +89,7 @@ SOURCES_ML = \ + builder.ml + + SOURCES_C = \ ++ ../mllib/dev_t-c.c \ + ../mllib/fsync-c.c \ + ../mllib/uri-c.c \ + ../mllib/mkdtemp-c.c \ +@@ -134,6 +135,7 @@ BOBJECTS = \ + $(top_builddir)/mllib/libdir.cmo \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/fsync.cmo \ + $(top_builddir)/mllib/planner.cmo \ +diff --git a/customize/Makefile.am b/customize/Makefile.am +index 033816c..661917a 100644 +--- a/customize/Makefile.am ++++ b/customize/Makefile.am +@@ -69,6 +69,7 @@ SOURCES_C = \ + ../fish/uri.c \ + ../fish/file-edit.c \ + ../fish/file-edit.h \ ++ ../mllib/dev_t-c.c \ + ../mllib/uri-c.c \ + crypt-c.c \ + perl_edit-c.c +@@ -93,6 +94,7 @@ virt_customize_CFLAGS = \ + BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/regedit.cmo \ + $(top_builddir)/mllib/URI.cmo \ +diff --git a/dib/Makefile.am b/dib/Makefile.am +index b969677..d1674a9 100644 +--- a/dib/Makefile.am ++++ b/dib/Makefile.am +@@ -33,6 +33,7 @@ SOURCES_ML = \ + dib.ml + + SOURCES_C = \ ++ ../mllib/dev_t-c.c \ + ../mllib/mkdtemp-c.c + + bin_PROGRAMS = +@@ -57,6 +58,7 @@ BOBJECTS = \ + $(top_builddir)/mllib/libdir.cmo \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/mkdtemp.cmo \ + $(SOURCES_ML:.ml=.cmo) +diff --git a/get-kernel/Makefile.am b/get-kernel/Makefile.am +index da94ece..9d8fc61 100644 +--- a/get-kernel/Makefile.am ++++ b/get-kernel/Makefile.am +@@ -27,6 +27,7 @@ SOURCES_ML = \ + get_kernel.ml + + SOURCES_C = \ ++ ../mllib/dev_t-c.c \ + ../mllib/uri-c.c \ + ../fish/uri.c + +@@ -56,6 +57,7 @@ BOBJECTS = \ + $(top_builddir)/mllib/libdir.cmo \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/URI.cmo \ + $(SOURCES_ML:.ml=.cmo) +diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml +index 2ba8f9a..c29dfa0 100644 +--- a/mllib/common_utils.ml ++++ b/mllib/common_utils.ml +@@ -819,6 +819,19 @@ let is_char_device file = + try (Unix.stat file).Unix.st_kind = Unix.S_CHR + with Unix.Unix_error _ -> false + ++let is_partition dev = ++ try ++ if not (is_block_device dev) then false ++ else ( ++ let rdev = (Unix.stat dev).Unix.st_rdev in ++ let major = Dev_t.major rdev in ++ let minor = Dev_t.minor rdev in ++ let path = sprintf "/sys/dev/block/%d:%d/partition" major minor in ++ Unix.access path [F_OK]; ++ true ++ ) ++ with Unix.Unix_error _ -> false ++ + (* Annoyingly Sys.is_directory throws an exception on failure + * (RHBZ#1022431). + *) +diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli +index ae89fd6..4cfe7d0 100644 +--- a/mllib/common_utils.mli ++++ b/mllib/common_utils.mli +@@ -327,6 +327,10 @@ val is_char_device : string -> bool + val is_directory : string -> bool + (** These don't throw exceptions, unlike the [Sys] functions. *) + ++val is_partition : string -> bool ++(** Return true if the host device [dev] is a partition. If it's ++ anything else, or missing, returns false. *) ++ + val absolute_path : string -> string + (** Convert any path to an absolute path. *) + +diff --git a/resize/Makefile.am b/resize/Makefile.am +index f4d1626..e9f48da 100644 +--- a/resize/Makefile.am ++++ b/resize/Makefile.am +@@ -30,6 +30,7 @@ SOURCES_ML = \ + resize.ml + + SOURCES_C = \ ++ ../mllib/dev_t-c.c \ + ../mllib/fsync-c.c \ + ../fish/progress.c \ + ../mllib/progress-c.c \ +@@ -58,6 +59,7 @@ BOBJECTS = \ + $(top_builddir)/mllib/URI.cmo \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(SOURCES_ML:.ml=.cmo) + XOBJECTS = $(BOBJECTS:.cmo=.cmx) +diff --git a/sparsify/Makefile.am b/sparsify/Makefile.am +index 3da7a7a..9df3e1f 100644 +--- a/sparsify/Makefile.am ++++ b/sparsify/Makefile.am +@@ -37,6 +37,7 @@ SOURCES_ML = \ + + SOURCES_C = \ + ../fish/progress.c \ ++ ../mllib/dev_t-c.c \ + ../mllib/progress-c.c \ + statvfs-c.c + +@@ -57,6 +58,7 @@ virt_sparsify_CFLAGS = \ + BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/progress.cmo \ + $(SOURCES_ML:.ml=.cmo) +diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am +index b890bca..e439a88 100644 +--- a/sysprep/Makefile.am ++++ b/sysprep/Makefile.am +@@ -80,6 +80,7 @@ SOURCES_ML = \ + main.ml + + SOURCES_C = \ ++ ../mllib/dev_t-c.c \ + ../mllib/uri-c.c \ + ../mllib/mkdtemp-c.c \ + ../customize/crypt-c.c \ +@@ -106,6 +107,7 @@ virt_sysprep_CFLAGS = \ + BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/URI.cmo \ + $(top_builddir)/mllib/mkdtemp.cmo \ +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 5d0ce95..5bffbfe 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -113,6 +113,7 @@ SOURCES_ML = \ + v2v.ml + + SOURCES_C = \ ++ ../mllib/dev_t-c.c \ + ../mllib/mkdtemp-c.c \ + domainxml-c.c \ + changeuid-c.c \ +@@ -137,6 +138,7 @@ virt_v2v_CFLAGS = \ + BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/regedit.cmo \ + $(top_builddir)/mllib/mkdtemp.cmo \ +@@ -187,6 +189,7 @@ virt_v2v_LINK = \ + $(OBJECTS) -o $@ + + virt_v2v_copy_to_local_SOURCES = \ ++ ../mllib/dev_t-c.c \ + domainxml-c.c \ + utils-c.c \ + xml-c.c +@@ -203,6 +206,7 @@ virt_v2v_copy_to_local_CFLAGS = \ + COPY_TO_LOCAL_BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/JSON.cmo \ + $(top_builddir)/mllib/curl.cmo \ +@@ -361,6 +365,7 @@ endif + v2v_unit_tests_BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/regedit.cmo \ + stringMap.cmo \ +-- +1.8.3.1 + diff --git a/SOURCES/0099-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch b/SOURCES/0099-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch deleted file mode 100644 index 6252d84..0000000 --- a/SOURCES/0099-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 4727bbbc937f819570ee9dca1d1bfcaff14ee73a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 19 Sep 2014 13:38:20 +0100 -Subject: [PATCH] RHEL 7: Remove User-Mode Linux (RHBZ#1144197). - -This isn't supported in RHEL 7. ---- - src/launch-uml.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/src/launch-uml.c b/src/launch-uml.c -index 21525e3..8643ea8 100644 ---- a/src/launch-uml.c -+++ b/src/launch-uml.c -@@ -47,7 +47,9 @@ struct backend_uml_data { - char umid[UML_UMID_LEN+1]; /* umid=<...> unique ID. */ - }; - -+#if 0 - static void print_vmlinux_command_line (guestfs_h *g, char **argv); -+#endif - - /* Run uml_mkcow to create a COW overlay. */ - static char * -@@ -85,6 +87,7 @@ create_cow_overlay_uml (guestfs_h *g, void *datav, struct drive *drv) - return make_cow_overlay (g, drv->src.u.path); - } - -+#if 0 - /* Test for features which are not supported by the UML backend. - * Possibly some of these should just be warnings, not errors. - */ -@@ -132,10 +135,17 @@ uml_supported (guestfs_h *g) - - return true; - } -+#endif - - static int - launch_uml (guestfs_h *g, void *datav, const char *arg) - { -+ error (g, -+ "launch: In RHEL, only the 'libvirt' or 'direct' method is supported.\n" -+ "In particular, User-Mode Linux (UML) is not supported."); -+ return -1; -+ -+#if 0 - struct backend_uml_data *data = datav; - CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline); - int console_sock = -1, daemon_sock = -1; -@@ -503,8 +513,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) - } - g->state = CONFIG; - return -1; -+#endif - } - -+#if 0 - /* 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. -@@ -534,6 +546,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv) - - fputc ('\n', stderr); - } -+#endif - - static int - shutdown_uml (guestfs_h *g, void *datav, int check_for_errors) --- -1.8.3.1 - diff --git a/SOURCES/0099-builder-Warn-if-output-is-a-host-partition-RHBZ-1342.patch b/SOURCES/0099-builder-Warn-if-output-is-a-host-partition-RHBZ-1342.patch new file mode 100644 index 0000000..23fa2d8 --- /dev/null +++ b/SOURCES/0099-builder-Warn-if-output-is-a-host-partition-RHBZ-1342.patch @@ -0,0 +1,125 @@ +From 44afd4c1f26379b32f62690cf19e06022cafa994 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Jun 2016 14:51:12 +0100 +Subject: [PATCH] builder: Warn if --output is a host partition (RHBZ#1342337). + +But allow the warning to be turned off using --no-warn-if-partition. + +Ming Xie tried to create a bootable USB key using +'virt-p2v-make-disk -o /dev/sdX1'. That works, but doesn't create a +bootable key because it puts everything into the first partition. + +Emit a warning if someone tries to do this to try to prevent user +error: + + virt-builder: warning: output device (/dev/sdb1) is a partition. If you + are writing to a USB key or external drive then you probably need to write + to the whole device, not to a partition. If this warning is wrong then you + can disable it with --no-warn-if-partition + +(cherry picked from commit 7274f11ad408bcd4299ba82b3b26f46e62930d03) +--- + builder/builder.ml | 9 +++++++++ + builder/cmdline.ml | 6 ++++++ + builder/cmdline.mli | 1 + + builder/virt-builder.pod | 9 +++++++++ + 4 files changed, 25 insertions(+) + +diff --git a/builder/builder.ml b/builder/builder.ml +index a6f92c7..ac4c748 100644 +--- a/builder/builder.ml ++++ b/builder/builder.ml +@@ -268,6 +268,15 @@ let main () = + + (* --- If we get here, we want to create a guest. --- *) + ++ (* Warn if the user might be writing to a partition on a USB key. *) ++ (match cmdline.output with ++ | Some device when is_partition device -> ++ if cmdline.warn_if_partition then ++ warning (f_"output device (%s) is a partition. If you are writing to a USB key or external drive then you probably need to write to the whole device, not to a partition. If this warning is wrong then you can disable it with --no-warn-if-partition") ++ device; ++ | Some _ | None -> () ++ ); ++ + (* Download the template, or it may be in the cache. *) + let template = + let template, delete_on_exit = +diff --git a/builder/cmdline.ml b/builder/cmdline.ml +index 4893cbf..5205fe6 100644 +--- a/builder/cmdline.ml ++++ b/builder/cmdline.ml +@@ -51,6 +51,7 @@ type cmdline = { + smp : int option; + sources : (string * string) list; + sync : bool; ++ warn_if_partition : bool; + } + + let parse_cmdline () = +@@ -115,6 +116,7 @@ let parse_cmdline () = + let add_source arg = push_front arg sources in + + let sync = ref true in ++ let warn_if_partition = ref true in + + let argspec = [ + "--arch", Arg.Set_string arch, "arch" ^ " " ^ s_"Set the output architecture"; +@@ -163,6 +165,8 @@ let parse_cmdline () = + "--smp", Arg.Int set_smp, "vcpus" ^ " " ^ s_"Set number of vCPUs"; + "--source", Arg.String add_source, "URL" ^ " " ^ s_"Set source URL"; + "--no-sync", Arg.Clear sync, " " ^ s_"Do not fsync output file on exit"; ++ "--no-warn-if-partition", Arg.Clear warn_if_partition, ++ " " ^ s_"Do not warn if writing to a partition"; + ] in + let customize_argspec, get_customize_ops = Customize_cmdline.argspec () in + let customize_argspec = +@@ -212,6 +216,7 @@ read the man page virt-builder(1). + let smp = !smp in + let sources = List.rev !sources in + let sync = !sync in ++ let warn_if_partition = !warn_if_partition in + + (* No arguments and machine-readable mode? Print some facts. *) + if args = [] && machine_readable then ( +@@ -323,4 +328,5 @@ read the man page virt-builder(1). + gpg = gpg; list_format = list_format; memsize = memsize; + network = network; ops = ops; output = output; + size = size; smp = smp; sources = sources; sync = sync; ++ warn_if_partition = warn_if_partition; + } +diff --git a/builder/cmdline.mli b/builder/cmdline.mli +index 4c201dd..854db61 100644 +--- a/builder/cmdline.mli ++++ b/builder/cmdline.mli +@@ -39,6 +39,7 @@ type cmdline = { + smp : int option; + sources : (string * string) list; + sync : bool; ++ warn_if_partition : bool; + } + + val parse_cmdline : unit -> cmdline +diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod +index 545b134..94ba430 100644 +--- a/builder/virt-builder.pod ++++ b/builder/virt-builder.pod +@@ -495,6 +495,15 @@ Note that you should not point I<--source> to sources that you don't + trust (unless the source is signed by someone you do trust). See also + the I<--no-network> option. + ++=item B<--no-warn-if-partition> ++ ++Do not emit a warning if the output device is a partition. This ++warning avoids a common user error when writing to a USB key or ++external drive, when you should normally write to the whole device ++(S>), not to a partition on the device ++(S>). Use this option to I this ++warning. ++ + =item B<-v> + + =item B<--verbose> +-- +1.8.3.1 + diff --git a/SOURCES/0100-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch b/SOURCES/0100-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch deleted file mode 100644 index 2e43fb7..0000000 --- a/SOURCES/0100-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 04f1f9879843e6e3005cfe13805856621aca6bcd Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sun, 28 Sep 2014 19:14:43 +0100 -Subject: [PATCH] RHEL 7: v2v: Select correct qemu binary for -o qemu mode - (RHBZ#1147313). - -RHEL 7 does not have qemu-system-x86_64 (etc), and in addition the -qemu binary is located in /usr/libexec. Encode the path to this -binary directly in the script. - -Note that we don't support people running qemu directly like this. -It's just for quick testing of converted VMs, and to help us with -support cases. ---- - 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 75644c2..9c17121 100644 ---- a/v2v/output_qemu.ml -+++ b/v2v/output_qemu.ml -@@ -48,7 +48,7 @@ object - let nl = " \\\n\t" in - fpf "#!/bin/sh -\n"; - fpf "\n"; -- fpf "qemu-system-%s" guestcaps.gcaps_arch; -+ fpf "/usr/libexec/qemu-kvm"; - fpf "%s-no-user-config -nodefaults" nl; - fpf "%s-name %s" nl (quote source.s_name); - fpf "%s-machine accel=kvm:tcg" nl; --- -1.8.3.1 - diff --git a/SOURCES/0100-p2v-Add-XTerm-button-which-launches-a-terminal-windo.patch b/SOURCES/0100-p2v-Add-XTerm-button-which-launches-a-terminal-windo.patch new file mode 100644 index 0000000..df53afd --- /dev/null +++ b/SOURCES/0100-p2v-Add-XTerm-button-which-launches-a-terminal-windo.patch @@ -0,0 +1,81 @@ +From a364cdd1d65a11f7672c22ae9d2d7ef553327d7c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 3 Jun 2016 10:29:46 +0100 +Subject: [PATCH] p2v: Add "XTerm" button which launches a terminal window. + +(cherry picked from commit bf434bdb3523b7629d50144f35a6bccc05bf94e6) +--- + p2v/gui.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 015fa21..b8d61b5 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -95,6 +95,7 @@ gui_conversion (struct config *config) + static void test_connection_clicked (GtkWidget *w, gpointer data); + static void *test_connection_thread (void *data); + static void configure_network_button_clicked (GtkWidget *w, gpointer data); ++static void xterm_button_clicked (GtkWidget *w, gpointer data); + static void about_button_clicked (GtkWidget *w, gpointer data); + static void connection_next_clicked (GtkWidget *w, gpointer data); + static void repopulate_output_combo (struct config *config); +@@ -112,6 +113,7 @@ create_connection_dialog (struct config *config) + GtkWidget *test_hbox, *test; + GtkWidget *about; + GtkWidget *configure_network; ++ GtkWidget *xterm; + char port_str[64]; + + conn_dlg = gtk_dialog_new (); +@@ -220,16 +222,18 @@ create_connection_dialog (struct config *config) + /* Buttons. */ + gtk_dialog_add_buttons (GTK_DIALOG (conn_dlg), + _("Configure network ..."), 1, +- _("About virt-p2v " PACKAGE_VERSION " ..."), 2, +- _("Next"), 3, ++ _("XTerm ..."), 2, ++ _("About virt-p2v " PACKAGE_VERSION " ..."), 3, ++ _("Next"), 4, + NULL); + +- next_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (conn_dlg), 3); ++ next_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (conn_dlg), 4); + gtk_widget_set_sensitive (next_button, FALSE); + + configure_network = + gtk_dialog_get_widget_for_response (GTK_DIALOG (conn_dlg), 1); +- about = gtk_dialog_get_widget_for_response (GTK_DIALOG (conn_dlg), 2); ++ xterm = gtk_dialog_get_widget_for_response (GTK_DIALOG (conn_dlg), 2); ++ about = gtk_dialog_get_widget_for_response (GTK_DIALOG (conn_dlg), 3); + + /* Signals. */ + g_signal_connect_swapped (G_OBJECT (conn_dlg), "destroy", +@@ -238,6 +242,8 @@ create_connection_dialog (struct config *config) + G_CALLBACK (test_connection_clicked), config); + g_signal_connect (G_OBJECT (configure_network), "clicked", + G_CALLBACK (configure_network_button_clicked), NULL); ++ g_signal_connect (G_OBJECT (xterm), "clicked", ++ G_CALLBACK (xterm_button_clicked), NULL); + g_signal_connect (G_OBJECT (about), "clicked", + G_CALLBACK (about_button_clicked), NULL); + g_signal_connect (G_OBJECT (next_button), "clicked", +@@ -387,6 +393,15 @@ configure_network_button_clicked (GtkWidget *w, gpointer data) + ignore_value (system ("nm-connection-editor &")); + } + ++/** ++ * Callback from the C button. ++ */ ++static void ++xterm_button_clicked (GtkWidget *w, gpointer data) ++{ ++ ignore_value (system ("xterm &")); ++} ++ + static void + about_button_clicked (GtkWidget *w, gpointer data) + { +-- +1.8.3.1 + diff --git a/SOURCES/0101-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch b/SOURCES/0101-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch deleted file mode 100644 index 9e7f474..0000000 --- a/SOURCES/0101-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch +++ /dev/null @@ -1,78 +0,0 @@ -From c8eca5fd761f8eb7822ccb765d3e9138d9bcb738 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 30 Sep 2014 10:50:27 +0100 -Subject: [PATCH] RHEL 7: v2v: Disable the --qemu-boot option (RHBZ#1147313). - -This cannot work because there is no Gtk or SDL output mode -in RHEL 7's qemu-kvm. - -In addition you will have to edit the -display option in the -qemu script. ---- - v2v/cmdline.ml | 4 +++- - v2v/virt-v2v.pod | 13 ------------- - 2 files changed, 3 insertions(+), 14 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 01f3335..14c3fb9 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -168,7 +168,7 @@ let parse_cmdline () = - "-os", Arg.Set_string output_storage, "storage " ^ s_"Set output storage location"; - "--password-file", Arg.Set_string password_file, "file " ^ s_"Use password from file"; - "--print-source", Arg.Set print_source, " " ^ s_"Print source and stop"; -- "--qemu-boot", Arg.Set qemu_boot, " " ^ s_"Boot in qemu (-o qemu only)"; -+ "--qemu-boot", Arg.Set qemu_boot, " " ^ s_"This option cannot be used in RHEL"; - "-q", Arg.Set quiet, " " ^ s_"Quiet output"; - "--quiet", Arg.Set quiet, ditto; - "--root", Arg.String set_root_choice,"ask|... " ^ s_"How to choose root filesystem"; -@@ -364,6 +364,8 @@ read the man page virt-v2v(1). - if not (is_directory output_storage) then - error (f_"-os %s: output directory does not exist or is not a directory") - output_storage; -+ if qemu_boot then -+ error (f_"-o qemu: the --qemu-boot option cannot be used in RHEL"); - Output_qemu.output_qemu verbose output_storage qemu_boot - - | `RHEV -> -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 5f4d42e..9edb2ca 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -139,11 +139,6 @@ Since C contains the path(s) to the guest disk - image(s) you do not need to specify the name of the disk image on the - command line. - --To convert a local disk image and immediately boot it in local --qemu, do: -- -- virt-v2v -i disk disk.img -o qemu -os /var/tmp --qemu-boot -- - =head1 OPTIONS - - =over 4 -@@ -350,9 +345,6 @@ This is similar to I<-o local>, except that a shell script is written - which you can use to boot the guest in qemu. The converted disks and - shell script are written to the directory specified by I<-os>. - --When using this output mode, you can also specify the I<--qemu-boot> --option which boots the guest under qemu immediately. -- - =item B<-o rhev> - - Set the output method to I. -@@ -436,11 +428,6 @@ Print information about the source guest and stop. This option is - useful when you are setting up network and bridge maps. - See L. - --=item B<--qemu-boot> -- --When using I<-o qemu> only, this boots the guest immediately after --virt-v2v finishes. -- - =item B<-q> - - =item B<--quiet> --- -1.8.3.1 - diff --git a/SOURCES/0101-p2v-Place-conversion-server-name-and-port-side-by-si.patch b/SOURCES/0101-p2v-Place-conversion-server-name-and-port-side-by-si.patch new file mode 100644 index 0000000..f517476 --- /dev/null +++ b/SOURCES/0101-p2v-Place-conversion-server-name-and-port-side-by-si.patch @@ -0,0 +1,138 @@ +From b8e5dd108de16061210a965d84a83909b97fd472 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 3 Jun 2016 11:10:20 +0100 +Subject: [PATCH] p2v: Place conversion server name and port side by side. + +Just a small rearrangement of the UI. + +(cherry picked from commit 9f3b6aa6e207b22792973577d7c6b21e6166b77e) +--- + p2v/gui.c | 37 ++++++++++++++++++------------------- + p2v/virt-p2v.pod | 4 +--- + 2 files changed, 19 insertions(+), 22 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index b8d61b5..832d72a 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -105,7 +105,8 @@ create_connection_dialog (struct config *config) + { + GtkWidget *intro, *table; + GtkWidget *server_label; +- GtkWidget *port_label; ++ GtkWidget *server_hbox; ++ GtkWidget *port_colon_label; + GtkWidget *username_label; + GtkWidget *password_label; + GtkWidget *identity_label; +@@ -125,44 +126,42 @@ create_connection_dialog (struct config *config) + gtk_label_set_line_wrap (GTK_LABEL (intro), TRUE); + gtk_misc_set_padding (GTK_MISC (intro), 10, 10); + +- table = gtk_table_new (7, 2, FALSE); ++ table = gtk_table_new (6, 2, FALSE); + server_label = gtk_label_new (_("Conversion server:")); + gtk_misc_set_alignment (GTK_MISC (server_label), 1., 0.5); + gtk_table_attach (GTK_TABLE (table), server_label, + 0, 1, 0, 1, GTK_FILL, GTK_FILL, 4, 4); ++ server_hbox = gtk_hbox_new (FALSE, 4); + server_entry = gtk_entry_new (); + if (config->server != NULL) + gtk_entry_set_text (GTK_ENTRY (server_entry), config->server); +- gtk_table_attach (GTK_TABLE (table), server_entry, +- 1, 2, 0, 1, GTK_FILL, GTK_FILL, 4, 4); +- +- port_label = gtk_label_new (_("SSH port:")); +- gtk_misc_set_alignment (GTK_MISC (port_label), 1., 0.5); +- gtk_table_attach (GTK_TABLE (table), port_label, +- 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 4); ++ port_colon_label = gtk_label_new (":"); + port_entry = gtk_entry_new (); + gtk_entry_set_width_chars (GTK_ENTRY (port_entry), 6); + snprintf (port_str, sizeof port_str, "%d", config->port); + gtk_entry_set_text (GTK_ENTRY (port_entry), port_str); +- gtk_table_attach (GTK_TABLE (table), port_entry, +- 1, 2, 1, 2, GTK_FILL, GTK_FILL, 4, 4); ++ gtk_box_pack_start (GTK_BOX (server_hbox), server_entry, TRUE, TRUE, 0); ++ gtk_box_pack_start (GTK_BOX (server_hbox), port_colon_label, FALSE, FALSE, 0); ++ gtk_box_pack_start (GTK_BOX (server_hbox), port_entry, FALSE, FALSE, 0); ++ gtk_table_attach (GTK_TABLE (table), server_hbox, ++ 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); + + username_label = gtk_label_new (_("User name:")); + gtk_misc_set_alignment (GTK_MISC (username_label), 1., 0.5); + gtk_table_attach (GTK_TABLE (table), username_label, +- 0, 1, 2, 3, GTK_FILL, GTK_FILL, 4, 4); ++ 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 4); + username_entry = gtk_entry_new (); + if (config->username != NULL) + gtk_entry_set_text (GTK_ENTRY (username_entry), config->username); + else + gtk_entry_set_text (GTK_ENTRY (username_entry), "root"); + gtk_table_attach (GTK_TABLE (table), username_entry, +- 1, 2, 2, 3, GTK_FILL, GTK_FILL, 4, 4); ++ 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); + + password_label = gtk_label_new (_("Password:")); + gtk_misc_set_alignment (GTK_MISC (password_label), 1., 0.5); + gtk_table_attach (GTK_TABLE (table), password_label, +- 0, 1, 3, 4, GTK_FILL, GTK_FILL, 4, 4); ++ 0, 1, 2, 3, GTK_FILL, GTK_FILL, 4, 4); + password_entry = gtk_entry_new (); + gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE); + #ifdef GTK_INPUT_PURPOSE_PASSWORD +@@ -172,31 +171,31 @@ create_connection_dialog (struct config *config) + if (config->password != NULL) + gtk_entry_set_text (GTK_ENTRY (password_entry), config->password); + gtk_table_attach (GTK_TABLE (table), password_entry, +- 1, 2, 3, 4, GTK_FILL, GTK_FILL, 4, 4); ++ 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); + + identity_label = gtk_label_new (_("SSH Identity URL:")); + gtk_misc_set_alignment (GTK_MISC (identity_label), 1., 0.5); + gtk_table_attach (GTK_TABLE (table), identity_label, +- 0, 1, 4, 5, GTK_FILL, GTK_FILL, 4, 4); ++ 0, 1, 3, 4, GTK_FILL, GTK_FILL, 4, 4); + identity_entry = gtk_entry_new (); + if (config->identity_url != NULL) + gtk_entry_set_text (GTK_ENTRY (identity_entry), config->identity_url); + gtk_table_attach (GTK_TABLE (table), identity_entry, +- 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4); ++ 1, 2, 3, 4, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); + + identity_tip_label = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL (identity_tip_label), + _("If using password authentication, leave the SSH Identity URL blank")); + gtk_label_set_line_wrap (GTK_LABEL (identity_tip_label), TRUE); + gtk_table_attach (GTK_TABLE (table), identity_tip_label, +- 1, 2, 5, 6, GTK_FILL, GTK_FILL, 4, 4); ++ 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4); + + sudo_button = + gtk_check_button_new_with_label (_("Use sudo when running virt-v2v")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sudo_button), + config->sudo); + gtk_table_attach (GTK_TABLE (table), sudo_button, +- 1, 2, 6, 7, GTK_FILL, GTK_FILL, 4, 4); ++ 1, 2, 5, 6, GTK_FILL, GTK_FILL, 4, 4); + + test_hbox = gtk_hbox_new (FALSE, 0); + test = gtk_button_new_with_label (_("Test connection")); +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index 3e4ef99..5ceafa7 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -81,9 +81,7 @@ When virt-p2v starts up in GUI mode, the first dialog looks like this: + ┌────────────────────────────────────────────────────────┐ + │ virt-p2v │ + │ │ +- │ Conversion server: [_________________________________] │ +- │ │ +- │ SSH port: [22_______________________________] │ ++ │ Conversion server: [_______________________] : [22___] │ + │ │ + │ User name: [root_____________________________] │ + │ │ +-- +1.8.3.1 + diff --git a/SOURCES/0102-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch b/SOURCES/0102-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch deleted file mode 100644 index 489126a..0000000 --- a/SOURCES/0102-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch +++ /dev/null @@ -1,74 +0,0 @@ -From dd3263f82d6ee73808c31896136b795643cd24c4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 2 Oct 2014 16:44:00 +0100 -Subject: [PATCH] RHEL 7: Revert "tests: rsync: Skip this test when the backend - is libvirt." - -This reverts commit 765dc6237ce7b93dd2f33d99be53eae92e048a7a. ---- - tests/rsync/test-rsync.sh | 35 +++++++---------------------------- - 1 file changed, 7 insertions(+), 28 deletions(-) - -diff --git a/tests/rsync/test-rsync.sh b/tests/rsync/test-rsync.sh -index 53fcab8..793d59d 100755 ---- a/tests/rsync/test-rsync.sh -+++ b/tests/rsync/test-rsync.sh -@@ -33,33 +33,10 @@ if ! rsync --help >/dev/null 2>&1; then - exit 77 - fi - --# Get host IP address. XXX Bit of a hack. --backend="$(guestfish get-backend)" --case "$backend" in -- direct) -- ip=169.254.2.2 -- listen_address=localhost -- ;; -- libvirt|libvirt:*) -- # This would work, except that the host firewall is effective -- # on virbr0, and that is likely to block the non-standard port -- # number that we listen on. --# ip="$(ip -4 -o address show virbr0 | --# awk '{print $4}' | --# awk -F/ '{print $1}')" --# listen_address="$ip" -- echo "$0: skipping test because host firewall will probably prevent this test from working" -- exit 77 -- ;; -- uml) -- echo "$0: skipping test because networking is not available in the UML backend" -- exit 77 -- ;; -- *) -- echo "$0: don't know how to get IP address of backend $backend" -- exit 77 -- ;; --esac -+if [ "$(guestfish get-backend)" = "uml" ]; then -+ echo "$0: skipping test because networking is not available in the UML backend" -+ exit 77 -+fi - - # If rsync is not available, bail. - if ! guestfish -a /dev/null run : available rsync; then -@@ -79,7 +56,7 @@ port="$(awk 'BEGIN{srand(); print 65000+int(500*rand())}' rsyncd.conf < +Date: Fri, 3 Jun 2016 14:21:59 +0100 +Subject: [PATCH] mllib: Fix other places where Dev_t module must be linked to + Common_utils. + +Fixes commit df7a33768eab2381b958ede2c8a40bc9cbc87928. + +(cherry picked from commit c97ca67a5c000dac24fdd3f3f749e77501eecd3f) +--- + mllib/Makefile.am | 9 ++++++++- + v2v/test-harness/Makefile.am | 2 ++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/mllib/Makefile.am b/mllib/Makefile.am +index e44abed..e0f1987 100644 +--- a/mllib/Makefile.am ++++ b/mllib/Makefile.am +@@ -136,10 +136,17 @@ libdir.ml: Makefile + + # Tests. + +-common_utils_tests_SOURCES = dummy.c ++common_utils_tests_SOURCES = \ ++ dev_t-c.c \ ++ dummy.c ++common_utils_tests_CPPFLAGS = \ ++ -I. \ ++ -I$(top_builddir) \ ++ -I$(shell $(OCAMLC) -where) + common_utils_tests_BOBJECTS = \ + guestfs_config.cmo \ + common_gettext.cmo \ ++ dev_t.cmo \ + common_utils.cmo \ + common_utils_tests.cmo + common_utils_tests_XOBJECTS = $(common_utils_tests_BOBJECTS:.cmo=.cmx) +diff --git a/v2v/test-harness/Makefile.am b/v2v/test-harness/Makefile.am +index a3c980a..cba5b41 100644 +--- a/v2v/test-harness/Makefile.am ++++ b/v2v/test-harness/Makefile.am +@@ -60,6 +60,7 @@ OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) + BOBJECTS = \ + $(top_builddir)/mllib/guestfs_config.cmo \ + $(top_builddir)/mllib/common_gettext.cmo \ ++ $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/v2v/xml.cmo \ + $(SOURCES_ML:.ml=.cmo) \ +@@ -94,6 +95,7 @@ libv2vth_a_CFLAGS = \ + -fPIC + + libv2vth_a_SOURCES = \ ++ ../../mllib/dev_t-c.c \ + ../xml-c.c + + v2v_test_harness.cmi: $(top_builddir)/ocaml/guestfs.cmi +-- +1.8.3.1 + diff --git a/SOURCES/0103-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch b/SOURCES/0103-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch deleted file mode 100644 index b398375..0000000 --- a/SOURCES/0103-RHEL-7-Revert-appliance-Change-example-ping-lines-to.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 2bbaa881d67ddaafb7c111ef8ad1f93c9879c52d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 2 Oct 2014 16:44:04 +0100 -Subject: [PATCH] RHEL 7: Revert "appliance: Change example ping lines to ping - 8.8.8.8." - -This reverts commit 07c0926b588db5c86214917b609c2f477c817c0e. ---- - appliance/init | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/appliance/init b/appliance/init -index 3d704ba..f719a72 100755 ---- a/appliance/init -+++ b/appliance/init -@@ -114,7 +114,8 @@ if grep -sq guestfs_verbose=1 /proc/cmdline; then - date - echo -n "clocksource: " - cat /sys/devices/system/clocksource/clocksource0/current_clocksource -- #ping -n -v -c 5 8.8.8.8 -+ #ping -n -v -c 5 10.0.2.2 -+ #ping -n -v -c 5 10.0.2.4 - - echo -n "uptime: "; cat /proc/uptime - fi --- -1.8.3.1 - diff --git a/SOURCES/0103-p2v-Add-more-authors-who-have-worked-on-virt-v2v-and.patch b/SOURCES/0103-p2v-Add-more-authors-who-have-worked-on-virt-v2v-and.patch new file mode 100644 index 0000000..be701fc --- /dev/null +++ b/SOURCES/0103-p2v-Add-more-authors-who-have-worked-on-virt-v2v-and.patch @@ -0,0 +1,46 @@ +From 305f1ed089bdf8eda3fa0020397bd50e9a7adf3d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 4 Jun 2016 14:46:20 +0100 +Subject: [PATCH] p2v: Add more authors who have worked on virt-v2v and + virt-p2v. + +Use this command as a starting point: + + git shortlog -s -- p2v v2v | awk -F'\t' '{print $2}' | sort -f + +However note the above will include people who made only incidental +code changes, and also misses out QA team members, so the actual list +still has to be curated by hand. + +(cherry picked from commit 3a231afcfa295489fc07cafb60108e0d05ecf4bb) +--- + p2v/about-authors.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/p2v/about-authors.c b/p2v/about-authors.c +index c6a4235..88f48f9 100644 +--- a/p2v/about-authors.c ++++ b/p2v/about-authors.c +@@ -20,12 +20,18 @@ + + #include "p2v.h" + +-/* The list of authors of virt-p2v and virt-v2v, for the About dialog. */ ++/* The list of authors of virt-p2v and virt-v2v, for the About dialog. ++ * ++ * Note: In alphabetical order of surname / family name. ++ */ + + const char *authors[] = { + "Matthew Booth", ++ "Cédric Bosdonnat", + "John Eckersberg", + "Richard W.M. Jones", ++ "Shahar Havivi", ++ "Roman Kagan", + "Mike Latimer", + "Pino Toscano", + "Ming Xie", +-- +1.8.3.1 + diff --git a/SOURCES/0104-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch b/SOURCES/0104-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch deleted file mode 100644 index 74c059d..0000000 --- a/SOURCES/0104-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 2392578b6774594eb33188606fd64c415055be63 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 2 Oct 2014 16:44:07 +0100 -Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Use qemu-bridge-helper to - implement a full network (RHBZ#1148012)." - -This reverts commit 224de20b9a8d5ea56f6337f19b4ca237bb88eca0. ---- - src/guestfs.pod | 10 ---------- - src/launch-libvirt.c | 44 +++++++++++++++++++++----------------------- - 2 files changed, 21 insertions(+), 33 deletions(-) - -diff --git a/src/guestfs.pod b/src/guestfs.pod -index 3c1ad46..81347f3 100644 ---- a/src/guestfs.pod -+++ b/src/guestfs.pod -@@ -1419,16 +1419,6 @@ On Fedora, install C for the C file - (containing symbols). Make sure the symbols precisely match the - kernel being used. - --=head3 network_bridge -- --The libvirt backend supports: -- -- export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=virbrX -- --This allows you to override the bridge that is connected to when the --network is enabled. The default is C. See also --L. -- - =head2 ATTACHING TO RUNNING DAEMONS - - I This is B and has a tendency to eat -diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c -index 79bc6fd..026fd5a 100644 ---- a/src/launch-libvirt.c -+++ b/src/launch-libvirt.c -@@ -105,7 +105,6 @@ struct backend_libvirt_data { - char *selinux_label; - char *selinux_imagelabel; - bool selinux_norelabel_disks; -- char *network_bridge; - char name[DOMAIN_NAME_LEN]; /* random name */ - bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/ - unsigned long qemu_version; /* qemu version (from libvirt) */ -@@ -332,12 +331,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___get_backend_setting_bool (g, "internal_libvirt_norelabel_disks"); -- if (g->enable_network) { -- data->network_bridge = -- guestfs_get_backend_setting (g, "network_bridge"); -- if (!data->network_bridge) -- data->network_bridge = safe_strdup (g, "virbr0"); -- } - guestfs_pop_error_handler (g); - - /* Locate and/or build the appliance. */ -@@ -1267,19 +1260,6 @@ construct_libvirt_xml_devices (guestfs_h *g, - } end_element (); - } end_element (); - -- /* Connect to libvirt bridge (see: RHBZ#1148012). */ -- if (g->enable_network) { -- start_element ("interface") { -- attribute ("type", "bridge"); -- start_element ("source") { -- attribute ("bridge", params->data->network_bridge); -- } end_element (); -- start_element ("model") { -- attribute ("type", "virtio"); -- } end_element (); -- } end_element (); -- } -- - } end_element (); /* */ - - return 0; -@@ -1661,6 +1641,27 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, - attribute ("value", tmpdir); - } end_element (); - -+ /* Workaround because libvirt user networking cannot specify "net=" -+ * parameter. -+ */ -+ if (g->enable_network) { -+ start_element ("qemu:arg") { -+ attribute ("value", "-netdev"); -+ } end_element (); -+ -+ start_element ("qemu:arg") { -+ attribute ("value", "user,id=usernet,net=169.254.0.0/16"); -+ } end_element (); -+ -+ start_element ("qemu:arg") { -+ attribute ("value", "-device"); -+ } end_element (); -+ -+ start_element ("qemu:arg") { -+ attribute ("value", VIRTIO_NET ",netdev=usernet"); -+ } end_element (); -+ } -+ - /* The qemu command line arguments requested by the caller. */ - for (hp = g->hv_params; hp; hp = hp->next) { - start_element ("qemu:arg") { -@@ -1745,9 +1746,6 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) - free (data->selinux_imagelabel); - data->selinux_imagelabel = NULL; - -- free (data->network_bridge); -- data->network_bridge = NULL; -- - free (data->uefi_code); - data->uefi_code = NULL; - free (data->uefi_vars); --- -1.8.3.1 - diff --git a/SOURCES/0104-customize-Add-uninstall-operation-RHBZ-1343375.patch b/SOURCES/0104-customize-Add-uninstall-operation-RHBZ-1343375.patch new file mode 100644 index 0000000..9308f80 --- /dev/null +++ b/SOURCES/0104-customize-Add-uninstall-operation-RHBZ-1343375.patch @@ -0,0 +1,103 @@ +From a99e410a2dc450569bc3218005fbc38e60e2d4af Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Jun 2016 10:24:54 +0100 +Subject: [PATCH] customize: Add --uninstall operation (RHBZ#1343375). + +(cherry picked from commit 6425a8824b13a60ddf5d04270808da00568b1b53) +--- + customize/customize_run.ml | 29 +++++++++++++++++++++++++++++ + generator/customize.ml | 17 +++++++++++++++-- + 2 files changed, 44 insertions(+), 2 deletions(-) + +diff --git a/customize/customize_run.ml b/customize/customize_run.ml +index 8c38d62..10647fd 100644 +--- a/customize/customize_run.ml ++++ b/customize/customize_run.ml +@@ -154,6 +154,30 @@ exec >>%s 2>&1 + | pm -> + error_unimplemented_package_manager (s_"--update") pm + ++ and guest_uninstall_command packages = ++ let quoted_args = String.concat " " (List.map quote packages) in ++ match g#inspect_get_package_management root with ++ | "apk" -> sprintf "apk del %s" quoted_args ++ | "apt" -> ++ (* http://unix.stackexchange.com/questions/22820 *) ++ sprintf " ++ export DEBIAN_FRONTEND=noninteractive ++ apt_opts='-q -y -o Dpkg::Options::=--force-confnew' ++ apt-get $apt_opts remove %s ++ " quoted_args ++ | "dnf" -> sprintf "dnf -y remove %s" quoted_args ++ | "pisi" -> sprintf "pisi rm %s" quoted_args ++ | "pacman" -> sprintf "pacman -R %s" quoted_args ++ | "urpmi" -> sprintf "urpme %s" quoted_args ++ | "xbps" -> sprintf "xbps-remove -Sy %s" quoted_args ++ | "yum" -> sprintf "yum -y remove %s" quoted_args ++ | "zypper" -> sprintf "zypper -n rm -l %s" quoted_args ++ ++ | "unknown" -> ++ error_unknown_package_manager (s_"--uninstall") ++ | pm -> ++ error_unimplemented_package_manager (s_"--uninstall") pm ++ + (* Windows has package_management == "unknown". *) + and error_unknown_package_manager flag = + error (f_"cannot use '%s' because no package manager has been detected for this guest OS.\n\nIf this guest OS is a common one with ordinary package management then this may have been caused by a failure of libguestfs inspection.\n\nFor OSes such as Windows that lack package management, this is not possible. Try using one of the '--firstboot*' flags instead (described in the manual).") flag +@@ -334,6 +358,11 @@ exec >>%s 2>&1 + message (f_"Running touch: %s") path; + g#touch path + ++ | `UninstallPackages pkgs -> ++ message (f_"Uninstalling packages: %s") (String.concat " " pkgs); ++ let cmd = guest_uninstall_command pkgs in ++ do_run ~display:cmd cmd ++ + | `Update -> + message (f_"Updating packages"); + let cmd = guest_update_command () in +diff --git a/generator/customize.ml b/generator/customize.ml +index 403bb89..8caf2b5 100644 +--- a/generator/customize.ml ++++ b/generator/customize.ml +@@ -214,7 +214,7 @@ installed during the image build using the guest's package manager + For an overview on the different ways to install packages, see + L. + +-See also I<--update>."; ++See also I<--update>, I<--uninstall>."; + }; + + { op_name = "link"; +@@ -424,6 +424,19 @@ string like C"; + This command performs a L-like operation on C."; + }; + ++ { op_name = "uninstall"; ++ op_type = StringList "PKG,PKG.."; ++ op_discrim = "`UninstallPackages"; ++ op_shortdesc = "Uninstall package(s)"; ++ op_pod_longdesc = "\ ++Uninstall the named packages (a comma-separated list). These are ++removed during the image build using the guest's package manager ++(eg. apt, yum, etc.). Dependent packages may also need to be ++uninstalled to satisfy the request. ++ ++See also I<--install>, I<--update>."; ++ }; ++ + { op_name = "update"; + op_type = Unit; + op_discrim = "`Update"; +@@ -433,7 +446,7 @@ Do the equivalent of C, C, or whatever + command is required to update the packages already installed in the + template to their latest versions. + +-See also I<--install>."; ++See also I<--install>, I<--uninstall>."; + }; + + { op_name = "upload"; +-- +1.8.3.1 + diff --git a/SOURCES/0105-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch b/SOURCES/0105-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch deleted file mode 100644 index a19ac90..0000000 --- a/SOURCES/0105-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 774e8f155f7f9dc369e3fd0e1838a1f309cda235 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 10 Oct 2014 17:45:39 +0100 -Subject: [PATCH] RHEL 7: Revert "appliance: add dhcp-client on Mageia" - -This reverts commit 8f3a2ca5358d5601be7a9247b6d08193c4e2da46. ---- - appliance/packagelist.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/appliance/packagelist.in b/appliance/packagelist.in -index e546eb3..a60e532 100644 ---- a/appliance/packagelist.in -+++ b/appliance/packagelist.in -@@ -183,7 +183,7 @@ ifelse(MAGEIA,1, - chkconfig /* for /etc/init.d */ - cdrkit-genisoimage - cdrkit-isotools -- dhcp-client -+ dhclient - extlinux - gfs2-utils - grub --- -1.8.3.1 - diff --git a/SOURCES/0105-p2v-Print-full-curl-error-when-failing-to-fetch-SSH-.patch b/SOURCES/0105-p2v-Print-full-curl-error-when-failing-to-fetch-SSH-.patch new file mode 100644 index 0000000..26fae55 --- /dev/null +++ b/SOURCES/0105-p2v-Print-full-curl-error-when-failing-to-fetch-SSH-.patch @@ -0,0 +1,81 @@ +From 6440601758720bd1390e768a8f26f313d7bb4ca9 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Jun 2016 14:50:47 +0100 +Subject: [PATCH] p2v: Print full curl error when failing to fetch SSH identify + URL (RHBZ#1343423). + +(cherry picked from commit 0e0a350c02b9c4d7a4108d2743ee1a61ce88a1f1) +--- + p2v/ssh.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index c4d7e2e..ce2b17b 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -168,11 +169,18 @@ static int + curl_download (const char *url, const char *local_file) + { + char curl_config_file[] = "/tmp/curl.XXXXXX"; ++ char error_file[] = "/tmp/curlerr.XXXXXX"; ++ CLEANUP_FREE char *error_message = NULL; + int fd, r; + size_t i, len; + FILE *fp; + CLEANUP_FREE char *curl_cmd = NULL; + ++ fd = mkstemp (error_file); ++ if (fd == -1) ++ error (EXIT_FAILURE, errno, "mkstemp: %s", error_file); ++ close (fd); ++ + /* Use a secure curl config file because escaping is easier. */ + fd = mkstemp (curl_config_file); + if (fd == -1) { +@@ -201,8 +209,8 @@ curl_download (const char *url, const char *local_file) + fclose (fp); + + /* Run curl to download the URL to a file. */ +- if (asprintf (&curl_cmd, "curl -f -o %s -K %s", +- local_file, curl_config_file) == -1) { ++ if (asprintf (&curl_cmd, "curl -f -s -S -o %s -K %s 2>%s", ++ local_file, curl_config_file, error_file) == -1) { + perror ("asprintf"); + exit (EXIT_FAILURE); + } +@@ -216,17 +224,20 @@ curl_download (const char *url, const char *local_file) + + /* Did curl subprocess fail? */ + if (WIFEXITED (r) && WEXITSTATUS (r) != 0) { +- /* XXX Better error handling. The codes can be looked up in +- * the curl(1) man page. +- */ +- set_ssh_error ("%s: curl error %d", url, WEXITSTATUS (r)); ++ if (read_whole_file (error_file, &error_message, NULL) == 0) ++ set_ssh_error ("%s: %s", url, error_message); ++ else ++ set_ssh_error ("%s: curl error %d", url, WEXITSTATUS (r)); ++ unlink (error_file); + return -1; + } + else if (!WIFEXITED (r)) { + set_ssh_error ("curl subprocess got a signal (%d)", r); ++ unlink (error_file); + return -1; + } + ++ unlink (error_file); + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0106-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch b/SOURCES/0106-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch deleted file mode 100644 index e2317bf..0000000 --- a/SOURCES/0106-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 3abf69d23cd95082daedb7cb1a1c98049f310368 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 10 Oct 2014 17:45:48 +0100 -Subject: [PATCH] RHEL 7: Revert "appliance: add dhcpcd and gptfdisk on - Archlinux" - -This reverts commit 979e7a49147f4ef1387337db262bf7ea12f627e3. ---- - appliance/packagelist.in | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/appliance/packagelist.in b/appliance/packagelist.in -index a60e532..9032d7d 100644 ---- a/appliance/packagelist.in -+++ b/appliance/packagelist.in -@@ -104,8 +104,7 @@ ifelse(ARCHLINUX,1, - btrfs-progs - cdrkit - cryptsetup -- dhcpcd -- gptfdisk -+ dhclient - grub - hivex - iproute2 --- -1.8.3.1 - diff --git a/SOURCES/0106-mllib-Use-Unix.F_OK-instead-of-plain-F_OK.patch b/SOURCES/0106-mllib-Use-Unix.F_OK-instead-of-plain-F_OK.patch new file mode 100644 index 0000000..4401fd7 --- /dev/null +++ b/SOURCES/0106-mllib-Use-Unix.F_OK-instead-of-plain-F_OK.patch @@ -0,0 +1,33 @@ +From 4e0b14a89cceb48b8ed1c63bcceb6a2c48dec167 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 14 Jun 2016 18:54:44 +0100 +Subject: [PATCH] mllib: Use Unix.F_OK instead of plain F_OK. + +Removes this warning: + + File "common_utils.ml", line 826, characters 24-28: + Warning 40: F_OK was selected from type Unix.access_permission. + It is not visible in the current scope, and will not + be selected if the type becomes unknown. + +(cherry picked from commit 2ecdc46114f564a42f8d6c51c2c2763ba3dda15e) +--- + mllib/common_utils.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml +index c29dfa0..be8810a 100644 +--- a/mllib/common_utils.ml ++++ b/mllib/common_utils.ml +@@ -827,7 +827,7 @@ let is_partition dev = + let major = Dev_t.major rdev in + let minor = Dev_t.minor rdev in + let path = sprintf "/sys/dev/block/%d:%d/partition" major minor in +- Unix.access path [F_OK]; ++ Unix.access path [Unix.F_OK]; + true + ) + with Unix.Unix_error _ -> false +-- +1.8.3.1 + diff --git a/SOURCES/0107-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch b/SOURCES/0107-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch deleted file mode 100644 index 0ad308e..0000000 --- a/SOURCES/0107-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 8b61f836790e57690852b41bdc0856df42a58867 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 10 Oct 2014 17:46:02 +0100 -Subject: [PATCH] RHEL 7: Revert "appliance: Use dhclient or dhcpcd instead of - hard-coding IP address of appliance." - -This reverts commit 67e6f32a240c7c234e6af637c1cd324b36a82cd3. ---- - appliance/init | 13 ++++++------- - appliance/packagelist.in | 6 ------ - 2 files changed, 6 insertions(+), 13 deletions(-) - -diff --git a/appliance/init b/appliance/init -index f719a72..6d62338 100755 ---- a/appliance/init -+++ b/appliance/init -@@ -79,13 +79,12 @@ hwclock -u -s - ip addr add 127.0.0.1/8 brd + dev lo scope host - ip link set dev lo up - --if grep -sq guestfs_network=1 /proc/cmdline; then -- if dhclient --version >/dev/null 2>&1; then -- dhclient -- else -- dhcpcd -- fi --fi -+ip addr add 169.254.2.10/16 brd + dev eth0 scope global -+ip link set dev eth0 up -+ -+ip route add default via 169.254.2.2 -+ -+echo nameserver 169.254.2.3 > /etc/resolv.conf - - # Scan for MDs. - mdadm -As --auto=yes --run -diff --git a/appliance/packagelist.in b/appliance/packagelist.in -index 9032d7d..8fb6eca 100644 ---- a/appliance/packagelist.in -+++ b/appliance/packagelist.in -@@ -27,7 +27,6 @@ ifelse(REDHAT,1, - btrfs-progs - cryptsetup - cryptsetup-luks dnl old name used before Fedora 17 -- dhclient - dnl e4fsprogs only exists on RHEL 5, will be ignored everywhere else. - e4fsprogs - genisoimage -@@ -74,7 +73,6 @@ dnl iproute has been renamed to iproute2 - iputils-ping - iputils-arping - iputils-tracepath -- isc-dhcp-client - libaugeas0 - libc-bin - libcap2 -@@ -104,7 +102,6 @@ ifelse(ARCHLINUX,1, - btrfs-progs - cdrkit - cryptsetup -- dhclient - grub - hivex - iproute2 -@@ -133,7 +130,6 @@ ifelse(SUSE,1, - augeas-lenses - btrfsprogs - cryptsetup -- dhcpcd - genisoimage - glibc-locale - gptfdisk -@@ -154,7 +150,6 @@ ifelse(FRUGALWARE,1, - btrfs-progs - cryptsetup-luks - cdrkit -- dhclient - grub2 - hfsplus - iproute2 -@@ -182,7 +177,6 @@ ifelse(MAGEIA,1, - chkconfig /* for /etc/init.d */ - cdrkit-genisoimage - cdrkit-isotools -- dhclient - extlinux - gfs2-utils - grub --- -1.8.3.1 - diff --git a/SOURCES/0107-p2v-ssh-Print-ssh-error-if-user-gives-invalid-conver.patch b/SOURCES/0107-p2v-ssh-Print-ssh-error-if-user-gives-invalid-conver.patch new file mode 100644 index 0000000..c501800 --- /dev/null +++ b/SOURCES/0107-p2v-ssh-Print-ssh-error-if-user-gives-invalid-conver.patch @@ -0,0 +1,87 @@ +From e65b2e73ff4f3c6bf692d12c34a0188aa51b552b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 16 Jun 2016 21:22:16 +0100 +Subject: [PATCH] p2v: ssh: Print ssh error if user gives invalid conversion + server (RHBZ#1167916). + +Instead of throwing away the ssh error and printing the generic +message "unexpected end of file waiting for password prompt", we +capture the ssh error and print it. The user will see the ssh +diagnostic, eg. "No route to host". + +(cherry picked from commit 8717a110120f84973f1148adf48e59222cf45e73) +--- + p2v/ssh.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index ce2b17b..d9210f3 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -97,6 +97,7 @@ static void compile_regexps (void) __attribute__((constructor)); + static void free_regexps (void) __attribute__((destructor)); + + static pcre *password_re; ++static pcre *ssh_message_re; + static pcre *prompt_re; + static pcre *version_re; + static pcre *feature_libguestfs_rewrite_re; +@@ -138,6 +139,7 @@ compile_regexps (void) + } while (0) + + COMPILE (password_re, "password:", 0); ++ COMPILE (ssh_message_re, "(ssh: .*)", 0); + /* The magic synchronization strings all match this expression. See + * start_ssh function below. + */ +@@ -156,6 +158,7 @@ static void + free_regexps (void) + { + pcre_free (password_re); ++ pcre_free (ssh_message_re); + pcre_free (prompt_re); + pcre_free (version_re); + pcre_free (feature_libguestfs_rewrite_re); +@@ -350,10 +353,14 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + + if (using_password_auth && + config->password && strlen (config->password) > 0) { ++ CLEANUP_FREE char *ssh_message = NULL; ++ + /* Wait for the password prompt. */ ++ wait_password_again: + switch (mexp_expect (h, + (mexp_regexp[]) { + { 100, .re = password_re }, ++ { 101, .re = ssh_message_re }, + { 0 } + }, ovector, ovecsize)) { + case 100: /* Got password prompt. */ +@@ -364,9 +371,23 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + } + break; + ++ case 101: ++ free (ssh_message); ++ ssh_message = strndup (&h->buffer[ovector[2]], ovector[3]-ovector[2]); ++ goto wait_password_again; ++ + case MEXP_EOF: + mexp_close (h); +- set_ssh_error ("unexpected end of file waiting for password prompt"); ++ /* This is where we get to if the user enters an incorrect or ++ * impossible hostname or port number. Hopefully ssh printed an ++ * error message, and we picked it up and put it in ++ * 'ssh_message' in case 101 above. If not we have to print a ++ * generic error instead. ++ */ ++ if (ssh_message) ++ set_ssh_error ("%s", ssh_message); ++ else ++ set_ssh_error ("unknown ssh error"); + return NULL; + + case MEXP_TIMEOUT: +-- +1.8.3.1 + diff --git a/SOURCES/0108-RHEL-7-v2v-Disable-unconfiguration-of-VMware-drivers.patch b/SOURCES/0108-RHEL-7-v2v-Disable-unconfiguration-of-VMware-drivers.patch deleted file mode 100644 index c642f83..0000000 --- a/SOURCES/0108-RHEL-7-v2v-Disable-unconfiguration-of-VMware-drivers.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 67d28ac629e96912bb7152bbb172217d0f1c70c0 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 23 Oct 2014 08:41:56 +0100 -Subject: [PATCH] RHEL 7: v2v: Disable unconfiguration of VMware drivers on - Linux (RHBZ#1155610). - -This is currently broken and breaks conversions. For details see: -https://bugzilla.redhat.com/show_bug.cgi?id=1155610 ---- - v2v/convert_linux.ml | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 709b4b9..67de2b1 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -537,6 +537,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - msg - ) - -+(* Disabled in RHEL 7.1: see https://bugzilla.redhat.com/show_bug.cgi?id=1155610 - and unconfigure_vmware () = - (* Look for any configured VMware yum repos and disable them. *) - let repos = -@@ -627,6 +628,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - warning ~prog (f_"VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)") - msg - ) -+*) - - and unconfigure_citrix () = - let pkgs = -@@ -1417,7 +1419,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - - unconfigure_xen (); - unconfigure_vbox (); -- unconfigure_vmware (); -+ (*unconfigure_vmware ();*) - unconfigure_citrix (); - unconfigure_efi (); - unconfigure_kudzu (); --- -1.8.3.1 - diff --git a/SOURCES/0108-p2v-Don-t-allow-password-SSH-identity-URL-fields-to-.patch b/SOURCES/0108-p2v-Don-t-allow-password-SSH-identity-URL-fields-to-.patch new file mode 100644 index 0000000..5e754b1 --- /dev/null +++ b/SOURCES/0108-p2v-Don-t-allow-password-SSH-identity-URL-fields-to-.patch @@ -0,0 +1,109 @@ +From b07b91cdc973bcaa65e9df0fa0e304943dcaffa6 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 17 Jun 2016 21:32:33 +0100 +Subject: [PATCH] p2v: Don't allow password & SSH identity URL fields to both + be non-empty. + +It makes no sense. By setting one field to non-sensitive when the +other field is populated, we can avoid this happening, and also make +tabbing between the fields simpler. + +As a consequence of making this change, I also got rid of the now +unnecessary explanatory text telling you to leave one field blank. + +(cherry picked from commit b0d2d697e03a11642ab36f4a92b1f849085d2db9) +--- + p2v/gui.c | 44 ++++++++++++++++++++++++++++++++++---------- + 1 file changed, 34 insertions(+), 10 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 832d72a..dad8f6e 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -92,6 +92,7 @@ gui_conversion (struct config *config) + /*----------------------------------------------------------------------*/ + /* Connection dialog. */ + ++static void password_or_identity_changed_callback (GtkWidget *w, gpointer data); + static void test_connection_clicked (GtkWidget *w, gpointer data); + static void *test_connection_thread (void *data); + static void configure_network_button_clicked (GtkWidget *w, gpointer data); +@@ -110,7 +111,6 @@ create_connection_dialog (struct config *config) + GtkWidget *username_label; + GtkWidget *password_label; + GtkWidget *identity_label; +- GtkWidget *identity_tip_label; + GtkWidget *test_hbox, *test; + GtkWidget *about; + GtkWidget *configure_network; +@@ -126,7 +126,7 @@ create_connection_dialog (struct config *config) + gtk_label_set_line_wrap (GTK_LABEL (intro), TRUE); + gtk_misc_set_padding (GTK_MISC (intro), 10, 10); + +- table = gtk_table_new (6, 2, FALSE); ++ table = gtk_table_new (5, 2, FALSE); + server_label = gtk_label_new (_("Conversion server:")); + gtk_misc_set_alignment (GTK_MISC (server_label), 1., 0.5); + gtk_table_attach (GTK_TABLE (table), server_label, +@@ -183,19 +183,12 @@ create_connection_dialog (struct config *config) + gtk_table_attach (GTK_TABLE (table), identity_entry, + 1, 2, 3, 4, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); + +- identity_tip_label = gtk_label_new (NULL); +- gtk_label_set_markup (GTK_LABEL (identity_tip_label), +- _("If using password authentication, leave the SSH Identity URL blank")); +- gtk_label_set_line_wrap (GTK_LABEL (identity_tip_label), TRUE); +- gtk_table_attach (GTK_TABLE (table), identity_tip_label, +- 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4); +- + sudo_button = + gtk_check_button_new_with_label (_("Use sudo when running virt-v2v")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sudo_button), + config->sudo); + gtk_table_attach (GTK_TABLE (table), sudo_button, +- 1, 2, 5, 6, GTK_FILL, GTK_FILL, 4, 4); ++ 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4); + + test_hbox = gtk_hbox_new (FALSE, 0); + test = gtk_button_new_with_label (_("Test connection")); +@@ -247,6 +240,37 @@ create_connection_dialog (struct config *config) + G_CALLBACK (about_button_clicked), NULL); + g_signal_connect (G_OBJECT (next_button), "clicked", + G_CALLBACK (connection_next_clicked), NULL); ++ g_signal_connect (G_OBJECT (password_entry), "changed", ++ G_CALLBACK (password_or_identity_changed_callback), NULL); ++ g_signal_connect (G_OBJECT (identity_entry), "changed", ++ G_CALLBACK (password_or_identity_changed_callback), NULL); ++} ++ ++/** ++ * The password or SSH identity URL entries are mutually exclusive, so ++ * if one contains text then disable the other. This function is ++ * called when the "changed" signal is received on either. ++ */ ++static void ++password_or_identity_changed_callback (GtkWidget *w, gpointer data) ++{ ++ const char *str; ++ int password_set; ++ int identity_set; ++ ++ str = gtk_entry_get_text (GTK_ENTRY (password_entry)); ++ password_set = str != NULL && STRNEQ (str, ""); ++ str = gtk_entry_get_text (GTK_ENTRY (identity_entry)); ++ identity_set = str != NULL && STRNEQ (str, ""); ++ ++ if (!password_set && !identity_set) { ++ gtk_widget_set_sensitive (password_entry, TRUE); ++ gtk_widget_set_sensitive (identity_entry, TRUE); ++ } ++ else if (identity_set) ++ gtk_widget_set_sensitive (password_entry, FALSE); ++ else if (password_set) ++ gtk_widget_set_sensitive (identity_entry, FALSE); + } + + static void +-- +1.8.3.1 + diff --git a/SOURCES/0109-RHEL-7-Disable-alternate-Augeas-lenses.patch b/SOURCES/0109-RHEL-7-Disable-alternate-Augeas-lenses.patch deleted file mode 100644 index c11e480..0000000 --- a/SOURCES/0109-RHEL-7-Disable-alternate-Augeas-lenses.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 1156f17878c25ba3221105b339ab9ff298bd123d Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 24 Oct 2014 16:33:50 +0100 -Subject: [PATCH] RHEL 7: Disable alternate Augeas lenses. - -These are included in the RHEL 7.1 augeas package, and therefore -not required in RHEL. - -See: -https://www.redhat.com/archives/libguestfs/2014-October/msg00220.html ---- - appliance/Makefile.am | 2 -- - daemon/augeas.c | 5 ++++- - daemon/lvm-filter.c | 4 ++-- - 3 files changed, 6 insertions(+), 5 deletions(-) - -diff --git a/appliance/Makefile.am b/appliance/Makefile.am -index 7b30bbe..c7eca20 100644 ---- a/appliance/Makefile.am -+++ b/appliance/Makefile.am -@@ -82,8 +82,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfsd.suppressions guestfs_lvm_c - 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)/guestfsd.suppressions tmp-d/etc/guestfsd.suppressions -- 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 - mv $@-t $@ -diff --git a/daemon/augeas.c b/daemon/augeas.c -index ce49726..7753e67 100644 ---- a/daemon/augeas.c -+++ b/daemon/augeas.c -@@ -134,7 +134,7 @@ do_aug_init (const char *root, int flags) - } - - /* Pass AUG_NO_ERR_CLOSE so we can display detailed errors. */ -- aug = aug_init (buf, "/usr/share/guestfs/", flags | AUG_NO_ERR_CLOSE); -+ aug = aug_init (buf, NULL, flags | AUG_NO_ERR_CLOSE); - - if (!aug) { - reply_with_error ("augeas initialization failed"); -@@ -148,6 +148,8 @@ do_aug_init (const char *root, int flags) - return -1; - } - -+ /* We already have the needed lenses in RHEL 7 */ -+#if 0 - if (!augeas_is_version (1, 2, 1)) { - int r = aug_transform (aug, "guestfs_shadow", "/etc/shadow", - 0 /* = included */); -@@ -166,6 +168,7 @@ do_aug_init (const char *root, int flags) - } - } - } -+#endif - - return 0; - } -diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c -index d82fde0..9e0f570 100644 ---- a/daemon/lvm-filter.c -+++ b/daemon/lvm-filter.c -@@ -121,7 +121,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; -@@ -132,7 +132,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"); --- -1.8.3.1 - diff --git a/SOURCES/0109-p2v-Disable-the-sudo-button-when-the-username-is-roo.patch b/SOURCES/0109-p2v-Disable-the-sudo-button-when-the-username-is-roo.patch new file mode 100644 index 0000000..6c55c30 --- /dev/null +++ b/SOURCES/0109-p2v-Disable-the-sudo-button-when-the-username-is-roo.patch @@ -0,0 +1,64 @@ +From 8bc5cc1f3b8ec7c71f7dc961a575abadfb578ace Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 17 Jun 2016 22:24:45 +0100 +Subject: [PATCH] p2v: Disable the sudo button when the username is root. + +(cherry picked from commit 072cf26dc3fdd90e8301b15f430b3f34a9bbf85b) +--- + p2v/gui.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/p2v/gui.c b/p2v/gui.c +index dad8f6e..93b086a 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -92,6 +92,7 @@ gui_conversion (struct config *config) + /*----------------------------------------------------------------------*/ + /* Connection dialog. */ + ++static void username_changed_callback (GtkWidget *w, gpointer data); + static void password_or_identity_changed_callback (GtkWidget *w, gpointer data); + static void test_connection_clicked (GtkWidget *w, gpointer data); + static void *test_connection_thread (void *data); +@@ -240,10 +241,38 @@ create_connection_dialog (struct config *config) + G_CALLBACK (about_button_clicked), NULL); + g_signal_connect (G_OBJECT (next_button), "clicked", + G_CALLBACK (connection_next_clicked), NULL); ++ g_signal_connect (G_OBJECT (username_entry), "changed", ++ G_CALLBACK (username_changed_callback), NULL); + g_signal_connect (G_OBJECT (password_entry), "changed", + G_CALLBACK (password_or_identity_changed_callback), NULL); + g_signal_connect (G_OBJECT (identity_entry), "changed", + G_CALLBACK (password_or_identity_changed_callback), NULL); ++ ++ /* Call this signal to initialize the sensitivity of the sudo ++ * button correctly. ++ */ ++ username_changed_callback (NULL, NULL); ++} ++ ++/** ++ * If the username is "root", disable the sudo button. ++ */ ++static void ++username_changed_callback (GtkWidget *w, gpointer data) ++{ ++ const char *str; ++ int username_is_root; ++ int sudo_is_set; ++ ++ str = gtk_entry_get_text (GTK_ENTRY (username_entry)); ++ username_is_root = str != NULL && STREQ (str, "root"); ++ sudo_is_set = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sudo_button)); ++ ++ /* The sudo button is sensitive if: ++ * - The username is not "root", or ++ * - The button is not already checked (to allow the user to uncheck it) ++ */ ++ gtk_widget_set_sensitive (sudo_button, !username_is_root || sudo_is_set); + } + + /** +-- +1.8.3.1 + diff --git a/SOURCES/0110-p2v-Add-a-dialog-confirming-the-user-really-means-to.patch b/SOURCES/0110-p2v-Add-a-dialog-confirming-the-user-really-means-to.patch new file mode 100644 index 0000000..bfdeafb --- /dev/null +++ b/SOURCES/0110-p2v-Add-a-dialog-confirming-the-user-really-means-to.patch @@ -0,0 +1,83 @@ +From eabb2aee8770ca07282138ea23f66b3c9e56f85b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Jun 2016 09:19:10 +0100 +Subject: [PATCH] p2v: Add a dialog confirming the user really means to cancel + (RHBZ#1340464). + +Thanks: Kean Li +(cherry picked from commit 4f4f0f1fe98dbc82227c3a393d76498b6624a400) +--- + p2v/gui.c | 34 ++++++++++++++++++++++++++++------ + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 93b086a..142d2eb 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -1409,7 +1409,7 @@ static void set_status (const char *msg); + static void add_v2v_output (const char *msg); + static void add_v2v_output_2 (const char *msg, size_t len); + static void *start_conversion_thread (void *data); +-static void cancel_conversion_clicked (GtkWidget *w, gpointer data); ++static void cancel_conversion_dialog (GtkWidget *w, gpointer data); + static void reboot_clicked (GtkWidget *w, gpointer data); + static gboolean close_running_dialog (GtkWidget *w, GdkEvent *event, gpointer data); + +@@ -1447,7 +1447,7 @@ create_running_dialog (void) + + /* Buttons. */ + gtk_dialog_add_buttons (GTK_DIALOG (run_dlg), +- _("Cancel conversion"), 1, ++ _("Cancel conversion ..."), 1, + _("Reboot"), 2, + NULL); + cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (run_dlg), 1); +@@ -1461,7 +1461,7 @@ create_running_dialog (void) + g_signal_connect_swapped (G_OBJECT (run_dlg), "destroy", + G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (G_OBJECT (cancel_button), "clicked", +- G_CALLBACK (cancel_conversion_clicked), NULL); ++ G_CALLBACK (cancel_conversion_dialog), NULL); + g_signal_connect (G_OBJECT (reboot_button), "clicked", + G_CALLBACK (reboot_clicked), NULL); + } +@@ -1753,11 +1753,33 @@ close_running_dialog (GtkWidget *w, GdkEvent *event, gpointer data) + return FALSE; + } + ++/** ++ * This is called when the user clicks on the "Cancel conversion" ++ * button. Since conversions can run for a long time, and cancelling ++ * the conversion is non-recoverable, this function displays a ++ * confirmation dialog before cancelling the conversion. ++ */ + static void +-cancel_conversion_clicked (GtkWidget *w, gpointer data) ++cancel_conversion_dialog (GtkWidget *w, gpointer data) + { +- /* This makes start_conversion return an error (eventually). */ +- cancel_conversion (); ++ GtkWidget *dlg; ++ ++ if (!conversion_is_running ()) ++ return; ++ ++ dlg = gtk_message_dialog_new (GTK_WINDOW (run_dlg), ++ GTK_DIALOG_DESTROY_WITH_PARENT, ++ GTK_MESSAGE_QUESTION, ++ GTK_BUTTONS_YES_NO, ++ _("Really cancel the conversion? " ++ "To convert this machine you will need to " ++ "re-run the conversion from the beginning.")); ++ gtk_window_set_title (GTK_WINDOW (dlg), _("Cancel the conversion")); ++ if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_YES) ++ /* This makes start_conversion return an error (eventually). */ ++ cancel_conversion (); ++ ++ gtk_widget_destroy (dlg); + } + + static void +-- +1.8.3.1 + diff --git a/SOURCES/0110-v2v-Add-a-note-about-escaping-username-like-DOMAIN-u.patch b/SOURCES/0110-v2v-Add-a-note-about-escaping-username-like-DOMAIN-u.patch deleted file mode 100644 index 99c562a..0000000 --- a/SOURCES/0110-v2v-Add-a-note-about-escaping-username-like-DOMAIN-u.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 7222c6d14b7d2c9eb5edb43da8ba83dbb002af71 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 23 Dec 2014 15:29:26 +0000 -Subject: [PATCH] v2v: Add a note about escaping username like DOMAIN\user. - -Thanks: Ben Hooper. -(cherry picked from commit 29df51d9bc24eaae9e42c3794b7dac9c78d8b3bd) ---- - v2v/virt-v2v.pod | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 9edb2ca..933955a 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -744,7 +744,12 @@ where: - - =item C - --is the (optional, but recommended) user to connect as -+is the (optional, but recommended) user to connect as. -+ -+If the username contains a backslash (eg. C) then you -+will need to URI-escape that character using C<%5c>: C -+(5c is the hexadecimal ASCII code for backslash.) Other punctuation -+may also have to be escaped. - - =item C - --- -1.8.3.1 - diff --git a/SOURCES/0111-v2v-adding-vdsm-ovf-output-option.patch b/SOURCES/0111-v2v-adding-vdsm-ovf-output-option.patch deleted file mode 100644 index f6bc5ee..0000000 --- a/SOURCES/0111-v2v-adding-vdsm-ovf-output-option.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 93c2eb23dacc9ffa226c92777c498792d7f5a6cf Mon Sep 17 00:00:00 2001 -From: Shahar Havivi -Date: Thu, 25 Dec 2014 11:57:12 +0200 -Subject: [PATCH] v2v: adding --vdsm-ovf-output option - -This option is needed by vdsm for writing the ovf to a specific directory. -The default is current directory. - -Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1176598 -Signed-off-by: Shahar Havivi -(cherry picked from commit 14d11916faf68afb672d1626348931f2b90afd08) ---- - v2v/cmdline.ml | 5 +++++ - v2v/output_vdsm.ml | 16 +++++++--------- - v2v/output_vdsm.mli | 1 + - v2v/test-v2v-o-vdsm-options.sh | 1 + - v2v/virt-v2v.pod | 8 +++++++- - 5 files changed, 21 insertions(+), 10 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 14c3fb9..97167b4 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -47,6 +47,7 @@ let parse_cmdline () = - let qemu_boot = ref false in - let quiet = ref false in - let vdsm_vm_uuid = ref "" in -+ let vdsm_ovf_output = ref "." in - let verbose = ref false in - let trace = ref false in - let vmtype = ref "" in -@@ -178,6 +179,8 @@ let parse_cmdline () = - Arg.String add_vdsm_vol_uuid, "uuid " ^ s_"Output vol UUID(s)"; - "--vdsm-vm-uuid", - Arg.Set_string vdsm_vm_uuid, "uuid " ^ s_"Output VM UUID"; -+ "--vdsm-ovf-output", -+ Arg.Set_string vdsm_ovf_output, " " ^ s_"Output OVF file"; - "-v", Arg.Set verbose, " " ^ s_"Enable debugging messages"; - "--verbose", Arg.Set verbose, ditto; - "-V", Arg.Unit display_version, " " ^ s_"Display version and exit"; -@@ -237,6 +240,7 @@ read the man page virt-v2v(1). - let vdsm_image_uuids = List.rev !vdsm_image_uuids in - let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in - let vdsm_vm_uuid = !vdsm_vm_uuid in -+ let vdsm_ovf_output = !vdsm_ovf_output in - let verbose = !verbose in - let trace = !trace in - let vmtype = -@@ -386,6 +390,7 @@ read the man page virt-v2v(1). - Output_vdsm.image_uuids = vdsm_image_uuids; - vol_uuids = vdsm_vol_uuids; - vm_uuid = vdsm_vm_uuid; -+ ovf_output = vdsm_ovf_output; - } in - Output_vdsm.output_vdsm verbose output_storage vdsm_params - vmtype output_alloc in -diff --git a/v2v/output_vdsm.ml b/v2v/output_vdsm.ml -index 293f57f..492f586 100644 ---- a/v2v/output_vdsm.ml -+++ b/v2v/output_vdsm.ml -@@ -30,6 +30,7 @@ type vdsm_params = { - image_uuids : string list; - vol_uuids : string list; - vm_uuid : string; -+ ovf_output : string; - } - - class output_vdsm verbose os vdsm_params vmtype output_alloc = -@@ -37,12 +38,13 @@ object - inherit output verbose - - method as_options = -- sprintf "-o vdsm -os %s%s%s --vdsm-vm-uuid %s%s" os -+ sprintf "-o vdsm -os %s%s%s --vdsm-vm-uuid %s --vdsm-ovf-output %s%s" os - (String.concat "" - (List.map (sprintf " --vdsm-image-uuid %s") vdsm_params.image_uuids)) - (String.concat "" - (List.map (sprintf " --vdsm-vol-uuid %s") vdsm_params.vol_uuids)) - vdsm_params.vm_uuid -+ vdsm_params.ovf_output - (match vmtype with - | None -> "" - | Some `Server -> " --vmtype server" -@@ -57,9 +59,6 @@ object - val mutable dd_mp = "" - val mutable dd_uuid = "" - -- (* Target metadata directory. *) -- val mutable ovf_dir = "" -- - (* This is called early on in the conversion and lets us choose the - * name of the target files that eventually get written by the main - * code. -@@ -98,13 +97,12 @@ object - ) vdsm_params.image_uuids; - - (* Note that VDSM has to create this directory too. *) -- ovf_dir <- dd_mp // dd_uuid // "master" // "vms" // vdsm_params.vm_uuid; -- if not (is_directory ovf_dir) then -+ if not (is_directory vdsm_params.ovf_output) then - error (f_"OVF (metadata) directory (%s) does not exist or is not a directory") -- ovf_dir; -+ vdsm_params.ovf_output; - - if verbose then -- eprintf "VDSM: OVF (metadata) directory: %s\n%!" ovf_dir; -+ eprintf "VDSM: OVF (metadata) directory: %s\n%!" vdsm_params.ovf_output; - - (* The final directory structure should look like this: - * ///images/ -@@ -164,7 +162,7 @@ object - vdsm_params.vm_uuid in - - (* Write it to the metadata file. *) -- let file = ovf_dir // vdsm_params.vm_uuid ^ ".ovf" in -+ let file = vdsm_params.ovf_output // vdsm_params.vm_uuid ^ ".ovf" in - let chan = open_out file in - doc_to_chan chan ovf; - close_out chan -diff --git a/v2v/output_vdsm.mli b/v2v/output_vdsm.mli -index 3ee5425..26ac15d 100644 ---- a/v2v/output_vdsm.mli -+++ b/v2v/output_vdsm.mli -@@ -22,6 +22,7 @@ type vdsm_params = { - image_uuids : string list; (* --vdsm-image-uuid (multiple) *) - vol_uuids : string list; (* --vdsm-vol-uuid (multiple) *) - vm_uuid : string; (* --vdsm-vm-uuid *) -+ ovf_output : string; (* --vdsm-ovf-output *) - } - (** Miscellaneous extra command line parameters used by VDSM. *) - -diff --git a/v2v/test-v2v-o-vdsm-options.sh b/v2v/test-v2v-o-vdsm-options.sh -index 8747d8a..e2098fa 100755 ---- a/v2v/test-v2v-o-vdsm-options.sh -+++ b/v2v/test-v2v-o-vdsm-options.sh -@@ -69,6 +69,7 @@ $VG virt-v2v --debug-gc \ - --vdsm-image-uuid IMAGE \ - --vdsm-vol-uuid VOL \ - --vdsm-vm-uuid VM \ -+ --vdsm-ovf-output $d/12345678-1234-1234-1234-123456789abc/master/vms/VM \ - - # Test the OVF metadata was created. - test -f $d/12345678-1234-1234-1234-123456789abc/master/vms/VM/VM.ovf -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 933955a..7ed2dda 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -483,6 +483,8 @@ OS which is not in the first VirtIO disk. - - =item B<--vdsm-vm-uuid> UUID - -+=item B<--vdsm-ovf-output> -+ - Normally the RHEV output mode chooses random UUIDs for the target - guest. However VDSM needs to control the UUIDs and passes these - parameters when virt-v2v runs under VDSM control. The parameters -@@ -502,7 +504,11 @@ is passed once for each guest disk) - - =item * - --the VM and OVF file (I<--vdsm-vm-uuid>). -+the OVF file name (I<--vdsm-vm-uuid>). -+ -+=item * -+ -+the OVF output directory (default current directory) (I<--vdsm-ovf-output>). - - =back - --- -1.8.3.1 - diff --git a/SOURCES/0111-virt-tools-Add-common-colours-option.patch b/SOURCES/0111-virt-tools-Add-common-colours-option.patch new file mode 100644 index 0000000..628b170 --- /dev/null +++ b/SOURCES/0111-virt-tools-Add-common-colours-option.patch @@ -0,0 +1,269 @@ +From 3b7c70dea311561c4ffe69ceee65a994a5543862 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Jun 2016 10:22:46 +0100 +Subject: [PATCH] virt tools: Add common --colours option. + +This option (alternately spelled: --color, --colour, --colors, or +--colours) enables ANSI colour sequences output even if that would be +disabled becaues the output is not a TTY. + +(cherry picked from commit b000d6bc68543035e3fc14853c8a9f518ed1b0f3) +--- + builder/virt-builder.pod | 9 +++++++++ + customize/virt-customize.pod | 9 +++++++++ + dib/virt-dib.pod | 9 +++++++++ + get-kernel/virt-get-kernel.pod | 9 +++++++++ + mllib/common_utils.ml | 42 +++++++++++++++++++++++++----------------- + resize/virt-resize.pod | 9 +++++++++ + sparsify/virt-sparsify.pod | 9 +++++++++ + sysprep/virt-sysprep.pod | 9 +++++++++ + v2v/cmdline.ml | 1 + + v2v/virt-v2v.pod | 9 +++++++++ + 10 files changed, 98 insertions(+), 17 deletions(-) + +diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod +index 94ba430..5e344de 100644 +--- a/builder/virt-builder.pod ++++ b/builder/virt-builder.pod +@@ -241,6 +241,15 @@ Using I<--no-check-signature> bypasses this check. + + See also I<--fingerprint>. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<--curl> CURL + + Specify an alternate L binary. You can also use this to add +diff --git a/customize/virt-customize.pod b/customize/virt-customize.pod +index 8fb9931..e8eb148 100644 +--- a/customize/virt-customize.pod ++++ b/customize/virt-customize.pod +@@ -74,6 +74,15 @@ disk format (not just an ISO). + Specify the disk format for the next I<--attach> option. The + C is usually C or C. Use C for ISOs. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<-c> URI + + =item B<--connect> URI +diff --git a/dib/virt-dib.pod b/dib/virt-dib.pod +index 9baae23..8ccb9f5 100644 +--- a/dib/virt-dib.pod ++++ b/dib/virt-dib.pod +@@ -72,6 +72,15 @@ Right now this option does nothing more than setting the C + environment variable for the elements, and it's up to them to + produce an image for the requested architecture. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<--debug> LEVEL + + Set the debug level to C, which is a non-negative integer +diff --git a/get-kernel/virt-get-kernel.pod b/get-kernel/virt-get-kernel.pod +index 92d6cb6..97a159c 100644 +--- a/get-kernel/virt-get-kernel.pod ++++ b/get-kernel/virt-get-kernel.pod +@@ -44,6 +44,15 @@ force a particular format use the I<--format> option. + Add a remote disk. The URI format is compatible with guestfish. + See L. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<-c> URI + + =item B<--connect> URI +diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml +index be8810a..7bd02f8 100644 +--- a/mllib/common_utils.ml ++++ b/mllib/common_utils.ml +@@ -299,27 +299,16 @@ let protect ~f ~finally = + finally (); + match r with Either ret -> ret | Or exn -> raise exn + +-let istty chan = +- Unix.isatty (Unix.descr_of_out_channel chan) +- +-(* ANSI terminal colours. *) +-let ansi_green ?(chan = stdout) () = +- if istty chan then output_string chan "\x1b[0;32m" +-let ansi_red ?(chan = stdout) () = +- if istty chan then output_string chan "\x1b[1;31m" +-let ansi_blue ?(chan = stdout) () = +- if istty chan then output_string chan "\x1b[1;34m" +-let ansi_magenta ?(chan = stdout) () = +- if istty chan then output_string chan "\x1b[1;35m" +-let ansi_restore ?(chan = stdout) () = +- if istty chan then output_string chan "\x1b[0m" +- + (* Program name. *) + let prog = Filename.basename Sys.executable_name + +-(* Stores the quiet (--quiet), trace (-x) and verbose (-v) flags in a +- * global variable. ++(* Stores the colours (--colours), quiet (--quiet), trace (-x) and ++ * verbose (-v) flags in a global variable. + *) ++let colours = ref false ++let set_colours () = colours := true ++let colours () = !colours ++ + let quiet = ref false + let set_quiet () = quiet := true + let quiet () = !quiet +@@ -332,6 +321,21 @@ let verbose = ref false + let set_verbose () = verbose := true + let verbose () = !verbose + ++(* ANSI terminal colours. *) ++let istty chan = ++ Unix.isatty (Unix.descr_of_out_channel chan) ++ ++let ansi_green ?(chan = stdout) () = ++ if colours () || istty chan then output_string chan "\x1b[0;32m" ++let ansi_red ?(chan = stdout) () = ++ if colours () || istty chan then output_string chan "\x1b[1;31m" ++let ansi_blue ?(chan = stdout) () = ++ if colours () || istty chan then output_string chan "\x1b[1;34m" ++let ansi_magenta ?(chan = stdout) () = ++ if colours () || istty chan then output_string chan "\x1b[1;35m" ++let ansi_restore ?(chan = stdout) () = ++ if colours () || istty chan then output_string chan "\x1b[0m" ++ + (* Timestamped progress messages, used for ordinary messages when not + * --quiet. + *) +@@ -596,6 +600,10 @@ let set_standard_options argspec = + "--debug-gc", Arg.Unit set_debug_gc, " " ^ s_"Debug GC and memory allocations (internal)"; + "-q", Arg.Unit set_quiet, " " ^ s_"Don't print progress messages"; + "--quiet", Arg.Unit set_quiet, " " ^ s_"Don't print progress messages"; ++ "--color", Arg.Unit set_colours, " " ^ s_"Use ANSI colour sequences even if not tty"; ++ "--colors", Arg.Unit set_colours, " " ^ s_"Use ANSI colour sequences even if not tty"; ++ "--colour", Arg.Unit set_colours, " " ^ s_"Use ANSI colour sequences even if not tty"; ++ "--colours", Arg.Unit set_colours, " " ^ s_"Use ANSI colour sequences even if not tty"; + ] @ argspec in + let argspec = + let cmp (arg1, _, _) (arg2, _, _) = compare_command_line_args arg1 arg2 in +diff --git a/resize/virt-resize.pod b/resize/virt-resize.pod +index a0ab459..2b2a485 100644 +--- a/resize/virt-resize.pod ++++ b/resize/virt-resize.pod +@@ -327,6 +327,15 @@ since around 2008. + + =back + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<-d> + + =item B<--debug> +diff --git a/sparsify/virt-sparsify.pod b/sparsify/virt-sparsify.pod +index b841251..44f7d4e 100644 +--- a/sparsify/virt-sparsify.pod ++++ b/sparsify/virt-sparsify.pod +@@ -155,6 +155,15 @@ B and exit. + + You cannot use this option and I<--in-place> together. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<--compress> + + Compress the output file. This I works if the output format is +diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod +index 44cf7f8..d671443 100644 +--- a/sysprep/virt-sysprep.pod ++++ b/sysprep/virt-sysprep.pod +@@ -59,6 +59,15 @@ force a particular format use the I<--format> option. + Add a remote disk. The URI format is compatible with guestfish. + See L. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<-c> URI + + =item B<--connect> URI +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 4623af9..b9992eb 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -296,6 +296,7 @@ read the man page virt-v2v(1). + if args = [] && machine_readable then ( + printf "virt-v2v\n"; + printf "libguestfs-rewrite\n"; ++ printf "colours-option\n"; + List.iter (printf "input:%s\n") (Modules_list.input_modules ()); + List.iter (printf "output:%s\n") (Modules_list.output_modules ()); + List.iter (printf "convert:%s\n") (Modules_list.convert_modules ()); +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 5800b34..93f0e77 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -154,6 +154,15 @@ Display help. + + See I<--network> below. + ++=item B<--colors> ++ ++=item B<--colours> ++ ++Use ANSI colour sequences to colourize messages. This is the default ++when the output is a tty. If the output of the program is redirected ++to a file, ANSI colour sequences are disabled unless you use this ++option. ++ + =item B<--compressed> + + Write a compressed output file. This is only allowed if the output +-- +1.8.3.1 + diff --git a/SOURCES/0112-p2v-Use-virt-v2v-colours-option-support-colour-in-th.patch b/SOURCES/0112-p2v-Use-virt-v2v-colours-option-support-colour-in-th.patch new file mode 100644 index 0000000..1520e88 --- /dev/null +++ b/SOURCES/0112-p2v-Use-virt-v2v-colours-option-support-colour-in-th.patch @@ -0,0 +1,359 @@ +From 16bd3feeb15684fa729012b419e9722904907bab Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Jun 2016 10:40:09 +0100 +Subject: [PATCH] p2v: Use virt-v2v --colours option, support colour in the run + dialog (RHBZ#1314244). + +(cherry picked from commit 5e8f820494e70766a48fee38bc617c37b0c61a48) +--- + p2v/conversion.c | 5 +- + p2v/gui.c | 179 +++++++++++++++++++++++++++++++++++++++++++++---------- + p2v/main.c | 1 + + p2v/p2v.h | 3 + + p2v/ssh.c | 24 ++++++-- + 5 files changed, 172 insertions(+), 40 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index f221f84..5265a76 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -320,9 +320,10 @@ start_conversion (struct config *config, + /* Build the virt-v2v command up in pieces to make the quoting + * slightly more sane. + */ +- if (mexp_printf (control_h, "( %s virt-v2v%s -i libvirtxml", ++ if (mexp_printf (control_h, "( %s virt-v2v%s%s -i libvirtxml", + config->sudo ? "sudo -n " : "", +- config->verbose ? " -v -x" : "") == -1) { ++ config->verbose ? " -v -x" : "", ++ feature_colours_option ? " --colours" : "") == -1) { + printf_fail: + set_conversion_error ("mexp_printf: virt-v2v command: %m"); + goto out; +diff --git a/p2v/gui.c b/p2v/gui.c +index 142d2eb..a3b4af9 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -71,6 +72,9 @@ static GtkWidget *run_dlg, + *v2v_output_sw, *v2v_output, *log_label, *status_label, + *cancel_button, *reboot_button; + ++/* Colour tags used in the v2v_output GtkTextBuffer. */ ++static GtkTextTag *v2v_output_tags[16]; ++ + /* The entry point from the main program. + * Note that gtk_init etc have already been called in main. + */ +@@ -1407,7 +1411,6 @@ get_memory_from_conv_dlg (void) + static void set_log_dir (const char *remote_dir); + static void set_status (const char *msg); + static void add_v2v_output (const char *msg); +-static void add_v2v_output_2 (const char *msg, size_t len); + static void *start_conversion_thread (void *data); + static void cancel_conversion_dialog (GtkWidget *w, gpointer data); + static void reboot_clicked (GtkWidget *w, gpointer data); +@@ -1416,6 +1419,12 @@ static gboolean close_running_dialog (GtkWidget *w, GdkEvent *event, gpointer da + static void + create_running_dialog (void) + { ++ size_t i; ++ static const char *tags[16] = ++ { "black", "maroon", "green", "olive", "navy", "purple", "teal", "silver", ++ "gray", "red", "lime", "yellow", "blue", "fuchsia", "cyan", "white" }; ++ GtkTextBuffer *buf; ++ + run_dlg = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (run_dlg), guestfs_int_program_name); + gtk_window_set_resizable (GTK_WINDOW (run_dlg), FALSE); +@@ -1428,6 +1437,17 @@ create_running_dialog (void) + gtk_text_view_set_editable (GTK_TEXT_VIEW (v2v_output), FALSE); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (v2v_output), GTK_WRAP_CHAR); + gtk_widget_set_size_request (v2v_output, 700, 400); ++ ++ buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (v2v_output)); ++ for (i = 0; i < 16; ++i) { ++ CLEANUP_FREE char *tag_name; ++ ++ if (asprintf (&tag_name, "tag_%s", tags[i]) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ v2v_output_tags[i] = ++ gtk_text_buffer_create_tag (buf, tag_name, "foreground", tags[i], NULL); ++ } ++ + log_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (log_label), 0., 0.5); + gtk_misc_set_padding (GTK_MISC (log_label), 10, 10); +@@ -1510,38 +1530,133 @@ set_status (const char *msg) + static void + add_v2v_output (const char *msg) + { ++ const char *p; + static size_t linelen = 0; +- const char *p0, *p; +- +- /* Gtk2 (in ~ Fedora 23) has a regression where it takes much +- * longer to display long lines, to the point where the virt-p2v +- * UI would still be slowly display kernel modules while the +- * conversion had finished. For this reason, arbitrarily break +- * long lines. +- */ +- for (p0 = p = msg; *p; ++p) { +- linelen++; +- if (*p == '\n' || linelen > 1024) { +- add_v2v_output_2 (p0, p-p0+1); +- if (*p != '\n') +- add_v2v_output_2 ("\n", 1); +- linelen = 0; +- p0 = p+1; +- } +- } +- add_v2v_output_2 (p0, p-p0); +-} +- +-static void +-add_v2v_output_2 (const char *msg, size_t len) +-{ +- GtkTextBuffer *buf; +- GtkTextIter iter; +- +- /* Insert it at the end. */ +- buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (v2v_output)); +- gtk_text_buffer_get_end_iter (buf, &iter); +- gtk_text_buffer_insert (buf, &iter, msg, len); ++ static enum { ++ state_normal, ++ state_escape1, /* seen ESC, expecting [ */ ++ state_escape2, /* seen ESC [, expecting 0 or 1 */ ++ state_escape3, /* seen ESC [ 0/1, expecting ; or m */ ++ state_escape4, /* seen ESC [ 0/1 ;, expecting 3 */ ++ state_escape5, /* seen ESC [ 0/1 ; 3, expecting 1/2/4/5 */ ++ state_escape6, /* seen ESC [ 0/1 ; 3 1/2/5/5, expecting m */ ++ state_cr, /* seen CR */ ++ state_truncating, /* truncating line until next \n */ ++ } state = state_normal; ++ static int colour = 0; ++ static GtkTextTag *tag = NULL; ++ GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (v2v_output)); ++ GtkTextIter iter, iter2; ++ const char *dots = " [...]"; ++ ++ for (p = msg; *p != '\0'; ++p) { ++ char c = *p; ++ ++ switch (state) { ++ case state_normal: ++ if (c == '\r') /* Start of possible CRLF sequence. */ ++ state = state_cr; ++ else if (c == '\x1b') { /* Start of an escape sequence. */ ++ state = state_escape1; ++ colour = 0; ++ } ++ else if (c != '\n' && linelen >= 256) { ++ /* Gtk2 (in ~ Fedora 23) has a regression where it takes much ++ * longer to display long lines, to the point where the ++ * virt-p2v UI would still be slowly displaying kernel modules ++ * while the conversion had finished. For this reason, ++ * arbitrarily truncate very long lines. ++ */ ++ gtk_text_buffer_get_end_iter (buf, &iter); ++ gtk_text_buffer_insert_with_tags (buf, &iter, ++ dots, strlen (dots), tag, NULL); ++ state = state_truncating; ++ colour = 0; ++ tag = NULL; ++ } ++ else { /* Treat everything else as a normal char. */ ++ if (c != '\n') linelen++; else linelen = 0; ++ gtk_text_buffer_get_end_iter (buf, &iter); ++ gtk_text_buffer_insert_with_tags (buf, &iter, &c, 1, tag, NULL); ++ } ++ break; ++ ++ case state_escape1: ++ if (c == '[') ++ state = state_escape2; ++ else ++ state = state_normal; ++ break; ++ ++ case state_escape2: ++ if (c == '0') ++ state = state_escape3; ++ else if (c == '1') { ++ state = state_escape3; ++ colour += 8; ++ } ++ else ++ state = state_normal; ++ break; ++ ++ case state_escape3: ++ if (c == ';') ++ state = state_escape4; ++ else if (c == 'm') { ++ tag = NULL; /* restore text colour */ ++ state = state_normal; ++ } ++ else ++ state = state_normal; ++ break; ++ ++ case state_escape4: ++ if (c == '3') ++ state = state_escape5; ++ else ++ state = state_normal; ++ break; ++ ++ case state_escape5: ++ if (c >= '0' && c <= '7') { ++ state = state_escape6; ++ colour += c - '0'; ++ } ++ else ++ state = state_normal; ++ break; ++ ++ case state_escape6: ++ if (c == 'm') { ++ assert (colour >= 0 && colour <= 15); ++ tag = v2v_output_tags[colour]; /* set colour tag */ ++ } ++ state = state_normal; ++ break; ++ ++ case state_cr: ++ if (c == '\n') ++ /* Process CRLF as single a newline character. */ ++ p--; ++ else { /* Delete current (== last) line. */ ++ linelen = 0; ++ gtk_text_buffer_get_end_iter (buf, &iter); ++ iter2 = iter; ++ gtk_text_iter_set_line_offset (&iter, 0); ++ /* Delete from iter..iter2 */ ++ gtk_text_buffer_delete (buf, &iter, &iter2); ++ } ++ state = state_normal; ++ break; ++ ++ case state_truncating: ++ if (c == '\n') { ++ p--; ++ state = state_normal; ++ } ++ break; ++ } /* switch (state) */ ++ } /* for */ + + /* Scroll to the end of the buffer. */ + gtk_text_buffer_get_end_iter (buf, &iter); +diff --git a/p2v/main.c b/p2v/main.c +index 99da3e4..99d0011 100644 +--- a/p2v/main.c ++++ b/p2v/main.c +@@ -42,6 +42,7 @@ char **all_disks; + char **all_removable; + char **all_interfaces; + int is_iso_environment = 0; ++int feature_colours_option = 0; + + static void udevadm_settle (void); + static void set_config_defaults (struct config *config); +diff --git a/p2v/p2v.h b/p2v/p2v.h +index 9ccaf0f..12dd210 100644 +--- a/p2v/p2v.h ++++ b/p2v/p2v.h +@@ -58,6 +58,9 @@ extern char **all_interfaces; + */ + extern int is_iso_environment; + ++/* True if virt-v2v supports the --colours option. */ ++extern int feature_colours_option; ++ + /* config.c */ + struct config { + int verbose; +diff --git a/p2v/ssh.c b/p2v/ssh.c +index d9210f3..266c236 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -101,6 +101,7 @@ static pcre *ssh_message_re; + static pcre *prompt_re; + static pcre *version_re; + static pcre *feature_libguestfs_rewrite_re; ++static pcre *feature_colours_option_re; + static pcre *feature_input_re; + static pcre *feature_output_re; + static pcre *portfwd_re; +@@ -149,6 +150,7 @@ compile_regexps (void) + "virt-v2v ([1-9].*)", + 0); + COMPILE (feature_libguestfs_rewrite_re, "libguestfs-rewrite", 0); ++ COMPILE (feature_colours_option_re, "colours-option", 0); + COMPILE (feature_input_re, "input:((?:\\w)*)", 0); + COMPILE (feature_output_re, "output:((?:\\w)*)", 0); + COMPILE (portfwd_re, "Allocated port ((?:\\d)+) for remote forward", 0); +@@ -162,6 +164,7 @@ free_regexps (void) + pcre_free (prompt_re); + pcre_free (version_re); + pcre_free (feature_libguestfs_rewrite_re); ++ pcre_free (feature_colours_option_re); + pcre_free (feature_input_re); + pcre_free (feature_output_re); + pcre_free (portfwd_re); +@@ -613,28 +616,37 @@ test_connection (struct config *config) + switch (mexp_expect (h, + (mexp_regexp[]) { + { 100, .re = feature_libguestfs_rewrite_re }, +- { 101, .re = feature_input_re }, +- { 102, .re = feature_output_re }, +- { 103, .re = prompt_re }, ++ { 101, .re = feature_colours_option_re }, ++ { 102, .re = feature_input_re }, ++ { 103, .re = feature_output_re }, ++ { 104, .re = prompt_re }, + { 0 } + }, ovector, ovecsize)) { + case 100: /* libguestfs-rewrite. */ + feature_libguestfs_rewrite = 1; + break; + +- case 101: ++ case 101: /* virt-v2v supports --colours option */ ++#if DEBUG_STDERR ++ fprintf (stderr, "%s: remote virt-v2v supports --colours option\n", ++ guestfs_int_program_name); ++#endif ++ feature_colours_option = 1; ++ break; ++ ++ case 102: + /* input: corresponds to an -i option in virt-v2v. */ + add_input_driver (&h->buffer[ovector[2]], + (size_t) (ovector[3]-ovector[2])); + break; + +- case 102: ++ case 103: + /* output: corresponds to an -o option in virt-v2v. */ + add_output_driver (&h->buffer[ovector[2]], + (size_t) (ovector[3]-ovector[2])); + break; + +- case 103: /* Got prompt, so end of output. */ ++ case 104: /* Got prompt, so end of output. */ + goto end_of_machine_readable; + + case MEXP_EOF: +-- +1.8.3.1 + diff --git a/SOURCES/0112-v2v-o-vdsm-should-assume-data-domain-at-os-path.patch b/SOURCES/0112-v2v-o-vdsm-should-assume-data-domain-at-os-path.patch deleted file mode 100644 index aac1f2b..0000000 --- a/SOURCES/0112-v2v-o-vdsm-should-assume-data-domain-at-os-path.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 766c53d1d28006cbefa2837f6f3bd9fd2bee64b8 Mon Sep 17 00:00:00 2001 -From: Shahar Havivi -Date: Mon, 26 Jan 2015 12:13:49 +0200 -Subject: [PATCH] v2v: -o vdsm should assume data domain at -os path - -Unlike -o rhev which have only one data domin, -o vdsm can and usually -does have multiple data domain. -The path to vdsm is pre mounted so no need to assume nfs path with -os -Example: --o vdsm -os /rhev/data-center// - -Bug-Url: https://bugzilla.redhat.com/1176591 -Signed-off-by: Shahar Havivi -(cherry picked from commit 889e55516869d1eadcdeae15e38dd8d3bbca8d20) ---- - v2v/output_vdsm.ml | 18 ++++++++++++++---- - v2v/test-v2v-o-vdsm-options.sh | 2 +- - v2v/virt-v2v.pod | 6 ++++-- - 3 files changed, 19 insertions(+), 7 deletions(-) - -diff --git a/v2v/output_vdsm.ml b/v2v/output_vdsm.ml -index 492f586..c7a243e 100644 ---- a/v2v/output_vdsm.ml -+++ b/v2v/output_vdsm.ml -@@ -63,9 +63,8 @@ object - * name of the target files that eventually get written by the main - * code. - * -- * 'os' is the output storage (-os nfs:/export). 'source' contains a -- * few useful fields such as the guest name. 'targets' describes the -- * destination files. We modify and return this list. -+ * 'os' is the output storage domain (-os /rhev/data//) -+ * this is already mounted path. - * - * Note it's good to fail here (early) if there are any problems, since - * the next time we are called (in {!create_metadata}) we have already -@@ -79,7 +78,18 @@ object - (List.length targets); - - let mp, uuid = -- Output_rhev.mount_and_check_storage_domain verbose (s_"Data Domain") os in -+ let fields = string_nsplit "/" os in (* ... "data-center" "UUID" *) -+ let fields = List.rev fields in (* "UUID" "data-center" ... *) -+ match fields with -+ | "" :: uuid :: rest (* handles trailing "/" case *) -+ | uuid :: rest -+ when String.length uuid = 36 -> -+ let mp = String.concat "/" (List.rev rest) in -+ mp, uuid -+ | _ -> -+ error (f_"vdsm: invalid -os parameter does not contain a valid UUID: %s") -+ os in -+ - dd_mp <- mp; - dd_uuid <- uuid; - if verbose then -diff --git a/v2v/test-v2v-o-vdsm-options.sh b/v2v/test-v2v-o-vdsm-options.sh -index e2098fa..c170467 100755 ---- a/v2v/test-v2v-o-vdsm-options.sh -+++ b/v2v/test-v2v-o-vdsm-options.sh -@@ -64,7 +64,7 @@ mkdir $d/12345678-1234-1234-1234-123456789abc/master/vms/VM - - $VG virt-v2v --debug-gc \ - -i libvirt -ic "$libvirt_uri" windows \ -- -o vdsm -os $d \ -+ -o vdsm -os $d/12345678-1234-1234-1234-123456789abc \ - --vmtype desktop \ - --vdsm-image-uuid IMAGE \ - --vdsm-vol-uuid VOL \ -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 7ed2dda..2e49fbf 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -360,8 +360,10 @@ See L below. - - Set the output method to I. - --This mode is similar to I<-o rhev> but is only used by RHEV VDSM --when it runs virt-v2v under VDSM control. -+This mode is similar to I<-o rhev>, but the full path to the -+data domain must be given: -+Cdata-center-uuidE/Edata-domain-uuidE>. -+This mode is only used when virt-v2v runs under VDSM control. - - =item B<-oa sparse> - --- -1.8.3.1 - diff --git a/SOURCES/0113-p2v-Use-a-wrapper-script-instead-of-long-virt-v2v-co.patch b/SOURCES/0113-p2v-Use-a-wrapper-script-instead-of-long-virt-v2v-co.patch new file mode 100644 index 0000000..416debf --- /dev/null +++ b/SOURCES/0113-p2v-Use-a-wrapper-script-instead-of-long-virt-v2v-co.patch @@ -0,0 +1,384 @@ +From 11ef6d48abcfc90c0a6e795a067547c289e883d6 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Jun 2016 14:44:24 +0100 +Subject: [PATCH] p2v: Use a wrapper script instead of long virt-v2v command + lne. + +Instead of constructing and directly executing a long virt-v2v command +line, build a wrapper script with the same command line and send it to +the remote server (stored in //virt-v2v-wrapper.sh). + +This will make it a bit easier to construct more complex virt-v2v +wrappers. + +Note this commit on its own is a simple refactoring and does not +change any functionality. + +(cherry picked from commit 514893b68b6180b3adc5bb762e9d67054a9a7f63) +--- + p2v/conversion.c | 203 +++++++++++++++++++++++++++++++++---------------------- + p2v/p2v.h | 2 +- + p2v/ssh.c | 25 ++++++- + p2v/virt-p2v.pod | 17 +++-- + 4 files changed, 159 insertions(+), 88 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index 5265a76..decaf7c 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -78,11 +79,11 @@ struct data_conn { + int nbd_remote_port; /* remote NBD port on conversion server */ + }; + +-static int send_quoted (mexp_h *, const char *s); + static pid_t start_qemu_nbd (int nbd_local_port, const char *device); + static int wait_qemu_nbd (int nbd_local_port, int timeout_seconds); + static void cleanup_data_conns (struct data_conn *data_conns, size_t nr); + static char *generate_libvirt_xml (struct config *, struct data_conn *); ++static char *generate_wrapper_script (struct config *, const char *remote_dir); + static const char *map_interface_to_network (struct config *, const char *interface); + + static char *conversion_error; +@@ -168,7 +169,8 @@ start_conversion (struct config *config, + size_t i, len; + const size_t nr_disks = guestfs_int_count_strings (config->disks); + struct data_conn data_conns[nr_disks]; +- CLEANUP_FREE char *remote_dir = NULL, *libvirt_xml = NULL; ++ CLEANUP_FREE char *remote_dir = NULL, *libvirt_xml = NULL, ++ *wrapper_script = NULL; + time_t now; + struct tm tm; + mexp_h *control_h = NULL; +@@ -276,7 +278,18 @@ start_conversion (struct config *config, + goto out; + + #if DEBUG_STDERR +- fprintf (stderr, "%s: libvirt XML:\n%s", guestfs_int_program_name, libvirt_xml); ++ fprintf (stderr, "%s: libvirt XML:\n%s", ++ guestfs_int_program_name, libvirt_xml); ++#endif ++ ++ /* Generate the virt-v2v wrapper script. */ ++ wrapper_script = generate_wrapper_script (config, remote_dir); ++ if (wrapper_script == NULL) ++ goto out; ++ ++#if DEBUG_STDERR ++ fprintf (stderr, "%s: wrapper script:\n%s", ++ guestfs_int_program_name, wrapper_script); + #endif + + /* Get the output from the 'dmesg' command. We will store this +@@ -305,7 +318,9 @@ start_conversion (struct config *config, + if (notify_ui) + notify_ui (NOTIFY_STATUS, _("Setting up the control connection ...")); + +- control_h = start_remote_connection (config, remote_dir, libvirt_xml, dmesg); ++ control_h = start_remote_connection (config, ++ remote_dir, libvirt_xml, ++ wrapper_script, dmesg); + if (control_h == NULL) { + const char *err = get_ssh_error (); + +@@ -317,66 +332,18 @@ start_conversion (struct config *config, + if (notify_ui) + notify_ui (NOTIFY_STATUS, _("Doing conversion ...")); + +- /* Build the virt-v2v command up in pieces to make the quoting +- * slightly more sane. +- */ +- if (mexp_printf (control_h, "( %s virt-v2v%s%s -i libvirtxml", +- config->sudo ? "sudo -n " : "", +- config->verbose ? " -v -x" : "", +- feature_colours_option ? " --colours" : "") == -1) { +- printf_fail: +- set_conversion_error ("mexp_printf: virt-v2v command: %m"); ++ if (mexp_printf (control_h, ++ /* To simplify things in the wrapper script, it ++ * writes virt-v2v's exit status to ++ * /remote_dir/status, and here we read that and ++ * exit the ssh shell with the same status. ++ */ ++ "%s/virt-v2v-wrapper.sh; " ++ "exit $(< %s/status)\n", ++ remote_dir, remote_dir) == -1) { ++ set_conversion_error ("mexp_printf: virt-v2v: %m"); + goto out; + } +- if (config->output) { /* -o */ +- if (mexp_printf (control_h, " -o ") == -1) +- goto printf_fail; +- if (send_quoted (control_h, config->output) == -1) +- goto printf_fail; +- } +- switch (config->output_allocation) { /* -oa */ +- case OUTPUT_ALLOCATION_NONE: +- /* nothing */ +- break; +- case OUTPUT_ALLOCATION_SPARSE: +- if (mexp_printf (control_h, " -oa sparse") == -1) +- goto printf_fail; +- break; +- case OUTPUT_ALLOCATION_PREALLOCATED: +- if (mexp_printf (control_h, " -oa preallocated") == -1) +- goto printf_fail; +- break; +- default: +- abort (); +- } +- if (config->output_format) { /* -of */ +- if (mexp_printf (control_h, " -of ") == -1) +- goto printf_fail; +- if (send_quoted (control_h, config->output_format) == -1) +- goto printf_fail; +- } +- if (config->output_storage) { /* -os */ +- if (mexp_printf (control_h, " -os ") == -1) +- goto printf_fail; +- if (send_quoted (control_h, config->output_storage) == -1) +- goto printf_fail; +- } +- if (mexp_printf (control_h, " --root first") == -1) +- goto printf_fail; +- if (mexp_printf (control_h, " %s/physical.xml", remote_dir) == -1) +- goto printf_fail; +- /* no stdin, and send stdout and stderr to the same place */ +- if (mexp_printf (control_h, " &1") == -1) +- goto printf_fail; +- if (mexp_printf (control_h, " ; echo $? > %s/status", remote_dir) == -1) +- goto printf_fail; +- if (mexp_printf (control_h, " ) | tee %s/virt-v2v-conversion-log.txt", +- remote_dir) == -1) +- goto printf_fail; +- if (mexp_printf (control_h, "; exit $(< %s/status)", remote_dir) == -1) +- goto printf_fail; +- if (mexp_printf (control_h, "\n") == -1) +- goto printf_fail; + + /* Read output from the virt-v2v process and echo it through the + * notify function, until virt-v2v closes the connection. +@@ -443,26 +410,6 @@ cancel_conversion (void) + set_cancel_requested (1); + } + +-/* Send a shell-quoted string to remote. */ +-static int +-send_quoted (mexp_h *h, const char *s) +-{ +- if (mexp_printf (h, "\"") == -1) +- return -1; +- while (*s) { +- if (*s == '$' || *s == '`' || *s == '\\' || *s == '"') { +- if (mexp_printf (h, "\\") == -1) +- return -1; +- } +- if (mexp_printf (h, "%c", *s) == -1) +- return -1; +- ++s; +- } +- if (mexp_printf (h, "\"") == -1) +- return -1; +- return 0; +-} +- + /* Note: returns process ID (> 0) or 0 if there is an error. */ + static pid_t + start_qemu_nbd (int port, const char *device) +@@ -980,3 +927,95 @@ map_interface_to_network (struct config *config, const char *interface) + /* No mapping found. */ + return "default"; + } ++ ++/** ++ * Print a shell-quoted string on C. ++ */ ++static void ++print_quoted (FILE *fp, const char *s) ++{ ++ fprintf (fp, "\""); ++ while (*s) { ++ if (*s == '$' || *s == '`' || *s == '\\' || *s == '"') ++ fprintf (fp, "\\"); ++ fprintf (fp, "%c", *s); ++ ++s; ++ } ++ fprintf (fp, "\""); ++} ++ ++/** ++ * Construct the virt-v2v wrapper script. ++ * ++ * This will be sent to the remote server, and is easier than trying ++ * to "type" a long and complex single command line into the ssh ++ * connection when we start the conversion. ++ */ ++static char * ++generate_wrapper_script (struct config *config, const char *remote_dir) ++{ ++ FILE *fp; ++ char *output = NULL; ++ size_t output_len = 0; ++ ++ fp = open_memstream (&output, &output_len); ++ if (fp == NULL) ++ error (EXIT_FAILURE, errno, "open_memstream"); ++ ++ fprintf (fp, "#!/bin/sh -\n"); ++ fprintf (fp, "\n"); ++ ++ /* The virt-v2v command. */ ++ fprintf (fp, "(\n"); ++ if (config->sudo) ++ fprintf (fp, "sudo -n "); ++ fprintf (fp, "virt-v2v"); ++ if (config->verbose) ++ fprintf (fp, " -v -x"); ++ if (feature_colours_option) ++ fprintf (fp, " --colours"); ++ fprintf (fp, " -i libvirtxml"); ++ ++ if (config->output) { /* -o */ ++ fprintf (fp, " -o "); ++ print_quoted (fp, config->output); ++ } ++ ++ switch (config->output_allocation) { /* -oa */ ++ case OUTPUT_ALLOCATION_NONE: ++ /* nothing */ ++ break; ++ case OUTPUT_ALLOCATION_SPARSE: ++ fprintf (fp, " -oa sparse"); ++ break; ++ case OUTPUT_ALLOCATION_PREALLOCATED: ++ fprintf (fp, " -oa preallocated"); ++ break; ++ default: ++ abort (); ++ } ++ ++ if (config->output_format) { /* -of */ ++ fprintf (fp, " -of "); ++ print_quoted (fp, config->output_format); ++ } ++ ++ if (config->output_storage) { /* -os */ ++ fprintf (fp, " -os "); ++ print_quoted (fp, config->output_storage); ++ } ++ ++ fprintf (fp, " --root first"); ++ fprintf (fp, " %s/physical.xml", remote_dir); ++ /* no stdin, and send stdout and stderr to the same place */ ++ fprintf (fp, " &1"); ++ fprintf (fp, "\n"); ++ fprintf (fp, "echo $? > %s/status", remote_dir); ++ fprintf (fp, "\n"); ++ fprintf (fp, " ) | tee %s/virt-v2v-conversion-log.txt", remote_dir); ++ fprintf (fp, "\n"); ++ ++ fclose (fp); ++ ++ return output; /* caller frees */ ++} +diff --git a/p2v/p2v.h b/p2v/p2v.h +index 12dd210..49c97b6 100644 +--- a/p2v/p2v.h ++++ b/p2v/p2v.h +@@ -127,7 +127,7 @@ extern int conversion_is_running (void); + /* ssh.c */ + extern int test_connection (struct config *); + extern mexp_h *open_data_connection (struct config *, int *local_port, int *remote_port); +-extern mexp_h *start_remote_connection (struct config *, const char *remote_dir, const char *libvirt_xml, const char *dmesg); ++extern mexp_h *start_remote_connection (struct config *, const char *remote_dir, const char *libvirt_xml, const char *wrapper_script, const char *dmesg); + extern const char *get_ssh_error (void); + + /* utils.c */ +diff --git a/p2v/ssh.c b/p2v/ssh.c +index 266c236..a8c762d 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -904,7 +904,7 @@ wait_for_prompt (mexp_h *h) + mexp_h * + start_remote_connection (struct config *config, + const char *remote_dir, const char *libvirt_xml, +- const char *dmesg) ++ const char *wrapper_script, const char *dmesg) + { + mexp_h *h; + char magic[9]; +@@ -960,6 +960,29 @@ start_remote_connection (struct config *config, + if (wait_for_prompt (h) == -1) + goto error; + ++ /* Upload the wrapper script to the remote directory. */ ++ if (mexp_printf (h, ++ "cat > '%s/virt-v2v-wrapper.sh' << '__%s__'\n" ++ "%s" ++ "__%s__\n", ++ remote_dir, magic, ++ wrapper_script, ++ magic) == -1) { ++ set_ssh_error ("mexp_printf: %m"); ++ goto error; ++ } ++ ++ if (wait_for_prompt (h) == -1) ++ goto error; ++ ++ if (mexp_printf (h, "chmod +x %s/virt-v2v-wrapper.sh\n", remote_dir) == -1) { ++ set_ssh_error ("mexp_printf: %m"); ++ goto error; ++ } ++ ++ if (wait_for_prompt (h) == -1) ++ goto error; ++ + if (dmesg != NULL) { + /* Upload the physical host dmesg to the remote directory. */ + if (mexp_printf (h, +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index 5ceafa7..0c233c5 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -693,6 +693,13 @@ on the conversion server. If conversion fails, you should examine + this log file, and you may be asked to supply the B, + B log file in any bug reports or support tickets. + ++=item F ++ ++I<(during/after conversion)> ++ ++This is the wrapper script which is used when running virt-v2v. For ++interest only, do not attempt to run this script yourself. ++ + =back + + Before conversion actually begins, virt-p2v then makes one or more +@@ -729,10 +736,12 @@ used. Secondly libguestfs creates an overlay on top of the NBD + connection which stores writes in a temporary file on the conversion + file. + +-The final step is to send the S> +-command to the conversion server over the control connection. This +-references the F file (see above), which in turn +-references the NBD listening port(s) of the data connection(s). ++The long S> command is ++wrapped inside a wrapper script and uploaded to the conversion server. ++The final step is to run this wrapper script, in turn running the ++virt-v2v command. The virt-v2v command references the F ++file (see above), which in turn references the NBD listening port(s) ++of the data connection(s). + + Output from the virt-v2v command (messages, debugging etc) is saved + both in the log file on the conversion server, and sent over the +-- +1.8.3.1 + diff --git a/SOURCES/0113-v2v-i-ova-Make-error-message-unsupported-file-format.patch b/SOURCES/0113-v2v-i-ova-Make-error-message-unsupported-file-format.patch deleted file mode 100644 index f4242c9..0000000 --- a/SOURCES/0113-v2v-i-ova-Make-error-message-unsupported-file-format.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e4dc8b36f3e7b16b81ea220b10325726c0406bca Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 28 Jan 2015 13:28:37 +0000 -Subject: [PATCH] v2v: -i ova: Make error message "unsupported file format" - clearer. - -Thanks: Moran Goldboim -(cherry picked from commit 6a195d0f9565ad0e6e46f3e9904a6dea129e59f4) ---- - v2v/input_ova.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 1ab0320..e2a1243 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -63,7 +63,7 @@ object - error (f_"error unpacking %s, see earlier error messages") ova; - tmpdir - | `GZip | `XZ | `Unknown -> -- error (f_"%s: unsupported file format") ova -+ error (f_"%s: unsupported file format\n\nFormats which we currently understand for '-i ova' are: uncompressed tar, zip") ova - ) in - - (* Exploded path must be absolute (RHBZ#1155121). *) --- -1.8.3.1 - diff --git a/SOURCES/0114-p2v-Don-t-display-debugging-messages-in-the-run-dial.patch b/SOURCES/0114-p2v-Don-t-display-debugging-messages-in-the-run-dial.patch new file mode 100644 index 0000000..e7cc555 --- /dev/null +++ b/SOURCES/0114-p2v-Don-t-display-debugging-messages-in-the-run-dial.patch @@ -0,0 +1,121 @@ +From 60edfe4cb0126a27de8c7f264dde6eaa49135436 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Jun 2016 15:12:08 +0100 +Subject: [PATCH] p2v: Don't display debugging messages in the run dialog. + +Previously we displayed the complete output of virt-v2v in the run +dialog. This output included all the debugging messages, and was very +long and confusing for users (especially we had false bug reports +about "errors" appearing in the debug output). + +Only display stdout in the run dialog. However make sure everything +(stdout and stderr) is still logged to the conversion log. + +(cherry picked from commit 7447fe2478e49f5121a40db973f8a1fb1daaec53) +--- + p2v/conversion.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------- + p2v/virt-p2v.pod | 7 ++++--- + 2 files changed, 46 insertions(+), 11 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index decaf7c..a7d1f11 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -962,11 +962,15 @@ generate_wrapper_script (struct config *config, const char *remote_dir) + if (fp == NULL) + error (EXIT_FAILURE, errno, "open_memstream"); + +- fprintf (fp, "#!/bin/sh -\n"); ++ fprintf (fp, "#!/bin/bash -\n"); + fprintf (fp, "\n"); + +- /* The virt-v2v command. */ +- fprintf (fp, "(\n"); ++ fprintf (fp, "cd %s\n", remote_dir); ++ fprintf (fp, "\n"); ++ ++ /* The virt-v2v command, as a shell function called "v2v". */ ++ fprintf (fp, "v2v ()\n"); ++ fprintf (fp, "{\n"); + if (config->sudo) + fprintf (fp, "sudo -n "); + fprintf (fp, "virt-v2v"); +@@ -1006,15 +1010,45 @@ generate_wrapper_script (struct config *config, const char *remote_dir) + } + + fprintf (fp, " --root first"); +- fprintf (fp, " %s/physical.xml", remote_dir); +- /* no stdin, and send stdout and stderr to the same place */ +- fprintf (fp, " &1"); ++ fprintf (fp, " physical.xml"); ++ fprintf (fp, " %s/status", remote_dir); ++ fprintf (fp, ++ "# Save the exit code of virt-v2v into the 'status' file.\n"); ++ fprintf (fp, "echo $? > status\n"); ++ fprintf (fp, "}\n"); + fprintf (fp, "\n"); +- fprintf (fp, " ) | tee %s/virt-v2v-conversion-log.txt", remote_dir); ++ ++ fprintf (fp, ++ "# Write a pre-emptive error status, in case the virt-v2v\n" ++ "# command doesn't get to run at all. This will be\n" ++ "# overwritten with the true exit code when virt-v2v runs.\n"); ++ fprintf (fp, "echo 99 > status\n"); + fprintf (fp, "\n"); + ++ fprintf (fp, "log=virt-v2v-conversion-log.txt\n"); ++ fprintf (fp, "rm -f $log\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"); ++ fprintf (fp, "\n"); ++ ++ fprintf (fp, ++ "# If virt-v2v failed then the error message (sent to stderr)\n" ++ "# will not be seen in virt-p2v. Send the last few lines of\n" ++ "# the log back to virt-p2v in this case.\n"); ++ fprintf (fp, ++ "if [ \"$(< status)\" -ne 0 ]; then\n" ++ " echo\n" ++ " echo\n" ++ " echo\n" ++ " echo '*** virt-v2v command failed ***'\n" ++ " tail -30 $log\n" ++ "fi\n"); ++ + fclose (fp); + + return output; /* caller frees */ +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index 0c233c5..b996541 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -267,7 +267,7 @@ When conversion is running you will see this dialog: + │ │ + └────────────────────────────────────────────────────────┘ + +-In the main scrolling area you will see log messages from the virt-v2v ++In the main scrolling area you will see messages from the virt-v2v + process. + + Below the main area, virt-p2v shows you the location of the directory +@@ -744,8 +744,9 @@ file (see above), which in turn references the NBD listening port(s) + of the data connection(s). + + Output from the virt-v2v command (messages, debugging etc) is saved +-both in the log file on the conversion server, and sent over the +-control connection to be displayed in the graphical UI. ++both in the log file on the conversion server. Only informational ++messages are sent back over the control connection to be displayed in ++the graphical UI. + + =head1 SEE ALSO + +-- +1.8.3.1 + diff --git a/SOURCES/0114-v2v-o-libvirt-Prevent-possible-XPath-injection.patch b/SOURCES/0114-v2v-o-libvirt-Prevent-possible-XPath-injection.patch deleted file mode 100644 index 3905238..0000000 --- a/SOURCES/0114-v2v-o-libvirt-Prevent-possible-XPath-injection.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 3815caab495ce2644eee574bb3564cddf886bebe Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 20 Dec 2014 17:46:53 +0000 -Subject: [PATCH] v2v: -o libvirt: Prevent possible XPath injection. - -Ensure the arch string is sane before using it in the following XPath -expression. Since the arch string can be derived from untrusted guest -data [see src/filearch.c], this prevents a possible XPath injection -vulnerability. - -(cherry picked from commit 6c6ce85f94c36803fe2db35a98db436bff0c14b0) ---- - v2v/output_libvirt.ml | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index dc9466c..7f9a3a0 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -30,9 +30,15 @@ module StringSet = Set.Make (String) - let string_set_of_list = - List.fold_left (fun set x -> StringSet.add x set) StringSet.empty - -+let arch_sanity_re = Str.regexp "^[-_A-Za-z0-9]+$" -+ - let target_features_of_capabilities_doc doc arch = - let xpathctx = Xml.xpath_new_context doc in - let expr = -+ (* Check the arch is sane. It comes from untrusted input. This -+ * avoids XPath injection below. -+ *) -+ assert (Str.string_match arch_sanity_re arch 0); - (* NB: Pay attention to the square brackets. This returns the - * nodes! - *) --- -1.8.3.1 - diff --git a/SOURCES/0115-p2v-Use-a-monospace-font-for-the-run-dialog.patch b/SOURCES/0115-p2v-Use-a-monospace-font-for-the-run-dialog.patch new file mode 100644 index 0000000..462a626 --- /dev/null +++ b/SOURCES/0115-p2v-Use-a-monospace-font-for-the-run-dialog.patch @@ -0,0 +1,38 @@ +From 5239a0d260109d33d1e436bc63fee4b6e58c44c8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Jun 2016 15:31:34 +0100 +Subject: [PATCH] p2v: Use a monospace font for the run dialog. + +(cherry picked from commit ca6fea7616f89775180ab686133052eca18f0e00) +--- + p2v/gui.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/p2v/gui.c b/p2v/gui.c +index a3b4af9..764b0f8 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -1448,6 +1448,20 @@ create_running_dialog (void) + gtk_text_buffer_create_tag (buf, tag_name, "foreground", tags[i], NULL); + } + ++#if GTK_CHECK_VERSION(3,16,0) /* gtk >= 3.16 */ ++ /* XXX This only sets the "CSS" style. It's not clear how to set ++ * the particular font. However (by accident) this does at least ++ * set the widget to use a monospace font. ++ */ ++ GtkStyleContext *context = gtk_widget_get_style_context (v2v_output); ++ gtk_style_context_add_class (context, "monospace"); ++#else ++ PangoFontDescription *font; ++ font = pango_font_description_from_string ("Monospace 11"); ++ gtk_widget_modify_font (v2v_output, font); ++ pango_font_description_free (font); ++#endif ++ + log_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (log_label), 0., 0.5); + gtk_misc_set_padding (GTK_MISC (log_label), 10, 10); +-- +1.8.3.1 + diff --git a/SOURCES/0115-v2v-Add-note-about-RHEL-4-conversions-hanging-during.patch b/SOURCES/0115-v2v-Add-note-about-RHEL-4-conversions-hanging-during.patch deleted file mode 100644 index 3c61206..0000000 --- a/SOURCES/0115-v2v-Add-note-about-RHEL-4-conversions-hanging-during.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 6c03f770b86348ec3ce8283e3df245cb22b716e8 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 30 Mar 2015 13:22:58 +0100 -Subject: [PATCH] v2v: Add note about RHEL 4 conversions hanging during SELinux - relabelling. - -(cherry picked from commit d4ab702dad39fe1f609ee17661f6bfa3a11dee31) ---- - v2v/virt-v2v.pod | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 2e49fbf..e3f97f2 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -618,6 +618,25 @@ below. - Windows Drivers are installed from /usr/share/virtio-win - if present - -+=head1 RHEL 4 -+ -+=head2 SELinux relabel appears to hang forever -+ -+In RHEL E 4.7 there was a bug which causes SELinux relabelling -+to appear to hang forever at: -+ -+ *** Warning -- SELinux relabel is required. *** -+ *** Disabling security enforcement. *** -+ *** Relabeling could take a very long time, *** -+ *** depending on file system size. *** -+ -+In reality it is waiting for you to press a key (but there is no -+visual indication of this). You can either hit the C<[Return]> key, -+at which point the guest will finish relabelling and reboot, or you -+can install policycoreutils E 1.18.1-4.13 before starting the v2v -+conversion. See also -+L -+ - =head1 WINDOWS - - =head2 Boot failure: 0x0000007B --- -1.8.3.1 - diff --git a/SOURCES/0116-p2v-Display-up-to-50-lines-of-the-virt-v2v-conversio.patch b/SOURCES/0116-p2v-Display-up-to-50-lines-of-the-virt-v2v-conversio.patch new file mode 100644 index 0000000..6c68815 --- /dev/null +++ b/SOURCES/0116-p2v-Display-up-to-50-lines-of-the-virt-v2v-conversio.patch @@ -0,0 +1,57 @@ +From d1f7ebc29a819c4ff1156169fa3a04efa7046685 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 20 Jun 2016 09:56:48 +0100 +Subject: [PATCH] p2v: Display up to 50 lines of the virt-v2v conversion log on + failure. + +For some failures, 30 lines was not sufficient and only part of the +error was shown. Increase the number of lines shown to 50. + +This also colourizes the failure message, and prominently displays the +location of the full log. The following message is now shown: + + *** virt-v2v command failed *** + + The full log is available on the conversion server in: + /tmp/virt-p2v-20160620-sga9rhk7/virt-v2v-conversion-log.txt + Only the last 50 lines are shown below. + + [followed by up to 50 lines of log] + +Updates and fixes commit 7447fe2478e49f5121a40db973f8a1fb1daaec53. + +(cherry picked from commit 6f5abc9539a4d47c98898b4c491d6b017d9abbbb) +--- + p2v/conversion.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index a7d1f11..fe18b4a 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -1045,9 +1045,19 @@ generate_wrapper_script (struct config *config, const char *remote_dir) + " echo\n" + " echo\n" + " echo\n" +- " echo '*** virt-v2v command failed ***'\n" +- " tail -30 $log\n" +- "fi\n"); ++ " echo -ne '\\e[1;31m'\n" ++ " echo '***' virt-v2v command failed '***'\n" ++ " echo\n" ++ " echo The full log is available on the conversion server in:\n" ++ " echo ' ' %s/$log\n" ++ " echo Only the last 50 lines are shown below.\n" ++ " echo -ne '\\e[0m'\n" ++ " echo\n" ++ " echo\n" ++ " echo\n" ++ " tail -50 $log\n" ++ "fi\n", ++ remote_dir); + + fclose (fp); + +-- +1.8.3.1 + diff --git a/SOURCES/0116-v2v-RHEL-4-You-have-to-update-lvm2-device-mapper-to-.patch b/SOURCES/0116-v2v-RHEL-4-You-have-to-update-lvm2-device-mapper-to-.patch deleted file mode 100644 index c6af10c..0000000 --- a/SOURCES/0116-v2v-RHEL-4-You-have-to-update-lvm2-device-mapper-to-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 953e67d5f2545886862e9a403663f919004719f4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 30 Mar 2015 13:23:10 +0100 -Subject: [PATCH] v2v: RHEL 4: You have to update lvm2, device-mapper to get - virtio support. - -Also include the updated selinux policy that goes with RHEL 4.8. - -Also mention that policycoreutils should be updated - see previous -commit. - -(cherry picked from commit 453db7e210673cbd361a4d380e07e607ea833b9c) ---- - v2v/virt-v2v.pod | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index e3f97f2..033040e 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -598,6 +598,10 @@ below. - RHEL 3 No virtio drivers are available - - RHEL 4 kernel >= 2.5.9-89.EL -+ lvm2 >= 2.02.42-5.el4 -+ device-mapper >= 1.02.28-2.el4 -+ selinux-policy-targeted >= 1.17.30-2.152.el4 -+ policycoreutils >= 1.18.1-4.13 - - RHEL 5 kernel >= 2.6.18-128.el5 - lvm2 >= 2.02.40-6.el5 --- -1.8.3.1 - diff --git a/SOURCES/0117-p2v-Don-t-display-libvirt-XML-and-wrapper-script-on-.patch b/SOURCES/0117-p2v-Don-t-display-libvirt-XML-and-wrapper-script-on-.patch new file mode 100644 index 0000000..7cf280a --- /dev/null +++ b/SOURCES/0117-p2v-Don-t-display-libvirt-XML-and-wrapper-script-on-.patch @@ -0,0 +1,38 @@ +From c29e8831ed1414ff57811921afe323f223743f8b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 20 Jun 2016 10:02:11 +0100 +Subject: [PATCH] p2v: Don't display libvirt XML and wrapper script on stderr. + +Confusing for end users, and not necessary for debugging since those +files are saved on the conversion server. + +(cherry picked from commit 55a0ab845d570c781d321b09213aa43a709e91cd) +--- + p2v/conversion.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index fe18b4a..b54f971 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -277,7 +277,7 @@ start_conversion (struct config *config, + if (libvirt_xml == NULL) + goto out; + +-#if DEBUG_STDERR ++#if DEBUG_STDERR && 0 + fprintf (stderr, "%s: libvirt XML:\n%s", + guestfs_int_program_name, libvirt_xml); + #endif +@@ -287,7 +287,7 @@ start_conversion (struct config *config, + if (wrapper_script == NULL) + goto out; + +-#if DEBUG_STDERR ++#if DEBUG_STDERR && 0 + fprintf (stderr, "%s: wrapper script:\n%s", + guestfs_int_program_name, wrapper_script); + #endif +-- +1.8.3.1 + diff --git a/SOURCES/0117-v2v-Add-support-for-REG_MULTI_SZ-multiple-strings-to.patch b/SOURCES/0117-v2v-Add-support-for-REG_MULTI_SZ-multiple-strings-to.patch deleted file mode 100644 index f8da6d6..0000000 --- a/SOURCES/0117-v2v-Add-support-for-REG_MULTI_SZ-multiple-strings-to.patch +++ /dev/null @@ -1,52 +0,0 @@ -From f66959c79ab2d0ed26d9012024ac0ee4068b2aab Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 7 Apr 2015 16:58:40 +0100 -Subject: [PATCH] v2v: Add support for REG_MULTI_SZ (multiple strings) to - registry editor. - -(cherry picked from commit 4fd70eab4ff7d9a8e49db2938a80dcef45db150c) ---- - mllib/regedit.ml | 8 ++++++++ - mllib/regedit.mli | 1 + - 2 files changed, 9 insertions(+) - -diff --git a/mllib/regedit.ml b/mllib/regedit.ml -index 673b215..0291fe4 100644 ---- a/mllib/regedit.ml -+++ b/mllib/regedit.ml -@@ -30,6 +30,7 @@ and regtype = - | REG_EXPAND_SZ of string - | REG_BINARY of string - | REG_DWORD of int32 -+| REG_MULTI_SZ of string list - - (* Take a 7 bit ASCII string and encode it as UTF16LE. *) - let encode_utf16le str = -@@ -97,5 +98,12 @@ and import_value g node = function - g#hivex_node_set_value node key 3L bin - | key, REG_DWORD dw -> - g#hivex_node_set_value node key 4L (le32_of_int (Int64.of_int32 dw)) -+ | key, REG_MULTI_SZ ss -> -+ (* http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx *) -+ List.iter (fun s -> assert (s <> "")) ss; -+ let ss = ss @ [""] in -+ let ss = List.map (fun s -> encode_utf16le s ^ "\000\000") ss in -+ let ss = String.concat "" ss in -+ g#hivex_node_set_value node key 7L ss - - let reg_import g root = List.iter (import_key g root) -diff --git a/mllib/regedit.mli b/mllib/regedit.mli -index 1f43cdd..985e405 100644 ---- a/mllib/regedit.mli -+++ b/mllib/regedit.mli -@@ -47,6 +47,7 @@ and regtype = - | REG_EXPAND_SZ of string (** String with %env% *) - | REG_BINARY of string (** Blob of binary data *) - | REG_DWORD of int32 (** Little endian 32 bit integer *) -+| REG_MULTI_SZ of string list (** List of strings *) - (* There are more types in the Registry, but we don't support them here... *) - (** Registry value type and data. - --- -1.8.3.1 - diff --git a/SOURCES/0118-p2v-Poll-to-make-Cancel-Conversion-button-more-respo.patch b/SOURCES/0118-p2v-Poll-to-make-Cancel-Conversion-button-more-respo.patch new file mode 100644 index 0000000..f6b2c00 --- /dev/null +++ b/SOURCES/0118-p2v-Poll-to-make-Cancel-Conversion-button-more-respo.patch @@ -0,0 +1,72 @@ +From a5806c1b4be3f74b25ec733328259e7966af6af6 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 20 Jun 2016 10:18:22 +0100 +Subject: [PATCH] p2v: Poll to make Cancel Conversion button more responsive. + +Previously cancelling the conversion only set a flag, which was +checked when the run dialog displayed new output from virt-v2v. When +virt-v2v was showing hundreds of debugging messages, this wasn't a +problem, but now that we are hiding those messages, cancelling the +conversion might mean a wait of seconds or minutes. + +By polling (albeit infrequently) we can make the cancel button more +responsive. + +(cherry picked from commit 6da4941db7f8a85997d6281b9b4c5165768e6489) +--- + p2v/conversion.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index b54f971..de2a4b2 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -346,13 +347,35 @@ start_conversion (struct config *config, + } + + /* Read output from the virt-v2v process and echo it through the +- * notify function, until virt-v2v closes the connection. ++ * notify function, until virt-v2v closes the connection. We ++ * actually poll in this loop (albeit it only every 2 seconds) so ++ * that the user won't have to wait too long between pressing the ++ * cancel button and having the conversion cancelled. + */ + while (!is_cancel_requested ()) { ++ int fd = mexp_get_fd (control_h); ++ struct pollfd fds[1]; ++ int rp; + char buf[257]; + ssize_t r; + +- r = read (mexp_get_fd (control_h), buf, sizeof buf - 1); ++ fds[0].fd = fd; ++ fds[0].events = POLLIN; ++ fds[0].revents = 0; ++ rp = poll (fds, 1, 2000 /* ms */); ++ if (rp == -1) { ++ /* See comment about this in miniexpect.c. */ ++ if (errno == EIO) ++ break; ++ set_conversion_error ("poll: %m"); ++ goto out; ++ } ++ else if (rp == 0) ++ /* Timeout. */ ++ continue; ++ /* ... else rp == 1, ignore revents and just do the read. */ ++ ++ r = read (fd, buf, sizeof buf - 1); + if (r == -1) { + /* See comment about this in miniexpect.c. */ + if (errno == EIO) +-- +1.8.3.1 + diff --git a/SOURCES/0118-v2v-Document-that-vCenter-5.0-is-required-RHBZ-11742.patch b/SOURCES/0118-v2v-Document-that-vCenter-5.0-is-required-RHBZ-11742.patch deleted file mode 100644 index 1b1c3a3..0000000 --- a/SOURCES/0118-v2v-Document-that-vCenter-5.0-is-required-RHBZ-11742.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d80e43e17b37af214aa6e81904afc7b7b9c47247 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 13 Apr 2015 11:46:29 +0100 -Subject: [PATCH] v2v: Document that vCenter >= 5.0 is required (RHBZ#1174200). - -vCenter 5.0 was released in 2011. We have not tested against any -earlier versions, but it was reported that it does not work with -vCenter 4. - -Thanks: Sokratis -(cherry picked from commit abf23ece49972111e19147087664e7442d84fdfd) ---- - v2v/virt-v2v.pod | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 033040e..7de265b 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -744,6 +744,8 @@ I<--bridge> option instead. For example: - - Virt-v2v is able to import guests from VMware vCenter Server. - -+vCenter E 5.0 is required. -+ - Note that virt-v2v B import guests directly from an ESXi - hypervisor. - --- -1.8.3.1 - diff --git a/SOURCES/0119-p2v-Gtk-3-workaround-for-RHEL-7.patch b/SOURCES/0119-p2v-Gtk-3-workaround-for-RHEL-7.patch new file mode 100644 index 0000000..9acd3c4 --- /dev/null +++ b/SOURCES/0119-p2v-Gtk-3-workaround-for-RHEL-7.patch @@ -0,0 +1,34 @@ +From eebe36dcdd8343b38c4b8d0327fd09413981a7dd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 21 Jun 2016 14:11:57 +0100 +Subject: [PATCH] p2v: Gtk 3 workaround for RHEL 7. + +New enough to complain about gtk_widget_modify_font, not new enough to +have gtk_style_context. + +Fixes commit ca6fea7616f89775180ab686133052eca18f0e00. + +(cherry picked from commit c87eab35c0b206306f98a2a267e299be32a9e5f2) +--- + p2v/gui.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 764b0f8..7414037 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -1458,7 +1458,11 @@ create_running_dialog (void) + #else + PangoFontDescription *font; + font = pango_font_description_from_string ("Monospace 11"); ++#if GTK_CHECK_VERSION(3,0,0) /* gtk >= 3 */ ++ gtk_widget_override_font (v2v_output, font); ++#else + gtk_widget_modify_font (v2v_output, font); ++#endif + pango_font_description_free (font); + #endif + +-- +1.8.3.1 + diff --git a/SOURCES/0119-v2v-Add-a-man-page-section-on-importing-from-OVA-fil.patch b/SOURCES/0119-v2v-Add-a-man-page-section-on-importing-from-OVA-fil.patch deleted file mode 100644 index 11f23f2..0000000 --- a/SOURCES/0119-v2v-Add-a-man-page-section-on-importing-from-OVA-fil.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 6d1d399ecb2016f12a6bdd6440cd4b5111050098 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 13 Apr 2015 12:01:22 +0100 -Subject: [PATCH] v2v: Add a man page section on importing from OVA files. - -(cherry picked from commit e062093881d66b56c4935054ad409ecf2531880b) ---- - v2v/virt-v2v.pod | 49 ++++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 44 insertions(+), 5 deletions(-) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 7de265b..91e8f3e 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -202,7 +202,8 @@ Set the input method to I. - - In this mode you can read a VMware ova file. Virt-v2v will read the - ova manifest file and check the vmdk volumes for validity (checksums) --as well as analyzing the ovf file, and then convert the guest. -+as well as analyzing the ovf file, and then convert the guest. See -+L below - - =item B<-ic> libvirtURI - -@@ -744,10 +745,9 @@ I<--bridge> option instead. For example: - - Virt-v2v is able to import guests from VMware vCenter Server. - --vCenter E 5.0 is required. -- --Note that virt-v2v B import guests directly from an ESXi --hypervisor. -+vCenter E 5.0 is required. Virt-v2v B import guests -+directly from an ESXi hypervisor. If you don't have vCenter, using -+OVA is recommended instead (see L below). - - 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 -@@ -884,6 +884,45 @@ In this case the output flags are set to write the converted guest to - a temporary directory as this is just an example, but you can also - write to libvirt or any other supported target. - -+=head1 INPUT FROM VMWARE OVA -+ -+Virt-v2v is able to import guests from VMware's OVA (Open -+Virtualization Appliance) files. Only OVAs exported from VMware -+vSphere will work. -+ -+=head2 OVA: 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 OVA: CREATE OVA -+ -+To create an OVA in vSphere, use the "Export OVF Template" option -+(from the VM context menu, or from the File menu). Either "Folder of -+files" (OVF) or "Single file" (OVA) will work, but OVA is probably -+easier to deal with. OVA files are really just uncompressed tar -+files, so you can use commands like C to view their -+contents. -+ -+=head2 OVA: IMPORTING A GUEST -+ -+To import an OVA file called C, do; -+ -+ $ virt-v2v -i ova VM.ova -o local -os /var/tmp -+ -+If you exported the guest as a "Folder of files", I if you -+unpacked the OVA tarball yourself, then you can point virt-v2v at the -+directory containing the files: -+ -+ $ virt-v2v -i ova /path/to/files -o local -os /var/tmp -+ - =head1 INPUT FROM RHEL 5 XEN - - Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts. --- -1.8.3.1 - diff --git a/SOURCES/0120-RHEL-7-v2v-Remove-dcpath-option-from-manual-page-RHB.patch b/SOURCES/0120-RHEL-7-v2v-Remove-dcpath-option-from-manual-page-RHB.patch new file mode 100644 index 0000000..32ece16 --- /dev/null +++ b/SOURCES/0120-RHEL-7-v2v-Remove-dcpath-option-from-manual-page-RHB.patch @@ -0,0 +1,38 @@ +From 6842d01281169683b6654c7629e21b5acf57ff6d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 10:38:47 -0400 +Subject: [PATCH] RHEL 7: v2v: Remove --dcpath option from manual page + (RHBZ#1315237). + +This is no longer required, since RHEL 7.3. +--- + v2v/virt-v2v.pod | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 93f0e77..4ea02ab 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. + +-=item B<--dcpath> Folder/Datacenter +- +-B You don't need to use this parameter if you have +-S 1.2.20>. +- +-For VMware vCenter, override the C parameter used to +-select the datacenter. Virt-v2v can usually calculate this from the +-C URI, but if it gets it wrong, then you can override it using +-this setting. Go to your vCenter web folder interface, eg. +-C (I a trailing slash), +-and examine the C parameter in the URLs that appear on this +-page. +- + =item B<--debug-gc> + + Debug garbage collection and memory allocation. This is only useful +-- +1.8.3.1 + diff --git a/SOURCES/0120-resize-fix-No-space-left-on-device-problem-when-copy.patch b/SOURCES/0120-resize-fix-No-space-left-on-device-problem-when-copy.patch deleted file mode 100644 index 29b302e..0000000 --- a/SOURCES/0120-resize-fix-No-space-left-on-device-problem-when-copy.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 67cdc9c732090a47f7f0345d43614c8b4a527f53 Mon Sep 17 00:00:00 2001 -From: Hu Tao -Date: Mon, 8 Dec 2014 11:20:54 +0800 -Subject: [PATCH] resize: fix 'No space left on device' problem when copying to - an extended partition (RHBZ#1169015) - -Because of the size of an extended partition reported by Linux is always 1024 -bytes, so it will always fail to copy to an extended partition. - -This patch fixes this problem by copying to the offset of an extended -partition in the destination disk. - -Signed-off-by: Hu Tao -(cherry picked from commit 9d6f0b6a86d68438b27a3d783677c63f39ec6627) ---- - resize/resize.ml | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/resize/resize.ml b/resize/resize.ml -index b581b39..b4e8990 100644 ---- a/resize/resize.ml -+++ b/resize/resize.ml -@@ -1152,9 +1152,15 @@ read the man page virt-resize(1). - * source = "/dev/sda2", because the device name only covers - * the first 1K of the partition. Instead, copy the - * source bytes from the parent disk (/dev/sda). -+ * -+ * You can't write directly to the extended partition, -+ * because the size of it reported by Linux is always 1024 -+ * bytes. Instead, write to the offset of the extended -+ * partition in the destination disk (/dev/sdb). - *) - let srcoffset = p.p_part.G.part_start in -- g#copy_device_to_device ~srcoffset ~size:copysize "/dev/sda" target -+ let destoffset = p.p_target_start *^ 512L in -+ g#copy_device_to_device ~srcoffset ~destoffset ~size:copysize "/dev/sda" "/dev/sdb" - ) - | OpIgnore | OpDelete -> () - in --- -1.8.3.1 - diff --git a/SOURCES/0121-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch b/SOURCES/0121-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch deleted file mode 100644 index f1d587b..0000000 --- a/SOURCES/0121-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch +++ /dev/null @@ -1,442 +0,0 @@ -From a72b602cfabd360335a63e70b6cb1abf7e82f69a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 31 Oct 2014 11:02:33 +0000 -Subject: [PATCH] launch: libvirt: Implement drive secrets (RHBZ#1159016). - -Implement the GUESTFS_ADD_DRIVE_OPTS_SECRET argument of -guestfs_add_drive_opts. For libvirt we have to save the secret in -libvirtd first, get a UUID, and then pass the UUID back through the -domain XML. - -(cherry picked from commit 6d6644d52d8092dd4f4add859ebda06bea4b5b56) ---- - bootstrap | 1 + - generator/actions.ml | 2 +- - m4/.gitignore | 4 + - src/launch-libvirt.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 4 files changed, 275 insertions(+), 4 deletions(-) - -diff --git a/bootstrap b/bootstrap -index b4afcdb..70789e3 100755 ---- a/bootstrap -+++ b/bootstrap -@@ -41,6 +41,7 @@ accept4 - areadlink - areadlinkat - arpa_inet -+base64 - byteswap - c-ctype - cloexec -diff --git a/generator/actions.ml b/generator/actions.ml -index ea715d0..4bc043b 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -1452,7 +1452,7 @@ specify the remote username you want. - =item C - - For the C protocol only, this specifies the 'secret' to use when --connecting to the remote device. -+connecting to the remote device. It must be base64 encoded. - - If not given, then a secret matching the given username will be looked up in the - default keychain locations, or if no username is given, then no authentication -diff --git a/m4/.gitignore b/m4/.gitignore -index ed73ab3..b0f8d4b 100644 ---- a/m4/.gitignore -+++ b/m4/.gitignore -@@ -5,6 +5,7 @@ - /argmatch.m4 - /arpa_inet_h.m4 - /asm-underscore.m4 -+/base64.m4 - /btowc.m4 - /byteswap.m4 - /canonicalize-lgpl.m4 -@@ -104,6 +105,7 @@ - /inttypes-pri.m4 - /ioctl.m4 - /i-ring.m4 -+/isatty.m4 - /isc-posix.m4 - /largefile.m4 - /lchown.m4 -@@ -166,6 +168,7 @@ - /printf-posix.m4 - /priv-set.m4 - /progtest.m4 -+/ptsname_r.m4 - /putenv.m4 - /quotearg.m4 - /quote.m4 -@@ -236,6 +239,7 @@ - /thread.m4 - /time_h.m4 - /timespec.m4 -+/ttyname_r.m4 - /uintmax_t.m4 - /ulonglong.m4 - /ungetc.m4 -diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c -index 026fd5a..5daa396 100644 ---- a/src/launch-libvirt.c -+++ b/src/launch-libvirt.c -@@ -49,6 +49,7 @@ - #endif - - #include "glthread/lock.h" -+#include "base64.h" - - #include "guestfs.h" - #include "guestfs-internal.h" -@@ -96,6 +97,27 @@ xmlBufferDetach (xmlBufferPtr buf) - } - #endif - -+#ifdef HAVE_ATTRIBUTE_CLEANUP -+#define CLEANUP_VIRSECRETFREE __attribute__((cleanup(cleanup_virSecretFree))) -+ -+static void -+cleanup_virSecretFree (void *ptr) -+{ -+ virSecretPtr secret_obj = * (virSecretPtr *) ptr; -+ if (secret_obj) -+ virSecretFree (secret_obj); -+} -+ -+#else /* !HAVE_ATTRIBUTE_CLEANUP */ -+#define CLEANUP_VIRSECRETFREE -+#endif -+ -+/* List used to store a mapping of secret to libvirt secret UUID. */ -+struct secret { -+ char *secret; -+ char uuid[VIR_UUID_STRING_BUFLEN]; -+}; -+ - #define DOMAIN_NAME_LEN (8+16+1) /* "guestfs-" + random + \0 */ - - /* Per-handle data. */ -@@ -108,6 +130,8 @@ struct backend_libvirt_data { - char name[DOMAIN_NAME_LEN]; /* random name */ - bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/ - unsigned long qemu_version; /* qemu version (from libvirt) */ -+ struct secret *secrets; /* list of secrets */ -+ size_t nr_secrets; - char *uefi_code; /* UEFI (firmware) code and variables. */ - char *uefi_vars; - }; -@@ -130,6 +154,9 @@ struct libvirt_xml_params { - }; - - static int parse_capabilities (guestfs_h *g, const char *capabilities_xml, struct backend_libvirt_data *data); -+static int add_secret (guestfs_h *g, virConnectPtr conn, struct backend_libvirt_data *data, const struct drive *drv); -+static int find_secret (guestfs_h *g, const struct backend_libvirt_data *data, const struct drive *drv, const char **type, const char **uuid); -+static int have_secret (guestfs_h *g, const struct backend_libvirt_data *data, const struct drive *drv); - static xmlChar *construct_libvirt_xml (guestfs_h *g, const struct libvirt_xml_params *params); - static void debug_appliance_permissions (guestfs_h *g); - static void debug_socket_permissions (guestfs_h *g); -@@ -224,6 +251,8 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) - CLEANUP_FREE xmlChar *xml = NULL; - CLEANUP_FREE char *appliance = NULL; - struct sockaddr_un addr; -+ struct drive *drv; -+ size_t i; - int r; - uint32_t size; - CLEANUP_FREE void *buf = NULL; -@@ -456,6 +485,14 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) - debug (g, "cannot find group 'qemu'"); - } - -+ /* Store any secrets in libvirtd, keeping a mapping from the secret -+ * to its UUID. -+ */ -+ ITER_DRIVES (g, i, drv) { -+ if (add_secret (g, conn, data, drv) == -1) -+ goto cleanup; -+ } -+ - /* Construct the libvirt XML. */ - if (g->verbose) - guestfs___print_timestamped_message (g, "create libvirt XML"); -@@ -1275,6 +1312,8 @@ construct_libvirt_xml_disk (guestfs_h *g, - CLEANUP_FREE char *path = NULL; - int is_host_device; - CLEANUP_FREE char *format = NULL; -+ const char *type, *uuid; -+ int r; - - /* XXX We probably could support this if we thought about it some more. */ - if (drv->iface) { -@@ -1386,9 +1425,15 @@ construct_libvirt_xml_disk (guestfs_h *g, - if (drv->src.username != NULL) { - start_element ("auth") { - attribute ("username", drv->src.username); -- /* TODO: write the drive secret, after first storing it separately -- * in libvirt -- */ -+ r = find_secret (g, data, drv, &type, &uuid); -+ if (r == -1) -+ return -1; -+ if (r == 1) { -+ start_element ("secret") { -+ attribute ("type", type); -+ attribute ("uuid", uuid); -+ } end_element (); -+ } - } end_element (); - } - break; -@@ -1696,6 +1741,216 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, - } - - static int -+construct_libvirt_xml_secret (guestfs_h *g, -+ const struct backend_libvirt_data *data, -+ const struct drive *drv, -+ xmlTextWriterPtr xo) -+{ -+ start_element ("secret") { -+ attribute ("ephemeral", "yes"); -+ attribute ("private", "yes"); -+ start_element ("description") { -+ string_format ("guestfs secret associated with %s %s", -+ data->name, drv->src.u.path); -+ } end_element (); -+ } end_element (); -+ -+ return 0; -+} -+ -+/* If drv->src.secret != NULL, store the secret in libvirt, and save -+ * the UUID so we can retrieve it later. Also there is some slight -+ * variation depending on the protocol. See -+ * http://libvirt.org/formatsecret.html -+ */ -+static int -+add_secret (guestfs_h *g, virConnectPtr conn, -+ struct backend_libvirt_data *data, const struct drive *drv) -+{ -+ CLEANUP_XMLBUFFERFREE xmlBufferPtr xb = NULL; -+ xmlOutputBufferPtr ob; -+ CLEANUP_XMLFREETEXTWRITER xmlTextWriterPtr xo = NULL; -+ CLEANUP_FREE xmlChar *xml = NULL; -+ CLEANUP_VIRSECRETFREE virSecretPtr secret_obj = NULL; -+ const char *secret = drv->src.secret; -+ CLEANUP_FREE unsigned char *secret_raw = NULL; -+ size_t secret_raw_len = 0; -+ size_t i; -+ -+ if (secret == NULL) -+ return 0; -+ -+ /* If it was already stored, don't create another secret. */ -+ if (have_secret (g, data, drv)) -+ return 0; -+ -+ /* Create the XML for the secret. */ -+ xb = xmlBufferCreate (); -+ if (xb == NULL) { -+ perrorf (g, "xmlBufferCreate"); -+ return -1; -+ } -+ ob = xmlOutputBufferCreateBuffer (xb, NULL); -+ if (ob == NULL) { -+ perrorf (g, "xmlOutputBufferCreateBuffer"); -+ return -1; -+ } -+ xo = xmlNewTextWriter (ob); -+ if (xo == NULL) { -+ perrorf (g, "xmlNewTextWriter"); -+ return -1; -+ } -+ -+ if (xmlTextWriterSetIndent (xo, 1) == -1 || -+ xmlTextWriterSetIndentString (xo, BAD_CAST " ") == -1) { -+ perrorf (g, "could not set XML indent"); -+ return -1; -+ } -+ if (xmlTextWriterStartDocument (xo, NULL, NULL, NULL) == -1) { -+ perrorf (g, "xmlTextWriterStartDocument"); -+ return -1; -+ } -+ -+ if (construct_libvirt_xml_secret (g, data, drv, xo) == -1) -+ return -1; -+ -+ if (xmlTextWriterEndDocument (xo) == -1) { -+ perrorf (g, "xmlTextWriterEndDocument"); -+ return -1; -+ } -+ xml = xmlBufferDetach (xb); -+ if (xml == NULL) { -+ perrorf (g, "xmlBufferDetach"); -+ return -1; -+ } -+ -+ debug (g, "libvirt secret XML:\n%s", xml); -+ -+ /* Pass the XML to libvirt. */ -+ secret_obj = virSecretDefineXML (conn, (const char *) xml, 0); -+ if (secret_obj == NULL) { -+ libvirt_error (g, _("could not define libvirt secret")); -+ return -1; -+ } -+ -+ /* For Ceph, we have to base64 decode the secret. For others, we -+ * currently just pass the secret straight through. -+ */ -+ switch (drv->src.protocol) { -+ case drive_protocol_rbd: -+ if (!base64_decode_alloc (secret, strlen (secret), -+ (char **) &secret_raw, &secret_raw_len)) { -+ error (g, _("rbd protocol secret must be base64 encoded")); -+ return -1; -+ } -+ if (secret_raw == NULL) { -+ error (g, _("base64_decode_alloc: %m")); -+ return -1; -+ } -+ break; -+ case drive_protocol_file: -+ case drive_protocol_ftp: -+ case drive_protocol_ftps: -+ case drive_protocol_gluster: -+ case drive_protocol_http: -+ case drive_protocol_https: -+ case drive_protocol_iscsi: -+ case drive_protocol_nbd: -+ case drive_protocol_sheepdog: -+ case drive_protocol_ssh: -+ case drive_protocol_tftp: -+ secret_raw = (unsigned char *) safe_strdup (g, secret); -+ secret_raw_len = strlen (secret); -+ } -+ -+ /* Set the secret. */ -+ if (virSecretSetValue (secret_obj, secret_raw, secret_raw_len, 0) == -1) { -+ libvirt_error (g, _("could not set libvirt secret value")); -+ return -1; -+ } -+ -+ /* Get back the UUID and save it in the private data. */ -+ i = data->nr_secrets; -+ data->nr_secrets++; -+ data->secrets = -+ safe_realloc (g, data->secrets, sizeof (struct secret) * data->nr_secrets); -+ -+ data->secrets[i].secret = safe_strdup (g, secret); -+ -+ if (virSecretGetUUIDString (secret_obj, data->secrets[i].uuid) == -1) { -+ libvirt_error (g, _("could not get UUID from libvirt secret")); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+have_secret (guestfs_h *g, -+ const struct backend_libvirt_data *data, const struct drive *drv) -+{ -+ size_t i; -+ -+ if (drv->src.secret == NULL) -+ return 0; -+ -+ for (i = 0; i < data->nr_secrets; ++i) { -+ if (STREQ (data->secrets[i].secret, drv->src.secret)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* Find a secret previously stored in libvirt. Returns the -+ * attributes. This function returns -1 -+ * if there was an error, 0 if there is no secret, and 1 if the -+ * secret was found and returned. -+ */ -+static int -+find_secret (guestfs_h *g, -+ const struct backend_libvirt_data *data, const struct drive *drv, -+ const char **type, const char **uuid) -+{ -+ size_t i; -+ -+ if (drv->src.secret == NULL) -+ return 0; -+ -+ for (i = 0; i < data->nr_secrets; ++i) { -+ if (STREQ (data->secrets[i].secret, drv->src.secret)) { -+ *uuid = data->secrets[i].uuid; -+ -+ *type = "volume"; -+ -+ switch (drv->src.protocol) { -+ case drive_protocol_rbd: -+ *type = "ceph"; -+ break; -+ case drive_protocol_iscsi: -+ *type = "iscsi"; -+ break; -+ case drive_protocol_file: -+ case drive_protocol_ftp: -+ case drive_protocol_ftps: -+ case drive_protocol_gluster: -+ case drive_protocol_http: -+ case drive_protocol_https: -+ case drive_protocol_nbd: -+ case drive_protocol_sheepdog: -+ case drive_protocol_ssh: -+ case drive_protocol_tftp: -+ /* set to a default value above */ ; -+ } -+ -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int - is_blk (const char *path) - { - struct stat statbuf; -@@ -1717,6 +1972,7 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) - struct backend_libvirt_data *data = datav; - virConnectPtr conn = data->conn; - virDomainPtr dom = data->dom; -+ size_t i; - int ret = 0; - int flags; - -@@ -1751,6 +2007,12 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) - free (data->uefi_vars); - data->uefi_vars = NULL; - -+ for (i = 0; i < data->nr_secrets; ++i) -+ free (data->secrets[i].secret); -+ free (data->secrets); -+ data->secrets = NULL; -+ data->nr_secrets = 0; -+ - return ret; - } - -@@ -1855,6 +2117,10 @@ hot_add_drive_libvirt (guestfs_h *g, void *datav, - return -1; - } - -+ /* If the drive has an associated secret, store it in libvirt. */ -+ if (add_secret (g, conn, data, drv) == -1) -+ return -1; -+ - /* Create the XML for the new disk. */ - xml = construct_libvirt_xml_hot_add_disk (g, data, drv, drv_index); - if (xml == NULL) --- -1.8.3.1 - diff --git a/SOURCES/0121-v2v-Fix-conversion-of-floppy-removable-devices-RHBZ-.patch b/SOURCES/0121-v2v-Fix-conversion-of-floppy-removable-devices-RHBZ-.patch new file mode 100644 index 0000000..a6503fa --- /dev/null +++ b/SOURCES/0121-v2v-Fix-conversion-of-floppy-removable-devices-RHBZ-.patch @@ -0,0 +1,203 @@ +From 8bd7c9c0d10699757e4edd6d3b5b9ae8667fb4a4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 22 Jun 2016 15:04:26 +0100 +Subject: [PATCH] v2v: Fix conversion of floppy removable devices + (RHBZ#1309706). + +The previous code treated floppy disks and CD-ROMs as the same kind of +thing, resulting in malformed libvirt XML. You would see the +following error when importing a guest into libvirt: + + error: Failed to define domain from /tmp/v2vlibvirt063486.xml + error: internal error: Invalid floppy device name: hdb + +because we incorrectly generated this bogus libvirt XML fragment: + + + + + + +This commit models floppy devices as a distinct type, occupying their +own bus ("/dev/fdX"). When writing to libvirt, we generate correct +XML fragments, looking like this: + + + + + + +Miscellaneous other changes were required in the code. There is also +a regression test (see following commit). + +Note this ignores floppy disks in '-o qemu' mode. + +(cherry picked from commit b9613acb94e3328204d96efab0dfc8b8ed1d3368) +--- + v2v/input_libvirtxml.ml | 1 + + v2v/output_libvirt.ml | 6 ++++-- + v2v/output_qemu.ml | 4 ++++ + v2v/target_bus_assignment.ml | 20 ++++++++++++-------- + v2v/test-v2v-i-ova.xml | 2 +- + v2v/types.ml | 1 + + v2v/types.mli | 10 +++++++--- + 7 files changed, 30 insertions(+), 14 deletions(-) + +diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml +index 1202302..a547edd 100644 +--- a/v2v/input_libvirtxml.ml ++++ b/v2v/input_libvirtxml.ml +@@ -297,6 +297,7 @@ let parse_libvirt_xml ?conn xml = + | Some s when String.is_prefix s "sd" -> get_drive_slot s 2 + | Some s when String.is_prefix s "vd" -> get_drive_slot s 2 + | Some s when String.is_prefix s "xvd" -> get_drive_slot s 3 ++ | Some s when String.is_prefix s "fd" -> get_drive_slot s 2 + | Some s -> + warning (f_" was ignored because the device name could not be recognized") s; + None in +diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml +index 05ad931..5a404ee 100644 +--- a/v2v/output_libvirt.ml ++++ b/v2v/output_libvirt.ml +@@ -173,7 +173,6 @@ let create_libvirt_xml ?pool source target_buses guestcaps + e "driver" [ "name", "qemu"; "type", "raw" ] []; + e "target" [ + "dev", drive_prefix ^ drive_name i; +- "bus", bus_name + ] [] + ] + in +@@ -187,7 +186,10 @@ let create_libvirt_xml ?pool source target_buses guestcaps + target_buses.target_ide_bus); + Array.to_list + (Array.mapi (make_disk "scsi" "sd") +- target_buses.target_scsi_bus) ++ target_buses.target_scsi_bus); ++ Array.to_list ++ (Array.mapi (make_disk "floppy" "fd") ++ target_buses.target_floppy_bus) + ] in + append devices disks; + +diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml +index d079ccd..94f80c2 100644 +--- a/v2v/output_qemu.ml ++++ b/v2v/output_qemu.ml +@@ -137,6 +137,10 @@ object + in + Array.iteri make_scsi target_buses.target_scsi_bus; + ++ (* XXX Highly unlikely that anyone cares, but the current ++ * code ignores target_buses.target_floppy_bus. ++ *) ++ + let net_bus = + match guestcaps.gcaps_net_bus with + | Virtio_net -> "virtio-net-pci" +diff --git a/v2v/target_bus_assignment.ml b/v2v/target_bus_assignment.ml +index 5ad8582..bce3a88 100644 +--- a/v2v/target_bus_assignment.ml ++++ b/v2v/target_bus_assignment.ml +@@ -21,11 +21,11 @@ open Common_gettext.Gettext + + open Types + +-(* XXX This doesn't do the right thing for PC legacy floppy devices. *) + let rec target_bus_assignment source targets guestcaps = + let virtio_blk_bus = ref [| |] + and ide_bus = ref [| |] +- and scsi_bus = ref [| |] in ++ and scsi_bus = ref [| |] ++ and floppy_bus = ref [| |] in + + (* Add the fixed disks (targets) to either the virtio-blk or IDE bus, + * depending on whether the guest has virtio drivers or not. +@@ -65,11 +65,14 @@ let rec target_bus_assignment source targets guestcaps = + fun r -> + let t = BusSlotRemovable r in + let bus = +- match r.s_removable_controller with +- | None -> ide_bus (* Wild guess, but should be safe. *) +- | Some Source_virtio_blk -> virtio_blk_bus +- | Some Source_IDE -> ide_bus +- | Some Source_SCSI -> scsi_bus in ++ match r.s_removable_type with ++ | Floppy -> floppy_bus ++ | CDROM -> ++ match r.s_removable_controller with ++ | None -> ide_bus (* Wild guess, but should be safe. *) ++ | Some Source_virtio_blk -> virtio_blk_bus ++ | Some Source_IDE -> ide_bus ++ | Some Source_SCSI -> scsi_bus in + + match r.s_removable_slot with + | None -> +@@ -88,7 +91,8 @@ let rec target_bus_assignment source targets guestcaps = + + { target_virtio_blk_bus = !virtio_blk_bus; + target_ide_bus = !ide_bus; +- target_scsi_bus = !scsi_bus } ++ target_scsi_bus = !scsi_bus; ++ target_floppy_bus = !floppy_bus } + + (* Insert a slot into the bus array, making the array bigger if necessary. *) + and insert bus i slot = +diff --git a/v2v/test-v2v-i-ova.xml b/v2v/test-v2v-i-ova.xml +index bb765e3..6dcfc31 100644 +--- a/v2v/test-v2v-i-ova.xml ++++ b/v2v/test-v2v-i-ova.xml +@@ -27,7 +27,7 @@ + + + +- ++ + + + +diff --git a/v2v/types.ml b/v2v/types.ml +index d082594..7491be4 100644 +--- a/v2v/types.ml ++++ b/v2v/types.ml +@@ -363,6 +363,7 @@ type target_buses = { + target_virtio_blk_bus : target_bus_slot array; + target_ide_bus : target_bus_slot array; + target_scsi_bus : target_bus_slot array; ++ target_floppy_bus : target_bus_slot array; + } + + and target_bus_slot = +diff --git a/v2v/types.mli b/v2v/types.mli +index 18ac138..c1cb245 100644 +--- a/v2v/types.mli ++++ b/v2v/types.mli +@@ -254,10 +254,11 @@ type target_buses = { + target_virtio_blk_bus : target_bus_slot array; + target_ide_bus : target_bus_slot array; + target_scsi_bus : target_bus_slot array; ++ target_floppy_bus : target_bus_slot array; + } + (** Mapping of fixed and removable disks to buses. + +- As shown in the diagram below, there are (currently) three buses ++ As shown in the diagram below, there are (currently) four buses + attached to the target VM. Each contains a chain of fixed or + removable disks. Slots can also be empty. + +@@ -276,8 +277,11 @@ type target_buses = { + ├────┤ hda ├───┤ hdb ├───┤ hdc ├───┤ hdd │ IDE bus + │ └─────┘ └─────┘ └─────┘ └─────┘ + │ ┌─────┐ ┌─────┐ +- └────┤ - ├───┤ vdb │ Virtio-blk bus +- └─────┘ └─────┘ ++ ├────┤ - ├───┤ vdb │ Virtio-blk bus ++ │ └─────┘ └─────┘ ++ │ ┌─────┐ ++ └────┤ fda │ Floppy disks ++ └─────┘ + v} + *) + +-- +1.8.3.1 + diff --git a/SOURCES/0122-v2v-Add-a-regression-test-for-floppy-assignment-RHBZ.patch b/SOURCES/0122-v2v-Add-a-regression-test-for-floppy-assignment-RHBZ.patch new file mode 100644 index 0000000..7c4e501 --- /dev/null +++ b/SOURCES/0122-v2v-Add-a-regression-test-for-floppy-assignment-RHBZ.patch @@ -0,0 +1,186 @@ +From f5ce839611e01ae4aed4125d24690644bb609ef8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 22 Jun 2016 14:48:22 +0100 +Subject: [PATCH] v2v: Add a regression test for floppy assignment + (RHBZ#1309706). + +(cherry picked from commit 0421c5afa330b80c17d8dce88abed2cb53f4f5cc) +--- + v2v/Makefile.am | 3 ++ + v2v/test-v2v-floppy.expected | 8 +++++ + v2v/test-v2v-floppy.sh | 77 ++++++++++++++++++++++++++++++++++++++++++++ + v2v/test-v2v-floppy.xml | 42 ++++++++++++++++++++++++ + 4 files changed, 130 insertions(+) + create mode 100644 v2v/test-v2v-floppy.expected + create mode 100755 v2v/test-v2v-floppy.sh + create mode 100644 v2v/test-v2v-floppy.xml + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 5bffbfe..a996e5d 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -25,6 +25,8 @@ EXTRA_DIST = \ + HACKING \ + test-v2v-cdrom.expected \ + test-v2v-cdrom.xml \ ++ test-v2v-floppy.expected \ ++ test-v2v-floppy.xml \ + test-v2v-i-ova.ovf \ + test-v2v-i-ova.xml \ + test-v2v-i-ova-formats.expected \ +@@ -303,6 +305,7 @@ endif + if ENABLE_APPLIANCE + TESTS += \ + test-v2v-cdrom.sh \ ++ test-v2v-floppy.sh \ + test-v2v-i-ova.sh \ + test-v2v-i-disk.sh \ + test-v2v-machine-readable.sh \ +diff --git a/v2v/test-v2v-floppy.expected b/v2v/test-v2v-floppy.expected +new file mode 100644 +index 0000000..dd74ed9 +--- /dev/null ++++ b/v2v/test-v2v-floppy.expected +@@ -0,0 +1,8 @@ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/v2v/test-v2v-floppy.sh b/v2v/test-v2v-floppy.sh +new file mode 100755 +index 0000000..d4ecfba +--- /dev/null ++++ b/v2v/test-v2v-floppy.sh +@@ -0,0 +1,77 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2015-2016 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 converting a guest with a floppy disk. ++# https://bugzilla.redhat.com/show_bug.cgi?id=1309706 ++ ++unset CDPATH ++export LANG=C ++set -e ++ ++if [ -n "$SKIP_TEST_V2V_FLOPPY_SH" ]; then ++ echo "$0: test skipped because environment variable is set" ++ exit 77 ++fi ++ ++if [ "$(guestfish get-backend)" = "uml" ]; then ++ echo "$0: test skipped because UML backend does not support network" ++ exit 77 ++fi ++ ++abs_builddir="$(pwd)" ++libvirt_uri="test://$abs_builddir/test-v2v-floppy.xml" ++ ++f=../test-data/phony-guests/windows.img ++if ! test -f $f || ! test -s $f; then ++ echo "$0: test skipped because phony Windows image was not created" ++ exit 77 ++fi ++ ++f=../test-data/phony-guests/blank-disk.img ++if ! test -f $f || ! test -s $f; then ++ echo "$0: test skipped because blank-disk.img was not created" ++ exit 77 ++fi ++ ++export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" ++export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win" ++ ++d=test-v2v-floppy.d ++rm -rf $d ++mkdir $d ++ ++$VG virt-v2v --debug-gc \ ++ -i libvirt -ic "$libvirt_uri" windows \ ++ -o local -os $d --no-copy ++ ++# Test the libvirt XML metadata was created. ++test -f $d/windows.xml ++ ++# Grab just the .. output and compare it to what we ++# expect. https://stackoverflow.com/questions/16587218 ++awk '//{p=0;print;next} ;p' \ ++ $d/windows.xml | ++ grep -v ' $d/disks ++ ++if ! diff -u test-v2v-floppy.expected $d/disks; then ++ echo "$0: unexpected disk assignments" ++ cat $d/disks ++ exit 1 ++fi ++ ++rm -r $d +diff --git a/v2v/test-v2v-floppy.xml b/v2v/test-v2v-floppy.xml +new file mode 100644 +index 0000000..41e1bef +--- /dev/null ++++ b/v2v/test-v2v-floppy.xml +@@ -0,0 +1,42 @@ ++ ++ ++ ++ windows ++ 1048576 ++ ++ hvm ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +1.8.3.1 + diff --git a/SOURCES/0122-v2v-allow-configurable-location-for-virtio-drivers.patch b/SOURCES/0122-v2v-allow-configurable-location-for-virtio-drivers.patch deleted file mode 100644 index 1f44b95..0000000 --- a/SOURCES/0122-v2v-allow-configurable-location-for-virtio-drivers.patch +++ /dev/null @@ -1,62 +0,0 @@ -From b89ad1b8ac7f31511254c383573c812ff93abd91 Mon Sep 17 00:00:00 2001 -From: Roman Kagan -Date: Tue, 31 Mar 2015 16:26:38 +0300 -Subject: [PATCH] v2v: allow configurable location for virtio drivers - -Make the location of the Windows virtio drivers overridable with the -environment variable VIRTIO_WIN_DIR, in the same vein as is done for -virt-tools. - -Signed-off-by: Roman Kagan -(cherry picked from commit b8cb5c0d69e7ab8cd8598c0c49f0d65a1366cd62) ---- - v2v/convert_windows.ml | 4 +++- - v2v/virt-v2v.pod | 10 ++++++++-- - 2 files changed, 11 insertions(+), 3 deletions(-) - -diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml -index 1605a91..1e77369 100644 ---- a/v2v/convert_windows.ml -+++ b/v2v/convert_windows.ml -@@ -47,7 +47,9 @@ let convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - try Sys.getenv "VIRT_TOOLS_DATA_DIR" - with Not_found -> Config.datadir // "virt-tools" in - -- let virtio_win_dir = "/usr/share/virtio-win" in -+ let virtio_win_dir = -+ try Sys.getenv "VIRTIO_WIN_DIR" -+ with Not_found -> Config.datadir // "virtio-win" in - - (* Check if RHEV-APT exists. This is optional. *) - let rhev_apt_exe = virt_tools_data_dir // "rhev-apt.exe" in -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 91e8f3e..5ee3bd8 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -620,8 +620,9 @@ below. - - OpenSUSE 10 kernel >= 2.6.25.5-1.1 - -- Windows Drivers are installed from /usr/share/virtio-win -- if present -+ Windows Drivers are installed from the directory pointed to by -+ "VIRTIO_WIN_DIR" environment variable -+ (/usr/share/virtio-win by default) if present - - =head1 RHEL 4 - -@@ -1440,6 +1441,11 @@ not distributed with virt-v2v. - - =back - -+=item C -+ -+This is where VirtIO drivers for Windows are searched for -+(F if unset). See L. -+ - =back - - For other environment variables, see L. --- -1.8.3.1 - diff --git a/SOURCES/0123-daemon-use-btrfs-1-to-get-btrfs-labels.patch b/SOURCES/0123-daemon-use-btrfs-1-to-get-btrfs-labels.patch deleted file mode 100644 index 243e978..0000000 --- a/SOURCES/0123-daemon-use-btrfs-1-to-get-btrfs-labels.patch +++ /dev/null @@ -1,100 +0,0 @@ -From d16202fa66f981949fc49573030721cda35705dc Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 14 Jan 2015 18:55:13 +0100 -Subject: [PATCH] daemon: use btrfs(1) to get btrfs labels - -blkid(1) (or actually, libblkid) seems to handle filesystem labels up -to 127 characters. Considering that btrfs labels can be up to 255 -characters, this means long labels are not read correctly (i.e. get -truncated) by blkid. - -Get the filesystem type, and if btrfs is available invoke -`btrfs filesystem` to get the label of btrfs filesystems. - -Related to RHBZ#1164708. - -(cherry picked from commit 6db3c100e7c18820ff9ecc22415940eb5fedc64e) ---- - daemon/blkid.c | 8 ++++++++ - daemon/btrfs.c | 24 ++++++++++++++++++++++++ - daemon/daemon.h | 3 +++ - 3 files changed, 35 insertions(+) - -diff --git a/daemon/blkid.c b/daemon/blkid.c -index b98c155..e8e7b58 100644 ---- a/daemon/blkid.c -+++ b/daemon/blkid.c -@@ -26,6 +26,7 @@ - - #include "daemon.h" - #include "actions.h" -+#include "optgroups.h" - - GUESTFSD_EXT_CMD(str_blkid, blkid); - -@@ -76,6 +77,13 @@ do_vfs_type (const mountable_t *mountable) - char * - do_vfs_label (const mountable_t *mountable) - { -+ CLEANUP_FREE char *type = do_vfs_type (mountable); -+ -+ if (type) { -+ if (STREQ (type, "btrfs") && optgroup_btrfs_available ()) -+ return btrfs_get_label (mountable->device); -+ } -+ - return get_blkid_tag (mountable->device, "LABEL"); - } - -diff --git a/daemon/btrfs.c b/daemon/btrfs.c -index 7a4d43d..86bad36 100644 ---- a/daemon/btrfs.c -+++ b/daemon/btrfs.c -@@ -42,6 +42,30 @@ optgroup_btrfs_available (void) - return prog_exists (str_btrfs) && filesystem_available ("btrfs") > 0; - } - -+char * -+btrfs_get_label (const char *device) -+{ -+ int r; -+ CLEANUP_FREE char *err = NULL; -+ char *out = NULL; -+ size_t len; -+ -+ r = command (&out, &err, str_btrfs, "filesystem", "label", -+ device, NULL); -+ if (r == -1) { -+ reply_with_error ("%s", err); -+ free (out); -+ return NULL; -+ } -+ -+ /* Trim trailing \n if present. */ -+ len = strlen (out); -+ if (len > 0 && out[len-1] == '\n') -+ out[len-1] = '\0'; -+ -+ return out; -+} -+ - /* Takes optional arguments, consult optargs_bitmask. */ - int - do_btrfs_filesystem_resize (const char *filesystem, int64_t size) -diff --git a/daemon/daemon.h b/daemon/daemon.h -index f442efd..24ee46a 100644 ---- a/daemon/daemon.h -+++ b/daemon/daemon.h -@@ -257,6 +257,9 @@ extern int copy_xattrs (const char *src, const char *dest); - /* Documented in xfs_admin(8). */ - #define XFS_LABEL_MAX 12 - -+/*-- in btrfs.c --*/ -+extern char *btrfs_get_label (const char *device); -+ - /* ordinary daemon functions use these to indicate errors - * NB: you don't need to prefix the string with the current command, - * it is added automatically by the client-side RPC stubs. --- -1.8.3.1 - diff --git a/SOURCES/0123-p2v-improve-error-message-for-sudo-with-password.patch b/SOURCES/0123-p2v-improve-error-message-for-sudo-with-password.patch new file mode 100644 index 0000000..5e5a84c --- /dev/null +++ b/SOURCES/0123-p2v-improve-error-message-for-sudo-with-password.patch @@ -0,0 +1,66 @@ +From 112cec4ab7334c92aaea99f11ce4a669d0691839 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 23 Jun 2016 11:07:18 +0200 +Subject: [PATCH] p2v: improve error message for sudo with password + +Print a better error message when the non-root user on the conversion +server requires a password to use sudo, and p2v is told to use sudo. + +See also RHZ#1340809. + +(cherry picked from commit 5b6a8e086264c85fb048c0eadff6c34351663133) +--- + p2v/ssh.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index a8c762d..f2c849f 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -98,6 +98,7 @@ static void free_regexps (void) __attribute__((destructor)); + + static pcre *password_re; + static pcre *ssh_message_re; ++static pcre *sudo_password_re; + static pcre *prompt_re; + static pcre *version_re; + static pcre *feature_libguestfs_rewrite_re; +@@ -141,6 +142,7 @@ compile_regexps (void) + + COMPILE (password_re, "password:", 0); + COMPILE (ssh_message_re, "(ssh: .*)", 0); ++ COMPILE (sudo_password_re, "sudo: a password is required", 0); + /* The magic synchronization strings all match this expression. See + * start_ssh function below. + */ +@@ -161,6 +163,7 @@ free_regexps (void) + { + pcre_free (password_re); + pcre_free (ssh_message_re); ++ pcre_free (sudo_password_re); + pcre_free (prompt_re); + pcre_free (version_re); + pcre_free (feature_libguestfs_rewrite_re); +@@ -546,6 +549,7 @@ test_connection (struct config *config) + (mexp_regexp[]) { + { 100, .re = version_re }, + { 101, .re = prompt_re }, ++ { 102, .re = sudo_password_re }, + { 0 } + }, ovector, ovecsize)) { + case 100: /* Got version string. */ +@@ -560,6 +564,11 @@ test_connection (struct config *config) + case 101: /* Got the prompt. */ + goto end_of_version; + ++ case 102: ++ mexp_close (h); ++ set_ssh_error ("sudo for user '%s' requires a password", config->username); ++ return -1; ++ + case MEXP_EOF: + mexp_close (h); + set_ssh_error ("unexpected end of file waiting virt-v2v --version output"); +-- +1.8.3.1 + diff --git a/SOURCES/0124-daemon-use-ntfslabel-1-to-get-ntfs-labels.patch b/SOURCES/0124-daemon-use-ntfslabel-1-to-get-ntfs-labels.patch deleted file mode 100644 index 7eb2cd4..0000000 --- a/SOURCES/0124-daemon-use-ntfslabel-1-to-get-ntfs-labels.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 0c4c35fc3efe4a82b644dfff8e93119fd10ff5a4 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 14 Jan 2015 18:59:57 +0100 -Subject: [PATCH] daemon: use ntfslabel(1) to get ntfs labels - -blkid(1) (or actually, libblkid) seems to handle filesystem labels up -to 127 characters. Considering that btrfs labels can be up to 128 -characters, this means long labels are not read correctly (i.e. get -truncated) by blkid. Furthermore, ntfs labels are actually unicode, -and libblkid seems to not decode them correctly. - -Hence, if ntfsprogs is available invoke `ntfslabel` to get the label -of ntfs filesystems. - -Related to RHBZ#1164708. - -(cherry picked from commit 8ad667f1983e98347f4d292c07f971d5362ff052) ---- - daemon/blkid.c | 2 ++ - daemon/daemon.h | 3 +++ - daemon/ntfs.c | 24 ++++++++++++++++++++++++ - 3 files changed, 29 insertions(+) - -diff --git a/daemon/blkid.c b/daemon/blkid.c -index e8e7b58..1ac42b4 100644 ---- a/daemon/blkid.c -+++ b/daemon/blkid.c -@@ -82,6 +82,8 @@ do_vfs_label (const mountable_t *mountable) - if (type) { - if (STREQ (type, "btrfs") && optgroup_btrfs_available ()) - return btrfs_get_label (mountable->device); -+ if (STREQ (type, "ntfs") && optgroup_ntfsprogs_available ()) -+ return ntfs_get_label (mountable->device); - } - - return get_blkid_tag (mountable->device, "LABEL"); -diff --git a/daemon/daemon.h b/daemon/daemon.h -index 24ee46a..e65bcb0 100644 ---- a/daemon/daemon.h -+++ b/daemon/daemon.h -@@ -260,6 +260,9 @@ extern int copy_xattrs (const char *src, const char *dest); - /*-- in btrfs.c --*/ - extern char *btrfs_get_label (const char *device); - -+/*-- in ntfs.c --*/ -+extern char *ntfs_get_label (const char *device); -+ - /* ordinary daemon functions use these to indicate errors - * NB: you don't need to prefix the string with the current command, - * it is added automatically by the client-side RPC stubs. -diff --git a/daemon/ntfs.c b/daemon/ntfs.c -index 762ca88..f1d12e0 100644 ---- a/daemon/ntfs.c -+++ b/daemon/ntfs.c -@@ -33,6 +33,7 @@ - GUESTFSD_EXT_CMD(str_ntfs3g_probe, ntfs-3g.probe); - GUESTFSD_EXT_CMD(str_ntfsresize, ntfsresize); - GUESTFSD_EXT_CMD(str_ntfsfix, ntfsfix); -+GUESTFSD_EXT_CMD(str_ntfslabel, ntfslabel); - - int - optgroup_ntfs3g_available (void) -@@ -46,6 +47,29 @@ optgroup_ntfsprogs_available (void) - return prog_exists (str_ntfsresize); - } - -+char * -+ntfs_get_label (const char *device) -+{ -+ int r; -+ CLEANUP_FREE char *err = NULL; -+ char *out = NULL; -+ size_t len; -+ -+ r = command (&out, &err, str_ntfslabel, device, NULL); -+ if (r == -1) { -+ reply_with_error ("%s", err); -+ free (out); -+ return NULL; -+ } -+ -+ /* Trim trailing \n if present. */ -+ len = strlen (out); -+ if (len > 0 && out[len-1] == '\n') -+ out[len-1] = '\0'; -+ -+ return out; -+} -+ - int - do_ntfs_3g_probe (int rw, const char *device) - { --- -1.8.3.1 - diff --git a/SOURCES/0124-p2v-Force-bash-as-the-remote-shell.patch b/SOURCES/0124-p2v-Force-bash-as-the-remote-shell.patch new file mode 100644 index 0000000..5fac537 --- /dev/null +++ b/SOURCES/0124-p2v-Force-bash-as-the-remote-shell.patch @@ -0,0 +1,60 @@ +From 2a0fc9580c0b169f3c1d884e300d8b3d59678431 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 11:19:37 +0100 +Subject: [PATCH] p2v: Force bash as the remote shell. + +As described in the comment, this solves a number of problems with +non-standard remote configurations. + +I tested this with: + + - tcsh + - zsh + - ksh + +and all behaved correctly. + +(cherry picked from commit d41cf142e1eb285eca798889d3b6a955afffbe32) +--- + p2v/ssh.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index f2c849f..d2c8035 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -416,13 +416,28 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + if (!wait_prompt) + return h; + +- /* Synchronize with the command prompt and set it to a known string. */ +- +- /* Note that we cannot control the initial prompt. It would involve ++ /* Ensure we are running bash, set environment variables, and ++ * synchronize with the command prompt and set it to a known ++ * string. There are multiple issues being solved here: ++ * ++ * We cannot control the initial shell prompt. It would involve + * changing the remote SSH configuration (AcceptEnv). However what + * we can do is to repeatedly send 'export PS1=' commands + * until we synchronize with the remote shell. ++ * ++ * We don't know if the user is using a Bourne-like shell (eg sh, ++ * bash) or csh/tcsh. Setting environment variables works ++ * differently. ++ * ++ * We don't know how command line editing is set up ++ * (https://bugzilla.redhat.com/1314244#c9). + */ ++ if (mexp_printf (h, "exec bash --noediting --noprofile\n") == -1) { ++ set_ssh_error ("setting bash as remote shell: %m"); ++ mexp_close (h); ++ return NULL; ++ } ++ + saved_timeout = mexp_get_timeout_ms (h); + mexp_set_timeout (h, 2); + +-- +1.8.3.1 + diff --git a/SOURCES/0125-mknod-filter-modes-in-mkfifo-mknod_b-mknod_c-RHBZ-11.patch b/SOURCES/0125-mknod-filter-modes-in-mkfifo-mknod_b-mknod_c-RHBZ-11.patch deleted file mode 100644 index ce4ae89..0000000 --- a/SOURCES/0125-mknod-filter-modes-in-mkfifo-mknod_b-mknod_c-RHBZ-11.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 549bd2733e2530b74632964b2e28548a5704114e Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 15 Jan 2015 14:40:17 +0100 -Subject: [PATCH] mknod: filter modes in mkfifo, mknod_b, mknod_c - (RHBZ#1182463). - -Since mkfifo, mknod_b, and mknod_c add the correct file type to the -modes of the resulting file, make sure the specified mode contains only -permissions bits. - -(cherry picked from commit 8b9ca28e111e38eafe8db7265e7fe18c5f31b460) ---- - daemon/mknod.c | 15 +++++++++++++++ - generator/actions.ml | 21 ++++++++++++++++++--- - 2 files changed, 33 insertions(+), 3 deletions(-) - -diff --git a/daemon/mknod.c b/daemon/mknod.c -index 7f71210..9af8701 100644 ---- a/daemon/mknod.c -+++ b/daemon/mknod.c -@@ -38,6 +38,15 @@ optgroup_mknod_available (void) - return 1; - } - -+#define CHECK_MODE \ -+ do { \ -+ if ((mode & ~07777) != 0) { \ -+ reply_with_error ("%o: mode must specify only file permission bits", \ -+ (unsigned int) mode); \ -+ return -1; \ -+ } \ -+ } while (0) -+ - int - do_mknod (int mode, int devmajor, int devminor, const char *path) - { -@@ -63,18 +72,24 @@ do_mknod (int mode, int devmajor, int devminor, const char *path) - int - do_mkfifo (int mode, const char *path) - { -+ CHECK_MODE; -+ - return do_mknod (mode | S_IFIFO, 0, 0, path); - } - - int - do_mknod_b (int mode, int devmajor, int devminor, const char *path) - { -+ CHECK_MODE; -+ - return do_mknod (mode | S_IFBLK, devmajor, devminor, path); - } - - int - do_mknod_c (int mode, int devmajor, int devminor, const char *path) - { -+ CHECK_MODE; -+ - return do_mknod (mode | S_IFCHR, devmajor, devminor, path); - } - -diff --git a/generator/actions.ml b/generator/actions.ml -index 4bc043b..263c6f3 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -6104,7 +6104,9 @@ The mode actually set is affected by the umask." }; - InitScratchFS, Always, TestResult ( - [["mkfifo"; "0o777"; "/mkfifo"]; - ["stat"; "/mkfifo"]], -- "S_ISFIFO (ret->mode) && (ret->mode & 0777) == 0755"), [] -+ "S_ISFIFO (ret->mode) && (ret->mode & 0777) == 0755"), []; -+ InitScratchFS, Always, TestLastFail ( -+ [["mkfifo"; "0o20777"; "/mkfifo-2"]]), []; - ]; - shortdesc = "make FIFO (named pipe)"; - longdesc = "\ -@@ -6112,6 +6114,9 @@ This call creates a FIFO (named pipe) called C with - mode C. It is just a convenient wrapper around - C. - -+Unlike with C, C B contain only permissions -+bits. -+ - The mode actually set is affected by the umask." }; - - { defaults with -@@ -6123,7 +6128,9 @@ The mode actually set is affected by the umask." }; - InitScratchFS, Always, TestResult ( - [["mknod_b"; "0o777"; "99"; "66"; "/mknod_b"]; - ["stat"; "/mknod_b"]], -- "S_ISBLK (ret->mode) && (ret->mode & 0777) == 0755"), [] -+ "S_ISBLK (ret->mode) && (ret->mode & 0777) == 0755"), []; -+ InitScratchFS, Always, TestLastFail ( -+ [["mknod_b"; "0o10777"; "99"; "66"; "/mknod_b-2"]]), []; - ]; - shortdesc = "make block device node"; - longdesc = "\ -@@ -6131,6 +6138,9 @@ This call creates a block device node called C with - mode C and device major/minor C and C. - It is just a convenient wrapper around C. - -+Unlike with C, C B contain only permissions -+bits. -+ - The mode actually set is affected by the umask." }; - - { defaults with -@@ -6142,7 +6152,9 @@ The mode actually set is affected by the umask." }; - InitScratchFS, Always, TestResult ( - [["mknod_c"; "0o777"; "99"; "66"; "/mknod_c"]; - ["stat"; "/mknod_c"]], -- "S_ISCHR (ret->mode) && (ret->mode & 0777) == 0755"), [] -+ "S_ISCHR (ret->mode) && (ret->mode & 0777) == 0755"), []; -+ InitScratchFS, Always, TestLastFail ( -+ [["mknod_c"; "0o20777"; "99"; "66"; "/mknod_c-2"]]), []; - ]; - shortdesc = "make char device node"; - longdesc = "\ -@@ -6150,6 +6162,9 @@ This call creates a char device node called C with - mode C and device major/minor C and C. - It is just a convenient wrapper around C. - -+Unlike with C, C B contain only permissions -+bits. -+ - The mode actually set is affected by the umask." }; - - { defaults with --- -1.8.3.1 - diff --git a/SOURCES/0125-p2v-Set-LANG-C-in-the-remote-shell-so-we-can-match-o.patch b/SOURCES/0125-p2v-Set-LANG-C-in-the-remote-shell-so-we-can-match-o.patch new file mode 100644 index 0000000..2ec43cf --- /dev/null +++ b/SOURCES/0125-p2v-Set-LANG-C-in-the-remote-shell-so-we-can-match-o.patch @@ -0,0 +1,39 @@ +From 5ca9876f652f093230ed8c4f50463a64b76dce62 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 11:27:01 +0100 +Subject: [PATCH] p2v: Set LANG=C in the remote shell so we can match on error + messages. + +Since commit 5b6a8e086264c85fb048c0eadff6c34351663133 we are now +matching on error messages, and therefore we must set LANG=C. + +(cherry picked from commit 5e794b86072cfaa1d2017d93bd3a24be72636c02) +--- + p2v/ssh.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index d2c8035..aa070d5 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -425,6 +425,8 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + * we can do is to repeatedly send 'export PS1=' commands + * until we synchronize with the remote shell. + * ++ * Since we parse error messages, we must set LANG=C. ++ * + * We don't know if the user is using a Bourne-like shell (eg sh, + * bash) or csh/tcsh. Setting environment variables works + * differently. +@@ -455,7 +457,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + /* The purpose of the '' inside the string is to ensure we don't + * mistake the command echo for the prompt. + */ +- if (mexp_printf (h, "export PS1='###''%s''### '\n", magic) == -1) { ++ if (mexp_printf (h, "export LANG=C PS1='###''%s''### '\n", magic) == -1) { + set_ssh_error ("random_string: %m"); + mexp_close (h); + return NULL; +-- +1.8.3.1 + diff --git a/SOURCES/0126-fish-Move-is_true-function-to-library-utilities.patch b/SOURCES/0126-fish-Move-is_true-function-to-library-utilities.patch deleted file mode 100644 index 855f1ab..0000000 --- a/SOURCES/0126-fish-Move-is_true-function-to-library-utilities.patch +++ /dev/null @@ -1,152 +0,0 @@ -From b361a8a13b4cea045315a018a79374e0203ad1fc Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 17 Dec 2014 12:34:53 +0000 -Subject: [PATCH] fish: Move 'is_true' function to library utilities. - -The 'is_true' function can be useful elsewhere, not just for parsing -guestfish command parameters. - -This is just code motion. - -(cherry picked from commit bdcd2fabe9a5ba6f61e662986fcd92e352f203c0) ---- - fish/fish.c | 26 -------------------------- - generator/fish.ml | 21 ++++++++++++++++----- - src/guestfs-internal-frontend.h | 1 + - src/utils.c | 23 +++++++++++++++++++++++ - 4 files changed, 40 insertions(+), 31 deletions(-) - -diff --git a/fish/fish.c b/fish/fish.c -index 981a7d4..6d07f36 100644 ---- a/fish/fish.c -+++ b/fish/fish.c -@@ -1293,32 +1293,6 @@ print_table (char *const *argv) - printf ("%s: %s\n", argv[i], argv[i+1]); - } - --int --is_true (const char *str) --{ -- /* Similar to Tcl_GetBoolean. */ -- -- if (STREQ (str, "1") || -- STRCASEEQ (str, "true") || -- STRCASEEQ (str, "t") || -- STRCASEEQ (str, "yes") || -- STRCASEEQ (str, "y") || -- STRCASEEQ (str, "on")) -- return 1; -- -- if (STREQ (str, "0") || -- STRCASEEQ (str, "false") || -- STRCASEEQ (str, "f") || -- STRCASEEQ (str, "no") || -- STRCASEEQ (str, "n") || -- STRCASEEQ (str, "off")) -- return 0; -- -- fprintf (stderr, _("%s: '%s': invalid boolean value, use 'true' or 'false'\n"), -- program_name, str); -- return -1; --} -- - /* Free strings from a non-NULL terminated char** */ - static void - free_n_strings (char **str, size_t len) -diff --git a/generator/fish.ml b/generator/fish.ml -index 3f53ffa..6d6802a 100644 ---- a/generator/fish.ml -+++ b/generator/fish.ml -@@ -84,12 +84,15 @@ let generate_fish_cmds () = - pr "#include \n"; - pr "#include \n"; - pr "#include \n"; -+ pr "#include \n"; - pr "\n"; - pr "#include \"c-ctype.h\"\n"; - pr "#include \"full-write.h\"\n"; - pr "#include \"xstrtol.h\"\n"; - pr "\n"; -- pr "#include \n"; -+ pr "#include \"guestfs.h\"\n"; -+ pr "#include \"guestfs-internal-frontend.h\"\n"; -+ pr "\n"; - pr "#include \"fish.h\"\n"; - pr "#include \"fish-cmds.h\"\n"; - pr "#include \"options.h\"\n"; -@@ -479,8 +482,12 @@ Guestfish will prompt for these separately." - pr " input_lineno++;\n"; - pr " if (%s == NULL) goto out_%s;\n" name name - | Bool name -> -- pr " switch (is_true (argv[i++])) {\n"; -- pr " case -1: goto out_%s;\n" name; -+ pr " switch (guestfs___is_true (argv[i++])) {\n"; -+ pr " case -1:\n"; -+ pr " fprintf (stderr,\n"; -+ pr " _(\"%%s: '%%s': invalid boolean value, use 'true' or 'false'\\n\"),\n"; -+ pr " program_name, argv[i-1]);\n"; -+ pr " goto out_%s;\n" name; - pr " case 0: %s = 0; break;\n" name; - pr " default: %s = 1;\n" name; - pr " }\n" -@@ -518,8 +525,12 @@ Guestfish will prompt for these separately." - pr "if (STRPREFIX (argv[i], \"%s:\")) {\n" n; - (match argt with - | OBool n -> -- pr " switch (is_true (&argv[i][%d])) {\n" (len+1); -- pr " case -1: goto out;\n"; -+ pr " switch (guestfs___is_true (&argv[i][%d])) {\n" (len+1); -+ pr " case -1:\n"; -+ pr " fprintf (stderr,\n"; -+ pr " _(\"%%s: '%%s': invalid boolean value, use 'true' or 'false'\\n\"),\n"; -+ pr " program_name, &argv[i][%d]);\n" (len+1); -+ pr " goto out;\n"; - pr " case 0: optargs_s.%s = 0; break;\n" n; - pr " default: optargs_s.%s = 1;\n" n; - pr " }\n" -diff --git a/src/guestfs-internal-frontend.h b/src/guestfs-internal-frontend.h -index 5c5d957..ba3ddde 100644 ---- a/src/guestfs-internal-frontend.h -+++ b/src/guestfs-internal-frontend.h -@@ -105,6 +105,7 @@ extern char **guestfs___split_string (char sep, const char *); - extern char *guestfs___exit_status_to_string (int status, const char *cmd_name, char *buffer, size_t buflen); - extern int guestfs___random_string (char *ret, size_t len); - extern char *guestfs___drive_name (size_t index, char *ret); -+extern int guestfs___is_true (const char *str); - - /* These functions are used internally by the CLEANUP_* macros. - * Don't call them directly. -diff --git a/src/utils.c b/src/utils.c -index be7f643..11c6953 100644 ---- a/src/utils.c -+++ b/src/utils.c -@@ -270,3 +270,26 @@ guestfs___drive_name (size_t index, char *ret) - *ret = '\0'; - return ret; - } -+ -+/* Similar to Tcl_GetBoolean. */ -+int -+guestfs___is_true (const char *str) -+{ -+ if (STREQ (str, "1") || -+ STRCASEEQ (str, "true") || -+ STRCASEEQ (str, "t") || -+ STRCASEEQ (str, "yes") || -+ STRCASEEQ (str, "y") || -+ STRCASEEQ (str, "on")) -+ return 1; -+ -+ if (STREQ (str, "0") || -+ STRCASEEQ (str, "false") || -+ STRCASEEQ (str, "f") || -+ STRCASEEQ (str, "no") || -+ STRCASEEQ (str, "n") || -+ STRCASEEQ (str, "off")) -+ return 0; -+ -+ return -1; -+} --- -1.8.3.1 - diff --git a/SOURCES/0126-sparsify-Move-statvfs-wrapper-function-to-mllib.patch b/SOURCES/0126-sparsify-Move-statvfs-wrapper-function-to-mllib.patch new file mode 100644 index 0000000..0c3b0f6 --- /dev/null +++ b/SOURCES/0126-sparsify-Move-statvfs-wrapper-function-to-mllib.patch @@ -0,0 +1,302 @@ +From c2f3c3eadc4f130a411c6fc259e65d30291bfd0c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 13:10:35 +0100 +Subject: [PATCH] sparsify: Move statvfs wrapper function to mllib. + +We wish to use this function in virt-v2v too, so move it to the common +directory. + +No functional change. + +(cherry picked from commit 24130d787256dc3d9e37e85b1ba35ac7dbeb86a1) +--- + mllib/Makefile.am | 3 +++ + mllib/StatVFS.ml | 21 +++++++++++++++++++++ + mllib/StatVFS.mli | 23 +++++++++++++++++++++++ + mllib/statvfs-c.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + po/POTFILES | 2 +- + po/POTFILES-ml | 1 + + sparsify/Makefile.am | 3 ++- + sparsify/copying.ml | 5 +---- + sparsify/statvfs-c.c | 50 -------------------------------------------------- + 9 files changed, 102 insertions(+), 56 deletions(-) + create mode 100644 mllib/StatVFS.ml + create mode 100644 mllib/StatVFS.mli + create mode 100644 mllib/statvfs-c.c + delete mode 100644 sparsify/statvfs-c.c + +diff --git a/mllib/Makefile.am b/mllib/Makefile.am +index e0f1987..0a6dd93 100644 +--- a/mllib/Makefile.am ++++ b/mllib/Makefile.am +@@ -36,6 +36,7 @@ SOURCES_MLI = \ + planner.mli \ + progress.mli \ + regedit.mli \ ++ StatVFS.mli \ + URI.mli + + SOURCES_ML = \ +@@ -50,6 +51,7 @@ SOURCES_ML = \ + mkdtemp.ml \ + planner.ml \ + regedit.ml \ ++ StatVFS.ml \ + JSON.ml \ + curl.ml + +@@ -60,6 +62,7 @@ SOURCES_C = \ + fsync-c.c \ + mkdtemp-c.c \ + progress-c.c \ ++ statvfs-c.c \ + uri-c.c + + if HAVE_OCAML +diff --git a/mllib/StatVFS.ml b/mllib/StatVFS.ml +new file mode 100644 +index 0000000..98e6d22 +--- /dev/null ++++ b/mllib/StatVFS.ml +@@ -0,0 +1,21 @@ ++(* virt tools interface to statvfs ++ * Copyright (C) 2016 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. ++ *) ++ ++(** Binding for [statvfs], but just for getting disk free space. *) ++ ++external free_space : string -> int64 = "guestfs_int_mllib_statvfs_free_space" +diff --git a/mllib/StatVFS.mli b/mllib/StatVFS.mli +new file mode 100644 +index 0000000..b1b8834 +--- /dev/null ++++ b/mllib/StatVFS.mli +@@ -0,0 +1,23 @@ ++(* virt tools interface to statvfs ++ * Copyright (C) 2016 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. ++ *) ++ ++(** Binding for [statvfs], but just for getting disk free space. *) ++ ++val free_space : string -> int64 ++(** [free_space path] returns the free space available on the ++ filesystem that contains [path], in bytes. *) +diff --git a/mllib/statvfs-c.c b/mllib/statvfs-c.c +new file mode 100644 +index 0000000..5c10531 +--- /dev/null ++++ b/mllib/statvfs-c.c +@@ -0,0 +1,50 @@ ++/* virt tools interface to statvfs ++ * Copyright (C) 2013-2016 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 ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++extern value guestfs_int_mllib_statvfs_free_space (value pathv); ++ ++value ++guestfs_int_mllib_statvfs_free_space (value pathv) ++{ ++ CAMLparam1 (pathv); ++ CAMLlocal1 (rv); ++ struct statvfs buf; ++ int64_t free_space; ++ ++ if (statvfs (String_val (pathv), &buf) == -1) { ++ perror ("statvfs"); ++ caml_failwith ("statvfs"); ++ } ++ ++ free_space = (int64_t) buf.f_bsize * buf.f_bavail; ++ rv = caml_copy_int64 (free_space); ++ ++ CAMLreturn (rv); ++} +diff --git a/po/POTFILES b/po/POTFILES +index 1252d8b..bef6540 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -266,6 +266,7 @@ mllib/dummy.c + mllib/fsync-c.c + mllib/mkdtemp-c.c + mllib/progress-c.c ++mllib/statvfs-c.c + mllib/uri-c.c + ocaml/guestfs-c-actions.c + ocaml/guestfs-c-errnos.c +@@ -292,7 +293,6 @@ rescue/rescue.c + rescue/test-virt-rescue.pl + resize/test-virt-resize.pl + ruby/ext/guestfs/_guestfs.c +-sparsify/statvfs-c.c + src/actions-0.c + src/actions-1.c + src/actions-2.c +diff --git a/po/POTFILES-ml b/po/POTFILES-ml +index 2b9bba1..5937ff5 100644 +--- a/po/POTFILES-ml ++++ b/po/POTFILES-ml +@@ -38,6 +38,7 @@ dib/utils.ml + get-kernel/get_kernel.ml + mllib/JSON.ml + mllib/JSON_tests.ml ++mllib/StatVFS.ml + mllib/URI.ml + mllib/common_gettext.ml + mllib/common_utils.ml +diff --git a/sparsify/Makefile.am b/sparsify/Makefile.am +index 9df3e1f..9dd9179 100644 +--- a/sparsify/Makefile.am ++++ b/sparsify/Makefile.am +@@ -39,7 +39,7 @@ SOURCES_C = \ + ../fish/progress.c \ + ../mllib/dev_t-c.c \ + ../mllib/progress-c.c \ +- statvfs-c.c ++ ../mllib/statvfs-c.c + + if HAVE_OCAML + +@@ -61,6 +61,7 @@ BOBJECTS = \ + $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/progress.cmo \ ++ $(top_builddir)/mllib/StatVFS.cmo \ + $(SOURCES_ML:.ml=.cmo) + XOBJECTS = $(BOBJECTS:.cmo=.cmx) + +diff --git a/sparsify/copying.ml b/sparsify/copying.ml +index 83cbec7..003dbf8 100644 +--- a/sparsify/copying.ml ++++ b/sparsify/copying.ml +@@ -31,9 +31,6 @@ open Cmdline + + module G = Guestfs + +-external statvfs_free_space : string -> int64 = +- "virt_sparsify_statvfs_free_space" +- + type tmp_place = + | Directory of string | Block_device of string | Prebuilt_file of string + +@@ -100,7 +97,7 @@ let run indisk outdisk check_tmpdir compress convert + virtual_size (human_size virtual_size); + + let print_warning () = +- let free_space = statvfs_free_space tmpdir in ++ let free_space = StatVFS.free_space tmpdir in + let extra_needed = virtual_size -^ free_space in + if extra_needed > 0L then ( + warning (f_"\ +diff --git a/sparsify/statvfs-c.c b/sparsify/statvfs-c.c +deleted file mode 100644 +index 76bff0b..0000000 +--- a/sparsify/statvfs-c.c ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* virt-sparsify - interface to statvfs +- * Copyright (C) 2013 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 +- +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +- +-#pragma GCC diagnostic ignored "-Wmissing-prototypes" +- +-value +-virt_sparsify_statvfs_free_space (value pathv) +-{ +- CAMLparam1 (pathv); +- CAMLlocal1 (rv); +- struct statvfs buf; +- int64_t free_space; +- +- if (statvfs (String_val (pathv), &buf) == -1) { +- perror ("statvfs"); +- caml_failwith ("statvfs"); +- } +- +- free_space = (int64_t) buf.f_bsize * buf.f_bavail; +- rv = caml_copy_int64 (free_space); +- +- CAMLreturn (rv); +-} +-- +1.8.3.1 + diff --git a/SOURCES/0127-environment-Use-guestfs___is_true-when-parsing-vario.patch b/SOURCES/0127-environment-Use-guestfs___is_true-when-parsing-vario.patch deleted file mode 100644 index aca8466..0000000 --- a/SOURCES/0127-environment-Use-guestfs___is_true-when-parsing-vario.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 05105da1347d3d7e9fbc41e0a14b8cd18905b60b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 17 Dec 2014 12:52:46 +0000 -Subject: [PATCH] environment: Use guestfs___is_true when parsing various - boolean environment variables (RHBZ#1175196). - -You can now use LIBGUESTFS_DEBUG=true (etc.) - -You can disable debugging/tracing by setting LIBGUESTFS_DEBUG=0 (etc.) - -(cherry picked from commit 5f6677ebd0fd6f6712de808ca27eab4468f966bc) ---- - fuse/test-guestmount-fd.c | 2 +- - src/handle.c | 30 ++++++++++++++++++++------- - tests/charsets/test-charset-fidelity.c | 4 ++-- - tests/mount-local/test-parallel-mount-local.c | 2 +- - tests/parallel/Makefile.am | 1 + - tests/parallel/test-parallel.c | 2 +- - tests/regressions/Makefile.am | 1 + - tests/regressions/rhbz914931.c | 2 +- - 8 files changed, 30 insertions(+), 14 deletions(-) - -diff --git a/fuse/test-guestmount-fd.c b/fuse/test-guestmount-fd.c -index 00eab0c..2b3ce5b 100644 ---- a/fuse/test-guestmount-fd.c -+++ b/fuse/test-guestmount-fd.c -@@ -50,7 +50,7 @@ main (int argc, char *argv[]) - - /* Allow the test to be skipped. */ - skip = getenv ("SKIP_TEST_GUESTMOUNT_FD"); -- if (skip && STREQ (skip, "1")) { -+ if (skip && guestfs___is_true (skip) > 0) { - fprintf (stderr, "%s: test skipped because environment variable set.\n", - program_name); - exit (77); -diff --git a/src/handle.c b/src/handle.c -index 141ba7d..0990082 100644 ---- a/src/handle.c -+++ b/src/handle.c -@@ -176,7 +176,7 @@ parse_environment (guestfs_h *g, - char *(*do_getenv) (const void *data, const char *), - const void *data) - { -- int memsize; -+ int memsize, b; - char *str; - - /* Don't bother checking the return values of functions -@@ -184,12 +184,24 @@ parse_environment (guestfs_h *g, - */ - - str = do_getenv (data, "LIBGUESTFS_TRACE"); -- if (str != NULL && STREQ (str, "1")) -- guestfs_set_trace (g, 1); -+ if (str) { -+ b = guestfs___is_true (str); -+ if (b == -1) { -+ error (g, _("%s=%s: non-boolean value"), "LIBGUESTFS_TRACE", str); -+ return -1; -+ } -+ guestfs_set_trace (g, b); -+ } - - str = do_getenv (data, "LIBGUESTFS_DEBUG"); -- if (str != NULL && STREQ (str, "1")) -- guestfs_set_verbose (g, 1); -+ if (str) { -+ b = guestfs___is_true (str); -+ if (b == -1) { -+ error (g, _("%s=%s: non-boolean value"), "LIBGUESTFS_TRACE", str); -+ return -1; -+ } -+ guestfs_set_verbose (g, b); -+ } - - str = do_getenv (data, "LIBGUESTFS_TMPDIR"); - if (str && STRNEQ (str, "")) { -@@ -816,6 +828,7 @@ int - guestfs___get_backend_setting_bool (guestfs_h *g, const char *name) - { - CLEANUP_FREE char *value = NULL; -+ int b; - - guestfs_push_error_handler (g, NULL, NULL); - value = guestfs_get_backend_setting (g, name); -@@ -827,10 +840,11 @@ guestfs___get_backend_setting_bool (guestfs_h *g, const char *name) - if (value == NULL) - return -1; - -- if (STREQ (value, "1")) -- return 1; -+ b = guestfs___is_true (value); -+ if (b == -1) -+ return -1; - -- return 0; -+ return b; - } - - int -diff --git a/tests/charsets/test-charset-fidelity.c b/tests/charsets/test-charset-fidelity.c -index 4b34b0e..7ce7d94 100644 ---- a/tests/charsets/test-charset-fidelity.c -+++ b/tests/charsets/test-charset-fidelity.c -@@ -81,7 +81,7 @@ main (int argc, char *argv[]) - - /* Allow this test to be skipped. */ - str = getenv (ourenvvar); -- if (str && STREQ (str, "1")) { -+ if (str && guestfs___is_true (str) > 0) { - printf ("%s: test skipped because environment variable is set.\n", - program_name); - exit (77); -@@ -126,7 +126,7 @@ test_filesystem (guestfs_h *g, const struct filesystem *fs) - - snprintf (envvar, sizeof envvar, "%s_%s", ourenvvar, fs->fs_name); - str = getenv (envvar); -- if (str && STREQ (str, "1")) { -+ if (str && guestfs___is_true (str) > 0) { - printf ("skipped test of %s because environment variable is set\n", - fs->fs_name); - return; -diff --git a/tests/mount-local/test-parallel-mount-local.c b/tests/mount-local/test-parallel-mount-local.c -index fa6cd79..88ca2d3 100644 ---- a/tests/mount-local/test-parallel-mount-local.c -+++ b/tests/mount-local/test-parallel-mount-local.c -@@ -94,7 +94,7 @@ main (int argc, char *argv[]) - - /* Allow the test to be skipped by setting an environment variable. */ - skip = getenv ("SKIP_TEST_PARALLEL_MOUNT_LOCAL"); -- if (skip && STREQ (skip, "1")) { -+ if (skip && guestfs___is_true (skip) > 0) { - fprintf (stderr, "%s: test skipped because environment variable set.\n", - program_name); - exit (77); -diff --git a/tests/parallel/Makefile.am b/tests/parallel/Makefile.am -index be63256..9421bfc 100644 ---- a/tests/parallel/Makefile.am -+++ b/tests/parallel/Makefile.am -@@ -34,6 +34,7 @@ test_parallel_CFLAGS = \ - -pthread \ - $(WARN_CFLAGS) $(WERROR_CFLAGS) - test_parallel_LDADD = \ -+ $(top_builddir)/src/libutils.la \ - $(top_builddir)/src/libguestfs.la \ - $(top_builddir)/gnulib/lib/libgnu.la - -diff --git a/tests/parallel/test-parallel.c b/tests/parallel/test-parallel.c -index edd87d9..e412143 100644 ---- a/tests/parallel/test-parallel.c -+++ b/tests/parallel/test-parallel.c -@@ -76,7 +76,7 @@ main (int argc, char *argv[]) - - /* Allow the test to be skipped by setting an environment variable. */ - skip = getenv ("SKIP_TEST_PARALLEL"); -- if (skip && STREQ (skip, "1")) { -+ if (skip && guestfs___is_true (skip) > 0) { - fprintf (stderr, "%s: test skipped because environment variable set.\n", - program_name); - exit (77); -diff --git a/tests/regressions/Makefile.am b/tests/regressions/Makefile.am -index a5e7cfc..de97526 100644 ---- a/tests/regressions/Makefile.am -+++ b/tests/regressions/Makefile.am -@@ -111,6 +111,7 @@ rhbz914931_CFLAGS = \ - -pthread \ - $(WARN_CFLAGS) $(WERROR_CFLAGS) - rhbz914931_LDADD = \ -+ $(top_builddir)/src/libutils.la \ - $(top_builddir)/src/libguestfs.la - - rhbz1055452_SOURCES = rhbz1055452.c -diff --git a/tests/regressions/rhbz914931.c b/tests/regressions/rhbz914931.c -index faa3dd2..569e261 100644 ---- a/tests/regressions/rhbz914931.c -+++ b/tests/regressions/rhbz914931.c -@@ -41,7 +41,7 @@ main (int argc, char *argv[]) - - /* Allow this test to be skipped. */ - str = getenv ("SKIP_TEST_RHBZ914931"); -- if (str && STREQ (str, "1")) { -+ if (str && guestfs___is_true (str) > 0) { - printf ("%s: test skipped because environment variable is set.\n", - program_name); - exit (77); --- -1.8.3.1 - diff --git a/SOURCES/0127-v2v-Move-calculation-of-overlay-directory-to-common-.patch b/SOURCES/0127-v2v-Move-calculation-of-overlay-directory-to-common-.patch new file mode 100644 index 0000000..4803abd --- /dev/null +++ b/SOURCES/0127-v2v-Move-calculation-of-overlay-directory-to-common-.patch @@ -0,0 +1,42 @@ +From 3064454f1a56589e47907e9c7a2742643e9fde91 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 13:11:45 +0100 +Subject: [PATCH] v2v: Move calculation of overlay directory to common code. + +There is a tiny functional change in this patch, since overlay_dir is +now always evaluated once (eg. even in --inplace mode), whereas +previously it was evaluated twice but only in copying mode. + +(cherry picked from commit a7fb3d601ab2ae3cdf2074d4c47afe59f00eea6d) +--- + v2v/v2v.ml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index f2f1cff..ebbfa68 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -201,10 +201,11 @@ and amend_source cmdline source = + + { source with s_nics = nics } + ++and overlay_dir = (open_guestfs ())#get_cachedir () ++ + (* Create a qcow2 v3 overlay to protect the source image(s). *) + and create_overlays src_disks = + message (f_"Creating an overlay to protect the source from being modified"); +- let overlay_dir = (open_guestfs ())#get_cachedir () in + List.mapi ( + fun i ({ s_qemu_uri = qemu_uri; s_format = format } as source) -> + let overlay_file = +@@ -720,7 +721,6 @@ and actual_target_size target = + + (* Save overlays if --debug-overlays option was used. *) + and preserve_overlays overlays src_name = +- let overlay_dir = (open_guestfs ())#get_cachedir () in + List.iter ( + fun ov -> + let saved_filename = +-- +1.8.3.1 + diff --git a/SOURCES/0128-fish-Add-regression-test-for-RHBZ-1175196.patch b/SOURCES/0128-fish-Add-regression-test-for-RHBZ-1175196.patch deleted file mode 100644 index 2a495fc..0000000 --- a/SOURCES/0128-fish-Add-regression-test-for-RHBZ-1175196.patch +++ /dev/null @@ -1,105 +0,0 @@ -From f724608f41122c82c2deb7a1e66f51fb053080c0 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 17 Dec 2014 13:02:06 +0000 -Subject: [PATCH] fish: Add regression test for RHBZ#1175196. - -(cherry picked from commit f1ecd6af808f22af913a589754ae11dc1e35b658) ---- - tests/regressions/Makefile.am | 2 ++ - tests/regressions/rhbz1175196.sh | 64 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 66 insertions(+) - create mode 100755 tests/regressions/rhbz1175196.sh - -diff --git a/tests/regressions/Makefile.am b/tests/regressions/Makefile.am -index de97526..72d26da 100644 ---- a/tests/regressions/Makefile.am -+++ b/tests/regressions/Makefile.am -@@ -42,6 +42,7 @@ EXTRA_DIST = \ - rhbz1044014.xml \ - rhbz1054761.sh \ - rhbz1091803.sh \ -+ rhbz1175196.sh \ - test-noexec-stack.pl - - TESTS = \ -@@ -66,6 +67,7 @@ TESTS = \ - rhbz1054761.sh \ - rhbz1055452 \ - rhbz1091803.sh \ -+ rhbz1175196.sh \ - test-noexec-stack.pl - - if HAVE_LIBVIRT -diff --git a/tests/regressions/rhbz1175196.sh b/tests/regressions/rhbz1175196.sh -new file mode 100755 -index 0000000..e88f447 ---- /dev/null -+++ b/tests/regressions/rhbz1175196.sh -@@ -0,0 +1,64 @@ -+#!/bin/bash - -+# libguestfs -+# Copyright (C) 2014 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. -+ -+# Regression test for: -+# https://bugzilla.redhat.com/show_bug.cgi?id=1175196 -+# Parse 'LIBGUESTFS_TRACE=0' in the environment. -+ -+set -e -+export LANG=C -+ -+output="$(guestfish < +Date: Thu, 23 Jun 2016 13:12:44 +0100 +Subject: [PATCH] v2v: Rename check_free_space -> check_guest_free_space. + +(cherry picked from commit d8a465a14c3596a9fea53560bc7ad2ee6c3111bc) +--- + v2v/v2v.ml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index ebbfa68..f3eae43 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -78,7 +78,7 @@ let rec main () = + let inspect = Inspect_source.inspect_source cmdline.root_choice g in + + let mpstats = get_mpstats g in +- check_free_space mpstats; ++ check_guest_free_space mpstats; + (match conversion_mode with + | Copying (_, targets) -> + check_target_free_space mpstats source targets output +@@ -327,7 +327,7 @@ and get_mpstats g = + * (RHBZ#1139543). To avoid this situation, check there is some + * headroom. Mainly we care about the root filesystem. + *) +-and check_free_space mpstats = ++and check_guest_free_space mpstats = + message (f_"Checking for sufficient free disk space in the guest"); + List.iter ( + fun { mp_path = mp; +-- +1.8.3.1 + diff --git a/SOURCES/0129-ping-daemon-Fix-error-in-the-description-of-this-API.patch b/SOURCES/0129-ping-daemon-Fix-error-in-the-description-of-this-API.patch deleted file mode 100644 index a07e8cd..0000000 --- a/SOURCES/0129-ping-daemon-Fix-error-in-the-description-of-this-API.patch +++ /dev/null @@ -1,28 +0,0 @@ -From f2e747fd52fccb1fef13f1a7f8793b05854c26c0 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 18 Dec 2014 10:59:15 +0000 -Subject: [PATCH] ping-daemon: Fix error in the description of this API - (RHBZ#1175676). - -Thanks: Lingfei Kong -(cherry picked from commit f6e74ecd73d9aeeb4c9ef0044d7112645b09172f) ---- - generator/actions.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/generator/actions.ml b/generator/actions.ml -index 263c6f3..c7a1777 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -5273,7 +5273,7 @@ running the program." }; - shortdesc = "ping the guest daemon"; - longdesc = "\ - This is a test probe into the guestfs daemon running inside --the hypervisor. Calling this function checks that the -+the libguestfs appliance. Calling this function checks that the - daemon responds to the ping message, without affecting the daemon - or attached block device(s) in any other way." }; - --- -1.8.3.1 - diff --git a/SOURCES/0129-v2v-Refuse-to-convert-if-1GB-of-free-space-in-tempor.patch b/SOURCES/0129-v2v-Refuse-to-convert-if-1GB-of-free-space-in-tempor.patch new file mode 100644 index 0000000..a09bd9e --- /dev/null +++ b/SOURCES/0129-v2v-Refuse-to-convert-if-1GB-of-free-space-in-tempor.patch @@ -0,0 +1,144 @@ +From 923789a842239fa18e45f42f22126ef0f4aa6802 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 13:27:09 +0100 +Subject: [PATCH] v2v: Refuse to convert if < 1GB of free space in temporary + directory (RHBZ#1316479). + +The error you would see is: + + virt-v2v: error: insufficient free space in the conversion server temporary + directory /var/tmp (853.8M). + + Either free up space in that directory, or set the LIBGUESTFS_CACHEDIR + environment variable to point to another directory with more than 1GB of + free space. + + See also the virt-v2v(1) manual, section "Minimum free space check in the + host". + +Also adds some documentation. + +Thanks: Ming Xie and Xiaodai Wang +(cherry picked from commit 9221ef6f7959ae3b979fd05007363810bc66062b) +--- + v2v/Makefile.am | 4 ++++ + v2v/v2v.ml | 15 +++++++++++++++ + v2v/virt-v2v.pod | 19 +++++++++++++++++++ + 3 files changed, 38 insertions(+) + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index a996e5d..e0d013a 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -117,6 +117,7 @@ SOURCES_ML = \ + SOURCES_C = \ + ../mllib/dev_t-c.c \ + ../mllib/mkdtemp-c.c \ ++ ../mllib/statvfs-c.c \ + domainxml-c.c \ + changeuid-c.c \ + utils-c.c \ +@@ -145,6 +146,7 @@ BOBJECTS = \ + $(top_builddir)/mllib/regedit.cmo \ + $(top_builddir)/mllib/mkdtemp.cmo \ + $(top_builddir)/mllib/JSON.cmo \ ++ $(top_builddir)/mllib/StatVFS.cmo \ + $(top_builddir)/mllib/curl.cmo \ + $(top_builddir)/customize/customize_utils.cmo \ + $(top_builddir)/customize/firstboot.cmo \ +@@ -192,6 +194,7 @@ virt_v2v_LINK = \ + + virt_v2v_copy_to_local_SOURCES = \ + ../mllib/dev_t-c.c \ ++ ../mllib/statvfs-c.c \ + domainxml-c.c \ + utils-c.c \ + xml-c.c +@@ -211,6 +214,7 @@ COPY_TO_LOCAL_BOBJECTS = \ + $(top_builddir)/mllib/dev_t.cmo \ + $(top_builddir)/mllib/common_utils.cmo \ + $(top_builddir)/mllib/JSON.cmo \ ++ $(top_builddir)/mllib/StatVFS.cmo \ + $(top_builddir)/mllib/curl.cmo \ + xml.cmo \ + utils.cmo \ +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index f3eae43..4b06bc1 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -49,6 +49,7 @@ let rec main () = + + let conversion_mode = + if not cmdline.in_place then ( ++ check_host_free_space (); + let overlays = create_overlays source.s_disks in + let targets = init_targets cmdline output source overlays in + Copying (overlays, targets) +@@ -203,6 +204,20 @@ and amend_source cmdline source = + + and overlay_dir = (open_guestfs ())#get_cachedir () + ++(* Conversion can fail or hang if there is insufficient free space in ++ * the temporary directory used to store overlays on the host ++ * (RHBZ#1316479). Although only a few hundred MB is actually ++ * required, make the minimum be 1 GB to allow for the possible 500 MB ++ * guestfs appliance which is also stored here. ++ *) ++and check_host_free_space () = ++ let free_space = StatVFS.free_space overlay_dir in ++ debug "check_host_free_space: overlay_dir=%s free_space=%Ld" ++ overlay_dir free_space; ++ if free_space < 1_073_741_824L then ++ error (f_"insufficient free space in the conversion server temporary directory %s (%s).\n\nEither free up space in that directory, or set the LIBGUESTFS_CACHEDIR environment variable to point to another directory with more than 1GB of free space.\n\nSee also the virt-v2v(1) manual, section \"Minimum free space check in the host\".") ++ overlay_dir (human_size free_space) ++ + (* Create a qcow2 v3 overlay to protect the source image(s). *) + and create_overlays src_disks = + message (f_"Creating an overlay to protect the source from being modified"); +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 4ea02ab..c68bcb5 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1495,6 +1495,8 @@ This temporarily places a full copy of the output disks in C<$TMPDIR>. + + =back + ++See also L below. ++ + =head2 VMware vCenter resources + + Copying from VMware vCenter is currently quite slow, but we believe +@@ -1546,6 +1548,8 @@ prevent the guest from subsequently booting correctly. + + =head1 FREE SPACE FOR CONVERSION + ++=head2 Free space in the guest ++ + Virt-v2v checks there is sufficient free space in the guest filesystem + to perform the conversion. Currently it checks: + +@@ -1568,6 +1572,21 @@ Minimum free space: 10 MB + + =back + ++=head2 Minimum free space check in the host ++ ++You must have sufficient free space in the host directory used to ++store temporary overlays (except in [--in-place] mode). To find out ++which directory this is, use: ++ ++ $ df -h "`guestfish get-cachedir`" ++ Filesystem Size Used Avail Use% Mounted on ++ /dev/mapper/root 50G 40G 6.8G 86% / ++ ++and look under the C column. Virt-v2v will refuse to do the ++conversion at all unless at least 1GB is available there. ++ ++See also L above. ++ + =head1 RUNNING VIRT-V2V AS ROOT OR NON-ROOT + + Nothing in virt-v2v inherently needs root access, and it will run just +-- +1.8.3.1 + diff --git a/SOURCES/0130-filearch-move-libmagic-code-in-an-own-function.patch b/SOURCES/0130-filearch-move-libmagic-code-in-an-own-function.patch deleted file mode 100644 index 828b166..0000000 --- a/SOURCES/0130-filearch-move-libmagic-code-in-an-own-function.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 45209466afa76eb93f5c27028c9b5c5e6ea4f572 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 13 Apr 2015 11:18:46 +0200 -Subject: [PATCH] filearch: move libmagic code in an own function - -Also use a cleanup attribue to ease the close of the magic_t handle. - -This is mostly code motion, hopefully with no actual behaviour changes. - -(cherry picked from commit 20acc1f124a3f3af365c27b7654bead5beb1ef4c) ---- - src/filearch.c | 100 +++++++++++++++++++++++++++++++++++++++------------------ - 1 file changed, 68 insertions(+), 32 deletions(-) - -diff --git a/src/filearch.c b/src/filearch.c -index c0380d9..e851279 100644 ---- a/src/filearch.c -+++ b/src/filearch.c -@@ -74,6 +74,22 @@ free_regexps (void) - pcre_free (re_elf_ppc64); - } - -+# ifdef HAVE_ATTRIBUTE_CLEANUP -+# define CLEANUP_MAGIC_T_FREE __attribute__((cleanup(cleanup_magic_t_free))) -+ -+static void -+cleanup_magic_t_free (void *ptr) -+{ -+ magic_t m = *(magic_t *) ptr; -+ -+ if (m) -+ magic_close (m); -+} -+ -+# else -+# define CLEANUP_MAGIC_T_FREE -+# endif -+ - /* Convert output from 'file' command on ELF files to the canonical - * architecture string. Caller must free the result. - */ -@@ -120,6 +136,55 @@ is_regular_file (const char *filename) - return lstat (filename, &statbuf) == 0 && S_ISREG (statbuf.st_mode); - } - -+static char * -+magic_for_file (guestfs_h *g, const char *filename, bool *loading_ok, -+ bool *matched) -+{ -+ int flags; -+ CLEANUP_MAGIC_T_FREE magic_t m = NULL; -+ const char *line; -+ char *elf_arch; -+ -+ flags = g->verbose ? MAGIC_DEBUG : 0; -+ flags |= MAGIC_ERROR | MAGIC_RAW; -+ -+ if (loading_ok) -+ *loading_ok = false; -+ if (matched) -+ *matched = false; -+ -+ m = magic_open (flags); -+ if (m == NULL) { -+ perrorf (g, "magic_open"); -+ return NULL; -+ } -+ -+ if (magic_load (m, NULL) == -1) { -+ perrorf (g, "magic_load: default magic database file"); -+ return NULL; -+ } -+ -+ line = magic_file (m, filename); -+ if (line == NULL) { -+ perrorf (g, "magic_file: %s", filename); -+ return NULL; -+ } -+ -+ if (loading_ok) -+ *loading_ok = true; -+ -+ elf_arch = match1 (g, line, re_file_elf); -+ if (elf_arch == NULL) { -+ error (g, "no re_file_elf match in '%s'", line); -+ return NULL; -+ } -+ -+ if (matched) -+ *matched = true; -+ -+ return canonical_elf_arch (g, elf_arch); -+} -+ - /* Download and uncompress the cpio file to find binaries within. */ - static const char *initrd_binaries[] = { - "bin/ls", -@@ -198,40 +263,11 @@ cpio_arch (guestfs_h *g, const char *file, const char *path) - safe_asprintf (g, "%s/%s", dir, initrd_binaries[i]); - - if (is_regular_file (bin)) { -- int flags; -- magic_t m; -- const char *line; -- CLEANUP_FREE char *elf_arch = NULL; -+ bool loading_ok, matched; - -- flags = g->verbose ? MAGIC_DEBUG : 0; -- flags |= MAGIC_ERROR | MAGIC_RAW; -- -- m = magic_open (flags); -- if (m == NULL) { -- perrorf (g, "magic_open"); -- goto out; -- } -- -- if (magic_load (m, NULL) == -1) { -- perrorf (g, "magic_load: default magic database file"); -- magic_close (m); -- goto out; -- } -- -- line = magic_file (m, bin); -- if (line == NULL) { -- perrorf (g, "magic_file: %s", bin); -- magic_close (m); -- goto out; -- } -- -- elf_arch = match1 (g, line, re_file_elf); -- if (elf_arch != NULL) { -- ret = canonical_elf_arch (g, elf_arch); -- magic_close (m); -+ ret = magic_for_file (g, bin, &loading_ok, &matched); -+ if (!loading_ok || matched) - goto out; -- } -- magic_close (m); - } - } - error (g, "file_architecture: could not determine architecture of cpio archive"); --- -1.8.3.1 - diff --git a/SOURCES/0130-p2v-Make-the-sudo-error-message-actionable.patch b/SOURCES/0130-p2v-Make-the-sudo-error-message-actionable.patch new file mode 100644 index 0000000..a80330a --- /dev/null +++ b/SOURCES/0130-p2v-Make-the-sudo-error-message-actionable.patch @@ -0,0 +1,29 @@ +From 0d3ac31739bcfa3c4dc4adb66de07d6859735c35 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 13:52:46 +0100 +Subject: [PATCH] p2v: Make the sudo error message actionable. + +Updates commit 5b6a8e086264c85fb048c0eadff6c34351663133. + +(cherry picked from commit 323c3e20a4d47fc5a0f1b5fcd3352f746c8bd9dd) +--- + p2v/ssh.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index aa070d5..083e04e 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -583,7 +583,8 @@ test_connection (struct config *config) + + case 102: + mexp_close (h); +- set_ssh_error ("sudo for user '%s' requires a password", config->username); ++ set_ssh_error ("sudo for user \"%s\" requires a password. Edit /etc/sudoers on the conversion server to ensure the \"NOPASSWD:\" option is set for this user.", ++ config->username); + return -1; + + case MEXP_EOF: +-- +1.8.3.1 + diff --git a/SOURCES/0131-p2v-ssh-Improve-consistency-of-error-messages.patch b/SOURCES/0131-p2v-ssh-Improve-consistency-of-error-messages.patch new file mode 100644 index 0000000..08a991b --- /dev/null +++ b/SOURCES/0131-p2v-ssh-Improve-consistency-of-error-messages.patch @@ -0,0 +1,482 @@ +From af87d247df5ebe6b94e04624c35b59155ae99eb5 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Jun 2016 14:25:23 +0100 +Subject: [PATCH] p2v: ssh: Improve consistency of error messages. + +(cherry picked from commit 8f8a651e591064d87974bd322a995519347ebae7) +--- + p2v/ssh.c | 133 +++++++++++++++++++++++++++++++++++--------------------------- + 1 file changed, 75 insertions(+), 58 deletions(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index 083e04e..93c4c55 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -93,6 +93,21 @@ get_ssh_error (void) + return ssh_error; + } + ++/* Like set_ssh_error, but for errors that aren't supposed to happen. */ ++#define set_ssh_internal_error(fs, ...) \ ++ set_ssh_error ("internal error: " fs, ##__VA_ARGS__) ++#define set_ssh_mexp_error(fn) \ ++ set_ssh_internal_error ("%s: %m", fn) ++#define set_ssh_pcre_error() \ ++ set_ssh_internal_error ("pcre error: %d\n", mexp_get_pcre_error (h)) ++ ++#define set_ssh_unexpected_eof(fs, ...) \ ++ set_ssh_error ("remote server closed the connection unexpectedly, " \ ++ "waiting for: " fs, ##__VA_ARGS__) ++#define set_ssh_unexpected_timeout(fs, ...) \ ++ set_ssh_error ("remote server timed out unexpectedly, " \ ++ "waiting for: " fs, ##__VA_ARGS__) ++ + static void compile_regexps (void) __attribute__((constructor)); + static void free_regexps (void) __attribute__((destructor)); + +@@ -241,7 +256,7 @@ curl_download (const char *url, const char *local_file) + return -1; + } + else if (!WIFEXITED (r)) { +- set_ssh_error ("curl subprocess got a signal (%d)", r); ++ set_ssh_internal_error ("curl subprocess got a signal (%d)", r); + unlink (error_file); + return -1; + } +@@ -353,7 +368,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + + h = mexp_spawnv ("ssh", (char **) args); + if (h == NULL) { +- set_ssh_error ("internal error: ssh: mexp_spawnv: %m"); ++ set_ssh_internal_error ("ssh: mexp_spawnv: %m"); + return NULL; + } + +@@ -371,7 +386,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + }, ovector, ovecsize)) { + case 100: /* Got password prompt. */ + if (mexp_printf (h, "%s\n", config->password) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + mexp_close (h); + return NULL; + } +@@ -383,7 +398,6 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + goto wait_password_again; + + case MEXP_EOF: +- mexp_close (h); + /* This is where we get to if the user enters an incorrect or + * impossible hostname or port number. Hopefully ssh printed an + * error message, and we picked it up and put it in +@@ -393,21 +407,22 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + if (ssh_message) + set_ssh_error ("%s", ssh_message); + else +- set_ssh_error ("unknown ssh error"); ++ set_ssh_error ("ssh closed the connection without printing an error."); ++ mexp_close (h); + return NULL; + + case MEXP_TIMEOUT: ++ set_ssh_unexpected_timeout ("password prompt"); + mexp_close (h); +- set_ssh_error ("timeout waiting for password prompt"); + return NULL; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + mexp_close (h); + return NULL; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + mexp_close (h); + return NULL; + } +@@ -435,7 +450,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + * (https://bugzilla.redhat.com/1314244#c9). + */ + if (mexp_printf (h, "exec bash --noediting --noprofile\n") == -1) { +- set_ssh_error ("setting bash as remote shell: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + mexp_close (h); + return NULL; + } +@@ -449,7 +464,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + int r; + + if (guestfs_int_random_string (magic, 8) == -1) { +- set_ssh_error ("random_string: %m"); ++ set_ssh_internal_error ("random_string: %m"); + mexp_close (h); + return NULL; + } +@@ -458,7 +473,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + * mistake the command echo for the prompt. + */ + if (mexp_printf (h, "export LANG=C PS1='###''%s''### '\n", magic) == -1) { +- set_ssh_error ("random_string: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + mexp_close (h); + return NULL; + } +@@ -472,8 +487,8 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + { 0 } + }, ovector, ovecsize)) { + case 100: /* Got password prompt unexpectedly. */ ++ set_ssh_error ("Login failed. Probably the username and/or password is wrong."); + mexp_close (h); +- set_ssh_error ("login failed - probably the username and/or password is wrong"); + return NULL; + + case 101: +@@ -483,7 +498,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + r = pcre_get_substring (h->buffer, ovector, + mexp_get_pcre_error (h), 1, &matched); + if (r < 0) { +- fprintf (stderr, "error: PCRE error reading substring (%d)\n", r); ++ fprintf (stderr, "error: pcre error reading substring (%d)\n", r); + exit (EXIT_FAILURE); + } + r = STREQ (magic, matched); +@@ -493,8 +508,8 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + goto got_prompt; + + case MEXP_EOF: ++ set_ssh_unexpected_eof ("the command prompt"); + mexp_close (h); +- set_ssh_error ("unexpected end of file waiting for command prompt"); + return NULL; + + case MEXP_TIMEOUT: +@@ -504,19 +519,19 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + break; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + mexp_close (h); + return NULL; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + mexp_close (h); + return NULL; + } + } + ++ set_ssh_error ("Failed to synchronize with remote shell after 60 seconds."); + mexp_close (h); +- set_ssh_error ("failed to synchronize with remote shell after 60 seconds"); + return NULL; + + got_prompt: +@@ -556,7 +571,7 @@ test_connection (struct config *config) + if (mexp_printf (h, + "%svirt-v2v --version\n", + config->sudo ? "sudo -n " : "") == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + mexp_close (h); + return -1; + } +@@ -582,28 +597,28 @@ test_connection (struct config *config) + goto end_of_version; + + case 102: +- mexp_close (h); + set_ssh_error ("sudo for user \"%s\" requires a password. Edit /etc/sudoers on the conversion server to ensure the \"NOPASSWD:\" option is set for this user.", + config->username); ++ mexp_close (h); + return -1; + + case MEXP_EOF: ++ set_ssh_unexpected_eof ("\"virt-v2v --version\" output"); + mexp_close (h); +- set_ssh_error ("unexpected end of file waiting virt-v2v --version output"); + return -1; + + case MEXP_TIMEOUT: ++ set_ssh_unexpected_timeout ("\"virt-v2v --version\" output"); + mexp_close (h); +- set_ssh_error ("timeout waiting for virt-v2v --version output"); + return -1; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + mexp_close (h); + return -1; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + mexp_close (h); + return -1; + } +@@ -612,9 +627,9 @@ test_connection (struct config *config) + + /* Got the prompt but no version number. */ + if (v2v_version == NULL) { +- mexp_close (h); + set_ssh_error ("virt-v2v is not installed on the conversion server, " +- "or it might be a too old version"); ++ "or it might be a too old version."); ++ mexp_close (h); + return -1; + } + +@@ -634,7 +649,7 @@ test_connection (struct config *config) + /* Get virt-v2v features. See: v2v/cmdline.ml */ + if (mexp_printf (h, "%svirt-v2v --machine-readable\n", + config->sudo ? "sudo -n " : "") == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + mexp_close (h); + return -1; + } +@@ -677,22 +692,22 @@ test_connection (struct config *config) + goto end_of_machine_readable; + + case MEXP_EOF: ++ set_ssh_unexpected_eof ("\"virt-v2v --machine-readable\" output"); + mexp_close (h); +- set_ssh_error ("unexpected end of file waiting virt-v2v --machine-readable output"); + return -1; + + case MEXP_TIMEOUT: ++ set_ssh_unexpected_timeout ("\"virt-v2v --machine-readable\" output"); + mexp_close (h); +- set_ssh_error ("timeout waiting virt-v2v --machine-readable output"); + return -1; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + mexp_close (h); + return -1; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + mexp_close (h); + return -1; + } +@@ -700,14 +715,14 @@ test_connection (struct config *config) + end_of_machine_readable: + + if (!feature_libguestfs_rewrite) { ++ set_ssh_error ("Invalid output of \"virt-v2v --machine-readable\" command."); + mexp_close (h); +- set_ssh_error ("invalid output of virt-v2v --machine-readable command"); + return -1; + } + + /* Test finished, shut down ssh. */ + if (mexp_printf (h, "exit\n") == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + mexp_close (h); + return -1; + } +@@ -717,30 +732,31 @@ test_connection (struct config *config) + break; + + case MEXP_TIMEOUT: ++ set_ssh_unexpected_timeout ("end of ssh session"); + mexp_close (h); +- set_ssh_error ("timeout waiting for end of ssh session"); + return -1; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + mexp_close (h); + return -1; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + mexp_close (h); + return -1; + } + + status = mexp_close (h); + if (status == -1) { +- set_ssh_error ("mexp_close: %m"); ++ set_ssh_internal_error ("mexp_close: %m"); + return -1; + } + if (WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP) + return 0; /* not an error */ + if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) { +- set_ssh_error ("unexpected close status from ssh subprocess (%d)", status); ++ set_ssh_internal_error ("unexpected close status from ssh subprocess (%d)", ++ status); + return -1; + } + return 0; +@@ -799,7 +815,7 @@ compatible_version (const char *v2v_version) + /* The major version must always be 1. */ + if (!STRPREFIX (v2v_version, "1.")) { + set_ssh_error ("virt-v2v major version is not 1 (\"%s\"), " +- "this version of virt-p2v is not compatible", ++ "this version of virt-p2v is not compatible.", + v2v_version); + return 0; + } +@@ -810,15 +826,15 @@ compatible_version (const char *v2v_version) + * We should remain compatible with any virt-v2v after 1.28. + */ + if (sscanf (v2v_version, "1.%u", &v2v_minor) != 1) { +- set_ssh_error ("cannot parse virt-v2v version string (\"%s\")", +- v2v_version); ++ set_ssh_internal_error ("cannot parse virt-v2v version string (\"%s\")", ++ v2v_version); + return 0; + } + + if (v2v_minor < 28) { + set_ssh_error ("virt-v2v version is < 1.28 (\"%s\"), " + "you must upgrade to virt-v2v >= 1.28 on " +- "the conversion server", v2v_version); ++ "the conversion server.", v2v_version); + return 0; + } + +@@ -858,34 +874,35 @@ open_data_connection (struct config *config, int *local_port, int *remote_port) + case 100: /* Ephemeral port. */ + port_str = strndup (&h->buffer[ovector[2]], ovector[3]-ovector[2]); + if (port_str == NULL) { +- set_ssh_error ("not enough memory for strndup"); ++ set_ssh_internal_error ("strndup: %m"); + mexp_close (h); + return NULL; + } + if (sscanf (port_str, "%d", remote_port) != 1) { +- set_ssh_error ("cannot extract the port number from '%s'", port_str); ++ set_ssh_internal_error ("cannot extract the port number from '%s'", ++ port_str); + mexp_close (h); + return NULL; + } + break; + + case MEXP_EOF: ++ set_ssh_unexpected_eof ("\"ssh -R\" output"); + mexp_close (h); +- set_ssh_error ("unexpected end of file waiting ssh -R output"); + return NULL; + + case MEXP_TIMEOUT: ++ set_ssh_unexpected_timeout ("\"ssh -R\" output"); + mexp_close (h); +- set_ssh_error ("timeout waiting for ssh -R output"); + return NULL; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + mexp_close (h); + return NULL; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + mexp_close (h); + return NULL; + } +@@ -909,19 +926,19 @@ wait_for_prompt (mexp_h *h) + return 0; + + case MEXP_EOF: +- set_ssh_error ("unexpected end of file waiting for prompt"); ++ set_ssh_unexpected_eof ("command prompt"); + return -1; + + case MEXP_TIMEOUT: +- set_ssh_error ("timeout waiting for prompt"); ++ set_ssh_unexpected_timeout ("command prompt"); + return -1; + + case MEXP_ERROR: +- set_ssh_error ("mexp_expect: %m"); ++ set_ssh_mexp_error ("mexp_expect"); + return -1; + + case MEXP_PCRE_ERROR: +- set_ssh_error ("PCRE error: %d\n", mexp_get_pcre_error (h)); ++ set_ssh_pcre_error (); + return -1; + } + +@@ -947,7 +964,7 @@ start_remote_connection (struct config *config, + + /* Create the remote directory. */ + if (mexp_printf (h, "mkdir %s\n", remote_dir) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +@@ -957,7 +974,7 @@ start_remote_connection (struct config *config, + /* Write some useful config information to files in the remote directory. */ + if (mexp_printf (h, "echo '%s' > %s/name\n", + config->guestname, remote_dir) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +@@ -965,7 +982,7 @@ start_remote_connection (struct config *config, + goto error; + + if (mexp_printf (h, "date > %s/time\n", remote_dir) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +@@ -980,7 +997,7 @@ start_remote_connection (struct config *config, + remote_dir, magic, + libvirt_xml, + magic) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +@@ -995,7 +1012,7 @@ start_remote_connection (struct config *config, + remote_dir, magic, + wrapper_script, + magic) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +@@ -1003,7 +1020,7 @@ start_remote_connection (struct config *config, + goto error; + + if (mexp_printf (h, "chmod +x %s/virt-v2v-wrapper.sh\n", remote_dir) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +@@ -1020,7 +1037,7 @@ start_remote_connection (struct config *config, + remote_dir, magic, + dmesg, + magic) == -1) { +- set_ssh_error ("mexp_printf: %m"); ++ set_ssh_mexp_error ("mexp_printf"); + goto error; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0131-v2v-Reduce-use-of-polymorphic-variants.patch b/SOURCES/0131-v2v-Reduce-use-of-polymorphic-variants.patch deleted file mode 100644 index 0d7fb53..0000000 --- a/SOURCES/0131-v2v-Reduce-use-of-polymorphic-variants.patch +++ /dev/null @@ -1,274 +0,0 @@ -From a71e0ff19b9cbb8942fbeacecd317ba888452b16 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 24 Dec 2014 18:10:37 +0000 -Subject: [PATCH] v2v: Reduce use of polymorphic variants. - -Ordinary variants prevent coding errors. - -(cherry picked from commit 3a080c3fbffa5846f71528c6fd978be7853b33b8) ---- - v2v/convert_linux.ml | 6 +++--- - v2v/input_disk.ml | 2 +- - v2v/input_libvirtxml.ml | 20 ++++++++++---------- - v2v/input_ova.ml | 8 ++++---- - v2v/output_libvirt.ml | 4 ++-- - v2v/output_qemu.ml | 6 +++--- - v2v/types.ml | 18 ++++++++++-------- - v2v/types.mli | 13 ++++++++----- - 8 files changed, 41 insertions(+), 36 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 67de2b1..718ddaf 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -1269,9 +1269,9 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = - fun i disk -> - let block_prefix_before_conversion = - match disk.s_controller with -- | Some `IDE -> ide_block_prefix -- | Some `SCSI -> "sd" -- | Some `Virtio_blk -> "vd" -+ | Some Source_IDE -> ide_block_prefix -+ | Some Source_SCSI -> "sd" -+ | Some Source_virtio_blk -> "vd" - | None -> - (* This is basically a guess. It assumes the source used IDE. *) - ide_block_prefix in -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index 8393786..98b321c 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -86,7 +86,7 @@ class input_disk verbose input_format disk = object - s_vcpu = 1; (* 1 vCPU is a safe default *) - s_features = [ "acpi"; "apic"; "pae" ]; - s_display = -- Some { s_display_type = `Window; s_keymap = None; s_password = None }; -+ Some { s_display_type = Window; s_keymap = None; s_password = None }; - s_disks = [disk]; - s_removables = []; - s_nics = [network]; -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index d1146f9..8057a00 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -96,10 +96,10 @@ let parse_libvirt_xml ~verbose xml = - match xpath_to_string "@type" "" with - | "" -> None - | "vnc" -> -- Some { s_display_type = `VNC; -+ Some { s_display_type = VNC; - s_keymap = keymap; s_password = password } - | "spice" -> -- Some { s_display_type = `Spice; -+ Some { s_display_type = Spice; - s_keymap = keymap; s_password = password } - | "sdl"|"desktop" as t -> - warning ~prog (f_"virt-v2v does not support local displays, so in the input libvirt XML was ignored") t; -@@ -138,9 +138,9 @@ let parse_libvirt_xml ~verbose xml = - let target_bus = xpath_to_string "target/@bus" "" in - match target_bus with - | "" -> None -- | "ide" -> Some `IDE -- | "scsi" -> Some `SCSI -- | "virtio" -> Some `Virtio_blk -+ | "ide" -> Some Source_IDE -+ | "scsi" -> Some Source_SCSI -+ | "virtio" -> Some Source_virtio_blk - | _ -> None in - - let format = -@@ -202,15 +202,15 @@ let parse_libvirt_xml ~verbose xml = - let target_bus = xpath_to_string "target/@bus" "" in - match target_bus with - | "" -> None -- | "ide" -> Some `IDE -- | "scsi" -> Some `SCSI -- | "virtio" -> Some `Virtio_blk -+ | "ide" -> Some Source_IDE -+ | "scsi" -> Some Source_SCSI -+ | "virtio" -> Some Source_virtio_blk - | _ -> None in - - let typ = - match xpath_to_string "@device" "" with -- | "cdrom" -> `CDROM -- | "floppy" -> `Floppy -+ | "cdrom" -> CDROM -+ | "floppy" -> Floppy - | _ -> assert false (* libxml2 error? *) in - - let disk = -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index e2a1243..211db43 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -167,8 +167,8 @@ object - - (* 6: iscsi controller, 5: ide *) - match controller with -- | 6 -> Some `SCSI -- | 5 -> Some `IDE -+ | 6 -> Some Source_SCSI -+ | 5 -> Some Source_IDE - | 0 -> - warning ~prog (f_"ova disk has no parent controller, please report this as a bug supplying the *.ovf file extracted from the ova"); - None -@@ -272,8 +272,8 @@ object - - let typ = - match id with -- | 14 -> `Floppy -- | 15 | 16 -> `CDROM -+ | 14 -> Floppy -+ | 15 | 16 -> CDROM - | _ -> assert false in - let disk = { - s_removable_type = typ; -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index 7f9a3a0..f4e480a 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -164,7 +164,7 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - - List.map ( - function -- | { s_removable_type = `CDROM } -> -+ | { s_removable_type = CDROM } -> - let i = !cdrom_index in - incr cdrom_index; - let name = cdrom_block_prefix ^ drive_name i in -@@ -173,7 +173,7 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - e "target" [ "dev", name; "bus", cdrom_bus ] [] - ] - -- | { s_removable_type = `Floppy } -> -+ | { s_removable_type = Floppy } -> - let i = !fd_index in - incr fd_index; - let name = "fd" ^ drive_name i in -diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml -index 9c17121..4b1d69a 100644 ---- a/v2v/output_qemu.ml -+++ b/v2v/output_qemu.ml -@@ -90,11 +90,11 @@ object - | None -> () - | Some display -> - (match display.s_display_type with -- | `Window -> -+ | Window -> - fpf "%s-display gtk" nl -- | `VNC -> -+ | VNC -> - fpf "%s-display vnc=:0" nl -- | `Spice -> -+ | Spice -> - fpf "%s-spice port=5900,addr=127.0.0.1" nl - ); - fpf "%s-vga %s" nl -diff --git a/v2v/types.ml b/v2v/types.ml -index 28d62fc..97120c2 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -38,11 +38,12 @@ and source_disk = { - s_format : string option; - s_controller : s_controller option; - } --and s_controller = [`IDE | `SCSI | `Virtio_blk] -+and s_controller = Source_IDE | Source_SCSI | Source_virtio_blk - and source_removable = { -- s_removable_type : [`CDROM|`Floppy]; -+ s_removable_type : s_removable_type; - s_removable_controller : s_controller option; - } -+and s_removable_type = CDROM | Floppy - and source_nic = { - s_mac : string option; - s_vnet : string; -@@ -51,10 +52,11 @@ and source_nic = { - } - and vnet_type = Bridge | Network - and source_display = { -- s_display_type : [`Window|`VNC|`Spice]; -+ s_display_type : s_display_type; - s_keymap : string option; - s_password : string option; - } -+and s_display_type = Window | VNC | Spice - - let rec string_of_source s = - sprintf " source name: %s -@@ -94,14 +96,14 @@ and string_of_source_disk { s_qemu_uri = qemu_uri; s_format = format; - | Some controller -> " [" ^ string_of_controller controller ^ "]") - - and string_of_controller = function -- | `IDE -> "ide" -- | `SCSI -> "scsi" -- | `Virtio_blk -> "virtio" -+ | Source_IDE -> "ide" -+ | Source_SCSI -> "scsi" -+ | Source_virtio_blk -> "virtio" - - and string_of_source_removable { s_removable_type = typ; - s_removable_controller = controller } = - sprintf "\t%s%s" -- (match typ with `CDROM -> "CD-ROM" | `Floppy -> "Floppy") -+ (match typ with CDROM -> "CD-ROM" | Floppy -> "Floppy") - (match controller with - | None -> "" - | Some controller -> " [" ^ string_of_controller controller ^ "]") -@@ -117,7 +119,7 @@ and string_of_source_nic { s_mac = mac; s_vnet = vnet; s_vnet_type = typ } = - and string_of_source_display { s_display_type = typ; - s_keymap = keymap; s_password = password } = - sprintf "%s%s%s" -- (match typ with `Window -> "window" | `VNC -> "vnc" | `Spice -> "spice") -+ (match typ with Window -> "window" | VNC -> "vnc" | Spice -> "spice") - (match keymap with None -> "" | Some km -> " " ^ km) - (match password with None -> "" | Some _ -> " with password") - -diff --git a/v2v/types.mli b/v2v/types.mli -index 07eec98..3d65596 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -42,19 +42,21 @@ and source_disk = { - } - (** A source disk. *) - --and s_controller = [`IDE | `SCSI | `Virtio_blk] -+and s_controller = Source_IDE | Source_SCSI | Source_virtio_blk - (** Source disk controller. - - For the purposes of this field, we can treat virtio-scsi as -- [`SCSI]. However we don't support conversions from virtio in any -+ [SCSI]. However we don't support conversions from virtio in any - case so virtio is here only to make it work for testing. *) - - and source_removable = { -- s_removable_type : [`CDROM|`Floppy]; (** Type. *) -+ s_removable_type : s_removable_type; (** Type. *) - s_removable_controller : s_controller option; (** Controller, eg. IDE, SCSI.*) - } - (** Removable media. *) - -+and s_removable_type = CDROM | Floppy -+ - and source_nic = { - s_mac : string option; (** MAC address. *) - s_vnet : string; (** Source network name. *) -@@ -65,11 +67,12 @@ and source_nic = { - and vnet_type = Bridge | Network - - and source_display = { -- s_display_type : [`Window|`VNC|`Spice]; (** Display type. *) -- s_keymap : string option; (** Guest keymap. *) -+ s_display_type : s_display_type; (** Display type. *) -+ s_keymap : string option; (** Guest keymap. *) - s_password : string option; (** If required, password to access - the display. *) - } -+and s_display_type = Window | VNC | Spice - - val string_of_source : source -> string - val string_of_source_disk : source_disk -> string --- -1.8.3.1 - diff --git a/SOURCES/0132-inspect-get-windows-drive-letters-for-GPT-disks.patch b/SOURCES/0132-inspect-get-windows-drive-letters-for-GPT-disks.patch new file mode 100644 index 0000000..5cda32c --- /dev/null +++ b/SOURCES/0132-inspect-get-windows-drive-letters-for-GPT-disks.patch @@ -0,0 +1,159 @@ +From 3d23c51e654f479de8ddbfd1cd7e44753d4bb19d Mon Sep 17 00:00:00 2001 +From: Dawid Zamirski +Date: Sat, 6 Feb 2016 11:50:05 -0500 +Subject: [PATCH] inspect: get windows drive letters for GPT disks. + +This patch updates the guestfs_inspect_get_drive_mappings API call to +also return drive letters for GPT paritions. Previously this worked +only for MBR partitions. This is achieved by matching the GPT partition +GUID with the info stored in the blob from +HKLM\SYSTEM\MountedDevices\DosDevices keys. For GPT partions this blob +contains a "DMIO:ID:" prefix followed by a 16 byte binary GUID. + +(cherry picked from commit 7cb28488a6b974c86a9dd0264d892cd01739c36e) +--- + src/inspect-fs-windows.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 94 insertions(+), 2 deletions(-) + +diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c +index 7e3ead5..f8717fc 100644 +--- a/src/inspect-fs-windows.c ++++ b/src/inspect-fs-windows.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #ifdef HAVE_ENDIAN_H + #include +@@ -57,6 +58,8 @@ static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs); + static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs); + static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs); + static char *map_registry_disk_blob (guestfs_h *g, const void *blob); ++static char *map_registry_disk_blob_gpt (guestfs_h *g, const void *blob); ++static char *extract_guid_from_registry_blob (guestfs_h *g, const void *blob); + + /* XXX Handling of boot.ini in the Perl version was pretty broken. It + * essentially didn't do anything for modern Windows guests. +@@ -386,6 +389,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) + int r; + size_t len = strlen (fs->windows_systemroot) + 64; + char system[len]; ++ char gpt_prefix[] = "DMIO:ID:"; + snprintf (system, len, "%s/system32/config/system", + fs->windows_systemroot); + +@@ -490,12 +494,18 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) + CLEANUP_FREE char *blob = NULL; + char *device; + int64_t type; ++ bool is_gpt; + + type = guestfs_hivex_value_type (g, v); + blob = guestfs_hivex_value_value (g, v, &len); +- if (blob != NULL && type == 3 && len == 12) { ++ is_gpt = memcmp (blob, gpt_prefix, 8) == 0; ++ if (blob != NULL && type == 3 && (len == 12 || is_gpt)) { + /* Try to map the blob to a known disk and partition. */ +- device = map_registry_disk_blob (g, blob); ++ if (is_gpt) ++ device = map_registry_disk_blob_gpt (g, blob); ++ else ++ device = map_registry_disk_blob (g, blob); ++ + if (device != NULL) { + fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1); + fs->drive_mappings[count++] = device; +@@ -605,6 +615,88 @@ map_registry_disk_blob (guestfs_h *g, const void *blob) + return safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num); + } + ++/* Matches Windows registry HKLM\SYSYTEM\MountedDevices\DosDevices blob to ++ * to libguestfs GPT partition device. For GPT disks, the blob is made of ++ * "DMIO:ID:" prefix followed by the GPT partition GUID. ++ */ ++static char * ++map_registry_disk_blob_gpt (guestfs_h *g, const void *blob) ++{ ++ CLEANUP_FREE_STRING_LIST char **parts = NULL; ++ CLEANUP_FREE char *blob_guid = extract_guid_from_registry_blob (g, blob); ++ size_t i; ++ ++ parts = guestfs_list_partitions (g); ++ if (parts == NULL) ++ return NULL; ++ ++ for (i = 0; parts[i] != NULL; ++i) { ++ CLEANUP_FREE char *fs_guid = NULL; ++ int partnum; ++ CLEANUP_FREE char *device = NULL; ++ CLEANUP_FREE char *type = NULL; ++ ++ partnum = guestfs_part_to_partnum (g, parts[i]); ++ if (partnum == -1) ++ continue; ++ ++ device = guestfs_part_to_dev (g, parts[i]); ++ if (device == NULL) ++ continue; ++ ++ type = guestfs_part_get_parttype (g, device); ++ if (type == NULL) ++ continue; ++ ++ if (STRCASENEQ (type, "gpt")) ++ continue; ++ ++ /* get the GPT parition GUID from the partition block device */ ++ fs_guid = guestfs_part_get_gpt_guid (g, device, partnum); ++ if (fs_guid == NULL) ++ continue; ++ ++ /* if both GUIDs match, we have found the mapping for our device */ ++ if (STRCASEEQ (fs_guid, blob_guid)) ++ return safe_strdup (g, parts[i]); ++ } ++ ++ return NULL; ++} ++ ++/* Extracts the binary GUID stored in blob from Windows registry ++ * HKLM\SYSTYEM\MountedDevices\DosDevices value and converts it to a ++ * GUID string so that it can be matched against libguestfs partition ++ * device GPT GUID. ++ */ ++static char * ++extract_guid_from_registry_blob (guestfs_h *g, const void *blob) ++{ ++ char guid_bytes[16]; ++ uint32_t data1; ++ uint16_t data2, data3; ++ uint64_t data4; ++ ++ /* get the GUID bytes from blob (skip 8 byte "DMIO:ID:" prefix) */ ++ memcpy (&guid_bytes, (char *) blob + 8, sizeof (guid_bytes)); ++ ++ /* copy relevant sections from blob to respective ints */ ++ memcpy (&data1, guid_bytes, sizeof (data1)); ++ memcpy (&data2, guid_bytes + 4, sizeof (data2)); ++ memcpy (&data3, guid_bytes + 6, sizeof (data3)); ++ memcpy (&data4, guid_bytes + 8, sizeof (data4)); ++ ++ /* ensure proper endianness */ ++ data1 = le32toh (data1); ++ data2 = le16toh (data2); ++ data3 = le16toh (data3); ++ data4 = be64toh (data4); ++ ++ return safe_asprintf (g, ++ "%08" PRIX32 "-%04" PRIX16 "-%04" PRIX16 "-%04" PRIX64 "-%012" PRIX64, ++ data1, data2, data3, data4 >> 48, data4 & 0xffffffffffff); ++} ++ + /* NB: This function DOES NOT test for the existence of the file. It + * will return non-NULL even if the file/directory does not exist. + * You have to call guestfs_is_file{,_opts} etc. +-- +1.8.3.1 + diff --git a/SOURCES/0132-v2v-convert-libvirt-display-listen-configuration-RHB.patch b/SOURCES/0132-v2v-convert-libvirt-display-listen-configuration-RHB.patch deleted file mode 100644 index 7a2454c..0000000 --- a/SOURCES/0132-v2v-convert-libvirt-display-listen-configuration-RHB.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 04426a61a5dc72dbaaee666c94398371bd385f76 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 10:38:54 +0200 -Subject: [PATCH] v2v: convert libvirt display listen configuration - (RHBZ#1174073) - -Read the listen configuration from the XML of libvirt domains, restoring -it when writing new libvirt XMLs. - -(cherry picked from commit 9360675dc244a8762e07a8a4289e7a30ca3e1eef) ---- - v2v/input_disk.ml | 3 ++- - v2v/input_libvirtxml.ml | 26 ++++++++++++++++++++++++-- - v2v/output_libvirt.ml | 11 +++++++++++ - v2v/types.ml | 15 +++++++++++++-- - v2v/types.mli | 5 +++++ - 5 files changed, 55 insertions(+), 5 deletions(-) - -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index 98b321c..e5a07b4 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -86,7 +86,8 @@ class input_disk verbose input_format disk = object - s_vcpu = 1; (* 1 vCPU is a safe default *) - s_features = [ "acpi"; "apic"; "pae" ]; - s_display = -- Some { s_display_type = Window; s_keymap = None; s_password = None }; -+ Some { s_display_type = Window; s_keymap = None; s_password = None; -+ s_listen = LNone }; - s_disks = [disk]; - s_removables = []; - s_nics = [network]; -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 8057a00..037405c 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -93,14 +93,36 @@ let parse_libvirt_xml ~verbose xml = - match xpath_to_string "@keymap" "" with "" -> None | k -> Some k in - let password = - match xpath_to_string "@passwd" "" with "" -> None | pw -> Some pw in -+ let listen = -+ let obj = Xml.xpath_eval_expression xpathctx "listen" in -+ let nr_nodes = Xml.xpathobj_nr_nodes obj in -+ if nr_nodes < 1 then LNone -+ else ( -+ (* Use only the first configuration. *) -+ match xpath_to_string "listen[1]/@type" "" with -+ | "" -> LNone -+ | "address" -> -+ (match xpath_to_string "listen[1]/@address" "" with -+ | "" -> LNone -+ | a -> LAddress a -+ ) -+ | "network" -> -+ (match xpath_to_string "listen[1]/@network" "" with -+ | "" -> LNone -+ | n -> LNetwork n -+ ) -+ | t -> -+ warning ~prog (f_" in the input libvirt XML was ignored") t; -+ LNone -+ ) in - match xpath_to_string "@type" "" with - | "" -> None - | "vnc" -> - Some { s_display_type = VNC; -- s_keymap = keymap; s_password = password } -+ s_keymap = keymap; s_password = password; s_listen = listen } - | "spice" -> - Some { s_display_type = Spice; -- s_keymap = keymap; s_password = password } -+ s_keymap = keymap; s_password = password; s_listen = listen } - | "sdl"|"desktop" as t -> - warning ~prog (f_"virt-v2v does not support local displays, so in the input libvirt XML was ignored") t; - None -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index f4e480a..118d4a4 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -237,6 +237,17 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - (match source.s_display with - | Some { s_password = Some pw } -> append_attr ("passwd", pw) graphics - | _ -> ()); -+ (match source.s_display with -+ | Some { s_listen = listen } -> -+ (match listen with -+ | LAddress a -> -+ let sub = e "listen" [ "type", "address"; "address", a ] [] in -+ append_child sub graphics -+ | LNetwork n -> -+ let sub = e "listen" [ "type", "network"; "network", n ] [] in -+ append_child sub graphics -+ | LNone -> ()) -+ | _ -> ()); - - video, graphics in - -diff --git a/v2v/types.ml b/v2v/types.ml -index 97120c2..e8ee288 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -55,8 +55,13 @@ and source_display = { - s_display_type : s_display_type; - s_keymap : string option; - s_password : string option; -+ s_listen : s_display_listen; - } - and s_display_type = Window | VNC | Spice -+and s_display_listen = -+ | LNone -+ | LAddress of string -+ | LNetwork of string - - let rec string_of_source s = - sprintf " source name: %s -@@ -117,11 +122,17 @@ and string_of_source_nic { s_mac = mac; s_vnet = vnet; s_vnet_type = typ } = - | Some mac -> " mac: " ^ mac) - - and string_of_source_display { s_display_type = typ; -- s_keymap = keymap; s_password = password } = -- sprintf "%s%s%s" -+ s_keymap = keymap; s_password = password; -+ s_listen = listen } = -+ sprintf "%s%s%s%s" - (match typ with Window -> "window" | VNC -> "vnc" | Spice -> "spice") - (match keymap with None -> "" | Some km -> " " ^ km) - (match password with None -> "" | Some _ -> " with password") -+ (match listen with -+ | LNone -> "" -+ | LAddress a -> sprintf " listening on address %s" a -+ | LNetwork n -> sprintf " listening on network %s" n -+ ) - - type overlay = { - ov_overlay_file : string; -diff --git a/v2v/types.mli b/v2v/types.mli -index 3d65596..e1aa6f9 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -71,8 +71,13 @@ and source_display = { - s_keymap : string option; (** Guest keymap. *) - s_password : string option; (** If required, password to access - the display. *) -+ s_listen : s_display_listen; (** Listen address. *) - } - and s_display_type = Window | VNC | Spice -+and s_display_listen = -+ | LNone -+ | LAddress of string (** Listen address. *) -+ | LNetwork of string (** Listen network. *) - - val string_of_source : source -> string - val string_of_source_disk : source_disk -> string --- -1.8.3.1 - diff --git a/SOURCES/0133-filearch-support-gzip-xz-compressed-files.patch b/SOURCES/0133-filearch-support-gzip-xz-compressed-files.patch deleted file mode 100644 index 7d8f5dc..0000000 --- a/SOURCES/0133-filearch-support-gzip-xz-compressed-files.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 525a1da911aaccb8587ec4d1b095b2be30f63f90 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 11:07:57 +0200 -Subject: [PATCH] filearch: support gzip/xz-compressed files - -Extract them to find out the architecture of the data they hold. -Useful to detect the architecture of e.g. compressed Linux modules. - -Provide in the test.iso two samples (compressing existing test data) of -binaries compressed with gzip and xz. - -(cherry picked from commit 7291b226d1b08c762ae2f2715a2ac9ed7b8d5d14) ---- - .gitignore | 2 ++ - generator/actions.ml | 4 ++++ - src/filearch.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ - tests/data/Makefile.am | 12 ++++++++++ - 4 files changed, 82 insertions(+) - -diff --git a/.gitignore b/.gitignore -index 269d735..267caa9 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -502,12 +502,14 @@ Makefile.in - /tests/data/100krandom - /tests/data/10klines - /tests/data/abssymlink -+/tests/data/bin-x86_64-dynamic.gz - /tests/data/blank-disk-* - /tests/data/blank-disk-* - /tests/data/hello.b64 - /tests/data/initrd - /tests/data/initrd-x86_64.img - /tests/data/initrd-x86_64.img.gz -+/tests/data/lib-i586.so.xz - /tests/data/test-grep.txt.gz - /tests/data/test.iso - /tests/disks/test-qemu-drive-libvirt.xml -diff --git a/generator/actions.ml b/generator/actions.ml -index c7a1777..ca0208b 100644 ---- a/generator/actions.ml -+++ b/generator/actions.ml -@@ -813,6 +813,10 @@ to specify the QEMU interface emulation to use at run time." }; - [["file_architecture"; "/initrd-x86_64.img"]], "x86_64"), []; - InitISOFS, Always, TestResultString ( - [["file_architecture"; "/initrd-x86_64.img.gz"]], "x86_64"), []; -+ InitISOFS, Always, TestResultString ( -+ [["file_architecture"; "/bin-x86_64-dynamic.gz"]], "x86_64"), []; -+ InitISOFS, Always, TestResultString ( -+ [["file_architecture"; "/lib-i586.so.xz"]], "i386"), []; - ]; - shortdesc = "detect the architecture of a binary file"; - longdesc = "\ -diff --git a/src/filearch.c b/src/filearch.c -index e851279..40e2225 100644 ---- a/src/filearch.c -+++ b/src/filearch.c -@@ -278,6 +278,66 @@ cpio_arch (guestfs_h *g, const char *file, const char *path) - return ret; - } - -+static char * -+compressed_file_arch (guestfs_h *g, const char *path, const char *method) -+{ -+ CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g), *dir = NULL; -+ CLEANUP_FREE char *tempfile = NULL, *tempfile_extracted = NULL; -+ CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); -+ char *ret = NULL; -+ int64_t size; -+ int r; -+ bool matched; -+ -+ if (asprintf (&dir, "%s/libguestfsXXXXXX", tmpdir) == -1) { -+ perrorf (g, "asprintf"); -+ return NULL; -+ } -+ -+ /* Security: Refuse to download file if it is huge. */ -+ size = guestfs_filesize (g, path); -+ if (size == -1 || size > 10000000) { -+ error (g, _("size of %s unreasonable (%" PRIi64 " bytes)"), -+ path, size); -+ goto out; -+ } -+ -+ if (mkdtemp (dir) == NULL) { -+ perrorf (g, "mkdtemp"); -+ goto out; -+ } -+ -+ tempfile = safe_asprintf (g, "%s/file", dir); -+ if (guestfs_download (g, path, tempfile) == -1) -+ goto out; -+ -+ tempfile_extracted = safe_asprintf (g, "%s/file_extracted", dir); -+ -+ /* Construct a command to extract named binaries from the initrd file. */ -+ guestfs_int_cmd_add_string_unquoted (cmd, method); -+ guestfs_int_cmd_add_string_unquoted (cmd, " "); -+ guestfs_int_cmd_add_string_quoted (cmd, tempfile); -+ guestfs_int_cmd_add_string_unquoted (cmd, " > "); -+ guestfs_int_cmd_add_string_quoted (cmd, tempfile_extracted); -+ -+ r = guestfs_int_cmd_run (cmd); -+ if (r == -1) -+ goto out; -+ if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { -+ guestfs_int_external_command_failed (g, r, method, path); -+ goto out; -+ } -+ -+ ret = magic_for_file (g, tempfile_extracted, NULL, &matched); -+ if (!matched) -+ error (g, "file_architecture: could not determine architecture of compressed file"); -+ -+ out: -+ guestfs_int_recursive_remove_dir (g, dir); -+ -+ return ret; -+} -+ - char * - guestfs__file_architecture (guestfs_h *g, const char *path) - { -@@ -300,6 +360,10 @@ guestfs__file_architecture (guestfs_h *g, const char *path) - ret = safe_strdup (g, "x86_64"); - else if (strstr (file, "cpio archive")) - ret = cpio_arch (g, file, path); -+ else if (strstr (file, "gzip compressed data")) -+ ret = compressed_file_arch (g, path, "zcat"); -+ else if (strstr (file, "XZ compressed data")) -+ ret = compressed_file_arch (g, path, "xzcat"); - else - error (g, "file_architecture: unknown architecture: %s", path); - -diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am -index 3127787..7e0d66a 100644 ---- a/tests/data/Makefile.am -+++ b/tests/data/Makefile.am -@@ -76,6 +76,7 @@ images_files_build = \ - 100kallspaces \ - 100krandom \ - 10klines \ -+ bin-x86_64-dynamic.gz \ - blank-disk-1s.raw \ - blank-disk-1s.qcow2 \ - blank-disk-1K.raw \ -@@ -87,6 +88,7 @@ images_files_build = \ - initrd \ - initrd-x86_64.img \ - initrd-x86_64.img.gz \ -+ lib-i586.so.xz \ - test-grep.txt.gz - - check_DATA = $(images_files_build) test.iso -@@ -193,3 +195,13 @@ test-grep.txt.gz: test-grep.txt - rm -f $@ $@-t - gzip --best -c $< > $@-t - mv $@-t $@ -+ -+bin-x86_64-dynamic.gz: bin-x86_64-dynamic -+ rm -f $@ $@-t -+ gzip --best -c $< > $@-t -+ mv $@-t $@ -+ -+lib-i586.so.xz: lib-i586.so -+ rm -f $@ $@-t -+ xz -c $< > $@-t -+ mv $@-t $@ --- -1.8.3.1 - diff --git a/SOURCES/0133-p2v-Refactor-into-get_blockdev_size-and-get_blockdev.patch b/SOURCES/0133-p2v-Refactor-into-get_blockdev_size-and-get_blockdev.patch new file mode 100644 index 0000000..b0a9675 --- /dev/null +++ b/SOURCES/0133-p2v-Refactor-into-get_blockdev_size-and-get_blockdev.patch @@ -0,0 +1,180 @@ +From a9d9b7d3cf9fa9928498273974830e9ba2002e5f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Jun 2016 14:45:05 +0100 +Subject: [PATCH] p2v: Refactor into get_blockdev_size and get_blockdev_model + functions. + +This is just refactoring, but it reveals and fixes a bug too. The +size_gb field was left as NULL when the --test-disk option was used. +Apparently passing NULL to gtk_list_store_set is fine, but just in +case I replaced it with "". + +(cherry picked from commit 68ff3ffd1de7b72255ee5098c0bfef90e6236cb5) +--- + p2v/gui.c | 40 ++++++++----------------------------- + p2v/p2v.h | 2 ++ + p2v/utils.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 75 insertions(+), 32 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 7414037..1bae4d8 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -869,47 +869,23 @@ populate_disks (GtkTreeView *disks_list) + G_TYPE_STRING, G_TYPE_STRING); + if (all_disks != NULL) { + for (i = 0; all_disks[i] != NULL; ++i) { +- CLEANUP_FREE char *size_filename = NULL; +- CLEANUP_FREE char *model_filename = NULL; +- CLEANUP_FREE char *size_str = NULL; ++ uint64_t size; + CLEANUP_FREE char *size_gb = NULL; + CLEANUP_FREE char *model = NULL; +- uint64_t size; + +- if (asprintf (&size_filename, "/sys/block/%s/size", +- all_disks[i]) == -1) { +- perror ("asprintf"); +- exit (EXIT_FAILURE); +- } +- if (g_file_get_contents (size_filename, &size_str, NULL, NULL) && +- sscanf (size_str, "%" SCNu64, &size) == 1) { +- size /= 2*1024*1024; /* size from kernel is given in sectors? */ +- if (asprintf (&size_gb, "%" PRIu64, size) == -1) { +- perror ("asprintf"); +- exit (EXIT_FAILURE); +- } +- } +- +- if (asprintf (&model_filename, "/sys/block/%s/device/model", +- all_disks[i]) == -1) { +- perror ("asprintf"); +- exit (EXIT_FAILURE); +- } +- if (g_file_get_contents (model_filename, &model, NULL, NULL)) { +- /* Need to chomp trailing \n from the content. */ +- size_t len = strlen (model); +- if (len > 0 && model[len-1] == '\n') +- model[len-1] = '\0'; +- } else { +- model = strdup (""); ++ if (all_disks[i][0] != '/') { /* not using --test-disk */ ++ size = get_blockdev_size (all_disks[i]); ++ if (asprintf (&size_gb, "%" PRIu64, size) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ model = get_blockdev_model (all_disks[i]); + } + + gtk_list_store_append (disks_store, &iter); + gtk_list_store_set (disks_store, &iter, + DISKS_COL_CONVERT, TRUE, + DISKS_COL_DEVICE, all_disks[i], +- DISKS_COL_SIZE, size_gb, +- DISKS_COL_MODEL, model, ++ DISKS_COL_SIZE, size_gb ? size_gb : "", ++ DISKS_COL_MODEL, model ? model : "", + -1); + } + } +diff --git a/p2v/p2v.h b/p2v/p2v.h +index 49c97b6..40b05b8 100644 +--- a/p2v/p2v.h ++++ b/p2v/p2v.h +@@ -131,6 +131,8 @@ extern mexp_h *start_remote_connection (struct config *, const char *remote_dir, + extern const char *get_ssh_error (void); + + /* utils.c */ ++extern uint64_t get_blockdev_size (const char *dev); ++extern char *get_blockdev_model (const char *dev); + extern char *get_if_addr (const char *if_name); + extern char *get_if_vendor (const char *if_name, int truncate); + extern void wait_network_online (const struct config *); +diff --git a/p2v/utils.c b/p2v/utils.c +index 3781a8d..18c2b7c 100644 +--- a/p2v/utils.c ++++ b/p2v/utils.c +@@ -20,9 +20,12 @@ + + #include + #include ++#include + #include + #include + #include ++#include ++#include + #include + #include + +@@ -38,6 +41,68 @@ + } \ + } while (0) + ++/** ++ * Return size of a block device, from F/size>. ++ * ++ * This function always succeeds, or else exits (since we expect ++ * C to always be valid and the C file to always exist). ++ */ ++uint64_t ++get_blockdev_size (const char *dev) ++{ ++ CLEANUP_FCLOSE FILE *fp = NULL; ++ CLEANUP_FREE char *path = NULL; ++ CLEANUP_FREE char *size_str = NULL; ++ size_t len; ++ uint64_t size; ++ ++ if (asprintf (&path, "/sys/block/%s/size", dev) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ ++ fp = fopen (path, "r"); ++ if (fp == NULL) ++ error (EXIT_FAILURE, errno, "fopen: %s", path); ++ if (getline (&size_str, &len, fp) == -1) ++ error (EXIT_FAILURE, errno, "getline: %s", path); ++ ++ if (sscanf (size_str, "%" SCNu64, &size) != 1) ++ error (EXIT_FAILURE, 0, "cannot parse %s: %s", path, size_str); ++ ++ size /= 2*1024*1024; /* size from kernel is given in sectors? */ ++ return size; ++} ++ ++/** ++ * Return model of a block device, from F/device/model>. ++ * ++ * Returns C if the file was not found. The caller must ++ * free the returned string. ++ */ ++char * ++get_blockdev_model (const char *dev) ++{ ++ CLEANUP_FCLOSE FILE *fp = NULL; ++ CLEANUP_FREE char *path = NULL; ++ char *model = NULL; ++ size_t len = 0; ++ ssize_t n; ++ ++ if (asprintf (&path, "/sys/block/%s/device/model", dev) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ fp = fopen (path, "r"); ++ if (fp == NULL) { ++ perror (path); ++ return NULL; ++ } ++ if ((n = getline (&model, &len, fp)) == -1) { ++ perror (path); ++ free (model); ++ return NULL; ++ } ++ CHOMP (model, n); ++ return model; ++} ++ + /* Return contents of /sys/class/net//address (if found). */ + char * + get_if_addr (const char *if_name) +-- +1.8.3.1 + diff --git a/SOURCES/0134-p2v-Combine-size-model-columns-into-the-device-colum.patch b/SOURCES/0134-p2v-Combine-size-model-columns-into-the-device-colum.patch new file mode 100644 index 0000000..b29a794 --- /dev/null +++ b/SOURCES/0134-p2v-Combine-size-model-columns-into-the-device-colum.patch @@ -0,0 +1,154 @@ +From 4ada7cd307f4cfb177e0f033eae05592030fc1e0 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Jun 2016 14:53:52 +0100 +Subject: [PATCH] p2v: Combine size & model columns into the device column. + +In the GUI disks block, instead of using separate "Size" and "Model" +columns, combine that information into a markup column under "Device". + +To make the GUI look consistent I also had to change the removables +"Device" column to be a markup column and embolden the device name +there too. + +(cherry picked from commit 6aba5a49448d8ed9776164005080620d37bb97e0) +--- + p2v/gui.c | 51 ++++++++++++++++++++++----------------------------- + p2v/virt-p2v.pod | 8 +++++--- + 2 files changed, 27 insertions(+), 32 deletions(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 1bae4d8..49c703d 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -503,8 +503,6 @@ static uint64_t get_memory_from_conv_dlg (void); + enum { + DISKS_COL_CONVERT = 0, + DISKS_COL_DEVICE, +- DISKS_COL_SIZE, +- DISKS_COL_MODEL, + NUM_DISKS_COLS, + }; + +@@ -859,33 +857,39 @@ static void + populate_disks (GtkTreeView *disks_list) + { + GtkListStore *disks_store; +- GtkCellRenderer *disks_col_convert, *disks_col_device, +- *disks_col_size, *disks_col_model; ++ GtkCellRenderer *disks_col_convert, *disks_col_device; + GtkTreeIter iter; + size_t i; + + disks_store = gtk_list_store_new (NUM_DISKS_COLS, +- G_TYPE_BOOLEAN, G_TYPE_STRING, +- G_TYPE_STRING, G_TYPE_STRING); ++ G_TYPE_BOOLEAN, G_TYPE_STRING); + if (all_disks != NULL) { + for (i = 0; all_disks[i] != NULL; ++i) { + uint64_t size; + CLEANUP_FREE char *size_gb = NULL; + CLEANUP_FREE char *model = NULL; ++ CLEANUP_FREE char *device_descr = NULL; + + if (all_disks[i][0] != '/') { /* not using --test-disk */ + size = get_blockdev_size (all_disks[i]); +- if (asprintf (&size_gb, "%" PRIu64, size) == -1) ++ if (asprintf (&size_gb, "%" PRIu64 "G", size) == -1) + error (EXIT_FAILURE, errno, "asprintf"); + model = get_blockdev_model (all_disks[i]); + } + ++ if (asprintf (&device_descr, ++ "%s\n" ++ "" ++ "%s %s" ++ "\n", ++ all_disks[i], ++ size_gb ? size_gb : "", model ? model : "") == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ + gtk_list_store_append (disks_store, &iter); + gtk_list_store_set (disks_store, &iter, + DISKS_COL_CONVERT, TRUE, +- DISKS_COL_DEVICE, all_disks[i], +- DISKS_COL_SIZE, size_gb ? size_gb : "", +- DISKS_COL_MODEL, model ? model : "", ++ DISKS_COL_DEVICE, device_descr, + -1); + } + } +@@ -905,25 +909,9 @@ populate_disks (GtkTreeView *disks_list) + -1, + _("Device"), + disks_col_device, +- "text", DISKS_COL_DEVICE, ++ "markup", DISKS_COL_DEVICE, + NULL); + gtk_cell_renderer_set_alignment (disks_col_device, 0.0, 0.0); +- disks_col_size = gtk_cell_renderer_text_new (); +- gtk_tree_view_insert_column_with_attributes (disks_list, +- -1, +- _("Size (GB)"), +- disks_col_size, +- "text", DISKS_COL_SIZE, +- NULL); +- gtk_cell_renderer_set_alignment (disks_col_size, 0.0, 0.0); +- disks_col_model = gtk_cell_renderer_text_new (); +- gtk_tree_view_insert_column_with_attributes (disks_list, +- -1, +- _("Model"), +- disks_col_model, +- "text", DISKS_COL_MODEL, +- NULL); +- gtk_cell_renderer_set_alignment (disks_col_model, 0.0, 0.0); + + g_signal_connect (disks_col_convert, "toggled", + G_CALLBACK (toggled), disks_store); +@@ -941,10 +929,15 @@ populate_removable (GtkTreeView *removable_list) + G_TYPE_BOOLEAN, G_TYPE_STRING); + if (all_removable != NULL) { + for (i = 0; all_removable[i] != NULL; ++i) { ++ CLEANUP_FREE char *device_descr = NULL; ++ ++ if (asprintf (&device_descr, "%s\n", all_removable[i]) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ + gtk_list_store_append (removable_store, &iter); + gtk_list_store_set (removable_store, &iter, + REMOVABLE_COL_CONVERT, TRUE, +- REMOVABLE_COL_DEVICE, all_removable[i], ++ REMOVABLE_COL_DEVICE, device_descr, + -1); + } + } +@@ -964,7 +957,7 @@ populate_removable (GtkTreeView *removable_list) + -1, + _("Device"), + removable_col_device, +- "text", REMOVABLE_COL_DEVICE, ++ "markup", REMOVABLE_COL_DEVICE, + NULL); + gtk_cell_renderer_set_alignment (removable_col_device, 0.0, 0.0); + +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index b996541..032a480 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -194,9 +194,11 @@ settings is fine. + ─ ─ ───────────────────────────────────────┐ + Fixed hard disks │ + │ +- Convert Device Size (GB) Model │ +- [✔] sda 1024 HITACHI │ +- [✔] sdb 119 HITACHI │ ++ Convert Device │ ++ [✔] sda │ ++ 1024G HITACHI │ ++ [✔] sdb │ ++ 119G HITACHI │ + │ + + Normally you would want to convert all hard disks. If you want +-- +1.8.3.1 + diff --git a/SOURCES/0134-v2v-convert-libvirt-display-port-configuration.patch b/SOURCES/0134-v2v-convert-libvirt-display-port-configuration.patch deleted file mode 100644 index 7bfe846..0000000 --- a/SOURCES/0134-v2v-convert-libvirt-display-port-configuration.patch +++ /dev/null @@ -1,129 +0,0 @@ -From bbafb02ae131fbe920886e7685ccd2b156af87e9 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 13:22:10 +0200 -Subject: [PATCH] v2v: convert libvirt display port configuration - -Read the port configuration from the XML of libvirt domains, restoring -it when writing new libvirt XMLs instead of always setting the -"autoport" option. - -(cherry picked from commit 1db249a0cc21c65e0d3192567b6016745cea7e58) ---- - v2v/input_disk.ml | 2 +- - v2v/input_libvirtxml.ml | 13 +++++++++++-- - v2v/output_libvirt.ml | 8 +++++++- - v2v/output_qemu.ml | 3 ++- - v2v/types.ml | 1 + - v2v/types.mli | 1 + - 6 files changed, 23 insertions(+), 5 deletions(-) - -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index e5a07b4..54e0bbe 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -87,7 +87,7 @@ class input_disk verbose input_format disk = object - s_features = [ "acpi"; "apic"; "pae" ]; - s_display = - Some { s_display_type = Window; s_keymap = None; s_password = None; -- s_listen = LNone }; -+ s_listen = LNone; s_port = None }; - s_disks = [disk]; - s_removables = []; - s_nics = [network]; -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 037405c..34f1bd1 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -115,14 +115,23 @@ let parse_libvirt_xml ~verbose xml = - warning ~prog (f_" in the input libvirt XML was ignored") t; - LNone - ) in -+ let port = -+ match xpath_to_string "@autoport" "yes" with -+ | "no" -> -+ let port = xpath_to_int "@port" (-1) in -+ if port >= 0 then Some port -+ else None -+ | _ -> None in - match xpath_to_string "@type" "" with - | "" -> None - | "vnc" -> - Some { s_display_type = VNC; -- s_keymap = keymap; s_password = password; s_listen = listen } -+ s_keymap = keymap; s_password = password; s_listen = listen; -+ s_port = port } - | "spice" -> - Some { s_display_type = Spice; -- s_keymap = keymap; s_password = password; s_listen = listen } -+ s_keymap = keymap; s_password = password; s_listen = listen; -+ s_port = port } - | "sdl"|"desktop" as t -> - warning ~prog (f_"virt-v2v does not support local displays, so in the input libvirt XML was ignored") t; - None -diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml -index 118d4a4..dee432d 100644 ---- a/v2v/output_libvirt.ml -+++ b/v2v/output_libvirt.ml -@@ -230,7 +230,6 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - - append_attr ("heads", "1") video; - -- append_attr ("autoport", "yes") graphics; - (match source.s_display with - | Some { s_keymap = Some km } -> append_attr ("keymap", km) graphics - | _ -> ()); -@@ -248,6 +247,13 @@ let create_libvirt_xml ?pool source targets guestcaps target_features = - append_child sub graphics - | LNone -> ()) - | _ -> ()); -+ (match source.s_display with -+ | Some { s_port = Some p } -> -+ append_attr ("autoport", "no") graphics; -+ append_attr ("port", string_of_int p) graphics -+ | _ -> -+ append_attr ("autoport", "yes") graphics; -+ append_attr ("port", "-1") graphics); - - video, graphics in - -diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml -index 4b1d69a..860e1bf 100644 ---- a/v2v/output_qemu.ml -+++ b/v2v/output_qemu.ml -@@ -95,7 +95,8 @@ object - | VNC -> - fpf "%s-display vnc=:0" nl - | Spice -> -- fpf "%s-spice port=5900,addr=127.0.0.1" nl -+ fpf "%s-spice port=%d,addr=127.0.0.1" nl -+ (match display.s_port with None -> 5900 | Some p -> p) - ); - fpf "%s-vga %s" nl - (match guestcaps.gcaps_video with Cirrus -> "cirrus" | QXL -> "qxl") -diff --git a/v2v/types.ml b/v2v/types.ml -index e8ee288..bbe679a 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -56,6 +56,7 @@ and source_display = { - s_keymap : string option; - s_password : string option; - s_listen : s_display_listen; -+ s_port : int option; - } - and s_display_type = Window | VNC | Spice - and s_display_listen = -diff --git a/v2v/types.mli b/v2v/types.mli -index e1aa6f9..5925c97 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -72,6 +72,7 @@ and source_display = { - s_password : string option; (** If required, password to access - the display. *) - s_listen : s_display_listen; (** Listen address. *) -+ s_port : int option; (** Display port. *) - } - and s_display_type = Window | VNC | Spice - and s_display_listen = --- -1.8.3.1 - diff --git a/SOURCES/0135-p2v-Display-serial-number-of-fixed-disks-RHBZ-855058.patch b/SOURCES/0135-p2v-Display-serial-number-of-fixed-disks-RHBZ-855058.patch new file mode 100644 index 0000000..e7a8483 --- /dev/null +++ b/SOURCES/0135-p2v-Display-serial-number-of-fixed-disks-RHBZ-855058.patch @@ -0,0 +1,184 @@ +From 97add8b77aebc8032b7d186f36e264e1d9ffa733 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Jun 2016 15:28:46 +0100 +Subject: [PATCH] p2v: Display serial number of fixed disks (RHBZ#855058). + +Use "lsblk -o serial" to get the serial number of each fixed disk, and +if it is available display that in the GUI. + +(cherry picked from commit 9270a27650abaf586070c51cb90b6a77ec13e0cf) +--- + p2v/dependencies.m4 | 8 ++++---- + p2v/gui.c | 8 ++++++-- + p2v/p2v.h | 1 + + p2v/utils.c | 34 ++++++++++++++++++++++++++++++++++ + p2v/virt-p2v.pod | 2 ++ + 5 files changed, 47 insertions(+), 6 deletions(-) + +diff --git a/p2v/dependencies.m4 b/p2v/dependencies.m4 +index 6cf2961..80d6c92 100644 +--- a/p2v/dependencies.m4 ++++ b/p2v/dependencies.m4 +@@ -30,6 +30,7 @@ ifelse(REDHAT,1, + /usr/bin/qemu-nbd + curl + ethtool ++ util-linux + + dnl The hwdata package contains PCI IDs, used by virt-p2v to display + dnl network vendor information (RHBZ#855059). +@@ -39,7 +40,6 @@ ifelse(REDHAT,1, + pciutils + hdparm + smartmontools +- util-linux + + dnl X11 environment + xterm +@@ -72,11 +72,11 @@ ifelse(DEBIAN,1, + qemu-utils + curl + ethtool ++ util-linux + hwdata + pciutils + hdparm + smartmontools +- util-linux + xorg + xterm + xserver-xorg-video-all +@@ -97,11 +97,11 @@ ifelse(ARCHLINUX,1, + qemu + curl + ethtool ++ util-linux + hwdata + pciutils + hdparm + smartmontools +- util-linux + xterm + xorg-xinit + xorg-server +@@ -123,11 +123,11 @@ ifelse(SUSE,1, + openssh + curl + ethtool ++ util-linux + hwdata + pciutils + hdparm + smartmontools +- util-linux + xinit + xorg-x11-server + xterm +diff --git a/p2v/gui.c b/p2v/gui.c +index 49c703d..58e9ea3 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -868,6 +868,7 @@ populate_disks (GtkTreeView *disks_list) + uint64_t size; + CLEANUP_FREE char *size_gb = NULL; + CLEANUP_FREE char *model = NULL; ++ CLEANUP_FREE char *serial = NULL; + CLEANUP_FREE char *device_descr = NULL; + + if (all_disks[i][0] != '/') { /* not using --test-disk */ +@@ -875,15 +876,18 @@ populate_disks (GtkTreeView *disks_list) + if (asprintf (&size_gb, "%" PRIu64 "G", size) == -1) + error (EXIT_FAILURE, errno, "asprintf"); + model = get_blockdev_model (all_disks[i]); ++ serial = get_blockdev_serial (all_disks[i]); + } + + if (asprintf (&device_descr, + "%s\n" + "" +- "%s %s" ++ "%s %s\n" ++ "%s%s" + "\n", + all_disks[i], +- size_gb ? size_gb : "", model ? model : "") == -1) ++ size_gb ? size_gb : "", model ? model : "", ++ serial ? "s/n " : "", serial ? serial : "") == -1) + error (EXIT_FAILURE, errno, "asprintf"); + + gtk_list_store_append (disks_store, &iter); +diff --git a/p2v/p2v.h b/p2v/p2v.h +index 40b05b8..3e75690 100644 +--- a/p2v/p2v.h ++++ b/p2v/p2v.h +@@ -133,6 +133,7 @@ extern const char *get_ssh_error (void); + /* utils.c */ + extern uint64_t get_blockdev_size (const char *dev); + extern char *get_blockdev_model (const char *dev); ++extern char *get_blockdev_serial (const char *dev); + extern char *get_if_addr (const char *if_name); + extern char *get_if_vendor (const char *if_name, int truncate); + extern void wait_network_online (const struct config *); +diff --git a/p2v/utils.c b/p2v/utils.c +index 18c2b7c..c9fbd2f 100644 +--- a/p2v/utils.c ++++ b/p2v/utils.c +@@ -103,6 +103,40 @@ get_blockdev_model (const char *dev) + return model; + } + ++/** ++ * Return the serial number of a block device. ++ * ++ * This is found using the lsblk command. ++ * ++ * Returns C if we could not get the serial number. The caller ++ * must free the returned string. ++ */ ++char * ++get_blockdev_serial (const char *dev) ++{ ++ CLEANUP_PCLOSE FILE *fp = NULL; ++ CLEANUP_FREE char *cmd = NULL; ++ char *serial = NULL; ++ size_t len = 0; ++ ssize_t n; ++ ++ if (asprintf (&cmd, "lsblk -o serial /dev/%s --nodeps --noheadings", ++ dev) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); ++ fp = popen (cmd, "r"); ++ if (fp == NULL) { ++ perror (cmd); ++ return NULL; ++ } ++ if ((n = getline (&serial, &len, fp)) == -1) { ++ perror (cmd); ++ free (serial); ++ return NULL; ++ } ++ CHOMP (serial, n); ++ return serial; ++} ++ + /* Return contents of /sys/class/net//address (if found). */ + char * + get_if_addr (const char *if_name) +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index 032a480..421925f 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -197,8 +197,10 @@ settings is fine. + Convert Device │ + [✔] sda │ + 1024G HITACHI │ ++ s/n 12345 │ + [✔] sdb │ + 119G HITACHI │ ++ s/n 12346 │ + │ + + Normally you would want to convert all hard disks. If you want +-- +1.8.3.1 + diff --git a/SOURCES/0135-v2v-domainxml-factor-out-connect-and-pool-loading.patch b/SOURCES/0135-v2v-domainxml-factor-out-connect-and-pool-loading.patch deleted file mode 100644 index aac730c..0000000 --- a/SOURCES/0135-v2v-domainxml-factor-out-connect-and-pool-loading.patch +++ /dev/null @@ -1,151 +0,0 @@ -From a71a1ecad6aa3b64616b35ba2bc2a671db80f1d5 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 15:16:01 +0200 -Subject: [PATCH] v2v: domainxml: factor out connect and pool loading - -Factor out the connection and pool loading out of v2v_pool_dumpxml, so -it can be used in later implementations requiring a pool. - -Should be just code motion. - -(cherry picked from commit 9001f61a402dc1820fd4c441e5cc78197c39b73b) ---- - v2v/domainxml-c.c | 101 ++++++++++++++++++++++++++++++++---------------------- - 1 file changed, 60 insertions(+), 41 deletions(-) - -diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c -index c9ed8c5..ba2a5bc 100644 ---- a/v2v/domainxml-c.c -+++ b/v2v/domainxml-c.c -@@ -106,6 +106,63 @@ libvirt_auth_default_wrapper (virConnectCredentialPtr cred, - } - } - -+virStoragePoolPtr -+connect_and_load_pool (value connv, value poolnamev) -+{ -+ CAMLparam2 (connv, poolnamev); -+ const char *conn_uri = NULL; -+ const char *poolname; -+ /* We have to assemble the error on the stack because a dynamic -+ * string couldn't be freed. -+ */ -+ char errmsg[256]; -+ virErrorPtr err; -+ virConnectPtr conn; -+ virStoragePoolPtr pool; -+ -+ if (connv != Val_int (0)) -+ conn_uri = String_val (Field (connv, 0)); /* Some conn */ -+ -+ /* We have to call the default authentication handler, not least -+ * since it handles all the PolicyKit crap. However it also makes -+ * coding this simpler. -+ */ -+ conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault, -+ VIR_CONNECT_RO); -+ if (conn == NULL) { -+ if (conn_uri) -+ snprintf (errmsg, sizeof errmsg, -+ _("cannot open libvirt connection '%s'"), conn_uri); -+ else -+ snprintf (errmsg, sizeof errmsg, _("cannot open libvirt connection")); -+ caml_invalid_argument (errmsg); -+ } -+ -+ /* Suppress default behaviour of printing errors to stderr. Note -+ * you can't set this to NULL to ignore errors; setting it to NULL -+ * restores the default error handler ... -+ */ -+ virConnSetErrorFunc (conn, NULL, ignore_errors); -+ -+ /* Look up the pool. */ -+ poolname = String_val (poolnamev); -+ -+ pool = virStoragePoolLookupByUUIDString (conn, poolname); -+ -+ if (!pool) -+ pool = virStoragePoolLookupByName (conn, poolname); -+ -+ if (!pool) { -+ err = virGetLastError (); -+ snprintf (errmsg, sizeof errmsg, -+ _("cannot find libvirt pool '%s': %s"), poolname, err->message); -+ virConnectClose (conn); -+ caml_invalid_argument (errmsg); -+ } -+ -+ CAMLreturnT (virStoragePoolPtr, pool); -+} -+ - value - v2v_dumpxml (value passwordv, value connv, value domnamev) - { -@@ -216,8 +273,6 @@ v2v_pool_dumpxml (value connv, value poolnamev) - { - CAMLparam2 (connv, poolnamev); - CAMLlocal1 (retv); -- const char *conn_uri = NULL; -- const char *poolname; - /* We have to assemble the error on the stack because a dynamic - * string couldn't be freed. - */ -@@ -227,52 +282,16 @@ v2v_pool_dumpxml (value connv, value poolnamev) - virStoragePoolPtr pool; - char *xml; - -- if (connv != Val_int (0)) -- conn_uri = String_val (Field (connv, 0)); /* Some conn */ -- -- /* We have to call the default authentication handler, not least -- * since it handles all the PolicyKit crap. However it also makes -- * coding this simpler. -- */ -- conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault, -- VIR_CONNECT_RO); -- if (conn == NULL) { -- if (conn_uri) -- snprintf (errmsg, sizeof errmsg, -- _("cannot open libvirt connection '%s'"), conn_uri); -- else -- snprintf (errmsg, sizeof errmsg, _("cannot open libvirt connection")); -- caml_invalid_argument (errmsg); -- } -- -- /* Suppress default behaviour of printing errors to stderr. Note -- * you can't set this to NULL to ignore errors; setting it to NULL -- * restores the default error handler ... -- */ -- virConnSetErrorFunc (conn, NULL, ignore_errors); -- - /* Look up the pool. */ -- poolname = String_val (poolnamev); -- -- pool = virStoragePoolLookupByUUIDString (conn, poolname); -- -- if (!pool) -- pool = virStoragePoolLookupByName (conn, poolname); -- -- if (!pool) { -- err = virGetLastError (); -- snprintf (errmsg, sizeof errmsg, -- _("cannot find libvirt pool '%s': %s"), poolname, err->message); -- virConnectClose (conn); -- caml_invalid_argument (errmsg); -- } -+ pool = connect_and_load_pool (connv, poolnamev); -+ conn = virStoragePoolGetConnect (pool); - - xml = virStoragePoolGetXMLDesc (pool, 0); - if (xml == NULL) { - err = virGetLastError (); - snprintf (errmsg, sizeof errmsg, - _("cannot fetch XML description of pool '%s': %s"), -- poolname, err->message); -+ String_val (poolnamev), err->message); - virStoragePoolFree (pool); - virConnectClose (conn); - caml_invalid_argument (errmsg); --- -1.8.3.1 - diff --git a/SOURCES/0136-p2v-Make-the-conversion-dialog-slightly-higher.patch b/SOURCES/0136-p2v-Make-the-conversion-dialog-slightly-higher.patch new file mode 100644 index 0000000..cc2ac09 --- /dev/null +++ b/SOURCES/0136-p2v-Make-the-conversion-dialog-slightly-higher.patch @@ -0,0 +1,28 @@ +From ca78e55220627878ce3808615953ec9ea8cba16c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Jun 2016 22:28:40 +0100 +Subject: [PATCH] p2v: Make the conversion dialog slightly higher. + +Otherwise the information pane is smaller than its content. + +(cherry picked from commit 40448d6d0d63d79da540c2a9e5eb098b537ede50) +--- + p2v/gui.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 58e9ea3..5ffe3d8 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -541,7 +541,7 @@ create_conversion_dialog (struct config *config) + /* XXX It would be nice not to have to set this explicitly, but + * if we don't then Gtk chooses a very small window. + */ +- gtk_widget_set_size_request (conv_dlg, 900, 560); ++ gtk_widget_set_size_request (conv_dlg, 900, 600); + + /* The main dialog area. */ + hbox = gtk_hbox_new (TRUE, 1); +-- +1.8.3.1 + diff --git a/SOURCES/0136-v2v-domainxml-add-vol_dumpxml.patch b/SOURCES/0136-v2v-domainxml-add-vol_dumpxml.patch deleted file mode 100644 index 060d6b7..0000000 --- a/SOURCES/0136-v2v-domainxml-add-vol_dumpxml.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 124edcf9a0900dc8e721180217b550b846b7c8f9 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 16:35:51 +0200 -Subject: [PATCH] v2v: domainxml: add vol_dumpxml - -Add a new vol_dumpxml to get the XML dump of a pool's volume. - -(cherry picked from commit 5da2ed95c11af6be6bee27f5b3dce8a6f3a29d74) ---- - v2v/domainxml-c.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - v2v/domainxml.ml | 1 + - v2v/domainxml.mli | 6 ++++++ - 3 files changed, 68 insertions(+) - -diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c -index ba2a5bc..60157e1 100644 ---- a/v2v/domainxml-c.c -+++ b/v2v/domainxml-c.c -@@ -305,6 +305,61 @@ v2v_pool_dumpxml (value connv, value poolnamev) - CAMLreturn (retv); - } - -+value -+v2v_vol_dumpxml (value connv, value poolnamev, value volnamev) -+{ -+ CAMLparam3 (connv, poolnamev, volnamev); -+ CAMLlocal1 (retv); -+ const char *volname; -+ /* We have to assemble the error on the stack because a dynamic -+ * string couldn't be freed. -+ */ -+ char errmsg[256]; -+ virErrorPtr err; -+ virConnectPtr conn; -+ virStoragePoolPtr pool; -+ virStorageVolPtr vol; -+ char *xml; -+ -+ /* Look up the pool. */ -+ pool = connect_and_load_pool (connv, poolnamev); -+ conn = virStoragePoolGetConnect (pool); -+ -+ /* Look up the volume. */ -+ volname = String_val (volnamev); -+ -+ vol = virStorageVolLookupByName (pool, volname); -+ -+ if (!vol) { -+ err = virGetLastError (); -+ snprintf (errmsg, sizeof errmsg, -+ _("cannot find libvirt volume '%s': %s"), volname, err->message); -+ virStoragePoolFree (pool); -+ virConnectClose (conn); -+ caml_invalid_argument (errmsg); -+ } -+ -+ xml = virStorageVolGetXMLDesc (vol, 0); -+ if (xml == NULL) { -+ err = virGetLastError (); -+ snprintf (errmsg, sizeof errmsg, -+ _("cannot fetch XML description of volume '%s': %s"), -+ volname, err->message); -+ virStorageVolFree (vol); -+ virStoragePoolFree (pool); -+ virConnectClose (conn); -+ caml_invalid_argument (errmsg); -+ } -+ virStorageVolFree (vol); -+ virStoragePoolFree (pool); -+ virConnectClose (conn); -+ -+ retv = caml_copy_string (xml); -+ free (xml); -+ -+ CAMLreturn (retv); -+} -+ - #else /* !HAVE_LIBVIRT */ - - value -@@ -319,4 +374,10 @@ v2v_pool_dumpxml (value connv, value poolv) - caml_invalid_argument ("virt-v2v was compiled without libvirt support"); - } - -+value -+v2v_vol_dumpxml (value connv, value poolnamev, value volnamev) -+{ -+ caml_invalid_argument ("virt-v2v was compiled without libvirt support"); -+} -+ - #endif /* !HAVE_LIBVIRT */ -diff --git a/v2v/domainxml.ml b/v2v/domainxml.ml -index 61ed5e0..d8b9ed4 100644 ---- a/v2v/domainxml.ml -+++ b/v2v/domainxml.ml -@@ -20,3 +20,4 @@ - - external dumpxml : ?password:string -> ?conn:string -> string -> string = "v2v_dumpxml" - external pool_dumpxml : ?conn:string -> string -> string = "v2v_pool_dumpxml" -+external vol_dumpxml : ?conn:string -> string -> string -> string = "v2v_vol_dumpxml" -diff --git a/v2v/domainxml.mli b/v2v/domainxml.mli -index ffb1c46..98690fe 100644 ---- a/v2v/domainxml.mli -+++ b/v2v/domainxml.mli -@@ -32,3 +32,9 @@ val pool_dumpxml : ?conn:string -> string -> string - (** [pool_dumpxml ?conn pool] returns the libvirt XML of pool [pool]. - The optional [?conn] parameter is the libvirt connection URI. - [pool] may be a pool name or UUID. *) -+ -+val vol_dumpxml : ?conn:string -> string -> string -> string -+(** [vol_dumpxml ?conn pool vol] returns the libvirt XML of volume [vol], -+ which is part of the pool [pool]. -+ The optional [?conn] parameter is the libvirt connection URI. -+ [pool] may be a pool name or UUID. *) --- -1.8.3.1 - diff --git a/SOURCES/0137-p2v-Fix-timeout-error-when-connecting-to-unresponsiv.patch b/SOURCES/0137-p2v-Fix-timeout-error-when-connecting-to-unresponsiv.patch new file mode 100644 index 0000000..fa100fe --- /dev/null +++ b/SOURCES/0137-p2v-Fix-timeout-error-when-connecting-to-unresponsiv.patch @@ -0,0 +1,106 @@ +From 0d49c72d27dd400062c5632a14c4ff225de22832 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 27 Jun 2016 10:16:51 +0100 +Subject: [PATCH] p2v: Fix timeout error when connecting to unresponsive ssh + server (RHBZ#1350363). + +If an ssh server is completely unresponsive (ie. it doesn't even send +back ICMP errors), then eventually ssh times out after ConnectTimeout +seconds [ConnectTimeout is an ssh option]. + +Unfortunately the miniexpect timeout (default 60 seconds) was less +than ConnectTimeout so we never saw the ssh error. Instead we would +see the internal error: + + remote server closed the connection unexpectedly, + waiting for: password prompt + +This commit sets the ssh ConnectTimeout to an explicit value, and sets +the miniexpect timeout to be 20 seconds larger than ConnectTimeout, so +that in most cases we will see the ssh error message before miniexpect +times out. + +Thanks: Ming Xie for finding and diagnosing the problem +(cherry picked from commit 0b836c40f2674e8632212363b9ad4f7781e5622e) +--- + p2v/ssh.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/p2v/ssh.c b/p2v/ssh.c +index 93c4c55..f4adde4 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -57,6 +57,8 @@ + #include "miniexpect.h" + #include "p2v.h" + ++#define SSH_TIMEOUT 60 /* seconds */ ++ + char *v2v_version = NULL; + char **input_drivers = NULL; + char **output_drivers = NULL; +@@ -309,6 +311,7 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + { + size_t i, j, nr_args, count; + char port_str[64]; ++ char connect_timeout_str[128]; + CLEANUP_FREE /* [sic] */ const char **args = NULL; + mexp_h *h; + const int ovecsize = 12; +@@ -328,9 +331,9 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + nr_args = guestfs_int_count_strings (extra_args); + + if (using_password_auth) +- nr_args += 11; +- else + nr_args += 13; ++ else ++ nr_args += 15; + args = malloc (sizeof (char *) * nr_args); + if (args == NULL) { + perror ("malloc"); +@@ -346,6 +349,10 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + args[j++] = config->username ? config->username : "root"; + args[j++] = "-o"; /* Host key will always be novel. */ + args[j++] = "StrictHostKeyChecking=no"; ++ args[j++] = "-o"; /* ConnectTimeout */ ++ snprintf (connect_timeout_str, sizeof connect_timeout_str, ++ "ConnectTimeout=%d", SSH_TIMEOUT); ++ args[j++] = connect_timeout_str; + if (using_password_auth) { + /* Only use password authentication. */ + args[j++] = "-o"; +@@ -366,12 +373,30 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt) + args[j++] = NULL; + assert (j == nr_args); + ++#if DEBUG_STDERR && 0 ++ fputs ("ssh command: ", stderr); ++ for (i = 0; i < nr_args - 1; ++i) { ++ if (i > 0) fputc (' ', stderr); ++ fputs (args[i], stderr); ++ } ++ fputc ('\n', stderr); ++#endif ++ ++ /* Create the miniexpect handle. */ + h = mexp_spawnv ("ssh", (char **) args); + if (h == NULL) { + set_ssh_internal_error ("ssh: mexp_spawnv: %m"); + return NULL; + } + ++ /* We want the ssh ConnectTimeout to be less than the miniexpect ++ * timeout, so that if the server is completely unresponsive we ++ * still see the error from ssh, not a timeout from miniexpect. The ++ * obvious solution to this is to set ConnectTimeout (above) and to ++ * set the miniexpect timeout to be a little bit larger. ++ */ ++ mexp_set_timeout (h, SSH_TIMEOUT + 20); ++ + if (using_password_auth && + config->password && strlen (config->password) > 0) { + CLEANUP_FREE char *ssh_message = NULL; +-- +1.8.3.1 + diff --git a/SOURCES/0137-v2v-pass-libvirt-connection-URI-to-parse_libvirt_xml.patch b/SOURCES/0137-v2v-pass-libvirt-connection-URI-to-parse_libvirt_xml.patch deleted file mode 100644 index fc7e86f..0000000 --- a/SOURCES/0137-v2v-pass-libvirt-connection-URI-to-parse_libvirt_xml.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 08eea12254c7c6d072028638965101e1a1c9448b Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 16:37:55 +0200 -Subject: [PATCH] v2v: pass libvirt connection URI to parse_libvirt_xml - -This makes it possible to connect to the right libvirt. - -(cherry picked from commit f7529522ab74d824c550d62953f0b8ecf1e61466) ---- - v2v/input_libvirt_other.ml | 2 +- - v2v/input_libvirt_vcenter_https.ml | 2 +- - v2v/input_libvirt_xen_ssh.ml | 2 +- - v2v/input_libvirtxml.ml | 2 +- - v2v/input_libvirtxml.mli | 2 +- - 5 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml -index c704af6..e675427 100644 ---- a/v2v/input_libvirt_other.ml -+++ b/v2v/input_libvirt_other.ml -@@ -70,7 +70,7 @@ object - *) - let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in - -- let source, disks = Input_libvirtxml.parse_libvirt_xml ~verbose xml in -+ let source, disks = Input_libvirtxml.parse_libvirt_xml ?conn:libvirt_uri ~verbose xml in - let disks = - List.map (fun { Input_libvirtxml.p_source_disk = disk } -> disk) disks in - { source with s_disks = disks } -diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml -index 783b630..d0d860e 100644 ---- a/v2v/input_libvirt_vcenter_https.ml -+++ b/v2v/input_libvirt_vcenter_https.ml -@@ -298,7 +298,7 @@ object - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in -- let source, disks = parse_libvirt_xml ~verbose xml in -+ let source, disks = parse_libvirt_xml ?conn:libvirt_uri ~verbose xml in - - (* Save the original source paths, so that we can remap them again - * in [#adjust_overlay_parameters]. -diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml -index cf5f1ae..ccb8bd0 100644 ---- a/v2v/input_libvirt_xen_ssh.ml -+++ b/v2v/input_libvirt_xen_ssh.ml -@@ -46,7 +46,7 @@ object - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in -- let source, disks = parse_libvirt_xml ~verbose xml in -+ let source, disks = parse_libvirt_xml ?conn:libvirt_uri ~verbose xml in - - (* Map the filename (which is relative to the remote - * Xen server) to an ssh URI. This is a JSON URI looking something -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 34f1bd1..357c46f 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -33,7 +33,7 @@ and parsed_source = - | P_source_file of string - | P_dont_rewrite - --let parse_libvirt_xml ~verbose xml = -+let parse_libvirt_xml ?conn ~verbose xml = - if verbose then - printf "libvirt xml is:\n%s\n" xml; - -diff --git a/v2v/input_libvirtxml.mli b/v2v/input_libvirtxml.mli -index e450899..934c9c5 100644 ---- a/v2v/input_libvirtxml.mli -+++ b/v2v/input_libvirtxml.mli -@@ -27,7 +27,7 @@ and parsed_source = - | P_source_file of string (** *) - | P_dont_rewrite (** s_qemu_uri is already set. *) - --val parse_libvirt_xml : verbose:bool -> string -> Types.source * parsed_disk list -+val parse_libvirt_xml : ?conn:string -> verbose:bool -> string -> Types.source * parsed_disk list - (** Take libvirt XML and parse it into a {!Types.source} structure and a - list of source disks. - --- -1.8.3.1 - diff --git a/SOURCES/0138-p2v-virt-p2v-make-disk-passes-through-no-warn-if-par.patch b/SOURCES/0138-p2v-virt-p2v-make-disk-passes-through-no-warn-if-par.patch new file mode 100644 index 0000000..cd9da22 --- /dev/null +++ b/SOURCES/0138-p2v-virt-p2v-make-disk-passes-through-no-warn-if-par.patch @@ -0,0 +1,88 @@ +From e46c64da93c82c765a36c75df65094d0221f99fc Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 27 Jun 2016 11:18:43 +0100 +Subject: [PATCH] p2v: virt-p2v-make-disk passes through --no-warn-if-partition + to virt-builder. + +See: https://bugzilla.redhat.com/show_bug.cgi?id=1342337#c4 + +Thanks: Junqin Zhou +(cherry picked from commit 07137ea565653ca22e055cef09a08add6ad5f1c9) +--- + p2v/virt-p2v-make-disk.in | 17 +++++++++++++---- + p2v/virt-p2v-make-disk.pod | 7 +++++++ + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/p2v/virt-p2v-make-disk.in b/p2v/virt-p2v-make-disk.in +index d58e7f1..cbbc9ff 100644 +--- a/p2v/virt-p2v-make-disk.in ++++ b/p2v/virt-p2v-make-disk.in +@@ -24,7 +24,7 @@ version="@PACKAGE_VERSION@" + + TEMP=`getopt \ + -o o:V \ +- --long help,inject-ssh-identity:,output:,verbose,version \ ++ --long help,inject-ssh-identity:,no-warn-if-partition,output:,verbose,version \ + -n $program -- "$@"` + if [ $? != 0 ]; then + echo "$program: problem parsing the command line arguments" +@@ -35,6 +35,7 @@ eval set -- "$TEMP" + output= + upload= + verbose= ++declare -a passthru + + usage () + { +@@ -57,11 +58,18 @@ while true; do + set +x + verbose=1 + shift;; ++ ++ # virt-builder parameters that are passed through. ++ --no-warn-if-partition) ++ passthru[${#passthru[*]}]="$1" ++ shift;; ++ ++ # help etc. ++ --help) ++ usage 0;; + -V|--version) + echo "$program $version" + exit 0;; +- --help) +- usage 0;; + --) + shift + break;; +@@ -206,7 +214,8 @@ virt-builder "$osversion" \ + s/^[Login]/[Login]\nReserveVT=1\n/ + ' \ + $upload \ +- $extra_args ++ $extra_args \ ++ "${passthru[@]}" + + # We have to do this so the cleanup() handler runs. + exit $? +diff --git a/p2v/virt-p2v-make-disk.pod b/p2v/virt-p2v-make-disk.pod +index d5a5db5..2e1bffb 100644 +--- a/p2v/virt-p2v-make-disk.pod ++++ b/p2v/virt-p2v-make-disk.pod +@@ -99,6 +99,13 @@ Display help. + Add an SSH identity (private key) file into the image. + See L above. + ++=item B<--no-warn-if-partition> ++ ++Normally you should not write to a partition on a USB drive (ie. don't ++use S>, use S> to make a bootable USB ++drive). If you do this, virt-builder prints a warning. This option ++suppresses that warning. ++ + =item B<-o> OUTPUT + + =item B<--output> OUTPUT +-- +1.8.3.1 + diff --git a/SOURCES/0138-v2v-start-importing-volume-disk-types-RHBZ-1146832.patch b/SOURCES/0138-v2v-start-importing-volume-disk-types-RHBZ-1146832.patch deleted file mode 100644 index 9e55e2d..0000000 --- a/SOURCES/0138-v2v-start-importing-volume-disk-types-RHBZ-1146832.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 88d41fa8dd122a9f90430a4615497dcc29c10231 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 14 Apr 2015 16:59:57 +0200 -Subject: [PATCH] v2v: start importing "volume" disk types (RHBZ#1146832) - -Import disks stored as "file"-type volumes. - -Side effect: a guest converted to libvirt using virt-v2v can be -converted again using virt-v2v. - -(cherry picked from commit 08b1ba35cfaa526982911fe9f355ed9c168d942d) ---- - v2v/input_libvirtxml.ml | 34 ++++++++++++++++++++++++++++++++-- - 1 file changed, 32 insertions(+), 2 deletions(-) - -diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml -index 357c46f..16a8115 100644 ---- a/v2v/input_libvirtxml.ml -+++ b/v2v/input_libvirtxml.ml -@@ -180,8 +180,8 @@ let parse_libvirt_xml ?conn ~verbose xml = - | "" -> None - | format -> Some format in - -- (* The attribute may be 'block', 'file' or -- * 'network'. We ignore any other types. -+ (* The attribute may be 'block', 'file', -+ * 'network' or 'volume'. We ignore any other types. - *) - match xpath_to_string "@type" "" with - | "block" -> -@@ -213,6 +213,36 @@ let parse_libvirt_xml ?conn ~verbose xml = - warning ~prog (f_"network with was ignored") - protocol - ) -+ | "volume" -> -+ let pool = xpath_to_string "source/@pool" "" in -+ let vol = xpath_to_string "source/@volume" "" in -+ if pool <> "" && vol <> "" then ( -+ let xml = Domainxml.vol_dumpxml ?conn pool vol in -+ let doc = Xml.parse_memory xml in -+ let xpathctx = Xml.xpath_new_context doc in -+ -+ let xpath_to_string expr default = -+ let obj = Xml.xpath_eval_expression xpathctx expr in -+ if Xml.xpathobj_nr_nodes obj < 1 then default -+ else ( -+ let node = Xml.xpathobj_node doc obj 0 in -+ Xml.node_as_string node -+ ) in -+ -+ (* Use the format specified in the volume itself. *) -+ let format = -+ match xpath_to_string "/volume/target/format/@type" "" with -+ | "" -> None -+ | format -> Some format in -+ -+ match xpath_to_string "/volume/@type" "" with -+ | "" | "file" -> -+ let path = xpath_to_string "/volume/target/path/text()" "" in -+ if path <> "" then -+ add_disk path format controller (P_source_file path) -+ | vol_type -> -+ warning ~prog (f_" with was ignored") vol_type -+ ) - | disk_type -> - warning ~prog (f_" was ignored") disk_type - done; --- -1.8.3.1 - diff --git a/SOURCES/0139-p2v-Add-install-option-to-virt-p2v-make-disk-virt-p2.patch b/SOURCES/0139-p2v-Add-install-option-to-virt-p2v-make-disk-virt-p2.patch new file mode 100644 index 0000000..9d5dffa --- /dev/null +++ b/SOURCES/0139-p2v-Add-install-option-to-virt-p2v-make-disk-virt-p2.patch @@ -0,0 +1,173 @@ +From 7708cc27dff5cd6836c855e3ec3df771617d473f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 27 Jun 2016 11:40:18 +0100 +Subject: [PATCH] p2v: Add --install option to virt-p2v-make-disk, + virt-p2v-make-kickstart. + +This allows you to install extra packages in the disk/ISO. The +implementation of this option in virt-p2v-make-disk was particularly +simple and followed naturally from the previous commit. + +(cherry picked from commit 2783f695ff425ba4ff9cd59f28bb6046a3bb1114) +--- + p2v/p2v.ks.in | 4 ++++ + p2v/virt-p2v-make-disk.in | 7 ++++++- + p2v/virt-p2v-make-disk.pod | 14 ++++++++++++++ + p2v/virt-p2v-make-kickstart.in | 8 +++++++- + p2v/virt-p2v-make-kickstart.pod | 14 ++++++++++++++ + 5 files changed, 45 insertions(+), 2 deletions(-) + +diff --git a/p2v/p2v.ks.in b/p2v/p2v.ks.in +index 384843d..62a9d01 100644 +--- a/p2v/p2v.ks.in ++++ b/p2v/p2v.ks.in +@@ -76,6 +76,10 @@ dracut-live + # The dependencies of virt-p2v. + __DEPENDENCIES__ + ++# Extra packages requested by the user via the virt-p2v-make-kickstart ++# --install option (if any). ++__EXTRA_PACKAGES__ ++ + %end + + # Post-install configuration. +diff --git a/p2v/virt-p2v-make-disk.in b/p2v/virt-p2v-make-disk.in +index cbbc9ff..cc7ee93 100644 +--- a/p2v/virt-p2v-make-disk.in ++++ b/p2v/virt-p2v-make-disk.in +@@ -24,7 +24,7 @@ version="@PACKAGE_VERSION@" + + TEMP=`getopt \ + -o o:V \ +- --long help,inject-ssh-identity:,no-warn-if-partition,output:,verbose,version \ ++ --long help,inject-ssh-identity:,install:,no-warn-if-partition,output:,verbose,version \ + -n $program -- "$@"` + if [ $? != 0 ]; then + echo "$program: problem parsing the command line arguments" +@@ -60,6 +60,11 @@ while true; do + shift;; + + # virt-builder parameters that are passed through. ++ --install) ++ passthru[${#passthru[*]}]="$1" ++ passthru[${#passthru[*]}]="$2" ++ shift 2;; ++ + --no-warn-if-partition) + passthru[${#passthru[*]}]="$1" + shift;; +diff --git a/p2v/virt-p2v-make-disk.pod b/p2v/virt-p2v-make-disk.pod +index 2e1bffb..514ddb0 100644 +--- a/p2v/virt-p2v-make-disk.pod ++++ b/p2v/virt-p2v-make-disk.pod +@@ -52,6 +52,15 @@ Write a virt-p2v bootable virtual disk image, and boot it under qemu: + where F would be the disk image of some guest that + you want to convert (for testing only). + ++=head1 ADDING EXTRA PACKAGES ++ ++You can install extra packages using the I<--install> option. This ++can be useful for making a more fully-featured virt-p2v disk with ++extra tools for debugging and troubleshooting. Give a list of ++packages, separated by commas. For example: ++ ++ virt-p2v-make-disk -o /var/tmp/p2v.img --install tcpdump,traceroute ++ + =head1 ADDING AN SSH IDENTITY + + You can inject an SSH identity (private key) file to the image using +@@ -99,6 +108,11 @@ Display help. + Add an SSH identity (private key) file into the image. + See L above. + ++=item B<--install> pkg,pkg,... ++ ++Add extra packages to the image. ++See L above. ++ + =item B<--no-warn-if-partition> + + Normally you should not write to a partition on a USB drive (ie. don't +diff --git a/p2v/virt-p2v-make-kickstart.in b/p2v/virt-p2v-make-kickstart.in +index 8a6e4d8..c57e212 100644 +--- a/p2v/virt-p2v-make-kickstart.in ++++ b/p2v/virt-p2v-make-kickstart.in +@@ -24,7 +24,7 @@ version="@PACKAGE_VERSION@" + + TEMP=`getopt \ + -o o:vV \ +- --long help,inject-ssh-identity:,output:,proxy:,verbose,version \ ++ --long help,inject-ssh-identity:,install:,output:,proxy:,verbose,version \ + -n $program -- "$@"` + if [ $? != 0 ]; then + echo "$program: problem parsing the command line arguments" +@@ -41,6 +41,7 @@ usage () + exit $1 + } + ++extra_packages= + output=p2v.ks + proxy= + ssh_identity= +@@ -51,6 +52,9 @@ while true; do + --inject-ssh-identity) + ssh_identity="$2" + shift 2;; ++ --install) ++ extra_packages="${extra_packages:+${extra_packages},}$2" ++ shift 2;; + -o|--output) + output="$2" + shift 2;; +@@ -186,6 +190,7 @@ done < $depsfile + -v "base64_ssh_identity=$base64_ssh_identity" \ + -v "base64_virt_p2v=$base64_virt_p2v" \ + -v "dependencies=$dependencies" \ ++ -v "extra_packages=$extra_packages" \ + -v "md5sum_virt_p2v=$md5sum_virt_p2v" \ + -v "repos=$repos" \ + -v "libexecdir=$libexecdir" \ +@@ -199,6 +204,7 @@ done < $depsfile + gsub (/__BASE64_SSH_IDENTITY__/, base64_ssh_identity); + gsub (/__BASE64_VIRT_P2V__/, base64_virt_p2v); + gsub (/__DEPENDENCIES__/, dependencies); ++ gsub (/__EXTRA_PACKAGES__/, gensub (/,/, "\n", "g", extra_packages)); + gsub (/__MD5SUM_VIRT_P2V__/, md5sum_virt_p2v); + gsub (/__REPOS__/, repos); + gsub (/__LIBEXECDIR__/, libexecdir); +diff --git a/p2v/virt-p2v-make-kickstart.pod b/p2v/virt-p2v-make-kickstart.pod +index cea3787..7e41c9d 100644 +--- a/p2v/virt-p2v-make-kickstart.pod ++++ b/p2v/virt-p2v-make-kickstart.pod +@@ -191,6 +191,15 @@ pxelinux starts up. + + =back + ++=head1 ADDING EXTRA PACKAGES ++ ++You can install extra packages using the I<--install> option. This ++can be useful for making a more fully-featured virt-p2v disk with ++extra tools for debugging and troubleshooting. Give a list of ++packages, separated by commas. For example: ++ ++ virt-p2v-make-kickstart [...] --install tcpdump,traceroute ++ + =head1 ADDING AN SSH IDENTITY + + You can inject an SSH identity (private key) file to the kickstart and +@@ -243,6 +252,11 @@ Display help. + Add an SSH identity (private key) file into the kickstart. + See L above. + ++=item B<--install> pkg,pkg,... ++ ++Add extra packages to the kickstart C<%packages> section. ++See L above. ++ + =item B<-o> OUTPUT + + =item B<--output> OUTPUT +-- +1.8.3.1 + diff --git a/SOURCES/0139-v2v-support-tar.gz-and-tar.xz-ova-files.patch b/SOURCES/0139-v2v-support-tar.gz-and-tar.xz-ova-files.patch deleted file mode 100644 index 51a0d3a..0000000 --- a/SOURCES/0139-v2v-support-tar.gz-and-tar.xz-ova-files.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 54350043efed23af2770a9b5a4b19afb1abdf4e5 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 15 Apr 2015 11:21:57 +0200 -Subject: [PATCH] v2v: support tar.gz and tar.xz ova files - -When dealing with a ova detected as gzip of xz, uncompress few bytes of -it to check whether it is a compressed tarball, and if so untar it. - -Related to RHBZ#1186800. - -(cherry picked from commit 3c582cfb8d62013a935953e919c79009452254f9) ---- - v2v/input_ova.ml | 48 ++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 42 insertions(+), 6 deletions(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 211db43..8079d28 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -43,13 +43,32 @@ object - *) - if is_directory ova then ova - else ( -+ let uncompress_head zcat file = -+ let cmd = sprintf "%s %s" zcat (quote file) in -+ let chan_out, chan_in, chan_err = Unix.open_process_full cmd [||] in -+ let buf = String.create 512 in -+ let len = input chan_out buf 0 (String.length buf) in -+ (* We're expecting the subprocess to fail because we close -+ * the pipe early, so: -+ *) -+ ignore (Unix.close_process_full (chan_out, chan_in, chan_err)); -+ -+ let tmpfile, chan = Filename.open_temp_file ~temp_dir:tmpdir "ova.file." "" in -+ output chan buf 0 len; -+ close_out chan; -+ -+ tmpfile in -+ -+ let untar ?(format = "") file outdir = -+ let cmd = sprintf "tar -x%sf %s -C %s" format (quote file) (quote outdir) in -+ if verbose then printf "%s\n%!" cmd; -+ if Sys.command cmd <> 0 then -+ error (f_"error unpacking %s, see earlier error messages") ova in -+ - match detect_file_type ova with - | `Tar -> - (* Normal ovas are tar file (not compressed). *) -- let cmd = sprintf "tar -xf %s -C %s" (quote ova) (quote tmpdir) in -- if verbose then printf "%s\n%!" cmd; -- if Sys.command cmd <> 0 then -- error (f_"error unpacking %s, see earlier error messages") ova; -+ untar ova tmpdir; - tmpdir - | `Zip -> - (* However, although not permitted by the spec, people ship -@@ -62,8 +81,25 @@ object - if Sys.command cmd <> 0 then - error (f_"error unpacking %s, see earlier error messages") ova; - tmpdir -- | `GZip | `XZ | `Unknown -> -- error (f_"%s: unsupported file format\n\nFormats which we currently understand for '-i ova' are: uncompressed tar, zip") ova -+ | (`GZip|`XZ) as format -> -+ let zcat, tar_fmt = -+ match format with -+ | `GZip -> "zcat", "z" -+ | `XZ -> "xzcat", "J" -+ | _ -> assert false in -+ let tmpfile = uncompress_head zcat ova in -+ let tmpfiletype = detect_file_type tmpfile in -+ (* Remove tmpfile from tmpdir, to leave it empty. *) -+ Sys.remove tmpfile; -+ (match tmpfiletype with -+ | `Tar -> -+ untar ~format:tar_fmt ova tmpdir; -+ tmpdir -+ | `Zip | `GZip | `XZ | `Unknown -> -+ error (f_"%s: unsupported file format\n\nFormats which we currently understand for '-i ova' are: tar (uncompressed, compress with gzip or xz), zip") ova -+ ) -+ | `Unknown -> -+ error (f_"%s: unsupported file format\n\nFormats which we currently understand for '-i ova' are: tar (uncompressed, compress with gzip or xz), zip") ova - ) in - - (* Exploded path must be absolute (RHBZ#1155121). *) --- -1.8.3.1 - diff --git a/SOURCES/0140-p2v-Add-less-package-to-the-ISO.patch b/SOURCES/0140-p2v-Add-less-package-to-the-ISO.patch new file mode 100644 index 0000000..4560fe8 --- /dev/null +++ b/SOURCES/0140-p2v-Add-less-package-to-the-ISO.patch @@ -0,0 +1,85 @@ +From 7f790117b1a5d6ce5d57dcae6e82517dfa8de350 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 27 Jun 2016 15:31:37 +0100 +Subject: [PATCH] p2v: Add 'less' package to the ISO. + +When running the xterm it is very useful to be able to do: + + dmesg | less + +(cherry picked from commit 5f248dcd395907f80e5a7a1ccb0d5f56b3e2e015) +--- + p2v/dependencies.m4 | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/p2v/dependencies.m4 b/p2v/dependencies.m4 +index 80d6c92..6acae8c 100644 +--- a/p2v/dependencies.m4 ++++ b/p2v/dependencies.m4 +@@ -31,6 +31,7 @@ ifelse(REDHAT,1, + curl + ethtool + util-linux ++ xterm + + dnl The hwdata package contains PCI IDs, used by virt-p2v to display + dnl network vendor information (RHBZ#855059). +@@ -40,9 +41,9 @@ ifelse(REDHAT,1, + pciutils + hdparm + smartmontools ++ less + + dnl X11 environment +- xterm + /usr/bin/xinit + /usr/bin/Xorg + xorg-x11-drivers +@@ -73,12 +74,13 @@ ifelse(DEBIAN,1, + curl + ethtool + util-linux ++ xterm + hwdata + pciutils + hdparm + smartmontools ++ less + xorg +- xterm + xserver-xorg-video-all + fonts-dejavu + metacity +@@ -98,11 +100,12 @@ ifelse(ARCHLINUX,1, + curl + ethtool + util-linux ++ xterm + hwdata + pciutils + hdparm + smartmontools +- xterm ++ less + xorg-xinit + xorg-server + xf86-video-* +@@ -124,13 +127,14 @@ ifelse(SUSE,1, + curl + ethtool + util-linux ++ xterm + hwdata + pciutils + hdparm + smartmontools ++ less + xinit + xorg-x11-server +- xterm + xf86-video-* + dejavu-fonts + NetworkManager +-- +1.8.3.1 + diff --git a/SOURCES/0140-v2v-use-.ovf-and-.mf-files-anywhere-within-ova-files.patch b/SOURCES/0140-v2v-use-.ovf-and-.mf-files-anywhere-within-ova-files.patch deleted file mode 100644 index f882de9..0000000 --- a/SOURCES/0140-v2v-use-.ovf-and-.mf-files-anywhere-within-ova-files.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 39536e75adc3444fe77952be8fdc978271dbb2eb Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 15 Apr 2015 13:22:13 +0200 -Subject: [PATCH] v2v: use .ovf and .mf files anywhere within ova files - -Do not rely on .ovf and .mf files being in the top-level of the ova -archive, but search them anywhere within the content of the ova. - -This also changes the result of the search of the .ovf file: previously, -one (random) file was picked in case there were more than one, while now -this situation triggers an error. - -Related to RHBZ#1186800. - -(cherry picked from commit 8049474636d1a56cb259af6e527fb6b0a42e43e1) ---- - v2v/input_ova.ml | 91 +++++++++++++++++++++++++++++++++----------------------- - 1 file changed, 53 insertions(+), 38 deletions(-) - -diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml -index 8079d28..f530b92 100644 ---- a/v2v/input_ova.ml -+++ b/v2v/input_ova.ml -@@ -107,51 +107,66 @@ object - if not (Filename.is_relative exploded) then exploded - else Sys.getcwd () // exploded in - -- let files = Sys.readdir exploded in -- let ovf = ref "" in -+ (* Find files in [dir] ending with [ext]. *) -+ let find_files dir ext = -+ let rec loop = function -+ | [] -> [] -+ | dir :: rest -> -+ let files = Array.to_list (Sys.readdir dir) in -+ let files = List.map (Filename.concat dir) files in -+ let dirs, files = List.partition Sys.is_directory files in -+ let files = List.filter ( -+ fun x -> -+ Filename.check_suffix x ext -+ ) files in -+ files @ loop (rest @ dirs) -+ in -+ loop [dir] -+ in -+ - (* Search for the ovf file. *) -- Array.iter ( -- fun file -> -- if Filename.check_suffix file ".ovf" then ovf := file -- ) files; -- let ovf = !ovf in -- if ovf = "" then -- error (f_"no .ovf file was found in %s") ova; -+ let ovf = find_files exploded ".ovf" in -+ let ovf = -+ match ovf with -+ | [] -> -+ error (f_"no .ovf file was found in %s") ova -+ | [x] -> x -+ | _ :: _ -> -+ error (f_"more than one .ovf file was found in %s") ova in - - (* Read any .mf (manifest) files and verify sha1. *) -+ let mf = find_files exploded ".mf" in - let rex = Str.regexp "SHA1(\\(.*\\))=\\([0-9a-fA-F]+\\)\r?" in -- Array.iter ( -+ List.iter ( - fun mf -> -- if Filename.check_suffix mf ".mf" then ( -- let chan = open_in (exploded // mf) in -- let rec loop () = -- let line = input_line chan in -- if Str.string_match rex line 0 then ( -- let disk = Str.matched_group 1 line in -- let expected = Str.matched_group 2 line in -- let cmd = sprintf "sha1sum %s" (quote (exploded // disk)) in -- let out = external_command ~prog cmd in -- match out with -- | [] -> -- error (f_"no output from sha1sum command, see previous errors") -- | [line] -> -- let actual, _ = string_split " " line in -- if actual <> expected then -- error (f_"checksum of disk %s does not match manifest %s (actual sha1(%s) = %s, expected sha1 (%s) = %s)") -- disk mf disk actual disk expected; -- if verbose then -- printf "sha1 of %s matches expected checksum %s\n%!" -- disk expected -- | _::_ -> error (f_"cannot parse output of sha1sum command") -- ) -- in -- (try loop () with End_of_file -> ()); -- close_in chan -- ) -- ) files; -+ let chan = open_in mf in -+ let rec loop () = -+ let line = input_line chan in -+ if Str.string_match rex line 0 then ( -+ let disk = Str.matched_group 1 line in -+ let expected = Str.matched_group 2 line in -+ let cmd = sprintf "sha1sum %s" (quote (exploded // disk)) in -+ let out = external_command ~prog cmd in -+ match out with -+ | [] -> -+ error (f_"no output from sha1sum command, see previous errors") -+ | [line] -> -+ let actual, _ = string_split " " line in -+ if actual <> expected then -+ error (f_"checksum of disk %s does not match manifest %s (actual sha1(%s) = %s, expected sha1 (%s) = %s)") -+ disk mf disk actual disk expected; -+ if verbose then -+ printf "sha1 of %s matches expected checksum %s\n%!" -+ disk expected -+ | _::_ -> error (f_"cannot parse output of sha1sum command") -+ ) -+ in -+ (try loop () with End_of_file -> ()); -+ close_in chan -+ ) mf; - - (* Parse the ovf file. *) -- let xml = read_whole_file (exploded // ovf) in -+ let xml = read_whole_file ovf in - let doc = Xml.parse_memory xml in - - (* Handle namespaces. *) --- -1.8.3.1 - diff --git a/SOURCES/0141-p2v-Remove-trailing-n-from-fixed-disks-device-box.patch b/SOURCES/0141-p2v-Remove-trailing-n-from-fixed-disks-device-box.patch new file mode 100644 index 0000000..a858fd8 --- /dev/null +++ b/SOURCES/0141-p2v-Remove-trailing-n-from-fixed-disks-device-box.patch @@ -0,0 +1,28 @@ +From ec9c4fa9e396b110bca94845d2d752081b6c5e4c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 28 Jun 2016 13:38:34 +0100 +Subject: [PATCH] p2v: Remove trailing \n from fixed disks device box. + +Fixes commit 6aba5a49448d8ed9776164005080620d37bb97e0. + +(cherry picked from commit 13307325e8a4bf12016897224d069309deb34135) +--- + p2v/gui.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/p2v/gui.c b/p2v/gui.c +index 5ffe3d8..9e9043a 100644 +--- a/p2v/gui.c ++++ b/p2v/gui.c +@@ -884,7 +884,7 @@ populate_disks (GtkTreeView *disks_list) + "" + "%s %s\n" + "%s%s" +- "\n", ++ "", + all_disks[i], + size_gb ? size_gb : "", model ? model : "", + serial ? "s/n " : "", serial ? serial : "") == -1) +-- +1.8.3.1 + diff --git a/SOURCES/0141-v2v-tests-add-port-1-to-test-v2v-i-ova.xml-reference.patch b/SOURCES/0141-v2v-tests-add-port-1-to-test-v2v-i-ova.xml-reference.patch deleted file mode 100644 index 4925650..0000000 --- a/SOURCES/0141-v2v-tests-add-port-1-to-test-v2v-i-ova.xml-reference.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0d350c9a950043b95860d95c3aecab41b515feea Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 15 Apr 2015 14:28:05 +0200 -Subject: [PATCH] v2v: tests: add port='-1' to test-v2v-i-ova.xml reference - -Followup of commit 1db249a0cc21c65e0d3192567b6016745cea7e58, as it -outputs a new port attribute. - -(cherry picked from commit 11450a2d36fd05bd0dc9baff97c2afd08b4c9b07) ---- - v2v/test-v2v-i-ova.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/test-v2v-i-ova.xml b/v2v/test-v2v-i-ova.xml -index 2d611f9..f3ecdc6 100644 ---- a/v2v/test-v2v-i-ova.xml -+++ b/v2v/test-v2v-i-ova.xml -@@ -33,7 +33,7 @@ - - -