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);
121 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
122 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
125 m->destination ? unique : (uint64_t) -1;
126 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
127 m->kdbus->cookie = m->header->serial;
129 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
134 append_destination(&d, m->destination, dl);
136 append_payload_vec(&d, m->header, sizeof(*m->header));
139 append_payload_vec(&d, m->fields, m->header->fields_size);
141 if (m->header->fields_size % 8 != 0) {
142 static const uint8_t padding[7] = {};
144 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
149 append_payload_vec(&d, m->body, m->header->body_size);
151 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
152 assert(m->kdbus->size <= sz);
154 m->free_kdbus = true;
159 int bus_kernel_take_fd(sd_bus *b) {
160 struct kdbus_cmd_hello hello = {};
168 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
172 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
176 b->bus_client = true;
178 r = bus_start_running(b);
185 int bus_kernel_connect(sd_bus *b) {
187 assert(b->input_fd < 0);
188 assert(b->output_fd < 0);
194 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
198 b->output_fd = b->input_fd;
200 return bus_kernel_take_fd(b);
203 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
208 assert(bus->state == BUS_RUNNING);
210 r = bus_message_setup_kmsg(m);
214 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
216 return errno == EAGAIN ? 0 : -errno;
221 static void close_kdbus_msg(struct kdbus_msg *k) {
222 struct kdbus_msg_data *d;
224 KDBUS_MSG_FOREACH_DATA(d, k) {
226 if (d->type != KDBUS_MSG_UNIX_FDS)
229 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
233 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
234 sd_bus_message *m = NULL;
235 struct kdbus_msg_data *d;
236 unsigned n_payload = 0, n_fds = 0;
237 _cleanup_free_ int *fds = NULL;
238 struct bus_header *h = NULL;
239 size_t total, n_bytes = 0, idx = 0;
240 struct kdbus_creds *creds = NULL;
242 const char *destination = NULL;
249 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
252 KDBUS_MSG_FOREACH_DATA(d, k) {
255 l = d->size - offsetof(struct kdbus_msg_data, data);
257 if (d->type == KDBUS_MSG_PAYLOAD) {
260 if (l < sizeof(struct bus_header))
263 h = (struct bus_header*) d->data;
269 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
274 f = realloc(fds, sizeof(int) * (n_fds + j));
279 memcpy(fds + n_fds, d->fds, j);
282 } else if (d->type == KDBUS_MSG_SRC_CREDS)
284 else if (d->type == KDBUS_MSG_TIMESTAMP)
286 else if (d->type == KDBUS_MSG_DST_NAME)
287 destination = d->str;
293 r = bus_header_size(h, &total);
297 if (n_bytes != total)
300 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
304 KDBUS_MSG_FOREACH_DATA(d, k) {
307 if (d->type != KDBUS_MSG_PAYLOAD)
310 l = d->size - offsetof(struct kdbus_msg_data, data);
311 if (idx == sizeof(struct bus_header) &&
312 l == BUS_MESSAGE_FIELDS_SIZE(m))
314 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
315 l == BUS_MESSAGE_BODY_SIZE(m))
317 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
318 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
319 sd_bus_message_unref(m);
327 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
332 m->uid_valid = m->gid_valid = true;
335 m->timestamp = nsec / NSEC_PER_USEC;
337 r = bus_message_parse_fields(m);
339 sd_bus_message_unref(m);
343 if (k->src_id == KDBUS_SRC_ID_KERNEL)
344 m->sender = "org.freedesktop.DBus";
346 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
347 m->sender = m->sender_buffer;
350 if (!m->destination) {
352 m->destination = destination;
353 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
354 k->dst_id != KDBUS_DST_ID_BROADCAST) {
355 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
356 m->destination = m->destination_buffer;
360 /* We take possession of the kmsg struct now */
362 m->free_kdbus = true;
371 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
382 q = aligned_alloc(8, sz);
387 k = bus->rbuffer = q;
390 /* Let's tell valgrind that there's really no need to
391 * initialize this fully. This should be removed again
392 * when valgrind learned the kdbus ioctls natively. */
393 #ifdef HAVE_VALGRIND_MEMCHECK_H
394 VALGRIND_MAKE_MEM_DEFINED(k, sz);
397 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
404 if (errno != ENOBUFS)
410 r = bus_kernel_make_message(bus, k, m);
416 return r < 0 ? r : 1;
419 int bus_kernel_create(const char *name, char **s) {
420 struct kdbus_cmd_fname *fname;
428 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
433 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
434 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
435 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
436 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD | KDBUS_CMD_FNAME_POLICY_OPEN;
437 fname->user_flags = 0;
439 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
443 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
444 close_nointr_nofail(fd);