]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd/sd-bus/sd-bus.c
sd-bus: adjust indentation of comments
[thirdparty/systemd.git] / src / libsystemd / sd-bus / sd-bus.c
index 3ea71ea13d264eaaacfa740e376f31b3e81a6d27..026ac8cb946946c4b6d4596899f31b4f8d0754f2 100644 (file)
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "def.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "parse-util.h"
+#include "path-util.h"
 #include "process-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 #define log_debug_bus_message(m)                                         \
         do {                                                             \
@@ -146,13 +148,13 @@ static void bus_reset_queues(sd_bus *b) {
         assert(b);
 
         while (b->rqueue_size > 0)
-                sd_bus_message_unref(b->rqueue[--b->rqueue_size]);
+                bus_message_unref_queued(b->rqueue[--b->rqueue_size], b);
 
         b->rqueue = mfree(b->rqueue);
         b->rqueue_allocated = 0;
 
         while (b->wqueue_size > 0)
-                sd_bus_message_unref(b->wqueue[--b->wqueue_size]);
+                bus_message_unref_queued(b->wqueue[--b->wqueue_size], b);
 
         b->wqueue = mfree(b->wqueue);
         b->wqueue_allocated = 0;
@@ -194,7 +196,6 @@ static sd_bus* bus_free(sd_bus *b) {
         free(b->auth_buffer);
         free(b->address);
         free(b->machine);
-        free(b->cgroup_root);
         free(b->description);
         free(b->patch_sender);
 
@@ -232,25 +233,29 @@ _public_ int sd_bus_new(sd_bus **ret) {
 
         assert_return(ret, -EINVAL);
 
-        b = new0(sd_bus, 1);
+        b = new(sd_bus, 1);
         if (!b)
                 return -ENOMEM;
 
-        b->n_ref = REFCNT_INIT;
-        b->input_fd = b->output_fd = -1;
-        b->inotify_fd = -1;
-        b->message_version = 1;
-        b->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
-        b->accept_fd = true;
-        b->original_pid = getpid_cached();
-        b->n_groups = (size_t) -1;
-
-        assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0);
+        *b = (sd_bus) {
+                .n_ref = 1,
+                .input_fd = -1,
+                .output_fd = -1,
+                .inotify_fd = -1,
+                .message_version = 1,
+                .creds_mask = SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME,
+                .accept_fd = true,
+                .original_pid = getpid_cached(),
+                .n_groups = (size_t) -1,
+                .close_on_exit = true,
+        };
 
         /* We guarantee that wqueue always has space for at least one entry */
         if (!GREEDY_REALLOC(b->wqueue, b->wqueue_allocated, 1))
                 return -ENOMEM;
 
+        assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0);
+
         *ret = TAKE_PTR(b);
         return 0;
 }
@@ -461,9 +466,9 @@ static int synthesize_connected_signal(sd_bus *bus) {
 
         /* If enabled, synthesizes a local "Connected" signal mirroring the local "Disconnected" signal. This is called
          * whenever we fully established a connection, i.e. after the authorization phase, and after receiving the
-         * Hello() reply. Or in other words, whenver we enter BUS_RUNNING state.
+         * Hello() reply. Or in other words, whenever we enter BUS_RUNNING state.
          *
-         * This is useful so that clients can start doing stuff whenver the connection is fully established in a way
+         * This is useful so that clients can start doing stuff whenever the connection is fully established in a way
          * that works independently from whether we connected to a full bus or just a direct connection. */
 
         if (!bus->connected_signal)
@@ -479,6 +484,7 @@ static int synthesize_connected_signal(sd_bus *bus) {
                 return r;
 
         bus_message_set_sender_local(bus, m);
+        m->read_counter = ++bus->read_counter;
 
         r = bus_seal_synthetic_message(bus, m);
         if (r < 0)
@@ -490,7 +496,7 @@ static int synthesize_connected_signal(sd_bus *bus) {
 
         /* Insert at the very front */
         memmove(bus->rqueue + 1, bus->rqueue, sizeof(sd_bus_message*) * bus->rqueue_size);
-        bus->rqueue[0] = TAKE_PTR(m);
+        bus->rqueue[0] = bus_message_ref_queued(m, bus);
         bus->rqueue_size++;
 
         return 0;
@@ -730,20 +736,28 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
 
         if (path) {
                 l = strlen(path);
-                if (l > sizeof(b->sockaddr.un.sun_path))
+                if (l >= sizeof(b->sockaddr.un.sun_path)) /* We insist on NUL termination */
                         return -E2BIG;
 
-                b->sockaddr.un.sun_family = AF_UNIX;
-                strncpy(b->sockaddr.un.sun_path, path, sizeof(b->sockaddr.un.sun_path));
-                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l;
-        } else if (abstract) {
+                b->sockaddr.un = (struct sockaddr_un) {
+                        .sun_family = AF_UNIX,
+                };
+
+                memcpy(b->sockaddr.un.sun_path, path, l);
+                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l + 1;
+
+        } else {
+                assert(abstract);
+
                 l = strlen(abstract);
-                if (l > sizeof(b->sockaddr.un.sun_path) - 1)
+                if (l >= sizeof(b->sockaddr.un.sun_path) - 1) /* We insist on NUL termination */
                         return -E2BIG;
 
-                b->sockaddr.un.sun_family = AF_UNIX;
-                b->sockaddr.un.sun_path[0] = 0;
-                strncpy(b->sockaddr.un.sun_path+1, abstract, sizeof(b->sockaddr.un.sun_path)-1);
+                b->sockaddr.un = (struct sockaddr_un) {
+                        .sun_family = AF_UNIX,
+                };
+
+                memcpy(b->sockaddr.un.sun_path+1, abstract, l);
                 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
         }
 
@@ -964,9 +978,11 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
         } else
                 b->nspid = 0;
 
-        b->sockaddr.un.sun_family = AF_UNIX;
-        /* Note that we use the old /var/run prefix here, to increase compatibility with really old containers */
-        strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
+        b->sockaddr.un = (struct sockaddr_un) {
+                .sun_family = AF_UNIX,
+                /* Note that we use the old /var/run prefix here, to increase compatibility with really old containers */
+                .sun_path = "/var/run/dbus/system_bus_socket",
+        };
         b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);
         b->is_local = false;
 
@@ -1190,7 +1206,7 @@ _public_ int sd_bus_open_with_description(sd_bus **ret, const char *description)
         assert_return(ret, -EINVAL);
 
         /* Let's connect to the starter bus if it is set, and
-         * otherwise to the bus that is appropropriate for the scope
+         * otherwise to the bus that is appropriate for the scope
          * we are running in */
 
         e = secure_getenv("DBUS_STARTER_BUS_TYPE");
@@ -1338,8 +1354,7 @@ _public_ int sd_bus_open_user_with_description(sd_bus **ret, const char *descrip
         b->bus_client = true;
         b->is_user = true;
 
-        /* We don't do any per-method access control on the user
-         * bus. */
+        /* We don't do any per-method access control on the user bus. */
         b->trusted = true;
         b->is_local = true;
 
@@ -1409,11 +1424,9 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
                 if (!in_charset(p, "0123456789") || *p == '\0') {
                         if (!machine_name_is_valid(p) || got_forward_slash)
                                 return -EINVAL;
-                        else {
-                                m = p;
-                                p = NULL;
-                                goto interpret_port_as_machine_old_syntax;
-                        }
+
+                        m = TAKE_PTR(p);
+                        goto interpret_port_as_machine_old_syntax;
                 }
         }
 
@@ -1545,17 +1558,24 @@ _public_ void sd_bus_close(sd_bus *bus) {
         bus_close_inotify_fd(bus);
 }
 
+_public_ sd_bus *sd_bus_close_unref(sd_bus *bus) {
+        if (!bus)
+                return NULL;
+
+        sd_bus_close(bus);
+
+        return sd_bus_unref(bus);
+}
+
 _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
         if (!bus)
                 return NULL;
 
         /* Have to do this before flush() to prevent hang */
         bus_kill_exec(bus);
-
         sd_bus_flush(bus);
-        sd_bus_close(bus);
 
-        return sd_bus_unref(bus);
+        return sd_bus_close_unref(bus);
 }
 
 void bus_enter_closing(sd_bus *bus) {
@@ -1567,7 +1587,7 @@ void bus_enter_closing(sd_bus *bus) {
         bus_set_state(bus, BUS_CLOSING);
 }
 
-DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(sd_bus, sd_bus, bus_free);
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus, sd_bus, bus_free);
 
 _public_ int sd_bus_is_open(sd_bus *bus) {
         assert_return(bus, -EINVAL);
@@ -1626,6 +1646,47 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
         return 0;
 }
 
+#define COOKIE_CYCLED (UINT32_C(1) << 31)
+
+static uint64_t cookie_inc(uint64_t cookie) {
+
+        /* Stay within the 32bit range, since classic D-Bus can't deal with more */
+        if (cookie >= UINT32_MAX)
+                return COOKIE_CYCLED; /* Don't go back to zero, but use the highest bit for checking
+                                       * whether we are looping. */
+
+        return cookie + 1;
+}
+
+static int next_cookie(sd_bus *b) {
+        uint64_t new_cookie;
+
+        assert(b);
+
+        new_cookie = cookie_inc(b->cookie);
+
+        /* Small optimization: don't bother with checking for cookie reuse until we overran cookiespace at
+         * least once, but then do it thorougly. */
+        if (FLAGS_SET(new_cookie, COOKIE_CYCLED)) {
+                uint32_t i;
+
+                /* Check if the cookie is currently in use. If so, pick the next one */
+                for (i = 0; i < COOKIE_CYCLED; i++) {
+                        if (!ordered_hashmap_contains(b->reply_callbacks, &new_cookie))
+                                goto good;
+
+                        new_cookie = cookie_inc(new_cookie);
+                }
+
+                /* Can't fulfill request */
+                return -EBUSY;
+        }
+
+good:
+        b->cookie = new_cookie;
+        return 0;
+}
+
 static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
         int r;
 
@@ -1652,7 +1713,11 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
                         return r;
         }
 
