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 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs