chiark / gitweb /
sd-bus: use IN_SET
[elogind.git] / src / libelogind / sd-bus / sd-bus.c
index d2a96f87b0fdc43a0d63c96245f57a68a2874724..6d304719e61f55d82467123aac2e5805d8b14693 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
 ***/
 
 #include <endian.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include <netdb.h>
 #include <poll.h>
-#include <sys/mman.h>
 #include <pthread.h>
-
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-#include "missing.h"
-#include "def.h"
-#include "cgroup-util.h"
-#include "bus-label.h"
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-container.h"
+#include "bus-control.h"
 #include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-type.h"
-#include "bus-socket.h"
 #include "bus-kernel.h"
-#include "bus-control.h"
+#include "bus-label.h"
+#include "bus-message.h"
 #include "bus-objects.h"
-#include "bus-util.h"
-#include "bus-container.h"
 #include "bus-protocol.h"
-#include "bus-track.h"
 #include "bus-slot.h"
+#include "bus-socket.h"
+#include "bus-track.h"
+#include "bus-type.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "hexdecoct.h"
+#include "hostname-util.h"
+#include "macro.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 #define log_debug_bus_message(m)                                         \
         do {                                                             \
@@ -68,6 +72,12 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
 static int attach_io_events(sd_bus *b);
 static void detach_io_events(sd_bus *b);
 
+static thread_local sd_bus *default_system_bus = NULL;
+#if 0 /// UNNEEDED by elogind
+static thread_local sd_bus *default_user_bus = NULL;
+#endif // 0
+static thread_local sd_bus *default_starter_bus = NULL;
+
 static void bus_close_fds(sd_bus *b) {
         assert(b);
 
@@ -214,8 +224,8 @@ _public_ int sd_bus_set_address(sd_bus *bus, const char *address) {
 _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
         assert_return(bus, -EINVAL);
         assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(input_fd >= 0, -EINVAL);
-        assert_return(output_fd >= 0, -EINVAL);
+        assert_return(input_fd >= 0, -EBADF);
+        assert_return(output_fd >= 0, -EBADF);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         bus->input_fd = input_fd;
@@ -223,8 +233,7 @@ _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
         return 0;
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
         char *p, **a;
 
@@ -298,7 +307,6 @@ _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
 
         return 0;
 }
-#endif // 0
 
 _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
         uint64_t new_flags;
@@ -308,10 +316,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
         assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
-        if (b)
-                bus->creds_mask |= mask;
-        else
-                bus->creds_mask &= ~mask;
+        SET_FLAG(bus->creds_mask, mask, b);
 
         /* The well knowns we need unconditionally, so that matches can work */
         bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
@@ -339,8 +344,6 @@ _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
         return 0;
 }
 
-/// UNNEEDED by elogind
-#if 0
 _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) {
         assert_return(bus, -EINVAL);
         assert_return(bus->state == BUS_UNSET, -EPERM);
@@ -376,8 +379,7 @@ _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) {
         return 0;
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) {
         assert_return(bus, -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -418,7 +420,7 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e
 }
 
 static int bus_send_hello(sd_bus *bus) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         int r;
 
         assert(bus);
@@ -531,7 +533,7 @@ static void skip_address_key(const char **p) {
         *p += strcspn(*p, ",");
 
         if (**p == ',')
-                (*p) ++;
+                (*p)++;
 }
 
 static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
@@ -696,7 +698,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
                                 goto fail;
                         }
 
-                        (*p) ++;
+                        (*p)++;
 
                         if (ul >= n_argv) {
                                 if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) {
@@ -828,8 +830,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
                 b->machine = machine;
                 machine = NULL;
         } else {
-                free(b->machine);
-                b->machine = NULL;
+                b->machine = mfree(b->machine);
         }
 
         if (pid) {
@@ -888,8 +889,7 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid
                 b->machine = machine;
                 machine = NULL;
         } else {
-                free(b->machine);
-                b->machine = NULL;
+                b->machine = mfree(b->machine);
         }
 
         if (pid) {
@@ -899,10 +899,9 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid
         } else
                 b->nspid = 0;
 
-        free(b->kernel);
-        b->kernel = strdup("/sys/fs/kdbus/0-system/bus");
-        if (!b->kernel)
-                return -ENOMEM;
+        r = free_and_strdup(&b->kernel, "/sys/fs/kdbus/0-system/bus");
+        if (r < 0)
+                return r;
 
         return 0;
 }