-        return sd_bus_message_seal(m, ++b->cookie, timeout);
+        r = next_cookie(b);
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_seal(m, b->cookie, timeout);
 }
 
 static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
@@ -1748,7 +1813,7 @@ static int dispatch_wqueue(sd_bus *bus) {
                          * anyway. */
 
                         bus->wqueue_size--;
-                        sd_bus_message_unref(bus->wqueue[0]);
+                        bus_message_unref_queued(bus->wqueue[0], bus);
                         memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
                         bus->windex = 0;
 
@@ -1777,6 +1842,15 @@ int bus_rqueue_make_room(sd_bus *bus) {
         return 0;
 }
 
+static void rqueue_drop_one(sd_bus *bus, size_t i) {
+        assert(bus);
+        assert(i < bus->rqueue_size);
+
+        bus_message_unref_queued(bus->rqueue[i], bus);
+        memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+        bus->rqueue_size--;
+}
+
 static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **m) {
         int r, ret = 0;
 
@@ -1791,10 +1865,8 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
         for (;;) {
                 if (bus->rqueue_size > 0) {
                         /* Dispatch a queued message */
-
-                        *m = bus->rqueue[0];
-                        bus->rqueue_size--;
-                        memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
+                        *m = sd_bus_message_ref(bus->rqueue[0]);
+                        rqueue_drop_one(bus, 0);
                         return 1;
                 }
 
@@ -1802,8 +1874,10 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
                 r = bus_read_message(bus, hint_priority, priority);
                 if (r < 0)
                         return r;
-                if (r == 0)
+                if (r == 0) {
+                        *m = NULL;
                         return ret;
+                }
 
                 ret = 1;
         }
@@ -1856,7 +1930,7 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
 
                 r = bus_write_message(bus, m, &idx);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
@@ -1870,7 +1944,7 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
                          * of the wqueue array is always allocated so
                          * that we always can remember how much was
                          * written. */
-                        bus->wqueue[0] = sd_bus_message_ref(m);
+                        bus->wqueue[0] = bus_message_ref_queued(m, bus);
                         bus->wqueue_size = 1;
                         bus->windex = idx;
                 }
