0

I'm trying to wrap my head around managing a systemd service using DBus calls. However, I can't seem to figure out the correct way to make a method call, since whatever I do it throws a DBus error

// Create connection
auto connection = Gio::DBus::Connection::get_sync(Gio::DBus::BusType::BUS_TYPE_SESSION);
// Create the parameters vector
std::vector<std::string> param_vec;
param_vec.push_back("my_unit_name");
auto param_vec_variant = Glib::Variant<std::vector<std::string>>::create(param_vec);
auto params = Glib::Variant<std::vector<std::string>>::create_tuple(param_vec_variant);

try {
    // Make the "GetUnit" dbus call to systemd
    auto response = connection->call_sync(
        "/org/freedesktop/systemd1",
        "org.freedesktop.systemd1.Manager",
        "GetUnit",
        params
    );
}
catch (Gio::DBus::Error err) {
    // org.freedesktop.DBus.Error.UnknownMethod being thrown
    std::cerr << Gio::DBus::ErrorUtils::get_remote_error(err) << std::endl;
}

Can anyone point out where I'm going wrong?

Ben
  • 394
  • 7
  • 13
  • Are you sure you’re passing enough parameters to `call_sync()`? The `bus_name` parameter, which should likely be `org.freedesktop.systemd1` appears to be missing. In addition, you might want to connect to the system bus rather than the session bus, unless you’re deliberately trying to control a session service (which is fine, but less common than trying to control a system service). – Philip Withnall Jun 29 '21 at 21:57
  • That's odd. I thought the bus name would be "session" since I'm on the session bus – Ben Jun 29 '21 at 21:58
  • The `bus_name` you pass to `call_sync()` is the unique or well-known name of the service you’re calling a method on. – Philip Withnall Jun 29 '21 at 22:03
  • Okay, yes `bus_name` is an optional parameter. I just added it like you said and I'm getting a new error, which is probably a sign that that was the problem. I'll update with a solution in the morning – Ben Jun 29 '21 at 22:05
  • Glad to hear it. – Philip Withnall Jun 29 '21 at 22:06
  • I was just writing this comment and might as well post it: Buses contain services (each with a unique name and zero or more well-known names). Services contain objects. Objects implement interfaces. Interfaces contain methods. In order to call a method you have to specify all of these things. You specify the bus by connecting to it, and then you pass the rest of the identifiers to `call_sync()`. They all have to be correct for the call to work. You may find debugging your D-Bus calls easier if you use a visual call graphing tool like Bustle (https://gitlab.freedesktop.org/bustle/bustle). – Philip Withnall Jun 29 '21 at 22:06
  • Thank you. I think you've definitely pointed out a misunderstanding of dbus that I had – Ben Jun 29 '21 at 22:12

1 Answers1

1

As Philip pointed out, my problem was with the connection->call_sync method, which took the default parameter bus_name = "" (docs).

The bus_name for systemd is org.freedesktop.systemd1, so the correct solution to this problem would be to add this parameter:

auto response = connection->call_sync(
    "/org/freedesktop/systemd1",
    "org.freedesktop.systemd1.Manager",
    "GetUnit",
    params,
    "org.freedesktop.systemd1" // bus_name
);

However, after further digging I found that it's actually not recommended to use the Connection object for DBus calls, and that I should actually be using Proxy.

Eventually I generalised my code using variadic parameters and settled on this function (try-catch block removed for readability):

template <typename... Types>
Glib::VariantContainerBase dbus_call(const Glib::ustring& method, const Types&... params) {
    auto proxy = Gio::DBus::Proxy::create_for_bus_sync(Gio::DBus::BusType::BUS_TYPE_SESSION, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager");
    auto params_variant = Glib::Variant<std::tuple<Types...>>::create(std::tuple<Types...>(params...));

    return proxy->call_sync(method, params_variant);
}

This can be called like so:

auto response = dbus_call("GetUnit", "my_unit_name");
Ben
  • 394
  • 7
  • 13