]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-kernel.c
bootchart: cleanup unused structs and globals
[thirdparty/systemd.git] / src / libsystemd-bus / bus-kernel.c
CommitLineData
6629161f
LP
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
7211f918
LP
22#ifdef HAVE_VALGRIND_MEMCHECK_H
23#include <valgrind/memcheck.h>
24#endif
25
6629161f 26#include <fcntl.h>
c556fe79 27#include <malloc.h>
6629161f
LP
28
29#include "util.h"
30
31#include "bus-internal.h"
32#include "bus-message.h"
33#include "bus-kernel.h"
a56f19c4 34#include "bus-bloom.h"
6629161f 35
6133cee2
KS
36#define KDBUS_ITEM_NEXT(item) \
37 (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
9097fe29 38
6133cee2
KS
39#define KDBUS_ITEM_FOREACH(item, head) \
40 for (item = (head)->items; \
41 (uint8_t *)(item) < (uint8_t *)(head) + (head)->size; \
42 item = KDBUS_ITEM_NEXT(item))
6629161f 43
6629161f
LP
44static int parse_unique_name(const char *s, uint64_t *id) {
45 int r;
46
47 assert(s);
48 assert(id);
49
50 if (!startswith(s, ":1."))
51 return 0;
52
53 r = safe_atou64(s + 3, id);
54 if (r < 0)
55 return r;
56
57 return 1;
58}
59
68cfd331 60static void append_payload_vec(struct kdbus_msg_item **d, const void *p, size_t sz) {
6629161f
LP
61 assert(d);
62 assert(p);
63 assert(sz > 0);
64
e86b80b8
LP
65 *d = ALIGN8_PTR(*d);
66
68cfd331 67 (*d)->size = offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec);
6629161f 68 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
e0a974b4 69 (*d)->vec.address = (intptr_t) p;
6629161f
LP
70 (*d)->vec.size = sz;
71
68cfd331 72 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
6629161f
LP
73}
74
68cfd331 75static void append_destination(struct kdbus_msg_item **d, const char *s, size_t length) {
6629161f 76 assert(d);
b5baa8fe 77 assert(s);
6629161f 78
e86b80b8
LP
79 *d = ALIGN8_PTR(*d);
80
68cfd331 81 (*d)->size = offsetof(struct kdbus_msg_item, str) + length + 1;
6629161f 82 (*d)->type = KDBUS_MSG_DST_NAME;
51038c03 83 memcpy((*d)->str, s, length + 1);
6629161f 84
68cfd331 85 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
6629161f
LP
86}
87
68cfd331 88static void* append_bloom(struct kdbus_msg_item **d, size_t length) {
a56f19c4
LP
89 void *r;
90
b5baa8fe 91 assert(d);
b5baa8fe
LP
92
93 *d = ALIGN8_PTR(*d);
94
68cfd331 95 (*d)->size = offsetof(struct kdbus_msg_item, data) + length;
b5baa8fe 96 (*d)->type = KDBUS_MSG_BLOOM;
a56f19c4 97 r = (*d)->data;
b5baa8fe 98
68cfd331 99 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
a56f19c4
LP
100
101 return r;
102}
103
9097fe29
LP
104static void append_fds(struct kdbus_msg_item **d, const int fds[], unsigned n_fds) {
105 assert(d);
106 assert(fds);
107 assert(n_fds > 0);
108
109 *d = ALIGN8_PTR(*d);
110 (*d)->size = offsetof(struct kdbus_msg_item, fds) + sizeof(int) * n_fds;
111 (*d)->type = KDBUS_MSG_UNIX_FDS;
112 memcpy((*d)->fds, fds, sizeof(int) * n_fds);
113
114 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
115}
116
a56f19c4
LP
117static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
118 unsigned i;
119 int r;
120
121 assert(m);
122 assert(bloom);
123
124 memset(bloom, 0, BLOOM_SIZE);
125
126 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
127
128 if (m->interface)
129 bloom_add_pair(bloom, "interface", m->interface);
130 if (m->member)
131 bloom_add_pair(bloom, "member", m->member);
132 if (m->path) {
133 bloom_add_pair(bloom, "path", m->path);
134 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
135 }
136
137 r = sd_bus_message_rewind(m, true);
138 if (r < 0)
139 return r;
140
141 for (i = 0; i < 64; i++) {
142 char type;
143 const char *t;
144 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
145 char *e;
146
147 r = sd_bus_message_peek_type(m, &type, NULL);
148 if (r < 0)
149 return r;
150
151 if (type != SD_BUS_TYPE_STRING &&
152 type != SD_BUS_TYPE_OBJECT_PATH &&
153 type != SD_BUS_TYPE_SIGNATURE)
154 break;
155
156 r = sd_bus_message_read_basic(m, type, &t);
157 if (r < 0)
158 return r;
159
160 e = stpcpy(buf, "arg");
161 if (i < 10)
162 *(e++) = '0' + i;
163 else {
164 *(e++) = '0' + (i / 10);
165 *(e++) = '0' + (i % 10);
166 }
167
168 *e = 0;
169 bloom_add_pair(bloom, buf, t);
170
171 strcpy(e, "-dot-prefix");
172 bloom_add_prefixes(bloom, buf, t, '.');
173 strcpy(e, "-slash-prefix");
174 bloom_add_prefixes(bloom, buf, t, '/');
175 }
176
177 return 0;
b5baa8fe
LP
178}
179
5b7d4c1c 180static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
68cfd331 181 struct kdbus_msg_item *d;
6629161f
LP
182 bool well_known;
183 uint64_t unique;
184 size_t sz, dl;
185 int r;
186
5b7d4c1c 187 assert(b);
6629161f
LP
188 assert(m);
189 assert(m->sealed);
e9a967f9
LP
190
191 if (m->kdbus)
192 return 0;
6629161f
LP
193
194 if (m->destination) {
195 r = parse_unique_name(m->destination, &unique);
196 if (r < 0)
197 return r;
198
199 well_known = r == 0;
200 } else
201 well_known = false;
202
b1454bf0 203 sz = offsetof(struct kdbus_msg, items);
6629161f 204
69aec65c 205 /* Add in fixed header, fields header and payload */
68cfd331 206 sz += 3 * ALIGN8(offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec));
6629161f 207
69aec65c 208 /* Add space for bloom filter */
68cfd331 209 sz += ALIGN8(offsetof(struct kdbus_msg_item, data) + BLOOM_SIZE);
b5baa8fe 210
6629161f
LP
211 /* Add in well-known destination header */
212 if (well_known) {
213 dl = strlen(m->destination);
68cfd331 214 sz += ALIGN8(offsetof(struct kdbus_msg_item, str) + dl + 1);
6629161f
LP
215 }
216
9097fe29
LP
217 /* Add space for unix fds */
218 if (m->n_fds > 0)
219 sz += ALIGN8(offsetof(struct kdbus_msg_item, fds) + sizeof(int)*m->n_fds);
220
c556fe79 221 m->kdbus = memalign(8, sz);
6629161f
LP
222 if (!m->kdbus)
223 return -ENOMEM;
224
d9115e18
LP
225 memset(m->kdbus, 0, sz);
226
6629161f
LP
227 m->kdbus->flags =
228 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
229 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
230 m->kdbus->dst_id =
231 well_known ? 0 :
b5baa8fe 232 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
6629161f
LP
233 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
234 m->kdbus->cookie = m->header->serial;
235
236 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
237
b1454bf0 238 d = m->kdbus->items;
6629161f
LP
239
240 if (well_known)
241 append_destination(&d, m->destination, dl);
242
243 append_payload_vec(&d, m->header, sizeof(*m->header));
244
69aec65c
LP
245 if (m->fields)
246 append_payload_vec(&d, m->fields, ALIGN8(m->header->fields_size));
6629161f
LP
247
248 if (m->body)
249 append_payload_vec(&d, m->body, m->header->body_size);
250
5b7d4c1c
LP
251 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
252 void *p;
253
a56f19c4
LP
254 p = append_bloom(&d, BLOOM_SIZE);
255 r = bus_message_setup_bloom(m, p);
256 if (r < 0) {
257 free(m->kdbus);
258 m->kdbus = NULL;
259 return -r;
260 }
5b7d4c1c 261 }
b5baa8fe 262
9097fe29
LP
263 if (m->n_fds > 0)
264 append_fds(&d, m->fds, m->n_fds);
265
e9a967f9 266 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
6629161f
LP
267 assert(m->kdbus->size <= sz);
268
e9a967f9
LP
269 m->free_kdbus = true;
270
6629161f
LP
271 return 0;
272}
273
274int bus_kernel_take_fd(sd_bus *b) {
69aec65c
LP
275 struct kdbus_cmd_hello hello = {
276 .conn_flags =
799e7ea8
KS
277 KDBUS_HELLO_ACCEPT_FD|
278 KDBUS_HELLO_ATTACH_COMM|
279 KDBUS_HELLO_ATTACH_EXE|
280 KDBUS_HELLO_ATTACH_CMDLINE|
281 KDBUS_HELLO_ATTACH_CGROUP|
282 KDBUS_HELLO_ATTACH_CAPS|
283 KDBUS_HELLO_ATTACH_SECLABEL|
284 KDBUS_HELLO_ATTACH_AUDIT
69aec65c 285 };
6629161f
LP
286 int r;
287
288 assert(b);
289
f08838da
LP
290 if (b->is_server)
291 return -EINVAL;
292
6629161f
LP
293 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
294 if (r < 0)
295 return -errno;
296
5b7d4c1c
LP
297 /* The higher 32bit of both flags fields are considered
298 * 'incompatible flags'. Refuse them all for now. */
299 if (hello.bus_flags > 0xFFFFFFFFULL ||
300 hello.conn_flags > 0xFFFFFFFFULL)
301 return -ENOTSUP;
302
a56f19c4
LP
303 if (hello.bloom_size != BLOOM_SIZE)
304 return -ENOTSUP;
305
de297575
LP
306 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
307 return -ENOMEM;
308
6629161f 309 b->is_kernel = true;
f08838da 310 b->bus_client = true;
9097fe29 311 b->can_fds = true;
6629161f
LP
312
313 r = bus_start_running(b);
314 if (r < 0)
315 return r;
316
317 return 1;
318}
319
320int bus_kernel_connect(sd_bus *b) {
321 assert(b);
322 assert(b->input_fd < 0);
323 assert(b->output_fd < 0);
324 assert(b->kernel);
325
f08838da
LP
326 if (b->is_server)
327 return -EINVAL;
328
6629161f 329 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
c320885c 330 if (b->input_fd < 0)
6629161f
LP
331 return -errno;
332
333 b->output_fd = b->input_fd;
334
335 return bus_kernel_take_fd(b);
336}
337
338int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
339 int r;
340
341 assert(bus);
342 assert(m);
343 assert(bus->state == BUS_RUNNING);
344
5b7d4c1c 345 r = bus_message_setup_kmsg(bus, m);
6629161f
LP
346 if (r < 0)
347 return r;
348
349 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
350 if (r < 0)
351 return errno == EAGAIN ? 0 : -errno;
352
51038c03 353 return 1;
6629161f
LP
354}
355
356static void close_kdbus_msg(struct kdbus_msg *k) {
68cfd331 357 struct kdbus_msg_item *d;
6629161f 358
6133cee2 359 KDBUS_ITEM_FOREACH(d, k) {
6629161f
LP
360
361 if (d->type != KDBUS_MSG_UNIX_FDS)
362 continue;
363
68cfd331 364 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_item, fds)) / sizeof(int));
6629161f
LP
365 }
366}
367
368static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
369 sd_bus_message *m = NULL;
68cfd331 370 struct kdbus_msg_item *d;
6629161f
LP
371 unsigned n_payload = 0, n_fds = 0;
372 _cleanup_free_ int *fds = NULL;
373 struct bus_header *h = NULL;
374 size_t total, n_bytes = 0, idx = 0;
69aec65c 375 const char *destination = NULL, *seclabel = NULL;
6629161f
LP
376 int r;
377
378 assert(bus);
379 assert(k);
380 assert(ret);
381
382 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
383 return 0;
384
6133cee2 385 KDBUS_ITEM_FOREACH(d, k) {
6629161f
LP
386 size_t l;
387
68cfd331 388 l = d->size - offsetof(struct kdbus_msg_item, data);
6629161f
LP
389
390 if (d->type == KDBUS_MSG_PAYLOAD) {
391
392 if (!h) {
393 if (l < sizeof(struct bus_header))
394 return -EBADMSG;
395
396 h = (struct bus_header*) d->data;
397 }
398
399 n_payload++;
400 n_bytes += l;
401
402 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
403 int *f;
404 unsigned j;
405
406 j = l / sizeof(int);
407 f = realloc(fds, sizeof(int) * (n_fds + j));
408 if (!f)
409 return -ENOMEM;
410
411 fds = f;
9097fe29 412 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
6629161f 413 n_fds += j;
f9be01f3 414
69aec65c 415 } else if (d->type == KDBUS_MSG_DST_NAME)
51038c03 416 destination = d->str;
69aec65c
LP
417 else if (d->type == KDBUS_MSG_SRC_SECLABEL)
418 seclabel = d->str;
6629161f
LP
419 }
420
421 if (!h)
422 return -EBADMSG;
423
424 r = bus_header_size(h, &total);
425 if (r < 0)
426 return r;
427
428 if (n_bytes != total)
429 return -EBADMSG;
430
69aec65c 431 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
6629161f
LP
432 if (r < 0)
433 return r;
434
6133cee2 435 KDBUS_ITEM_FOREACH(d, k) {
6629161f
LP
436 size_t l;
437
68cfd331 438 l = d->size - offsetof(struct kdbus_msg_item, data);
6629161f 439
69aec65c 440 if (d->type == KDBUS_MSG_PAYLOAD) {
f9be01f3 441
69aec65c
LP
442 if (idx == sizeof(struct bus_header) &&
443 l == ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)))
444 m->fields = d->data;
445 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
446 l == BUS_MESSAGE_BODY_SIZE(m))
447 m->body = d->data;
448 else if (!(idx == 0 && l == sizeof(struct bus_header))) {
449 sd_bus_message_unref(m);
450 return -EBADMSG;
451 }
452
453 idx += l;
454 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
455 m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
456 m->uid = d->creds.uid;
457 m->gid = d->creds.gid;
458 m->pid = d->creds.pid;
459 m->tid = d->creds.tid;
460 m->uid_valid = m->gid_valid = true;
461 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
462 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
463 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
464 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
465 m->comm = d->str;
466 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
467 m->tid_comm = d->str;
468 else if (d->type == KDBUS_MSG_SRC_EXE)
469 m->exe = d->str;
77930f11
LP
470 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
471 m->cmdline = d->str;
472 m->cmdline_length = l;
4a875b61
LP
473 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
474 m->cgroup = d->str;
120f919e
LP
475 else if (d->type == KDBUS_MSG_SRC_AUDIT)
476 m->audit = &d->audit;
102ea8e4
LP
477 else if (d->type == KDBUS_MSG_SRC_CAPS) {
478 m->capability = d->data;
479 m->capability_size = l;
480 } else
77930f11 481 log_debug("Got unknown field from kernel %llu", d->type);
69aec65c 482 }
acb5a3cb 483
6629161f
LP
484 r = bus_message_parse_fields(m);
485 if (r < 0) {
486 sd_bus_message_unref(m);
487 return r;
488 }
489
51038c03
LP
490 if (k->src_id == KDBUS_SRC_ID_KERNEL)
491 m->sender = "org.freedesktop.DBus";
492 else {
493 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
494 m->sender = m->sender_buffer;
495 }
496
497 if (!m->destination) {
498 if (destination)
499 m->destination = destination;
500 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
501 k->dst_id != KDBUS_DST_ID_BROADCAST) {
502 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
503 m->destination = m->destination_buffer;
504 }
505 }
506
6629161f
LP
507 /* We take possession of the kmsg struct now */
508 m->kdbus = k;
509 m->free_kdbus = true;
510 m->free_fds = true;
511
512 fds = NULL;
513
514 *ret = m;
515 return 1;
516}
517
518int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
519 struct kdbus_msg *k;
f08838da 520 size_t sz = 1024;
6629161f
LP
521 int r;
522
523 assert(bus);
524 assert(m);
525
526 for (;;) {
527 void *q;
528
c556fe79 529 q = memalign(8, sz);
6629161f
LP
530 if (!q)
531 return -errno;
532
8e738242 533 free(bus->rbuffer);
6629161f
LP
534 k = bus->rbuffer = q;
535 k->size = sz;
536
7211f918
LP
537 /* Let's tell valgrind that there's really no need to
538 * initialize this fully. This should be removed again
539 * when valgrind learned the kdbus ioctls natively. */
beca33ee 540#ifdef HAVE_VALGRIND_MEMCHECK_H
7211f918 541 VALGRIND_MAKE_MEM_DEFINED(k, sz);
beca33ee 542#endif
7211f918 543
6629161f
LP
544 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
545 if (r >= 0)
546 break;
547
548 if (errno == EAGAIN)
549 return 0;
550
e9a967f9 551 if (errno != ENOBUFS)
6629161f
LP
552 return -errno;
553
554 sz *= 2;
555 }
556
557 r = bus_kernel_make_message(bus, k, m);
558 if (r > 0)
559 bus->rbuffer = NULL;
560 else
561 close_kdbus_msg(k);
562
51038c03 563 return r < 0 ? r : 1;
6629161f
LP
564}
565
566int bus_kernel_create(const char *name, char **s) {
5b7d4c1c 567 struct kdbus_cmd_bus_make *make;
a2cef833 568 struct kdbus_cmd_make_item *n, *cg;
6629161f
LP
569 size_t l;
570 int fd;
571 char *p;
572
573 assert(name);
574 assert(s);
575
576 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
577 if (fd < 0)
578 return -errno;
579
580 l = strlen(name);
a2cef833
KS
581 make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
582 sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t) +
583 sizeof(struct kdbus_cmd_make_item) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
584
585 cg = make->items;
799e7ea8 586 cg->type = KDBUS_MAKE_CGROUP;
a2cef833
KS
587 cg->data64[0] = 1;
588 cg->size = sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t);
589
590 n = KDBUS_ITEM_NEXT(cg);
799e7ea8 591 n->type = KDBUS_MAKE_NAME;
a2cef833
KS
592 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
593 n->size = sizeof(struct kdbus_cmd_make_item) + strlen(n->str) + 1;
594
595 make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
799e7ea8 596 make->flags = KDBUS_MAKE_ACCESS_WORLD | KDBUS_MAKE_POLICY_OPEN;
5b7d4c1c 597 make->bus_flags = 0;
a56f19c4 598 make->bloom_size = BLOOM_SIZE;
a56f19c4 599 assert_cc(BLOOM_SIZE % 8 == 0);
5b7d4c1c 600
a2cef833 601 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
6629161f
LP
602 if (!p)
603 return -ENOMEM;
604
5b7d4c1c 605 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
6629161f
LP
606 close_nointr_nofail(fd);
607 free(p);
608 return -errno;
609 }
610
611 if (s)
612 *s = p;
613
614 return fd;
615}