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_message *m) {
97 struct kdbus_msg_data *d;
109 if (m->destination) {
110 r = parse_unique_name(m->destination, &unique);
118 sz = offsetof(struct kdbus_msg, data);
120 /* Add in fixed header, fields header, fields header padding and payload */
121 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
123 sz += ALIGN8(offsetof(struct kdbus_msg_data, data) + 5);
125 /* Add in well-known destination header */
127 dl = strlen(m->destination);
128 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
131 m->kdbus = aligned_alloc(8, sz);
135 memset(m->kdbus, 0, sz);
138 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
139 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
142 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
143 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
144 m->kdbus->cookie = m->header->serial;
146 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
151 append_destination(&d, m->destination, dl);
153 append_payload_vec(&d, m->header, sizeof(*m->header));
156 append_payload_vec(&d, m->fields, m->header->fields_size);
158 if (m->header->fields_size % 8 != 0) {
159 static const uint8_t padding[7] = {};
161 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
166 append_payload_vec(&d, m->body, m->header->body_size);
168 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST)
169 append_bloom(&d, "bloom", 5);
171 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
172 assert(m->kdbus->size <= sz);
174 m->free_kdbus = true;
179 int bus_kernel_take_fd(sd_bus *b) {
180 struct kdbus_cmd_hello hello = {};
188 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
192 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
196 b->bus_client = true;
198 r = bus_start_running(b);
205 int bus_kernel_connect(sd_bus *b) {
207 assert(b->input_fd < 0);
208 assert(b->output_fd < 0);
214 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
218 b->output_fd = b->input_fd;
220 return bus_kernel_take_fd(b);
223 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
228 assert(bus->state == BUS_RUNNING);
230 r = bus_message_setup_kmsg(m);
234 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
236 return errno == EAGAIN ? 0 : -errno;
241 static void close_kdbus_msg(struct kdbus_msg *k) {
242 struct kdbus_msg_data *d;
244 KDBUS_MSG_FOREACH_DATA(d, k) {
246 if (d->type != KDBUS_MSG_UNIX_FDS)
249 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
253 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
254 sd_bus_message *m = NULL;
255 struct kdbus_msg_data *d;
256 unsigned n_payload = 0, n_fds = 0;
257 _cleanup_free_ int *fds = NULL;
258 struct bus_header *h = NULL;
259 size_t total, n_bytes = 0, idx = 0;
260 struct kdbus_creds *creds = NULL;
262 const char *destination = NULL;
269 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
272 KDBUS_MSG_FOREACH_DATA(d, k) {
275 l = d->size - offsetof(struct kdbus_msg_data, data);
277 if (d->type == KDBUS_MSG_PAYLOAD) {
280 if (l < sizeof(struct bus_header))
283 h = (struct bus_header*) d->data;
289 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
294 f = realloc(fds, sizeof(int) * (n_fds + j));
299 memcpy(fds + n_fds, d->fds, j);
302 } else if (d->type == KDBUS_MSG_SRC_CREDS)
304 else if (d->type == KDBUS_MSG_TIMESTAMP)
306 else if (d->type == KDBUS_MSG_DST_NAME)
307 destination = d->str;
313 r = bus_header_size(h, &total);
317 if (n_bytes != total)
320 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
324 KDBUS_MSG_FOREACH_DATA(d, k) {
327 if (d->type != KDBUS_MSG_PAYLOAD)
330 l = d->size - offsetof(struct kdbus_msg_data, data);
331 if (idx == sizeof(struct bus_header) &&
332 l == BUS_MESSAGE_FIELDS_SIZE(m))
334 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
335 l == BUS_MESSAGE_BODY_SIZE(m))
337 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
338 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
339 sd_bus_message_unref(m);
347 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
352 m->uid_valid = m->gid_valid = true;
355 m->timestamp = nsec / NSEC_PER_USEC;
357 r = bus_message_parse_fields(m);
359 sd_bus_message_unref(m);
363 if (k->src_id == KDBUS_SRC_ID_KERNEL)
364 m->sender = "org.freedesktop.DBus";
366 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
367 m->sender = m->sender_buffer;
370 if (!m->destination) {
372 m->destination = destination;
373 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
374 k->dst_id != KDBUS_DST_ID_BROADCAST) {
375 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
376 m->destination = m->destination_buffer;
380 /* We take possession of the kmsg struct now */
382 m->free_kdbus = true;
391 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
402 q = aligned_alloc(8, sz);
407 k = bus->rbuffer = q;
410 /* Let's tell valgrind that there's really no need to
411 * initialize this fully. This should be removed again
412 * when valgrind learned the kdbus ioctls natively. */
413 #ifdef HAVE_VALGRIND_MEMCHECK_H
414 VALGRIND_MAKE_MEM_DEFINED(k, sz);
417 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
424 if (errno != ENOBUFS)
430 r = bus_kernel_make_message(bus, k, m);
436 return r < 0 ? r : 1;
439 int bus_kernel_create(const char *name, char **s) {
440 struct kdbus_cmd_fname *fname;
448 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
453 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
454 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
455 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
456 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD | KDBUS_CMD_FNAME_POLICY_OPEN;
457 fname->user_flags = 0;
459 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
463 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
464 close_nointr_nofail(fd);