@@ -1884,7 +1958,7 @@ _public_ int sd_bus_send(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++] = bus_message_ref_queued(m, bus);
         }
 
 finish:
@@ -1945,13 +2019,7 @@ static int timeout_compare(const void *a, const void *b) {
         if (x->timeout_usec == 0 && y->timeout_usec != 0)
                 return 1;
 
-        if (x->timeout_usec < y->timeout_usec)
-                return -1;
-
-        if (x->timeout_usec > y->timeout_usec)
-                return 1;
-
-        return 0;
+        return CMP(x->timeout_usec, y->timeout_usec);
 }
 
 _public_ int sd_bus_call_async(
@@ -2068,7 +2136,7 @@ _public_ int sd_bus_call(
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
         usec_t timeout;
         uint64_t cookie;
-        unsigned i;
+        size_t i;
         int r;
 
         bus_assert_return(m, -EINVAL, error);
@@ -2110,37 +2178,30 @@ _public_ int sd_bus_call(
                 usec_t left;
 
                 while (i < bus->rqueue_size) {
-                        sd_bus_message *incoming = NULL;
+                        _cleanup_(sd_bus_message_unrefp) sd_bus_message *incoming = NULL;
 
-                        incoming = bus->rqueue[i];
+                        incoming = sd_bus_message_ref(bus->rqueue[i]);
 
                         if (incoming->reply_cookie == cookie) {
                                 /* Found a match! */
 
-                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
-                                bus->rqueue_size--;
+                                rqueue_drop_one(bus, i);
                                 log_debug_bus_message(incoming);
 
                                 if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
 
                                         if (incoming->n_fds <= 0 || bus->accept_fd) {
                                                 if (reply)
-                                                        *reply = incoming;
-                                                else
-                                                        sd_bus_message_unref(incoming);
+                                                        *reply = TAKE_PTR(incoming);
 
                                                 return 1;
                                         }
 
-                                        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;
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
 
-                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
-                                        r = sd_bus_error_copy(error, &incoming->error);
-                                        sd_bus_message_unref(incoming);
-                                        return r;
-                                } else {
+                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
+                                        return sd_bus_error_copy(error, &incoming->error);
+                                else {
                                         r = -EIO;
                                         goto fail;
                                 }
@@ -2150,15 +2211,11 @@ _public_ int sd_bus_call(
                                    incoming->sender &&
                                    streq(bus->unique_name, incoming->sender)) {
 
-                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
-                                bus->rqueue_size--;
+                                rqueue_drop_one(bus, i);
 
-                                /* Our own message? Somebody is trying
-                                 * to send its own client a message,
-                                 * let's not dead-lock, let's fail
-                                 * immediately. */
+                                /* Our own message? Somebody is trying to send its own client a message,
+                                 * let's not dead-lock, let's fail immediately. */
 
-                                sd_bus_message_unref(incoming);
                                 r = -ELOOP;
                                 goto fail;
                         }
@@ -2169,7 +2226,7 @@ _public_ int sd_bus_call(
 
                 r = bus_read_message(bus, false, 0);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 r = -ECONNRESET;
                         }
@@ -2202,7 +2259,7 @@ _public_ int sd_bus_call(
 
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 r = -ECONNRESET;
                         }
@@ -2365,6 +2422,8 @@ static int process_timeout(sd_bus *bus) {
         if (r < 0)
                 return r;
 
+        m->read_counter = ++bus->read_counter;
+
         r = bus_seal_synthetic_message(bus, m);
         if (r < 0)
                 return r;
@@ -2467,6 +2526,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
                 synthetic_reply->realtime = m->realtime;
                 synthetic_reply->monotonic = m->monotonic;
                 synthetic_reply->seqnum = m->seqnum;
+                synthetic_reply->read_counter = m->read_counter;
 
                 r = bus_seal_synthetic_message(bus, synthetic_reply);
                 if (r < 0)
@@ -2616,7 +2676,6 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
                                 SD_BUS_ERROR_UNKNOWN_METHOD,
                                  "Unknown method '%s' on interface '%s'.", m->member, m->interface);
         }
-
         if (r < 0)
                 return r;
 
@@ -2740,7 +2799,6 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd
                         return r;
 
                 *ret = TAKE_PTR(m);
-
                 return 1;
         }
 
@@ -2811,6 +2869,8 @@ static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c)
         if (r < 0)
                 return r;
 
+        m->read_counter = ++bus->read_counter;
+
         r = bus_seal_synthetic_message(bus, m);
         if (r < 0)
                 return r;
@@ -2875,6 +2935,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
                 return r;
 
         bus_message_set_sender_local(bus, m);
+        m->read_counter = ++bus->read_counter;
 
         r = bus_seal_synthetic_message(bus, m);
         if (r < 0)
@@ -2962,7 +3023,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
                 assert_not_reached("Unknown state");
         }
 
-        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+        if (ERRNO_IS_DISCONNECT(r)) {
                 bus_enter_closing(bus);
                 r = 1;
         } else if (r < 0)
@@ -3093,7 +3154,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         for (;;) {
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
@@ -3184,8 +3245,6 @@ static int add_match_callback(
                 bus->current_slot = match_slot->match_callback.install_slot;
                 bus->current_handler = add_match_callback;
                 bus->current_userdata = userdata;
-
-                match_slot->match_callback.install_slot = sd_bus_slot_unref(match_slot->match_callback.install_slot);
         } else {
                 if (failed) /* Generic failure handling: destroy the connection */
                         bus_enter_closing(sd_bus_message_get_bus(m));
@@ -3193,6 +3252,9 @@ static int add_match_callback(
                 r = 1;
         }
 
+        /* We don't need the install method reply slot anymore, let's free it */
+        match_slot->match_callback.install_slot = sd_bus_slot_unref(match_slot->match_callback.install_slot);
+
         if (failed && match_slot->floating)
                 bus_slot_disconnect(match_slot, true);
 
@@ -3264,7 +3326,7 @@ static int bus_add_match_full(
                                  * then make it floating. */
                                 r = sd_bus_slot_set_floating(s->match_callback.install_slot, true);
                         } else
-                                r = bus_add_match_internal(bus, s->match_callback.match_string);
+                                r = bus_add_match_internal(bus, s->match_callback.match_string, &s->match_callback.after);
                         if (r < 0)
                                 goto finish;
 
@@ -3407,8 +3469,10 @@ static int quit_callback(sd_event_source *event, void *userdata) {
 
         assert(event);
 
-        sd_bus_flush(bus);
-        sd_bus_close(bus);
+        if (bus->close_on_exit) {
+                sd_bus_flush(bus);
+                sd_bus_close(bus);
+        }
 
         return 1;
 }
@@ -3700,7 +3764,7 @@ _public_ int sd_bus_path_encode(const char *prefix, const char *external_id, cha
         if (!e)
                 return -ENOMEM;
 
-        ret = strjoin(prefix, "/", e);
+        ret = path_join(prefix, e);
         if (!ret)
                 return -ENOMEM;
 
@@ -3813,7 +3877,7 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
          *     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
+         *     actually path matched the template. Otherwise, they're left
          *     untouched.
          *
          * This function returns <0 on error, 0 if the path does not match the
@@ -3921,24 +3985,6 @@ _public_ int sd_bus_get_description(sd_bus *bus, const char **description) {
         return 0;
 }
 
-int bus_get_root_path(sd_bus *bus) {
-        int r;
-
-        if (bus->cgroup_root)
-                return 0;
-
-        r = cg_get_root_path(&bus->cgroup_root);
-        if (r == -ENOENT) {
-                bus->cgroup_root = strdup("/");
-                if (!bus->cgroup_root)
-                        return -ENOMEM;
-
-                r = 0;
-        }
-
-        return r;
-}
-
 _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
         assert_return(bus, -EINVAL);
         assert_return(bus = bus_resolve(bus), -ENOPKG);
@@ -4133,3 +4179,18 @@ _public_ int sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret) {
         *ret = bus->method_call_timeout = BUS_DEFAULT_TIMEOUT;
         return 0;
 }
+
+_public_ int sd_bus_set_close_on_exit(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus = bus_resolve(bus), -ENOPKG);
+
+        bus->close_on_exit = b;
+        return 0;
+}
+
+_public_ int sd_bus_get_close_on_exit(sd_bus *bus) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus = bus_resolve(bus), -ENOPKG);
+
+        return bus->close_on_exit;
+}