]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-message.c
core: convert PID 1 to libsystemd-bus
[thirdparty/systemd.git] / src / libsystemd-bus / bus-message.c
CommitLineData
de1c301e
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
22#include <errno.h>
2c93b4ef 23#include <fcntl.h>
bc7fd8cd 24#include <sys/mman.h>
de1c301e
LP
25
26#include "util.h"
9a17484d 27#include "utf8.h"
89ffcd2a 28#include "strv.h"
6629161f 29#include "time-util.h"
d8d3d8a7 30#include "cgroup-util.h"
de1c301e 31
de1c301e 32#include "sd-bus.h"
9a17484d 33#include "bus-message.h"
de1c301e
LP
34#include "bus-internal.h"
35#include "bus-type.h"
36#include "bus-signature.h"
37
80a46c73 38static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
de1c301e 39
bc7fd8cd
LP
40static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
41
42 if (p == NULL)
43 return NULL;
44
45 if (old_base == new_base)
46 return (void*) p;
47
48 if ((uint8_t*) p < (uint8_t*) old_base)
49 return (void*) p;
50
51 if ((uint8_t*) p >= (uint8_t*) old_base + sz)
52 return (void*) p;
53
54 return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
55}
56
57static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
58 assert(m);
59 assert(part);
60
61 if (part->memfd >= 0) {
66b26c5c
LP
62 /* If we can reuse the memfd, try that. For that it
63 * can't be sealed yet. */
bc7fd8cd
LP
64
65 if (!part->sealed)
66 bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped);
67 else {
89b4fc46
LP
68 if (part->mapped > 0)
69 assert_se(munmap(part->data, part->mapped) == 0);
bc7fd8cd
LP
70
71 close_nointr_nofail(part->memfd);
72 }
73
453a0c29
LP
74 } else if (part->munmap_this)
75 munmap(part->data, part->mapped);
76 else if (part->free_this)
bc7fd8cd
LP
77 free(part->data);
78
79 if (part != &m->body)
80 free(part);
81}
82
83static void message_reset_parts(sd_bus_message *m) {
84 struct bus_body_part *part;
85
86 assert(m);
87
88 part = &m->body;
89 while (m->n_body_parts > 0) {
90 struct bus_body_part *next = part->next;
91 message_free_part(m, part);
92 part = next;
93 m->n_body_parts--;
94 }
95
96 m->body_end = NULL;
97
98 m->cached_rindex_part = NULL;
99 m->cached_rindex_part_begin = 0;
100}
101
102static void message_reset_containers(sd_bus_message *m) {
9a17484d
LP
103 unsigned i;
104
105 assert(m);
106
107 for (i = 0; i < m->n_containers; i++)
108 free(m->containers[i].signature);
109
110 free(m->containers);
111 m->containers = NULL;
112
113 m->n_containers = 0;
114 m->root_container.index = 0;
115}
116
de1c301e 117static void message_free(sd_bus_message *m) {
de1c301e
LP
118 assert(m);
119
120 if (m->free_header)
121 free(m->header);
122
bc7fd8cd 123 message_reset_parts(m);
de1c301e 124
6629161f
LP
125 if (m->free_kdbus)
126 free(m->kdbus);
127
62b3e928
KS
128 if (m->release_kdbus) {
129 uint64_t off;
130
131 off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer;
132 ioctl(m->bus->input_fd, KDBUS_CMD_MSG_RELEASE, &off);
133 }
fd8d62d9 134
f54514f3
LP
135 if (m->bus)
136 sd_bus_unref(m->bus);
137
2c93b4ef
LP
138 if (m->free_fds) {
139 close_many(m->fds, m->n_fds);
140 free(m->fds);
141 }
de1c301e 142
bc7fd8cd
LP
143 if (m->iovec != m->iovec_fixed)
144 free(m->iovec);
145
77930f11
LP
146 free(m->cmdline_array);
147
bc7fd8cd 148 message_reset_containers(m);
9a17484d 149 free(m->root_container.signature);
de1c301e 150
9a17484d 151 free(m->peeked_signature);
d8d3d8a7
LP
152
153 free(m->unit);
154 free(m->user_unit);
155 free(m->session);
de1c301e
LP
156 free(m);
157}
158
c91cb83c
LP
159static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz) {
160 void *op, *np;
161 size_t old_size, new_size, start;
de1c301e 162
c91cb83c 163 assert(m);
de1c301e 164
c91cb83c 165 if (m->poisoned)
de1c301e
LP
166 return NULL;
167
c91cb83c
LP
168 old_size = sizeof(struct bus_header) + m->header->fields_size;
169 start = ALIGN_TO(old_size, align);
170 new_size = start + sz;
de1c301e 171
c91cb83c
LP
172 if (old_size == new_size)
173 return (uint8_t*) m->header + old_size;
de1c301e 174
c91cb83c
LP
175 if (new_size > (size_t) ((uint32_t) -1))
176 goto poison;
de1c301e 177
c91cb83c
LP
178 if (m->free_header) {
179 np = realloc(m->header, ALIGN8(new_size));
180 if (!np)
181 goto poison;
182 } else {
183 /* Initially, the header is allocated as part of of
184 * the sd_bus_message itself, let's replace it by
185 * dynamic data */
de1c301e 186
c91cb83c
LP
187 np = malloc(ALIGN8(new_size));
188 if (!np)
189 goto poison;
de1c301e 190
c91cb83c
LP
191 memcpy(np, m->header, sizeof(struct bus_header));
192 }
de1c301e 193
c91cb83c
LP
194 /* Zero out padding */
195 if (start > old_size)
196 memset((uint8_t*) np + old_size, 0, start - old_size);
bc7fd8cd 197
c91cb83c
LP
198 op = m->header;
199 m->header = np;
200 m->header->fields_size = new_size - sizeof(struct bus_header);
de1c301e 201
bc7fd8cd 202 /* Adjust quick access pointers */
c91cb83c
LP
203 m->path = adjust_pointer(m->path, op, old_size, m->header);
204 m->interface = adjust_pointer(m->interface, op, old_size, m->header);
205 m->member = adjust_pointer(m->member, op, old_size, m->header);
206 m->destination = adjust_pointer(m->destination, op, old_size, m->header);
207 m->sender = adjust_pointer(m->sender, op, old_size, m->header);
208 m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
bc7fd8cd 209
c91cb83c 210 m->free_header = true;
de1c301e 211
c91cb83c
LP
212 return (uint8_t*) np + start;
213
214poison:
215 m->poisoned = true;
216 return NULL;
de1c301e
LP
217}
218
219static int message_append_field_string(
220 sd_bus_message *m,
221 uint8_t h,
222 char type,
223 const char *s,
224 const char **ret) {
225
226 size_t l;
227 uint8_t *p;
228
229 assert(m);
230
231 l = strlen(s);
232 if (l > (size_t) (uint32_t) -1)
233 return -EINVAL;
234
235 /* field id byte + signature length + signature 's' + NUL + string length + string + NUL */
236 p = message_extend_fields(m, 8, 4 + 4 + l + 1);
237 if (!p)
238 return -ENOMEM;
239
240 p[0] = h;
241 p[1] = 1;
242 p[2] = type;
243 p[3] = 0;
244
245 ((uint32_t*) p)[1] = l;
246 memcpy(p + 8, s, l + 1);
247
248 if (ret)
bc7fd8cd 249 *ret = (char*) p + 8;
de1c301e
LP
250
251 return 0;
252}
253
254static int message_append_field_signature(
255 sd_bus_message *m,
256 uint8_t h,
257 const char *s,
258 const char **ret) {
259
260 size_t l;
261 uint8_t *p;
262
263 assert(m);
264
265 l = strlen(s);
266 if (l > 255)
267 return -EINVAL;
268
269 /* field id byte + signature length + signature 'g' + NUL + string length + string + NUL */
270 p = message_extend_fields(m, 8, 4 + 1 + l + 1);
271 if (!p)
272 return -ENOMEM;
273
274 p[0] = h;
275 p[1] = 1;
276 p[2] = SD_BUS_TYPE_SIGNATURE;
277 p[3] = 0;
278 p[4] = l;
279 memcpy(p + 5, s, l + 1);
280
281 if (ret)
282 *ret = (const char*) p + 5;
283
284 return 0;
285}
286
287static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) {
288 uint8_t *p;
289
290 assert(m);
291
292 /* field id byte + signature length + signature 'u' + NUL + value */
293 p = message_extend_fields(m, 8, 4 + 4);
294 if (!p)
295 return -ENOMEM;
296
297 p[0] = h;
298 p[1] = 1;
299 p[2] = SD_BUS_TYPE_UINT32;
300 p[3] = 0;
301
302 ((uint32_t*) p)[1] = x;
303
304 return 0;
305}
306
6629161f 307int bus_message_from_header(
2571ead1
LP
308 void *buffer,
309 size_t length,
2c93b4ef
LP
310 int *fds,
311 unsigned n_fds,
312 const struct ucred *ucred,
2571ead1 313 const char *label,
6629161f 314 size_t extra,
2571ead1
LP
315 sd_bus_message **ret) {
316
80a46c73
LP
317 sd_bus_message *m;
318 struct bus_header *h;
6629161f 319 size_t a, label_sz;
80a46c73
LP
320
321 assert(buffer || length <= 0);
2c93b4ef 322 assert(fds || n_fds <= 0);
80a46c73
LP
323 assert(ret);
324
325 if (length < sizeof(struct bus_header))
326 return -EBADMSG;
327
328 h = buffer;
329 if (h->version != 1)
330 return -EBADMSG;
331
332 if (h->serial == 0)
333 return -EBADMSG;
334
335 if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
336 return -EBADMSG;
337
6629161f
LP
338 if (h->endian != SD_BUS_LITTLE_ENDIAN &&
339 h->endian != SD_BUS_BIG_ENDIAN)
80a46c73
LP
340 return -EBADMSG;
341
6629161f 342 a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
80a46c73 343
2571ead1
LP
344 if (label) {
345 label_sz = strlen(label);
6629161f
LP
346 a += label_sz + 1;
347 }
2571ead1
LP
348
349 m = malloc0(a);
80a46c73
LP
350 if (!m)
351 return -ENOMEM;
352
353 m->n_ref = 1;
2c93b4ef 354 m->sealed = true;
80a46c73 355 m->header = h;
2c93b4ef
LP
356 m->fds = fds;
357 m->n_fds = n_fds;
80a46c73 358
2571ead1
LP
359 if (ucred) {
360 m->uid = ucred->uid;
361 m->pid = ucred->pid;
362 m->gid = ucred->gid;
363 m->uid_valid = m->gid_valid = true;
364 }
365
366 if (label) {
6629161f 367 m->label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
2571ead1
LP
368 memcpy(m->label, label, label_sz + 1);
369 }
370
6629161f
LP
371 *ret = m;
372 return 0;
373}
374
375int bus_message_from_malloc(
376 void *buffer,
377 size_t length,
378 int *fds,
379 unsigned n_fds,
380 const struct ucred *ucred,
381 const char *label,
382 sd_bus_message **ret) {
383
384 sd_bus_message *m;
385 int r;
386
387 r = bus_message_from_header(buffer, length, fds, n_fds, ucred, label, 0, &m);
388 if (r < 0)
389 return r;
390
391 if (length != BUS_MESSAGE_SIZE(m)) {
392 r = -EBADMSG;
393 goto fail;
394 }
395
bc7fd8cd
LP
396 m->n_body_parts = 1;
397 m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
398 m->body.size = length - sizeof(struct bus_header) - ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
399 m->body.sealed = true;
400 m->body.memfd = -1;
6629161f 401
80a46c73 402 m->n_iovec = 1;
bc7fd8cd 403 m->iovec = m->iovec_fixed;
80a46c73
LP
404 m->iovec[0].iov_base = buffer;
405 m->iovec[0].iov_len = length;
406
6629161f 407 r = bus_message_parse_fields(m);
2c93b4ef
LP
408 if (r < 0)
409 goto fail;
410
411 /* We take possession of the memory and fds now */
412 m->free_header = true;
413 m->free_fds = true;
80a46c73
LP
414
415 *ret = m;
416 return 0;
2c93b4ef
LP
417
418fail:
419 message_free(m);
420 return r;
80a46c73
LP
421}
422
de1c301e
LP
423static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
424 sd_bus_message *m;
425
80a46c73 426 m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
de1c301e
LP
427 if (!m)
428 return NULL;
429
430 m->n_ref = 1;
431 m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
80a46c73 432 m->header->endian = SD_BUS_NATIVE_ENDIAN;
de1c301e
LP
433 m->header->type = type;
434 m->header->version = bus ? bus->message_version : 1;
021a1e78 435 m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
de1c301e 436
9b05bc48
LP
437 if (bus)
438 m->bus = sd_bus_ref(bus);
439
de1c301e
LP
440 return m;
441}
442
d9f644e2 443_public_ int sd_bus_message_new_signal(
de1c301e
LP
444 sd_bus *bus,
445 const char *path,
446 const char *interface,
447 const char *member,
448 sd_bus_message **m) {
449
450 sd_bus_message *t;
451 int r;
452
9d6c7c82
LP
453 assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
454 assert_return(object_path_is_valid(path), -EINVAL);
455 assert_return(interface_name_is_valid(interface), -EINVAL);
456 assert_return(member_name_is_valid(member), -EINVAL);
457 assert_return(m, -EINVAL);
de1c301e 458
40ca29a1 459 t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
de1c301e
LP
460 if (!t)
461 return -ENOMEM;
462
89ffcd2a
LP
463 t->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
464
de1c301e
LP
465 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
466 if (r < 0)
467 goto fail;
468 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
469 if (r < 0)
470 goto fail;
471 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
472 if (r < 0)
473 goto fail;
474
475 *m = t;
476 return 0;
477
478fail:
479 sd_bus_message_unref(t);
480 return r;
481}
482
d9f644e2 483_public_ int sd_bus_message_new_method_call(
de1c301e
LP
484 sd_bus *bus,
485 const char *destination,
486 const char *path,
487 const char *interface,
488 const char *member,
489 sd_bus_message **m) {
490
491 sd_bus_message *t;
492 int r;
493
9d6c7c82
LP
494 assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
495 assert_return(!destination || service_name_is_valid(destination), -EINVAL);
496 assert_return(object_path_is_valid(path), -EINVAL);
497 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
498 assert_return(member_name_is_valid(member), -EINVAL);
499 assert_return(m, -EINVAL);
de1c301e 500
40ca29a1 501 t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
de1c301e
LP
502 if (!t)
503 return -ENOMEM;
504
505 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
506 if (r < 0)
507 goto fail;
508 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
509 if (r < 0)
510 goto fail;
511
512 if (interface) {
513 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
514 if (r < 0)
515 goto fail;
516 }
517
518 if (destination) {
519 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
520 if (r < 0)
521 goto fail;
522 }
523
524 *m = t;
525 return 0;
526
527fail:
528 message_free(t);
529 return r;
530}
531
5407f2de 532static int message_new_reply(
de1c301e
LP
533 sd_bus *bus,
534 sd_bus_message *call,
5407f2de 535 uint8_t type,
de1c301e
LP
536 sd_bus_message **m) {
537
538 sd_bus_message *t;
539 int r;
540
9d6c7c82
LP
541 assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
542 assert_return(call, -EINVAL);
543 assert_return(call->sealed, -EPERM);
544 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
545 assert_return(m, -EINVAL);
de1c301e 546
5407f2de 547 t = message_new(bus, type);
de1c301e
LP
548 if (!t)
549 return -ENOMEM;
550
89ffcd2a 551 t->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
de1c301e 552 t->reply_serial = BUS_MESSAGE_SERIAL(call);
5407f2de 553
de1c301e
LP
554 r = message_append_field_uint32(t, SD_BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_serial);
555 if (r < 0)
556 goto fail;
557
558 if (call->sender) {
8f155917 559 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
de1c301e
LP
560 if (r < 0)
561 goto fail;
562 }
563
5407f2de
LP
564 t->dont_send = !!(call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED);
565
de1c301e 566 *m = t;
89ffcd2a 567 return 0;
de1c301e
LP
568
569fail:
570 message_free(t);
571 return r;
572}
573
d9f644e2 574_public_ int sd_bus_message_new_method_return(
5407f2de
LP
575 sd_bus *bus,
576 sd_bus_message *call,
577 sd_bus_message **m) {
578
40ca29a1 579 return message_new_reply(bus, call, SD_BUS_MESSAGE_METHOD_RETURN, m);
5407f2de
LP
580}
581
d9f644e2 582_public_ int sd_bus_message_new_method_error(
de1c301e
LP
583 sd_bus *bus,
584 sd_bus_message *call,
585 const sd_bus_error *e,
586 sd_bus_message **m) {
587
588 sd_bus_message *t;
589 int r;
590
9d6c7c82
LP
591 assert_return(sd_bus_error_is_set(e), -EINVAL);
592 assert_return(m, -EINVAL);
de1c301e 593
40ca29a1 594 r = message_new_reply(bus, call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
de1c301e 595 if (r < 0)
5407f2de 596 return r;
de1c301e
LP
597
598 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
599 if (r < 0)
600 goto fail;
601
602 if (e->message) {
603 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
604 if (r < 0)
605 goto fail;
606 }
607
608 *m = t;
609 return 0;
610
611fail:
612 message_free(t);
613 return r;
614}
615
d9f644e2 616_public_ int sd_bus_message_new_method_errorf(
29ddb38f
LP
617 sd_bus *bus,
618 sd_bus_message *call,
619 sd_bus_message **m,
620 const char *name,
621 const char *format,
622 ...) {
623
40ca29a1 624 _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
29ddb38f
LP
625 va_list ap;
626 int r;
627
40ca29a1
LP
628 assert_return(name, -EINVAL);
629 assert_return(m, -EINVAL);
630
631 va_start(ap, format);
632 r = bus_error_setfv(&error, name, format, ap);
633 va_end(ap);
29ddb38f 634
29ddb38f
LP
635 if (r < 0)
636 return r;
637
40ca29a1
LP
638 return sd_bus_message_new_method_error(bus, call, &error, m);
639}
29ddb38f 640
d9f644e2 641_public_ int sd_bus_message_new_method_errno(
40ca29a1
LP
642 sd_bus *bus,
643 sd_bus_message *call,
644 int error,
645 const sd_bus_error *p,
646 sd_bus_message **m) {
29ddb38f 647
40ca29a1 648 _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
29ddb38f 649
40ca29a1
LP
650 if (sd_bus_error_is_set(p))
651 return sd_bus_message_new_method_error(bus, call, p, m);
29ddb38f 652
40ca29a1 653 sd_bus_error_set_errno(&berror, error);
29ddb38f 654
40ca29a1
LP
655 return sd_bus_message_new_method_error(bus, call, &berror, m);
656}
29ddb38f 657
d9f644e2 658_public_ int sd_bus_message_new_method_errnof(
40ca29a1
LP
659 sd_bus *bus,
660 sd_bus_message *call,
661 sd_bus_message **m,
662 int error,
663 const char *format,
664 ...) {
665
666 _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
667 va_list ap;
668 int r;
669
670 va_start(ap, format);
671 r = bus_error_set_errnofv(&berror, error, format, ap);
672 va_end(ap);
673
674 if (r < 0)
675 return r;
676
677 return sd_bus_message_new_method_error(bus, call, &berror, m);
29ddb38f
LP
678}
679
eb01ba5d
LP
680int bus_message_new_synthetic_error(
681 sd_bus *bus,
682 uint64_t serial,
683 const sd_bus_error *e,
684 sd_bus_message **m) {
685
686 sd_bus_message *t;
687 int r;
688
689 assert(sd_bus_error_is_set(e));
690 assert(m);
691
40ca29a1 692 t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
eb01ba5d
LP
693 if (!t)
694 return -ENOMEM;
695
696 t->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
697 t->reply_serial = serial;
698
699 r = message_append_field_uint32(t, SD_BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_serial);
700 if (r < 0)
701 goto fail;
702
703 if (bus && bus->unique_name) {
704 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
705 if (r < 0)
706 goto fail;
707 }
708
3a7d4f1b
LP
709 r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
710 if (r < 0)
711 goto fail;
712
713 if (e->message) {
714 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
715 if (r < 0)
716 goto fail;
717 }
718
eb01ba5d
LP
719 *m = t;
720 return 0;
721
722fail:
723 message_free(t);
724 return r;
725}
726
d9f644e2 727_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
9d6c7c82 728 assert_return(m, NULL);
de1c301e
LP
729
730 assert(m->n_ref > 0);
731 m->n_ref++;
732
733 return m;
734}
735
d9f644e2 736_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
9d6c7c82 737 assert_return(m, NULL);
de1c301e
LP
738
739 assert(m->n_ref > 0);
740 m->n_ref--;
741
742 if (m->n_ref <= 0)
743 message_free(m);
744
745 return NULL;
746}
747
d9f644e2 748_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
9d6c7c82
LP
749 assert_return(m, -EINVAL);
750 assert_return(type, -EINVAL);
de1c301e
LP
751
752 *type = m->header->type;
753 return 0;
754}
755
d9f644e2 756_public_ int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial) {
9d6c7c82
LP
757 assert_return(m, -EINVAL);
758 assert_return(serial, -EINVAL);
759 assert_return(m->header->serial != 0, -ENOENT);
de1c301e
LP
760
761 *serial = BUS_MESSAGE_SERIAL(m);
762 return 0;
763}
764
d9f644e2 765_public_ int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial) {
9d6c7c82
LP
766 assert_return(m, -EINVAL);
767 assert_return(serial, -EINVAL);
768 assert_return(m->reply_serial != 0, -ENOENT);
de1c301e
LP
769
770 *serial = m->reply_serial;
771 return 0;
772}
773
d9f644e2 774_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
9d6c7c82 775 assert_return(m, -EINVAL);
de1c301e 776
40ca29a1 777 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
de1c301e
LP
778}
779
1fee9de5
LP
780_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
781 assert_return(m, -EINVAL);
782
783 return !!(m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START);
784}
785
d9f644e2 786_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
9d6c7c82 787 assert_return(m, NULL);
de1c301e
LP
788
789 return m->path;
790}
791
d9f644e2 792_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
9d6c7c82 793 assert_return(m, NULL);
de1c301e
LP
794
795 return m->interface;
796}
797
d9f644e2 798_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
9d6c7c82 799 assert_return(m, NULL);
de1c301e
LP
800
801 return m->member;
802}
d9f644e2
ZJS
803
804_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
9d6c7c82 805 assert_return(m, NULL);
de1c301e
LP
806
807 return m->destination;
808}
809
d9f644e2 810_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
9d6c7c82 811 assert_return(m, NULL);
de1c301e
LP
812
813 return m->sender;
814}
815
d9f644e2 816_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
9d6c7c82
LP
817 assert_return(m, NULL);
818 assert_return(sd_bus_error_is_set(&m->error), NULL);
de1c301e
LP
819
820 return &m->error;
821}
822
d9f644e2 823_public_ int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid) {
9d6c7c82
LP
824 assert_return(m, -EINVAL);
825 assert_return(uid, -EINVAL);
826 assert_return(m->uid_valid, -ESRCH);
de1c301e
LP
827
828 *uid = m->uid;
829 return 0;
830}
831
d9f644e2 832_public_ int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid) {
9d6c7c82
LP
833 assert_return(m, -EINVAL);
834 assert_return(gid, -EINVAL);
835 assert_return(m->gid_valid, -ESRCH);
de1c301e
LP
836
837 *gid = m->gid;
838 return 0;
839}
840
d9f644e2 841_public_ int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid) {
9d6c7c82
LP
842 assert_return(m, -EINVAL);
843 assert_return(pid, -EINVAL);
844 assert_return(m->pid > 0, -ESRCH);
de1c301e
LP
845
846 *pid = m->pid;
847 return 0;
848}
849
d9f644e2 850_public_ int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) {
9d6c7c82
LP
851 assert_return(m, -EINVAL);
852 assert_return(tid, -EINVAL);
853 assert_return(m->tid > 0, -ESRCH);
de1c301e
LP
854
855 *tid = m->tid;
856 return 0;
857}
858
d9f644e2 859_public_ int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
860 assert_return(m, -EINVAL);
861 assert_return(usec, -EINVAL);
862 assert_return(m->pid_starttime > 0, -ESRCH);
8323bc1f
LP
863
864 *usec = m->pid_starttime;
865 return 0;
866}
867
d9f644e2 868_public_ int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **ret) {
9d6c7c82
LP
869 assert_return(m, -EINVAL);
870 assert_return(m->label, -ESRCH);
2571ead1 871
4a875b61
LP
872 *ret = m->label;
873 return 0;
2571ead1
LP
874}
875
d9f644e2 876_public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
877 assert_return(m, -EINVAL);
878 assert_return(usec, -EINVAL);
879 assert_return(m->monotonic > 0, -ESRCH);
acb5a3cb 880
69aec65c 881 *usec = m->monotonic;
acb5a3cb
LP
882 return 0;
883}
884
d9f644e2 885_public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
886 assert_return(m, -EINVAL);
887 assert_return(usec, -EINVAL);
888 assert_return(m->realtime > 0, -ESRCH);
69aec65c
LP
889
890 *usec = m->realtime;
891 return 0;
892}
893
d9f644e2 894_public_ int sd_bus_message_get_comm(sd_bus_message *m, const char **ret) {
9d6c7c82
LP
895 assert_return(m, -EINVAL);
896 assert_return(ret, -EINVAL);
897 assert_return(m->comm, -ESRCH);
69aec65c 898
4a875b61
LP
899 *ret = m->comm;
900 return 0;
69aec65c
LP
901}
902
d9f644e2 903_public_ int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **ret) {
9d6c7c82
LP
904 assert_return(m, -EINVAL);
905 assert_return(ret, -EINVAL);
906 assert_return(m->tid_comm, -ESRCH);
69aec65c 907
4a875b61
LP
908 *ret = m->tid_comm;
909 return 0;
69aec65c
LP
910}
911
d9f644e2 912_public_ int sd_bus_message_get_exe(sd_bus_message *m, const char **ret) {
9d6c7c82
LP
913 assert_return(m, -EINVAL);
914 assert_return(ret, -EINVAL);
915 assert_return(m->exe, -ESRCH);
69aec65c 916
4a875b61
LP
917 *ret = m->exe;
918 return 0;
919}
920
d9f644e2 921_public_ int sd_bus_message_get_cgroup(sd_bus_message *m, const char **ret) {
9d6c7c82
LP
922 assert_return(m, -EINVAL);
923 assert_return(ret, -EINVAL);
924 assert_return(m->cgroup, -ESRCH);
4a875b61
LP
925
926 *ret = m->cgroup;
927 return 0;
69aec65c
LP
928}
929
d9f644e2 930_public_ int sd_bus_message_get_unit(sd_bus_message *m, const char **ret) {
d8d3d8a7
LP
931 int r;
932
9d6c7c82
LP
933 assert_return(m, -EINVAL);
934 assert_return(ret, -EINVAL);
935 assert_return(m->cgroup, -ESRCH);
d8d3d8a7
LP
936
937 if (!m->unit) {
938 r = cg_path_get_unit(m->cgroup, &m->unit);
939 if (r < 0)
940 return r;
941 }
942
943 *ret = m->unit;
944 return 0;
945}
946
d9f644e2 947_public_ int sd_bus_message_get_user_unit(sd_bus_message *m, const char **ret) {
d8d3d8a7
LP
948 int r;
949
9d6c7c82
LP
950 assert_return(m, -EINVAL);
951 assert_return(ret, -EINVAL);
952 assert_return(m->cgroup, -ESRCH);
d8d3d8a7
LP
953
954 if (!m->user_unit) {
955 r = cg_path_get_user_unit(m->cgroup, &m->user_unit);
956 if (r < 0)
957 return r;
958 }
959
960 *ret = m->user_unit;
961 return 0;
962}
963
d9f644e2 964_public_ int sd_bus_message_get_session(sd_bus_message *m, const char **ret) {
d8d3d8a7
LP
965 int r;
966
9d6c7c82
LP
967 assert_return(m, -EINVAL);
968 assert_return(ret, -EINVAL);
969 assert_return(m->cgroup, -ESRCH);
d8d3d8a7
LP
970
971 if (!m->session) {
972 r = cg_path_get_session(m->cgroup, &m->session);
973 if (r < 0)
974 return r;
975 }
976
977 *ret = m->session;
978 return 0;
979}
980
d9f644e2 981_public_ int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid) {
9d6c7c82
LP
982 assert_return(m, -EINVAL);
983 assert_return(uid, -EINVAL);
984 assert_return(m->cgroup, -ESRCH);
bc7f3beb
LP
985
986 return cg_path_get_owner_uid(m->cgroup, uid);
987}
988
d9f644e2 989_public_ int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline) {
77930f11
LP
990 size_t n, i;
991 const char *p;
992 bool first;
993
9d6c7c82
LP
994 assert_return(m, -EINVAL);
995 assert_return(m->cmdline, -ESRCH);
77930f11
LP
996
997 for (p = m->cmdline, n = 0; p < m->cmdline + m->cmdline_length; p++)
998 if (*p == 0)
999 n++;
1000
1001 m->cmdline_array = new(char*, n + 1);
1002 if (!m->cmdline_array)
1003 return -ENOMEM;
1004
1005 for (p = m->cmdline, i = 0, first = true; p < m->cmdline + m->cmdline_length; p++) {
1006 if (first)
1007 m->cmdline_array[i++] = (char*) p;
1008
1009 first = *p == 0;
1010 }
1011
1012 m->cmdline_array[i] = NULL;
1013 *cmdline = m->cmdline_array;
1014
1015 return 0;
1016}
1017
d9f644e2 1018_public_ int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid) {
9d6c7c82
LP
1019 assert_return(m, -EINVAL);
1020 assert_return(sessionid, -EINVAL);
1021 assert_return(m->audit, -ESRCH);
120f919e
LP
1022
1023 *sessionid = m->audit->sessionid;
1024 return 0;
1025}
1026
d9f644e2 1027_public_ int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *uid) {
9d6c7c82
LP
1028 assert_return(m, -EINVAL);
1029 assert_return(uid, -EINVAL);
1030 assert_return(m->audit, -ESRCH);
120f919e
LP
1031
1032 *uid = m->audit->loginuid;
1033 return 0;
1034}
1035
d9f644e2 1036_public_ int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability) {
102ea8e4
LP
1037 unsigned sz;
1038
9d6c7c82
LP
1039 assert_return(m, -EINVAL);
1040 assert_return(capability < 0, -EINVAL);
1041 assert_return(!m->capability, -ESRCH);
102ea8e4
LP
1042
1043 sz = m->capability_size / 4;
1044 if ((unsigned) capability >= sz*8)
1045 return 0;
1046
1047 return !!(m->capability[2 * sz + (capability / 8)] & (1 << (capability % 8)));
1048}
1049
d9f644e2
ZJS
1050_public_ int sd_bus_message_is_signal(sd_bus_message *m,
1051 const char *interface,
1052 const char *member) {
9d6c7c82 1053 assert_return(m, -EINVAL);
de1c301e 1054
40ca29a1 1055 if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
de1c301e
LP
1056 return 0;
1057
1058 if (interface && (!m->interface || !streq(m->interface, interface)))
1059 return 0;
1060
1061 if (member && (!m->member || !streq(m->member, member)))
1062 return 0;
1063
1064 return 1;
1065}
1066
d9f644e2
ZJS
1067_public_ int sd_bus_message_is_method_call(sd_bus_message *m,
1068 const char *interface,
1069 const char *member) {
9d6c7c82 1070 assert_return(m, -EINVAL);
de1c301e 1071
40ca29a1 1072 if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
de1c301e
LP
1073 return 0;
1074
1075 if (interface && (!m->interface || !streq(m->interface, interface)))
1076 return 0;
1077
1078 if (member && (!m->member || !streq(m->member, member)))
1079 return 0;
1080
1081 return 1;
1082}
1083
d9f644e2 1084_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
9d6c7c82 1085 assert_return(m, -EINVAL);
de1c301e 1086
40ca29a1 1087 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
de1c301e
LP
1088 return 0;
1089
1090 if (name && (!m->error.name || !streq(m->error.name, name)))
1091 return 0;
1092
1093 return 1;
1094}
1095
d9f644e2 1096_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
9d6c7c82
LP
1097 assert_return(m, -EINVAL);
1098 assert_return(!m->sealed, -EPERM);
1099 assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
de1c301e
LP
1100
1101 if (b)
1102 m->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
1103 else
1104 m->header->flags &= ~SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
1105
1106 return 0;
1107}
1108
1fee9de5
LP
1109_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
1110 assert_return(m, -EINVAL);
1111 assert_return(!m->sealed, -EPERM);
1112
1113 if (b)
1114 m->header->flags |= SD_BUS_MESSAGE_NO_AUTO_START;
1115 else
1116 m->header->flags &= ~SD_BUS_MESSAGE_NO_AUTO_START;
1117
1118 return 0;
1119}
1120
de1c301e
LP
1121static struct bus_container *message_get_container(sd_bus_message *m) {
1122 assert(m);
1123
1124 if (m->n_containers == 0)
1125 return &m->root_container;
1126
9a17484d
LP
1127 assert(m->containers);
1128 return m->containers + m->n_containers - 1;
de1c301e
LP
1129}
1130
bc7fd8cd
LP
1131struct bus_body_part *message_append_part(sd_bus_message *m) {
1132 struct bus_body_part *part;
1133
1134 assert(m);
1135
1136 if (m->poisoned)
1137 return NULL;
1138
1139 if (m->n_body_parts <= 0) {
1140 part = &m->body;
1141 zero(*part);
1142 } else {
1143 assert(m->body_end);
1144
1145 part = new0(struct bus_body_part, 1);
1146 if (!part) {
1147 m->poisoned = true;
1148 return NULL;
1149 }
1150
1151 m->body_end->next = part;
1152 }
1153
1154 part->memfd = -1;
1155 m->body_end = part;
1156 m->n_body_parts ++;
1157
1158 return part;
1159}
1160
1161static void part_zero(struct bus_body_part *part, size_t sz) {
1162 assert(part);
1163 assert(sz > 0);
1164 assert(sz < 8);
1165
453a0c29
LP
1166 /* All other fields can be left in their defaults */
1167 assert(!part->data);
1168 assert(part->memfd < 0);
1169
bc7fd8cd 1170 part->size = sz;
453a0c29
LP
1171 part->is_zero = true;
1172 part->sealed = true;
bc7fd8cd
LP
1173}
1174
1175static int part_make_space(
1176 struct sd_bus_message *m,
1177 struct bus_body_part *part,
1178 size_t sz,
1179 void **q) {
1180
1181 void *n;
1182 int r;
1183
1184 assert(m);
1185 assert(part);
1186 assert(!part->sealed);
1187
1188 if (m->poisoned)
1189 return -ENOMEM;
1190
1191 if (!part->data && part->memfd < 0)
1192 part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped);
1193
1194 if (part->memfd >= 0) {
1195 uint64_t u = sz;
1196
1197 r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &u);
1198 if (r < 0) {
1199 m->poisoned = true;
1200 return -errno;
1201 }
1202
453a0c29
LP
1203 if (!part->data || sz > part->mapped) {
1204 size_t psz = PAGE_ALIGN(sz > 0 ? sz : 1);
bc7fd8cd
LP
1205
1206 if (part->mapped <= 0)
1207 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
1208 else
1209 n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
1210
1211 if (n == MAP_FAILED) {
1212 m->poisoned = true;
1213 return -errno;
1214 }
1215
1216 part->mapped = psz;
1217 part->data = n;
1218 }
bf30e48f
KS
1219
1220 part->munmap_this = true;
bc7fd8cd 1221 } else {
23c6f770 1222 n = realloc(part->data, MAX(sz, 1u));
bc7fd8cd
LP
1223 if (!n) {
1224 m->poisoned = true;
1225 return -ENOMEM;
1226 }
1227
1228 part->data = n;
1229 part->free_this = true;
1230 }
1231
1232 if (q)
1233 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1234
1235 part->size = sz;
1236 return 0;
1237}
1238
453a0c29 1239static void message_extend_containers(sd_bus_message *m, size_t expand) {
de1c301e 1240 struct bus_container *c;
453a0c29
LP
1241
1242 assert(m);
1243
1244 if (expand <= 0)
1245 return;
1246
1247 /* Update counters */
1248 for (c = m->containers; c < m->containers + m->n_containers; c++)
1249 if (c->array_size)
1250 *c->array_size += expand;
453a0c29
LP
1251}
1252
1253static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz) {
bc7fd8cd
LP
1254 struct bus_body_part *part = NULL;
1255 size_t start_body, end_body, padding, start_part, end_part, added;
1256 bool add_new_part;
1257 void *p;
1258 int r;
de1c301e
LP
1259
1260 assert(m);
9a17484d 1261 assert(align > 0);
bc7fd8cd 1262 assert(!m->sealed);
de1c301e 1263
bc7fd8cd
LP
1264 if (m->poisoned)
1265 return NULL;
de1c301e 1266
bc7fd8cd
LP
1267 start_body = ALIGN_TO((size_t) m->header->body_size, align);
1268 end_body = start_body + sz;
1269
1270 padding = start_body - m->header->body_size;
1271 added = padding + sz;
1272
1273 /* Check for 32bit overflows */
1274 if (end_body > (size_t) ((uint32_t) -1)) {
1275 m->poisoned = true;
de1c301e 1276 return NULL;
bc7fd8cd 1277 }
de1c301e 1278
bc7fd8cd
LP
1279 add_new_part =
1280 m->n_body_parts <= 0 ||
1281 m->body_end->sealed ||
1282 padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
de1c301e 1283
bc7fd8cd
LP
1284 if (add_new_part) {
1285 if (padding > 0) {
1286 part = message_append_part(m);
1287 if (!part)
1288 return NULL;
1289
1290 part_zero(part, padding);
1291 }
1292
1293 part = message_append_part(m);
1294 if (!part)
1295 return NULL;
1296
1297 r = part_make_space(m, part, sz, &p);
1298 if (r < 0)
1299 return NULL;
1300 } else {
453a0c29 1301 struct bus_container *c;
bc7fd8cd
LP
1302 void *op;
1303 size_t os;
1304
1305 part = m->body_end;
1306 op = part->data;
1307 os = part->size;
1308
1309 start_part = ALIGN_TO(part->size, align);
1310 end_part = start_part + sz;
1311
1312 r = part_make_space(m, part, end_part, &p);
1313 if (r < 0)
1314 return NULL;
1315
1316 if (padding > 0) {
1317 memset(p, 0, padding);
1318 p = (uint8_t*) p + padding;
de1c301e
LP
1319 }
1320
bc7fd8cd
LP
1321 /* Readjust pointers */
1322 for (c = m->containers; c < m->containers + m->n_containers; c++)
1323 c->array_size = adjust_pointer(c->array_size, op, os, part->data);
1324
1325 m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
de1c301e
LP
1326 }
1327
bc7fd8cd 1328 m->header->body_size = end_body;
453a0c29 1329 message_extend_containers(m, added);
de1c301e
LP
1330
1331 return p;
1332}
1333
1334int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
1335 struct bus_container *c;
27f6e5c7 1336 ssize_t align, sz;
de1c301e
LP
1337 uint32_t k;
1338 void *a;
2c93b4ef 1339 int fd = -1;
62cfa9da 1340 uint32_t fdi = 0;
2c93b4ef 1341 int r;
de1c301e 1342
9d6c7c82 1343 assert_return(m, -EINVAL);
9d6c7c82
LP
1344 assert_return(!m->sealed, -EPERM);
1345 assert_return(bus_type_is_basic(type), -EINVAL);
1346 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1347
1348 c = message_get_container(m);
1349
1350 if (c->signature && c->signature[c->index]) {
1351 /* Container signature is already set */
1352
1353 if (c->signature[c->index] != type)
9a17484d 1354 return -ENXIO;
de1c301e 1355 } else {
5cbe7492
LP
1356 char *e;
1357
de1c301e
LP
1358 /* Maybe we can append to the signature? But only if this is the top-level container*/
1359 if (c->enclosing != 0)
9a17484d 1360 return -ENXIO;
de1c301e
LP
1361
1362 e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
bc7fd8cd
LP
1363 if (!e) {
1364 m->poisoned = true;
de1c301e 1365 return -ENOMEM;
bc7fd8cd 1366 }
de1c301e
LP
1367 }
1368
de1c301e
LP
1369 switch (type) {
1370
1371 case SD_BUS_TYPE_STRING:
cd6f997f
LP
1372 /* To make things easy we'll serialize a NULL string
1373 * into the empty string */
1374 p = strempty(p);
1375
1376 /* Fall through... */
de1c301e 1377 case SD_BUS_TYPE_OBJECT_PATH:
b8beb278 1378
cd6f997f
LP
1379 if (!p) {
1380 r = -EINVAL;
1381 goto fail;
1382 }
1383
de1c301e
LP
1384 align = 4;
1385 sz = 4 + strlen(p) + 1;
1386 break;
1387
1388 case SD_BUS_TYPE_SIGNATURE:
b8beb278 1389
cd6f997f
LP
1390 if (!p) {
1391 r = -EINVAL;
1392 goto fail;
1393 }
1394
de1c301e
LP
1395 align = 1;
1396 sz = 1 + strlen(p) + 1;
1397 break;
1398
1399 case SD_BUS_TYPE_BOOLEAN:
b3273daf 1400
15912917
KS
1401 if (!p) {
1402 r = -EINVAL;
1403 goto fail;
1404 }
1405
de1c301e
LP
1406 align = sz = 4;
1407
1408 assert_cc(sizeof(int) == sizeof(uint32_t));
1409 memcpy(&k, p, 4);
1410 k = !!k;
1411 p = &k;
1412 break;
1413
2c93b4ef
LP
1414 case SD_BUS_TYPE_UNIX_FD: {
1415 int z, *f;
1416
15912917
KS
1417 if (!p) {
1418 r = -EINVAL;
1419 goto fail;
1420 }
1421
2c93b4ef
LP
1422 if (!m->allow_fds) {
1423 r = -ENOTSUP;
1424 goto fail;
1425 }
1426
1427 align = sz = 4;
1428
1429 z = *(int*) p;
1430 if (z < 0) {
1431 r = -EINVAL;
1432 goto fail;
1433 }
1434
1435 fd = fcntl(z, F_DUPFD_CLOEXEC, 3);
1436 if (fd < 0) {
1437 r = -errno;
1438 goto fail;
1439 }
1440
1441 f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
1442 if (!f) {
bc7fd8cd 1443 m->poisoned = true;
2c93b4ef
LP
1444 r = -ENOMEM;
1445 goto fail;
1446 }
1447
1448 fdi = m->n_fds;
1449 f[fdi] = fd;
1450 m->fds = f;
1451 m->free_fds = true;
1452 break;
1453 }
1454
de1c301e 1455 default:
b3273daf
LP
1456 if (!p) {
1457 r = -EINVAL;
1458 goto fail;
1459 }
1460
de1c301e
LP
1461 align = bus_type_get_alignment(type);
1462 sz = bus_type_get_size(type);
1463 break;
1464 }
1465
1466 assert(align > 0);
1467 assert(sz > 0);
1468
1469 a = message_extend_body(m, align, sz);
1470 if (!a) {
2c93b4ef
LP
1471 r = -ENOMEM;
1472 goto fail;
de1c301e
LP
1473 }
1474
1475 if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
1476 *(uint32_t*) a = sz - 5;
1477 memcpy((uint8_t*) a + 4, p, sz - 4);
1478
1479 if (stored)
1480 *stored = (const uint8_t*) a + 4;
1481
1482 } else if (type == SD_BUS_TYPE_SIGNATURE) {
1483 *(uint8_t*) a = sz - 1;
1484 memcpy((uint8_t*) a + 1, p, sz - 1);
1485
1486 if (stored)
1487 *stored = (const uint8_t*) a + 1;
2c93b4ef
LP
1488 } else if (type == SD_BUS_TYPE_UNIX_FD) {
1489 *(uint32_t*) a = fdi;
1490
1491 if (stored)
1492 *stored = a;
1493
1494 m->n_fds ++;
de1c301e
LP
1495
1496 } else {
1497 memcpy(a, p, sz);
1498
1499 if (stored)
1500 *stored = a;
1501 }
1502
1503 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1504 c->index++;
de1c301e
LP
1505
1506 return 0;
2c93b4ef
LP
1507
1508fail:
2c93b4ef
LP
1509 if (fd >= 0)
1510 close_nointr_nofail(fd);
1511
1512 return r;
de1c301e
LP
1513}
1514
d9f644e2 1515_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
de1c301e
LP
1516 return message_append_basic(m, type, p, NULL);
1517}
1518
938bcbab
LP
1519_public_ int sd_bus_message_append_string_space(
1520 sd_bus_message *m,
1521 size_t size,
1522 char **s) {
1523
f8e013f8 1524 struct bus_container *c;
f8e013f8 1525 void *a;
f8e013f8 1526
9d6c7c82
LP
1527 assert_return(m, -EINVAL);
1528 assert_return(s, -EINVAL);
1529 assert_return(!m->sealed, -EPERM);
1530 assert_return(!m->poisoned, -ESTALE);
f8e013f8
LP
1531
1532 c = message_get_container(m);
1533
1534 if (c->signature && c->signature[c->index]) {
1535 /* Container signature is already set */
1536
1537 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1538 return -ENXIO;
1539 } else {
5cbe7492
LP
1540 char *e;
1541
f8e013f8
LP
1542 /* Maybe we can append to the signature? But only if this is the top-level container*/
1543 if (c->enclosing != 0)
1544 return -ENXIO;
1545
1546 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
bc7fd8cd
LP
1547 if (!e) {
1548 m->poisoned = true;
f8e013f8 1549 return -ENOMEM;
bc7fd8cd 1550 }
f8e013f8
LP
1551 }
1552
f8e013f8 1553 a = message_extend_body(m, 4, 4 + size + 1);
bc7fd8cd
LP
1554 if (!a)
1555 return -ENOMEM;
f8e013f8
LP
1556
1557 *(uint32_t*) a = size;
1558 *s = (char*) a + 4;
1559
1560 (*s)[size] = 0;
1561
1562 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1563 c->index++;
1564
1565 return 0;
f8e013f8
LP
1566}
1567
938bcbab
LP
1568_public_ int sd_bus_message_append_string_iovec(
1569 sd_bus_message *m,
1570 const struct iovec *iov,
1571 unsigned n) {
1572
1573 size_t size;
1574 unsigned i;
1575 char *p;
1576 int r;
1577
1578 assert_return(m, -EINVAL);
1579 assert_return(!m->sealed, -EPERM);
1580 assert_return(iov || n == 0, -EINVAL);
1581 assert_return(!m->poisoned, -ESTALE);
1582
1583 size = IOVEC_TOTAL_SIZE(iov, n);
1584
1585 r = sd_bus_message_append_string_space(m, size, &p);
1586 if (r < 0)
1587 return r;
1588
1589 for (i = 0; i < n; i++) {
1590
1591 if (iov[i].iov_base)
1592 memcpy(p, iov[i].iov_base, iov[i].iov_len);
1593 else
1594 memset(p, ' ', iov[i].iov_len);
1595
1596 p += iov[i].iov_len;
1597 }
1598
1599 return 0;
1600}
1601
de1c301e
LP
1602static int bus_message_open_array(
1603 sd_bus_message *m,
1604 struct bus_container *c,
1605 const char *contents,
1606 uint32_t **array_size) {
1607
9a17484d 1608 unsigned nindex;
bc7fd8cd 1609 void *a, *op;
de1c301e 1610 int alignment;
bc7fd8cd
LP
1611 size_t os;
1612 struct bus_body_part *o;
de1c301e
LP
1613
1614 assert(m);
1615 assert(c);
1616 assert(contents);
1617 assert(array_size);
1618
29ddb38f 1619 if (!signature_is_single(contents, true))
de1c301e
LP
1620 return -EINVAL;
1621
1622 alignment = bus_type_get_alignment(contents[0]);
1623 if (alignment < 0)
1624 return alignment;
1625
1626 if (c->signature && c->signature[c->index]) {
1627
1628 /* Verify the existing signature */
1629
1630 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
9a17484d 1631 return -ENXIO;
de1c301e
LP
1632
1633 if (!startswith(c->signature + c->index + 1, contents))
9a17484d 1634 return -ENXIO;
de1c301e
LP
1635
1636 nindex = c->index + 1 + strlen(contents);
1637 } else {
5cbe7492
LP
1638 char *e;
1639
de1c301e 1640 if (c->enclosing != 0)
9a17484d 1641 return -ENXIO;
de1c301e
LP
1642
1643 /* Extend the existing signature */
1644
1645 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
bc7fd8cd
LP
1646 if (!e) {
1647 m->poisoned = true;
de1c301e 1648 return -ENOMEM;
bc7fd8cd 1649 }
de1c301e
LP
1650
1651 nindex = e - c->signature;
1652 }
1653
de1c301e 1654 a = message_extend_body(m, 4, 4);
bc7fd8cd 1655 if (!a)
de1c301e 1656 return -ENOMEM;
de1c301e 1657
bc7fd8cd
LP
1658 o = m->body_end;
1659 op = m->body_end->data;
1660 os = m->body_end->size;
de1c301e 1661
bc7fd8cd
LP
1662 /* Add alignment between size and first element */
1663 if (!message_extend_body(m, alignment, 0))
de1c301e 1664 return -ENOMEM;
de1c301e
LP
1665
1666 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1667 c->index = nindex;
1668
bc7fd8cd
LP
1669 /* location of array size might have changed so let's readjust a */
1670 if (o == m->body_end)
1671 a = adjust_pointer(a, op, os, m->body_end->data);
de1c301e 1672
bc7fd8cd 1673 *(uint32_t*) a = 0;
de1c301e
LP
1674 *array_size = a;
1675 return 0;
1676}
1677
1678static int bus_message_open_variant(
1679 sd_bus_message *m,
1680 struct bus_container *c,
1681 const char *contents) {
1682
9a17484d 1683 size_t l;
de1c301e
LP
1684 void *a;
1685
1686 assert(m);
1687 assert(c);
1688 assert(contents);
1689
29ddb38f 1690 if (!signature_is_single(contents, false))
de1c301e
LP
1691 return -EINVAL;
1692
1693 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1694 return -EINVAL;
1695
1696 if (c->signature && c->signature[c->index]) {
1697
1698 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
9a17484d 1699 return -ENXIO;
de1c301e
LP
1700
1701 } else {
5cbe7492
LP
1702 char *e;
1703
de1c301e 1704 if (c->enclosing != 0)
9a17484d 1705 return -ENXIO;
de1c301e
LP
1706
1707 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
bc7fd8cd
LP
1708 if (!e) {
1709 m->poisoned = true;
de1c301e 1710 return -ENOMEM;
bc7fd8cd 1711 }
de1c301e
LP
1712 }
1713
de1c301e
LP
1714 l = strlen(contents);
1715 a = message_extend_body(m, 1, 1 + l + 1);
bc7fd8cd 1716 if (!a)
de1c301e 1717 return -ENOMEM;
de1c301e
LP
1718
1719 *(uint8_t*) a = l;
1720 memcpy((uint8_t*) a + 1, contents, l + 1);
1721
1722 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1723 c->index++;
de1c301e
LP
1724
1725 return 0;
1726}
1727
1728static int bus_message_open_struct(
1729 sd_bus_message *m,
1730 struct bus_container *c,
1731 const char *contents) {
1732
1733 size_t nindex;
de1c301e
LP
1734
1735 assert(m);
1736 assert(c);
1737 assert(contents);
1738
1739 if (!signature_is_valid(contents, false))
1740 return -EINVAL;
1741
1742 if (c->signature && c->signature[c->index]) {
1743 size_t l;
1744
1745 l = strlen(contents);
1746
1747 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1748 !startswith(c->signature + c->index + 1, contents) ||
1749 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
9a17484d 1750 return -ENXIO;
de1c301e
LP
1751
1752 nindex = c->index + 1 + l + 1;
1753 } else {
5cbe7492
LP
1754 char *e;
1755
de1c301e 1756 if (c->enclosing != 0)
9a17484d 1757 return -ENXIO;
de1c301e
LP
1758
1759 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
bc7fd8cd
LP
1760 if (!e) {
1761 m->poisoned = true;
de1c301e 1762 return -ENOMEM;
bc7fd8cd 1763 }
de1c301e
LP
1764
1765 nindex = e - c->signature;
1766 }
1767
1768 /* Align contents to 8 byte boundary */
bc7fd8cd 1769 if (!message_extend_body(m, 8, 0))
de1c301e 1770 return -ENOMEM;
de1c301e
LP
1771
1772 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1773 c->index = nindex;
1774
1775 return 0;
1776}
1777
1778static int bus_message_open_dict_entry(
1779 sd_bus_message *m,
1780 struct bus_container *c,
1781 const char *contents) {
1782
1783 size_t nindex;
1784
1785 assert(m);
1786 assert(c);
1787 assert(contents);
1788
1789 if (!signature_is_pair(contents))
1790 return -EINVAL;
1791
1792 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1793 return -ENXIO;
de1c301e
LP
1794
1795 if (c->signature && c->signature[c->index]) {
1796 size_t l;
1797
1798 l = strlen(contents);
1799
1800 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
1801 !startswith(c->signature + c->index + 1, contents) ||
1802 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
9a17484d 1803 return -ENXIO;
de1c301e
LP
1804
1805 nindex = c->index + 1 + l + 1;
1806 } else
9a17484d 1807 return -ENXIO;
de1c301e
LP
1808
1809 /* Align contents to 8 byte boundary */
1810 if (!message_extend_body(m, 8, 0))
1811 return -ENOMEM;
1812
1813 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1814 c->index = nindex;
1815
1816 return 0;
1817}
1818
d9f644e2 1819_public_ int sd_bus_message_open_container(
de1c301e
LP
1820 sd_bus_message *m,
1821 char type,
1822 const char *contents) {
1823
9a17484d 1824 struct bus_container *c, *w;
de1c301e 1825 uint32_t *array_size = NULL;
9a17484d 1826 char *signature;
b3af9646 1827 size_t before;
de1c301e
LP
1828 int r;
1829
9d6c7c82
LP
1830 assert_return(m, -EINVAL);
1831 assert_return(!m->sealed, -EPERM);
1832 assert_return(contents, -EINVAL);
1833 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1834
1835 /* Make sure we have space for one more container */
9a17484d 1836 w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
bc7fd8cd
LP
1837 if (!w) {
1838 m->poisoned = true;
de1c301e 1839 return -ENOMEM;
bc7fd8cd
LP
1840 }
1841
9a17484d 1842 m->containers = w;
de1c301e
LP
1843
1844 c = message_get_container(m);
1845
1846 signature = strdup(contents);
bc7fd8cd
LP
1847 if (!signature) {
1848 m->poisoned = true;
de1c301e 1849 return -ENOMEM;
bc7fd8cd 1850 }
de1c301e 1851
b3af9646
LP
1852 /* Save old index in the parent container, in case we have to
1853 * abort this container */
1854 c->saved_index = c->index;
1855 before = m->header->body_size;
1856
de1c301e
LP
1857 if (type == SD_BUS_TYPE_ARRAY)
1858 r = bus_message_open_array(m, c, contents, &array_size);
1859 else if (type == SD_BUS_TYPE_VARIANT)
1860 r = bus_message_open_variant(m, c, contents);
1861 else if (type == SD_BUS_TYPE_STRUCT)
1862 r = bus_message_open_struct(m, c, contents);
1863 else if (type == SD_BUS_TYPE_DICT_ENTRY)
1864 r = bus_message_open_dict_entry(m, c, contents);
1865 else
1866 r = -EINVAL;
1867
1868 if (r < 0) {
1869 free(signature);
1870 return r;
1871 }
1872
1873 /* OK, let's fill it in */
9a17484d
LP
1874 w += m->n_containers++;
1875 w->enclosing = type;
1876 w->signature = signature;
1877 w->index = 0;
1878 w->array_size = array_size;
b3af9646
LP
1879 w->before = before;
1880 w->begin = m->rindex;
de1c301e
LP
1881
1882 return 0;
1883}
1884
d9f644e2 1885_public_ int sd_bus_message_close_container(sd_bus_message *m) {
de1c301e
LP
1886 struct bus_container *c;
1887
9d6c7c82
LP
1888 assert_return(m, -EINVAL);
1889 assert_return(!m->sealed, -EPERM);
1890 assert_return(m->n_containers > 0, -EINVAL);
1891 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1892
1893 c = message_get_container(m);
de1c301e 1894 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1895 if (c->signature && c->signature[c->index] != 0)
de1c301e
LP
1896 return -EINVAL;
1897
1898 free(c->signature);
1899 m->n_containers--;
1900
1901 return 0;
1902}
1903
1b492614
LP
1904typedef struct {
1905 const char *types;
1906 unsigned n_struct;
1907 unsigned n_array;
1908} TypeStack;
1909
1910static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
1911 assert(stack);
1912 assert(max > 0);
1913
1914 if (*i >= max)
1915 return -EINVAL;
1916
1917 stack[*i].types = types;
1918 stack[*i].n_struct = n_struct;
1919 stack[*i].n_array = n_array;
1920 (*i)++;
1921
1922 return 0;
1923}
1924
1925static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
1926 assert(stack);
1927 assert(max > 0);
1928 assert(types);
1929 assert(n_struct);
1930 assert(n_array);
1931
1932 if (*i <= 0)
1933 return 0;
1934
1935 (*i)--;
1936 *types = stack[*i].types;
1937 *n_struct = stack[*i].n_struct;
1938 *n_array = stack[*i].n_array;
1939
1940 return 1;
1941}
1942
917b5dc7 1943int bus_message_append_ap(
de1c301e
LP
1944 sd_bus_message *m,
1945 const char *types,
1946 va_list ap) {
1947
1b492614
LP
1948 unsigned n_array, n_struct;
1949 TypeStack stack[BUS_CONTAINER_DEPTH];
1950 unsigned stack_ptr = 0;
de1c301e
LP
1951 int r;
1952
1953 assert(m);
88d331d5
LP
1954
1955 if (!types)
1956 return 0;
de1c301e 1957
1b492614
LP
1958 n_array = (unsigned) -1;
1959 n_struct = strlen(types);
1960
1961 for (;;) {
1962 const char *t;
1963
1964 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
1965 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
1966 if (r < 0)
1967 return r;
1968 if (r == 0)
1969 break;
1970
1971 r = sd_bus_message_close_container(m);
1972 if (r < 0)
1973 return r;
1974
1975 continue;
1976 }
1977
1978 t = types;
1979 if (n_array != (unsigned) -1)
1980 n_array --;
1981 else {
1982 types ++;
1983 n_struct--;
1984 }
1985
de1c301e
LP
1986 switch (*t) {
1987
1988 case SD_BUS_TYPE_BYTE: {
1989 uint8_t x;
1990
1991 x = (uint8_t) va_arg(ap, int);
1992 r = sd_bus_message_append_basic(m, *t, &x);
1993 break;
1994 }
1995
1996 case SD_BUS_TYPE_BOOLEAN:
1997 case SD_BUS_TYPE_INT32:
9a17484d
LP
1998 case SD_BUS_TYPE_UINT32:
1999 case SD_BUS_TYPE_UNIX_FD: {
de1c301e
LP
2000 uint32_t x;
2001
9a17484d
LP
2002 /* We assume a boolean is the same as int32_t */
2003 assert_cc(sizeof(int32_t) == sizeof(int));
2004
de1c301e
LP
2005 x = va_arg(ap, uint32_t);
2006 r = sd_bus_message_append_basic(m, *t, &x);
2007 break;
2008 }
2009
2010 case SD_BUS_TYPE_INT16:
2011 case SD_BUS_TYPE_UINT16: {
2012 uint16_t x;
2013
2014 x = (uint16_t) va_arg(ap, int);
2015 r = sd_bus_message_append_basic(m, *t, &x);
2016 break;
2017 }
2018
2019 case SD_BUS_TYPE_INT64:
2020 case SD_BUS_TYPE_UINT64:
2021 case SD_BUS_TYPE_DOUBLE: {
2022 uint64_t x;
2023
2024 x = va_arg(ap, uint64_t);
2025 r = sd_bus_message_append_basic(m, *t, &x);
2026 break;
2027 }
2028
2029 case SD_BUS_TYPE_STRING:
2030 case SD_BUS_TYPE_OBJECT_PATH:
2031 case SD_BUS_TYPE_SIGNATURE: {
2032 const char *x;
2033
2034 x = va_arg(ap, const char*);
2035 r = sd_bus_message_append_basic(m, *t, x);
2036 break;
2037 }
2038
de1c301e 2039 case SD_BUS_TYPE_ARRAY: {
de1c301e
LP
2040 size_t k;
2041
2042 r = signature_element_length(t + 1, &k);
2043 if (r < 0)
2044 return r;
2045
2046 {
2047 char s[k + 1];
de1c301e
LP
2048 memcpy(s, t + 1, k);
2049 s[k] = 0;
de1c301e
LP
2050
2051 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
2052 if (r < 0)
2053 return r;
1b492614 2054 }
de1c301e 2055
1b492614
LP
2056 if (n_array == (unsigned) -1) {
2057 types += k;
2058 n_struct -= k;
de1c301e
LP
2059 }
2060
1b492614
LP
2061 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2062 if (r < 0)
2063 return r;
2064
2065 types = t + 1;
2066 n_struct = k;
2067 n_array = va_arg(ap, unsigned);
2068
de1c301e
LP
2069 break;
2070 }
2071
2072 case SD_BUS_TYPE_VARIANT: {
2073 const char *s;
2074
2075 s = va_arg(ap, const char*);
2076 if (!s)
2077 return -EINVAL;
2078
2079 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
2080 if (r < 0)
2081 return r;
2082
1b492614 2083 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
de1c301e
LP
2084 if (r < 0)
2085 return r;
2086
1b492614
LP
2087 types = s;
2088 n_struct = strlen(s);
2089 n_array = (unsigned) -1;
2090
de1c301e
LP
2091 break;
2092 }
2093
2094 case SD_BUS_TYPE_STRUCT_BEGIN:
2095 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
2096 size_t k;
2097
2098 r = signature_element_length(t, &k);
2099 if (r < 0)
2100 return r;
2101
2102 {
2103 char s[k - 1];
2104
2105 memcpy(s, t + 1, k - 2);
2106 s[k - 2] = 0;
2107
2108 r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
2109 if (r < 0)
2110 return r;
1b492614 2111 }
de1c301e 2112
1b492614
LP
2113 if (n_array == (unsigned) -1) {
2114 types += k - 1;
2115 n_struct -= k - 1;
2116 }
de1c301e 2117
1b492614
LP
2118 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2119 if (r < 0)
2120 return r;
de1c301e 2121
1b492614
LP
2122 types = t + 1;
2123 n_struct = k - 2;
2124 n_array = (unsigned) -1;
de1c301e
LP
2125
2126 break;
2127 }
2128
2129 default:
2130 r = -EINVAL;
2131 }
2132
2133 if (r < 0)
2134 return r;
2135 }
2136
2137 return 0;
2138}
2139
d9f644e2 2140_public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
de1c301e
LP
2141 va_list ap;
2142 int r;
2143
9d6c7c82
LP
2144 assert_return(m, -EINVAL);
2145 assert_return(types, -EINVAL);
2146 assert_return(!m->sealed, -EPERM);
2147 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
2148
2149 va_start(ap, types);
917b5dc7 2150 r = bus_message_append_ap(m, types, ap);
de1c301e
LP
2151 va_end(ap);
2152
2153 return r;
2154}
2155
d9f644e2
ZJS
2156_public_ int sd_bus_message_append_array_space(sd_bus_message *m,
2157 char type,
2158 size_t size,
2159 void **ptr) {
b3af9646
LP
2160 ssize_t align, sz;
2161 void *a;
2162 int r;
2163
9d6c7c82
LP
2164 assert_return(m, -EINVAL);
2165 assert_return(!m->sealed, -EPERM);
2166 assert_return(bus_type_is_trivial(type), -EINVAL);
2167 assert_return(ptr || size == 0, -EINVAL);
2168 assert_return(!m->poisoned, -ESTALE);
b3af9646
LP
2169
2170 align = bus_type_get_alignment(type);
2171 sz = bus_type_get_size(type);
2172
2173 assert_se(align > 0);
2174 assert_se(sz > 0);
2175
2176 if (size % sz != 0)
2177 return -EINVAL;
2178
2179 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2180 if (r < 0)
2181 return r;
2182
2183 a = message_extend_body(m, align, size);
bc7fd8cd
LP
2184 if (!a)
2185 return -ENOMEM;
b3af9646
LP
2186
2187 r = sd_bus_message_close_container(m);
2188 if (r < 0)
bc7fd8cd 2189 return r;
b3af9646
LP
2190
2191 *ptr = a;
2192 return 0;
b3af9646
LP
2193}
2194
d9f644e2
ZJS
2195_public_ int sd_bus_message_append_array(sd_bus_message *m,
2196 char type,
2197 const void *ptr,
2198 size_t size) {
b3af9646
LP
2199 int r;
2200 void *p;
2201
9d6c7c82
LP
2202 assert_return(m, -EINVAL);
2203 assert_return(!m->sealed, -EPERM);
2204 assert_return(bus_type_is_trivial(type), -EINVAL);
2205 assert_return(ptr || size == 0, -EINVAL);
2206 assert_return(!m->poisoned, -ESTALE);
b3af9646 2207
f8e013f8 2208 r = sd_bus_message_append_array_space(m, type, size, &p);
b3af9646
LP
2209 if (r < 0)
2210 return r;
2211
2212 if (size > 0)
2213 memcpy(p, ptr, size);
2214
2215 return 0;
2216}
2217
938bcbab
LP
2218_public_ int sd_bus_message_append_array_iovec(
2219 sd_bus_message *m,
2220 char type,
2221 const struct iovec *iov,
2222 unsigned n) {
2223
2224 size_t size;
2225 unsigned i;
2226 void *p;
2227 int r;
2228
2229 assert_return(m, -EINVAL);
2230 assert_return(!m->sealed, -EPERM);
2231 assert_return(bus_type_is_trivial(type), -EINVAL);
2232 assert_return(iov || n == 0, -EINVAL);
2233 assert_return(!m->poisoned, -ESTALE);
2234
2235 size = IOVEC_TOTAL_SIZE(iov, n);
2236
2237 r = sd_bus_message_append_array_space(m, type, size, &p);
2238 if (r < 0)
2239 return r;
2240
2241 for (i = 0; i < n; i++) {
2242
2243 if (iov[i].iov_base)
2244 memcpy(p, iov[i].iov_base, iov[i].iov_len);
2245 else
2246 memset(p, 0, iov[i].iov_len);
2247
2248 p = (uint8_t*) p + iov[i].iov_len;
2249 }
2250
2251 return 0;
2252}
2253
d9f644e2
ZJS
2254_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
2255 char type,
2256 sd_memfd *memfd) {
453a0c29
LP
2257 _cleanup_close_ int copy_fd = -1;
2258 struct bus_body_part *part;
2259 ssize_t align, sz;
2260 uint64_t size;
2261 void *a;
2262 int r;
2263
2264 if (!m)
2265 return -EINVAL;
2266 if (!memfd)
2267 return -EINVAL;
2268 if (m->sealed)
2269 return -EPERM;
2270 if (!bus_type_is_trivial(type))
2271 return -EINVAL;
2272 if (m->poisoned)
2273 return -ESTALE;
2274
2275 r = sd_memfd_set_sealed(memfd, true);
2276 if (r < 0)
2277 return r;
2278
2279 copy_fd = sd_memfd_dup_fd(memfd);
2280 if (copy_fd < 0)
2281 return copy_fd;
2282
2283 r = sd_memfd_get_size(memfd, &size);
2284 if (r < 0)
2285 return r;
2286
2287 align = bus_type_get_alignment(type);
2288 sz = bus_type_get_size(type);
2289
2290 assert_se(align > 0);
2291 assert_se(sz > 0);
2292
2293 if (size % sz != 0)
2294 return -EINVAL;
2295
5cbe7492 2296 if (size > (uint64_t) (uint32_t) -1)
453a0c29
LP
2297 return -EINVAL;
2298
2299 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2300 if (r < 0)
2301 return r;
2302
2303 a = message_extend_body(m, align, 0);
2304 if (!a)
2305 return -ENOMEM;
2306
2307 part = message_append_part(m);
2308 if (!part)
2309 return -ENOMEM;
2310
2311 part->memfd = copy_fd;
2312 part->sealed = true;
2313 part->size = size;
2314 copy_fd = -1;
2315
2316 message_extend_containers(m, size);
2317 m->header->body_size += size;
2318
2319 return sd_bus_message_close_container(m);
2320}
2321
d9f644e2 2322_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
5cbe7492
LP
2323 _cleanup_close_ int copy_fd = -1;
2324 struct bus_body_part *part;
2325 struct bus_container *c;
2326 uint64_t size;
2327 void *a;
2328 int r;
2329
55736ed0
LP
2330 assert_return(m, -EINVAL);
2331 assert_return(memfd, -EINVAL);
2332 assert_return(!m->sealed, -EPERM);
2333 assert_return(!m->poisoned, -ESTALE);
5cbe7492
LP
2334
2335 r = sd_memfd_set_sealed(memfd, true);
2336 if (r < 0)
2337 return r;
2338
2339 copy_fd = sd_memfd_dup_fd(memfd);
2340 if (copy_fd < 0)
2341 return copy_fd;
2342
2343 r = sd_memfd_get_size(memfd, &size);
2344 if (r < 0)
2345 return r;
2346
2347 /* We require this to be NUL terminated */
2348 if (size == 0)
2349 return -EINVAL;
2350
2351 if (size > (uint64_t) (uint32_t) -1)
2352 return -EINVAL;
2353
2354 c = message_get_container(m);
2355 if (c->signature && c->signature[c->index]) {
2356 /* Container signature is already set */
2357
2358 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2359 return -ENXIO;
2360 } else {
2361 char *e;
2362
2363 /* Maybe we can append to the signature? But only if this is the top-level container*/
2364 if (c->enclosing != 0)
2365 return -ENXIO;
2366
2367 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2368 if (!e) {
2369 m->poisoned = true;
2370 return -ENOMEM;
2371 }
2372 }
2373
2374 a = message_extend_body(m, 4, 4);
2375 if (!a)
2376 return -ENOMEM;
2377
2378 *(uint32_t*) a = size - 1;
2379
2380 part = message_append_part(m);
2381 if (!part)
2382 return -ENOMEM;
2383
2384 part->memfd = copy_fd;
2385 part->sealed = true;
2386 part->size = size;
2387 copy_fd = -1;
2388
2389 message_extend_containers(m, size);
2390 m->header->body_size += size;
2391
2392 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2393 c->index++;
2394
2395 return 0;
2396}
2397
d9f644e2 2398_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
55736ed0
LP
2399 char **i;
2400 int r;
2401
2402 assert_return(m, -EINVAL);
2403 assert_return(!m->sealed, -EPERM);
2404 assert_return(!m->poisoned, -ESTALE);
2405
2406 r = sd_bus_message_open_container(m, 'a', "s");
2407 if (r < 0)
2408 return r;
2409
2410 STRV_FOREACH(i, l) {
2411 r = sd_bus_message_append_basic(m, 's', *i);
2412 if (r < 0)
2413 return r;
2414 }
2415
2416 return sd_bus_message_close_container(m);
2417}
2418
a392d361 2419int bus_body_part_map(struct bus_body_part *part) {
453a0c29
LP
2420 void *p;
2421 size_t psz;
2422
2423 assert_se(part);
2424
2425 if (part->data)
2426 return 0;
2427
2428 if (part->size <= 0)
2429 return 0;
2430
1307c3ff
LP
2431 /* For smaller zero parts (as used for padding) we don't need to map anything... */
2432 if (part->memfd < 0 && part->is_zero && part->size < 8) {
2433 static const uint8_t zeroes[7] = { };
2434 part->data = (void*) zeroes;
2435 return 0;
2436 }
2437
453a0c29
LP
2438 psz = PAGE_ALIGN(part->size);
2439
2440 if (part->memfd >= 0)
2441 p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
2442 else if (part->is_zero)
2443 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
2444 else
2445 return -EINVAL;
2446
2447 if (p == MAP_FAILED)
2448 return -errno;
2449
2450 part->mapped = psz;
2451 part->data = p;
a392d361
LP
2452 part->munmap_this = true;
2453
453a0c29
LP
2454 return 0;
2455}
2456
a392d361
LP
2457void bus_body_part_unmap(struct bus_body_part *part) {
2458
2459 assert_se(part);
2460
2461 if (part->memfd < 0)
2462 return;
2463
a392d361
LP
2464 if (!part->data)
2465 return;
2466
bf30e48f
KS
2467 if (!part->munmap_this)
2468 return;
a392d361
LP
2469
2470 assert_se(munmap(part->data, part->mapped) == 0);
2471
2472 part->data = NULL;
2473 part->mapped = 0;
2474 part->munmap_this = false;
2475
2476 return;
2477}
2478
9a17484d 2479static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
bc7fd8cd 2480 size_t k, start, end;
de1c301e 2481
9a17484d
LP
2482 assert(rindex);
2483 assert(align > 0);
de1c301e 2484
9a17484d 2485 start = ALIGN_TO((size_t) *rindex, align);
bc7fd8cd 2486 end = start + nbytes;
9a17484d 2487
bc7fd8cd 2488 if (end > sz)
9a17484d
LP
2489 return -EBADMSG;
2490
2491 /* Verify that padding is 0 */
2492 for (k = *rindex; k < start; k++)
2493 if (((const uint8_t*) p)[k] != 0)
2494 return -EBADMSG;
2495
2496 if (r)
2497 *r = (uint8_t*) p + start;
2498
bc7fd8cd 2499 *rindex = end;
9a17484d
LP
2500
2501 return 1;
de1c301e
LP
2502}
2503
7b058942
LP
2504static bool message_end_of_signature(sd_bus_message *m) {
2505 struct bus_container *c;
2506
2507 assert(m);
2508
2509 c = message_get_container(m);
2510 return !c->signature || c->signature[c->index] == 0;
2511}
2512
9a17484d
LP
2513static bool message_end_of_array(sd_bus_message *m, size_t index) {
2514 struct bus_container *c;
de1c301e 2515
9a17484d 2516 assert(m);
de1c301e 2517
9a17484d
LP
2518 c = message_get_container(m);
2519 if (!c->array_size)
2520 return false;
de1c301e 2521
9a17484d 2522 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
de1c301e
LP
2523}
2524
1405bef3 2525_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
7b058942
LP
2526 assert_return(m, -EINVAL);
2527 assert_return(m->sealed, -EPERM);
2528
2529 if (complete && m->n_containers > 0)
2530 return false;
2531
2532 if (message_end_of_signature(m))
2533 return true;
2534
2535 if (message_end_of_array(m, m->rindex))
2536 return true;
2537
2538 return false;
2539}
2540
bc7fd8cd
LP
2541static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
2542 struct bus_body_part *part;
2543 size_t begin;
453a0c29
LP
2544 int r;
2545
bc7fd8cd
LP
2546 assert(m);
2547
2548 if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
2549 part = m->cached_rindex_part;
2550 begin = m->cached_rindex_part_begin;
2551 } else {
2552 part = &m->body;
2553 begin = 0;
2554 }
2555
2556 while (part) {
2557 if (index < begin)
2558 return NULL;
2559
2560 if (index + sz <= begin + part->size) {
453a0c29 2561
a392d361 2562 r = bus_body_part_map(part);
453a0c29
LP
2563 if (r < 0)
2564 return NULL;
2565
bc7fd8cd 2566 if (p)
453a0c29 2567 *p = (uint8_t*) part->data + index - begin;
bc7fd8cd
LP
2568
2569 m->cached_rindex_part = part;
2570 m->cached_rindex_part_begin = begin;
2571
2572 return part;
2573 }
2574
453a0c29 2575 begin += part->size;
bc7fd8cd
LP
2576 part = part->next;
2577 }
2578
2579 return NULL;
2580}
2581
2582static int message_peek_body(
2583 sd_bus_message *m,
2584 size_t *rindex,
2585 size_t align,
2586 size_t nbytes,
2587 void **ret) {
2588
2589 size_t k, start, end, padding;
2590 struct bus_body_part *part;
2591 uint8_t *q;
2592
de1c301e 2593 assert(m);
9a17484d
LP
2594 assert(rindex);
2595 assert(align > 0);
de1c301e 2596
9a17484d
LP
2597 if (message_end_of_array(m, *rindex))
2598 return 0;
de1c301e 2599
bc7fd8cd
LP
2600 start = ALIGN_TO((size_t) *rindex, align);
2601 padding = start - *rindex;
2602 end = start + nbytes;
2603
2604 if (end > BUS_MESSAGE_BODY_SIZE(m))
2605 return -EBADMSG;
2606
2607 part = find_part(m, *rindex, padding, (void**) &q);
2608 if (!part)
2609 return -EBADMSG;
2610
2611 if (q) {
2612 /* Verify padding */
2613 for (k = 0; k < padding; k++)
2614 if (q[k] != 0)
2615 return -EBADMSG;
2616 }
2617
2618 part = find_part(m, start, nbytes, (void**) &q);
2619 if (!part || !q)
2620 return -EBADMSG;
2621
2622 *rindex = end;
2623
2624 if (ret)
2625 *ret = q;
2626
2627 return 1;
9a17484d 2628}
de1c301e 2629
ac89bf1d 2630static bool validate_nul(const char *s, size_t l) {
de1c301e 2631
9a17484d
LP
2632 /* Check for NUL chars in the string */
2633 if (memchr(s, 0, l))
2634 return false;
de1c301e 2635
9a17484d
LP
2636 /* Check for NUL termination */
2637 if (s[l] != 0)
2638 return false;
de1c301e 2639
ac89bf1d
LP
2640 return true;
2641}
2642
2643static bool validate_string(const char *s, size_t l) {
2644
2645 if (!validate_nul(s, l))
2646 return false;
2647
9a17484d
LP
2648 /* Check if valid UTF8 */
2649 if (!utf8_is_valid(s))
2650 return false;
2651
2652 return true;
de1c301e
LP
2653}
2654
9a17484d 2655static bool validate_signature(const char *s, size_t l) {
de1c301e 2656
ac89bf1d 2657 if (!validate_nul(s, l))
9a17484d 2658 return false;
de1c301e 2659
9a17484d
LP
2660 /* Check if valid signature */
2661 if (!signature_is_valid(s, true))
2662 return false;
2663
2664 return true;
2665}
2666
ac89bf1d
LP
2667static bool validate_object_path(const char *s, size_t l) {
2668
2669 if (!validate_nul(s, l))
2670 return false;
2671
2672 if (!object_path_is_valid(s))
2673 return false;
2674
2675 return true;
2676}
2677
d9f644e2 2678_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
9a17484d 2679 struct bus_container *c;
9a17484d 2680 void *q;
0dcd14b9 2681 int r;
9a17484d 2682
9d6c7c82
LP
2683 assert_return(m, -EINVAL);
2684 assert_return(m->sealed, -EPERM);
2685 assert_return(bus_type_is_basic(type), -EINVAL);
de1c301e 2686
7b058942 2687 if (message_end_of_signature(m))
430fb8fa 2688 return -ENXIO;
9a17484d 2689
1daf8121
LP
2690 if (message_end_of_array(m, m->rindex))
2691 return 0;
2692
7b058942 2693 c = message_get_container(m);
9a17484d
LP
2694 if (c->signature[c->index] != type)
2695 return -ENXIO;
2696
2697 switch (type) {
2698
2699 case SD_BUS_TYPE_STRING:
2700 case SD_BUS_TYPE_OBJECT_PATH: {
2701 uint32_t l;
2702 size_t rindex;
2703
2704 rindex = m->rindex;
2705 r = message_peek_body(m, &rindex, 4, 4, &q);
2706 if (r <= 0)
2707 return r;
2708
2709 l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
2710 r = message_peek_body(m, &rindex, 1, l+1, &q);
de1c301e
LP
2711 if (r < 0)
2712 return r;
9a17484d
LP
2713 if (r == 0)
2714 return -EBADMSG;
2715
ac89bf1d
LP
2716 if (type == SD_BUS_TYPE_OBJECT_PATH) {
2717 if (!validate_object_path(q, l))
2718 return -EBADMSG;
2719 } else {
2720 if (!validate_string(q, l))
2721 return -EBADMSG;
2722 }
9a17484d
LP
2723
2724 m->rindex = rindex;
0dcd14b9
LP
2725 if (p)
2726 *(const char**) p = q;
2727
9a17484d 2728 break;
de1c301e
LP
2729 }
2730
9a17484d
LP
2731 case SD_BUS_TYPE_SIGNATURE: {
2732 uint8_t l;
2733 size_t rindex;
2734
2735 rindex = m->rindex;
2736 r = message_peek_body(m, &rindex, 1, 1, &q);
2737 if (r <= 0)
2738 return r;
2739
2740 l = *(uint8_t*) q;
2741 r = message_peek_body(m, &rindex, 1, l+1, &q);
de1c301e
LP
2742 if (r < 0)
2743 return r;
9a17484d
LP
2744 if (r == 0)
2745 return -EBADMSG;
2746
2747 if (!validate_signature(q, l))
2748 return -EBADMSG;
2749
2750 m->rindex = rindex;
0dcd14b9
LP
2751
2752 if (p)
2753 *(const char**) p = q;
9a17484d 2754 break;
de1c301e
LP
2755 }
2756
9a17484d 2757 default: {
27f6e5c7
ZJS
2758 ssize_t sz, align;
2759 size_t rindex;
de1c301e 2760
9a17484d
LP
2761 align = bus_type_get_alignment(type);
2762 sz = bus_type_get_size(type);
27f6e5c7 2763 assert(align > 0 && sz > 0);
de1c301e 2764
2c93b4ef
LP
2765 rindex = m->rindex;
2766 r = message_peek_body(m, &rindex, align, sz, &q);
9a17484d
LP
2767 if (r <= 0)
2768 return r;
2769
2770 switch (type) {
2771
2772 case SD_BUS_TYPE_BYTE:
0dcd14b9
LP
2773 if (p)
2774 *(uint8_t*) p = *(uint8_t*) q;
9a17484d
LP
2775 break;
2776
2777 case SD_BUS_TYPE_BOOLEAN:
0dcd14b9 2778 if (p)
102d8f81 2779 *(int*) p = !!*(uint32_t*) q;
9a17484d
LP
2780 break;
2781
2782 case SD_BUS_TYPE_INT16:
2783 case SD_BUS_TYPE_UINT16:
0dcd14b9
LP
2784 if (p)
2785 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
9a17484d
LP
2786 break;
2787
2788 case SD_BUS_TYPE_INT32:
2789 case SD_BUS_TYPE_UINT32:
0dcd14b9
LP
2790 if (p)
2791 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
9a17484d
LP
2792 break;
2793
2794 case SD_BUS_TYPE_INT64:
2795 case SD_BUS_TYPE_UINT64:
2796 case SD_BUS_TYPE_DOUBLE:
0dcd14b9
LP
2797 if (p)
2798 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
9a17484d
LP
2799 break;
2800
2c93b4ef 2801 case SD_BUS_TYPE_UNIX_FD: {
2c93b4ef
LP
2802 uint32_t j;
2803
2804 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
2805 if (j >= m->n_fds)
2806 return -EBADMSG;
2807
0dcd14b9
LP
2808 if (p)
2809 *(int*) p = m->fds[j];
2c93b4ef
LP
2810 break;
2811 }
2812
9a17484d
LP
2813 default:
2814 assert_not_reached("Unknown basic type...");
2815 }
2816
b3af9646 2817 m->rindex = rindex;
2c93b4ef 2818
9a17484d
LP
2819 break;
2820 }
2821 }
2822
2823 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2824 c->index++;
2825
2826 return 1;
de1c301e
LP
2827}
2828
9a17484d
LP
2829static int bus_message_enter_array(
2830 sd_bus_message *m,
2831 struct bus_container *c,
2832 const char *contents,
2833 uint32_t **array_size) {
2834
2835 size_t rindex;
2836 void *q;
2837 int r, alignment;
2838
2839 assert(m);
2840 assert(c);
2841 assert(contents);
2842 assert(array_size);
2843
29ddb38f 2844 if (!signature_is_single(contents, true))
de1c301e 2845 return -EINVAL;
9a17484d
LP
2846
2847 alignment = bus_type_get_alignment(contents[0]);
2848 if (alignment < 0)
2849 return alignment;
2850
2851 if (!c->signature || c->signature[c->index] == 0)
2852 return 0;
2853
2854 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
2855 return -ENXIO;
2856
2857 if (!startswith(c->signature + c->index + 1, contents))
2858 return -ENXIO;
2859
2860 rindex = m->rindex;
2861 r = message_peek_body(m, &rindex, 4, 4, &q);
2862 if (r <= 0)
2863 return r;
2864
ac89bf1d 2865 if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
80a46c73 2866 return -EBADMSG;
9a17484d
LP
2867
2868 r = message_peek_body(m, &rindex, alignment, 0, NULL);
2869 if (r < 0)
2870 return r;
2871 if (r == 0)
2872 return -EBADMSG;
2873
2874 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2875 c->index += 1 + strlen(contents);
2876
2877 m->rindex = rindex;
2878
2879 *array_size = (uint32_t*) q;
2880
2881 return 1;
2882}
2883
2884static int bus_message_enter_variant(
2885 sd_bus_message *m,
2886 struct bus_container *c,
2887 const char *contents) {
2888
2889 size_t rindex;
2890 uint8_t l;
2891 void *q;
2892 int r;
2893
2894 assert(m);
2895 assert(c);
2896 assert(contents);
2897
29ddb38f 2898 if (!signature_is_single(contents, false))
de1c301e 2899 return -EINVAL;
de1c301e 2900
9a17484d
LP
2901 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
2902 return -EINVAL;
2903
2904 if (!c->signature || c->signature[c->index] == 0)
2905 return 0;
2906
2907 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
2908 return -ENXIO;
2909
2910 rindex = m->rindex;
2911 r = message_peek_body(m, &rindex, 1, 1, &q);
2912 if (r <= 0)
2913 return r;
2914
2915 l = *(uint8_t*) q;
2916 r = message_peek_body(m, &rindex, 1, l+1, &q);
2917 if (r < 0)
2918 return r;
2919 if (r == 0)
2920 return -EBADMSG;
2921
2922 if (!validate_signature(q, l))
2923 return -EBADMSG;
2924
2925 if (!streq(q, contents))
2926 return -ENXIO;
2927
2928 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2929 c->index++;
2930
2931 m->rindex = rindex;
2932
2933 return 1;
de1c301e
LP
2934}
2935
9a17484d
LP
2936static int bus_message_enter_struct(
2937 sd_bus_message *m,
2938 struct bus_container *c,
2939 const char *contents) {
2940
2941 size_t l;
2942 int r;
2943
2944 assert(m);
2945 assert(c);
2946 assert(contents);
2947
2948 if (!signature_is_valid(contents, false))
2949 return -EINVAL;
2950
2951 if (!c->signature || c->signature[c->index] == 0)
2952 return 0;
2953
2954 l = strlen(contents);
2955
2956 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
2957 !startswith(c->signature + c->index + 1, contents) ||
2958 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
2959 return -ENXIO;
2960
2961 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
2962 if (r <= 0)
2963 return r;
2964
2965 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2966 c->index += 1 + l + 1;
2967
2968 return 1;
2969}
2970
2971static int bus_message_enter_dict_entry(
2972 sd_bus_message *m,
2973 struct bus_container *c,
2974 const char *contents) {
2975
2976 size_t l;
2977 int r;
2978
2979 assert(m);
2980 assert(c);
2981 assert(contents);
2982
2983 if (!signature_is_pair(contents))
2984 return -EINVAL;
2985
2986 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2987 return -ENXIO;
2988
2989 if (!c->signature || c->signature[c->index] == 0)
2990 return 0;
2991
2992 l = strlen(contents);
2993
2994 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
2995 !startswith(c->signature + c->index + 1, contents) ||
2996 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
2997 return -ENXIO;
2998
2999 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
3000 if (r <= 0)
3001 return r;
3002
3003 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3004 c->index += 1 + l + 1;
3005
3006 return 1;
3007}
3008
d9f644e2
ZJS
3009_public_ int sd_bus_message_enter_container(sd_bus_message *m,
3010 char type,
3011 const char *contents) {
9a17484d
LP
3012 struct bus_container *c, *w;
3013 uint32_t *array_size = NULL;
3014 char *signature;
b3af9646 3015 size_t before;
9a17484d
LP
3016 int r;
3017
275b39fe
LP
3018 assert_return(m, -EINVAL);
3019 assert_return(m->sealed, -EPERM);
3020 assert_return(type != 0 || !contents, -EINVAL);
3021
3022 if (type == 0 || !contents) {
3023 const char *cc;
3024 char tt;
3025
3026 /* Allow entering into anonymous containers */
3027 r = sd_bus_message_peek_type(m, &tt, &cc);
3028 if (r <= 0)
3029 return r;
3030
3031 if (type != 0 && type != tt)
3032 return -ENXIO;
3033
3034 if (contents && !streq(contents, cc))
3035 return -ENXIO;
3036
3037 type = tt;
3038 contents = cc;
3039 }
9a17484d 3040
ed205a6b
LP
3041 /*
3042 * We enforce a global limit on container depth, that is much
3043 * higher than the 32 structs and 32 arrays the specification
3044 * mandates. This is simpler to implement for us, and we need
3045 * this only to ensure our container array doesn't grow
3046 * without bounds. We are happy to return any data from a
3047 * message as long as the data itself is valid, even if the
3048 * overall message might be not.
3049 *
3050 * Note that the message signature is validated when
3051 * parsing the headers, and that validation does check the
3052 * 32/32 limit.
3053 *
3054 * Note that the specification defines no limits on the depth
3055 * of stacked variants, but we do.
3056 */
3057 if (m->n_containers >= BUS_CONTAINER_DEPTH)
3058 return -EBADMSG;
3059
9a17484d
LP
3060 w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
3061 if (!w)
3062 return -ENOMEM;
3063 m->containers = w;
3064
7b058942 3065 if (message_end_of_signature(m))
430fb8fa 3066 return -ENXIO;
9a17484d 3067
1daf8121
LP
3068 if (message_end_of_array(m, m->rindex))
3069 return 0;
3070
7b058942
LP
3071 c = message_get_container(m);
3072
9a17484d
LP
3073 signature = strdup(contents);
3074 if (!signature)
3075 return -ENOMEM;
3076
b3af9646
LP
3077 c->saved_index = c->index;
3078 before = m->rindex;
3079
9a17484d
LP
3080 if (type == SD_BUS_TYPE_ARRAY)
3081 r = bus_message_enter_array(m, c, contents, &array_size);
3082 else if (type == SD_BUS_TYPE_VARIANT)
3083 r = bus_message_enter_variant(m, c, contents);
3084 else if (type == SD_BUS_TYPE_STRUCT)
3085 r = bus_message_enter_struct(m, c, contents);
3086 else if (type == SD_BUS_TYPE_DICT_ENTRY)
3087 r = bus_message_enter_dict_entry(m, c, contents);
3088 else
3089 r = -EINVAL;
3090
3091 if (r <= 0) {
3092 free(signature);
3093 return r;
3094 }
3095
3096 /* OK, let's fill it in */
3097 w += m->n_containers++;
3098 w->enclosing = type;
3099 w->signature = signature;
3100 w->index = 0;
3101 w->array_size = array_size;
b3af9646 3102 w->before = before;
9a17484d
LP
3103 w->begin = m->rindex;
3104
3105 return 1;
3106}
3107
d9f644e2 3108_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
9a17484d
LP
3109 struct bus_container *c;
3110
9d6c7c82
LP
3111 assert_return(m, -EINVAL);
3112 assert_return(m->sealed, -EPERM);
f959af20 3113 assert_return(m->n_containers > 0, -ENXIO);
9a17484d
LP
3114
3115 c = message_get_container(m);
3116 if (c->enclosing == SD_BUS_TYPE_ARRAY) {
3117 uint32_t l;
3118
3119 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
3120 if (c->begin + l != m->rindex)
3121 return -EBUSY;
3122
3123 } else {
3124 if (c->signature && c->signature[c->index] != 0)
f959af20 3125 return -EBUSY;
9a17484d
LP
3126 }
3127
3128 free(c->signature);
3129 m->n_containers--;
3130
3131 return 1;
3132}
3133
b3af9646
LP
3134static void message_quit_container(sd_bus_message *m) {
3135 struct bus_container *c;
3136
3137 assert(m);
3138 assert(m->sealed);
3139 assert(m->n_containers > 0);
3140
3141 c = message_get_container(m);
3142
3143 /* Undo seeks */
3144 assert(m->rindex >= c->before);
3145 m->rindex = c->before;
3146
3147 /* Free container */
3148 free(c->signature);
3149 m->n_containers--;
3150
3151 /* Correct index of new top-level container */
3152 c = message_get_container(m);
3153 c->index = c->saved_index;
3154}
3155
d9f644e2 3156_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
3157 struct bus_container *c;
3158 int r;
3159
c430fee6
LP
3160 assert_return(m, -EINVAL);
3161 assert_return(m->sealed, -EPERM);
9a17484d 3162
7b058942 3163 if (message_end_of_signature(m))
9a17484d
LP
3164 goto eof;
3165
3166 if (message_end_of_array(m, m->rindex))
3167 goto eof;
3168
7b058942
LP
3169 c = message_get_container(m);
3170
9a17484d
LP
3171 if (bus_type_is_basic(c->signature[c->index])) {
3172 if (contents)
3173 *contents = NULL;
3174 if (type)
3175 *type = c->signature[c->index];
3176 return 1;
3177 }
3178
3179 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
3180
3181 if (contents) {
3182 size_t l;
3183 char *sig;
3184
3185 r = signature_element_length(c->signature+c->index+1, &l);
3186 if (r < 0)
3187 return r;
3188
80a46c73
LP
3189 assert(l >= 1);
3190
9a17484d
LP
3191 sig = strndup(c->signature + c->index + 1, l);
3192 if (!sig)
3193 return -ENOMEM;
3194
3195 free(m->peeked_signature);
3196 m->peeked_signature = sig;
3197
3198 *contents = sig;
3199 }
3200
3201 if (type)
3202 *type = SD_BUS_TYPE_ARRAY;
3203
3204 return 1;
3205 }
3206
3207 if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
3208 c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
3209
3210 if (contents) {
3211 size_t l;
3212 char *sig;
3213
3214 r = signature_element_length(c->signature+c->index, &l);
3215 if (r < 0)
3216 return r;
3217
3218 assert(l >= 2);
3219 sig = strndup(c->signature + c->index + 1, l - 2);
3220 if (!sig)
3221 return -ENOMEM;
3222
3223 free(m->peeked_signature);
3224 m->peeked_signature = sig;
3225
3226 *contents = sig;
3227 }
3228
3229 if (type)
3230 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
3231
3232 return 1;
3233 }
3234
3235 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
3236 if (contents) {
3237 size_t rindex, l;
3238 void *q;
3239
3240 rindex = m->rindex;
3241 r = message_peek_body(m, &rindex, 1, 1, &q);
3242 if (r < 0)
3243 return r;
3244 if (r == 0)
3245 goto eof;
3246
3247 l = *(uint8_t*) q;
3248 r = message_peek_body(m, &rindex, 1, l+1, &q);
3249 if (r < 0)
3250 return r;
3251 if (r == 0)
3252 return -EBADMSG;
3253
3254 if (!validate_signature(q, l))
3255 return -EBADMSG;
3256
3257 *contents = q;
3258 }
3259
3260 if (type)
3261 *type = SD_BUS_TYPE_VARIANT;
3262
3263 return 1;
3264 }
3265
3266 return -EINVAL;
3267
3268eof:
3269 if (type)
7b058942 3270 *type = 0;
9a17484d
LP
3271 if (contents)
3272 *contents = NULL;
3273 return 0;
3274}
3275
d9f644e2 3276_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
3277 struct bus_container *c;
3278
9d6c7c82
LP
3279 assert_return(m, -EINVAL);
3280 assert_return(m->sealed, -EPERM);
9a17484d
LP
3281
3282 if (complete) {
bc7fd8cd 3283 message_reset_containers(m);
9a17484d
LP
3284 m->rindex = 0;
3285 m->root_container.index = 0;
3286
3287 c = message_get_container(m);
3288 } else {
3289 c = message_get_container(m);
3290
3291 c->index = 0;
3292 m->rindex = c->begin;
3293 }
3294
3295 return !isempty(c->signature);
3296}
718db961 3297
1b492614
LP
3298static int message_read_ap(
3299 sd_bus_message *m,
3300 const char *types,
3301 va_list ap) {
9a17484d 3302
fe1d424d
LP
3303 unsigned n_array, n_struct;
3304 TypeStack stack[BUS_CONTAINER_DEPTH];
3305 unsigned stack_ptr = 0;
430fb8fa 3306 unsigned n_loop = 0;
9a17484d
LP
3307 int r;
3308
3309 assert(m);
1b492614 3310
430fb8fa 3311 if (isempty(types))
1b492614 3312 return 0;
9a17484d 3313
fe1d424d
LP
3314 /* Ideally, we'd just call ourselves recursively on every
3315 * complex type. However, the state of a va_list that is
3316 * passed to a function is undefined after that function
3317 * returns. This means we need to docode the va_list linearly
3318 * in a single stackframe. We hence implement our own
3319 * home-grown stack in an array. */
3320
430fb8fa
LP
3321 n_array = (unsigned) -1; /* lenght of current array entries */
3322 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
3323
3324 for (;;) {
3325 const char *t;
3326
430fb8fa
LP
3327 n_loop++;
3328
1b492614 3329 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
3330 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
3331 if (r < 0)
3332 return r;
3333 if (r == 0)
3334 break;
3335
3336 r = sd_bus_message_exit_container(m);
3337 if (r < 0)
3338 return r;
3339
3340 continue;
3341 }
3342
3343 t = types;
3344 if (n_array != (unsigned) -1)
3345 n_array --;
3346 else {
3347 types ++;
3348 n_struct--;
3349 }
3350
9a17484d
LP
3351 switch (*t) {
3352
3353 case SD_BUS_TYPE_BYTE:
3354 case SD_BUS_TYPE_BOOLEAN:
3355 case SD_BUS_TYPE_INT16:
3356 case SD_BUS_TYPE_UINT16:
3357 case SD_BUS_TYPE_INT32:
3358 case SD_BUS_TYPE_UINT32:
3359 case SD_BUS_TYPE_INT64:
3360 case SD_BUS_TYPE_UINT64:
3361 case SD_BUS_TYPE_DOUBLE:
3362 case SD_BUS_TYPE_STRING:
3363 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
3364 case SD_BUS_TYPE_SIGNATURE:
3365 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
3366 void *p;
3367
3368 p = va_arg(ap, void*);
3369 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
3370 if (r < 0)
3371 return r;
430fb8fa
LP
3372 if (r == 0) {
3373 if (n_loop <= 1)
3374 return 0;
3375
fe1d424d 3376 return -ENXIO;
430fb8fa 3377 }
fe1d424d 3378
9a17484d
LP
3379 break;
3380 }
3381
3382 case SD_BUS_TYPE_ARRAY: {
3383 size_t k;
3384
3385 r = signature_element_length(t + 1, &k);
3386 if (r < 0)
3387 return r;
3388
3389 {
9a17484d 3390 char s[k + 1];
9a17484d
LP
3391 memcpy(s, t + 1, k);
3392 s[k] = 0;
9a17484d
LP
3393
3394 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
3395 if (r < 0)
3396 return r;
430fb8fa
LP
3397 if (r == 0) {
3398 if (n_loop <= 1)
3399 return 0;
3400
9a17484d 3401 return -ENXIO;
430fb8fa 3402 }
fe1d424d 3403 }
9a17484d 3404
fe1d424d
LP
3405 if (n_array == (unsigned) -1) {
3406 types += k;
3407 n_struct -= k;
9a17484d
LP
3408 }
3409
fe1d424d
LP
3410 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
3411 if (r < 0)
3412 return r;
3413
3414 types = t + 1;
3415 n_struct = k;
3416 n_array = va_arg(ap, unsigned);
3417
9a17484d
LP
3418 break;
3419 }
3420
3421 case SD_BUS_TYPE_VARIANT: {
3422 const char *s;
3423
3424 s = va_arg(ap, const char *);
3425 if (!s)
3426 return -EINVAL;
3427
3428 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
3429 if (r < 0)
3430 return r;
430fb8fa
LP
3431 if (r == 0) {
3432 if (n_loop <= 1)
3433 return 0;
3434
9a17484d 3435 return -ENXIO;
430fb8fa 3436 }
9a17484d 3437
fe1d424d 3438 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
3439 if (r < 0)
3440 return r;
9a17484d 3441
fe1d424d
LP
3442 types = s;
3443 n_struct = strlen(s);
3444 n_array = (unsigned) -1;
3445
9a17484d
LP
3446 break;
3447 }
3448
3449 case SD_BUS_TYPE_STRUCT_BEGIN:
3450 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
3451 size_t k;
3452
3453 r = signature_element_length(t, &k);
3454 if (r < 0)
3455 return r;
3456
3457 {
3458 char s[k - 1];
3459 memcpy(s, t + 1, k - 2);
3460 s[k - 2] = 0;
3461
3462 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
3463 if (r < 0)
3464 return r;
430fb8fa
LP
3465 if (r == 0) {
3466 if (n_loop <= 1)
3467 return 0;
9a17484d 3468 return -ENXIO;
430fb8fa 3469 }
fe1d424d 3470 }
9a17484d 3471
fe1d424d
LP
3472 if (n_array == (unsigned) -1) {
3473 types += k - 1;
3474 n_struct -= k - 1;
3475 }
9a17484d 3476
fe1d424d
LP
3477 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
3478 if (r < 0)
3479 return r;
9a17484d 3480
fe1d424d
LP
3481 types = t + 1;
3482 n_struct = k - 2;
3483 n_array = (unsigned) -1;
9a17484d
LP
3484
3485 break;
3486 }
3487
3488 default:
fe1d424d 3489 return -EINVAL;
9a17484d 3490 }
9a17484d
LP
3491 }
3492
3493 return 1;
3494}
3495
d9f644e2 3496_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
3497 va_list ap;
3498 int r;
3499
9b07511d
LP
3500 assert_return(m, -EINVAL);
3501 assert_return(m->sealed, -EPERM);
3502 assert_return(types, -EINVAL);
9a17484d
LP
3503
3504 va_start(ap, types);
3505 r = message_read_ap(m, types, ap);
3506 va_end(ap);
3507
3508 return r;
3509}
3510
d9f644e2 3511_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
3512 int r;
3513
3514 assert_return(m, -EINVAL);
3515 assert_return(m->sealed, -EPERM);
3516 assert_return(types, -EINVAL);
3517
3518 if (isempty(types))
3519 return 0;
3520
3521 switch (*types) {
3522
3523 case SD_BUS_TYPE_BYTE:
3524 case SD_BUS_TYPE_BOOLEAN:
3525 case SD_BUS_TYPE_INT16:
3526 case SD_BUS_TYPE_UINT16:
3527 case SD_BUS_TYPE_INT32:
3528 case SD_BUS_TYPE_UINT32:
3529 case SD_BUS_TYPE_INT64:
3530 case SD_BUS_TYPE_UINT64:
3531 case SD_BUS_TYPE_DOUBLE:
3532 case SD_BUS_TYPE_STRING:
3533 case SD_BUS_TYPE_OBJECT_PATH:
3534 case SD_BUS_TYPE_SIGNATURE:
3535 case SD_BUS_TYPE_UNIX_FD:
3536
3537 r = sd_bus_message_read_basic(m, *types, NULL);
3538 if (r <= 0)
3539 return r;
3540
3541 r = sd_bus_message_skip(m, types + 1);
3542 if (r < 0)
3543 return r;
3544
3545 return 1;
3546
3547 case SD_BUS_TYPE_ARRAY: {
3548 size_t k;
3549
3550 r = signature_element_length(types + 1, &k);
3551 if (r < 0)
3552 return r;
3553
3554 {
3555 char s[k+1];
3556 memcpy(s, types+1, k);
3557 s[k] = 0;
3558
3559 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
3560 if (r <= 0)
3561 return r;
3562
3563 for (;;) {
3564 r = sd_bus_message_skip(m, s);
3565 if (r < 0)
3566 return r;
3567 if (r == 0)
3568 break;
3569 }
3570
3571 r = sd_bus_message_exit_container(m);
3572 if (r < 0)
3573 return r;
3574 }
3575
3576 r = sd_bus_message_skip(m, types + 1 + k);
3577 if (r < 0)
3578 return r;
3579
3580 return 1;
3581 }
3582
3583 case SD_BUS_TYPE_VARIANT: {
3584 const char *contents;
3585 char x;
3586
3587 r = sd_bus_message_peek_type(m, &x, &contents);
3588 if (r <= 0)
3589 return r;
3590
3591 if (x != SD_BUS_TYPE_VARIANT)
3592 return -ENXIO;
3593
3594 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
3595 if (r <= 0)
3596 return r;
3597
3598 r = sd_bus_message_skip(m, contents);
3599 if (r < 0)
3600 return r;
3601 assert(r != 0);
3602
3603 r = sd_bus_message_exit_container(m);
3604 if (r < 0)
3605 return r;
3606
3607 r = sd_bus_message_skip(m, types + 1);
3608 if (r < 0)
3609 return r;
3610
3611 return 1;
3612 }
3613
3614 case SD_BUS_TYPE_STRUCT_BEGIN:
3615 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
3616 size_t k;
3617
3618 r = signature_element_length(types, &k);
3619 if (r < 0)
3620 return r;
3621
3622 {
3623 char s[k-1];
3624 memcpy(s, types+1, k-2);
3625 s[k-2] = 0;
3626
3627 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
3628 if (r <= 0)
3629 return r;
3630
3631 r = sd_bus_message_skip(m, s);
3632 if (r < 0)
3633 return r;
3634 assert(r != 0);
3635
3636 r = sd_bus_message_exit_container(m);
3637 if (r < 0)
3638 return r;
3639 }
3640
3641 r = sd_bus_message_skip(m, types + k);
3642 if (r < 0)
3643 return r;
3644
3645 return 1;
3646 }
3647
3648 default:
3649 return -EINVAL;
3650 }
3651}
3652
d9f644e2
ZJS
3653_public_ int sd_bus_message_read_array(sd_bus_message *m,
3654 char type,
3655 const void **ptr,
3656 size_t *size) {
b3af9646
LP
3657 struct bus_container *c;
3658 void *p;
3659 size_t sz;
3660 ssize_t align;
3661 int r;
3662
9d6c7c82
LP
3663 assert_return(m, -EINVAL);
3664 assert_return(m->sealed, -EPERM);
3665 assert_return(bus_type_is_trivial(type), -EINVAL);
3666 assert_return(ptr, -EINVAL);
3667 assert_return(size, -EINVAL);
3668 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
b3af9646
LP
3669
3670 align = bus_type_get_alignment(type);
3671 if (align < 0)
3672 return align;
3673
3674 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
66b26c5c 3675 if (r <= 0)
b3af9646
LP
3676 return r;
3677
3678 c = message_get_container(m);
3679 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
3680
5e86fd7b
LP
3681 if (sz == 0)
3682 /* Zero length array, let's return some aligned
3683 * pointer that is not NULL */
3684 p = (uint8_t*) NULL + align;
3685 else {
3686 r = message_peek_body(m, &m->rindex, align, sz, &p);
3687 if (r < 0)
3688 goto fail;
3689 if (r == 0) {
3690 r = -EBADMSG;
3691 goto fail;
3692 }
b3af9646
LP
3693 }
3694
3695 r = sd_bus_message_exit_container(m);
3696 if (r < 0)
3697 goto fail;
3698
3699 *ptr = (const void*) p;
3700 *size = sz;
3701
3702 return 1;
3703
3704fail:
3705 message_quit_container(m);
3706 return r;
3707}
3708
80a46c73
LP
3709static int message_peek_fields(
3710 sd_bus_message *m,
3711 size_t *rindex,
3712 size_t align,
3713 size_t nbytes,
3714 void **ret) {
3715
3716 assert(m);
3717 assert(rindex);
3718 assert(align > 0);
3719
c91cb83c 3720 return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
80a46c73
LP
3721}
3722
9f26c90c
LP
3723static int message_peek_field_uint32(
3724 sd_bus_message *m,
3725 size_t *ri,
3726 uint32_t *ret) {
3727
3728 int r;
3729 void *q;
3730
3731 assert(m);
3732 assert(ri);
3733
3734 r = message_peek_fields(m, ri, 4, 4, &q);
3735 if (r < 0)
3736 return r;
3737
3738 if (ret)
3739 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3740
3741 return 0;
3742}
3743
80a46c73
LP
3744static int message_peek_field_string(
3745 sd_bus_message *m,
6693860f 3746 bool (*validate)(const char *p),
80a46c73
LP
3747 size_t *ri,
3748 const char **ret) {
3749
9f26c90c 3750 uint32_t l;
80a46c73
LP
3751 int r;
3752 void *q;
3753
9a17484d 3754 assert(m);
80a46c73
LP
3755 assert(ri);
3756
9f26c90c 3757 r = message_peek_field_uint32(m, ri, &l);
80a46c73
LP
3758 if (r < 0)
3759 return r;
3760
80a46c73
LP
3761 r = message_peek_fields(m, ri, 1, l+1, &q);
3762 if (r < 0)
3763 return r;
9a17484d 3764
6693860f
LP
3765 if (validate) {
3766 if (!validate_nul(q, l))
3767 return -EBADMSG;
3768
3769 if (!validate(q))
ac89bf1d
LP
3770 return -EBADMSG;
3771 } else {
3772 if (!validate_string(q, l))
3773 return -EBADMSG;
3774 }
80a46c73
LP
3775
3776 if (ret)
3777 *ret = q;
3778
3779 return 0;
3780}
3781
3782static int message_peek_field_signature(
3783 sd_bus_message *m,
3784 size_t *ri,
3785 const char **ret) {
3786
3787 size_t l;
3788 int r;
3789 void *q;
3790
3791 assert(m);
3792 assert(ri);
3793
3794 r = message_peek_fields(m, ri, 1, 1, &q);
3795 if (r < 0)
3796 return r;
3797
3798 l = *(uint8_t*) q;
3799 r = message_peek_fields(m, ri, 1, l+1, &q);
3800 if (r < 0)
3801 return r;
3802
3803 if (!validate_signature(q, l))
3804 return -EBADMSG;
3805
3806 if (ret)
3807 *ret = q;
3808
3809 return 0;
3810}
3811
80a46c73
LP
3812static int message_skip_fields(
3813 sd_bus_message *m,
3814 size_t *ri,
3815 uint32_t array_size,
3816 const char **signature) {
3817
3818 size_t original_index;
3819 int r;
3820
3821 assert(m);
3822 assert(ri);
3823 assert(signature);
3824
3825 original_index = *ri;
3826
3827 for (;;) {
3828 char t;
80a46c73
LP
3829 size_t l;
3830
3831 if (array_size != (uint32_t) -1 &&
3832 array_size <= *ri - original_index)
3833 return 0;
3834
3835 t = **signature;
3836 if (!t)
3837 return 0;
3838
6693860f
LP
3839 if (t == SD_BUS_TYPE_STRING) {
3840
3841 r = message_peek_field_string(m, NULL, ri, NULL);
3842 if (r < 0)
3843 return r;
3844
3845 (*signature)++;
3846
3847 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 3848
6693860f 3849 r = message_peek_field_string(m, object_path_is_valid, ri, NULL);
80a46c73
LP
3850 if (r < 0)
3851 return r;
3852
3853 (*signature)++;
3854
3855 } else if (t == SD_BUS_TYPE_SIGNATURE) {
3856
3857 r = message_peek_field_signature(m, ri, NULL);
3858 if (r < 0)
3859 return r;
3860
3861 (*signature)++;
3862
3863 } else if (bus_type_is_basic(t)) {
27f6e5c7 3864 ssize_t align, k;
80a46c73 3865
c66a2e0c
TG
3866 align = bus_type_get_alignment(t);
3867 k = bus_type_get_size(t);
27f6e5c7 3868 assert(align > 0 && k > 0);
80a46c73
LP
3869
3870 r = message_peek_fields(m, ri, align, k, NULL);
3871 if (r < 0)
3872 return r;
9a17484d 3873
80a46c73
LP
3874 (*signature)++;
3875
3876 } else if (t == SD_BUS_TYPE_ARRAY) {
3877
3878 r = signature_element_length(*signature+1, &l);
3879 if (r < 0)
3880 return r;
3881
3882 assert(l >= 1);
3883 {
3884 char sig[l-1], *s;
9f26c90c 3885 uint32_t nas;
80a46c73
LP
3886 int alignment;
3887
3888 strncpy(sig, *signature + 1, l-1);
3889 s = sig;
3890
3891 alignment = bus_type_get_alignment(sig[0]);
3892 if (alignment < 0)
3893 return alignment;
3894
9f26c90c 3895 r = message_peek_field_uint32(m, ri, &nas);
80a46c73
LP
3896 if (r < 0)
3897 return r;
ac89bf1d 3898 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
3899 return -EBADMSG;
3900
3901 r = message_peek_fields(m, ri, alignment, 0, NULL);
3902 if (r < 0)
3903 return r;
3904
3905 r = message_skip_fields(m, ri, nas, (const char**) &s);
3906 if (r < 0)
3907 return r;
3908 }
3909
3910 (*signature) += 1 + l;
3911
3912 } else if (t == SD_BUS_TYPE_VARIANT) {
3913 const char *s;
3914
3915 r = message_peek_field_signature(m, ri, &s);
3916 if (r < 0)
3917 return r;
3918
3919 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
3920 if (r < 0)
3921 return r;
3922
3923 (*signature)++;
3924
3925 } else if (t == SD_BUS_TYPE_STRUCT ||
3926 t == SD_BUS_TYPE_DICT_ENTRY) {
3927
3928 r = signature_element_length(*signature, &l);
3929 if (r < 0)
3930 return r;
3931
3932 assert(l >= 2);
3933 {
3934 char sig[l-1], *s;
3935 strncpy(sig, *signature + 1, l-1);
3936 s = sig;
3937
3938 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
3939 if (r < 0)
3940 return r;
3941 }
3942
3943 *signature += l;
3944 } else
3945 return -EINVAL;
3946 }
3947}
3948
6629161f 3949int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
3950 size_t ri;
3951 int r;
2c93b4ef 3952 uint32_t unix_fds = 0;
80a46c73
LP
3953
3954 assert(m);
3955
3956 for (ri = 0; ri < BUS_MESSAGE_FIELDS_SIZE(m); ) {
3957 const char *signature;
3958 uint8_t *header;
3959
3960 r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
3961 if (r < 0)
3962 return r;
3963
3964 r = message_peek_field_signature(m, &ri, &signature);
3965 if (r < 0)
3966 return r;
3967
3968 switch (*header) {
3969 case _SD_BUS_MESSAGE_HEADER_INVALID:
3970 return -EBADMSG;
3971
3972 case SD_BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
3973
3974 if (m->path)
3975 return -EBADMSG;
3976
80a46c73
LP
3977 if (!streq(signature, "o"))
3978 return -EBADMSG;
3979
6693860f 3980 r = message_peek_field_string(m, object_path_is_valid, &ri, &m->path);
80a46c73
LP
3981 break;
3982
3983 case SD_BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
3984
3985 if (m->interface)
3986 return -EBADMSG;
3987
80a46c73
LP
3988 if (!streq(signature, "s"))
3989 return -EBADMSG;
3990
6693860f 3991 r = message_peek_field_string(m, interface_name_is_valid, &ri, &m->interface);
80a46c73
LP
3992 break;
3993
3994 case SD_BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
3995
3996 if (m->member)
3997 return -EBADMSG;
3998
80a46c73
LP
3999 if (!streq(signature, "s"))
4000 return -EBADMSG;
4001
6693860f 4002 r = message_peek_field_string(m, member_name_is_valid, &ri, &m->member);
80a46c73
LP
4003 break;
4004
4005 case SD_BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
4006
4007 if (m->error.name)
4008 return -EBADMSG;
4009
80a46c73
LP
4010 if (!streq(signature, "s"))
4011 return -EBADMSG;
4012
6693860f 4013 r = message_peek_field_string(m, error_name_is_valid, &ri, &m->error.name);
80a46c73
LP
4014 break;
4015
4016 case SD_BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
4017
4018 if (m->destination)
4019 return -EBADMSG;
4020
80a46c73
LP
4021 if (!streq(signature, "s"))
4022 return -EBADMSG;
4023
dbb642af 4024 r = message_peek_field_string(m, sender_name_is_valid, &ri, &m->destination);
80a46c73
LP
4025 break;
4026
4027 case SD_BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
4028
4029 if (m->sender)
4030 return -EBADMSG;
4031
80a46c73
LP
4032 if (!streq(signature, "s"))
4033 return -EBADMSG;
4034
dbb642af 4035 r = message_peek_field_string(m, sender_name_is_valid, &ri, &m->sender);
80a46c73
LP
4036 break;
4037
4038
4039 case SD_BUS_MESSAGE_HEADER_SIGNATURE: {
4040 const char *s;
4041 char *c;
4042
2c93b4ef
LP
4043 if (m->root_container.signature)
4044 return -EBADMSG;
4045
80a46c73
LP
4046 if (!streq(signature, "g"))
4047 return -EBADMSG;
4048
4049 r = message_peek_field_signature(m, &ri, &s);
4050 if (r < 0)
4051 return r;
4052
4053 c = strdup(s);
4054 if (!c)
4055 return -ENOMEM;
4056
4057 free(m->root_container.signature);
4058 m->root_container.signature = c;
80a46c73
LP
4059 break;
4060 }
4061
4062 case SD_BUS_MESSAGE_HEADER_REPLY_SERIAL:
2c93b4ef
LP
4063 if (m->reply_serial != 0)
4064 return -EBADMSG;
4065
80a46c73
LP
4066 if (!streq(signature, "u"))
4067 return -EBADMSG;
4068
4069 r = message_peek_field_uint32(m, &ri, &m->reply_serial);
6693860f
LP
4070 if (r < 0)
4071 return r;
4072
4073 if (m->reply_serial == 0)
4074 return -EBADMSG;
4075
80a46c73
LP
4076 break;
4077
2c93b4ef
LP
4078 case SD_BUS_MESSAGE_HEADER_UNIX_FDS:
4079 if (unix_fds != 0)
4080 return -EBADMSG;
4081
4082 if (!streq(signature, "u"))
4083 return -EBADMSG;
4084
4085 r = message_peek_field_uint32(m, &ri, &unix_fds);
4086 if (r < 0)
4087 return -EBADMSG;
4088
4089 if (unix_fds == 0)
4090 return -EBADMSG;
4091
4092 break;
4093
80a46c73
LP
4094 default:
4095 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
4096 }
4097
4098 if (r < 0)
4099 return r;
4100 }
4101
2c93b4ef
LP
4102 if (m->n_fds != unix_fds)
4103 return -EBADMSG;
4104
80a46c73
LP
4105 if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
4106 return -EBADMSG;
4107
4108 switch (m->header->type) {
4109
40ca29a1 4110 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
4111 if (!m->path || !m->interface || !m->member)
4112 return -EBADMSG;
4113 break;
4114
40ca29a1 4115 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
4116
4117 if (!m->path || !m->member)
4118 return -EBADMSG;
4119
4120 break;
4121
40ca29a1 4122 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73
LP
4123
4124 if (m->reply_serial == 0)
4125 return -EBADMSG;
4126 break;
4127
40ca29a1 4128 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73
LP
4129
4130 if (m->reply_serial == 0 || !m->error.name)
4131 return -EBADMSG;
4132 break;
4133 }
9a17484d 4134
89ffcd2a 4135 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 4136 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
89ffcd2a
LP
4137 sd_bus_message_read(m, "s", &m->error.message);
4138
9a17484d
LP
4139 return 0;
4140}
4141
9a17484d 4142int bus_message_seal(sd_bus_message *m, uint64_t serial) {
47e6ce32 4143 struct bus_body_part *part;
69aec65c 4144 size_t l, a;
47e6ce32
LP
4145 unsigned i;
4146 int r;
9a17484d
LP
4147
4148 assert(m);
4149
4150 if (m->sealed)
4151 return -EPERM;
4152
4153 if (m->n_containers > 0)
4154 return -EBADMSG;
4155
13c299d3
LP
4156 if (m->poisoned)
4157 return -ESTALE;
4158
9a17484d
LP
4159 /* If there's a non-trivial signature set, then add it in here */
4160 if (!isempty(m->root_container.signature)) {
80a46c73 4161 r = message_append_field_signature(m, SD_BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
9a17484d
LP
4162 if (r < 0)
4163 return r;
4164 }
4165
4166 if (m->n_fds > 0) {
4167 r = message_append_field_uint32(m, SD_BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
4168 if (r < 0)
4169 return r;
4170 }
4171
66b26c5c
LP
4172 /* Add padding at the end of the fields part, since we know
4173 * the body needs to start at an 8 byte alignment. We made
4174 * sure we allocated enough space for this, so all we need to
4175 * do here is to zero it out. */
69aec65c
LP
4176 l = BUS_MESSAGE_FIELDS_SIZE(m);
4177 a = ALIGN8(l) - l;
c91cb83c
LP
4178 if (a > 0)
4179 memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
69aec65c 4180
66b26c5c
LP
4181 /* If this is something we can send as memfd, then let's seal
4182 the memfd now. Note that we can send memfds as payload only
4183 for directed messages, and not for broadcasts. */
8f155917 4184 if (m->destination && m->bus && m->bus->use_memfd) {
66b26c5c 4185 MESSAGE_FOREACH_PART(part, i, m)
8f155917 4186 if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
66b26c5c 4187 bus_body_part_unmap(part);
a392d361 4188
66b26c5c
LP
4189 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
4190 part->sealed = true;
4191 }
4192 }
47e6ce32 4193
9a17484d
LP
4194 m->header->serial = serial;
4195 m->sealed = true;
4196
9a17484d
LP
4197 return 0;
4198}
4199
d9f644e2 4200_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
4201 assert_return(m, -EINVAL);
4202 assert_return(destination, -EINVAL);
4203 assert_return(!m->sealed, -EPERM);
4204 assert_return(!m->destination, -EEXIST);
9a17484d
LP
4205
4206 return message_append_field_string(m, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
4207}
4208
de1c301e
LP
4209int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
4210 size_t total;
de1c301e 4211 void *p, *e;
bc7fd8cd
LP
4212 unsigned i;
4213 struct bus_body_part *part;
de1c301e
LP
4214
4215 assert(m);
4216 assert(buffer);
4217 assert(sz);
4218
6629161f 4219 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
4220
4221 p = malloc(total);
4222 if (!p)
4223 return -ENOMEM;
4224
c91cb83c 4225 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 4226 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 4227 e = mempcpy(e, part->data, part->size);
2100fa10
LP
4228
4229 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
4230
4231 *buffer = p;
4232 *sz = total;
4233
4234 return 0;
4235}
89ffcd2a
LP
4236
4237int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
4238 int r;
4239
4240 assert(m);
4241 assert(l);
4242
4243 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 4244 if (r <= 0)
89ffcd2a
LP
4245 return r;
4246
4247 for (;;) {
4248 const char *s;
4249
4250 r = sd_bus_message_read_basic(m, 's', &s);
4251 if (r < 0)
4252 return r;
4253 if (r == 0)
4254 break;
4255
4256 r = strv_extend(l, s);
4257 if (r < 0)
4258 return r;
4259 }
4260
4261 r = sd_bus_message_exit_container(m);
4262 if (r < 0)
4263 return r;
4264
405cd3aa 4265 return 1;
89ffcd2a 4266}
392d5b37 4267
ba341e7c 4268_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
4686d1b6
MAP
4269 char **strv = NULL;
4270 int r;
4271
4272 assert_return(m, -EINVAL);
4273 assert_return(m->sealed, -EPERM);
4274 assert_return(l, -EINVAL);
4275
4276 r = bus_message_read_strv_extend(m, &strv);
4277 if (r <= 0) {
4278 strv_free(strv);
4279 return r;
4280 }
4281
4282 *l = strv;
4283 return 1;
4284}
4285
392d5b37
LP
4286const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
4287 int r;
42c5aaf3
LP
4288 const char *t = NULL;
4289 unsigned j;
392d5b37
LP
4290
4291 assert(m);
4292
4293 r = sd_bus_message_rewind(m, true);
4294 if (r < 0)
4295 return NULL;
4296
42c5aaf3
LP
4297 for (j = 0; j <= i; j++) {
4298 char type;
4299
392d5b37
LP
4300 r = sd_bus_message_peek_type(m, &type, NULL);
4301 if (r < 0)
4302 return NULL;
4303
4304 if (type != SD_BUS_TYPE_STRING &&
4305 type != SD_BUS_TYPE_OBJECT_PATH &&
4306 type != SD_BUS_TYPE_SIGNATURE)
4307 return NULL;
4308
4309 r = sd_bus_message_read_basic(m, type, &t);
4310 if (r < 0)
4311 return NULL;
392d5b37
LP
4312 }
4313
392d5b37
LP
4314 return t;
4315}
2100fa10 4316
c91cb83c
LP
4317bool bus_header_is_complete(struct bus_header *h, size_t size) {
4318 size_t full;
4319
4320 assert(h);
4321 assert(size);
4322
4323 if (size < sizeof(struct bus_header))
4324 return false;
4325
4326 full = sizeof(struct bus_header) +
4327 (h->endian == SD_BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
4328
4329 return size >= full;
4330}
4331
4332int bus_header_message_size(struct bus_header *h, size_t *sum) {
6629161f
LP
4333 size_t fs, bs;
4334
4335 assert(h);
4336 assert(sum);
4337
4338 if (h->endian == SD_BUS_NATIVE_ENDIAN) {
4339 fs = h->fields_size;
4340 bs = h->body_size;
4341 } else if (h->endian == SD_BUS_REVERSE_ENDIAN) {
4342 fs = bswap_32(h->fields_size);
4343 bs = bswap_32(h->body_size);
4344 } else
4345 return -EBADMSG;
2100fa10 4346
6629161f
LP
4347 *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
4348 return 0;
2100fa10 4349}
eb01ba5d 4350
d9f644e2 4351_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
40ca29a1 4352 assert_return(m, -EINVAL);
eb01ba5d 4353
40ca29a1 4354 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
4355 return 0;
4356
40ca29a1 4357 return sd_bus_error_get_errno(&m->error);
eb01ba5d 4358}
29ddb38f 4359
d9f644e2 4360_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
4361 struct bus_container *c;
4362
9d6c7c82 4363 assert_return(m, NULL);
29ddb38f
LP
4364
4365 c = complete ? &m->root_container : message_get_container(m);
40ca29a1 4366 return c->signature ?: "";
29ddb38f 4367}
c430fee6 4368
d9f644e2 4369_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
4370 bool done_something = false;
4371 int r;
4372
80ba3b84
LP
4373 assert_return(m, -EINVAL);
4374 assert_return(source, -EINVAL);
4375 assert_return(!m->sealed, -EPERM);
4376 assert_return(source->sealed, -EPERM);
4377
c430fee6
LP
4378 do {
4379 const char *contents;
4380 char type;
4381 union {
4382 uint8_t u8;
4383 uint16_t u16;
4384 int16_t s16;
4385 uint32_t u32;
4386 int32_t s32;
4387 uint64_t u64;
4388 int64_t s64;
4389 double d64;
4390 const char *string;
4391 int i;
4392 } basic;
4393
4394 r = sd_bus_message_peek_type(source, &type, &contents);
4395 if (r < 0)
4396 return r;
4397 if (r == 0)
4398 break;
4399
4400 done_something = true;
4401
4402 if (bus_type_is_container(type) > 0) {
4403
4404 r = sd_bus_message_enter_container(source, type, contents);
4405 if (r < 0)
4406 return r;
4407
4408 r = sd_bus_message_open_container(m, type, contents);
4409 if (r < 0)
4410 return r;
4411
4412 r = sd_bus_message_copy(m, source, true);
4413 if (r < 0)
4414 return r;
4415
4416 r = sd_bus_message_close_container(m);
4417 if (r < 0)
4418 return r;
4419
4420 r = sd_bus_message_exit_container(source);
4421 if (r < 0)
4422 return r;
4423
4424 continue;
4425 }
4426
4427 r = sd_bus_message_read_basic(source, type, &basic);
4428 if (r < 0)
4429 return r;
4430
4431 assert(r > 0);
4432
4433 if (type == SD_BUS_TYPE_OBJECT_PATH ||
4434 type == SD_BUS_TYPE_SIGNATURE ||
4435 type == SD_BUS_TYPE_STRING)
4436 r = sd_bus_message_append_basic(m, type, basic.string);
4437 else
4438 r = sd_bus_message_append_basic(m, type, &basic);
4439
4440 if (r < 0)
4441 return r;
4442
4443 } while (all);
4444
4445 return done_something;
4446}
4447
d9f644e2 4448_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
4449 const char *c;
4450 char t;
4451 int r;
4452
4453 assert_return(m, -EINVAL);
4454 assert_return(m->sealed, -EPERM);
4455 assert_return(!type || bus_type_is_valid(type), -EINVAL);
4456 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
4457 assert_return(type || contents, -EINVAL);
4458 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
4459
4460 r = sd_bus_message_peek_type(m, &t, &c);
4461 if (r <= 0)
4462 return r;
4463
4464 if (type != 0 && type != t)
4465 return 0;
4466
4467 if (contents && !streq_ptr(contents, c))
4468 return 0;
4469
4470 return 1;
4471}