SD_BUS_MESSAGE_READ(3)

okay bestie, you're looking at SD_BUS_MESSAGE_READ(3) and it's literally the page where you learn how to pull a whole lil sequence of values out of a D-Bus message without losing the plot πŸ’…βœ¨

🌸 NAME 🌸

sd_bus_message_read, sd_bus_message_readv, sd_bus_message_peek_type β€” read a sequence of values from a message, no cap 🫢

πŸ¦‹ SYNOPSIS πŸ¦‹

#include <systemd/sd-bus.h>

int sd_bus_message_read(sd_bus_message *m, const char *types, ...);

int sd_bus_message_readv(sd_bus_message *m, const char *types,
                         va_list ap);

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

πŸ’– DESCRIPTION πŸ’–

okay so sd_bus_message_read() reads a sequence of fields from the D-Bus message object m, and yes bestie, it advances the read position in the message. The type string types describes the types of items expected in the message and the field arguments that follow it. The type string may be NULL or empty, and in that case literally nothing gets read 🫠

The type string is composed of the elements described in sd_bus_message_append(3) β€” so that's basic types and container types, iykyk 🌈 It must contain zero or more single "complete types". The type string is NUL-terminated, periodt.

For each type specified in the type string, one or more arguments need to be specified after the types parameter, in the same order. The arguments must be pointers to appropriate types β€” a pointer to int8_t for a "y" in the type string, a pointer to int32_t for an "i", a pointer to const char* for an "s", and so on β€” and those get set based on the values in the message ✨

As an exception, in case of array and variant types, the first argument is an "input" argument that further specifies how the message should be read. Peep the table below for a complete list of allowed arguments and their types πŸ‘€

bestie, this next bit is important: if the basic type is a pointer (e.g., const char * in the case of a string), the argument is a pointer to a pointer, and also the pointer value that is written is only borrowed β€” the contents must be copied if they are to be used after the end of the message's lifetime. no cap, do not just keep that pointer chilling past the message's whole existence 😭
and if the type is "h" (UNIX file descriptor), the descriptor is not duplicated by this call, and the returned descriptor remains in possession of the message object. The caller needs to duplicate it in order to keep an open reference to it after the message object is freed πŸ’€

Each argument may also be NULL, in which case the value is read and ignored πŸ™ˆ

πŸŽ€ Table 1. Item type specifiers πŸŽ€

okay bestie, this is the cheat sheet you're gonna bookmark. every specifier string, the constant it maps to, what it means, and exactly what type your pointer argument has to be. no cap, the pointer types are the part people get wrong. πŸ’…

  • "y" β€” SD_BUS_TYPE_BYTE β€” an 8-bit unsigned integer. first arg type: uint8_t *.
  • "b" β€” SD_BUS_TYPE_BOOLEAN β€” a boolean. first arg type: int * (NB: not bool * 🫠 like pls do not).
  • "n" β€” SD_BUS_TYPE_INT16 β€” a 16-bit signed integer. first arg type: int16_t *.
  • "q" β€” SD_BUS_TYPE_UINT16 β€” a 16-bit unsigned integer. first arg type: uint16_t *.
  • "i" β€” SD_BUS_TYPE_INT32 β€” a 32-bit signed integer. first arg type: int32_t *.
  • "u" β€” SD_BUS_TYPE_UINT32 β€” a 32-bit unsigned integer. first arg type: uint32_t *.
  • "x" β€” SD_BUS_TYPE_INT64 β€” a 64-bit signed integer. first arg type: int64_t *.
  • "t" β€” SD_BUS_TYPE_UINT64 β€” a 64-bit unsigned integer. first arg type: uint64_t *.
  • "d" β€” SD_BUS_TYPE_DOUBLE β€” an IEEE 754 double precision floating-point. first arg type: double *.
  • "s" β€” SD_BUS_TYPE_STRING β€” a UTF-8 string. first arg type: const char **.
  • "o" β€” SD_BUS_TYPE_OBJECT_PATH β€” a D-Bus object path string. first arg type: const char **.
  • "g" β€” SD_BUS_TYPE_SIGNATURE β€” a D-Bus signature string. first arg type: const char **.
  • "h" β€” SD_BUS_TYPE_UNIX_FD β€” a UNIX file descriptor. first arg type: int *.
  • "a" β€” SD_BUS_TYPE_ARRAY β€” an array. first arg type: int, which specifies the expected length n of the array. after that come n sets of arguments appropriate for the array element type πŸ¦‹
  • "v" β€” SD_BUS_TYPE_VARIANT β€” a variant. first arg type: a signature string. after that come arguments appropriate for the types specified by the signature ✨
  • "(" β€” SD_BUS_TYPE_STRUCT_BEGIN β€” described as array start. the arguments are those appropriate for the structure elements.
  • ")" β€” SD_BUS_TYPE_STRUCT_END β€” described as array end. the arguments are those appropriate for the structure elements.
  • "{" β€” SD_BUS_TYPE_DICT_ENTRY_BEGIN β€” dictionary entry start. first arg: arguments appropriate for the first type in the pair. second: arguments appropriate for the second type in the pair πŸ“
  • "}" β€” SD_BUS_TYPE_DICT_ENTRY_END β€” dictionary entry end. first arg: arguments appropriate for the first type in the pair. second: arguments appropriate for the second type in the pair πŸ“
