aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xfree86/os-support/linux/systemd-logind.c
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2014-03-09 21:32:55 +0100
committermarha <marha@users.sourceforge.net>2014-03-09 21:32:55 +0100
commit3dd4b6420f686b0147d5b8136268cc63196e253b (patch)
tree2c81c3f7503dbcfb5b64fd95b40bb1c2204598ef /xorg-server/hw/xfree86/os-support/linux/systemd-logind.c
parent321c01267ae1c446f1bd22b642567fcafa016c02 (diff)
downloadvcxsrv-3dd4b6420f686b0147d5b8136268cc63196e253b.tar.gz
vcxsrv-3dd4b6420f686b0147d5b8136268cc63196e253b.tar.bz2
vcxsrv-3dd4b6420f686b0147d5b8136268cc63196e253b.zip
fontconfig mesa xserver git update 9 Mar 2014
xserver commit 1c61d38528a573caadee2468ee59ea558c822e09 fontconfig commit f8ccf379eb1092592ae0b65deb563c5491f69de9 mesa commit 897f40f25d21af678b1b67c1a68c4a6722d19983
Diffstat (limited to 'xorg-server/hw/xfree86/os-support/linux/systemd-logind.c')
-rw-r--r--xorg-server/hw/xfree86/os-support/linux/systemd-logind.c532
1 files changed, 532 insertions, 0 deletions
diff --git a/xorg-server/hw/xfree86/os-support/linux/systemd-logind.c b/xorg-server/hw/xfree86/os-support/linux/systemd-logind.c
new file mode 100644
index 000000000..abb8e44d9
--- /dev/null
+++ b/xorg-server/hw/xfree86/os-support/linux/systemd-logind.c
@@ -0,0 +1,532 @@
+/*
+ * 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@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);
+
+ /* Do delayed input probing, this must be done after the above enabling */
+ xf86InputEnableVTProbe();
+}
+
+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; /* Don't forcibly take over over the session */
+ 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);
+}