]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-kernel.c
journal: fix broken tags _SOURCE_REALTIME_TIMESTAMP and _MACHINE_ID
[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
LP
26#include <fcntl.h>
27
28#include "util.h"
29
30#include "bus-internal.h"
31#include "bus-message.h"
32#include "bus-kernel.h"
33
34#define KDBUS_MSG_FOREACH_DATA(d, k) \
35 for ((d) = (k)->data; \
36 (uint8_t*) (d) < (uint8_t*) (k) + (k)->size; \
37 (d) = (struct kdbus_msg_data*) ((uint8_t*) (d) + ALIGN8((d)->size)))
38
6629161f
LP
39static int parse_unique_name(const char *s, uint64_t *id) {
40 int r;
41
42 assert(s);
43 assert(id);
44
45 if (!startswith(s, ":1."))
46 return 0;
47
48 r = safe_atou64(s + 3, id);
49 if (r < 0)
50 return r;
51
52 return 1;
53}
54
55static void append_payload_vec(struct kdbus_msg_data **d, const void *p, size_t sz) {
56 assert(d);
57 assert(p);
58 assert(sz > 0);
59
e86b80b8
LP
60 *d = ALIGN8_PTR(*d);
61
6629161f
LP
62 (*d)->size = offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec);
63 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
64 (*d)->vec.address = (uint64_t) p;
65 (*d)->vec.size = sz;
66
e86b80b8 67 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + (*d)->size);
6629161f
LP
68}
69
70static void append_destination(struct kdbus_msg_data **d, const char *s, size_t length) {
71 assert(d);
b5baa8fe 72 assert(s);
6629161f 73
e86b80b8
LP
74 *d = ALIGN8_PTR(*d);
75
51038c03 76 (*d)->size = offsetof(struct kdbus_msg_data, str) + length + 1;
6629161f 77 (*d)->type = KDBUS_MSG_DST_NAME;
51038c03 78 memcpy((*d)->str, s, length + 1);
6629161f 79
e86b80b8 80 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + (*d)->size);
6629161f
LP
81}
82
b5baa8fe
LP
83static void append_bloom(struct kdbus_msg_data **d, const void *p, size_t length) {
84 assert(d);
85 assert(p);
86
87 *d = ALIGN8_PTR(*d);
88
89 (*d)->size = offsetof(struct kdbus_msg_data, data) + length;
90 (*d)->type = KDBUS_MSG_BLOOM;
91 memcpy((*d)->data, p, length);
92
93 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + (*d)->size);
94}
95
6629161f
LP
96static int bus_message_setup_kmsg(sd_bus_message *m) {
97 struct kdbus_msg_data *d;
98 bool well_known;
99 uint64_t unique;
100 size_t sz, dl;
101 int r;
102
103 assert(m);
104 assert(m->sealed);
e9a967f9
LP
105
106 if (m->kdbus)
107 return 0;
6629161f
LP
108
109 if (m->destination) {
110 r = parse_unique_name(m->destination, &unique);
111 if (r < 0)
112 return r;
113
114 well_known = r == 0;
115 } else
116 well_known = false;
117
118 sz = offsetof(struct kdbus_msg, data);
119
120 /* Add in fixed header, fields header, fields header padding and payload */
121 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
122
b5baa8fe
LP
123 sz += ALIGN8(offsetof(struct kdbus_msg_data, data) + 5);
124
6629161f
LP
125 /* Add in well-known destination header */
126 if (well_known) {
127 dl = strlen(m->destination);
128 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
129 }
130
8e738242 131 m->kdbus = aligned_alloc(8, sz);
6629161f
LP
132 if (!m->kdbus)
133 return -ENOMEM;
134
d9115e18
LP
135 memset(m->kdbus, 0, sz);
136
6629161f
LP
137 m->kdbus->flags =
138 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
139 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
140 m->kdbus->dst_id =
141 well_known ? 0 :
b5baa8fe 142 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
6629161f
LP
143 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
144 m->kdbus->cookie = m->header->serial;
145
146 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
147
148 d = m->kdbus->data;
149
150 if (well_known)
151 append_destination(&d, m->destination, dl);
152
153 append_payload_vec(&d, m->header, sizeof(*m->header));
154
155 if (m->fields) {
156 append_payload_vec(&d, m->fields, m->header->fields_size);
157
158 if (m->header->fields_size % 8 != 0) {
159 static const uint8_t padding[7] = {};
160
161 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
162 }
163 }
164
165 if (m->body)
166 append_payload_vec(&d, m->body, m->header->body_size);
167
b5baa8fe
LP
168 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST)
169 append_bloom(&d, "bloom", 5);
170
e9a967f9 171 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
6629161f
LP
172 assert(m->kdbus->size <= sz);
173
e9a967f9
LP
174 m->free_kdbus = true;
175
6629161f
LP
176 return 0;
177}
178
179int bus_kernel_take_fd(sd_bus *b) {
180 struct kdbus_cmd_hello hello = {};
181 int r;
182
183 assert(b);
184
f08838da
LP
185 if (b->is_server)
186 return -EINVAL;
187
6629161f
LP
188 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
189 if (r < 0)
190 return -errno;
191
de297575
LP
192 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
193 return -ENOMEM;
194
6629161f 195 b->is_kernel = true;
f08838da 196 b->bus_client = true;
6629161f
LP
197
198 r = bus_start_running(b);
199 if (r < 0)
200 return r;
201
202 return 1;
203}
204
205int bus_kernel_connect(sd_bus *b) {
206 assert(b);
207 assert(b->input_fd < 0);
208 assert(b->output_fd < 0);
209 assert(b->kernel);
210
f08838da
LP
211 if (b->is_server)
212 return -EINVAL;
213
6629161f 214 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
c320885c 215 if (b->input_fd < 0)
6629161f
LP
216 return -errno;
217
218 b->output_fd = b->input_fd;
219
220 return bus_kernel_take_fd(b);
221}
222
223int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
224 int r;
225
226 assert(bus);
227 assert(m);
228 assert(bus->state == BUS_RUNNING);
229
230 r = bus_message_setup_kmsg(m);
231 if (r < 0)
232 return r;
233
234 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
235 if (r < 0)
236 return errno == EAGAIN ? 0 : -errno;
237
51038c03 238 return 1;
6629161f
LP
239}
240
241static void close_kdbus_msg(struct kdbus_msg *k) {
242 struct kdbus_msg_data *d;
243
244 KDBUS_MSG_FOREACH_DATA(d, k) {
245
246 if (d->type != KDBUS_MSG_UNIX_FDS)
247 continue;
248
249 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
250 }
251}
252
253static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
254 sd_bus_message *m = NULL;
255 struct kdbus_msg_data *d;
256 unsigned n_payload = 0, n_fds = 0;
257 _cleanup_free_ int *fds = NULL;
258 struct bus_header *h = NULL;
259 size_t total, n_bytes = 0, idx = 0;
f9be01f3 260 struct kdbus_creds *creds = NULL;
acb5a3cb 261 uint64_t nsec = 0;
51038c03 262 const char *destination = NULL;
6629161f
LP
263 int r;
264
265 assert(bus);
266 assert(k);
267 assert(ret);
268
269 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
270 return 0;
271
272 KDBUS_MSG_FOREACH_DATA(d, k) {
273 size_t l;
274
275 l = d->size - offsetof(struct kdbus_msg_data, data);
276
277 if (d->type == KDBUS_MSG_PAYLOAD) {
278
279 if (!h) {
280 if (l < sizeof(struct bus_header))
281 return -EBADMSG;
282
283 h = (struct bus_header*) d->data;
284 }
285
286 n_payload++;
287 n_bytes += l;
288
289 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
290 int *f;
291 unsigned j;
292
293 j = l / sizeof(int);
294 f = realloc(fds, sizeof(int) * (n_fds + j));
295 if (!f)
296 return -ENOMEM;
297
298 fds = f;
299 memcpy(fds + n_fds, d->fds, j);
300 n_fds += j;
f9be01f3
LP
301
302 } else if (d->type == KDBUS_MSG_SRC_CREDS)
303 creds = &d->creds;
acb5a3cb
LP
304 else if (d->type == KDBUS_MSG_TIMESTAMP)
305 nsec = d->ts_ns;
51038c03
LP
306 else if (d->type == KDBUS_MSG_DST_NAME)
307 destination = d->str;
6629161f
LP
308 }
309
310 if (!h)
311 return -EBADMSG;
312
313 r = bus_header_size(h, &total);
314 if (r < 0)
315 return r;
316
317 if (n_bytes != total)
318 return -EBADMSG;
319
320 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
321 if (r < 0)
322 return r;
323
324 KDBUS_MSG_FOREACH_DATA(d, k) {
325 size_t l;
326
327 if (d->type != KDBUS_MSG_PAYLOAD)
328 continue;
329
330 l = d->size - offsetof(struct kdbus_msg_data, data);
6629161f
LP
331 if (idx == sizeof(struct bus_header) &&
332 l == BUS_MESSAGE_FIELDS_SIZE(m))
333 m->fields = d->data;
334 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
335 l == BUS_MESSAGE_BODY_SIZE(m))
336 m->body = d->data;
e9a967f9
LP
337 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
338 !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
6629161f
LP
339 sd_bus_message_unref(m);
340 return -EBADMSG;
341 }
342
343 idx += l;
344 }
345
f9be01f3 346 if (creds) {
8323bc1f 347 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
f9be01f3
LP
348 m->uid = creds->uid;
349 m->gid = creds->gid;
350 m->pid = creds->pid;
351 m->tid = creds->tid;
352 m->uid_valid = m->gid_valid = true;
353 }
354
acb5a3cb
LP
355 m->timestamp = nsec / NSEC_PER_USEC;
356
6629161f
LP
357 r = bus_message_parse_fields(m);
358 if (r < 0) {
359 sd_bus_message_unref(m);
360 return r;
361 }
362
51038c03
LP
363 if (k->src_id == KDBUS_SRC_ID_KERNEL)
364 m->sender = "org.freedesktop.DBus";
365 else {
366 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
367 m->sender = m->sender_buffer;
368 }
369
370 if (!m->destination) {
371 if (destination)
372 m->destination = destination;
373 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
374 k->dst_id != KDBUS_DST_ID_BROADCAST) {
375 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
376 m->destination = m->destination_buffer;
377 }
378 }
379
6629161f
LP
380 /* We take possession of the kmsg struct now */
381 m->kdbus = k;
382 m->free_kdbus = true;
383 m->free_fds = true;
384
385 fds = NULL;
386
387 *ret = m;
388 return 1;
389}
390
391int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
392 struct kdbus_msg *k;
f08838da 393 size_t sz = 1024;
6629161f
LP
394 int r;
395
396 assert(bus);
397 assert(m);
398
399 for (;;) {
400 void *q;
401
8e738242 402 q = aligned_alloc(8, sz);
6629161f
LP
403 if (!q)
404 return -errno;
405
8e738242 406 free(bus->rbuffer);
6629161f
LP
407 k = bus->rbuffer = q;
408 k->size = sz;
409
7211f918
LP
410 /* Let's tell valgrind that there's really no need to
411 * initialize this fully. This should be removed again
412 * when valgrind learned the kdbus ioctls natively. */
beca33ee 413#ifdef HAVE_VALGRIND_MEMCHECK_H
7211f918 414 VALGRIND_MAKE_MEM_DEFINED(k, sz);
beca33ee 415#endif
7211f918 416
6629161f
LP
417 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
418 if (r >= 0)
419 break;
420
421 if (errno == EAGAIN)
422 return 0;
423
e9a967f9 424 if (errno != ENOBUFS)
6629161f
LP
425 return -errno;
426
427 sz *= 2;
428 }
429
430 r = bus_kernel_make_message(bus, k, m);
431 if (r > 0)
432 bus->rbuffer = NULL;
433 else
434 close_kdbus_msg(k);
435
51038c03 436 return r < 0 ? r : 1;
6629161f
LP
437}
438
439int bus_kernel_create(const char *name, char **s) {
440 struct kdbus_cmd_fname *fname;
441 size_t l;
442 int fd;
443 char *p;
444
445 assert(name);
446 assert(s);
447
448 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
449 if (fd < 0)
450 return -errno;
451
452 l = strlen(name);
453 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
454 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
455 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
4e6db592 456 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD | KDBUS_CMD_FNAME_POLICY_OPEN;
6629161f
LP
457 fname->user_flags = 0;
458
459 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
460 if (!p)
461 return -ENOMEM;
462
b4da2689 463 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
6629161f
LP
464 close_nointr_nofail(fd);
465 free(p);
466 return -errno;
467 }
468
469 if (s)
470 *s = p;
471
472 return fd;
473}