Search code examples
c++linuxsystemddbus

Why do I get an error when I exit the sd-bus container?


I'm using RHEL 8 and systemd version is 239-74 I want to get data using dbus on c++ It's not a problem when using just one container(but this case also occur same error when exiting container) But when i should use one more containers I get "Device or Resource busy"

#include <iostream>
#include <unistd.h>
#include <systemd/sd-bus.h>

int main() {
        sd_bus_error error = SD_BUS_ERROR_NULL;
        sd_bus *bus = nullptr;
        int ret = sd_bus_open_system(&bus);
        const char *service_name = "org.freedesktop.systemd1";
        const char *object_path = "/org/freedesktop/systemd1";
        const char *interface = "org.freedesktop.systemd1.Manager";
        const char *method = "ListUnits";

        sd_bus_message *reply = nullptr;
        ret = sd_bus_call_method(bus,
                        service_name,
                        object_path,
                        interface,
                        method,
                        &error,
                        &reply,
                        "");
        if (ret < 0) {
                return 1;
        }
        const char *unit_name;
        const char *unit_description;
        const char *unit_load_state;
        const char *unit_active_state;
        const char *sub_state,*followed_state,*object1_path,*queued_job,*job_type,*job_object_path;
        unsigned int uint;

        ret = sd_bus_message_enter_container(reply, 'a', "(ssssssouso)");
        if(ret<0){
                std::cerr <<strerror(-ret);
        }
        ret = sd_bus_message_exit_container(reply);
        if(ret<0){
                std::cerr <<strerror(-ret);
        }
        sd_bus_message_unref(reply);
        sd_bus_unref(bus);

        return 0;
}

I think environment problem but on Ubuntu, same error occurred. I want read array of dict, but i can't exit container so i can't get other data


Solution

  • From the documentation:

    Note that sd_bus_message_exit_container() may only be called after iterating through all members of the container, i.e. reading or skipping over them.

    You need to consume the contents of the array before exiting the container:

    ret = sd_bus_message_enter_container(reply, 'a', "(ssssssouso)");
    if(ret<0){
        std::cerr <<strerror(-ret);
    }
    
    struct {
        const char *primary_name, *human_name, *load_state, *active_state, *sub_state, *following;
        const char **unit_object_path;
        uint32_t queued_job_id;
        const char *job_type
        const char **job_object_path;
    } unit;
    
    for (;;) {
        ret = sd_bus_message_read(reply, "(ssssssouso)", &unit.primary_name, &unit.human_name, &unit.load_state, &unit.active_state, &unit.sub_state, &unit.following, &unit.unit_object_path, &unit.queued_job_id, &unit.job_type, &unit.job_object_path);
        if (ret == 0) {
            // done reading
            break;
        }
        if(ret<0){
            std::cerr <<strerror(-ret);
            break;
        }
    }
    
    ret = sd_bus_message_exit_container(reply);
    if(ret<0){
        std::cerr <<strerror(-ret);
    }