void systemd_logind_release_fd(int _major, int _minor) { struct systemd_logind_info *info = &logind_info; InputInfoPtr pInfo; DBusError error; DBusMessage *msg = NULL; DBusMessage *reply = NULL; dbus_int32_t major = _major; dbus_int32_t minor = _minor; int matches = 0; if (!info->session || major == 0) return; /* Only release the fd if there is only 1 InputInfo left for this major * and minor, otherwise other InputInfo's are still referencing the fd. */ pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs, major, minor); while (pInfo) { matches++; pInfo = systemd_logind_find_info_ptr_by_devnum(pInfo->next, major, minor); } if (matches > 1) { LogMessage(X_INFO, "systemd-logind: not releasing fd for %u:%u, still in use\n", major, minor); return; } LogMessage(X_INFO, "systemd-logind: releasing fd for %u:%u\n", major, minor); 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); }
static void systemd_logind_set_input_fd_for_all_devs(int major, int minor, int fd, Bool enable) { InputInfoPtr pInfo; pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs, major, minor); while (pInfo) { pInfo->fd = fd; pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd); if (enable) xf86EnableInputDeviceForVTSwitch(pInfo); pInfo = systemd_logind_find_info_ptr_by_devnum(pInfo->next, major, minor); } }
int systemd_logind_take_fd(int _major, int _minor, const char *path, Bool *paused_ret) { struct systemd_logind_info *info = &logind_info; InputInfoPtr pInfo; 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; /* Check if we already have an InputInfo entry with this major, minor * (shared device-nodes happen ie with Wacom tablets). */ pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs, major, minor); if (pInfo) { LogMessage(X_INFO, "systemd-logind: returning pre-existing fd for %s %u:%u\n", path, major, minor); *paused_ret = FALSE; return pInfo->fd; } 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; }
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; dbus_error_init(&error); if (dbus_message_is_signal(message, "org.freedesktop.DBus", "NameOwnerChanged")) { char *name, *old_owner, *new_owner; dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID); if (dbus_error_is_set(&error)) { LogMessage(X_ERROR, "systemd-logind: NameOwnerChanged: %s\n", error.message); dbus_error_free(&error); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (name && strcmp(name, "org.freedesktop.login1") == 0) FatalError("systemd-logind disappeared (stopped/restarted?)\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (strcmp(dbus_message_get_path(message), info->session) != 0) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 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(xf86InputDevs, 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); systemd_logind_set_input_fd_for_all_devs(major, minor, -1, FALSE); } 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; else systemd_logind_set_input_fd_for_all_devs(major, minor, fd, info->vt_active); /* Always call vtenter(), in case there are only legacy video devs */ systemd_logind_vtenter(); } return DBUS_HANDLER_RESULT_HANDLED; }