If the virt-p2v ISO doesn't contain the correct drivers for the
hardware on the physical server, that can cause peculiar conversion
problems. This was hard to diagnose because we could not see the
'dmesg' output from the physical server.
Upload 'dmesg' output from the physical server (more precisely: from
the virt-p2v ISO's kernel running on the physical server) to the
virt-v2v conversion server debugging directory, so that this
information is available for debugging later.
Unfortunately this involves yet another copy of the 'read_whole_file'
function.
---
p2v/Makefile.am | 3 +-
p2v/conversion.c | 32 ++++++++++++++++++-
p2v/p2v.h | 5 ++-
p2v/ssh.c | 21 ++++++++++++-
p2v/virt-p2v.pod | 8 +++++
p2v/whole-file.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
po/POTFILES | 1 +
7 files changed, 160 insertions(+), 4 deletions(-)
create mode 100644 p2v/whole-file.c
diff --git a/p2v/Makefile.am b/p2v/Makefile.am
index 0fd9ef5..2401a07 100644
--- a/p2v/Makefile.am
+++ b/p2v/Makefile.am
@@ -60,7 +60,8 @@ virt_p2v_SOURCES = \
miniexpect.h \
p2v.h \
ssh.c \
- utils.c
+ utils.c \
+ whole-file.c
virt_p2v_CPPFLAGS = \
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
diff --git a/p2v/conversion.c b/p2v/conversion.c
index e2f37cd..f781921 100644
--- a/p2v/conversion.c
+++ b/p2v/conversion.c
@@ -37,6 +37,8 @@
#include <libxml/xmlwriter.h>
+#include "ignore-value.h"
+
#include "miniexpect.h"
#include "p2v.h"
@@ -129,6 +131,10 @@ start_conversion (struct config *config,
time_t now;
struct tm tm;
mexp_h *control_h = NULL;
+ char dmesg_file[] = "/tmp/dmesg.XXXXXX";
+ char dmesg_cmd[64];
+ CLEANUP_FREE char *dmesg = NULL;
+ int fd, r;
#if DEBUG_STDERR
print_config (config, stderr);
@@ -230,11 +236,35 @@ start_conversion (struct config *config,
fprintf (stderr, "%s: libvirt XML:\n%s", guestfs_int_program_name,
libvirt_xml);
#endif
+ /* Get the output from the 'dmesg' command. We will store this
+ * on the remote server.
+ */
+ fd = mkstemp (dmesg_file);
+ if (fd == -1) {
+ perror ("mkstemp");
+ goto skip_dmesg;
+ }
+ close (fd);
+ snprintf (dmesg_cmd, sizeof dmesg_cmd,
+ "dmesg > %s", dmesg_file);
+ r = system (dmesg_cmd);
+ if (r == -1) {
+ perror ("system");
+ goto skip_dmesg;
+ }
+ if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
+ fprintf (stderr, "'dmesg' failed (ignored)\n");
+ goto skip_dmesg;
+ }
+
+ ignore_value (read_whole_file (dmesg_file, &dmesg, NULL));
+ skip_dmesg:
+
/* Open the control connection and start conversion */
if (notify_ui)
notify_ui (NOTIFY_STATUS, _("Setting up the control connection ..."));
- control_h = start_remote_connection (config, remote_dir, libvirt_xml);
+ control_h = start_remote_connection (config, remote_dir, libvirt_xml, dmesg);
if (control_h == NULL) {
const char *err = get_ssh_error ();
diff --git a/p2v/p2v.h b/p2v/p2v.h
index 35b3f3c..f35200e 100644
--- a/p2v/p2v.h
+++ b/p2v/p2v.h
@@ -116,7 +116,7 @@ extern void cancel_conversion (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);
+extern mexp_h *start_remote_connection (struct config *, const char *remote_dir, const
char *libvirt_xml, const char *dmesg);
extern const char *get_ssh_error (void);
/* utils.c */
@@ -124,6 +124,9 @@ 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 *);
+/* whole-file.c */
+extern int read_whole_file (const char *filename, char **data_r, size_t *size_r);
+
/* virt-v2v version and features (read from remote). */
extern int v2v_major;
extern int v2v_minor;
diff --git a/p2v/ssh.c b/p2v/ssh.c
index cd059c5..6dc6854 100644
--- a/p2v/ssh.c
+++ b/p2v/ssh.c
@@ -848,7 +848,8 @@ wait_for_prompt (mexp_h *h)
mexp_h *
start_remote_connection (struct config *config,
- const char *remote_dir, const char *libvirt_xml)
+ const char *remote_dir, const char *libvirt_xml,
+ const char *dmesg)
{
mexp_h *h;
char magic[9];
@@ -904,6 +905,24 @@ start_remote_connection (struct config *config,
if (wait_for_prompt (h) == -1)
goto error;
+ if (dmesg != NULL) {
+ /* Upload the physical host dmesg to the remote directory. */
+ if (mexp_printf (h,
+ "cat > '%s/dmesg' << '__%s__'\n"
+ "%s"
+ "\n"
+ "__%s__\n",
+ remote_dir, magic,
+ dmesg,
+ magic) == -1) {
+ set_ssh_error ("mexp_printf: %m");
+ goto error;
+ }
+
+ if (wait_for_prompt (h) == -1)
+ goto error;
+ }
+
return h;
error:
diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
index be6b015..1d1b41c 100644
--- a/p2v/virt-p2v.pod
+++ b/p2v/virt-p2v.pod
@@ -628,6 +628,14 @@ Into this directory are written various files which include:
=over 4
+=item F<dmesg>
+
+I<before conversion>
+
+The dmesg output from the physical machine. Useful for detecting
+problems such as missing device drivers or firmware on the virt-p2v
+ISO.
+
=item F<name>
I<before conversion>
diff --git a/p2v/whole-file.c b/p2v/whole-file.c
new file mode 100644
index 0000000..a7e09b8
--- /dev/null
+++ b/p2v/whole-file.c
@@ -0,0 +1,94 @@
+/* libguestfs
+ * Copyright (C) 2011-2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <libintl.h>
+
+#include "p2v.h"
+
+/* Read the whole file into a memory buffer and return it. The file
+ * should be a regular, local, trusted file.
+ */
+int
+read_whole_file (const char *filename, char **data_r, size_t *size_r)
+{
+ int fd;
+ char *data;
+ off_t size;
+ off_t n;
+ ssize_t r;
+ struct stat statbuf;
+
+ fd = open (filename, O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ fprintf (stderr, "open: %s: %m\n", filename);
+ return -1;
+ }
+
+ if (fstat (fd, &statbuf) == -1) {
+ fprintf (stderr, "stat: %s: %m\n", filename);
+ close (fd);
+ return -1;
+ }
+
+ size = statbuf.st_size;
+ data = malloc (size + 1);
+ if (data == NULL) {
+ perror ("malloc");
+ return -1;
+ }
+
+ n = 0;
+ while (n < size) {
+ r = read (fd, &data[n], size - n);
+ if (r == -1) {
+ fprintf (stderr, "read: %s: %m\n", filename);
+ free (data);
+ close (fd);
+ return -1;
+ }
+ if (r == 0) {
+ fprintf (stderr, "read: %s: unexpected end of file\n", filename);
+ free (data);
+ close (fd);
+ return -1;
+ }
+ n += r;
+ }
+
+ if (close (fd) == -1) {
+ fprintf (stderr, "close: %s: %m\n", filename);
+ free (data);
+ return -1;
+ }
+
+ /* For convenience of callers, \0-terminate the data. */
+ data[size] = '\0';
+
+ *data_r = data;
+ if (size_r != NULL)
+ *size_r = size;
+
+ return 0;
+}
diff --git a/po/POTFILES b/po/POTFILES
index 09a8425..c6c277c 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -279,6 +279,7 @@ p2v/main.c
p2v/miniexpect.c
p2v/ssh.c
p2v/utils.c
+p2v/whole-file.c
perl/bindtests.pl
perl/lib/Sys/Guestfs.c
perl/lib/Sys/Guestfs.pm
--
2.5.0