dbus Subscribe to Signals for /run/rpm-ostree-transaction.sock Fails
Closed this issue · 1 comments
Host system details
● ppos:fedora/38/x86_64/photon-pony-base
Version: PhotonPonyOSBase 38.20230830.0 (2023-08-30T08:20:51Z)
BaseCommit: 64481d03e28be7bf5694b171b314c0f9e05f5ae177ad71bdbc54b0ddc469855a
GPGSignature: Valid signature by F4AADD82266C8BC2DB3FC9B0D6763692AE005CBF
LayeredPackages: 'g++' abseil-cpp-devel bustle clang clang-tools-extra cmake cppcheck d-feet d-spy dbus-devel dbus-tools dotnet-runtime-7.0 dotnet-sdk-7.0 doxygen gcovr gdb grpc-devel grpc-plugins libasan liblsan libtsan
libubsan libudev-devel nuget opalkelly plantuml python3-pip qt soci-devel spcm4 spcm4-akmod
LocalPackages: cert-gen-1.5.0-1.noarch
Unlocked: development
ppos:fedora/38/x86_64/photon-pony-base
Version: PhotonPonyOSBase 38.20230830.0 (2023-08-30T08:20:51Z)
BaseCommit: 64481d03e28be7bf5694b171b314c0f9e05f5ae177ad71bdbc54b0ddc469855a
GPGSignature: Valid signature by F4AADD82266C8BC2DB3FC9B0D6763692AE005CBF
LayeredPackages: 'g++' abseil-cpp-devel bustle clang clang-tools-extra cmake cppcheck d-feet d-spy dbus-devel dotnet-runtime-7.0 dotnet-sdk-7.0 doxygen gcovr gdb grpc-devel grpc-plugins libasan liblsan libtsan libubsan
libudev-devel nuget opalkelly plantuml python3-pip soci-devel spcm4 spcm4-akmod
LocalPackages: cert-gen-1.5.0-1.noarch
ppos:fedora/38/x86_64/photon-pony-base
Version: PhotonPonyOSBase 38.20230828.0 (2023-08-28T08:39:50Z)
BaseCommit: 6c242a5ce9a03eb48868008888f7dd03fe6c524955659c2572c0ad16f244b7dc
GPGSignature: Valid signature by F4AADD82266C8BC2DB3FC9B0D6763692AE005CBF
LayeredPackages: 'g++' abseil-cpp-devel clang clang-tools-extra cmake cppcheck d-spy dbus-devel dotnet-runtime-7.0 dotnet-sdk-7.0 doxygen gcovr gdb grpc-devel grpc-plugins libasan liblsan libtsan libubsan libudev-devel nuget
opalkelly plantuml python3-pip soci-devel spcm4 spcm4-akmod
Pinned: yes
ppos:fedora/38/x86_64/photon-pony-base
Version: PhotonPonyOSBase 38.20230828.0 (2023-08-28T08:39:50Z)
BaseCommit: 6c242a5ce9a03eb48868008888f7dd03fe6c524955659c2572c0ad16f244b7dc
GPGSignature: Valid signature by F4AADD82266C8BC2DB3FC9B0D6763692AE005CBF
LayeredPackages: 'g++' abseil-cpp-devel clang clang-tools-extra cmake cppcheck d-spy dbus-devel dotnet-runtime-7.0 dotnet-sdk-7.0 doxygen gcovr gdb grpc-devel grpc-plugins libasan liblsan libtsan libubsan libudev-devel nuget
plantuml python3-pip soci-devel
Pinned: yes
Expected vs actual behavior
I can successfully trigger an Upgrade
org.projectatomic.rpmostree1.Upgrade
. Then I successfully connect to the returned transaction_address
using libdbus
. There I can call org.projectatomic.rpmostree1.Transaction.Start
or even org.projectatomic.rpmostree1.Transaction.Cancel
. BUT I'm failing to subscribe to signals. I always get: NAME - org.freedesktop.DBus.Error.UnknownMethod, MESSAGE - Object does not exist at path “/org/freedesktop/DBus”'.
I tried to reduce my code to the following example showing the error. Invoking it after one has started an upgrade via for example d-spy
results in Match Error (Object does not exist at path “/org/freedesktop/DBus”)
.
Expected:
Subscribing to events should work as expected.
Steps to reproduce it
all:
gcc test.c -o test $(shell pkg-config --cflags --libs dbus-1)
Code:
#include <dbus/dbus.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
DBusError err;
dbus_error_init(&err);
// Connect to the custom D-Bus socket
DBusConnection* conn = dbus_connection_open("unix:path=/run/rpm-ostree-transaction.sock", &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Connection Error: %s\n", err.message);
dbus_error_free(&err);
}
if (conn == NULL) {
exit(1);
}
printf("Connected\n");
dbus_error_init(&err);
dbus_bus_add_match(conn, "type='signal', sender='org.projectatomic.rpmostree1', interface='org.projectatomic.rpmostree1.Transaction', member='Message', path='/'", &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Match Error (%s)\n", err.message);
dbus_error_free(&err);
exit(1);
}
printf("Registered!");
// Main loop
while (dbus_connection_read_write_dispatch(conn, -1)) {
// your custom handling code
}
// Clean up
dbus_connection_unref(conn);
return 0;
}
rpm-ostree install dbus-devel
make
./test
💣
Would you like to work on the issue?
I tried to, but I'm failing to find any hints. I even tried to take a look how cockpit-ostree handles it here: https://github.com/cockpit-project/cockpit-ostree/blob/bdb2e19f6e42c696f94656f385689089278d5ba7/src/client.js#L653-L676
But as far as I can see it, they are doing the same thing.
Solution
Since the daemon offers only an implementation without /org/freedesktop/DBus
we can not use dbus_bus_add_match(...)
for delegated filtering. A solution is to listen to all incoming events and then filter manually.
#include <dbus/dbus.h>
#include <stdio.h>
#include <stdlib.h>
DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data) {
if (dbus_message_is_signal(message, "org.projectatomic.rpmostree1.Transaction", "Finished")) {
printf("FINISHED Signal\n");
} else if (dbus_message_is_signal(message, "org.projectatomic.rpmostree1.Transaction", "Message")) {
printf("MESSAGE Signal\n");
}
// Print the message type
int type = dbus_message_get_type(message);
const char *type_str = dbus_message_type_to_string(type);
printf("Message Type: %s\n", type_str);
// Print the interface, if present
const char *interface = dbus_message_get_interface(message);
if (interface) {
printf("Interface: %s\n", interface);
}
// Print the method or signal name, if present
const char *member = dbus_message_get_member(message);
if (member) {
printf("Member: %s\n", member);
}
// Print the sender, if present
const char *sender = dbus_message_get_sender(message);
if (sender) {
printf("Sender: %s\n", sender);
}
// Print the destination, if present
const char *destination = dbus_message_get_destination(message);
if (destination) {
printf("Destination: %s\n", destination);
}
// Handle specific message types if necessary
if (type == DBUS_MESSAGE_TYPE_SIGNAL) {
// Handle signals
} else if (type == DBUS_MESSAGE_TYPE_METHOD_CALL) {
// Handle method calls
}
printf("\n"); // Add a new line for clarity
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
int main() {
DBusError err;
dbus_error_init(&err);
// Connect to the custom D-Bus socket
DBusConnection* conn = dbus_connection_open("unix:path=/run/rpm-ostree-transaction.sock", &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Connection Error: %s\n", err.message);
dbus_error_free(&err);
exit(1);
}
if (conn == NULL) {
exit(1);
}
printf("Connected\n");
dbus_connection_add_filter(conn, signal_filter, NULL, NULL);
printf("Registered!\n");
// Main loop
while (dbus_connection_read_write_dispatch(conn, -1)) {
// your custom handling code
}
// Clean up
dbus_connection_remove_filter(conn, signal_filter, NULL);
dbus_connection_unref(conn);
return 0;
}