We do this by sending an Inhibit() message to logind and receiving a
file descriptor back, which we hold open until the conversion
completes (or fails). This is described here:
https://www.freedesktop.org/wiki/Software/systemd/inhibit/
This adds an additional optional dependency on DBus since we use DBus
to call the Inhibit() method.
Reported-by: Chris Cowley.
---
docs/guestfs-building.pod | 8 +++
m4/guestfs_misc_libraries.m4 | 9 +++
p2v/Makefile.am | 5 +-
p2v/conversion.c | 10 +++
p2v/inhibit.c | 153 +++++++++++++++++++++++++++++++++++++++++++
p2v/p2v.h | 3 +
6 files changed, 187 insertions(+), 1 deletion(-)
create mode 100644 p2v/inhibit.c
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index 5c1806d..1e4a574 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -282,6 +282,14 @@ Either Gtk 2 or Gtk 3 can be used. If you want to select a specific
version of Gtk, use S<C<./configure --with-gtk=2>> or
S<C<./configure --with-gtk=3>>.
+=item DBus
+
+Optional.
+
+If the DBus C API is available, virt-p2v can send a DBus message to
+logind to inhibit power saving (sleep, suspend, etc) during P2V
+conversions.
+
=item zip
=item unzip
diff --git a/m4/guestfs_misc_libraries.m4 b/m4/guestfs_misc_libraries.m4
index fee265b..82864f9 100644
--- a/m4/guestfs_misc_libraries.m4
+++ b/m4/guestfs_misc_libraries.m4
@@ -103,6 +103,15 @@ elif test "x$with_gtk" = "xcheck"; then
])
fi
+dnl DBus is an optional dependency of virt-p2v.
+PKG_CHECK_MODULES([DBUS], [dbus-1], [
+ AC_SUBST([DBUS_CFLAGS])
+ AC_SUBST([DBUS_LIBS])
+ AC_DEFINE([HAVE_DBUS],[1],[DBus found at compile time.])
+],[
+ AC_MSG_WARN([DBus not found, virt-p2v will not be able to inhibit power saving during
P2V conversions])
+])
+
dnl Can we build virt-p2v?
AC_MSG_CHECKING([if we can build virt-p2v])
if test "x$GTK_LIBS" != "x"; then
diff --git a/p2v/Makefile.am b/p2v/Makefile.am
index 1f6e601..216ab30 100644
--- a/p2v/Makefile.am
+++ b/p2v/Makefile.am
@@ -77,6 +77,7 @@ virt_p2v_SOURCES = \
config.c \
conversion.c \
gui.c \
+ inhibit.c \
kernel.c \
kernel-cmdline.c \
main.c \
@@ -97,13 +98,15 @@ virt_p2v_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(PCRE_CFLAGS) \
$(LIBXML2_CFLAGS) \
- $(GTK_CFLAGS)
+ $(GTK_CFLAGS) \
+ $(DBUS_CFLAGS)
virt_p2v_LDADD = \
$(top_builddir)/src/libutils.la \
$(PCRE_LIBS) \
$(LIBXML2_LIBS) \
$(GTK_LIBS) \
+ $(DBUS_LIBS) \
../gnulib/lib/libgnu.la
# Scripts to build the disk image, USB key, or kickstart.
diff --git a/p2v/conversion.c b/p2v/conversion.c
index 3be9a45..a5b6769 100644
--- a/p2v/conversion.c
+++ b/p2v/conversion.c
@@ -208,6 +208,7 @@ start_conversion (struct config *config,
char libvirt_xml_file[] = "/tmp/p2v.XXXXXX/physical.xml";
char wrapper_script[] = "/tmp/p2v.XXXXXX/virt-v2v-wrapper.sh";
char dmesg_file[] = "/tmp/p2v.XXXXXX/dmesg";
+ int inhibit_fd = -1;
#if DEBUG_STDERR
print_config (config, stderr);
@@ -218,6 +219,12 @@ start_conversion (struct config *config,
set_running (1);
set_cancel_requested (0);
+ inhibit_fd = inhibit_sleep ();
+#ifdef DEBUG_STDERR
+ if (inhibit_fd == -1)
+ fprintf (stderr, "warning: virt-p2v cannot inhibit power saving during
conversion.\n");
+#endif
+
data_conns = malloc (sizeof (struct data_conn) * nr_disks);
if (data_conns == NULL)
error (EXIT_FAILURE, errno, "malloc");
@@ -426,6 +433,9 @@ start_conversion (struct config *config,
}
cleanup_data_conns (data_conns, nr_disks);
+ if (inhibit_fd >= 0)
+ close (inhibit_fd);
+
set_running (0);
return ret;
diff --git a/p2v/inhibit.c b/p2v/inhibit.c
new file mode 100644
index 0000000..b5acfd4
--- /dev/null
+++ b/p2v/inhibit.c
@@ -0,0 +1,153 @@
+/* virt-p2v
+ * 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.
+ */
+
+/**
+ * This file is used to inhibit power saving, sleep, suspend etc during
+ * the conversion.
+ *
+ * The method it uses is to send a dbus message to logind, as
+ * described here:
+ *
+ *
https://www.freedesktop.org/wiki/Software/systemd/inhibit/
+ *
+ * If virt-p2v is compiled with DBus support then this does nothing.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+#endif
+
+#include "p2v.h"
+
+/**
+ * Inhibit all forms of power saving. A file descriptor is returned,
+ * and when the file descriptor is closed the inhibit is stopped.
+ *
+ * If the function returns C<-1> then C<Inhibit> operation could not
+ * be performed (eg. if we are compiled with DBus support, or there is
+ * some error contacting logind). This is not usually fatal from the
+ * point of view of the caller, conversion can continue.
+ */
+int
+inhibit_sleep (void)
+{
+#ifdef HAVE_DBUS
+ DBusError err;
+ DBusConnection *conn = NULL;
+ DBusMessage *msg = NULL;
+ DBusMessageIter args;
+ DBusPendingCall *pending = NULL;
+ const char *what = "shutdown:sleep:idle";
+ const char *who = "virt-p2v";
+ const char *why = "virt-p2v conversion is running";
+ const char *mode = "block";
+ int fd = -1;
+
+ dbus_error_init (&err);
+
+ conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set (&err)) {
+ fprintf (stderr, "dbus: cannot connect to system bus: %s\n", err.message);
+ goto out;
+ }
+ if (conn == NULL)
+ goto out;
+
+ msg = dbus_message_new_method_call ("org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "Inhibit");
+ if (msg == NULL) {
+ fprintf (stderr, "dbus: cannot create message\n");
+ goto out;
+ }
+
+ dbus_message_iter_init_append (msg, &args);
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &what) ||
+ !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &who) ||
+ !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &why) ||
+ !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &mode)) {
+ fprintf (stderr, "dbus: cannot add message arguments\n");
+ goto out;
+ }
+
+ if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) {
+ fprintf (stderr, "dbus: cannot send Inhibit message to logind\n");
+ goto out;
+ }
+ if (pending == NULL)
+ goto out;
+ dbus_connection_flush (conn);
+ dbus_message_unref (msg);
+ msg = NULL;
+
+ dbus_pending_call_block (pending);
+ msg = dbus_pending_call_steal_reply (pending);
+ if (msg == NULL) {
+ fprintf (stderr, "dbus: could not read message reply\n");
+ goto out;
+ }
+
+ dbus_pending_call_unref (pending);
+ pending = NULL;
+
+ if (!dbus_message_iter_init (msg, &args)) {
+ fprintf (stderr, "dbus: message reply has no return value\n");
+ goto out;
+ }
+
+ if (dbus_message_iter_get_arg_type (&args) != DBUS_TYPE_UNIX_FD) {
+ fprintf (stderr, "dbus: message reply is not a file descriptor\n");
+ goto out;
+ }
+
+ dbus_message_iter_get_basic (&args, &fd);
+
+#ifdef DEBUG_STDERR
+ fprintf (stderr, "dbus: Inhibit() call returned file descriptor %d\n", fd);
+#endif
+
+out:
+ if (pending != NULL)
+ dbus_pending_call_unref (pending);
+ if (msg != NULL)
+ dbus_message_unref (msg);
+
+ /* This is the system bus connection, so unref-ing it does not
+ * actually close it.
+ */
+ if (conn != NULL)
+ dbus_connection_unref (conn);
+
+ dbus_error_free (&err);
+
+ return fd;
+
+#else /* !HAVE_DBUS */
+#ifdef DEBUG_STDERR
+ fprintf (stderr, "warning: virt-p2v compiled without DBus support.\n");
+#endif
+ return -1;
+#endif
+}
diff --git a/p2v/p2v.h b/p2v/p2v.h
index 1282a17..86e2c50 100644
--- a/p2v/p2v.h
+++ b/p2v/p2v.h
@@ -120,6 +120,9 @@ extern const char *get_conversion_error (void);
extern void cancel_conversion (void);
extern int conversion_is_running (void);
+/* inhibit.c */
+extern int inhibit_sleep (void);
+
/* ssh.c */
extern int test_connection (struct config *);
extern mexp_h *open_data_connection (struct config *, int *local_port, int
*remote_port);
--
2.9.3