From: "Daniel P. Berrange" <berrange(a)redhat.com>
Use the freedesktop inhibition DBus service to prevent host
shutdown or session logout while any VMs are running.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/rpc/virnetserver.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index b108399..aaf98a9 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -27,6 +27,10 @@
#include <string.h>
#include <fcntl.h>
+#ifdef HAVE_DBUS
+# include <dbus/dbus.h>
+#endif
+
#include "virnetserver.h"
#include "logging.h"
#include "memory.h"
@@ -37,6 +41,7 @@
#include "virfile.h"
#include "event.h"
#include "virnetservermdns.h"
+#include "virdbus.h"
#ifndef SA_SIGINFO
# define SA_SIGINFO 0
@@ -102,6 +107,8 @@ struct _virNetServer {
unsigned int autoShutdownTimeout;
size_t autoShutdownInhibitions;
+ bool autoShutdownCallingInhibit;
+ int autoShutdownInhibitFd;
virNetServerClientPrivNew clientPrivNew;
virNetServerClientPrivPreExecRestart clientPrivPreExecRestart;
@@ -391,6 +398,7 @@ virNetServerPtr virNetServerNew(size_t min_workers,
srv->clientPrivFree = clientPrivFree;
srv->clientPrivOpaque = clientPrivOpaque;
srv->privileged = geteuid() == 0 ? true : false;
+ srv->autoShutdownInhibitFd = -1;
if (mdnsGroupName &&
!(srv->mdnsGroupName = strdup(mdnsGroupName))) {
@@ -716,10 +724,104 @@ void virNetServerAutoShutdown(virNetServerPtr srv,
}
+#ifdef HAVE_DBUS
+static void virNetServerGotInhibitReply(DBusPendingCall *pending,
+ void *opaque)
+{
+ virNetServerPtr srv = opaque;
+ DBusMessage *reply;
+ int fd;
+
+ virNetServerLock(srv);
+ srv->autoShutdownCallingInhibit = false;
+
+ VIR_DEBUG("srv=%p", srv);
+
+ reply = dbus_pending_call_steal_reply(pending);
+ if (reply == NULL)
+ goto cleanup;
+
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_UNIX_FD, &fd,
+ DBUS_TYPE_INVALID)) {
+ if (srv->autoShutdownInhibitions) {
+ srv->autoShutdownInhibitFd = fd;
+ } else {
+ /* We stopped the last VM since we made the inhibit call */
+ VIR_FORCE_CLOSE(fd);
+ }
+ }
+ dbus_message_unref(reply);
+
+cleanup:
+ virNetServerUnlock(srv);
+}
+
+
+/* As per:
http://www.freedesktop.org/wiki/Software/systemd/inhibit */
+static void virNetServerCallInhibit(virNetServerPtr srv,
+ const char *what,
+ const char *who,
+ const char *why,
+ const char *mode)
+{
+ DBusMessage *message;
+ DBusPendingCall *pendingReply;
+ DBusConnection *systemBus;
+
+ VIR_DEBUG("srv=%p what=%s who=%s why=%s mode=%s",
+ srv, NULLSTR(what), NULLSTR(who), NULLSTR(why), NULLSTR(mode));
+
+ if (!(systemBus = virDBusGetSystemBus()))
+ return;
+
+ /* Only one outstanding call at a time */
+ if (srv->autoShutdownCallingInhibit)
+ return;
+
+ message = dbus_message_new_method_call("org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "Inhibit");
+ if (message == NULL)
+ return;
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &what,
+ DBUS_TYPE_STRING, &who,
+ DBUS_TYPE_STRING, &why,
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ pendingReply = NULL;
+ if (dbus_connection_send_with_reply(systemBus, message,
+ &pendingReply,
+ 25*1000)) {
+ dbus_pending_call_set_notify(pendingReply,
+ virNetServerGotInhibitReply,
+ srv, NULL);
+ srv->autoShutdownCallingInhibit = true;
+ }
+ dbus_message_unref(message);
+}
+#endif
+
void virNetServerAddShutdownInhibition(virNetServerPtr srv)
{
virNetServerLock(srv);
srv->autoShutdownInhibitions++;
+
+ VIR_DEBUG("srv=%p inhibitions=%zu", srv, srv->autoShutdownInhibitions);
+
+#ifdef HAVE_DBUS
+ if (srv->autoShutdownInhibitions == 1)
+ virNetServerCallInhibit(srv,
+ "shutdown",
+ _("Libvirt"),
+ _("Virtual machines need to be saved"),
+ "delay");
+#endif
+
virNetServerUnlock(srv);
}
@@ -728,6 +830,12 @@ void virNetServerRemoveShutdownInhibition(virNetServerPtr srv)
{
virNetServerLock(srv);
srv->autoShutdownInhibitions--;
+
+ VIR_DEBUG("srv=%p inhibitions=%zu", srv, srv->autoShutdownInhibitions);
+
+ if (srv->autoShutdownInhibitions == 0)
+ VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd);
+
virNetServerUnlock(srv);
}
@@ -1065,6 +1173,8 @@ void virNetServerDispose(void *obj)
virNetServerPtr srv = obj;
int i;
+ VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd);
+
for (i = 0 ; i < srv->nservices ; i++)
virNetServerServiceToggle(srv->services[i], false);
--
1.7.12.1