mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
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:
parent
79b8a56995
commit
313309261d
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user