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/>.
26 #include "bus-internal.h"
27 #include "bus-message.h"
28 #include "bus-kernel.h"
30 #define KDBUS_MSG_FOREACH_DATA(d, k) \
31 for ((d) = (k)->data; \
32 (uint8_t*) (d) < (uint8_t*) (k) + (k)->size; \
33 (d) = (struct kdbus_msg_data*) ((uint8_t*) (d) + ALIGN8((d)->size)))
37 static int parse_unique_name(const char *s, uint64_t *id) {
43 if (!startswith(s, ":1."))
46 r = safe_atou64(s + 3, id);
53 static void append_payload_vec(struct kdbus_msg_data **d, const void *p, size_t sz) {
58 (*d)->size = offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec);
59 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
60 (*d)->vec.address = (uint64_t) p;
63 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
66 static void append_destination(struct kdbus_msg_data **d, const char *s, size_t length) {
70 (*d)->size = offsetof(struct kdbus_msg_data, data) + length + 1;
71 (*d)->type = KDBUS_MSG_DST_NAME;
72 memcpy((*d)->data, s, length + 1);
74 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
77 static int bus_message_setup_kmsg(sd_bus_message *m) {
78 struct kdbus_msg_data *d;
89 r = parse_unique_name(m->destination, &unique);
97 sz = offsetof(struct kdbus_msg, data);
99 /* Add in fixed header, fields header, fields header padding and payload */
100 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
102 /* Add in well-known destination header */
104 dl = strlen(m->destination);
105 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
108 m->kdbus = malloc0(sz);
113 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
114 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
117 m->destination ? unique : (uint64_t) -1;
118 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
119 m->kdbus->cookie = m->header->serial;
121 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
126 append_destination(&d, m->destination, dl);
128 append_payload_vec(&d, m->header, sizeof(*m->header));
131 append_payload_vec(&d, m->fields, m->header->fields_size);
133 if (m->header->fields_size % 8 != 0) {
134 static const uint8_t padding[7] = {};
136 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
141 append_payload_vec(&d, m->body, m->header->body_size);
143 m->kdbus->size = (uint8_t*) m - (uint8_t*) m->kdbus;
144 assert(m->kdbus->size <= sz);
149 int bus_kernel_take_fd(sd_bus *b) {
150 struct kdbus_cmd_hello hello = {};
155 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
161 r = bus_start_running(b);
168 int bus_kernel_connect(sd_bus *b) {
170 assert(b->input_fd < 0);
171 assert(b->output_fd < 0);
174 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
178 b->output_fd = b->input_fd;
180 return bus_kernel_take_fd(b);
183 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
188 assert(bus->state == BUS_RUNNING);
190 r = bus_message_setup_kmsg(m);
194 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
196 return errno == EAGAIN ? 0 : -errno;
201 static void close_kdbus_msg(struct kdbus_msg *k) {
202 struct kdbus_msg_data *d;
204 KDBUS_MSG_FOREACH_DATA(d, k) {
206 if (d->type != KDBUS_MSG_UNIX_FDS)
209 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
213 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
214 sd_bus_message *m = NULL;
215 struct kdbus_msg_data *d;
216 unsigned n_payload = 0, n_fds = 0;
217 _cleanup_free_ int *fds = NULL;
218 struct bus_header *h = NULL;
219 size_t total, n_bytes = 0, idx = 0;
226 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
229 KDBUS_MSG_FOREACH_DATA(d, k) {
232 l = d->size - offsetof(struct kdbus_msg_data, data);
234 if (d->type == KDBUS_MSG_PAYLOAD) {
237 if (l < sizeof(struct bus_header))
240 h = (struct bus_header*) d->data;
246 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
251 f = realloc(fds, sizeof(int) * (n_fds + j));
256 memcpy(fds + n_fds, d->fds, j);
264 r = bus_header_size(h, &total);
268 if (n_bytes != total)
271 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
275 KDBUS_MSG_FOREACH_DATA(d, k) {
278 if (d->type != KDBUS_MSG_PAYLOAD)
281 l = d->size - offsetof(struct kdbus_msg_data, data);
283 if (idx == sizeof(struct bus_header) &&
284 l == BUS_MESSAGE_FIELDS_SIZE(m))
286 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
287 l == BUS_MESSAGE_BODY_SIZE(m))
290 sd_bus_message_unref(m);
297 r = bus_message_parse_fields(m);
299 sd_bus_message_unref(m);
303 /* We take possession of the kmsg struct now */
305 m->free_kdbus = true;
314 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
325 q = realloc(bus->rbuffer, sz);
329 k = bus->rbuffer = q;
332 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
339 if (errno != -EMSGSIZE)
345 r = bus_kernel_make_message(bus, k, m);
354 int bus_kernel_create(const char *name, char **s) {
355 struct kdbus_cmd_fname *fname;
363 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
368 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
369 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
370 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
371 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD;
372 fname->user_flags = 0;
374 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
378 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, &fname) < 0) {
379 close_nointr_nofail(fd);