@@ -1011,6 +1010,8 @@ static int bus_parse_next_address(sd_bus *b) {
 }
 
 static int bus_start_address(sd_bus *b) {
+        bool container_kdbus_available = false;
+        bool kdbus_available = false;
         int r;
 
         assert(b);
@@ -1020,19 +1021,40 @@ static int bus_start_address(sd_bus *b) {
 
                 bus_close_fds(b);
 
+                /*
+                 * Usually, if you provide multiple different bus-addresses, we
+                 * try all of them in order. We use the first one that
+                 * succeeds. However, if you mix kernel and unix addresses, we
+                 * never try unix-addresses if a previous kernel address was
+                 * tried and kdbus was available. This is required to prevent
+                 * clients to fallback to the bus-proxy if kdbus is available
+                 * but failed (eg., too many connections).
+                 */
+
                 if (b->exec_path)
                         r = bus_socket_exec(b);
-#if 0
-               else if ((b->nspid > 0 || b->machine) && b->kernel)
+                else if ((b->nspid > 0 || b->machine) && b->kernel) {
                         r = bus_container_connect_kernel(b);
-                else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC)
-                        r = bus_container_connect_socket(b);
-#endif // 0
-                else if (b->kernel)
+                        if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT))
+                                container_kdbus_available = true;
+
+                } else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) {
+                        if (!container_kdbus_available)
+                                r = bus_container_connect_socket(b);
+                        else
+                                skipped = true;
+
+                } else if (b->kernel) {
                         r = bus_kernel_connect(b);
-                else if (b->sockaddr.sa.sa_family != AF_UNSPEC)
-                        r = bus_socket_connect(b);
-                else
+                        if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT))
+                                kdbus_available = true;
+
+                } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
+                        if (!kdbus_available)
+                                r = bus_socket_connect(b);
+                        else
+                                skipped = true;
+                } else
                         skipped = true;
 
                 if (!skipped) {
@@ -1137,12 +1159,19 @@ _public_ int sd_bus_open(sd_bus **ret) {
         if (e) {
                 if (streq(e, "system"))
                         return sd_bus_open_system(ret);
+#if 0 /// elogind does not support systemd units
                 else if (STR_IN_SET(e, "session", "user"))
                         return sd_bus_open_user(ret);
+#endif // 0
         }
 
         e = secure_getenv("DBUS_STARTER_ADDRESS");
         if (!e) {
+#if 0 /// elogind does not support systemd units
+                if (cg_pid_get_owner_uid(0, NULL) >= 0)
+                        return sd_bus_open_user(ret);
+                else
+#endif // 0
                 return sd_bus_open_system(ret);
         }
 
@@ -1220,8 +1249,11 @@ fail:
         return r;
 }
 
+#if 0 /// elogind can not open/use a user bus
 int bus_set_address_user(sd_bus *b) {
         const char *e;
+        uid_t uid;
+        int r;
 
         assert(b);
 
@@ -1229,6 +1261,10 @@ int bus_set_address_user(sd_bus *b) {
         if (e)
                 return sd_bus_set_address(b, e);
 
+        r = cg_pid_get_owner_uid(0, &uid);
+        if (r < 0)
+                uid = getuid();
+
         e = secure_getenv("XDG_RUNTIME_DIR");
         if (e) {
                 _cleanup_free_ char *ee = NULL;
@@ -1237,17 +1273,19 @@ int bus_set_address_user(sd_bus *b) {
                 if (!ee)
                         return -ENOMEM;
 
-                (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee);
+                (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee);
         } else
-                (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid());
+                (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid);
 
         if (!b->address)
                 return -ENOMEM;
 
         return 0;
 }
+#endif // 0
 
 _public_ int sd_bus_open_user(sd_bus **ret) {
+#if 0 /// elogind does not support user buses
         sd_bus *b;
         int r;
 
@@ -1278,6 +1316,9 @@ _public_ int sd_bus_open_user(sd_bus **ret) {
 fail:
         bus_free(b);
         return r;
+#else
+        return sd_bus_open_system(ret);
+#endif // 0
 }
 
 int bus_set_address_system_remote(sd_bus *b, const char *host) {
@@ -1450,7 +1491,9 @@ static void bus_enter_closing(sd_bus *bus) {
 }
 
 _public_ sd_bus *sd_bus_ref(sd_bus *bus) {
-        assert_return(bus, NULL);
+
+        if (!bus)
+                return NULL;
 
         assert_se(REFCNT_INC(bus->n_ref) >= 2);
 
@@ -1471,8 +1514,7 @@ _public_ sd_bus *sd_bus_unref(sd_bus *bus) {
         return NULL;
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_is_open(sd_bus *bus) {
 
         assert_return(bus, -EINVAL);
@@ -1506,8 +1548,7 @@ _public_ int sd_bus_can_send(sd_bus *bus, char type) {
         return bus_type_is_valid(type);
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
         int r;
 
@@ -1644,7 +1685,7 @@ static int dispatch_wqueue(sd_bus *bus) {
                          * it got full, then all bets are off
                          * anyway. */
 
-                        bus->wqueue_size --;
+                        bus->wqueue_size--;
                         sd_bus_message_unref(bus->wqueue[0]);
                         memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
                         bus->windex = 0;
@@ -1693,7 +1734,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
                         /* Dispatch a queued message */
 
                         *m = bus->rqueue[0];
-                        bus->rqueue_size --;
+                        bus->rqueue_size--;
                         memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
                         return 1;
                 }
@@ -1710,7 +1751,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
 }
 
 static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bool hint_sync_call) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
         int r;
 
         assert_return(m, -EINVAL);
@@ -1757,7 +1798,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
 
                 r = bus_write_message(bus, m, hint_sync_call, &idx);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
@@ -1785,7 +1826,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
                 if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
                         return -ENOMEM;
 
-                bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m);
+                bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m);
         }
 
 finish:
@@ -1799,6 +1840,7 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) {
         return bus_send_internal(bus, m, cookie, false);
 }
 
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
         int r;
 
@@ -1824,6 +1866,7 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat
 
         return sd_bus_send(bus, m, cookie);
 }
+#endif // 0
 
 static usec_t calc_elapse(uint64_t usec) {
         if (usec == (uint64_t) -1)
@@ -1858,8 +1901,8 @@ _public_ int sd_bus_call_async(
                 void *userdata,
                 uint64_t usec) {
 
-        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
-        _cleanup_bus_slot_unref_ sd_bus_slot *s = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
+        _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *s = NULL;
         int r;
 
         assert_return(m, -EINVAL);
@@ -1957,43 +2000,45 @@ _public_ int sd_bus_call(
                 sd_bus_error *error,
                 sd_bus_message **reply) {
 
-        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
         usec_t timeout;
         uint64_t cookie;
         unsigned i;
         int r;
 
-        assert_return(m, -EINVAL);
-        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
-        assert_return(!bus_error_is_dirty(error), -EINVAL);
+        bus_assert_return(m, -EINVAL, error);
+        bus_assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL, error);
+        bus_assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL, error);
+        bus_assert_return(!bus_error_is_dirty(error), -EINVAL, error);
 
         if (!bus)
                 bus = m->bus;
 
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
+        bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
+        bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error);
 
-        if (!BUS_IS_OPEN(bus->state))
-                return -ENOTCONN;
+        if (!BUS_IS_OPEN(bus->state)) {
+                r = -ENOTCONN;
+                goto fail;
+        }
 
         r = bus_ensure_running(bus);
         if (r < 0)
-                return r;
+                goto fail;
 
         i = bus->rqueue_size;
 
         r = bus_seal_message(bus, m, usec);
         if (r < 0)
-                return r;
+                goto fail;
 
         r = bus_remarshal_message(bus, &m);
         if (r < 0)
-                return r;
+                goto fail;
 
         r = bus_send_internal(bus, m, &cookie, true);
         if (r < 0)
-                return r;
+                goto fail;
 
         timeout = calc_elapse(m->timeout);
 
@@ -2024,14 +2069,17 @@ _public_ int sd_bus_call(
                                         }
 
                                         r = sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
+                                        sd_bus_message_unref(incoming);
+                                        return r;
 
-                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
+                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
                                         r = sd_bus_error_copy(error, &incoming->error);
-                                else
-                                        r = -EIO;
-
                                 sd_bus_message_unref(incoming);
                                 return r;
+                                } else {
+                                        r = -EIO;
+                                        goto fail;
+                                }
 
                         } else if (BUS_MESSAGE_COOKIE(incoming) == cookie &&
                                    bus->unique_name &&
@@ -2047,7 +2095,8 @@ _public_ int sd_bus_call(
                                  * immediately. */
 
                                 sd_bus_message_unref(incoming);
-                                return -ELOOP;
+                                r = -ELOOP;
+                                goto fail;
                         }
 
                         /* Try to read more, right-away */
@@ -2056,12 +2105,12 @@ _public_ int sd_bus_call(
 
                 r = bus_read_message(bus, false, 0);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
-                                return -ECONNRESET;
+                                r = -ECONNRESET;
                         }
 
-                        return r;
+                        goto fail;
                 }
                 if (r > 0)
                         continue;
