Search code examples
ddbusudisks

How to list all the removable devices with DBus and UDisks2?


I need to list, filter and open block devices with UDisks2. I am trying to list all the removable devices.

The GetBlockDevices method provided by UDisks2 requires a a{sv} type. If I am not mistaken, it's a HashTable of string keys and Variant values.

How can I use this information to list the devices? So far I tried the following:

import std.stdio, ddbus;

void main()
{
    Connection conn = connectToBus();
    PathIface obj = new PathIface(conn, "org.freedesktop.UDsks2",
            "/org/freedesktop/UDisks2/Manager", "org.freedesktop.UDisks2.Manager");

    writeln(obj.call!string("GetBlockDevices", "org.freedesktop.DBus", ???));
}

The call method requires an Arg at as it's last parameter. How can I provide a a{sv} in there?


I am using the ddbus library.


For args, I used Variant!string[string] since Variant itself is a templated type. I also removed the superfluous "org.freedesktop.DBus" from the call method parameter.

import std.stdio, ddbus;
import ddbus: Variant;

void main()
{
    Connection conn = connectToBus();
    PathIface obj = new PathIface(conn, "org.freedesktop.DBus",
            "/org/freedesktop/UDisks2/Manager", "org.freedesktop.UDisks2.Manager");

    Variant!string[string] arg;
    writeln(obj.call!string("GetBlockDevices", arg));
}

However I am getting the following error:

ddbus.exception.DBusException@../../.dub/packages/ddbus-2.3.0/ddbus/source/ddbus/thin.d(833): org.freedesktop.DBus does not understand message GetBlockDevices


Solution

  • Your issues are:

    1. The D-Bus name org.freedesktop.UDisks2 is on the system bus (not on the session bus), so the connectToBus() call needs to be changed.
    2. The bus name is org.freedeskop.UDisks2, not org.freedesktop.DBus
    3. The return value of GetBlockDevices is ao (array of object paths), but you are calling it with call!string which means you would get back a string. Change this to call!(ObjectPath[])
    4. (optional) you made your arguments Variant!string[string]. The Variant!T type in ddbus is a helper which will just make any type T act like a variant in the dbus protocol, but it doesn't actually allow any additional types. If you want to support passing any types ddbus supports either using std.variant : Variant or there is a special type you can use with the ddbus variant using Variant!DBusAny which is a more lightweight tagged union with only support for all the dbus types (and more introspection)

    I believe this code is what you want with all the issues fixed:

    import std.stdio, ddbus;
    import ddbus : Variant;
    import ddbus.c_lib;
    
    void main()
    {
        Connection conn = connectToBus(DBusBusType.DBUS_BUS_SYSTEM);
        PathIface obj = new PathIface(conn,
            busName("org.freedesktop.UDisks2"),
            ObjectPath("/org/freedesktop/UDisks2/Manager"),
            interfaceName("org.freedesktop.UDisks2.Manager"));
    
        Variant!DBusAny[string] arg;
        writeln(obj.call!(ObjectPath[])("GetBlockDevices", arg));
    }
    

    In this code I have also used the type-safe ddbus API, which makes the arguments in PathIface more clear. The type-safe API requires ddbus 3.0.0-beta.1 or above.

    Example output:

    [/org/freedesktop/UDisks2/block_devices/sdc1, /org/freedesktop/UDisks2/block_devices/sdb1, /org/freedesktop/UDisks2/block_devices/sda, /org/freedesktop/UDisks2/block_devices/nvme0n1p2, /org/freedesktop/UDisks2/block_devices/sdb3, /org/freedesktop/UDisks2/block_devices/sdc, /org/freedesktop/UDisks2/block_devices/nvme0n1, /org/freedesktop/UDisks2/block_devices/sr0, /org/freedesktop/UDisks2/block_devices/nvme0n1p1, /org/freedesktop/UDisks2/block_devices/sde, /org/freedesktop/UDisks2/block_devices/sdb2, /org/freedesktop/UDisks2/block_devices/sdb, /org/freedesktop/UDisks2/block_devices/sda1, /org/freedesktop/UDisks2/block_devices/sde1, /org/freedesktop/UDisks2/block_devices/sdb4, /org/freedesktop/UDisks2/block_devices/sdd]