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 int bus_message_setup_kmsg(sd_bus_message *m) {
84 struct kdbus_msg_data *d;
97 r = parse_unique_name(m->destination, &unique);
105 sz = offsetof(struct kdbus_msg, data);
107 /* Add in fixed header, fields header, fields header padding and payload */
108 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
110 /* Add in well-known destination header */
112 dl = strlen(m->destination);
113 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
116 m->kdbus = aligned_alloc(8, sz);
120 memset(m->kdbus, 0, sz);
123 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
124 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
127 m->destination ? unique : (uint64_t) -1;
128 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
129 m->kdbus->cookie = m->header->serial;
131 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
136 append_destination(&d, m->destination, dl);
138 append_payload_vec(&d, m->header, sizeof(*m->header));
141 append_payload_vec(&d, m->fields, m->header->fields_size);
143 if (m->header->fields_size % 8 != 0) {
144 static const uint8_t padding[7] = {};
146 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
151 append_payload_vec(&d, m->body, m->header->body_size);
153 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
154 assert(m->kdbus->size <= sz);
156 m->free_kdbus = true;
161 int bus_kernel_take_fd(sd_bus *b) {
162 struct kdbus_cmd_hello hello = {};
170 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
174 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
178 b->bus_client = true;
180 r = bus_start_running(b);
187 int bus_kernel_connect(sd_bus *b) {
189 assert(b->input_fd < 0);
190 assert(b->output_fd < 0);
196 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
200 b->output_fd = b->input_fd;
202 return bus_kernel_take_fd(b);
205 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
210 assert(bus->state == BUS_RUNNING);
212 r = bus_message_setup_kmsg(m);
216 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
218 return errno == EAGAIN ? 0 : -errno;
223 static void close_kdbus_msg(struct kdbus_msg *k) {
224 struct kdbus_msg_data *d;
226 KDBUS_MSG_FOREACH_DATA(d, k) {
228 if (d->type != KDBUS_MSG_UNIX_FDS)
231 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
235 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
236 sd_bus_message *m = NULL;
237 struct kdbus_msg_data *d;
238 unsigned n_payload = 0, n_fds = 0;
239 _cleanup_free_ int *fds = NULL;
240 struct bus_header *h = NULL;
241 size_t total, n_bytes = 0, idx = 0;
242 struct kdbus_creds *creds = NULL;
244 const char *destination = NULL;
251 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
254 KDBUS_MSG_FOREACH_DATA(d, k) {
257 l = d->size - offsetof(struct kdbus_msg_data, data);
259 if (d->type == KDBUS_MSG_PAYLOAD) {
262 if (l < sizeof(struct bus_header))
265 h = (struct bus_header*) d->data;
271 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
276 f = realloc(fds, sizeof(int) * (n_fds + j));
281 memcpy(fds + n_fds, d->fds, j);
284 } else if (d->type == KDBUS_MSG_SRC_CREDS)
286 else if (d->type == KDBUS_MSG_TIMESTAMP)
288 else if (d->type == KDBUS_MSG_DST_NAME)
289 destination = d->str;
295 r = bus_header_size(h, &total);
299 if (n_bytes != total)
302 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
306 KDBUS_MSG_FOREACH_DATA(d, k) {
309 if (d->type != KDBUS_MSG_PAYLOAD)
312 l = d->size - offsetof(struct kdbus_msg_data, data);
313 if (idx == sizeof(struct bus_header) &&
314 l == BUS_MESSAGE_FIELDS_SIZE(m))
316 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
317 l == BUS_MESSAGE_BODY_SIZE(m))
319 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
320 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
321 sd_bus_message_unref(m);
329 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
334 m->uid_valid = m->gid_valid = true;
337 m->timestamp = nsec / NSEC_PER_USEC;
339 r = bus_message_parse_fields(m);
341 sd_bus_message_unref(m);
345 if (k->src_id == KDBUS_SRC_ID_KERNEL)
346 m->sender = "org.freedesktop.DBus";
348 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
349 m->sender = m->sender_buffer;
352 if (!m->destination) {
354 m->destination = destination;
355 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
356 k->dst_id != KDBUS_DST_ID_BROADCAST) {
357 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
358 m->destination = m->destination_buffer;
362 /* We take possession of the kmsg struct now */
364 m->free_kdbus = true;
373 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
384 q = aligned_alloc(8, sz);
389 k = bus->rbuffer = q;
392 /* Let's tell valgrind that there's really no need to
393 * initialize this fully. This should be removed again
394 * when valgrind learned the kdbus ioctls natively. */
395 #ifdef HAVE_VALGRIND_MEMCHECK_H
396 VALGRIND_MAKE_MEM_DEFINED(k, sz);
399 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
406 if (errno != ENOBUFS)
412 r = bus_kernel_make_message(bus, k, m);
418 return r < 0 ? r : 1;
421 int bus_kernel_create(const char *name, char **s) {
422 struct kdbus_cmd_fname *fname;
430 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
435 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
436 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
437 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
438 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD | KDBUS_CMD_FNAME_POLICY_OPEN;
439 fname->user_flags = 0;
441 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
445 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
446 close_nointr_nofail(fd);