heads up bestie: if objects of the specified types are not present at the current position in the message, an error is returned. like, that's it, that's the vibe check, and you failed it 😭

okay so sd_bus_message_readv() is literally equivalent to sd_bus_message_read(), except it's called with a va_list instead of a variable number of arguments. And bestie, important caveat: this function does not call the va_end() macro. Because it invokes the va_arg() macro, the value of ap is undefined after the call. no cap, that's just the rule. πŸ’…

sd_bus_message_peek_type() determines the type of the next element in m to be read by sd_bus_message_read() or similar functions. On success, the type is stored in type, if it is not NULL. If the type is a container type, the type of its elements is stored in contents, if it is not NULL. If this function successfully determines the type of the next element in m, it returns a positive integer. If there are no more elements to be read, it returns zero. peek type, peek slay ✨


πŸ’– RETURN VALUE πŸ’–

On success, these functions return a non-negative integer. On failure, they return a negative errno-style error code. that's the vibe check, fr fr πŸ’…

😭 Errors 😭

Returned errors may indicate the following problems, bestie:

  • -EINVAL β€” specified type string is invalid, or the message parameter is NULL. 🫠
  • -ENXIO β€” the message does not contain the specified type at the current position. ngl, awkward.
  • -EBADMSG β€” the message cannot be parsed. yikes πŸ’€
  • -EBUSY β€” when reading from a container, this error will be returned if unread elements are left in the container.

Added in version 251.


🧚 NOTES 🧚

Functions described here are available as a shared library, which can be compiled against and linked to with the libsystemd pkg-config(1) file. iconic build behavior ✨

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. Multiple independent objects may be used from different threads in parallel. so like, share the object, don't fight over it πŸ’…

The code described here uses getenv(3), which is declared to be not multi-thread-safe. This means that the code calling the functions described here must not call setenv(3) from a parallel thread. It is recommended to only do calls to setenv() from an early phase of the program when no other threads have been started. do the setup early, bestie, before the group chat gets chaotic 🌸


πŸ”₯ EXAMPLES πŸ”₯

Read a single basic type (a 64-bit integer):

           sd_bus_message *m;
           int64_t x;

           sd_bus_message_read(m, "x", &x);

Read a boolean value:

           sd_bus_message *m;
           int x; /* Do not use C99 "bool" type here, it is typically smaller
                     in memory and would cause memory corruption */

           sd_bus_message_read(m, "b", &x);
bestie, that comment is not a joke: do not use C99 "bool" here, it is typically smaller in memory and would cause memory corruption. πŸ’€

Read all types of integers:

           uint8_t y;
           int16_t n;
           uint16_t q;
           int32_t i;
           uint32_t u;
           int64_t x;
           uint64_t t;
           double d;

           sd_bus_message_read(m, "ynqiuxtd", &y, &n, &q, &i, &u, &x, &t, &d);

Read a structure composed of a string and a D-Bus path:

           const char *s, *p;

           sd_bus_message_read(m, "(so)", &s, &p);

Read a variant, with the real type "gt" (signature, unsigned integer):

           const char *s;
           uint64_t *v;

           sd_bus_message_read(m, "v", "gt", &s, &v);

Read a dictionary containing three pairs of type {integer=>string}:

           int i, j, k;
           const char *s, *t, *u;

           sd_bus_message_read(m, "a{is}", 3, &i, &s, &j, &t, &k, &u);

Read a single file descriptor, and duplicate it in order to keep it open after the message is freed.

           sd_bus_message *m;
           int fd, fd_copy;

           sd_bus_message_read(m, "h", &fd);
           fd_copy = fcntl(fd, FD_DUPFD_CLOEXEC, 3);

πŸ¦‹ HISTORY πŸ¦‹

sd_bus_message_read() and sd_bus_message_readv() were added in version 240. πŸ‘‘

sd_bus_message_peek_type() was added in version 246. ✨


πŸ‘‘ SEE ALSO πŸ‘‘


okay bye bestie! source/version: systemd 261.3; page: SD_BUS_MESSAGE_READ(3); date: whenever you're reading this in your terminal πŸŒΈπŸ’– not copying the footer line, just giving it main character energy ✨

πŸ“¦ where this page comes from