SD_BUS_CALL_METHOD(3)

πŸ’… SD_BUS_CALL_METHOD(3) β€” the sd_bus_call_method family, explained

okay so bestie, welcome to the SD_BUS_CALL_METHOD(3) page ✨ this is the one manual page you need if you want to yell at a D-Bus method and get an answer back without hand-assembling a whole message like a Victorian orphan. it's giving "convenience function, but make it fashion" πŸŽ€


🌸 NAME 🌸

sd_bus_call_method, sd_bus_call_methodv, sd_bus_call_method_async, sd_bus_call_method_asyncv β€” these init a bus message object and fire off the corresponding D-Bus method call. like, both things, one function. we love a multitasker πŸ’…


✨ SYNOPSIS ✨

#include <systemd/sd-bus.h>

typedef int (*sd_bus_message_handler_t)(sd_bus_message *m,
                                        void *userdata,
                                        sd_bus_error *ret_error);

int sd_bus_call_method(sd_bus *bus, const char *destination,
                       const char *path, const char *interface,
                       const char *member, sd_bus_error *ret_error,
                       sd_bus_message **reply, const char *types, ...);

int sd_bus_call_methodv(sd_bus *bus, const char *destination,
                        const char *path, const char *interface,
                        const char *member, sd_bus_error *ret_error,
                        sd_bus_message **reply, const char *types,
                        va_list ap);

int sd_bus_call_method_async(sd_bus *bus, sd_bus_slot **slot,
                             const char *destination, const char *path,
                             const char *interface, const char *member,
                             sd_bus_message_handler_t callback,
                             void *userdata, const char *types, ...);

int sd_bus_call_method_asyncv(sd_bus *bus, sd_bus_slot **slot,
                              const char *destination, const char *path,
                              const char *interface, const char *member,
                              sd_bus_message_handler_t callback,
                              void *userdata, const char *types,
                              va_list ap);

πŸ¦‹ DESCRIPTION πŸ¦‹

sd_bus_call_method() is the convenience queen πŸ‘‘ she inits a bus message object and calls the corresponding D-Bus method, all in one go. basically she's three functions in a trench coat: sd_bus_message_new_method_call(3), sd_bus_message_append(3) and sd_bus_call(3), all smooshed into a single function call. iconic. no notes. 🫢

sd_bus_call_method_async() is her chill sibling πŸ’œ same energy, but the call goes out asynchronously. she combines sd_bus_message_new_method_call(3), sd_bus_message_append(3) and sd_bus_call_async(3) into one function call, so you don't have to block and wait like it's 2011. main character energy fr πŸ”₯


⭐ RETURN VALUE ⭐

when it works? non-negative integer. slay πŸ’– when it doesn't? a negative errno-style error code. sad but honest 😭

πŸ™ˆ Errors

for the full list of possible errors, go read the man pages for sd_bus_message_new_method_call(3), sd_bus_message_append(3), sd_bus_call(3) and sd_bus_call_async(3). they have the receipts πŸ“œ


🌈 NOTES 🌈

  • these functions are available as a shared library, which you can compile against and link to using the libsystemd pkg-config(1) file. yes, libsystemd. use it, love it. πŸŽ€
  • all functions listed here are thread-agnostic, and only a single thread may operate on a given object at any given time. different threads can hit the same object at different times, and multiple independent objects can absolutely be used from different threads in parallel. so like... share the object, not the moment πŸ¦‹
  • the code described here uses getenv(3), which is literally declared not multi-thread-safe. that means if you're calling these functions, you must not call setenv(3) from a parallel thread. bestie please, only call setenv() in an early phase of the program, before any other threads have been started. i'm begging πŸ™

πŸ’œ EXAMPLES πŸ’œ

✨ Example 1. Make a call to a D-Bus method that takes a single parameter ✨

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

/* This is equivalent to:
 * busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 \
 *       org.freedesktop.systemd1.Manager GetUnitByPID $$
 *
 * Compile with 'cc print-unit-path-call-method.c -lsystemd'
 */

#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#include <systemd/sd-bus.h>

#define _cleanup_(f) __attribute__((cleanup(f)))
#define DESTINATION "org.freedesktop.systemd1"
#define PATH        "/org/freedesktop/systemd1"
#define INTERFACE   "org.freedesktop.systemd1.Manager"
#define MEMBER      "GetUnitByPID"

static int log_error(int error, const char *message) {
  fprintf(stderr, "%s: %s\n", message, strerror(-error));
  return error;
}

int main(int argc, char **argv) {
  _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
  _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
  _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
  int r;

  r = sd_bus_open_system(&bus);
  if (r < 0)
    return log_error(r, "Failed to acquire bus");

  r = sd_bus_call_method(bus, DESTINATION, PATH, INTERFACE, MEMBER, &error, &reply, "u", (unsigned) getpid());
  if (r < 0)
    return log_error(r, MEMBER " call failed");

  const char *ans;
  r = sd_bus_message_read(reply, "o", &ans);
  if (r < 0)
    return log_error(r, "Failed to read reply");

  printf("Unit path is \"%s\".\n", ans);

  return 0;
}

so what does this do? it defines a minimally useful program that opens a connection to the bus, calls a method, waits for the reply, and finally extracts and prints the answer. and it does actual error handling and proper memory management, so you can look your compiler in the eye πŸ˜ŒπŸ’…


🌸 HISTORY 🌸

  • sd_bus_call_method() and sd_bus_call_method_async() were added in version 221.
  • sd_bus_call_methodv() and sd_bus_call_method_asyncv() were added in version 246.

(the glow-up was real and it happened in stages πŸ¦‹)


πŸ‘‘ SEE ALSO πŸ‘‘

systemd(1), sd-bus(3), sd_bus_message_new_method_call(3), sd_bus_message_append(3), sd_bus_call(3), sd_bus_set_property(3), sd_bus_emit_signal(3)


that's the whole page, bestie, you ate it up fr fr πŸ’– this absolute banger of a manual page ships with systemd 261.3 β€” go forth, call your methods, handle your errnos, and remember: one thread per object at a time, or it's giving undefined chaos πŸ’€βœ¨

πŸ“¦ where this page comes from