From 313309261de61745425eed00795020107c74fab2 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 31 Oct 2012 19:03:56 +0000 Subject: [PATCH] Inhibit desktop shutdown while any virtual machines are running Use the freedesktop inhibition DBus service to prevent host shutdown or session logout while any VMs are running. Signed-off-by: Daniel P. Berrange --- src/rpc/virnetserver.c | 108 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index b10839933b..ae1dfa2027 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -37,6 +37,7 @@ #include "virfile.h" #include "event.h" #include "virnetservermdns.h" +#include "virdbus.h" #ifndef SA_SIGINFO # define SA_SIGINFO 0 @@ -102,6 +103,8 @@ struct _virNetServer { unsigned int autoShutdownTimeout; size_t autoShutdownInhibitions; + bool autoShutdownCallingInhibit; + int autoShutdownInhibitFd; virNetServerClientPrivNew clientPrivNew; virNetServerClientPrivPreExecRestart clientPrivPreExecRestart; @@ -390,7 +393,8 @@ virNetServerPtr virNetServerNew(size_t min_workers, srv->clientPrivPreExecRestart = clientPrivPreExecRestart; srv->clientPrivFree = clientPrivFree; srv->clientPrivOpaque = clientPrivOpaque; - srv->privileged = geteuid() == 0 ? true : false; + srv->privileged = geteuid() == 0; + srv->autoShutdownInhibitFd = -1; if (mdnsGroupName && !(srv->mdnsGroupName = strdup(mdnsGroupName))) { @@ -716,10 +720,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 +826,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 +1169,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); -- 2.47.2