[systemd-commits] 2 commits - src/libsystemd
Daniel Mack
zonque at kemper.freedesktop.org
Sun Jan 19 14:01:29 PST 2014
src/libsystemd/bus-kernel.c | 964 ++++++++++++++++++++++---------------------
src/libsystemd/bus-kernel.h | 1
src/libsystemd/bus-message.h | 1
src/libsystemd/sd-bus.c | 62 +-
4 files changed, 539 insertions(+), 489 deletions(-)
New commits:
commit 021b89861d0b1defcbd6ba71d1aaf6271785a942
Author: Daniel Mack <zonque at gmail.com>
Date: Sat Jan 18 20:09:14 2014 +0100
sd-bus: let sd_bus_call() use the synchronous kdbus method
diff --git a/src/libsystemd/bus-kernel.c b/src/libsystemd/bus-kernel.c
index f85b4d5..5ace724 100644
--- a/src/libsystemd/bus-kernel.c
+++ b/src/libsystemd/bus-kernel.c
@@ -251,7 +251,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
m->kdbus->flags =
((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
- ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+ ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0) |
+ (m->reply_sync ? KDBUS_MSG_FLAGS_SYNC_REPLY : 0);
m->kdbus->dst_id =
well_known ? 0 :
m->destination ? unique : KDBUS_DST_ID_BROADCAST;
@@ -788,6 +789,39 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
return 0;
}
+ if (m->reply_sync) {
+ struct kdbus_msg *k;
+
+ k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + m->kdbus->offset_reply);
+ r = bus_kernel_make_message(bus, k);
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
+}
+
+int bus_call_kernel(
+ sd_bus *bus,
+ sd_bus_message *m,
+ uint64_t usec,
+ sd_bus_error *error,
+ sd_bus_message **reply) {
+
+ int r;
+ uint64_t cookie;
+
+ m->reply_sync = !!reply;
+
+ r = sd_bus_send(bus, m, &cookie);
+ if (r < 0)
+ return r;
+
+ if (reply) {
+ assert(bus->rqueue_size > 0);
+ *reply = bus->rqueue[--bus->rqueue_size];
+ }
+
return 1;
}
diff --git a/src/libsystemd/bus-kernel.h b/src/libsystemd/bus-kernel.h
index 2aba0bb..88954aa 100644
--- a/src/libsystemd/bus-kernel.h
+++ b/src/libsystemd/bus-kernel.h
@@ -62,6 +62,7 @@ int bus_kernel_take_fd(sd_bus *b);
int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m);
int bus_kernel_read_message(sd_bus *bus);
+int bus_call_kernel(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *error, sd_bus_message **reply);
int bus_kernel_create_bus(const char *name, bool world, char **s);
int bus_kernel_create_namespace(const char *name, char **s);
diff --git a/src/libsystemd/bus-message.h b/src/libsystemd/bus-message.h
index 5322375..efddc97 100644
--- a/src/libsystemd/bus-message.h
+++ b/src/libsystemd/bus-message.h
@@ -107,6 +107,7 @@ struct sd_bus_message {
bool free_fds:1;
bool release_kdbus:1;
bool poisoned:1;
+ bool reply_sync:1;
struct bus_header *header;
struct bus_body_part body;
diff --git a/src/libsystemd/sd-bus.c b/src/libsystemd/sd-bus.c
index 95d80db..fa045a6 100644
--- a/src/libsystemd/sd-bus.c
+++ b/src/libsystemd/sd-bus.c
@@ -1720,41 +1720,19 @@ int bus_ensure_running(sd_bus *bus) {
}
}
-_public_ int sd_bus_call(
+static int bus_call_dbus1(
sd_bus *bus,
- sd_bus_message *_m,
+ sd_bus_message *m,
uint64_t usec,
sd_bus_error *error,
sd_bus_message **reply) {
- _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
usec_t timeout;
uint64_t cookie;
unsigned i;
int r;
- assert_return(bus, -EINVAL);
- assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
- 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);
- assert_return(!bus_pid_changed(bus), -ECHILD);
-
- r = bus_ensure_running(bus);
- if (r < 0)
- return r;
-
i = bus->rqueue_size;
-
- r = bus_seal_message(bus, m, usec);
- if (r < 0)
- return r;
-
- r = bus_remarshal_message(bus, &m);
- if (r < 0)
- return r;
-
r = sd_bus_send(bus, m, &cookie);
if (r < 0)
return r;
@@ -1853,6 +1831,42 @@ _public_ int sd_bus_call(
}
}
+_public_ int sd_bus_call(
+ sd_bus *bus,
+ sd_bus_message *_m,
+ uint64_t usec,
+ sd_bus_error *error,
+ sd_bus_message **reply) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+ 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);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ r = bus_ensure_running(bus);
+ if (r < 0)
+ return r;
+
+ r = bus_seal_message(bus, m, usec);
+ if (r < 0)
+ return r;
+
+ r = bus_remarshal_message(bus, &m);
+ if (r < 0)
+ return r;
+
+ if (bus->is_kernel)
+ return bus_call_kernel(bus, m, usec, error, reply);
+ else
+ return bus_call_dbus1(bus, m, usec, error, reply);
+}
+
_public_ int sd_bus_get_fd(sd_bus *bus) {
assert_return(bus, -EINVAL);
commit cb67f7184e61fafc984c4cd1e921d71a7e67c2ae
Author: Daniel Mack <zonque at gmail.com>
Date: Sat Jan 18 20:06:21 2014 +0100
bus-kernel: move bus_kernel_make_message
This makes future commits more readable.
diff --git a/src/libsystemd/bus-kernel.c b/src/libsystemd/bus-kernel.c
index d3eeb52..f85b4d5 100644
--- a/src/libsystemd/bus-kernel.c
+++ b/src/libsystemd/bus-kernel.c
@@ -320,630 +320,630 @@ fail:
return r;
}
-int bus_kernel_take_fd(sd_bus *b) {
- struct kdbus_cmd_hello *hello;
- struct kdbus_item *item;
- size_t l = 0, sz;
+static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
+ sd_bus_message *m = NULL;
+ struct kdbus_item *d;
+ unsigned n_fds = 0;
+ _cleanup_free_ int *fds = NULL;
+ struct bus_header *h = NULL;
+ size_t total, n_bytes = 0, idx = 0;
+ const char *destination = NULL, *seclabel = NULL;
int r;
- assert(b);
+ assert(bus);
+ assert(k);
+ assert(k->payload_type == KDBUS_PAYLOAD_DBUS);
- if (b->is_server)
- return -EINVAL;
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ size_t l;
- b->use_memfd = 1;
+ l = d->size - offsetof(struct kdbus_item, data);
- sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
+ switch (d->type) {
- if (b->fake_creds_valid)
- sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
+ case KDBUS_ITEM_PAYLOAD_OFF:
+ if (!h) {
+ h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
- if (b->fake_label) {
- l = strlen(b->fake_label);
- sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
- }
+ if (!bus_header_is_complete(h, d->vec.size))
+ return -EBADMSG;
+ }
- hello = alloca0(sz);
- hello->size = sz;
- hello->conn_flags = b->hello_flags;
- hello->attach_flags = b->attach_flags;
- hello->pool_size = KDBUS_POOL_SIZE;
+ n_bytes += d->vec.size;
+ break;
- item = hello->items;
+ case KDBUS_ITEM_PAYLOAD_MEMFD:
+ if (!h)
+ return -EBADMSG;
- if (b->fake_creds_valid) {
- item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
- item->type = KDBUS_ITEM_CREDS;
- item->creds = b->fake_creds;
+ n_bytes += d->memfd.size;
+ break;
- item = KDBUS_ITEM_NEXT(item);
- }
+ case KDBUS_ITEM_FDS: {
+ int *f;
+ unsigned j;
- if (b->fake_label) {
- item->size = offsetof(struct kdbus_item, str) + l + 1;
- memcpy(item->str, b->fake_label, l+1);
- }
+ j = l / sizeof(int);
+ f = realloc(fds, sizeof(int) * (n_fds + j));
+ if (!f)
+ return -ENOMEM;
- r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
- if (r < 0)
- return -errno;
+ fds = f;
+ memcpy(fds + n_fds, d->fds, sizeof(int) * j);
+ n_fds += j;
+ break;
+ }
- if (!b->kdbus_buffer) {
- b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
- if (b->kdbus_buffer == MAP_FAILED) {
- b->kdbus_buffer = NULL;
- return -errno;
+ case KDBUS_ITEM_SECLABEL:
+ seclabel = d->str;
+ break;
}
}
- /* The higher 32bit of both flags fields are considered
- * 'incompatible flags'. Refuse them all for now. */
- if (hello->bus_flags > 0xFFFFFFFFULL ||
- hello->conn_flags > 0xFFFFFFFFULL)
- return -ENOTSUP;
-
- if (hello->bloom_size != BLOOM_SIZE)
- return -ENOTSUP;
-
- if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
- return -ENOMEM;
+ if (!h)
+ return -EBADMSG;
- b->unique_id = hello->id;
+ r = bus_header_message_size(h, &total);
+ if (r < 0)
+ return r;
- b->is_kernel = true;
- b->bus_client = true;
- b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
- b->message_version = 2;
- b->message_endian = BUS_NATIVE_ENDIAN;
+ if (n_bytes != total)
+ return -EBADMSG;
- /* the kernel told us the UUID of the underlying bus */
- memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
+ /* on kdbus we only speak native endian gvariant, never dbus1
+ * marshalling or reverse endian */
+ if (h->version != 2 ||
+ h->endian != BUS_NATIVE_ENDIAN)
+ return -EPROTOTYPE;
- return bus_start_running(b);
-}
+ r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
+ if (r < 0)
+ return r;
-int bus_kernel_connect(sd_bus *b) {
- assert(b);
- assert(b->input_fd < 0);
- assert(b->output_fd < 0);
- assert(b->kernel);
+ /* The well-known names list is different from the other
+ credentials. If we asked for it, but nothing is there, this
+ means that the list of well-known names is simply empty, not
+ that we lack any data */
- if (b->is_server)
- return -EINVAL;
+ m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
- b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (b->input_fd < 0)
- return -errno;
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ size_t l;
- b->output_fd = b->input_fd;
+ l = d->size - offsetof(struct kdbus_item, data);
- return bus_kernel_take_fd(b);
-}
+ switch (d->type) {
-int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
- int r;
+ case KDBUS_ITEM_PAYLOAD_OFF: {
+ size_t begin_body;
- assert(bus);
- assert(m);
- assert(bus->state == BUS_RUNNING);
+ begin_body = BUS_MESSAGE_BODY_BEGIN(m);
- /* If we can't deliver, we want room for the error message */
- r = bus_rqueue_make_room(bus);
- if (r < 0)
- return r;
+ if (idx + d->vec.size > begin_body) {
+ struct bus_body_part *part;
- r = bus_message_setup_kmsg(bus, m);
- if (r < 0)
- return r;
+ /* Contains body material */
- 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;
- sd_bus_message *reply;
+ part = message_append_part(m);
+ if (!part) {
+ r = -ENOMEM;
+ goto fail;
+ }
- if (errno == EAGAIN || errno == EINTR)
- return 0;
- else if (errno == ENXIO || errno == ESRCH) {
+ /* A -1 offset is NUL padding. */
+ part->is_zero = d->vec.offset == ~0ULL;
- /* ENXIO: unique name not known
- * ESRCH: well-known name not known */
+ if (idx >= begin_body) {
+ if (!part->is_zero)
+ part->data = (uint8_t *)k + d->vec.offset;
+ part->size = d->vec.size;
+ } else {
+ if (!part->is_zero)
+ part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
+ part->size = d->vec.size - (begin_body - idx);
+ }
- if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
- sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
- else {
- log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
- return 0;
+ part->sealed = true;
}
- } else if (errno == EADDRNOTAVAIL) {
+ idx += d->vec.size;
+ break;
+ }
- /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
+ case KDBUS_ITEM_PAYLOAD_MEMFD: {
+ struct bus_body_part *part;
- if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
- sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
- else {
- log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
- return 0;
+ if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
+ r = -EBADMSG;
+ goto fail;
}
- } else
- return -errno;
- r = bus_message_new_synthetic_error(
- bus,
- BUS_MESSAGE_COOKIE(m),
- &error,
- &reply);
+ part = message_append_part(m);
+ if (!part) {
+ r = -ENOMEM;
+ goto fail;
+ }
- if (r < 0)
- return r;
+ part->memfd = d->memfd.fd;
+ part->size = d->memfd.size;
+ part->sealed = true;
- r = bus_seal_synthetic_message(bus, reply);
- if (r < 0)
- return r;
+ idx += d->memfd.size;
+ break;
+ }
- bus->rqueue[bus->rqueue_size++] = reply;
+ case KDBUS_ITEM_CREDS:
+ /* UID/GID/PID are always valid */
+ m->creds.uid = (uid_t) d->creds.uid;
+ m->creds.gid = (gid_t) d->creds.gid;
+ m->creds.pid = (pid_t) d->creds.pid;
+ m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
- return 0;
- }
+ /* The PID starttime/TID might be missing
+ * however, when the data is faked by some
+ * data bus proxy and it lacks that
+ * information about the real client since
+ * SO_PEERCRED is used for that */
- return 1;
-}
+ if (d->creds.starttime > 0) {
+ m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
+ m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
+ }
-static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
- uint64_t off;
- struct kdbus_item *d;
+ if (d->creds.tid > 0) {
+ m->creds.tid = (pid_t) d->creds.tid;
+ m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
+ }
+ break;
- assert(bus);
- assert(k);
+ case KDBUS_ITEM_TIMESTAMP:
+ m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
+ m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
+ break;
- off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
- ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
+ case KDBUS_ITEM_PID_COMM:
+ m->creds.comm = d->str;
+ m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
+ break;
- KDBUS_ITEM_FOREACH(d, k, items) {
+ case KDBUS_ITEM_TID_COMM:
+ m->creds.tid_comm = d->str;
+ m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
+ break;
- 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);
- }
-}
+ case KDBUS_ITEM_EXE:
+ m->creds.exe = d->str;
+ m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
+ break;
-static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- int r;
+ case KDBUS_ITEM_CMDLINE:
+ m->creds.cmdline = d->str;
+ m->creds.cmdline_size = l;
+ m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
+ break;
- assert(bus);
+ case KDBUS_ITEM_CGROUP:
+ m->creds.cgroup = d->str;
+ m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
- r = sd_bus_message_new_signal(
- bus,
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "NameOwnerChanged",
- &m);
- if (r < 0)
- return r;
+ if (!bus->cgroup_root) {
+ r = cg_get_root_path(&bus->cgroup_root);
+ if (r < 0)
+ goto fail;
+ }
- r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
- if (r < 0)
- return r;
+ m->creds.cgroup_root = bus->cgroup_root;
- m->sender = "org.freedesktop.DBus";
+ break;
- r = bus_seal_synthetic_message(bus, m);
- if (r < 0)
- return r;
+ case KDBUS_ITEM_AUDIT:
+ m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+ m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
+ m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
+ break;
- bus->rqueue[bus->rqueue_size++] = m;
- m = NULL;
+ case KDBUS_ITEM_CAPS:
+ m->creds.capability = d->data;
+ m->creds.capability_size = l;
+ m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
+ break;
- return 1;
-}
+ case KDBUS_ITEM_DST_NAME:
+ if (!service_name_is_valid(d->str))
+ return -EBADMSG;
-static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
- char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
+ destination = d->str;
+ break;
- assert(bus);
- assert(k);
- assert(d);
+ case KDBUS_ITEM_NAME:
+ if (!service_name_is_valid(d->name.name))
+ return -EBADMSG;
- if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
- old_owner[0] = 0;
- else
- sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id);
+ r = strv_extend(&m->creds.well_known_names, d->name.name);
+ if (r < 0)
+ goto fail;
+ break;
- if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
+ case KDBUS_ITEM_FDS:
+ case KDBUS_ITEM_SECLABEL:
+ break;
- if (isempty(old_owner))
- return 0;
+ default:
+ log_debug("Got unknown field from kernel %llu", d->type);
+ }
+ }
- new_owner[0] = 0;
- } else
- sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id);
+ r = bus_message_parse_fields(m);
+ if (r < 0)
+ goto fail;
- return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
-}
+ /* Override information from the user header with data from the kernel */
+ if (k->src_id == KDBUS_SRC_ID_KERNEL)
+ m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
+ else {
+ snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
+ m->sender = m->creds.unique_name = m->sender_buffer;
+ }
-static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
- char owner[UNIQUE_NAME_MAX];
+ if (destination)
+ m->destination = destination;
+ else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
+ m->destination = NULL;
+ else if (k->dst_id == KDBUS_DST_ID_NAME)
+ m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
+ else {
+ snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
+ m->destination = m->destination_buffer;
+ }
- assert(bus);
- assert(k);
- assert(d);
+ /* We take possession of the kmsg struct now */
+ m->kdbus = k;
+ m->release_kdbus = true;
+ m->free_fds = true;
+ fds = NULL;
- sprintf(owner, ":1.%llu", d->id_change.id);
+ bus->rqueue[bus->rqueue_size++] = m;
- return push_name_owner_changed(
- bus, owner,
- d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
- d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
-}
+ return 1;
-static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- int r;
+fail:
+ if (m) {
+ struct bus_body_part *part;
+ unsigned i;
- assert(bus);
- assert(k);
- assert(d);
+ /* Make sure the memfds are not freed twice */
+ MESSAGE_FOREACH_PART(part, i, m)
+ if (part->memfd >= 0)
+ part->memfd = -1;
- r = bus_message_new_synthetic_error(
- bus,
- k->cookie_reply,
- d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
- &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
- &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
- &m);
- if (r < 0)
- return r;
+ sd_bus_message_unref(m);
+ }
- m->sender = "org.freedesktop.DBus";
+ return r;
+}
- r = bus_seal_synthetic_message(bus, m);
- if (r < 0)
- return r;
+int bus_kernel_take_fd(sd_bus *b) {
+ struct kdbus_cmd_hello *hello;
+ struct kdbus_item *item;
+ size_t l = 0, sz;
+ int r;
- bus->rqueue[bus->rqueue_size++] = m;
- m = NULL;
+ assert(b);
- return 1;
-}
+ if (b->is_server)
+ return -EINVAL;
-static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
- struct kdbus_item *d, *found = NULL;
+ b->use_memfd = 1;
- static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
- [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
- [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
- [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
- [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
- [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+ if (b->fake_creds_valid)
+ sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
- [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
- [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
- };
+ if (b->fake_label) {
+ l = strlen(b->fake_label);
+ sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
+ }
- assert(bus);
- assert(k);
- assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
+ hello = alloca0(sz);
+ hello->size = sz;
+ hello->conn_flags = b->hello_flags;
+ hello->attach_flags = b->attach_flags;
+ hello->pool_size = KDBUS_POOL_SIZE;
- KDBUS_ITEM_FOREACH(d, k, items) {
- if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
- if (found)
- return -EBADMSG;
- found = d;
- } else
- log_debug("Got unknown field from kernel %llu", d->type);
+ item = hello->items;
+
+ if (b->fake_creds_valid) {
+ item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
+ item->type = KDBUS_ITEM_CREDS;
+ item->creds = b->fake_creds;
+
+ item = KDBUS_ITEM_NEXT(item);
}
- if (!found) {
- log_debug("Didn't find a kernel message to translate.");
- return 0;
+ if (b->fake_label) {
+ item->size = offsetof(struct kdbus_item, str) + l + 1;
+ memcpy(item->str, b->fake_label, l+1);
}
- return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
-}
+ r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
+ if (r < 0)
+ return -errno;
-static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
- sd_bus_message *m = NULL;
- struct kdbus_item *d;
- unsigned n_fds = 0;
- _cleanup_free_ int *fds = NULL;
- struct bus_header *h = NULL;
- size_t total, n_bytes = 0, idx = 0;
- const char *destination = NULL, *seclabel = NULL;
- int r;
+ if (!b->kdbus_buffer) {
+ b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
+ if (b->kdbus_buffer == MAP_FAILED) {
+ b->kdbus_buffer = NULL;
+ return -errno;
+ }
+ }
- assert(bus);
- assert(k);
- assert(k->payload_type == KDBUS_PAYLOAD_DBUS);
+ /* The higher 32bit of both flags fields are considered
+ * 'incompatible flags'. Refuse them all for now. */
+ if (hello->bus_flags > 0xFFFFFFFFULL ||
+ hello->conn_flags > 0xFFFFFFFFULL)
+ return -ENOTSUP;
- KDBUS_ITEM_FOREACH(d, k, items) {
- size_t l;
+ if (hello->bloom_size != BLOOM_SIZE)
+ return -ENOTSUP;
- l = d->size - offsetof(struct kdbus_item, data);
+ if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
+ return -ENOMEM;
- switch (d->type) {
+ b->unique_id = hello->id;
- case KDBUS_ITEM_PAYLOAD_OFF:
- if (!h) {
- h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
+ b->is_kernel = true;
+ b->bus_client = true;
+ b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
+ b->message_version = 2;
+ b->message_endian = BUS_NATIVE_ENDIAN;
- if (!bus_header_is_complete(h, d->vec.size))
- return -EBADMSG;
- }
+ /* the kernel told us the UUID of the underlying bus */
+ memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
- n_bytes += d->vec.size;
- break;
+ return bus_start_running(b);
+}
- case KDBUS_ITEM_PAYLOAD_MEMFD:
- if (!h)
- return -EBADMSG;
+int bus_kernel_connect(sd_bus *b) {
+ assert(b);
+ assert(b->input_fd < 0);
+ assert(b->output_fd < 0);
+ assert(b->kernel);
- n_bytes += d->memfd.size;
- break;
+ if (b->is_server)
+ return -EINVAL;
- case KDBUS_ITEM_FDS: {
- int *f;
- unsigned j;
+ b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (b->input_fd < 0)
+ return -errno;
- j = l / sizeof(int);
- f = realloc(fds, sizeof(int) * (n_fds + j));
- if (!f)
- return -ENOMEM;
+ b->output_fd = b->input_fd;
- fds = f;
- memcpy(fds + n_fds, d->fds, sizeof(int) * j);
- n_fds += j;
- break;
- }
+ return bus_kernel_take_fd(b);
+}
- case KDBUS_ITEM_SECLABEL:
- seclabel = d->str;
- break;
- }
- }
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
+ int r;
- if (!h)
- return -EBADMSG;
+ assert(bus);
+ assert(m);
+ assert(bus->state == BUS_RUNNING);
- r = bus_header_message_size(h, &total);
+ /* If we can't deliver, we want room for the error message */
+ r = bus_rqueue_make_room(bus);
if (r < 0)
return r;
- if (n_bytes != total)
- return -EBADMSG;
-
- /* on kdbus we only speak native endian gvariant, never dbus1
- * marshalling or reverse endian */
- if (h->version != 2 ||
- h->endian != BUS_NATIVE_ENDIAN)
- return -EPROTOTYPE;
-
- r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
+ r = bus_message_setup_kmsg(bus, m);
if (r < 0)
return r;
- /* The well-known names list is different from the other
- credentials. If we asked for it, but nothing is there, this
- means that the list of well-known names is simply empty, not
- that we lack any data */
-
- m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+ 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;
+ sd_bus_message *reply;
- KDBUS_ITEM_FOREACH(d, k, items) {
- size_t l;
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+ else if (errno == ENXIO || errno == ESRCH) {
- l = d->size - offsetof(struct kdbus_item, data);
+ /* ENXIO: unique name not known
+ * ESRCH: well-known name not known */
- switch (d->type) {
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+ sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
+ else {
+ log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
+ return 0;
+ }
- case KDBUS_ITEM_PAYLOAD_OFF: {
- size_t begin_body;
+ } else if (errno == EADDRNOTAVAIL) {
- begin_body = BUS_MESSAGE_BODY_BEGIN(m);
+ /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
- if (idx + d->vec.size > begin_body) {
- struct bus_body_part *part;
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+ sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
+ else {
+ log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
+ return 0;
+ }
+ } else
+ return -errno;
- /* Contains body material */
+ r = bus_message_new_synthetic_error(
+ bus,
+ BUS_MESSAGE_COOKIE(m),
+ &error,
+ &reply);
- part = message_append_part(m);
- if (!part) {
- r = -ENOMEM;
- goto fail;
- }
+ if (r < 0)
+ return r;
- /* A -1 offset is NUL padding. */
- part->is_zero = d->vec.offset == ~0ULL;
+ r = bus_seal_synthetic_message(bus, reply);
+ if (r < 0)
+ return r;
- if (idx >= begin_body) {
- if (!part->is_zero)
- part->data = (uint8_t *)k + d->vec.offset;
- part->size = d->vec.size;
- } else {
- if (!part->is_zero)
- part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
- part->size = d->vec.size - (begin_body - idx);
- }
+ bus->rqueue[bus->rqueue_size++] = reply;
- part->sealed = true;
- }
+ return 0;
+ }
- idx += d->vec.size;
- break;
- }
+ return 1;
+}
- case KDBUS_ITEM_PAYLOAD_MEMFD: {
- struct bus_body_part *part;
+static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
+ uint64_t off;
+ struct kdbus_item *d;
- if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
- r = -EBADMSG;
- goto fail;
- }
+ assert(bus);
+ assert(k);
- part = message_append_part(m);
- if (!part) {
- r = -ENOMEM;
- goto fail;
- }
+ off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
+ ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
- part->memfd = d->memfd.fd;
- part->size = d->memfd.size;
- part->sealed = true;
+ KDBUS_ITEM_FOREACH(d, k, items) {
- idx += d->memfd.size;
- break;
- }
+ 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);
+ }
+}
- case KDBUS_ITEM_CREDS:
- /* UID/GID/PID are always valid */
- m->creds.uid = (uid_t) d->creds.uid;
- m->creds.gid = (gid_t) d->creds.gid;
- m->creds.pid = (pid_t) d->creds.pid;
- m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
+static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
- /* The PID starttime/TID might be missing
- * however, when the data is faked by some
- * data bus proxy and it lacks that
- * information about the real client since
- * SO_PEERCRED is used for that */
+ assert(bus);
- if (d->creds.starttime > 0) {
- m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
- m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
- }
+ r = sd_bus_message_new_signal(
+ bus,
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameOwnerChanged",
+ &m);
+ if (r < 0)
+ return r;
- if (d->creds.tid > 0) {
- m->creds.tid = (pid_t) d->creds.tid;
- m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
- }
- break;
+ r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
+ if (r < 0)
+ return r;
- case KDBUS_ITEM_TIMESTAMP:
- m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
- m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
- break;
+ m->sender = "org.freedesktop.DBus";
- case KDBUS_ITEM_PID_COMM:
- m->creds.comm = d->str;
- m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
- break;
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
- case KDBUS_ITEM_TID_COMM:
- m->creds.tid_comm = d->str;
- m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
- break;
+ bus->rqueue[bus->rqueue_size++] = m;
+ m = NULL;
- case KDBUS_ITEM_EXE:
- m->creds.exe = d->str;
- m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
- break;
+ return 1;
+}
- case KDBUS_ITEM_CMDLINE:
- m->creds.cmdline = d->str;
- m->creds.cmdline_size = l;
- m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
- break;
+static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+ char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
- case KDBUS_ITEM_CGROUP:
- m->creds.cgroup = d->str;
- m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
+ assert(bus);
+ assert(k);
+ assert(d);
- if (!bus->cgroup_root) {
- r = cg_get_root_path(&bus->cgroup_root);
- if (r < 0)
- goto fail;
- }
+ if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
+ old_owner[0] = 0;
+ else
+ sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id);
- m->creds.cgroup_root = bus->cgroup_root;
+ if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
- break;
+ if (isempty(old_owner))
+ return 0;
- case KDBUS_ITEM_AUDIT:
- m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
- m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
- m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
- break;
+ new_owner[0] = 0;
+ } else
+ sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id);
- case KDBUS_ITEM_CAPS:
- m->creds.capability = d->data;
- m->creds.capability_size = l;
- m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
- break;
+ return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
+}
- case KDBUS_ITEM_DST_NAME:
- if (!service_name_is_valid(d->str))
- return -EBADMSG;
+static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+ char owner[UNIQUE_NAME_MAX];
- destination = d->str;
- break;
+ assert(bus);
+ assert(k);
+ assert(d);
- case KDBUS_ITEM_NAME:
- if (!service_name_is_valid(d->name.name))
- return -EBADMSG;
+ sprintf(owner, ":1.%llu", d->id_change.id);
- r = strv_extend(&m->creds.well_known_names, d->name.name);
- if (r < 0)
- goto fail;
- break;
+ return push_name_owner_changed(
+ bus, owner,
+ d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
+ d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
+}
- case KDBUS_ITEM_FDS:
- case KDBUS_ITEM_SECLABEL:
- break;
+static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
- default:
- log_debug("Got unknown field from kernel %llu", d->type);
- }
- }
+ assert(bus);
+ assert(k);
+ assert(d);
- r = bus_message_parse_fields(m);
+ r = bus_message_new_synthetic_error(
+ bus,
+ k->cookie_reply,
+ d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
+ &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
+ &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
+ &m);
if (r < 0)
- goto fail;
-
- /* Override information from the user header with data from the kernel */
- if (k->src_id == KDBUS_SRC_ID_KERNEL)
- m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
- else {
- snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
- m->sender = m->creds.unique_name = m->sender_buffer;
- }
+ return r;
- if (destination)
- m->destination = destination;
- else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
- m->destination = NULL;
- else if (k->dst_id == KDBUS_DST_ID_NAME)
- m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
- else {
- snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
- m->destination = m->destination_buffer;
- }
+ m->sender = "org.freedesktop.DBus";
- /* We take possession of the kmsg struct now */
- m->kdbus = k;
- m->release_kdbus = true;
- m->free_fds = true;
- fds = NULL;
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
bus->rqueue[bus->rqueue_size++] = m;
+ m = NULL;
return 1;
+}
-fail:
- if (m) {
- struct bus_body_part *part;
- unsigned i;
+static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
+ struct kdbus_item *d, *found = NULL;
- /* Make sure the memfds are not freed twice */
- MESSAGE_FOREACH_PART(part, i, m)
- if (part->memfd >= 0)
- part->memfd = -1;
+ static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
+ [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
- sd_bus_message_unref(m);
+ [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+ [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+
+ [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+ [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+ };
+
+ assert(bus);
+ assert(k);
+ assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
+ if (found)
+ return -EBADMSG;
+ found = d;
+ } else
+ log_debug("Got unknown field from kernel %llu", d->type);
}
- return r;
+ if (!found) {
+ log_debug("Didn't find a kernel message to translate.");
+ return 0;
+ }
+
+ return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
}
int bus_kernel_read_message(sd_bus *bus) {
More information about the systemd-commits
mailing list