@@ -2070,8 +2119,10 @@ _public_ int sd_bus_call(
                         usec_t n;
 
                         n = now(CLOCK_MONOTONIC);
-                        if (n >= timeout)
-                                return -ETIMEDOUT;
+                        if (n >= timeout) {
+                                r = -ETIMEDOUT;
+                                goto fail;
+                        }
 
                         left = timeout - n;
                 } else
@@ -2079,22 +2130,28 @@ _public_ int sd_bus_call(
 
                 r = bus_poll(bus, true, left);
                 if (r < 0)
-                        return r;
-                if (r == 0)
-                        return -ETIMEDOUT;
+                        goto fail;
+                if (r == 0) {
+                        r = -ETIMEDOUT;
+                        goto fail;
+                }
 
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
-                                return -ECONNRESET;
+                                r = -ECONNRESET;
                         }
 
-                        return r;
+                        goto fail;
                 }
         }
+
+fail:
+        return sd_bus_error_set_errno(error, r);
 }
 
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_get_fd(sd_bus *bus) {
 
         assert_return(bus, -EINVAL);
@@ -2103,6 +2160,7 @@ _public_ int sd_bus_get_fd(sd_bus *bus) {
 
         return bus->input_fd;
 }
+#endif // 0
 
 _public_ int sd_bus_get_events(sd_bus *bus) {
         int flags = 0;
@@ -2183,8 +2241,8 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
 }
 
 static int process_timeout(sd_bus *bus) {
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message* m = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message* m = NULL;
         struct reply_callback *c;
         sd_bus_slot *slot;
         usec_t n;
@@ -2220,7 +2278,7 @@ static int process_timeout(sd_bus *bus) {
 
         slot = container_of(c, sd_bus_slot, reply_callback);
 
-        bus->iteration_counter ++;
+        bus->iteration_counter++;
 
         bus->current_message = m;
         bus->current_slot = sd_bus_slot_ref(slot);
@@ -2265,8 +2323,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
 }
 
 static int process_reply(sd_bus *bus, sd_bus_message *m) {
-        _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *synthetic_reply = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
         struct reply_callback *c;
         sd_bus_slot *slot;
         int r;
@@ -2345,7 +2403,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
 }
 
 static int process_filter(sd_bus *bus, sd_bus_message *m) {
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
         struct filter_callback *l;
         int r;
 
@@ -2411,7 +2469,7 @@ static int process_match(sd_bus *bus, sd_bus_message *m) {
 }
 
 static int process_builtin(sd_bus *bus, sd_bus_message *m) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         int r;
 
         assert(bus);
@@ -2543,7 +2601,7 @@ static int dispatch_track(sd_bus *bus) {
 }
 
 static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         int r;
 
         assert(bus);
@@ -2607,7 +2665,7 @@ null_message:
 }
 
 static int process_closing(sd_bus *bus, sd_bus_message **ret) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         struct reply_callback *c;
         int r;
 
@@ -2616,7 +2674,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
 
         c = ordered_hashmap_first(bus->reply_callbacks);
         if (c) {
-                _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
                 sd_bus_slot *slot;
 
                 /* First, fail all outstanding method calls */
@@ -2732,7 +2790,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
 
         case BUS_OPENING:
                 r = bus_socket_process_opening(bus);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                         bus_enter_closing(bus);
                         r = 1;
                 } else if (r < 0)
@@ -2743,7 +2801,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
 
         case BUS_AUTHENTICATING:
                 r = bus_socket_process_authenticating(bus);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                         bus_enter_closing(bus);
                         r = 1;
                 } else if (r < 0)
@@ -2757,7 +2815,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
         case BUS_RUNNING:
         case BUS_HELLO:
                 r = process_running(bus, hint_priority, priority, ret);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                         bus_enter_closing(bus);
                         r = 1;
 
@@ -2778,8 +2836,7 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
         return bus_process_internal(bus, false, 0, ret);
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_message **ret) {
         return bus_process_internal(bus, true, priority, ret);
 }
