Bug found by David Henningsson. --- reserve-monitor.c | 74 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/reserve-monitor.c b/reserve-monitor.c index 4097a6f..39a0c77 100644 --- a/reserve-monitor.c +++ b/reserve-monitor.c @@ -59,6 +59,22 @@ struct rm_monitor { "member='NameOwnerChanged'," \ "arg0='%s'" +static unsigned get_busy( + DBusConnection *c, + const char *name_owner) { + + const char *un; + + if (!name_owner || !*name_owner) + return FALSE; + + if ((un = dbus_bus_get_unique_name(c))) + if (strcmp(name_owner, un) == 0) + return FALSE; + + return TRUE; +} + static DBusHandlerResult filter_handler( DBusConnection *c, DBusMessage *s, @@ -87,16 +103,7 @@ static DBusHandlerResult filter_handler( if (strcmp(name, m->service_name) == 0) { unsigned old_busy = m->busy; - m->busy = !!(new && *new); - - /* If we ourselves own the device, then don't consider this 'busy' */ - if (m->busy) { - const char *un; - - if ((un = dbus_bus_get_unique_name(c))) - if (strcmp(new, un) == 0) - m->busy = FALSE; - } + m->busy = get_busy(c, new); if (m->busy != old_busy && m->change_cb) { m->ref++; @@ -115,11 +122,13 @@ invalid: int rm_watch( rm_monitor **_m, DBusConnection *connection, - const char*device_name, + const char *device_name, rm_change_cb_t change_cb, DBusError *error) { rm_monitor *m = NULL; + DBusMessage *msg = NULL, *reply = NULL; + const char *name_owner; int r; DBusError _error; @@ -178,13 +187,44 @@ int rm_watch( m->matching = 1; - m->busy = dbus_bus_name_has_owner(m->connection, m->service_name, error); + if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner"))) { + r = -ENOMEM; + goto fail; + } - if (dbus_error_is_set(error)) { - r = -EIO; + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &m->service_name, DBUS_TYPE_INVALID)) { + r = -ENOMEM; goto fail; } + reply = dbus_connection_send_with_reply_and_block(m->connection, msg, DBUS_TIMEOUT_USE_DEFAULT, error); + dbus_message_unref(msg); + msg = NULL; + + if (reply) { + if (!dbus_message_get_args(reply, error, DBUS_TYPE_STRING, &name_owner, DBUS_TYPE_INVALID)) { + r = -EIO; + goto fail; + } + } else { + if (dbus_error_has_name(error, "org.freedesktop.DBus.Error.NameHasNoOwner")) { + dbus_error_free(error); + name_owner = NULL; + } else { + r = -EIO; + goto fail; + } + } + + m->busy = get_busy(m->connection, name_owner); + + /* The reply can't be unreffed earlier, because name_owner points + * inside the message. */ + if (reply) { + dbus_message_unref(reply); + reply = NULL; + } + *_m = m; return 0; @@ -192,6 +232,12 @@ fail: if (&_error == error) dbus_error_free(&_error); + if (msg) + dbus_message_unref(msg); + + if (reply) + dbus_message_unref(reply); + if (m) rm_release(m); -- 1.7.10.4