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;
91 r = parse_unique_name(m->destination, &unique);
99 sz = offsetof(struct kdbus_msg, data);
101 /* Add in fixed header, fields header, fields header padding and payload */
102 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
104 /* Add in well-known destination header */
106 dl = strlen(m->destination);
107 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
110 m->kdbus = malloc0(sz);
115 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
116 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
119 m->destination ? unique : (uint64_t) -1;
120 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
121 m->kdbus->cookie = m->header->serial;
123 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
128 append_destination(&d, m->destination, dl);
130 append_payload_vec(&d, m->header, sizeof(*m->header));
133 append_payload_vec(&d, m->fields, m->header->fields_size);
135 if (m->header->fields_size % 8 != 0) {
136 static const uint8_t padding[7] = {};
138 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
143 append_payload_vec(&d, m->body, m->header->body_size);
145 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
146 assert(m->kdbus->size <= sz);
148 m->free_kdbus = true;
153 int bus_kernel_take_fd(sd_bus *b) {
154 struct kdbus_cmd_hello hello = {};
159 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
163 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
168 r = bus_start_running(b);
175 int bus_kernel_connect(sd_bus *b) {
177 assert(b->input_fd < 0);
178 assert(b->output_fd < 0);
181 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
185 b->output_fd = b->input_fd;
187 return bus_kernel_take_fd(b);
190 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
195 assert(bus->state == BUS_RUNNING);
197 r = bus_message_setup_kmsg(m);
201 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
203 return errno == EAGAIN ? 0 : -errno;
208 static void close_kdbus_msg(struct kdbus_msg *k) {
209 struct kdbus_msg_data *d;
211 KDBUS_MSG_FOREACH_DATA(d, k) {
213 if (d->type != KDBUS_MSG_UNIX_FDS)
216 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
220 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
221 sd_bus_message *m = NULL;
222 struct kdbus_msg_data *d;
223 unsigned n_payload = 0, n_fds = 0;
224 _cleanup_free_ int *fds = NULL;
225 struct bus_header *h = NULL;
226 size_t total, n_bytes = 0, idx = 0;
227 struct kdbus_creds *creds = NULL;
234 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
237 KDBUS_MSG_FOREACH_DATA(d, k) {
240 l = d->size - offsetof(struct kdbus_msg_data, data);
242 if (d->type == KDBUS_MSG_PAYLOAD) {
245 if (l < sizeof(struct bus_header))
248 h = (struct bus_header*) d->data;
254 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
259 f = realloc(fds, sizeof(int) * (n_fds + j));
264 memcpy(fds + n_fds, d->fds, j);
267 } else if (d->type == KDBUS_MSG_SRC_CREDS)
274 r = bus_header_size(h, &total);
278 if (n_bytes != total)
281 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
285 KDBUS_MSG_FOREACH_DATA(d, k) {
288 if (d->type != KDBUS_MSG_PAYLOAD)
291 l = d->size - offsetof(struct kdbus_msg_data, data);
292 if (idx == sizeof(struct bus_header) &&
293 l == BUS_MESSAGE_FIELDS_SIZE(m))
295 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
296 l == BUS_MESSAGE_BODY_SIZE(m))
298 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
299 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
300 sd_bus_message_unref(m);
308 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
313 m->uid_valid = m->gid_valid = true;
316 r = bus_message_parse_fields(m);
318 sd_bus_message_unref(m);
322 /* We take possession of the kmsg struct now */
324 m->free_kdbus = true;
333 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
344 q = realloc(bus->rbuffer, sz);
348 k = bus->rbuffer = q;
351 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
358 if (errno != ENOBUFS)
364 r = bus_kernel_make_message(bus, k, m);
373 int bus_kernel_create(const char *name, char **s) {
374 struct kdbus_cmd_fname *fname;
382 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
387 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
388 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
389 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
390 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD;
391 fname->user_flags = 0;
393 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
397 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
398 close_nointr_nofail(fd);