[systemd-devel] libsystemd/sd_bus: trouble understanding how to parse complex responses
Lennart Poettering
lennart at poettering.net
Wed Sep 9 16:31:26 UTC 2020
On Di, 08.09.20 20:51, Sergey 'Jin' Bostandzhyan (jin at mediatomb.cc) wrote:
> >
> > https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
>
> Oh, so you mean that when I use "busctl call" it would detect and fake a
> GetManagedObjects() method invocation and internally use XML
> introspection?
No. I meant that "busctl introspect" and "busctl tree" use the XML
data, and not GetManagedObjects(). If you invoke "busctl call" then
you get what you ask for, we do no magic redirect.
> Is it somehow possible to figure this out via command line tools if the
> problem is in the missing GetManagedObjects() implementation or not?
Well, the introspection data should advertise GetManagedObjects()
method if it's supported.
>
> > > while (sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{oa{sa{sv}}}") > 0)
> > > {
> >
> > Hmm, this is what you'd write when you have an array of arrays...
>
> Uhm, how do I correctly "enter" a container like this one:
> "a{oa{sa{sv}}}" ?
Using sd_bus_message_enter_container() as you do, but you#d not call
it in a loop like you do, as that only makes sense if the actual type
string is "aa{oa{sa{sv}}}", i.e. starts with an array of arrays.
> I guess this is correct, what GetManagedObjects() returns is an array of
> dictionaries "a{oa{sa{sv}}}" or am I misinterpreting it?
Well, the way dbus encodes dictionaries is as "array of dictionary
entries. That's what the "a{…}" means.
> sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "oa{sa{sv}}")
> returns 1 on the first call, thats where I get the first path that
> equals to "/org/freedesktop/ModemManager1/Modem/0" and it returns 0 on the
> next invocation.
It returns 0 if you reached the end of the surrounding container, i.e. the
end of the structure or array.
> > Normally, you#d enter the array once and then iterate through the
> > dict entries contained therein. i.e. unless there's an "aa" object
> > somewhere (i.e. "array of array") you'd do the while loop around the
> > dict entries, not the array object.
>
> Could you please clarify how iteration works in sd_bus sense? Is my
> understanding correct that I need to use sd_bus_message_skip() before
> exiting the container in order to iterate to the next item, if I am not
> interested in parsing all of the nested items? Or can I just "exit" at any
> time and expect the next "enter" invocation to fast forward to the
> next entry?
You are supposed to be at the end of the structure/array when calling
sd_bus_message_exit_container(). Otherwise you'll get EBUSY. We should
probably document that in the man page.
> Based on what you are saying the inner while loop that I had right after
> entering the array should have returned all items. So I start by entering
> the array:
>
> // starting with a{oa{sa{sv}}}
> sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{oa{sa{sv}}}")
>
> And loop over dictionary key-value pairs:
>
> // brings me down into oa{sa{sv}}}, I am only interested in the object paths:
> while (sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "oa{sa{sv}}") > 0) {
> sd_bus_message_read_basic(m, SD_BUS_TYPE_OBJECT_PATH, &path);
> sd_bus_message_skip(m, "a{sa{sv}}");
> sd_bus_message_exit_container(m);
> }
>
> Does the above look correct? As mentioned, I am not getting errors, return
> codes are fine, so it all looks normal, but I am only reading out
> the first path, on the second iteration
> sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
> "oa{sa{sv}}") returns 0 which aborts the loop.
This does look correct to me.
> At this point I am not sure if sd_bus actually behaves correctly and
> GetManagedObjects() returns only one path or if I messed up the parsing of
> the reply somehow? And I am not sure how to check that...
>
> I would like to avoid parsing XML if I can, but of course that option is
> still there; nevertheless, I would first like to understand what is going on
> with the GetManagedObjects() call and if the problem is really there or
> somewhere else.
Consider using "busctl monitor" to see what the message your client
receives actually contains.
Lennart
--
Lennart Poettering, Berlin
More information about the systemd-devel
mailing list