Beispiel #1
0
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;
}