From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list