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