[systemd-devel] libsystemd/sd_bus: trouble understanding how to parse complex responses
Sergey 'Jin' Bostandzhyan
jin at mediatomb.cc
Mon Sep 7 17:40:51 UTC 2020
Hi,
I have spent quite some time on this, but I don't seem to be getting
anywhere, so I hope someone could point me in the right direction.
I am learning sd_bus, my goal is to get a list of available modem services
from ModemManager. To make sure that what I am looking for is actually there,
I first checked with busctl:
Service org.freedesktop.ModemManager1:
└─/org
└─/org/freedesktop
└─/org/freedesktop/ModemManager1
├─/org/freedesktop/ModemManager1/Modem
│ └─/org/freedesktop/ModemManager1/Modem/0
└─/org/freedesktop/ModemManager1/SIM
└─/org/freedesktop/ModemManager1/SIM/0
Service /org/freedesktop/ModemManager1:
Failed to introspect object / of service /org/freedesktop/ModemManager1: Invali argument
No objects discovered.
The tree looks fine, the error message is a bit weird?
The only things I am interested in are the paths:
/org/freedesktop/ModemManager1/Modem/0
/org/freedesktop/ModemManager1/SIM/0
The above paths may change when the modem is replugged, so I'd like to query
them dynamically.
I learned that the call to list what I need is "GetManagedObjects":
busctl call org.freedesktop.ModemManager1 /org/freedesktop/ModemManager1 org.freedesktop.DBus.ObjectManager GetManagedObjects
It returns a data structure of the type a{oa{sa{sv}}} and the
object paths "/org/freedesktop/ModemManager1/Modem/0" and
"/org/freedesktop/ModemManager1/SIM/0" are indeed present in its
output.
However, when trying to parse the response in the code I only get as far as
reading the first /org/freedesktop/ModemManager1/Modem/0 but I never get
to the second /org/freedesktop/ModemManager1/SIM/0 entry.
What I am doing is (full and compilable source is attached, here I am leaving
out the error checks etc):
while (sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{oa{sa{sv}}}") > 0)
{
while (sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
"oa{sa{sv}}") > 0)
{
const char *path;
sd_bus_message_read_basic(m, SD_BUS_TYPE_OBJECT_PATH, &path);
fprintf(stderr, "Object path: %s\n", path);
sd_bus_message_skip(m, "a{sa{sv}}");
/* exit dictionary entry */
sd_bus_message_exit_container(m);
} // while SD_BUS_TYPE_DICT_ENTRY
/* exit array */
sd_bus_message_exit_container(m);
} // while SD_BUS_TYPE_ARRAY
I do not get any errors in the "real" version (attached), but it never
gets further to the SIM entry. What am I missing?
Kind regards,
Jin
-------------- next part --------------
/* compile: gcc `pkg-config --cflags --libs libsystemd` listpaths.c -o listpaths
Looking for:
/org/freedesktop/ModemManager1/Modem/0
/org/freedesktop/ModemManager1/SIM/0
$ busctl tree org.freedesktop.ModemManager1 /org/freedesktop/ModemManager1
Service org.freedesktop.ModemManager1:
└─/org
└─/org/freedesktop
└─/org/freedesktop/ModemManager1
├─/org/freedesktop/ModemManager1/Modem
│ └─/org/freedesktop/ModemManager1/Modem/0
└─/org/freedesktop/ModemManager1/SIM
└─/org/freedesktop/ModemManager1/SIM/0
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <systemd/sd-bus.h>
int main()
{
sd_bus *bus = NULL;
if (sd_bus_open_system(&bus) < 0)
{
return 1;
}
while (sd_bus_is_ready(bus) <= 0)
{
sd_bus_wait(bus, 1000);
sd_bus_process(bus, NULL);
}
printf("Bus ready.\n");
sd_bus_message *m = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
int ret = sd_bus_call_method(bus, "org.freedesktop.ModemManager1",
"/org/freedesktop/ModemManager1",
"org.freedesktop.DBus.ObjectManager",
"GetManagedObjects", &error, &m, NULL);
if (ret < 0)
{
printf("Could not get object list\n");
return ret;
}
while (sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
"{oa{sa{sv}}}") > 0)
{
while (sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
"oa{sa{sv}}") > 0)
{
const char *path;
if (sd_bus_message_read_basic(m, SD_BUS_TYPE_OBJECT_PATH, &path) <
0)
{
printf("Could not read object path\n");
goto finish;
}
fprintf(stderr, "Object path: %s\n", path);
if (sd_bus_message_skip(m, "a{sa{sv}}") < 0)
{
printf("Could not skip message\n");
goto finish;
}
/* exit dictionary entry */
if (sd_bus_message_exit_container(m) < 0)
{
printf("Could not exit container (inner loop)\n");
goto finish;
}
} // while SD_BUS_TYPE_DICT_ENTRY
/* exit array */
if (sd_bus_message_exit_container(m) < 0)
{
printf("Could not exit container (outer loop)\n");
goto finish;
}
} // while SD_BUS_TYPE_ARRAY
finish:
sd_bus_error_free(&error);
sd_bus_message_unref(m);
sd_bus_unref(bus);
return 0;
}
More information about the systemd-devel
mailing list