chiark / gitweb /
bus: add support for attaching name to bus connections for debugging purposes
[elogind.git] / src / libsystemd / sd-bus / bus-kernel.c
index f85b4d5676ff252c0642e0dbd2082dc23d196727..78a6c1062a65665a69c6ce83e18764ed6640804c 100644 (file)
@@ -26,6 +26,7 @@
 #include <fcntl.h>
 #include <malloc.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
 
 #include "util.h"
 #include "strv.h"
@@ -206,6 +207,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
         assert(m);
         assert(m->sealed);
 
+        /* We put this together only once, if this message is reused
+         * we reuse the earlier-built version */
         if (m->kdbus)
                 return 0;
 
@@ -499,6 +502,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
                 case KDBUS_ITEM_TIMESTAMP:
                         m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
                         m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
+                        m->seqnum = d->timestamp.seqnum;
                         break;
 
                 case KDBUS_ITEM_PID_COMM:
@@ -625,7 +629,9 @@ fail:
 int bus_kernel_take_fd(sd_bus *b) {
         struct kdbus_cmd_hello *hello;
         struct kdbus_item *item;
-        size_t l = 0, sz;
+        _cleanup_free_ char *g = NULL;
+        const char *name;
+        size_t l = 0, m = 0, sz;
         int r;
 
         assert(b);
@@ -635,10 +641,52 @@ int bus_kernel_take_fd(sd_bus *b) {
 
         b->use_memfd = 1;
 
-        sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
+        if (b->connection_name) {
+                g = sd_bus_label_escape(b->connection_name);
+                if (!g)
+                        return -ENOMEM;
+
+                name = g;
+        } else {
+                char pr[17] = {};
+
+                /* If no name is explicitly set, we'll include a hint
+                 * indicating the library implementation, a hint which
+                 * kind of bus this is and the thread name */
+
+                assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
+
+                if (isempty(pr)) {
+                        name = b->is_system ? "sd-system" :
+                                b->is_user ? "sd-user" : "sd";
+                } else {
+                        _cleanup_free_ char *e = NULL;
+
+                        e = sd_bus_label_escape(pr);
+                        if (!e)
+                                return -ENOMEM;
+
+                        g = strappend(b->is_system ? "sd-system-" :
+                                      b->is_user ? "sd-user-" : "sd-",
+                                      e);
+                        if (!g)
+                                return -ENOMEM;
+
+                        name = g;
+                }
+
+                b->connection_name = sd_bus_label_unescape(name);
+                if (!b->connection_name)
+                        return -ENOMEM;
+        }
+
+        m = strlen(name);
+
+        sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) +
+                ALIGN8(offsetof(struct kdbus_item, str) + m + 1);
 
         if (b->fake_creds_valid)
-                sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
+                sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds));
 
         if (b->fake_label) {
                 l = strlen(b->fake_label);
@@ -653,6 +701,11 @@ int bus_kernel_take_fd(sd_bus *b) {
 
         item = hello->items;
 
+        item->size = offsetof(struct kdbus_item, str) + m + 1;
+        item->type = KDBUS_ITEM_CONN_NAME;
+        memcpy(item->str, name, m + 1);
+        item = KDBUS_ITEM_NEXT(item);
+
         if (b->fake_creds_valid) {
                 item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
                 item->type = KDBUS_ITEM_CREDS;
@@ -663,6 +716,7 @@ int bus_kernel_take_fd(sd_bus *b) {
 
         if (b->fake_label) {
                 item->size = offsetof(struct kdbus_item, str) + l + 1;
+                item->type = KDBUS_ITEM_SECLABEL;
                 memcpy(item->str, b->fake_label, l+1);
         }
 
@@ -722,7 +776,26 @@ int bus_kernel_connect(sd_bus *b) {
         return bus_kernel_take_fd(b);
 }
 
-int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
+static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
+        uint64_t off;
+        struct kdbus_item *d;
+
+        assert(bus);
+        assert(k);
+
+        off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
+        ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
+
+        KDBUS_ITEM_FOREACH(d, k, items) {
+
+                if (d->type == KDBUS_ITEM_FDS)
+                        close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
+                else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
+                        close_nointr_nofail(d->memfd.fd);
+        }
+}
+
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) {
         int r;
 
         assert(bus);
@@ -738,6 +811,14 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
         if (r < 0)
                 return r;
 
+        /* If this is a synchronous method call, then let's tell the
+         * kernel, so that it can pass CPU time/scheduling to the
+         * destination for the time, if it wants to. If we
+         * synchronously wait for the result anyway, we won't need CPU
+         * anyway. */
+        if (hint_sync_call)
+                m->kdbus->flags |= KDBUS_MSG_FLAGS_EXPECT_REPLY|KDBUS_MSG_FLAGS_SYNC_REPLY;
+
         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
         if (r < 0) {
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -785,29 +866,31 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
 
                 bus->rqueue[bus->rqueue_size++] = reply;
 
-                return 0;
-        }
-
-        return 1;
-}
-
-static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
-        uint64_t off;
-        struct kdbus_item *d;
+        } else if (hint_sync_call) {
+                struct kdbus_msg *k;
 
-        assert(bus);
-        assert(k);
+                k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + m->kdbus->offset_reply);
+                assert(k);
 
-        off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
-        ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
+                if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
 
-        KDBUS_ITEM_FOREACH(d, k, items) {
+                        r = bus_kernel_make_message(bus, k);
+                        if (r < 0) {
+                                close_kdbus_msg(bus, k);
 
-                if (d->type == KDBUS_ITEM_FDS)
-                        close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
-                else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
-                        close_nointr_nofail(d->memfd.fd);
+                                /* Anybody can send us invalid messages, let's just drop them. */
+                                if (r == -EBADMSG || r == -EPROTOTYPE)
+                                        log_debug("Ignoring invalid message: %s", strerror(-r));
+                                else
+                                        return r;
+                        }
+                } else {
+                        log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
+                        close_kdbus_msg(bus, k);
+                }
         }
+
+        return 1;
 }
 
 static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
@@ -964,8 +1047,8 @@ int bus_kernel_read_message(sd_bus *bus) {
 
                 return -errno;
         }
-        k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
 
+        k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
         if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
                 r = bus_kernel_make_message(bus, k);
 
@@ -977,8 +1060,10 @@ int bus_kernel_read_message(sd_bus *bus) {
 
         } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
                 r = bus_kernel_translate_message(bus, k);
-        else
+        else {
+                log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
                 r = 0;
+        }
 
         if (r <= 0)
                 close_kdbus_msg(bus, k);