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);
159 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
164 r = bus_start_running(b);
171 int bus_kernel_connect(sd_bus *b) {
173 assert(b->input_fd < 0);
174 assert(b->output_fd < 0);
177 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
181 b->output_fd = b->input_fd;
183 return bus_kernel_take_fd(b);
186 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
191 assert(bus->state == BUS_RUNNING);
193 r = bus_message_setup_kmsg(m);
197 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
199 return errno == EAGAIN ? 0 : -errno;
204 static void close_kdbus_msg(struct kdbus_msg *k) {
205 struct kdbus_msg_data *d;
207 KDBUS_MSG_FOREACH_DATA(d, k) {
209 if (d->type != KDBUS_MSG_UNIX_FDS)
212 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
216 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
217 sd_bus_message *m = NULL;
218 struct kdbus_msg_data *d;
219 unsigned n_payload = 0, n_fds = 0;
220 _cleanup_free_ int *fds = NULL;
221 struct bus_header *h = NULL;
222 size_t total, n_bytes = 0, idx = 0;
229 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
232 KDBUS_MSG_FOREACH_DATA(d, k) {
235 l = d->size - offsetof(struct kdbus_msg_data, data);
237 if (d->type == KDBUS_MSG_PAYLOAD) {
240 if (l < sizeof(struct bus_header))
243 h = (struct bus_header*) d->data;
249 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
254 f = realloc(fds, sizeof(int) * (n_fds + j));
259 memcpy(fds + n_fds, d->fds, j);
267 r = bus_header_size(h, &total);
271 if (n_bytes != total)
274 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
278 KDBUS_MSG_FOREACH_DATA(d, k) {
281 if (d->type != KDBUS_MSG_PAYLOAD)
284 l = d->size - offsetof(struct kdbus_msg_data, data);
286 if (idx == sizeof(struct bus_header) &&
287 l == BUS_MESSAGE_FIELDS_SIZE(m))
289 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
290 l == BUS_MESSAGE_BODY_SIZE(m))
293 sd_bus_message_unref(m);
300 r = bus_message_parse_fields(m);
302 sd_bus_message_unref(m);
306 /* We take possession of the kmsg struct now */
308 m->free_kdbus = true;
317 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
328 q = realloc(bus->rbuffer, sz);
332 k = bus->rbuffer = q;
335 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
342 if (errno != -EMSGSIZE)
348 r = bus_kernel_make_message(bus, k, m);
357 int bus_kernel_create(const char *name, char **s) {
358 struct kdbus_cmd_fname *fname;
366 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
371 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
372 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
373 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
374 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD;
375 fname->user_flags = 0;
377 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
381 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
382 close_nointr_nofail(fd);