[PATCH v2 10/14] systemd-logind: Add systemd-logind "core"

Hans de Goede hdegoede at redhat.com
Tue Feb 4 12:49:16 CET 2014


This commits add the bulk of the systemd-logind integration code, but does
not hook it up yet other then calling its init and fini functions, which
don't do that much.

Note the configure bits check for udev since systemd-logind use will only be
supported in combination with udev. Besides that it only checks for dbus
since all communication with systemd-logind is happening over dbus, so
no further libs are needed.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 configure.ac                                 |  21 ++
 hw/xfree86/common/xf86Init.c                 |   3 +
 hw/xfree86/common/xf86platformBus.c          |   2 +-
 hw/xfree86/common/xf86platformBus.h          |   2 +
 hw/xfree86/os-support/linux/Makefile.am      |   6 +
 hw/xfree86/os-support/linux/systemd-logind.c | 529 +++++++++++++++++++++++++++
 include/Makefile.am                          |   1 +
 include/dix-config.h.in                      |   3 +
 include/systemd-logind.h                     |  45 +++
 9 files changed, 611 insertions(+), 1 deletion(-)
 create mode 100644 hw/xfree86/os-support/linux/systemd-logind.c
 create mode 100644 include/systemd-logind.h

diff --git a/configure.ac b/configure.ac
index fe9b783..bc89bfe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -626,6 +626,7 @@ AC_ARG_ENABLE(clientids,      AS_HELP_STRING([--disable-clientids], [Build Xorg
 AC_ARG_ENABLE(pciaccess, AS_HELP_STRING([--enable-pciaccess], [Build Xorg with pciaccess library (default: enabled)]), [PCI=$enableval], [PCI=yes])
 AC_ARG_ENABLE(linux_acpi, AS_HELP_STRING([--disable-linux-acpi], [Disable building ACPI support on Linux (if available).]), [enable_linux_acpi=$enableval], [enable_linux_acpi=yes])
 AC_ARG_ENABLE(linux_apm, AS_HELP_STRING([--disable-linux-apm], [Disable building APM support on Linux (if available).]), [enable_linux_apm=$enableval], [enable_linux_apm=yes])
+AC_ARG_ENABLE(systemd-logind, AC_HELP_STRING([--enable-systemd-logind], [Build systemd-logind support (default: auto)]), [SYSTEMD_LOGIND=$enableval], [SYSTEMD_LOGIND=auto])
 
 dnl DDXes.
 AC_ARG_ENABLE(xorg,    	      AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto])
@@ -901,6 +902,26 @@ if test "x$CONFIG_HAL" = xyes; then
 fi
 AM_CONDITIONAL(CONFIG_HAL, [test "x$CONFIG_HAL" = xyes])
 
+if test "x$SYSTEMD_LOGIND" = xauto; then
+        if test "x$HAVE_DBUS" = xyes -a "x$CONFIG_UDEV" = xyes ; then
+                SYSTEMD_LOGIND=yes
+        else
+                SYSTEMD_LOGIND=no
+        fi
+fi
+if test "x$SYSTEMD_LOGIND" = xyes; then
+        if ! test "x$HAVE_DBUS" = xyes; then
+                AC_MSG_ERROR([systemd-logind requested, but D-Bus is not installed.])
+        fi
+        if ! test "x$CONFIG_UDEV" = xyes ; then
+                AC_MSG_ERROR([systemd-logind is only supported in combination with udev configuration.])
+        fi
+
+        AC_DEFINE(SYSTEMD_LOGIND, 1, [Enable systemd-logind integration])
+        NEED_DBUS="yes"
+fi
+AM_CONDITIONAL(SYSTEMD_LOGIND, [test "x$SYSTEMD_LOGIND" = xyes])
+
 if test "x$NEED_DBUS" = xyes; then
         AC_DEFINE(NEED_DBUS, 1, [Enable D-Bus core])
 fi
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index ff4d38f..4579ff5 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -54,6 +54,7 @@
 #include "site.h"
 #include "mi.h"
 #include "dbus-core.h"
+#include "systemd-logind.h"
 
 #include "compiler.h"
 
@@ -458,6 +459,7 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
             DoShowOptions();
 
         dbus_core_init();
+        systemd_logind_init();
 
         /* Do a general bus probe.  This will be a PCI probe for x86 platforms */
         xf86BusProbe();
@@ -1062,6 +1064,7 @@ ddxGiveUp(enum ExitCode error)
     if (xorgHWOpenConsole)
         xf86CloseConsole();
 
+    systemd_logind_fini();
     dbus_core_fini();
 
     xf86CloseLog(error);
diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c
index e1d7bd0..4447e19 100644
--- a/hw/xfree86/common/xf86platformBus.c
+++ b/hw/xfree86/common/xf86platformBus.c
@@ -52,7 +52,7 @@ int platformSlotClaimed;
 
 int xf86_num_platform_devices;
 
-static struct xf86_platform_device *xf86_platform_devices;
+struct xf86_platform_device *xf86_platform_devices;
 
 int
 xf86_add_platform_device(struct OdevAttributes *attribs, Bool unowned)
diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h
index 3e27d34..78b5a5b 100644
--- a/hw/xfree86/common/xf86platformBus.h
+++ b/hw/xfree86/common/xf86platformBus.h
@@ -36,12 +36,14 @@ struct xf86_platform_device {
 /* xf86_platform_device flags */
 #define XF86_PDEV_UNOWNED       0x01
 #define XF86_PDEV_SERVER_FD     0x02
+#define XF86_PDEV_PAUSED        0x04
 
 #ifdef XSERVER_PLATFORM_BUS
 int xf86platformProbe(void);
 int xf86platformProbeDev(DriverPtr drvp);
 
 extern int xf86_num_platform_devices;
+extern struct xf86_platform_device *xf86_platform_devices;
 
 extern char *
 xf86_get_platform_attrib(int index, int attrib_id);
diff --git a/hw/xfree86/os-support/linux/Makefile.am b/hw/xfree86/os-support/linux/Makefile.am
index 83e7e00..1686dc2 100644
--- a/hw/xfree86/os-support/linux/Makefile.am
+++ b/hw/xfree86/os-support/linux/Makefile.am
@@ -21,6 +21,11 @@ APM_SRCS = lnx_apm.c
 XORG_CFLAGS += -DHAVE_APM
 endif
 
+if SYSTEMD_LOGIND
+LOGIND_SRCS = systemd-logind.c
+XORG_CFLAGS += $(DBUS_CFLAGS)
+endif
+
 liblinux_la_SOURCES = lnx_init.c lnx_video.c \
                      lnx_agp.c lnx_kmod.c lnx_bell.c lnx_platform.c \
                      $(srcdir)/../shared/bios_mmap.c \
@@ -30,6 +35,7 @@ liblinux_la_SOURCES = lnx_init.c lnx_video.c \
 		     $(srcdir)/../shared/sigio.c \
                      $(ACPI_SRCS) \
                      $(APM_SRCS) \
+                     $(LOGIND_SRCS) \
                      $(PLATFORM_PCI_SUPPORT)
 
 AM_CFLAGS = -DUSESTDRES -DHAVE_SYSV_IPC $(DIX_CFLAGS) $(XORG_CFLAGS) $(PLATFORM_DEFINES)
diff --git a/hw/xfree86/os-support/linux/systemd-logind.c b/hw/xfree86/os-support/linux/systemd-logind.c
new file mode 100644
index 0000000..176defd
--- /dev/null
+++ b/hw/xfree86/os-support/linux/systemd-logind.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright © 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Hans de Goede <hdegoede at redhat.com>
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <dbus/dbus.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "os.h"
+#include "dbus-core.h"
+#include "xf86.h"
+#include "xf86platformBus.h"
+#include "xf86Xinput.h"
+
+#include "systemd-logind.h"
+
+#define DBUS_TIMEOUT 500 /* Wait max 0.5 seconds */
+
+struct systemd_logind_info {
+    DBusConnection *conn;
+    char *session;
+    Bool active;
+    Bool vt_active;
+};
+
+static struct systemd_logind_info logind_info;
+
+int
+systemd_logind_take_fd(int _major, int _minor, const char *path,
+                       Bool *paused_ret)
+{
+    struct systemd_logind_info *info = &logind_info;
+    DBusError error;
+    DBusMessage *msg = NULL;
+    DBusMessage *reply = NULL;
+    dbus_int32_t major = _major;
+    dbus_int32_t minor = _minor;
+    dbus_bool_t paused;
+    int fd = -1;
+
+    if (!info->session || major == 0)
+        return -1;
+
+    /* logind does not support mouse devs (with evdev we don't need them) */
+    if (strstr(path, "mouse"))
+        return -1;
+
+    dbus_error_init(&error);
+
+    msg = dbus_message_new_method_call("org.freedesktop.login1", info->session,
+            "org.freedesktop.login1.Session", "TakeDevice");
+    if (!msg) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major,
+                                       DBUS_TYPE_UINT32, &minor,
+                                       DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
+                                                      DBUS_TIMEOUT, &error);
+    if (!reply) {
+        LogMessage(X_ERROR, "systemd-logind: failed to take device %s: %s\n",
+                   path, error.message);
+        goto cleanup;
+    }
+
+    if (!dbus_message_get_args(reply, &error,
+                               DBUS_TYPE_UNIX_FD, &fd,
+                               DBUS_TYPE_BOOLEAN, &paused,
+                               DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: TakeDevice %s: %s\n",
+                   path, error.message);
+        goto cleanup;
+    }
+
+    *paused_ret = paused;
+
+    LogMessage(X_INFO, "systemd-logind: got fd for %s %u:%u fd %d paused %d\n",
+               path, major, minor, fd, paused);
+
+cleanup:
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    dbus_error_free(&error);
+
+    return fd;
+}
+
+void
+systemd_logind_release_fd(int _major, int _minor)
+{
+    struct systemd_logind_info *info = &logind_info;
+    DBusError error;
+    DBusMessage *msg = NULL;
+    DBusMessage *reply = NULL;
+    dbus_int32_t major = _major;
+    dbus_int32_t minor = _minor;
+
+    if (!info->session || major == 0)
+        return;
+
+    dbus_error_init(&error);
+
+    msg = dbus_message_new_method_call("org.freedesktop.login1", info->session,
+            "org.freedesktop.login1.Session", "ReleaseDevice");
+    if (!msg) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major,
+                                       DBUS_TYPE_UINT32, &minor,
+                                       DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
+                                                      DBUS_TIMEOUT, &error);
+    if (!reply)
+        LogMessage(X_ERROR, "systemd-logind: failed to release device: %s\n",
+                   error.message);
+
+cleanup:
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    dbus_error_free(&error);
+}
+
+int
+systemd_logind_controls_session(void)
+{
+    return logind_info.session ? 1 : 0;
+}
+
+void
+systemd_logind_vtenter(void)
+{
+    struct systemd_logind_info *info = &logind_info;
+    InputInfoPtr pInfo;
+    int i;
+
+    if (!info->session)
+        return; /* Not using systemd-logind */
+
+    if (!info->active)
+        return; /* Session not active */
+
+    if (info->vt_active)
+        return; /* Already did vtenter */
+
+    for (i = 0; i < xf86_num_platform_devices; i++) {
+        if (xf86_platform_devices[i].flags & XF86_PDEV_PAUSED)
+            break;
+    }
+    if (i != xf86_num_platform_devices)
+        return; /* Some drm nodes are still paused wait for resume */
+
+    xf86VTEnter();
+    info->vt_active = TRUE;
+
+    /* Activate any input devices which were resumed before the drm nodes */
+    for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next)
+        if ((pInfo->flags & XI86_SERVER_FD) && pInfo->fd != -1)
+            xf86EnableInputDeviceForVTSwitch(pInfo);
+}
+
+static InputInfoPtr
+systemd_logind_find_info_ptr_by_devnum(int major, int minor)
+{
+    InputInfoPtr pInfo;
+
+    for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next)
+        if (pInfo->major == major && pInfo->minor == minor &&
+                (pInfo->flags & XI86_SERVER_FD))
+            return pInfo;
+
+    return NULL;
+}
+
+static void
+systemd_logind_ack_pause(struct systemd_logind_info *info,
+                         dbus_int32_t minor, dbus_int32_t major)
+{
+    DBusError error;
+    DBusMessage *msg = NULL;
+    DBusMessage *reply = NULL;
+
+    dbus_error_init(&error);
+
+    msg = dbus_message_new_method_call("org.freedesktop.login1", info->session,
+            "org.freedesktop.login1.Session", "PauseDeviceComplete");
+    if (!msg) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major,
+                                       DBUS_TYPE_UINT32, &minor,
+                                       DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
+                                                      DBUS_TIMEOUT, &error);
+    if (!reply)
+        LogMessage(X_ERROR, "systemd-logind: failed to ack pause: %s\n",
+                   error.message);
+
+cleanup:
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    dbus_error_free(&error);
+}
+
+static DBusHandlerResult
+message_filter(DBusConnection * connection, DBusMessage * message, void *data)
+{
+    struct systemd_logind_info *info = data;
+    struct xf86_platform_device *pdev = NULL;
+    InputInfoPtr pInfo = NULL;
+    int ack = 0, pause = 0, fd = -1;
+    DBusError error;
+    dbus_int32_t major, minor;
+    char *pause_str;
+
+    if (strcmp(dbus_message_get_path(message), info->session) != 0)
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    dbus_error_init(&error);
+
+    if (dbus_message_is_signal(message, "org.freedesktop.login1.Session",
+                               "PauseDevice")) {
+        if (!dbus_message_get_args(message, &error,
+                               DBUS_TYPE_UINT32, &major,
+                               DBUS_TYPE_UINT32, &minor,
+                               DBUS_TYPE_STRING, &pause_str,
+                               DBUS_TYPE_INVALID)) {
+            LogMessage(X_ERROR, "systemd-logind: PauseDevice: %s\n",
+                       error.message);
+            dbus_error_free(&error);
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+
+        if (strcmp(pause_str, "pause") == 0) {
+            pause = 1;
+            ack = 1;
+        }
+        else if (strcmp(pause_str, "force") == 0) {
+            pause = 1;
+        }
+        else if (strcmp(pause_str, "gone") == 0) {
+            /* Device removal is handled through udev */
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+        else {
+            LogMessage(X_WARNING, "systemd-logind: unknown pause type: %s\n",
+                       pause_str);
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+    }
+    else if (dbus_message_is_signal(message, "org.freedesktop.login1.Session",
+                                    "ResumeDevice")) {
+        if (!dbus_message_get_args(message, &error,
+                                   DBUS_TYPE_UINT32, &major,
+                                   DBUS_TYPE_UINT32, &minor,
+                                   DBUS_TYPE_UNIX_FD, &fd,
+                                   DBUS_TYPE_INVALID)) {
+            LogMessage(X_ERROR, "systemd-logind: ResumeDevice: %s\n",
+                       error.message);
+            dbus_error_free(&error);
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+    } else
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    LogMessage(X_INFO, "systemd-logind: got %s for %u:%u\n",
+               pause ? "pause" : "resume", major, minor);
+
+    pdev = xf86_find_platform_device_by_devnum(major, minor);        
+    if (!pdev)
+        pInfo = systemd_logind_find_info_ptr_by_devnum(major, minor);
+    if (!pdev && !pInfo) {
+        LogMessage(X_WARNING, "systemd-logind: could not find dev %u:%u\n",
+                   major, minor);
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    if (pause) {
+        /* Our VT_PROCESS usage guarantees we've already given up the vt */
+        info->active = info->vt_active = FALSE;
+        /* Note the actual vtleave has already been handled by xf86Events.c */
+        if (pdev)
+            pdev->flags |= XF86_PDEV_PAUSED;
+        else {
+            close(pInfo->fd);
+            pInfo->fd = -1;
+            pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", -1);
+        }
+        if (ack)
+            systemd_logind_ack_pause(info, major, minor);
+    }
+    else {
+        /* info->vt_active gets set by systemd_logind_vtenter() */
+        info->active = TRUE;
+
+        if (pdev) {
+            pdev->flags &= ~XF86_PDEV_PAUSED;
+            systemd_logind_vtenter();
+        }
+        else {
+            pInfo->fd = fd;
+            pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd);
+            if (info->vt_active)
+                xf86EnableInputDeviceForVTSwitch(pInfo);
+        }
+    }
+    return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+connect_hook(DBusConnection *connection, void *data)
+{
+    struct systemd_logind_info *info = data;
+    DBusError error;
+    DBusMessage *msg = NULL;
+    DBusMessage *reply = NULL;
+    dbus_int32_t arg;
+    char *session = NULL;
+
+    dbus_error_init(&error);
+
+    msg = dbus_message_new_method_call("org.freedesktop.login1",
+            "/org/freedesktop/login1", "org.freedesktop.login1.Manager",
+            "GetSessionByPID");
+    if (!msg) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    arg = getpid();
+    if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &arg,
+                                  DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    reply = dbus_connection_send_with_reply_and_block(connection, msg,
+                                                      DBUS_TIMEOUT, &error);
+    if (!reply) {
+        LogMessage(X_ERROR, "systemd-logind: failed to get session: %s\n",
+                   error.message);
+        goto cleanup;
+    }
+    dbus_message_unref(msg);
+
+    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &session,
+                               DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: GetSessionByPID: %s\n",
+                   error.message);
+        goto cleanup;
+    }
+    session = XNFstrdup(session);
+
+    dbus_message_unref(reply);
+    reply = NULL;
+
+
+    msg = dbus_message_new_method_call("org.freedesktop.login1",
+            session, "org.freedesktop.login1.Session", "TakeControl");
+    if (!msg) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    arg = FALSE;
+    if (!dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg,
+                                  DBUS_TYPE_INVALID)) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    reply = dbus_connection_send_with_reply_and_block(connection, msg,
+                                                      DBUS_TIMEOUT, &error);
+    if (!reply) {
+        LogMessage(X_ERROR, "systemd-logind: TakeControl failed: %s\n",
+                   error.message);
+        goto cleanup;
+    }
+
+    /*
+     * HdG: This is not useful with systemd <= 208 since the signal only
+     * contains invalidated property names there, rather than property, val
+     * pairs as it should.  Instead we just use the first resume / pause now.
+     */
+#if 0
+    snprintf(match, sizeof(match),
+        "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='%s'",
+        session);
+    dbus_bus_add_match(connection, match, &error);
+    if (dbus_error_is_set(&error)) {
+        LogMessage(X_ERROR, "systemd-logind: could not add match: %s\n",
+                   error.message);
+        goto cleanup;
+    }
+#endif
+
+    if (!dbus_connection_add_filter(connection, message_filter, info, NULL)) {
+        LogMessage(X_ERROR, "systemd-logind: could not add filter: %s\n",
+                   error.message);
+        goto cleanup;
+    }
+
+    LogMessage(X_INFO, "systemd-logind: took control of session %s\n",
+               session);
+    info->conn = connection;
+    info->session = session;
+    info->vt_active = info->active = TRUE; /* The server owns the vt during init */
+    session = NULL;
+
+cleanup:
+    free(session);
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    dbus_error_free(&error);
+}
+
+static void
+systemd_logind_release_control(struct systemd_logind_info *info)
+{
+    DBusError error;
+    DBusMessage *msg = NULL;
+    DBusMessage *reply = NULL;
+
+    dbus_error_init(&error);
+
+    msg = dbus_message_new_method_call("org.freedesktop.login1",
+            info->session, "org.freedesktop.login1.Session", "ReleaseControl");
+    if (!msg) {
+        LogMessage(X_ERROR, "systemd-logind: out of memory\n");
+        goto cleanup;
+    }
+
+    reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
+                                                      DBUS_TIMEOUT, &error);
+    if (!reply) {
+        LogMessage(X_ERROR, "systemd-logind: ReleaseControl failed: %s\n",
+                   error.message);
+        goto cleanup;
+    }
+
+cleanup:
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    dbus_error_free(&error);
+}
+
+static void
+disconnect_hook(void *data)
+{
+    struct systemd_logind_info *info = data;
+
+    free(info->session);
+    info->session = NULL;
+    info->conn = NULL;
+}
+
+static struct dbus_core_hook core_hook = {
+    .connect = connect_hook,
+    .disconnect = disconnect_hook,
+    .data = &logind_info,
+};
+
+int
+systemd_logind_init(void)
+{
+    return dbus_core_add_hook(&core_hook);
+}
+
+void
+systemd_logind_fini(void)
+{
+    if (logind_info.session)
+        systemd_logind_release_control(&logind_info);
+
+    dbus_core_remove_hook(&core_hook);
+}
diff --git a/include/Makefile.am b/include/Makefile.am
index fa6da00..6578038 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -72,4 +72,5 @@ EXTRA_DIST = 	\
 	dix-config-apple-verbatim.h \
 	dixfontstubs.h eventconvert.h eventstr.h inpututils.h \
 	protocol-versions.h \
+	systemd-logind.h \
 	xsha1.h
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 7c77956..3865d5e 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -420,6 +420,9 @@
 /* Support HAL for hotplug */
 #undef CONFIG_HAL
 
+/* Enable systemd-logind integration */
+#undef SYSTEMD_LOGIND 1
+
 /* Have a monotonic clock from clock_gettime() */
 #undef MONOTONIC_CLOCK
 
diff --git a/include/systemd-logind.h b/include/systemd-logind.h
new file mode 100644
index 0000000..7acc4ff
--- /dev/null
+++ b/include/systemd-logind.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Hans de Goede <hdegoede at redhat.com>
+ */
+
+#ifndef SYSTEMD_LOGIND_H
+#define SYSTEMD_LOGIND_H
+
+#ifdef SYSTEMD_LOGIND
+int systemd_logind_init(void);
+void systemd_logind_fini(void);
+int systemd_logind_take_fd(int major, int minor, const char *path, Bool *paus);
+void systemd_logind_release_fd(int major, int minor);
+int systemd_logind_controls_session(void);
+void systemd_logind_vtenter(void);
+#else
+#define systemd_logind_init()
+#define systemd_logind_fini()
+#define systemd_logind_take_fd(major, minor, path) -1
+#define systemd_logind_rekease_fd(dev)
+#define systemd_logind_controls_session() 0
+#define systemd_logind_vtenter()
+#endif
+
+#endif
-- 
1.8.5.3



More information about the xorg-devel mailing list