@@ -2883,7 +2940,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         for (;;) {
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
@@ -2900,6 +2957,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         }
 }
 
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_add_filter(
                 sd_bus *bus,
                 sd_bus_slot **slot,
@@ -2926,6 +2984,7 @@ _public_ int sd_bus_add_filter(
 
         return 0;
 }
+#endif // 0
 
 _public_ int sd_bus_add_match(
                 sd_bus *bus,
@@ -3002,8 +3061,7 @@ finish:
         return r;
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 int bus_remove_match_by_string(
                 sd_bus *bus,
                 const char *match,
@@ -3280,8 +3338,7 @@ _public_ sd_bus_message* sd_bus_get_current_message(sd_bus *bus) {
         return bus->current_message;
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) {
         assert_return(bus, NULL);
 
@@ -3329,15 +3386,16 @@ static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus
 }
 
 _public_ int sd_bus_default_system(sd_bus **ret) {
-        static thread_local sd_bus *default_system_bus = NULL;
-
         return bus_default(sd_bus_open_system, &default_system_bus, ret);
 }
 
-_public_ int sd_bus_default_user(sd_bus **ret) {
-        static thread_local sd_bus *default_user_bus = NULL;
 
+_public_ int sd_bus_default_user(sd_bus **ret) {
+#if 0 /// elogind does not support user buses
         return bus_default(sd_bus_open_user, &default_user_bus, ret);
+#else
+        return sd_bus_default_system(ret);
+#endif // 0
 }
 
 _public_ int sd_bus_default(sd_bus **ret) {
@@ -3354,8 +3412,10 @@ _public_ int sd_bus_default(sd_bus **ret) {
         if (e) {
                 if (streq(e, "system"))
                         return sd_bus_default_system(ret);
+#if 0 /// elogind does not support systemd units
                 else if (STR_IN_SET(e, "user", "session"))
                         return sd_bus_default_user(ret);
+#endif // 0
         }
 
         /* No type is specified, so we have not other option than to
@@ -3363,7 +3423,6 @@ _public_ int sd_bus_default(sd_bus **ret) {
 
         e = secure_getenv("DBUS_STARTER_ADDRESS");
         if (e) {
-                static thread_local sd_bus *default_starter_bus = NULL;
 
                 return bus_default(sd_bus_open, &default_starter_bus, ret);
         }
@@ -3371,11 +3430,15 @@ _public_ int sd_bus_default(sd_bus **ret) {
         /* Finally, if nothing is set use the cached connection for
          * the right scope */
 
+#if 0 /// elogind does not support systemd units
+        if (cg_pid_get_owner_uid(0, NULL) >= 0)
+                return sd_bus_default_user(ret);
+        else
+#endif // 0
         return sd_bus_default_system(ret);
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) {
         assert_return(b, -EINVAL);
         assert_return(tid, -EINVAL);
@@ -3433,7 +3496,171 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext
         *external_id = ret;
         return 1;
 }
-#endif // 0
+
+_public_ int sd_bus_path_encode_many(char **out, const char *path_template, ...) {
+        _cleanup_strv_free_ char **labels = NULL;
+        char *path, *path_pos, **label_pos;
+        const char *sep, *template_pos;
+        size_t path_length;
+        va_list list;
+        int r;
+
+        assert_return(out, -EINVAL);
+        assert_return(path_template, -EINVAL);
+
+        path_length = strlen(path_template);
+
+        va_start(list, path_template);
+        for (sep = strchr(path_template, '%'); sep; sep = strchr(sep + 1, '%')) {
+                const char *arg;
+                char *label;
+
+                arg = va_arg(list, const char *);
+                if (!arg) {
+                        va_end(list);
+                        return -EINVAL;
+                }
+
+                label = bus_label_escape(arg);
+                if (!label) {
+                        va_end(list);
+                        return -ENOMEM;
+                }
+
+                r = strv_consume(&labels, label);
+                if (r < 0) {
+                        va_end(list);
+                        return r;
+                }
+
+                /* add label length, but account for the format character */
+                path_length += strlen(label) - 1;
+        }
+        va_end(list);
+
+        path = malloc(path_length + 1);
+        if (!path)
+                return -ENOMEM;
+
+        path_pos = path;
+        label_pos = labels;
+
+        for (template_pos = path_template; *template_pos; ) {
+                sep = strchrnul(template_pos, '%');
+                path_pos = mempcpy(path_pos, template_pos, sep - template_pos);
+                if (!*sep)
+                        break;
+
+                path_pos = stpcpy(path_pos, *label_pos++);
+                template_pos = sep + 1;
+        }
+
+        *path_pos = 0;
+        *out = path;
+        return 0;
+}
+
+_public_ int sd_bus_path_decode_many(const char *path, const char *path_template, ...) {
+        _cleanup_strv_free_ char **labels = NULL;
+        const char *template_pos, *path_pos;
+        char **label_pos;
+        va_list list;
+        int r;
+
+        /*
+         * This decodes an object-path based on a template argument. The
+         * template consists of a verbatim path, optionally including special
+         * directives:
+         *
+         *   - Each occurrence of '%' in the template matches an arbitrary
+         *     substring of a label in the given path. At most one such
+         *     directive is allowed per label. For each such directive, the
+         *     caller must provide an output parameter (char **) via va_arg. If
+         *     NULL is passed, the given label is verified, but not returned.
+         *     For each matched label, the *decoded* label is stored in the
+         *     passed output argument, and the caller is responsible to free
+         *     it. Note that the output arguments are only modified if the
+         *     actualy path matched the template. Otherwise, they're left
+         *     untouched.
+         *
+         * This function returns <0 on error, 0 if the path does not match the
+         * template, 1 if it matched.
+         */
+
+        assert_return(path, -EINVAL);
+        assert_return(path_template, -EINVAL);
+
+        path_pos = path;
+
+        for (template_pos = path_template; *template_pos; ) {
+                const char *sep;
+                size_t length;
+                char *label;
+
+                /* verify everything until the next '%' matches verbatim */
+                sep = strchrnul(template_pos, '%');
+                length = sep - template_pos;
+                if (strncmp(path_pos, template_pos, length))
+                        return 0;
+
+                path_pos += length;
+                template_pos += length;
+
+                if (!*template_pos)
+                        break;
+
+                /* We found the next '%' character. Everything up until here
+                 * matched. We now skip ahead to the end of this label and make
+                 * sure it matches the tail of the label in the path. Then we
+                 * decode the string in-between and save it for later use. */
+
+                ++template_pos; /* skip over '%' */
+
+                sep = strchrnul(template_pos, '/');
+                length = sep - template_pos; /* length of suffix to match verbatim */
+
+                /* verify the suffixes match */
+                sep = strchrnul(path_pos, '/');
+                if (sep - path_pos < (ssize_t)length ||
+                    strncmp(sep - length, template_pos, length))
+                        return 0;
+
+                template_pos += length; /* skip over matched label */
+                length = sep - path_pos - length; /* length of sub-label to decode */
+
+                /* store unescaped label for later use */
+                label = bus_label_unescape_n(path_pos, length);
+                if (!label)
+                        return -ENOMEM;
+
+                r = strv_consume(&labels, label);
+                if (r < 0)
+                        return r;
+
+                path_pos = sep; /* skip decoded label and suffix */
+        }
+
+        /* end of template must match end of path */
+        if (*path_pos)
+                return 0;
+
+        /* copy the labels over to the caller */
+        va_start(list, path_template);
+        for (label_pos = labels; label_pos && *label_pos; ++label_pos) {
+                char **arg;
+
+                arg = va_arg(list, char **);
+                if (arg)
+                        *arg = *label_pos;
+                else
+                        free(*label_pos);
+        }
+        va_end(list);
+
+        free(labels);
+        labels = NULL;
+        return 1;
+}
 
 _public_ int sd_bus_try_close(sd_bus *bus) {
         int r;
@@ -3461,8 +3688,6 @@ _public_ int sd_bus_try_close(sd_bus *bus) {
         return 0;
 }
 
-/// UNNEEDED by elogind
-#if 0
 _public_ int sd_bus_get_description(sd_bus *bus, const char **description) {
         assert_return(bus, -EINVAL);
         assert_return(description, -EINVAL);
@@ -3492,8 +3717,7 @@ int bus_get_root_path(sd_bus *bus) {
         return r;
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
         int r;
 
@@ -3591,4 +3815,21 @@ _public_ int sd_bus_is_monitor(sd_bus *bus) {
 
         return !!(bus->hello_flags & KDBUS_HELLO_MONITOR);
 }
+
+static void flush_close(sd_bus *bus) {
+        if (!bus)
+                return;
+
+        /* Flushes and closes the specified bus. We take a ref before,
+         * to ensure the flushing does not cause the bus to be
+         * unreferenced. */
+
+        sd_bus_flush_close_unref(sd_bus_ref(bus));
+}
+
+_public_ void sd_bus_default_flush_close(void) {
+        flush_close(default_starter_bus);
+        flush_close(default_user_bus);
+        flush_close(default_system_bus);
+}
 #endif // 0