1

I'm having a problem with qdbus. I need to pass sba(sv) to the SetUnitProperties method. I am only able to pass sba{sv} by using a dictonary. I can't find any documentation or examples on how to pass an array. Here is the error message : "Invalid arguments 'sba{sv}' to call org.freedesktop.systemd1.Manager.SetUnitProperties(), expecting 'sba(sv)'.".

I have also tried using StartTransienUnit which is even more complicated requiring ssa(sv)a(sa(sv)) !

Here is my code in C:

int QUsbDeviceWrapper::swUpdate() {
    // Initialize the D-Bus connection
    QDBusConnection connection = QDBusConnection::systemBus();

    // Check if the connection is valid
    if (!connection.isConnected()) {
        qWarning("Cannot connect to the D-Bus system bus");
        return 1;
    }

    // Obtain a proxy object for the systemd1 service
    QDBusInterface managerInterface("org.freedesktop.systemd1",
                                    "/org/freedesktop/systemd1",
                                    "org.freedesktop.systemd1.Manager",
                                    connection);

    // Check if the interface is valid
    if (!managerInterface.isValid()) {
        qWarning("Failed to obtain interface to systemd1.Manager");
        return 1;
    }

    // Prepare arguments for the SetUnitProperties method
    QString serviceName = "[email protected]";
    bool runtime = true;
    QVariantMap properties;
    properties.insert("StopWhenUnneeded", QVariant(false)); // Use QVariant for boolean value

    // Call the SetUnitProperties method
    QDBusMessage response = managerInterface.call("SetUnitProperties", serviceName, runtime, properties);

    // Check if the call was successful
    if (response.type() == QDBusMessage::ErrorMessage) {
        qWarning() << "Error calling SetUnitProperties:" << response.errorMessage();
        return 1;
    }

    qDebug() << "SetUnitProperties call successful";

    return 0;
}

I have tried using a QVariantMap to define the array but dbus doesen't accept it. I was expecting dbus to change the unit's properties.

2 Answers 2

1

This seems to be making the call, but actually crashes for some reason:

    // Prepare arguments for the SetUnitProperties method
    QString serviceName = "[email protected]";
    bool runtime = true;

    QVariantList propertiesList;
    propertiesList << QVariant::fromValue(Property("StopWhenUnneeded", false));
    // Append other properties...

    // Call the SetUnitProperties method
    QDBusMessage response = managerInterface.call("SetUnitProperties", serviceName, runtime, propertiesList);

Property is defined as:

struct Property {
    Property(const QString &propertyName, bool propertyValue):
        propertyName(propertyName),
        propertyValue(propertyValue) {}
    QString propertyName;
    bool propertyValue;
};

Q_DECLARE_METATYPE(Property)

// Marshall the MyStructure data into a D-Bus argument
QDBusArgument &operator<<(QDBusArgument &argument, const Property &property)
{
    argument.beginStructure();
    argument << property.propertyName << property.propertyValue;
    argument.endStructure();
    return argument;
}

// Retrieve the MyStructure data from the D-Bus argument
const QDBusArgument &operator>>(const QDBusArgument &argument, Property &property)
{
    argument.beginStructure();
    argument >> property.propertyName >> property.propertyValue;
    argument.endStructure();
    return argument;
}

Also don't forget to call qDBusRegisterMetaType<Property>();

0

According to QDBus documentation, an array can be passed as a QList<something>.

For a(sv) you might need to define a custom type for the {QString, QDBusVariant} structure, then pass it to qDBusRegisterMetaType(), and then you would be able to pass a QList<mySvTupleType> as the argument.

Likewise a(sa(sv)) would involve another custom {QString, QList<mySvTupleType>} structure.

The manual way of creating such a message appears to involve QDBusArgument with its beginArray() and beginStructure() methods – it might actually be easier to build the message by hand this way.

(I don't know offhand why systemd chose to use such a type, but perhaps they specifically needed an ordered dict for this particular method call – the regular dict/map type in many languages wouldn't preserve the ordering.)

3
  • Thanks. I have also tried something like that but I'm unsure of my code. I have defined this structure: struct Properties { QString key; QDBusVariant value; }; And then pass a QVariantList to dbus containing a list of the properties. I then get this error: Invalid arguments 'sbav'.
    – gomme600
    Commented Jun 4 at 7:01
  • Don't pass a QVariantList – just a regular QList<Properties> or something along those lines. (As you can see from the message, QVariantList implies that each element is automatically packed into a QVariant, but you don't need that here – all elements are of the same type.) Commented Jun 4 at 7:15
  • I get this compilation error when calling the list directly: error: no matching function for call to ‘QVariant::QVariant(QList<Properties>&)’. I can't seem to pass my own type to dbus. I have registered Properties like this : qDBusRegisterMetaType<Properties>(); And I am adding data to it like this : QList<Properties> propertiesList; propertiesList.append(Properties{QString("StopWhenUnneeded"), QDBusVariant(QVariant(false))});
    – gomme600
    Commented Jun 4 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.