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