]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-kernel.c
bus: make kdbus work so that we can exchange real messages
[thirdparty/systemd.git] / src / libsystemd-bus / bus-kernel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <fcntl.h>
23
24 #include "util.h"
25
26 #include "bus-internal.h"
27 #include "bus-message.h"
28 #include "bus-kernel.h"
29
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)))
34
35
36
37 static int parse_unique_name(const char *s, uint64_t *id) {
38 int r;
39
40 assert(s);
41 assert(id);
42
43 if (!startswith(s, ":1."))
44 return 0;
45
46 r = safe_atou64(s + 3, id);
47 if (r < 0)
48 return r;
49
50 return 1;
51 }
52
53 static void append_payload_vec(struct kdbus_msg_data **d, const void *p, size_t sz) {
54 assert(d);
55 assert(p);
56 assert(sz > 0);
57
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;
61 (*d)->vec.size = sz;
62
63 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
64 }
65
66 static void append_destination(struct kdbus_msg_data **d, const char *s, size_t length) {
67 assert(d);
68 assert(d);
69
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);
73
74 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
75 }
76
77 static int bus_message_setup_kmsg(sd_bus_message *m) {
78 struct kdbus_msg_data *d;
79 bool well_known;
80 uint64_t unique;
81 size_t sz, dl;
82 int r;
83
84 assert(m);
85 assert(m->sealed);
86
87 if (m->kdbus)
88 return 0;
89
90 if (m->destination) {
91 r = parse_unique_name(m->destination, &unique);
92 if (r < 0)
93 return r;
94
95 well_known = r == 0;
96 } else
97 well_known = false;
98
99 sz = offsetof(struct kdbus_msg, data);
100
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));
103
104 /* Add in well-known destination header */
105 if (well_known) {
106 dl = strlen(m->destination);
107 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
108 }
109
110 m->kdbus = malloc0(sz);
111 if (!m->kdbus)
112 return -ENOMEM;
113
114 m->kdbus->flags =
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);
117 m->kdbus->dst_id =
118 well_known ? 0 :
119 m->destination ? unique : (uint64_t) -1;
120 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
121 m->kdbus->cookie = m->header->serial;
122
123 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
124
125 d = m->kdbus->data;
126
127 if (well_known)
128 append_destination(&d, m->destination, dl);
129
130 append_payload_vec(&d, m->header, sizeof(*m->header));
131
132 if (m->fields) {
133 append_payload_vec(&d, m->fields, m->header->fields_size);
134
135 if (m->header->fields_size % 8 != 0) {
136 static const uint8_t padding[7] = {};
137
138 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
139 }
140 }
141
142 if (m->body)
143 append_payload_vec(&d, m->body, m->header->body_size);
144
145 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
146 assert(m->kdbus->size <= sz);
147
148 m->free_kdbus = true;
149
150 return 0;
151 }
152
153 int bus_kernel_take_fd(sd_bus *b) {
154 struct kdbus_cmd_hello hello = {};
155 int r;
156
157 assert(b);
158
159 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
160 if (r < 0)
161 return -errno;
162
163 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
164 return -ENOMEM;
165
166 b->is_kernel = true;
167
168 r = bus_start_running(b);
169 if (r < 0)
170 return r;
171
172 return 1;
173 }
174
175 int bus_kernel_connect(sd_bus *b) {
176 assert(b);
177 assert(b->input_fd < 0);
178 assert(b->output_fd < 0);
179 assert(b->kernel);
180
181 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
182 if (b->input_fd < 0)
183 return -errno;
184
185 b->output_fd = b->input_fd;
186
187 return bus_kernel_take_fd(b);
188 }
189
190 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
191 int r;
192
193 assert(bus);
194 assert(m);
195 assert(bus->state == BUS_RUNNING);
196
197 r = bus_message_setup_kmsg(m);
198 if (r < 0)
199 return r;
200
201 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
202 if (r < 0)
203 return errno == EAGAIN ? 0 : -errno;
204
205 return 0;
206 }
207
208 static void close_kdbus_msg(struct kdbus_msg *k) {
209 struct kdbus_msg_data *d;
210
211 KDBUS_MSG_FOREACH_DATA(d, k) {
212
213 if (d->type != KDBUS_MSG_UNIX_FDS)
214 continue;
215
216 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
217 }
218 }
219
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 int r;
228
229 assert(bus);
230 assert(k);
231 assert(ret);
232
233 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
234 return 0;
235
236 KDBUS_MSG_FOREACH_DATA(d, k) {
237 size_t l;
238
239 l = d->size - offsetof(struct kdbus_msg_data, data);
240
241 if (d->type == KDBUS_MSG_PAYLOAD) {
242
243 if (!h) {
244 if (l < sizeof(struct bus_header))
245 return -EBADMSG;
246
247 h = (struct bus_header*) d->data;
248 }
249
250 n_payload++;
251 n_bytes += l;
252
253 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
254 int *f;
255 unsigned j;
256
257 j = l / sizeof(int);
258 f = realloc(fds, sizeof(int) * (n_fds + j));
259 if (!f)
260 return -ENOMEM;
261
262 fds = f;
263 memcpy(fds + n_fds, d->fds, j);
264 n_fds += j;
265 }
266 }
267
268 if (!h)
269 return -EBADMSG;
270
271 r = bus_header_size(h, &total);
272 if (r < 0)
273 return r;
274
275 if (n_bytes != total)
276 return -EBADMSG;
277
278 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
279 if (r < 0)
280 return r;
281
282 KDBUS_MSG_FOREACH_DATA(d, k) {
283 size_t l;
284
285 if (d->type != KDBUS_MSG_PAYLOAD)
286 continue;
287
288 l = d->size - offsetof(struct kdbus_msg_data, data);
289 if (idx == sizeof(struct bus_header) &&
290 l == BUS_MESSAGE_FIELDS_SIZE(m))
291 m->fields = d->data;
292 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
293 l == BUS_MESSAGE_BODY_SIZE(m))
294 m->body = d->data;
295 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
296 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
297 sd_bus_message_unref(m);
298 return -EBADMSG;
299 }
300
301 idx += l;
302 }
303
304 r = bus_message_parse_fields(m);
305 if (r < 0) {
306 sd_bus_message_unref(m);
307 return r;
308 }
309
310 /* We take possession of the kmsg struct now */
311 m->kdbus = k;
312 m->free_kdbus = true;
313 m->free_fds = true;
314
315 fds = NULL;
316
317 *ret = m;
318 return 1;
319 }
320
321 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
322 struct kdbus_msg *k;
323 size_t sz = 128;
324 int r;
325
326 assert(bus);
327 assert(m);
328
329 for (;;) {
330 void *q;
331
332 q = realloc(bus->rbuffer, sz);
333 if (!q)
334 return -errno;
335
336 k = bus->rbuffer = q;
337 k->size = sz;
338
339 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
340 if (r >= 0)
341 break;
342
343 if (errno == EAGAIN)
344 return 0;
345
346 if (errno != ENOBUFS)
347 return -errno;
348
349 sz *= 2;
350 }
351
352 r = bus_kernel_make_message(bus, k, m);
353 if (r > 0)
354 bus->rbuffer = NULL;
355 else
356 close_kdbus_msg(k);
357
358 return r;
359 }
360
361 int bus_kernel_create(const char *name, char **s) {
362 struct kdbus_cmd_fname *fname;
363 size_t l;
364 int fd;
365 char *p;
366
367 assert(name);
368 assert(s);
369
370 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
371 if (fd < 0)
372 return -errno;
373
374 l = strlen(name);
375 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
376 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
377 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
378 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD;
379 fname->user_flags = 0;
380
381 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
382 if (!p)
383 return -ENOMEM;
384
385 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
386 close_nointr_nofail(fd);
387 free(p);
388 return -errno;
389 }
390
391 if (s)
392 *s = p;
393
394 return fd;
395 }