【问题标题】:Why is my DBus call giving an UnknownMethod DBus error?为什么我的 DBus 调用会给出 UnknownMethod DBus 错误?
【发布时间】:2021-06-29 15:14:54
【问题描述】:

我正在尝试使用 DBus 调用来管理 systemd 服务。但是,我似乎无法找出进行方法调用的正确方法,因为无论我做什么都会引发 DBus 错误

// 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;
}

谁能指出我哪里出错了?

【问题讨论】:

  • 您确定向call_sync() 传递了足够多的参数吗? bus_name 参数(应该是 org.freedesktop.systemd1)似乎丢失了。此外,您可能希望连接到系统总线而不是会话总线,除非您有意尝试控制会话服务(这很好,但不如尝试控制系统服务常见)。
  • 这很奇怪。我认为总线名称将是“会话”,因为我在会话总线上
  • 您传递给call_sync()bus_name 是您调用方法的服务的唯一名称或众所周知的名称。
  • 好的,是的 bus_name 是一个可选参数。我就像你说的那样添加了它,我收到了一个新错误,这可能表明这是问题所在。我会在早上更新解决方案
  • 很高兴听到这个消息。

标签: c++ systemd glib dbus glibmm


【解决方案1】:

正如 Philip 指出的,我的问题在于 connection-&gt;call_sync 方法,它采用默认参数 bus_name = "" (docs)。

systemd 的bus_nameorg.freedesktop.systemd1,所以解决这个问题的正确方法是添加这个参数:

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

但是,经过进一步挖掘,我发现实际上是not recommended 使用Connection 对象进行DBus 调用,而我实际上应该使用Proxy

最终我使用可变参数概括了我的代码并选择了这个函数(为了便于阅读,删除了 try-catch 块):

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);
}

可以这样调用:

auto response = dbus_call("GetUnit", "my_unit_name");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-14
    • 2019-03-14
    • 2012-11-29
    • 2013-12-15
    • 2016-07-10
    • 2011-12-18
    • 2014-02-07
    • 1970-01-01
    相关资源
    最近更新 更多