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 <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2012-10-31 19:03:56 +00:00
parent 79b8a56995
commit 313309261d

View File

@ -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);