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 "virfile.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "virnetservermdns.h"
|
#include "virnetservermdns.h"
|
||||||
|
#include "virdbus.h"
|
||||||
|
|
||||||
#ifndef SA_SIGINFO
|
#ifndef SA_SIGINFO
|
||||||
# define SA_SIGINFO 0
|
# define SA_SIGINFO 0
|
||||||
@ -102,6 +103,8 @@ struct _virNetServer {
|
|||||||
|
|
||||||
unsigned int autoShutdownTimeout;
|
unsigned int autoShutdownTimeout;
|
||||||
size_t autoShutdownInhibitions;
|
size_t autoShutdownInhibitions;
|
||||||
|
bool autoShutdownCallingInhibit;
|
||||||
|
int autoShutdownInhibitFd;
|
||||||
|
|
||||||
virNetServerClientPrivNew clientPrivNew;
|
virNetServerClientPrivNew clientPrivNew;
|
||||||
virNetServerClientPrivPreExecRestart clientPrivPreExecRestart;
|
virNetServerClientPrivPreExecRestart clientPrivPreExecRestart;
|
||||||
@ -390,7 +393,8 @@ virNetServerPtr virNetServerNew(size_t min_workers,
|
|||||||
srv->clientPrivPreExecRestart = clientPrivPreExecRestart;
|
srv->clientPrivPreExecRestart = clientPrivPreExecRestart;
|
||||||
srv->clientPrivFree = clientPrivFree;
|
srv->clientPrivFree = clientPrivFree;
|
||||||
srv->clientPrivOpaque = clientPrivOpaque;
|
srv->clientPrivOpaque = clientPrivOpaque;
|
||||||
srv->privileged = geteuid() == 0 ? true : false;
|
srv->privileged = geteuid() == 0;
|
||||||
|
srv->autoShutdownInhibitFd = -1;
|
||||||
|
|
||||||
if (mdnsGroupName &&
|
if (mdnsGroupName &&
|
||||||
!(srv->mdnsGroupName = strdup(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)
|
void virNetServerAddShutdownInhibition(virNetServerPtr srv)
|
||||||
{
|
{
|
||||||
virNetServerLock(srv);
|
virNetServerLock(srv);
|
||||||
srv->autoShutdownInhibitions++;
|
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);
|
virNetServerUnlock(srv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,6 +826,12 @@ void virNetServerRemoveShutdownInhibition(virNetServerPtr srv)
|
|||||||
{
|
{
|
||||||
virNetServerLock(srv);
|
virNetServerLock(srv);
|
||||||
srv->autoShutdownInhibitions--;
|
srv->autoShutdownInhibitions--;
|
||||||
|
|
||||||
|
VIR_DEBUG("srv=%p inhibitions=%zu", srv, srv->autoShutdownInhibitions);
|
||||||
|
|
||||||
|
if (srv->autoShutdownInhibitions == 0)
|
||||||
|
VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd);
|
||||||
|
|
||||||
virNetServerUnlock(srv);
|
virNetServerUnlock(srv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1065,6 +1169,8 @@ void virNetServerDispose(void *obj)
|
|||||||
virNetServerPtr srv = obj;
|
virNetServerPtr srv = obj;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd);
|
||||||
|
|
||||||
for (i = 0 ; i < srv->nservices ; i++)
|
for (i = 0 ; i < srv->nservices ; i++)
|
||||||
virNetServerServiceToggle(srv->services[i], false);
|
virNetServerServiceToggle(srv->services[i], false);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user