Rewrite console-kit.c using GDBus instead of libdbus. GDBus provides a more convenient way to access DBus objects. All DBus method calls share a fair amount of common code here, so add a helper function dbus_call_method_for_string(). --- src/vdagentd/console-kit.c | 597 ++++++++++++------------------------- 1 file changed, 192 insertions(+), 405 deletions(-) diff --git a/src/vdagentd/console-kit.c b/src/vdagentd/console-kit.c index ef49db5..4c02ebe 100644 --- a/src/vdagentd/console-kit.c +++ b/src/vdagentd/console-kit.c @@ -20,24 +20,21 @@ */ #include "session-info.h" -#include <dbus/dbus.h> -#include <stdbool.h> -#include <unistd.h> #include <stdlib.h> -#include <string.h> #include <syslog.h> #include <glib.h> +#include <gio/gio.h> struct session_info { - DBusConnection *connection; - int fd; + GDBusConnection *dbus; char *seat; char *active_session; int verbose; - gchar *match_seat_signals; - gchar *match_session_signals; gboolean session_is_locked; gboolean session_idle_hint; + guint seat_signals_subs_id; + guint session_signals_subs_id; + ActiveSessionChangeCb session_change_cb; }; #define INTERFACE_CONSOLE_KIT "org.freedesktop.ConsoleKit" @@ -58,169 +55,112 @@ struct session_info { #define SESSION_SIGNAL_IDLE_HINT_CHANGED "IdleHintChanged" static char *console_kit_get_first_seat(struct session_info *info); -static char *console_kit_check_active_session_change(struct session_info *info); +static void si_dbus_signal_listeners_update(struct session_info *info); -static void si_dbus_match_remove(struct session_info *info) +static void si_dbus_signals_unsubscribe(struct session_info *info) { - DBusError error; - if (info->match_seat_signals != NULL) { - dbus_error_init(&error); - dbus_bus_remove_match(info->connection, - info->match_seat_signals, - &error); - if (info->verbose) - syslog(LOG_DEBUG, "(console-kit) seat match removed: %s", - info->match_seat_signals); - g_free(info->match_seat_signals); - info->match_seat_signals = NULL; + if (info->seat_signals_subs_id) { + g_dbus_connection_signal_unsubscribe(info->dbus, + info->seat_signals_subs_id); + info->seat_signals_subs_id = 0; } - - if (info->match_session_signals != NULL) { - dbus_error_init(&error); - dbus_bus_remove_match(info->connection, - info->match_session_signals, - &error); - - if (info->verbose) - syslog(LOG_DEBUG, "(console-kit) session match removed: %s", - info->match_session_signals); - g_free(info->match_session_signals); - info->match_session_signals = NULL; + if (info->session_signals_subs_id) { + g_dbus_connection_signal_unsubscribe(info->dbus, + info->session_signals_subs_id); + info->session_signals_subs_id = 0; } } -static void si_dbus_match_rule_update(struct session_info *info) +static void active_session_changed_cb(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - DBusError error; + struct session_info *info = user_data; - if (info->connection == NULL) - return; + g_clear_pointer(&info->active_session, g_free); - si_dbus_match_remove(info); - - /* Seat signals */ - if (info->seat != NULL) { - info->match_seat_signals = - g_strdup_printf ("type='signal',interface='%s',path='%s'," - "member='ActiveSessionChanged'", - INTERFACE_CONSOLE_KIT_SEAT, - info->seat); - if (info->verbose) - syslog(LOG_DEBUG, "(console-kit) seat match: %s", - info->match_seat_signals); - - dbus_error_init(&error); - dbus_bus_add_match(info->connection, - info->match_seat_signals, - &error); - if (dbus_error_is_set(&error)) { - syslog(LOG_WARNING, "Unable to add dbus rule match: %s", - error.message); - dbus_error_free(&error); - g_free(info->match_seat_signals); - info->match_seat_signals = NULL; - } + /* s = G_VARIANT_TYPE_STRING, o = G_VARIANT_TYPE_OBJECT_PATH */ + if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(s)")) && + !g_variant_is_of_type(parameters, G_VARIANT_TYPE("(o)"))) { + syslog(LOG_ERR, "ActiveSessionChanged message has unexpected type"); + return; } - /* Session signals */ - if (info->active_session != NULL) { - info->match_session_signals = - g_strdup_printf ("type='signal',interface='%s',path='%s'", - INTERFACE_CONSOLE_KIT_SESSION, - info->active_session); - if (info->verbose) - syslog(LOG_DEBUG, "(console-kit) session match: %s", - info->match_session_signals); - - dbus_error_init(&error); - dbus_bus_add_match(info->connection, - info->match_session_signals, - &error); - if (dbus_error_is_set(&error)) { - syslog(LOG_WARNING, "Unable to add dbus rule match: %s", - error.message); - dbus_error_free(&error); - g_free(info->match_session_signals); - info->match_session_signals = NULL; - } - } + g_variant_get(parameters, "(s)", &info->active_session); + if (info->active_session) + si_dbus_signal_listeners_update(info); + else + syslog(LOG_WARNING, "(console-kit) received invalid session. " + "No active-session at the moment"); + + if (info->session_change_cb) + info->session_change_cb(info->active_session); } -static void -si_dbus_read_signals(struct session_info *info) +static void session_signal_cb(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - DBusMessage *message = NULL; - - dbus_connection_read_write(info->connection, 0); - message = dbus_connection_pop_message(info->connection); - while (message != NULL) { - const char *member; - - member = dbus_message_get_member (message); - if (g_strcmp0(member, SEAT_SIGNAL_ACTIVE_SESSION_CHANGED) == 0) { - DBusMessageIter iter; - gint type; - gchar *session; - - free(info->active_session); - info->active_session = NULL; - - dbus_message_iter_init(message, &iter); - type = dbus_message_iter_get_arg_type(&iter); - /* Session should be an object path, but there is a bug in - ConsoleKit where it sends a string rather than an object_path - accept object_path too in case the bug ever gets fixed */ - if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) { - dbus_message_iter_get_basic(&iter, &session); - if (session != NULL && session[0] != '\0') { - info->active_session = g_strdup(session); - si_dbus_match_rule_update(info); - } else { - syslog(LOG_WARNING, "(console-kit) received invalid session. " - "No active-session at the moment"); - } - } else { - syslog(LOG_ERR, - "ActiveSessionChanged message has unexpected type: '%c'", - type); - } - } else if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) { - info->session_is_locked = TRUE; - } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) { - info->session_is_locked = FALSE; - } else if (g_strcmp0(member, SESSION_SIGNAL_IDLE_HINT_CHANGED) == 0) { - DBusMessageIter iter; - gint type; - dbus_bool_t idle_hint; - - dbus_message_iter_init(message, &iter); - type = dbus_message_iter_get_arg_type(&iter); - if (type == DBUS_TYPE_BOOLEAN) { - dbus_message_iter_get_basic(&iter, &idle_hint); - info->session_idle_hint = (idle_hint); - } else { - syslog(LOG_ERR, - "(console-kit) IdleHintChanged has unexpected type: '%c'", - type); - } - } else { - if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) { - syslog(LOG_WARNING, "(console-kit) received non signal message"); - } else if (info->verbose) { - syslog(LOG_DEBUG, "(console-kit) Signal not handled: %s", member); - } - } - - dbus_message_unref(message); - dbus_connection_read_write(info->connection, 0); - message = dbus_connection_pop_message(info->connection); + struct session_info *info = user_data; + + if (!g_strcmp0(signal_name, SESSION_SIGNAL_IDLE_HINT_CHANGED)) { + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(b)"))) + g_variant_get(parameters, "(b)", &info->session_idle_hint); + else + syslog(LOG_ERR, "(console-kit) IdleHintChanged has unexpected type"); + return; } + + if (!g_strcmp0(signal_name, SESSION_SIGNAL_LOCK)) + info->session_is_locked = TRUE; + else if (!g_strcmp0(signal_name, SESSION_SIGNAL_UNLOCK)) + info->session_is_locked = FALSE; +} + +static void si_dbus_signal_listeners_update(struct session_info *info) +{ + if (info->dbus == NULL) + return; + + si_dbus_signals_unsubscribe(info); + + if (info->seat != NULL) + info->seat_signals_subs_id = + g_dbus_connection_signal_subscribe(info->dbus, + INTERFACE_CONSOLE_KIT, + INTERFACE_CONSOLE_KIT_SEAT, + SEAT_SIGNAL_ACTIVE_SESSION_CHANGED, + info->seat, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + active_session_changed_cb, + info, NULL); + + if (info->active_session != NULL) + info->session_signals_subs_id = + g_dbus_connection_signal_subscribe(info->dbus, + INTERFACE_CONSOLE_KIT, + INTERFACE_CONSOLE_KIT_SESSION, + NULL, + info->active_session, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + session_signal_cb, + info, NULL); } struct session_info *session_info_create(int verbose, ActiveSessionChangeCb cb) { struct session_info *info; - DBusError error; + GError *err = NULL; info = calloc(1, sizeof(*info)); if (!info) @@ -229,32 +169,21 @@ struct session_info *session_info_create(int verbose, ActiveSessionChangeCb cb) info->verbose = verbose; info->session_is_locked = FALSE; info->session_idle_hint = FALSE; - - dbus_error_init(&error); - info->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (info->connection == NULL || dbus_error_is_set(&error)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "Unable to connect to system bus: %s", - error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "Unable to connect to system bus"); + info->session_change_cb = cb; + info->dbus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (err) { + syslog(LOG_ERR, "%s: %s", __func__, err->message); + g_error_free(err); free(info); return NULL; } - if (!dbus_connection_get_unix_fd(info->connection, &info->fd)) { - syslog(LOG_ERR, "Unable to get connection fd"); - session_info_destroy(info); - return NULL; - } - if (!console_kit_get_first_seat(info)) { session_info_destroy(info); return NULL; } - si_dbus_match_rule_update(info); + si_dbus_signal_listeners_update(info); return info; } @@ -263,8 +192,8 @@ void session_info_destroy(struct session_info *info) if (!info) return; - si_dbus_match_remove(info); - dbus_connection_close(info->connection); + si_dbus_signals_unsubscribe(info); + g_object_unref(info->dbus); free(info->seat); free(info->active_session); free(info); @@ -272,217 +201,120 @@ void session_info_destroy(struct session_info *info) int session_info_get_fd(struct session_info *info) { - return info->fd; + return -1; } -static char *console_kit_get_first_seat(struct session_info *info) +/* Invoke a method on a remote object through DBus and wait for reply. + * + * Return type must be one of G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_SIGNATURE, + * G_VARIANT_TYPE_OBJECT_PATH, G_VARIANT_TYPE_OBJECT_PATH_ARRAY. + * + * In the case of G_VARIANT_TYPE_OBJECT_PATH_ARRAY, + * first element of the array is returned. + * + * Returns a newly-allocated string extracted from reply, or NULL on error */ +static gchar *dbus_call_method_for_string(GDBusConnection *dbus, + const gchar *bus_name, + const gchar *obj_path, + const gchar *interface, + const gchar *method, + GVariant *msg_body, + const GVariantType *ret_type) { - DBusError error; - DBusMessage *message = NULL; - DBusMessage *reply = NULL; - DBusMessageIter iter, subiter; - int type; - char *seat = NULL; - - - message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT, - OBJ_PATH_CONSOLE_KIT_MANAGER, - INTERFACE_CONSOLE_KIT_MANAGER, - "GetSeats"); - if (message == NULL) { - syslog(LOG_ERR, "Unable to create dbus message"); - goto exit; - } + GDBusMessage *message, *reply; + GError *err = NULL; + GVariant *body; + gchar *ret_str; - dbus_error_init(&error); - reply = dbus_connection_send_with_reply_and_block(info->connection, - message, - -1, - &error); - if (reply == NULL || dbus_error_is_set(&error)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "GetSeats failed: %s", error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "GetSeats failed"); - goto exit; - } + message = g_dbus_message_new_method_call(bus_name, obj_path, + interface, method); + g_dbus_message_set_body(message, msg_body); - dbus_message_iter_init(reply, &iter); - type = dbus_message_iter_get_arg_type(&iter); - if (type != DBUS_TYPE_ARRAY) { - syslog(LOG_ERR, - "expected an array return value, got a '%c' instead", type); - goto exit; - } + reply = g_dbus_connection_send_message_with_reply_sync(dbus, message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err); - dbus_message_iter_recurse(&iter, &subiter); - type = dbus_message_iter_get_arg_type(&subiter); - if (type != DBUS_TYPE_OBJECT_PATH) { - syslog(LOG_ERR, - "expected an object path element, got a '%c' instead", type); - goto exit; + g_object_unref(message); + + if (reply && g_dbus_message_to_gerror(reply, &err)) { + /* Remote process replied with an error (G_DBUS_MESSAGE_TYPE_ERROR). */ + g_object_unref(reply); + } + if (err) { + syslog(LOG_ERR, "%s call failed: %s", method, err->message); + g_error_free(err); + return NULL; } - dbus_message_iter_get_basic(&subiter, &seat); - info->seat = strdup(seat); + /* Reply always comes as a tuple, unpack it. */ + body = g_variant_get_child_value(g_dbus_message_get_body(reply), 0); + g_object_unref(reply); -exit: - if (reply != NULL) { - dbus_message_unref(reply); + if (g_variant_is_of_type(body, ret_type) == FALSE) { + syslog(LOG_ERR, "%s call returned a value of unexpected type: \"%s\"", + method, g_variant_get_type_string(body)); + g_variant_unref(body); + return NULL; } - if (message != NULL) { - dbus_message_unref(message); + if (g_variant_is_of_type(body, G_VARIANT_TYPE_OBJECT_PATH_ARRAY)) { + /* Get the first item in the array, this is NULL for an empty array. */ + const gchar **objv = g_variant_get_objv(body, NULL); + ret_str = g_strdup(objv[0]); + g_free(objv); + } else { + ret_str = g_strdup(g_variant_get_string(body, NULL)); } + g_variant_unref(body); + return ret_str; +} + +static char *console_kit_get_first_seat(struct session_info *info) +{ + info->seat = + dbus_call_method_for_string(info->dbus, + INTERFACE_CONSOLE_KIT, + OBJ_PATH_CONSOLE_KIT_MANAGER, + INTERFACE_CONSOLE_KIT_MANAGER, + "GetSeats", NULL, + G_VARIANT_TYPE_OBJECT_PATH_ARRAY); + syslog(LOG_INFO, "(console-kit) seat: %s", info->seat); return info->seat; } const char *session_info_get_active_session(struct session_info *info) { - DBusError error; - DBusMessage *message = NULL; - DBusMessage *reply = NULL; - char *session = NULL; - if (!info) return NULL; if (info->active_session) - return console_kit_check_active_session_change(info); - - message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT, - info->seat, - INTERFACE_CONSOLE_KIT_SEAT, - "GetActiveSession"); - if (message == NULL) { - syslog(LOG_ERR, "Unable to create dbus message"); - goto exit; - } + return info->active_session; - dbus_error_init(&error); - reply = dbus_connection_send_with_reply_and_block(info->connection, - message, - -1, - &error); - if (reply == NULL || dbus_error_is_set(&error)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "GetActiveSession failed: %s", error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "GetActiveSession failed"); - goto exit; - } + info->active_session = + dbus_call_method_for_string(info->dbus, + INTERFACE_CONSOLE_KIT, + info->seat, + INTERFACE_CONSOLE_KIT_SEAT, + "GetActiveSession", NULL, + G_VARIANT_TYPE_OBJECT_PATH); - dbus_error_init(&error); - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_OBJECT_PATH, &session, - DBUS_TYPE_INVALID)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "error get ssid from reply: %s", error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "error getting ssid from reply"); - session = NULL; - goto exit; - } - - info->active_session = strdup(session); - si_dbus_match_rule_update(info); - -exit: - if (reply != NULL) { - dbus_message_unref(reply); - } - - if (message != NULL) { - dbus_message_unref(message); - } - - /* In case the session was changed while we were running */ - return console_kit_check_active_session_change(info); + si_dbus_signal_listeners_update(info); + return info->active_session; } char *session_info_session_for_pid(struct session_info *info, uint32_t pid) { - DBusError error; - DBusMessage *message = NULL; - DBusMessage *reply = NULL; - DBusMessageIter args; - char *ssid = NULL; - if (!info) return NULL; - message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT, - OBJ_PATH_CONSOLE_KIT_MANAGER, - INTERFACE_CONSOLE_KIT_MANAGER, - "GetSessionForUnixProcess"); - if (message == NULL) { - syslog(LOG_ERR, "Unable to create dbus message"); - goto exit; - } - - dbus_message_iter_init_append(message, &args); - if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) { - syslog(LOG_ERR, "Unable to append dbus message args"); - goto exit; - } - - dbus_error_init(&error); - reply = dbus_connection_send_with_reply_and_block(info->connection, - message, - -1, - &error); - if (reply == NULL || dbus_error_is_set(&error)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s", - error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "GetSessionForUnixProcess failed"); - goto exit; - } - - dbus_error_init(&error); - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_OBJECT_PATH, &ssid, - DBUS_TYPE_INVALID)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "error get ssid from reply: %s", error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "error getting ssid from reply"); - ssid = NULL; - goto exit; - } - - ssid = strdup(ssid); - -exit: - if (reply != NULL) { - dbus_message_unref(reply); - } - - if (message != NULL) { - dbus_message_unref(message); - } - - return ssid; -} - -static char *console_kit_check_active_session_change(struct session_info *info) -{ - si_dbus_read_signals(info); - if (info->verbose) - syslog(LOG_DEBUG, "(console-kit) active-session: '%s'", - (info->active_session ? info->active_session : "None")); - - return info->active_session; + return dbus_call_method_for_string(info->dbus, + INTERFACE_CONSOLE_KIT, + OBJ_PATH_CONSOLE_KIT_MANAGER, + INTERFACE_CONSOLE_KIT_MANAGER, + "GetSessionForUnixProcess", + g_variant_new("(u)", pid), + G_VARIANT_TYPE_OBJECT_PATH); } gboolean session_info_session_is_locked(struct session_info *info) @@ -496,7 +328,6 @@ gboolean session_info_session_is_locked(struct session_info *info) * IdleHintChanged. So use the IdleHint value. * systemd-login uses locked-hint which is not implemented in ConsoleKit, * see https://github.com/ConsoleKit2/ConsoleKit2/issues/89 */ - si_dbus_read_signals(info); locked = info->session_idle_hint; if (info->verbose) { syslog(LOG_DEBUG, "(console-kit) session is locked: %s", @@ -509,69 +340,25 @@ gboolean session_info_session_is_locked(struct session_info *info) * in order to verify if active session belongs to user (non greeter) */ gboolean session_info_is_user(struct session_info *info) { - DBusError error; - DBusMessage *message = NULL; - DBusMessage *reply = NULL; - gchar *session_type = NULL; - gboolean ret = TRUE; + gchar *session_type; + gboolean ret; g_return_val_if_fail (info != NULL, TRUE); - g_return_val_if_fail (info->connection != NULL, TRUE); g_return_val_if_fail (info->active_session != NULL, TRUE); - message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT, - info->active_session, - INTERFACE_CONSOLE_KIT_SESSION, - "GetSessionType"); - if (message == NULL) { - syslog(LOG_ERR, - "(console-kit) Unable to create dbus message for GetSessionType"); - return TRUE; - } - - dbus_error_init(&error); - reply = dbus_connection_send_with_reply_and_block(info->connection, - message, - -1, - &error); - if (reply == NULL || dbus_error_is_set(&error)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, "GetSessionType failed: %s", error.message); - dbus_error_free(&error); - } else - syslog(LOG_ERR, "GetSessionType failed"); - goto exit; - } - - dbus_error_init(&error); - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_STRING, &session_type, - DBUS_TYPE_INVALID)) { - if (dbus_error_is_set(&error)) { - syslog(LOG_ERR, - "(console-kit) fail to get session-type from reply: %s", - error.message); - dbus_error_free(&error); - } else { - syslog(LOG_ERR, "(console-kit) fail to get session-type from reply"); - } - session_type = NULL; - goto exit; - } + session_type = + dbus_call_method_for_string(info->dbus, + INTERFACE_CONSOLE_KIT, + info->active_session, + INTERFACE_CONSOLE_KIT_SESSION, + "GetSessionType", NULL, + G_VARIANT_TYPE_STRING); /* Empty session_type means user */ if (info->verbose) syslog(LOG_DEBUG, "(console-kit) session-type is '%s'", session_type); - ret = (g_strcmp0 (session_type, "LoginWindow") != 0); - -exit: - if (reply != NULL) { - dbus_message_unref(reply); - } - if (message != NULL) { - dbus_message_unref(message); - } + ret = (g_strcmp0(session_type, "LoginWindow") != 0); + g_free(session_type); return ret; } -- 2.17.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel