/** * Removes a link from the list. This is a constant-time operation. * * @param list address of the list head. * @param link the list link to remove. */ void _dbus_list_remove_link (DBusList **list, DBusList *link) { _dbus_list_unlink (list, link); free_link (link); }
/** * Removes the last link in the list and returns it. This is a * constant-time operation. * * @param list address of the list head. * @returns the last link in the list, or #NULL for an empty list. */ DBusList* _dbus_list_pop_last_link (DBusList **list) { DBusList *link; link = _dbus_list_get_last_link (list); if (link == NULL) return NULL; _dbus_list_unlink (list, link); return link; }
EXPORT_C #endif DBusList* _dbus_list_pop_first_link (DBusList **list) { DBusList *link; link = _dbus_list_get_first_link (list); if (link == NULL) return NULL; _dbus_list_unlink (list, link); return link; }
/* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_add_owner (BusService *service, DBusConnection *connection, dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { BusOwner *bus_owner; DBusList *bus_owner_link; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* Send service acquired message first, OOM will result * in cancelling the transaction */ if (service->owners == NULL) { if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) return FALSE; } bus_owner_link = _bus_service_find_owner_link (service, connection); if (bus_owner_link == NULL) { bus_owner = bus_owner_new (service, connection, flags); if (bus_owner == NULL) { BUS_SET_OOM (error); return FALSE; } bus_owner_set_flags (bus_owner, flags); if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) { if (!_dbus_list_append (&service->owners, bus_owner)) { bus_owner_unref (bus_owner); BUS_SET_OOM (error); return FALSE; } } else { if (!_dbus_list_insert_after (&service->owners, _dbus_list_get_first_link (&service->owners), bus_owner)) { bus_owner_unref (bus_owner); BUS_SET_OOM (error); return FALSE; } } } else { /* Update the link since we are already in the queue * No need for operations that can produce OOM */ bus_owner = (BusOwner *) bus_owner_link->data; if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) { DBusList *link; _dbus_list_unlink (&service->owners, bus_owner_link); link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); } bus_owner_set_flags (bus_owner, flags); return TRUE; } if (!add_cancel_ownership_to_transaction (transaction, service, bus_owner)) { bus_service_unlink_owner (service, bus_owner); BUS_SET_OOM (error); return FALSE; } return TRUE; }
dbus_bool_t bus_registry_acquire_service (BusRegistry *registry, DBusConnection *connection, const DBusString *service_name, dbus_uint32_t flags, dbus_uint32_t *result, BusTransaction *transaction, DBusError *error) { dbus_bool_t retval; DBusConnection *old_owner_conn; BusClientPolicy *policy; BusService *service; BusActivation *activation; BusSELinuxID *sid; BusOwner *primary_owner; retval = FALSE; if (!_dbus_validate_bus_name (service_name, 0, _dbus_string_get_length (service_name))) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Requested bus name \"%s\" is not valid", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to acquire invalid service name\n"); goto out; } if (_dbus_string_get_byte (service_name, 0) == ':') { /* Not allowed; only base services can start with ':' */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Cannot acquire a service starting with ':' such as \"%s\"", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", _dbus_string_get_const_data (service_name)); goto out; } if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Connection \"%s\" is not allowed to own the service \"%s\"because " "it is reserved for D-Bus' use only", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", DBUS_SERVICE_DBUS); goto out; } policy = bus_connection_get_policy (connection); _dbus_assert (policy != NULL); /* Note that if sid is #NULL then the bus's own context gets used * in bus_connection_selinux_allows_acquire_service() */ sid = bus_selinux_id_table_lookup (registry->service_sid_table, service_name); if (!bus_selinux_allows_acquire_service (connection, sid, _dbus_string_get_const_data (service_name), error)) { if (dbus_error_is_set (error) && dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) { goto out; } dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection \"%s\" is not allowed to own the service \"%s\" due " "to SELinux policy", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } if (!bus_client_policy_check_can_own (policy, service_name)) { dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection \"%s\" is not allowed to own the service \"%s\" due " "to security policies in the configuration file", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } if (bus_connection_get_n_services_owned (connection) >= bus_context_get_max_services_per_connection (registry->context)) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Connection \"%s\" is not allowed to own more services " "(increase limits in configuration file if required)", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)"); goto out; } service = bus_registry_lookup (registry, service_name); if (service != NULL) { primary_owner = bus_service_get_primary_owner (service); if (primary_owner != NULL) old_owner_conn = primary_owner->conn; else old_owner_conn = NULL; } else old_owner_conn = NULL; if (service == NULL) { service = bus_registry_ensure (registry, service_name, connection, flags, transaction, error); if (service == NULL) goto out; } primary_owner = bus_service_get_primary_owner (service); if (primary_owner == NULL) goto out; if (old_owner_conn == NULL) { _dbus_assert (primary_owner->conn == connection); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } else if (old_owner_conn == connection) { bus_owner_set_flags (primary_owner, flags); *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; } else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && !(bus_service_get_allow_replacement (service))) || ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) { DBusList *link; BusOwner *temp_owner; /* Since we can't be queued if we are already in the queue remove us */ link = _bus_service_find_owner_link (service, connection); if (link != NULL) { _dbus_list_unlink (&service->owners, link); temp_owner = (BusOwner *)link->data; bus_owner_unref (temp_owner); _dbus_list_free_link (link); } *result = DBUS_REQUEST_NAME_REPLY_EXISTS; } else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || !(bus_service_get_allow_replacement (service)))) { /* Queue the connection */ if (!bus_service_add_owner (service, connection, flags, transaction, error)) goto out; *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; } else { /* Replace the current owner */ /* We enqueue the new owner and remove the first one because * that will cause NameAcquired and NameLost messages to * be sent. */ if (!bus_service_add_owner (service, connection, flags, transaction, error)) goto out; if (primary_owner->do_not_queue) { if (!bus_service_remove_owner (service, old_owner_conn, transaction, error)) goto out; } else { if (!bus_service_swap_owner (service, old_owner_conn, transaction, error)) goto out; } _dbus_assert (connection == bus_service_get_primary_owner (service)->conn); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } activation = bus_context_get_activation (registry->context); retval = bus_activation_send_pending_auto_activation_messages (activation, service, transaction); if (!retval) BUS_SET_OOM (error); out: return retval; }
/* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_remove_owner (BusService *service, DBusConnection *connection, BusTransaction *transaction, DBusError *error) { BusOwner *primary_owner; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we * might have to undo if the notification-sending failed */ /* Send service lost message */ primary_owner = bus_service_get_primary_owner (service); if (primary_owner != NULL && primary_owner->conn == connection) { if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; } else { /* if we are not the primary owner then just remove us from the queue */ DBusList *link; BusOwner *temp_owner; link = _bus_service_find_owner_link (service, connection); _dbus_list_unlink (&service->owners, link); temp_owner = (BusOwner *)link->data; bus_owner_unref (temp_owner); _dbus_list_free_link (link); return TRUE; } if (service->owners == NULL) { _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); } else if (_dbus_list_length_is_one (&service->owners)) { if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), NULL, transaction, error)) return FALSE; } else { DBusList *link; BusOwner *new_owner; DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); new_owner = (BusOwner *)link->data; new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } bus_service_unlink_owner (service, primary_owner); if (service->owners == NULL) bus_service_unlink (service); return TRUE; }
dbus_bool_t bus_service_swap_owner (BusService *service, DBusConnection *connection, BusTransaction *transaction, DBusError *error) { DBusList *swap_link; BusOwner *primary_owner; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we * might have to undo if the notification-sending failed */ /* Send service lost message */ primary_owner = bus_service_get_primary_owner (service); if (primary_owner == NULL || primary_owner->conn != connection) _dbus_assert_not_reached ("Tried to swap a non primary owner"); if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; if (service->owners == NULL) { _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); } else if (_dbus_list_length_is_one (&service->owners)) { _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); } else { DBusList *link; BusOwner *new_owner; DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); new_owner = (BusOwner *)link->data; new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } /* unlink the primary and make it the second link */ swap_link = _dbus_list_get_first_link (&service->owners); _dbus_list_unlink (&service->owners, swap_link); _dbus_list_insert_after_link (&service->owners, _dbus_list_get_first_link (&service->owners), swap_link); return TRUE; }
void bus_expire_list_unlink (BusExpireList *list, DBusList *link) { _dbus_list_unlink (&list->items, link); }