SD_BUS_M...CONTAINER(3)

πŸ’… NAME πŸ’…

okay so bestie, gather round β€” this is the SD_BUS_M...CONTAINER(3) page, and it's all about sd_bus_message_open_container, sd_bus_message_close_container, sd_bus_message_enter_container, and sd_bus_message_exit_container β€” the four functions that let you create containers inside D-Bus messages and hop around between them. like little nesting dolls but make it IPC ✨


πŸŽ€ SYNOPSIS πŸŽ€

#include <systemd/sd-bus.h>

int sd_bus_message_open_container(sd_bus_message *m, char type,
                                  const char *contents);

int sd_bus_message_close_container(sd_bus_message *m);

int sd_bus_message_enter_container(sd_bus_message *m, char type,
                                   const char *contents);

int sd_bus_message_exit_container(sd_bus_message *m);

πŸ¦‹ DESCRIPTION πŸ¦‹

sd_bus_message_open_container() literally just appends a brand-new container onto the message m. and once you've opened it? you fill it up with content using sd_bus_message_append(3) and its bestie functions, iykyk.

containers behave like a stack β€” very main character, very LIFO. to nest containers inside each other, you just call sd_bus_message_open_container() multiple times without calling sd_bus_message_close_container() in between. each new container gets nested inside the one before it. adorable. πŸͺ†

type is the container type β€” it should be one of "r", "a", "v" or "e", exactly as described in sd_bus_message_append(3). and no, you don't have to use the literals: the corresponding constants SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT or SD_BUS_TYPE_DICT_ENTRY work too. pick your fighter πŸ’…

contents describes the type of the container's elements β€” a D-Bus type string following the rules laid out in sd_bus_message_append(3).

sd_bus_message_close_container() closes the last container you opened with sd_bus_message_open_container(). on success, the write pointer of the message m ends up positioned right after the closed container β€” either in its parent container, or in m itself if there's no parent container. slay.

sd_bus_message_enter_container() enters the next container of the message m, but for reading. it behaves mostly the same as sd_bus_message_open_container(). entering a container is what lets you read its contents with sd_bus_message_read(3) and similar functions. type and contents work exactly like they do in sd_bus_message_open_container().

sd_bus_message_exit_container() exits the scope of the last container you entered with sd_bus_message_enter_container(), and behaves mostly the same as sd_bus_message_close_container().

⚠️ real talk: sd_bus_message_exit_container() may only be called after you've iterated through all the members of the container β€” like, actually reading or skipping over them. if you wanna bounce out early without reading every single member, use sd_bus_message_skip(3) to skip over fields of a container, and then you can exit with sd_bus_message_exit_container(). no skipping the required steps, bestie 😭

🌸 RETURN VALUE 🌸

on success, all of these return a non-negative integer. here's the receipts:

  • sd_bus_message_open_container() and sd_bus_message_close_container() return 0.
  • sd_bus_message_enter_container() returns 1 if it successfully opened a new container, and 0 if that wasn't possible because it hit the end of the currently open container or message.
  • sd_bus_message_exit_container() returns 1 on success.

on failure, all of these return a negative errno-style error code. 😀

πŸ’€ Errors πŸ’€

the errors you might get back mean the following:

  • -EINVAL β€” m or contents are NULL, or type is invalid.

Added in version 246.

  • -EBADMSG β€” message m has invalid structure.

Added in version 254.

  • -ENXIO β€” message m doesn't have a container of type type at the current position, or the contents don't match contents.

Added in version 254.

  • -EPERM β€” the message m is already sealed. πŸ”’

Added in version 246.

  • -ESTALE β€” the message m is in an invalid state.

Added in version 246.

  • -ENOMEM β€” memory allocation failed. it happens to the best of us 🫢

Added in version 246.

  • -EBUSY β€” sd_bus_message_exit_container() was called but there are still unread members left in the container. not you trying to leave before the party's over πŸ’€

Added in version 247.


⭐ NOTES ⭐

the functions described here are available as a shared library, which you can compile against and link to with the libsystemd pkg-config(1) file. standard.

all functions listed here are thread-agnostic, and only a single thread may operate on a given object at any given time. different threads may access the same object at different times, and multiple independent objects can be used from different threads in parallel. so like… share the object, not the moment. periodt.

the code described here uses getenv(3), which is declared to be not multi-thread-safe. what that means for you: code calling the functions described here must not call setenv(3) from a parallel thread. the recommendation is to only do calls to setenv() from an early phase of the program, back when no other threads have been started. do it before the group chat gets loud. 🧚


πŸ”₯ EXAMPLES πŸ”₯

Example 1. Append an array of strings to a message

/* SPDX-License-Identifier: MIT-0 */

#include <systemd/sd-bus.h>

int append_strings_to_message(sd_bus_message *m, const char *const *arr) {
  const char *s;
  int r;

  r = sd_bus_message_open_container(m, 'a', "s");
  if (r < 0)
    return r;

  for (s = *arr; *s; s++) {
    r = sd_bus_message_append(m, "s", s);
    if (r < 0)
      return r;
  }

  return sd_bus_message_close_container(m);
}

Example 2. Read an array of strings from a message

/* SPDX-License-Identifier: MIT-0 */

#include <stdio.h>

#include <systemd/sd-bus.h>

int read_strings_from_message(sd_bus_message *m) {
  int r;

  r = sd_bus_message_enter_container(m, 'a', "s");
  if (r < 0)
    return r;

  for (;;) {
    const char *s;

    r = sd_bus_message_read(m, "s", &s);
    if (r < 0)
      return r;
    if (r == 0)
      break;

    printf("%s\n", s);
  }

  return sd_bus_message_exit_container(m);
}

🌈 SEE ALSO 🌈

systemd(1), sd-bus(3), sd_bus_message_append(3), sd_bus_message_read(3), sd_bus_message_skip(3), The D-Bus specification[1]


πŸ“Ž NOTES πŸ“Ž

  1. The D-Bus specification https://dbus.freedesktop.org/doc/dbus-specification.html

and that's the whole page, bestie β€” you ate that πŸ’… this one's from systemd 261.3, dated alongside the SD_BUS_M...CONTAINER(3) footer, so go forth and nest your containers responsibly. mwah πŸ«ΆπŸ’–

πŸ“¦ where this page comes from