1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
30 #include "bus-internal.h"
31 #include "bus-message.h"
32 #include "bus-kernel.h"
34 #define KDBUS_MSG_FOREACH_DATA(d, k) \
35 for ((d) = (k)->data; \
36 (uint8_t*) (d) < (uint8_t*) (k) + (k)->size; \
37 (d) = (struct kdbus_msg_data*) ((uint8_t*) (d) + ALIGN8((d)->size)))
39 static int parse_unique_name(const char *s, uint64_t *id) {
45 if (!startswith(s, ":1."))
48 r = safe_atou64(s + 3, id);
55 static void append_payload_vec(struct kdbus_msg_data **d, const void *p, size_t sz) {
62 (*d)->size = offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec);
63 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
64 (*d)->vec.address = (uint64_t) p;
67 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + (*d)->size);
70 static void append_destination(struct kdbus_msg_data **d, const char *s, size_t length) {
76 (*d)->size = offsetof(struct kdbus_msg_data, str) + length + 1;
77 (*d)->type = KDBUS_MSG_DST_NAME;
78 memcpy((*d)->str, s, length + 1);
80 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + (*d)->size);
83 static void append_bloom(struct kdbus_msg_data **d, const void *p, size_t length) {
89 (*d)->size = offsetof(struct kdbus_msg_data, data) + length;
90 (*d)->type = KDBUS_MSG_BLOOM;
91 memcpy((*d)->data, p, length);
93 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + (*d)->size);
96 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
97 struct kdbus_msg_data *d;
110 if (m->destination) {
111 r = parse_unique_name(m->destination, &unique);
119 sz = offsetof(struct kdbus_msg, data);
121 /* Add in fixed header, fields header, fields header padding and payload */
122 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
124 sz += ALIGN8(offsetof(struct kdbus_msg_data, data) + b->bloom_size);
126 /* Add in well-known destination header */
128 dl = strlen(m->destination);
129 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
132 m->kdbus = aligned_alloc(8, sz);
136 memset(m->kdbus, 0, sz);
139 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
140 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
143 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
144 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
145 m->kdbus->cookie = m->header->serial;
147 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
152 append_destination(&d, m->destination, dl);
154 append_payload_vec(&d, m->header, sizeof(*m->header));
157 append_payload_vec(&d, m->fields, m->header->fields_size);
159 if (m->header->fields_size % 8 != 0) {
160 static const uint8_t padding[7] = {};
162 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
167 append_payload_vec(&d, m->body, m->header->body_size);
169 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
172 /* For now, let's add a mask all bloom filter */
173 p = alloca(b->bloom_size);
174 memset(p, 0xFF, b->bloom_size);
175 append_bloom(&d, p, b->bloom_size);
178 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
179 assert(m->kdbus->size <= sz);
181 m->free_kdbus = true;
186 int bus_kernel_take_fd(sd_bus *b) {
187 struct kdbus_cmd_hello hello = {};
195 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
199 /* The higher 32bit of both flags fields are considered
200 * 'incompatible flags'. Refuse them all for now. */
201 if (hello.bus_flags > 0xFFFFFFFFULL ||
202 hello.conn_flags > 0xFFFFFFFFULL)
205 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
208 b->bloom_size = hello.bloom_size;
210 b->bus_client = true;
212 r = bus_start_running(b);
219 int bus_kernel_connect(sd_bus *b) {
221 assert(b->input_fd < 0);
222 assert(b->output_fd < 0);
228 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
232 b->output_fd = b->input_fd;
234 return bus_kernel_take_fd(b);
237 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
242 assert(bus->state == BUS_RUNNING);
244 r = bus_message_setup_kmsg(bus, m);
248 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
250 return errno == EAGAIN ? 0 : -errno;
255 static void close_kdbus_msg(struct kdbus_msg *k) {
256 struct kdbus_msg_data *d;
258 KDBUS_MSG_FOREACH_DATA(d, k) {
260 if (d->type != KDBUS_MSG_UNIX_FDS)
263 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
267 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
268 sd_bus_message *m = NULL;
269 struct kdbus_msg_data *d;
270 unsigned n_payload = 0, n_fds = 0;
271 _cleanup_free_ int *fds = NULL;
272 struct bus_header *h = NULL;
273 size_t total, n_bytes = 0, idx = 0;
274 struct kdbus_creds *creds = NULL;
276 const char *destination = NULL;
283 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
286 KDBUS_MSG_FOREACH_DATA(d, k) {
289 l = d->size - offsetof(struct kdbus_msg_data, data);
291 if (d->type == KDBUS_MSG_PAYLOAD) {
294 if (l < sizeof(struct bus_header))
297 h = (struct bus_header*) d->data;
303 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
308 f = realloc(fds, sizeof(int) * (n_fds + j));
313 memcpy(fds + n_fds, d->fds, j);
316 } else if (d->type == KDBUS_MSG_SRC_CREDS)
318 else if (d->type == KDBUS_MSG_TIMESTAMP)
320 else if (d->type == KDBUS_MSG_DST_NAME)
321 destination = d->str;
327 r = bus_header_size(h, &total);
331 if (n_bytes != total)
334 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
338 KDBUS_MSG_FOREACH_DATA(d, k) {
341 if (d->type != KDBUS_MSG_PAYLOAD)
344 l = d->size - offsetof(struct kdbus_msg_data, data);
345 if (idx == sizeof(struct bus_header) &&
346 l == BUS_MESSAGE_FIELDS_SIZE(m))
348 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
349 l == BUS_MESSAGE_BODY_SIZE(m))
351 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
352 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
353 sd_bus_message_unref(m);
361 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
366 m->uid_valid = m->gid_valid = true;
369 m->timestamp = nsec / NSEC_PER_USEC;
371 r = bus_message_parse_fields(m);
373 sd_bus_message_unref(m);
377 if (k->src_id == KDBUS_SRC_ID_KERNEL)
378 m->sender = "org.freedesktop.DBus";
380 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
381 m->sender = m->sender_buffer;
384 if (!m->destination) {
386 m->destination = destination;
387 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
388 k->dst_id != KDBUS_DST_ID_BROADCAST) {
389 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
390 m->destination = m->destination_buffer;
394 /* We take possession of the kmsg struct now */
396 m->free_kdbus = true;
405 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
416 q = aligned_alloc(8, sz);
421 k = bus->rbuffer = q;
424 /* Let's tell valgrind that there's really no need to
425 * initialize this fully. This should be removed again
426 * when valgrind learned the kdbus ioctls natively. */
427 #ifdef HAVE_VALGRIND_MEMCHECK_H
428 VALGRIND_MAKE_MEM_DEFINED(k, sz);
431 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
438 if (errno != ENOBUFS)
444 r = bus_kernel_make_message(bus, k, m);
450 return r < 0 ? r : 1;
453 int bus_kernel_create(const char *name, char **s) {
454 struct kdbus_cmd_bus_make *make;
462 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
467 make = alloca(offsetof(struct kdbus_cmd_bus_make, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
468 sprintf(make->name, "%lu-%s", (unsigned long) getuid(), name);
469 make->size = offsetof(struct kdbus_cmd_bus_make, name) + strlen(make->name) + 1;
470 make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
472 make->bloom_size = 16;
474 p = strjoin("/dev/kdbus/", make->name, "/bus", NULL);
478 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
479 close_nointr_nofail(fd);