chiark / gitweb /
Unifiy free() usage
[elogind.git] / src / libelogind / sd-bus / bus-message.c
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>
23 #include <fcntl.h>
24 #include <sys/mman.h>
25
26 #include "util.h"
27 #include "utf8.h"
28 #include "strv.h"
29 #include "time-util.h"
30 #include "memfd-util.h"
31
32 #include "sd-bus.h"
33 #include "bus-message.h"
34 #include "bus-internal.h"
35 #include "bus-type.h"
36 #include "bus-signature.h"
37 #include "bus-gvariant.h"
38 #include "bus-util.h"
39
40 static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
41
42 static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
43
44         if (p == NULL)
45                 return NULL;
46
47         if (old_base == new_base)
48                 return (void*) p;
49
50         if ((uint8_t*) p < (uint8_t*) old_base)
51                 return (void*) p;
52
53         if ((uint8_t*) p >= (uint8_t*) old_base + sz)
54                 return (void*) p;
55
56         return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
57 }
58
59 static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
60         assert(m);
61         assert(part);
62
63         if (part->memfd >= 0) {
64                 /* If we can reuse the memfd, try that. For that it
65                  * can't be sealed yet. */
66
67                 if (!part->sealed) {
68                         assert(part->memfd_offset == 0);
69                         assert(part->data == part->mmap_begin);
70                         bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
71                 } else {
72                         if (part->mapped > 0)
73                                 assert_se(munmap(part->mmap_begin, part->mapped) == 0);
74
75                         safe_close(part->memfd);
76                 }
77
78         } else if (part->munmap_this)
79                 munmap(part->mmap_begin, part->mapped);
80         else if (part->free_this)
81                 free(part->data);
82
83         if (part != &m->body)
84                 free(part);
85 }
86
87 static void message_reset_parts(sd_bus_message *m) {
88         struct bus_body_part *part;
89
90         assert(m);
91
92         part = &m->body;
93         while (m->n_body_parts > 0) {
94                 struct bus_body_part *next = part->next;
95                 message_free_part(m, part);
96                 part = next;
97                 m->n_body_parts--;
98         }
99
100         m->body_end = NULL;
101
102         m->cached_rindex_part = NULL;
103         m->cached_rindex_part_begin = 0;
104 }
105
106 static void message_reset_containers(sd_bus_message *m) {
107         unsigned i;
108
109         assert(m);
110
111         for (i = 0; i < m->n_containers; i++) {
112                 free(m->containers[i].signature);
113                 free(m->containers[i].offsets);
114         }
115
116         m->containers = mfree(m->containers);
117
118         m->n_containers = m->containers_allocated = 0;
119         m->root_container.index = 0;
120 }
121
122 static void message_free(sd_bus_message *m) {
123         assert(m);
124
125         if (m->free_header)
126                 free(m->header);
127
128         message_reset_parts(m);
129
130         if (m->release_kdbus)
131                 bus_kernel_cmd_free(m->bus, (uint8_t *) m->kdbus - (uint8_t *) m->bus->kdbus_buffer);
132
133         if (m->free_kdbus)
134                 free(m->kdbus);
135
136         sd_bus_unref(m->bus);
137
138         if (m->free_fds) {
139                 close_many(m->fds, m->n_fds);
140                 free(m->fds);
141         }
142
143         if (m->iovec != m->iovec_fixed)
144                 free(m->iovec);
145
146         m->destination_ptr = mfree(m->destination_ptr);
147         message_reset_containers(m);
148         free(m->root_container.signature);
149         free(m->root_container.offsets);
150
151         free(m->root_container.peeked_signature);
152
153         bus_creds_done(&m->creds);
154         free(m);
155 }
156
157 static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
158         void *op, *np;
159         size_t old_size, new_size, start;
160
161         assert(m);
162
163         if (m->poisoned)
164                 return NULL;
165
166         old_size = sizeof(struct bus_header) + m->fields_size;
167         start = ALIGN_TO(old_size, align);
168         new_size = start + sz;
169
170         if (new_size < start ||
171             new_size > (size_t) ((uint32_t) -1))
172                 goto poison;
173
174         if (old_size == new_size)
175                 return (uint8_t*) m->header + old_size;
176
177         if (m->free_header) {
178                 np = realloc(m->header, ALIGN8(new_size));
179                 if (!np)
180                         goto poison;
181         } else {
182                 /* Initially, the header is allocated as part of of
183                  * the sd_bus_message itself, let's replace it by
184                  * dynamic data */
185
186                 np = malloc(ALIGN8(new_size));
187                 if (!np)
188                         goto poison;
189
190                 memcpy(np, m->header, sizeof(struct bus_header));
191         }
192
193         /* Zero out padding */
194         if (start > old_size)
195                 memzero((uint8_t*) np + old_size, start - old_size);
196
197         op = m->header;
198         m->header = np;
199         m->fields_size = new_size - sizeof(struct bus_header);
200
201         /* Adjust quick access pointers */
202         m->path = adjust_pointer(m->path, op, old_size, m->header);
203         m->interface = adjust_pointer(m->interface, op, old_size, m->header);
204         m->member = adjust_pointer(m->member, op, old_size, m->header);
205         m->destination = adjust_pointer(m->destination, op, old_size, m->header);
206         m->sender = adjust_pointer(m->sender, op, old_size, m->header);
207         m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
208
209         m->free_header = true;
210
211         if (add_offset) {
212                 if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
213                         goto poison;
214
215                 m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
216         }
217
218         return (uint8_t*) np + start;
219
220 poison:
221         m->poisoned = true;
222         return NULL;
223 }
224
225 static int message_append_field_string(
226                 sd_bus_message *m,
227                 uint64_t h,
228                 char type,
229                 const char *s,
230                 const char **ret) {
231
232         size_t l;
233         uint8_t *p;
234
235         assert(m);
236
237         /* dbus1 only allows 8bit header field ids */
238         if (h > 0xFF)
239                 return -EINVAL;
240
241         /* dbus1 doesn't allow strings over 32bit, let's enforce this
242          * globally, to not risk convertability */
243         l = strlen(s);
244         if (l > (size_t) (uint32_t) -1)
245                 return -EINVAL;
246
247         /* Signature "(yv)" where the variant contains "s" */
248
249         if (BUS_MESSAGE_IS_GVARIANT(m)) {
250
251                 /* (field id 64bit, ((string + NUL) + NUL + signature string 's') */
252                 p = message_extend_fields(m, 8, 8 + l + 1 + 1 + 1, true);
253                 if (!p)
254                         return -ENOMEM;
255
256                 *((uint64_t*) p) = h;
257                 memcpy(p+8, s, l);
258                 p[8+l] = 0;
259                 p[8+l+1] = 0;
260                 p[8+l+2] = type;
261
262                 if (ret)
263                         *ret = (char*) p + 8;
264
265         } else {
266                 /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
267                 p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
268                 if (!p)
269                         return -ENOMEM;
270
271                 p[0] = (uint8_t) h;
272                 p[1] = 1;
273                 p[2] = type;
274                 p[3] = 0;
275
276                 ((uint32_t*) p)[1] = l;
277                 memcpy(p + 8, s, l + 1);
278
279                 if (ret)
280                         *ret = (char*) p + 8;
281         }
282
283         return 0;
284 }
285
286 static int message_append_field_signature(
287                 sd_bus_message *m,
288                 uint64_t h,
289                 const char *s,
290                 const char **ret) {
291
292         size_t l;
293         uint8_t *p;
294
295         assert(m);
296
297         /* dbus1 only allows 8bit header field ids */
298         if (h > 0xFF)
299                 return -EINVAL;
300
301         /* dbus1 doesn't allow signatures over 8bit, let's enforce
302          * this globally, to not risk convertability */
303         l = strlen(s);
304         if (l > 255)
305                 return -EINVAL;
306
307         /* Signature "(yv)" where the variant contains "g" */
308
309         if (BUS_MESSAGE_IS_GVARIANT(m))
310                 /* For gvariant the serialization is the same as for normal strings */
311                 return message_append_field_string(m, h, 'g', s, ret);
312         else {
313                 /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
314                 p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
315                 if (!p)
316                         return -ENOMEM;
317
318                 p[0] = (uint8_t) h;
319                 p[1] = 1;
320                 p[2] = SD_BUS_TYPE_SIGNATURE;
321                 p[3] = 0;
322                 p[4] = l;
323                 memcpy(p + 5, s, l + 1);
324
325                 if (ret)
326                         *ret = (const char*) p + 5;
327         }
328
329         return 0;
330 }
331
332 static int message_append_field_uint32(sd_bus_message *m, uint64_t h, uint32_t x) {
333         uint8_t *p;
334
335         assert(m);
336
337         /* dbus1 only allows 8bit header field ids */
338         if (h > 0xFF)
339                 return -EINVAL;
340
341         if (BUS_MESSAGE_IS_GVARIANT(m)) {
342                 /* (field id 64bit + ((value + NUL + signature string 'u') */
343
344                 p = message_extend_fields(m, 8, 8 + 4 + 1 + 1, true);
345                 if (!p)
346                         return -ENOMEM;
347
348                 *((uint64_t*) p) = h;
349                 *((uint32_t*) (p + 8)) = x;
350                 p[12] = 0;
351                 p[13] = 'u';
352         } else {
353                 /* (field id byte + (signature length + signature 'u' + NUL) + value) */
354                 p = message_extend_fields(m, 8, 4 + 4, false);
355                 if (!p)
356                         return -ENOMEM;
357
358                 p[0] = (uint8_t) h;
359                 p[1] = 1;
360                 p[2] = 'u';
361                 p[3] = 0;
362
363                 ((uint32_t*) p)[1] = x;
364         }
365
366         return 0;
367 }
368
369 static int message_append_field_uint64(sd_bus_message *m, uint64_t h, uint64_t x) {
370         uint8_t *p;
371
372         assert(m);
373
374         /* dbus1 only allows 8bit header field ids */
375         if (h > 0xFF)
376                 return -EINVAL;
377
378         if (BUS_MESSAGE_IS_GVARIANT(m)) {
379                 /* (field id 64bit + ((value + NUL + signature string 't') */
380
381                 p = message_extend_fields(m, 8, 8 + 8 + 1 + 1, true);
382                 if (!p)
383                         return -ENOMEM;
384
385                 *((uint64_t*) p) = h;
386                 *((uint64_t*) (p + 8)) = x;
387                 p[16] = 0;
388                 p[17] = 't';
389         } else {
390                 /* (field id byte + (signature length + signature 't' + NUL) + 4 byte padding + value) */
391                 p = message_extend_fields(m, 8, 4 + 4 + 8, false);
392                 if (!p)
393                         return -ENOMEM;
394
395                 p[0] = (uint8_t) h;
396                 p[1] = 1;
397                 p[2] = 't';
398                 p[3] = 0;
399                 p[4] = 0;
400                 p[5] = 0;
401                 p[6] = 0;
402                 p[7] = 0;
403
404                 ((uint64_t*) p)[1] = x;
405         }
406
407         return 0;
408 }
409
410 static int message_append_reply_cookie(sd_bus_message *m, uint64_t cookie) {
411         assert(m);
412
413         if (BUS_MESSAGE_IS_GVARIANT(m))
414                 return message_append_field_uint64(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, cookie);
415         else {
416                 /* 64bit cookies are not supported on dbus1 */
417                 if (cookie > 0xffffffffUL)
418                         return -EOPNOTSUPP;
419
420                 return message_append_field_uint32(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) cookie);
421         }
422 }
423
424 int bus_message_from_header(
425                 sd_bus *bus,
426                 void *header,
427                 size_t header_accessible,
428                 void *footer,
429                 size_t footer_accessible,
430                 size_t message_size,
431                 int *fds,
432                 unsigned n_fds,
433                 const char *label,
434                 size_t extra,
435                 sd_bus_message **ret) {
436
437         _cleanup_free_ sd_bus_message *m = NULL;
438         struct bus_header *h;
439         size_t a, label_sz;
440
441         assert(bus);
442         assert(header || header_accessible <= 0);
443         assert(footer || footer_accessible <= 0);
444         assert(fds || n_fds <= 0);
445         assert(ret);
446
447         if (header_accessible < sizeof(struct bus_header))
448                 return -EBADMSG;
449
450         if (header_accessible > message_size)
451                 return -EBADMSG;
452         if (footer_accessible > message_size)
453                 return -EBADMSG;
454
455         h = header;
456         if (!IN_SET(h->version, 1, 2))
457                 return -EBADMSG;
458
459         if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
460                 return -EBADMSG;
461
462         if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
463                 return -EBADMSG;
464
465         /* Note that we are happy with unknown flags in the flags header! */
466
467         a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
468
469         if (label) {
470                 label_sz = strlen(label);
471                 a += label_sz + 1;
472         }
473
474         m = malloc0(a);
475         if (!m)
476                 return -ENOMEM;
477
478         m->n_ref = 1;
479         m->sealed = true;
480         m->header = header;
481         m->header_accessible = header_accessible;
482         m->footer = footer;
483         m->footer_accessible = footer_accessible;
484
485         if (BUS_MESSAGE_IS_GVARIANT(m)) {
486                 size_t ws;
487
488                 if (h->dbus2.cookie == 0)
489                         return -EBADMSG;
490
491                 /* dbus2 derives the sizes from the message size and
492                 the offset table at the end, since it is formatted as
493                 gvariant "yyyyuta{tv}v". Since the message itself is a
494                 structure with precisely to variable sized entries,
495                 there's only one offset in the table, which marks the
496                 end of the fields array. */
497
498                 ws = bus_gvariant_determine_word_size(message_size, 0);
499                 if (footer_accessible < ws)
500                         return -EBADMSG;
501
502                 m->fields_size = bus_gvariant_read_word_le((uint8_t*) footer + footer_accessible - ws, ws);
503                 if (ALIGN8(m->fields_size) > message_size - ws)
504                         return -EBADMSG;
505                 if (m->fields_size < sizeof(struct bus_header))
506                         return -EBADMSG;
507
508                 m->fields_size -= sizeof(struct bus_header);
509                 m->body_size = message_size - (sizeof(struct bus_header) + ALIGN8(m->fields_size));
510         } else {
511                 if (h->dbus1.serial == 0)
512                         return -EBADMSG;
513
514                 /* dbus1 has the sizes in the header */
515                 m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
516                 m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
517
518                 if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size)
519                         return -EBADMSG;
520         }
521
522         m->fds = fds;
523         m->n_fds = n_fds;
524
525         if (label) {
526                 m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
527                 memcpy(m->creds.label, label, label_sz + 1);
528
529                 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
530         }
531
532         m->bus = sd_bus_ref(bus);
533         *ret = m;
534         m = NULL;
535
536         return 0;
537 }
538
539 int bus_message_from_malloc(
540                 sd_bus *bus,
541                 void *buffer,
542                 size_t length,
543                 int *fds,
544                 unsigned n_fds,
545                 const char *label,
546                 sd_bus_message **ret) {
547
548         sd_bus_message *m;
549         size_t sz;
550         int r;
551
552         r = bus_message_from_header(
553                         bus,
554                         buffer, length, /* in this case the initial bytes and the final bytes are the same */
555                         buffer, length,
556                         length,
557                         fds, n_fds,
558                         label,
559                         0, &m);
560         if (r < 0)
561                 return r;
562
563         sz = length - sizeof(struct bus_header) - ALIGN8(m->fields_size);
564         if (sz > 0) {
565                 m->n_body_parts = 1;
566                 m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(m->fields_size);
567                 m->body.size = sz;
568                 m->body.sealed = true;
569                 m->body.memfd = -1;
570         }
571
572         m->n_iovec = 1;
573         m->iovec = m->iovec_fixed;
574         m->iovec[0].iov_base = buffer;
575         m->iovec[0].iov_len = length;
576
577         r = bus_message_parse_fields(m);
578         if (r < 0)
579                 goto fail;
580
581         /* We take possession of the memory and fds now */
582         m->free_header = true;
583         m->free_fds = true;
584
585         *ret = m;
586         return 0;
587
588 fail:
589         message_free(m);
590         return r;
591 }
592
593 static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
594         sd_bus_message *m;
595
596         assert(bus);
597
598         m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
599         if (!m)
600                 return NULL;
601
602         m->n_ref = 1;
603         m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
604         m->header->endian = BUS_NATIVE_ENDIAN;
605         m->header->type = type;
606         m->header->version = bus->message_version;
607         m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
608         m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
609         m->bus = sd_bus_ref(bus);
610
611         if (bus->allow_interactive_authorization)
612                 m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
613
614         return m;
615 }
616
617 _public_ int sd_bus_message_new_signal(
618                 sd_bus *bus,
619                 sd_bus_message **m,
620                 const char *path,
621                 const char *interface,
622                 const char *member) {
623
624         sd_bus_message *t;
625         int r;
626
627         assert_return(bus, -ENOTCONN);
628         assert_return(bus->state != BUS_UNSET, -ENOTCONN);
629         assert_return(object_path_is_valid(path), -EINVAL);
630         assert_return(interface_name_is_valid(interface), -EINVAL);
631         assert_return(member_name_is_valid(member), -EINVAL);
632         assert_return(m, -EINVAL);
633
634         t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
635         if (!t)
636                 return -ENOMEM;
637
638         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
639
640         r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
641         if (r < 0)
642                 goto fail;
643         r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
644         if (r < 0)
645                 goto fail;
646         r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
647         if (r < 0)
648                 goto fail;
649
650         *m = t;
651         return 0;
652
653 fail:
654         sd_bus_message_unref(t);
655         return r;
656 }
657
658 _public_ int sd_bus_message_new_method_call(
659                 sd_bus *bus,
660                 sd_bus_message **m,
661                 const char *destination,
662                 const char *path,
663                 const char *interface,
664                 const char *member) {
665
666         sd_bus_message *t;
667         int r;
668
669         assert_return(bus, -ENOTCONN);
670         assert_return(bus->state != BUS_UNSET, -ENOTCONN);
671         assert_return(!destination || service_name_is_valid(destination), -EINVAL);
672         assert_return(object_path_is_valid(path), -EINVAL);
673         assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
674         assert_return(member_name_is_valid(member), -EINVAL);
675         assert_return(m, -EINVAL);
676
677         t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
678         if (!t)
679                 return -ENOMEM;
680
681         r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
682         if (r < 0)
683                 goto fail;
684         r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
685         if (r < 0)
686                 goto fail;
687
688         if (interface) {
689                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
690                 if (r < 0)
691                         goto fail;
692         }
693
694         if (destination) {
695                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
696                 if (r < 0)
697                         goto fail;
698         }
699
700         *m = t;
701         return 0;
702
703 fail:
704         message_free(t);
705         return r;
706 }
707
708 static int message_new_reply(
709                 sd_bus_message *call,
710                 uint8_t type,
711                 sd_bus_message **m) {
712
713         sd_bus_message *t;
714         int r;
715
716         assert_return(call, -EINVAL);
717         assert_return(call->sealed, -EPERM);
718         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
719         assert_return(call->bus->state != BUS_UNSET, -ENOTCONN);
720         assert_return(m, -EINVAL);
721
722         t = message_new(call->bus, type);
723         if (!t)
724                 return -ENOMEM;
725
726         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
727         t->reply_cookie = BUS_MESSAGE_COOKIE(call);
728         if (t->reply_cookie == 0)
729                 return -EOPNOTSUPP;
730
731         r = message_append_reply_cookie(t, t->reply_cookie);
732         if (r < 0)
733                 goto fail;
734
735         if (call->sender) {
736                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
737                 if (r < 0)
738                         goto fail;
739         }
740
741         t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
742         t->enforced_reply_signature = call->enforced_reply_signature;
743
744         *m = t;
745         return 0;
746
747 fail:
748         message_free(t);
749         return r;
750 }
751
752 _public_ int sd_bus_message_new_method_return(
753                 sd_bus_message *call,
754                 sd_bus_message **m) {
755
756         return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
757 }
758
759 _public_ int sd_bus_message_new_method_error(
760                 sd_bus_message *call,
761                 sd_bus_message **m,
762                 const sd_bus_error *e) {
763
764         sd_bus_message *t;
765         int r;
766
767         assert_return(sd_bus_error_is_set(e), -EINVAL);
768         assert_return(m, -EINVAL);
769
770         r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
771         if (r < 0)
772                 return r;
773
774         r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
775         if (r < 0)
776                 goto fail;
777
778         if (e->message) {
779                 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
780                 if (r < 0)
781                         goto fail;
782         }
783
784         t->error._need_free = -1;
785
786         *m = t;
787         return 0;
788
789 fail:
790         message_free(t);
791         return r;
792 }
793
794 _public_ int sd_bus_message_new_method_errorf(
795                 sd_bus_message *call,
796                 sd_bus_message **m,
797                 const char *name,
798                 const char *format,
799                 ...) {
800
801         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
802         va_list ap;
803
804         assert_return(name, -EINVAL);
805         assert_return(m, -EINVAL);
806
807         va_start(ap, format);
808         bus_error_setfv(&error, name, format, ap);
809         va_end(ap);
810
811         return sd_bus_message_new_method_error(call, m, &error);
812 }
813
814 _public_ int sd_bus_message_new_method_errno(
815                 sd_bus_message *call,
816                 sd_bus_message **m,
817                 int error,
818                 const sd_bus_error *p) {
819
820         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
821
822         if (sd_bus_error_is_set(p))
823                 return sd_bus_message_new_method_error(call, m, p);
824
825         sd_bus_error_set_errno(&berror, error);
826
827         return sd_bus_message_new_method_error(call, m, &berror);
828 }
829
830 /// UNNEEDED by elogind
831 #if 0
832 _public_ int sd_bus_message_new_method_errnof(
833                 sd_bus_message *call,
834                 sd_bus_message **m,
835                 int error,
836                 const char *format,
837                 ...) {
838
839         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
840         va_list ap;
841
842         va_start(ap, format);
843         sd_bus_error_set_errnofv(&berror, error, format, ap);
844         va_end(ap);
845
846         return sd_bus_message_new_method_error(call, m, &berror);
847 }
848 #endif // 0
849
850 void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m) {
851         assert(bus);
852         assert(m);
853
854         m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus.Local";
855         m->creds.well_known_names_local = true;
856         m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
857 }
858
859 void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m) {
860         assert(bus);
861         assert(m);
862
863         m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
864         m->creds.well_known_names_driver = true;
865         m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
866 }
867
868 int bus_message_new_synthetic_error(
869                 sd_bus *bus,
870                 uint64_t cookie,
871                 const sd_bus_error *e,
872                 sd_bus_message **m) {
873
874         sd_bus_message *t;
875         int r;
876
877         assert(bus);
878         assert(sd_bus_error_is_set(e));
879         assert(m);
880
881         t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
882         if (!t)
883                 return -ENOMEM;
884
885         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
886         t->reply_cookie = cookie;
887
888         r = message_append_reply_cookie(t, t->reply_cookie);
889         if (r < 0)
890                 goto fail;
891
892         if (bus && bus->unique_name) {
893                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
894                 if (r < 0)
895                         goto fail;
896         }
897
898         r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
899         if (r < 0)
900                 goto fail;
901
902         if (e->message) {
903                 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
904                 if (r < 0)
905                         goto fail;
906         }
907
908         t->error._need_free = -1;
909
910         bus_message_set_sender_driver(bus, t);
911
912         *m = t;
913         return 0;
914
915 fail:
916         message_free(t);
917         return r;
918 }
919
920 _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
921         assert_return(m, NULL);
922
923         assert(m->n_ref > 0);
924         m->n_ref++;
925
926         return m;
927 }
928
929 _public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
930
931         if (!m)
932                 return NULL;
933
934         assert(m->n_ref > 0);
935         m->n_ref--;
936
937         if (m->n_ref > 0)
938                 return NULL;
939
940         message_free(m);
941         return NULL;
942 }
943
944 /// UNNEEDED by elogind
945 #if 0
946 _public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
947         assert_return(m, -EINVAL);
948         assert_return(type, -EINVAL);
949
950         *type = m->header->type;
951         return 0;
952 }
953
954 _public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
955         uint64_t c;
956
957         assert_return(m, -EINVAL);
958         assert_return(cookie, -EINVAL);
959
960         c = BUS_MESSAGE_COOKIE(m);
961         if (c == 0)
962                 return -ENODATA;
963
964         *cookie = BUS_MESSAGE_COOKIE(m);
965         return 0;
966 }
967
968 _public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
969         assert_return(m, -EINVAL);
970         assert_return(cookie, -EINVAL);
971
972         if (m->reply_cookie == 0)
973                 return -ENODATA;
974
975         *cookie = m->reply_cookie;
976         return 0;
977 }
978
979 _public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) {
980         assert_return(m, -EINVAL);
981
982         return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
983                 !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
984 }
985
986 _public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
987         assert_return(m, -EINVAL);
988
989         return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
990 }
991 #endif // 0
992
993 _public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
994         assert_return(m, -EINVAL);
995
996         return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
997                 (m->header->flags & BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION);
998 }
999
1000 _public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
1001         assert_return(m, NULL);
1002
1003         return m->path;
1004 }
1005
1006 _public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
1007         assert_return(m, NULL);
1008
1009         return m->interface;
1010 }
1011
1012 _public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
1013         assert_return(m, NULL);
1014
1015         return m->member;
1016 }
1017
1018 _public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
1019         assert_return(m, NULL);
1020
1021         return m->destination;
1022 }
1023
1024 _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
1025         assert_return(m, NULL);
1026
1027         return m->sender;
1028 }
1029
1030 _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
1031         assert_return(m, NULL);
1032
1033         if (!sd_bus_error_is_set(&m->error))
1034                 return NULL;
1035
1036         return &m->error;
1037 }
1038
1039 /// UNNEEDED by elogind
1040 #if 0
1041 _public_ int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec) {
1042         assert_return(m, -EINVAL);
1043         assert_return(usec, -EINVAL);
1044
1045         if (m->monotonic <= 0)
1046                 return -ENODATA;
1047
1048         *usec = m->monotonic;
1049         return 0;
1050 }
1051
1052 _public_ int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec) {
1053         assert_return(m, -EINVAL);
1054         assert_return(usec, -EINVAL);
1055
1056         if (m->realtime <= 0)
1057                 return -ENODATA;
1058
1059         *usec = m->realtime;
1060         return 0;
1061 }
1062
1063 _public_ int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t *seqnum) {
1064         assert_return(m, -EINVAL);
1065         assert_return(seqnum, -EINVAL);
1066
1067         if (m->seqnum <= 0)
1068                 return -ENODATA;
1069
1070         *seqnum = m->seqnum;
1071         return 0;
1072 }
1073 #endif // 0
1074
1075 _public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
1076         assert_return(m, NULL);
1077
1078         if (m->creds.mask == 0)
1079                 return NULL;
1080
1081         return &m->creds;
1082 }
1083
1084 /// UNNEEDED by elogind
1085 #if 0
1086 _public_ int sd_bus_message_is_signal(
1087                 sd_bus_message *m,
1088                 const char *interface,
1089                 const char *member) {
1090
1091         assert_return(m, -EINVAL);
1092
1093         if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
1094                 return 0;
1095
1096         if (interface && (!m->interface || !streq(m->interface, interface)))
1097                 return 0;
1098
1099         if (member &&  (!m->member || !streq(m->member, member)))
1100                 return 0;
1101
1102         return 1;
1103 }
1104 #endif // 0
1105
1106 _public_ int sd_bus_message_is_method_call(
1107                 sd_bus_message *m,
1108                 const char *interface,
1109                 const char *member) {
1110
1111         assert_return(m, -EINVAL);
1112
1113         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1114                 return 0;
1115
1116         if (interface && (!m->interface || !streq(m->interface, interface)))
1117                 return 0;
1118
1119         if (member &&  (!m->member || !streq(m->member, member)))
1120                 return 0;
1121
1122         return 1;
1123 }
1124
1125 _public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
1126         assert_return(m, -EINVAL);
1127
1128         if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
1129                 return 0;
1130
1131         if (name && (!m->error.name || !streq(m->error.name, name)))
1132                 return 0;
1133
1134         return 1;
1135 }
1136
1137 /// UNNEEDED by elogind
1138 #if 0
1139 _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) {
1140         assert_return(m, -EINVAL);
1141         assert_return(!m->sealed, -EPERM);
1142         assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
1143
1144         if (b)
1145                 m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
1146         else
1147                 m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
1148
1149         return 0;
1150 }
1151 #endif // 0
1152
1153 _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
1154         assert_return(m, -EINVAL);
1155         assert_return(!m->sealed, -EPERM);
1156
1157         if (b)
1158                 m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
1159         else
1160                 m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
1161
1162         return 0;
1163 }
1164
1165 /// UNNEEDED by elogind
1166 #if 0
1167 _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *m, int b) {
1168         assert_return(m, -EINVAL);
1169         assert_return(!m->sealed, -EPERM);
1170
1171         if (b)
1172                 m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
1173         else
1174                 m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
1175
1176         return 0;
1177 }
1178 #endif // 0
1179
1180 static struct bus_container *message_get_container(sd_bus_message *m) {
1181         assert(m);
1182
1183         if (m->n_containers == 0)
1184                 return &m->root_container;
1185
1186         assert(m->containers);
1187         return m->containers + m->n_containers - 1;
1188 }
1189
1190 struct bus_body_part *message_append_part(sd_bus_message *m) {
1191         struct bus_body_part *part;
1192
1193         assert(m);
1194
1195         if (m->poisoned)
1196                 return NULL;
1197
1198         if (m->n_body_parts <= 0) {
1199                 part = &m->body;
1200                 zero(*part);
1201         } else {
1202                 assert(m->body_end);
1203
1204                 part = new0(struct bus_body_part, 1);
1205                 if (!part) {
1206                         m->poisoned = true;
1207                         return NULL;
1208                 }
1209
1210                 m->body_end->next = part;
1211         }
1212
1213         part->memfd = -1;
1214         m->body_end = part;
1215         m->n_body_parts ++;
1216
1217         return part;
1218 }
1219
1220 static void part_zero(struct bus_body_part *part, size_t sz) {
1221         assert(part);
1222         assert(sz > 0);
1223         assert(sz < 8);
1224
1225         /* All other fields can be left in their defaults */
1226         assert(!part->data);
1227         assert(part->memfd < 0);
1228
1229         part->size = sz;
1230         part->is_zero = true;
1231         part->sealed = true;
1232 }
1233
1234 static int part_make_space(
1235                 struct sd_bus_message *m,
1236                 struct bus_body_part *part,
1237                 size_t sz,
1238                 void **q) {
1239
1240         void *n;
1241         int r;
1242
1243         assert(m);
1244         assert(part);
1245         assert(!part->sealed);
1246
1247         if (m->poisoned)
1248                 return -ENOMEM;
1249
1250         if (!part->data && part->memfd < 0) {
1251                 part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
1252                 part->mmap_begin = part->data;
1253         }
1254
1255         if (part->memfd >= 0) {
1256
1257                 if (part->allocated == 0 || sz > part->allocated) {
1258                         uint64_t new_allocated;
1259
1260                         new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
1261                         r = memfd_set_size(part->memfd, new_allocated);
1262                         if (r < 0) {
1263                                 m->poisoned = true;
1264                                 return r;
1265                         }
1266
1267                         part->allocated = new_allocated;
1268                 }
1269
1270                 if (!part->data || sz > part->mapped) {
1271                         size_t psz;
1272
1273                         psz = PAGE_ALIGN(sz > 0 ? sz : 1);
1274                         if (part->mapped <= 0)
1275                                 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
1276                         else
1277                                 n = mremap(part->mmap_begin, part->mapped, psz, MREMAP_MAYMOVE);
1278
1279                         if (n == MAP_FAILED) {
1280                                 m->poisoned = true;
1281                                 return -errno;
1282                         }
1283
1284                         part->mmap_begin = part->data = n;
1285                         part->mapped = psz;
1286                         part->memfd_offset = 0;
1287                 }
1288
1289                 part->munmap_this = true;
1290         } else {
1291                 if (part->allocated == 0 || sz > part->allocated) {
1292                         size_t new_allocated;
1293
1294                         new_allocated = sz > 0 ? 2 * sz : 64;
1295                         n = realloc(part->data, new_allocated);
1296                         if (!n) {
1297                                 m->poisoned = true;
1298                                 return -ENOMEM;
1299                         }
1300
1301                         part->data = n;
1302                         part->allocated = new_allocated;
1303                         part->free_this = true;
1304                 }
1305         }
1306
1307         if (q)
1308                 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1309
1310         part->size = sz;
1311         return 0;
1312 }
1313
1314 static int message_add_offset(sd_bus_message *m, size_t offset) {
1315         struct bus_container *c;
1316
1317         assert(m);
1318         assert(BUS_MESSAGE_IS_GVARIANT(m));
1319
1320         /* Add offset to current container, unless this is the first
1321          * item in it, which will have the 0 offset, which we can
1322          * ignore. */
1323         c = message_get_container(m);
1324
1325         if (!c->need_offsets)
1326                 return 0;
1327
1328         if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
1329                 return -ENOMEM;
1330
1331         c->offsets[c->n_offsets++] = offset;
1332         return 0;
1333 }
1334
1335 static void message_extend_containers(sd_bus_message *m, size_t expand) {
1336         struct bus_container *c;
1337
1338         assert(m);
1339
1340         if (expand <= 0)
1341                 return;
1342
1343         /* Update counters */
1344         for (c = m->containers; c < m->containers + m->n_containers; c++) {
1345
1346                 if (c->array_size)
1347                         *c->array_size += expand;
1348         }
1349 }
1350
1351 static void *message_extend_body(
1352                 sd_bus_message *m,
1353                 size_t align,
1354                 size_t sz,
1355                 bool add_offset,
1356                 bool force_inline) {
1357
1358         size_t start_body, end_body, padding, added;
1359         void *p;
1360         int r;
1361
1362         assert(m);
1363         assert(align > 0);
1364         assert(!m->sealed);
1365
1366         if (m->poisoned)
1367                 return NULL;
1368
1369         start_body = ALIGN_TO((size_t) m->body_size, align);
1370         end_body = start_body + sz;
1371
1372         padding = start_body - m->body_size;
1373         added = padding + sz;
1374
1375         /* Check for 32bit overflows */
1376         if (end_body > (size_t) ((uint32_t) -1) ||
1377             end_body < start_body) {
1378                 m->poisoned = true;
1379                 return NULL;
1380         }
1381
1382         if (added > 0) {
1383                 struct bus_body_part *part = NULL;
1384                 bool add_new_part;
1385
1386                 add_new_part =
1387                         m->n_body_parts <= 0 ||
1388                         m->body_end->sealed ||
1389                         (padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size) ||
1390                         (force_inline && m->body_end->size > MEMFD_MIN_SIZE); /* if this must be an inlined extension, let's create a new part if the previous part is large enough to be inlined */
1391
1392                 if (add_new_part) {
1393                         if (padding > 0) {
1394                                 part = message_append_part(m);
1395                                 if (!part)
1396                                         return NULL;
1397
1398                                 part_zero(part, padding);
1399                         }
1400
1401                         part = message_append_part(m);
1402                         if (!part)
1403                                 return NULL;
1404
1405                         r = part_make_space(m, part, sz, &p);
1406                         if (r < 0)
1407                                 return NULL;
1408                 } else {
1409                         struct bus_container *c;
1410                         void *op;
1411                         size_t os, start_part, end_part;
1412
1413                         part = m->body_end;
1414                         op = part->data;
1415                         os = part->size;
1416
1417                         start_part = ALIGN_TO(part->size, align);
1418                         end_part = start_part + sz;
1419
1420                         r = part_make_space(m, part, end_part, &p);
1421                         if (r < 0)
1422                                 return NULL;
1423
1424                         if (padding > 0) {
1425                                 memzero(p, padding);
1426                                 p = (uint8_t*) p + padding;
1427                         }
1428
1429                         /* Readjust pointers */
1430                         for (c = m->containers; c < m->containers + m->n_containers; c++)
1431                                 c->array_size = adjust_pointer(c->array_size, op, os, part->data);
1432
1433                         m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
1434                 }
1435         } else
1436                 /* Return something that is not NULL and is aligned */
1437                 p = (uint8_t *) NULL + align;
1438
1439         m->body_size = end_body;
1440         message_extend_containers(m, added);
1441
1442         if (add_offset) {
1443                 r = message_add_offset(m, end_body);
1444                 if (r < 0) {
1445                         m->poisoned = true;
1446                         return NULL;
1447                 }
1448         }
1449
1450         return p;
1451 }
1452
1453 static int message_push_fd(sd_bus_message *m, int fd) {
1454         int *f, copy;
1455
1456         assert(m);
1457
1458         if (fd < 0)
1459                 return -EINVAL;
1460
1461         if (!m->allow_fds)
1462                 return -EOPNOTSUPP;
1463
1464         copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
1465         if (copy < 0)
1466                 return -errno;
1467
1468         f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
1469         if (!f) {
1470                 m->poisoned = true;
1471                 safe_close(copy);
1472                 return -ENOMEM;
1473         }
1474
1475         m->fds = f;
1476         m->fds[m->n_fds] = copy;
1477         m->free_fds = true;
1478
1479         return copy;
1480 }
1481
1482 int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
1483         _cleanup_close_ int fd = -1;
1484         struct bus_container *c;
1485         ssize_t align, sz;
1486         void *a;
1487
1488         assert_return(m, -EINVAL);
1489         assert_return(!m->sealed, -EPERM);
1490         assert_return(bus_type_is_basic(type), -EINVAL);
1491         assert_return(!m->poisoned, -ESTALE);
1492
1493         c = message_get_container(m);
1494
1495         if (c->signature && c->signature[c->index]) {
1496                 /* Container signature is already set */
1497
1498                 if (c->signature[c->index] != type)
1499                         return -ENXIO;
1500         } else {
1501                 char *e;
1502
1503                 /* Maybe we can append to the signature? But only if this is the top-level container */
1504                 if (c->enclosing != 0)
1505                         return -ENXIO;
1506
1507                 e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
1508                 if (!e) {
1509                         m->poisoned = true;
1510                         return -ENOMEM;
1511                 }
1512         }
1513
1514         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1515                 uint8_t u8;
1516                 uint32_t u32;
1517
1518                 switch (type) {
1519
1520                 case SD_BUS_TYPE_SIGNATURE:
1521                 case SD_BUS_TYPE_STRING:
1522                         p = strempty(p);
1523
1524                         /* Fall through... */
1525                 case SD_BUS_TYPE_OBJECT_PATH:
1526                         if (!p)
1527                                 return -EINVAL;
1528
1529                         align = 1;
1530                         sz = strlen(p) + 1;
1531                         break;
1532
1533                 case SD_BUS_TYPE_BOOLEAN:
1534
1535                         u8 = p && *(int*) p;
1536                         p = &u8;
1537
1538                         align = sz = 1;
1539                         break;
1540
1541                 case SD_BUS_TYPE_UNIX_FD:
1542
1543                         if (!p)
1544                                 return -EINVAL;
1545
1546                         fd = message_push_fd(m, *(int*) p);
1547                         if (fd < 0)
1548                                 return fd;
1549
1550                         u32 = m->n_fds;
1551                         p = &u32;
1552
1553                         align = sz = 4;
1554                         break;
1555
1556                 default:
1557                         align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
1558                         sz = bus_gvariant_get_size(CHAR_TO_STR(type));
1559                         break;
1560                 }
1561
1562                 assert(align > 0);
1563                 assert(sz > 0);
1564
1565                 a = message_extend_body(m, align, sz, true, false);
1566                 if (!a)
1567                         return -ENOMEM;
1568
1569                 memcpy(a, p, sz);
1570
1571                 if (stored)
1572                         *stored = (const uint8_t*) a;
1573
1574         } else {
1575                 uint32_t u32;
1576
1577                 switch (type) {
1578
1579                 case SD_BUS_TYPE_STRING:
1580                         /* To make things easy we'll serialize a NULL string
1581                          * into the empty string */
1582                         p = strempty(p);
1583
1584                         /* Fall through... */
1585                 case SD_BUS_TYPE_OBJECT_PATH:
1586
1587                         if (!p)
1588                                 return -EINVAL;
1589
1590                         align = 4;
1591                         sz = 4 + strlen(p) + 1;
1592                         break;
1593
1594                 case SD_BUS_TYPE_SIGNATURE:
1595
1596                         p = strempty(p);
1597
1598                         align = 1;
1599                         sz = 1 + strlen(p) + 1;
1600                         break;
1601
1602                 case SD_BUS_TYPE_BOOLEAN:
1603
1604                         u32 = p && *(int*) p;
1605                         p = &u32;
1606
1607                         align = sz = 4;
1608                         break;
1609
1610                 case SD_BUS_TYPE_UNIX_FD:
1611
1612                         if (!p)
1613                                 return -EINVAL;
1614
1615                         fd = message_push_fd(m, *(int*) p);
1616                         if (fd < 0)
1617                                 return fd;
1618
1619                         u32 = m->n_fds;
1620                         p = &u32;
1621
1622                         align = sz = 4;
1623                         break;
1624
1625                 default:
1626                         align = bus_type_get_alignment(type);
1627                         sz = bus_type_get_size(type);
1628                         break;
1629                 }
1630
1631                 assert(align > 0);
1632                 assert(sz > 0);
1633
1634                 a = message_extend_body(m, align, sz, false, false);
1635                 if (!a)
1636                         return -ENOMEM;
1637
1638                 if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
1639                         *(uint32_t*) a = sz - 5;
1640                         memcpy((uint8_t*) a + 4, p, sz - 4);
1641
1642                         if (stored)
1643                                 *stored = (const uint8_t*) a + 4;
1644
1645                 } else if (type == SD_BUS_TYPE_SIGNATURE) {
1646                         *(uint8_t*) a = sz - 2;
1647                         memcpy((uint8_t*) a + 1, p, sz - 1);
1648
1649                         if (stored)
1650                                 *stored = (const uint8_t*) a + 1;
1651                 } else {
1652                         memcpy(a, p, sz);
1653
1654                         if (stored)
1655                                 *stored = a;
1656                 }
1657         }
1658
1659         if (type == SD_BUS_TYPE_UNIX_FD)
1660                 m->n_fds ++;
1661
1662         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1663                 c->index++;
1664
1665         fd = -1;
1666         return 0;
1667 }
1668
1669 _public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
1670         return message_append_basic(m, type, p, NULL);
1671 }
1672
1673 _public_ int sd_bus_message_append_string_space(
1674                 sd_bus_message *m,
1675                 size_t size,
1676                 char **s) {
1677
1678         struct bus_container *c;
1679         void *a;
1680
1681         assert_return(m, -EINVAL);
1682         assert_return(s, -EINVAL);
1683         assert_return(!m->sealed, -EPERM);
1684         assert_return(!m->poisoned, -ESTALE);
1685
1686         c = message_get_container(m);
1687
1688         if (c->signature && c->signature[c->index]) {
1689                 /* Container signature is already set */
1690
1691                 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1692                         return -ENXIO;
1693         } else {
1694                 char *e;
1695
1696                 /* Maybe we can append to the signature? But only if this is the top-level container */
1697                 if (c->enclosing != 0)
1698                         return -ENXIO;
1699
1700                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
1701                 if (!e) {
1702                         m->poisoned = true;
1703                         return -ENOMEM;
1704                 }
1705         }
1706
1707         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1708                 a = message_extend_body(m, 1, size + 1, true, false);
1709                 if (!a)
1710                         return -ENOMEM;
1711
1712                 *s = a;
1713         } else {
1714                 a = message_extend_body(m, 4, 4 + size + 1, false, false);
1715                 if (!a)
1716                         return -ENOMEM;
1717
1718                 *(uint32_t*) a = size;
1719                 *s = (char*) a + 4;
1720         }
1721
1722         (*s)[size] = 0;
1723
1724         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1725                 c->index++;
1726
1727         return 0;
1728 }
1729
1730 /// UNNEEDED by elogind
1731 #if 0
1732 _public_ int sd_bus_message_append_string_iovec(
1733                 sd_bus_message *m,
1734                 const struct iovec *iov,
1735                 unsigned n) {
1736
1737         size_t size;
1738         unsigned i;
1739         char *p;
1740         int r;
1741
1742         assert_return(m, -EINVAL);
1743         assert_return(!m->sealed, -EPERM);
1744         assert_return(iov || n == 0, -EINVAL);
1745         assert_return(!m->poisoned, -ESTALE);
1746
1747         size = IOVEC_TOTAL_SIZE(iov, n);
1748
1749         r = sd_bus_message_append_string_space(m, size, &p);
1750         if (r < 0)
1751                 return r;
1752
1753         for (i = 0; i < n; i++) {
1754
1755                 if (iov[i].iov_base)
1756                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
1757                 else
1758                         memset(p, ' ', iov[i].iov_len);
1759
1760                 p += iov[i].iov_len;
1761         }
1762
1763         return 0;
1764 }
1765 #endif // 0
1766
1767 static int bus_message_open_array(
1768                 sd_bus_message *m,
1769                 struct bus_container *c,
1770                 const char *contents,
1771                 uint32_t **array_size,
1772                 size_t *begin,
1773                 bool *need_offsets) {
1774
1775         unsigned nindex;
1776         int alignment, r;
1777
1778         assert(m);
1779         assert(c);
1780         assert(contents);
1781         assert(array_size);
1782         assert(begin);
1783         assert(need_offsets);
1784
1785         if (!signature_is_single(contents, true))
1786                 return -EINVAL;
1787
1788         if (c->signature && c->signature[c->index]) {
1789
1790                 /* Verify the existing signature */
1791
1792                 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
1793                         return -ENXIO;
1794
1795                 if (!startswith(c->signature + c->index + 1, contents))
1796                         return -ENXIO;
1797
1798                 nindex = c->index + 1 + strlen(contents);
1799         } else {
1800                 char *e;
1801
1802                 if (c->enclosing != 0)
1803                         return -ENXIO;
1804
1805                 /* Extend the existing signature */
1806
1807                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
1808                 if (!e) {
1809                         m->poisoned = true;
1810                         return -ENOMEM;
1811                 }
1812
1813                 nindex = e - c->signature;
1814         }
1815
1816         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1817                 alignment = bus_gvariant_get_alignment(contents);
1818                 if (alignment < 0)
1819                         return alignment;
1820
1821                 /* Add alignment padding and add to offset list */
1822                 if (!message_extend_body(m, alignment, 0, false, false))
1823                         return -ENOMEM;
1824
1825                 r = bus_gvariant_is_fixed_size(contents);
1826                 if (r < 0)
1827                         return r;
1828
1829                 *begin = m->body_size;
1830                 *need_offsets = r == 0;
1831         } else {
1832                 void *a, *op;
1833                 size_t os;
1834                 struct bus_body_part *o;
1835
1836                 alignment = bus_type_get_alignment(contents[0]);
1837                 if (alignment < 0)
1838                         return alignment;
1839
1840                 a = message_extend_body(m, 4, 4, false, false);
1841                 if (!a)
1842                         return -ENOMEM;
1843
1844                 o = m->body_end;
1845                 op = m->body_end->data;
1846                 os = m->body_end->size;
1847
1848                 /* Add alignment between size and first element */
1849                 if (!message_extend_body(m, alignment, 0, false, false))
1850                         return -ENOMEM;
1851
1852                 /* location of array size might have changed so let's readjust a */
1853                 if (o == m->body_end)
1854                         a = adjust_pointer(a, op, os, m->body_end->data);
1855
1856                 *(uint32_t*) a = 0;
1857                 *array_size = a;
1858         }
1859
1860         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1861                 c->index = nindex;
1862
1863         return 0;
1864 }
1865
1866 static int bus_message_open_variant(
1867                 sd_bus_message *m,
1868                 struct bus_container *c,
1869                 const char *contents) {
1870
1871         assert(m);
1872         assert(c);
1873         assert(contents);
1874
1875         if (!signature_is_single(contents, false))
1876                 return -EINVAL;
1877
1878         if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1879                 return -EINVAL;
1880
1881         if (c->signature && c->signature[c->index]) {
1882
1883                 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
1884                         return -ENXIO;
1885
1886         } else {
1887                 char *e;
1888
1889                 if (c->enclosing != 0)
1890                         return -ENXIO;
1891
1892                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
1893                 if (!e) {
1894                         m->poisoned = true;
1895                         return -ENOMEM;
1896                 }
1897         }
1898
1899         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1900                 /* Variants are always aligned to 8 */
1901
1902                 if (!message_extend_body(m, 8, 0, false, false))
1903                         return -ENOMEM;
1904
1905         } else {
1906                 size_t l;
1907                 void *a;
1908
1909                 l = strlen(contents);
1910                 a = message_extend_body(m, 1, 1 + l + 1, false, false);
1911                 if (!a)
1912                         return -ENOMEM;
1913
1914                 *(uint8_t*) a = l;
1915                 memcpy((uint8_t*) a + 1, contents, l + 1);
1916         }
1917
1918         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1919                 c->index++;
1920
1921         return 0;
1922 }
1923
1924 static int bus_message_open_struct(
1925                 sd_bus_message *m,
1926                 struct bus_container *c,
1927                 const char *contents,
1928                 size_t *begin,
1929                 bool *need_offsets) {
1930
1931         size_t nindex;
1932         int r;
1933
1934         assert(m);
1935         assert(c);
1936         assert(contents);
1937         assert(begin);
1938         assert(need_offsets);
1939
1940         if (!signature_is_valid(contents, false))
1941                 return -EINVAL;
1942
1943         if (c->signature && c->signature[c->index]) {
1944                 size_t l;
1945
1946                 l = strlen(contents);
1947
1948                 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1949                     !startswith(c->signature + c->index + 1, contents) ||
1950                     c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
1951                         return -ENXIO;
1952
1953                 nindex = c->index + 1 + l + 1;
1954         } else {
1955                 char *e;
1956
1957                 if (c->enclosing != 0)
1958                         return -ENXIO;
1959
1960                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
1961                 if (!e) {
1962                         m->poisoned = true;
1963                         return -ENOMEM;
1964                 }
1965
1966                 nindex = e - c->signature;
1967         }
1968
1969         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1970                 int alignment;
1971
1972                 alignment = bus_gvariant_get_alignment(contents);
1973                 if (alignment < 0)
1974                         return alignment;
1975
1976                 if (!message_extend_body(m, alignment, 0, false, false))
1977                         return -ENOMEM;
1978
1979                 r = bus_gvariant_is_fixed_size(contents);
1980                 if (r < 0)
1981                         return r;
1982
1983                 *begin = m->body_size;
1984                 *need_offsets = r == 0;
1985         } else {
1986                 /* Align contents to 8 byte boundary */
1987                 if (!message_extend_body(m, 8, 0, false, false))
1988                         return -ENOMEM;
1989         }
1990
1991         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1992                 c->index = nindex;
1993
1994         return 0;
1995 }
1996
1997 static int bus_message_open_dict_entry(
1998                 sd_bus_message *m,
1999                 struct bus_container *c,
2000                 const char *contents,
2001                 size_t *begin,
2002                 bool *need_offsets) {
2003
2004         int r;
2005
2006         assert(m);
2007         assert(c);
2008         assert(contents);
2009         assert(begin);
2010         assert(need_offsets);
2011
2012         if (!signature_is_pair(contents))
2013                 return -EINVAL;
2014
2015         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2016                 return -ENXIO;
2017
2018         if (c->signature && c->signature[c->index]) {
2019                 size_t l;
2020
2021                 l = strlen(contents);
2022
2023                 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
2024                     !startswith(c->signature + c->index + 1, contents) ||
2025                     c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
2026                         return -ENXIO;
2027         } else
2028                 return -ENXIO;
2029
2030         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2031                 int alignment;
2032
2033                 alignment = bus_gvariant_get_alignment(contents);
2034                 if (alignment < 0)
2035                         return alignment;
2036
2037                 if (!message_extend_body(m, alignment, 0, false, false))
2038                         return -ENOMEM;
2039
2040                 r = bus_gvariant_is_fixed_size(contents);
2041                 if (r < 0)
2042                         return r;
2043
2044                 *begin = m->body_size;
2045                 *need_offsets = r == 0;
2046         } else {
2047                 /* Align contents to 8 byte boundary */
2048                 if (!message_extend_body(m, 8, 0, false, false))
2049                         return -ENOMEM;
2050         }
2051
2052         return 0;
2053 }
2054
2055 _public_ int sd_bus_message_open_container(
2056                 sd_bus_message *m,
2057                 char type,
2058                 const char *contents) {
2059
2060         struct bus_container *c, *w;
2061         uint32_t *array_size = NULL;
2062         char *signature;
2063         size_t before, begin = 0;
2064         bool need_offsets = false;
2065         int r;
2066
2067         assert_return(m, -EINVAL);
2068         assert_return(!m->sealed, -EPERM);
2069         assert_return(contents, -EINVAL);
2070         assert_return(!m->poisoned, -ESTALE);
2071
2072         /* Make sure we have space for one more container */
2073         if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
2074                 m->poisoned = true;
2075                 return -ENOMEM;
2076         }
2077
2078         c = message_get_container(m);
2079
2080         signature = strdup(contents);
2081         if (!signature) {
2082                 m->poisoned = true;
2083                 return -ENOMEM;
2084         }
2085
2086         /* Save old index in the parent container, in case we have to
2087          * abort this container */
2088         c->saved_index = c->index;
2089         before = m->body_size;
2090
2091         if (type == SD_BUS_TYPE_ARRAY)
2092                 r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
2093         else if (type == SD_BUS_TYPE_VARIANT)
2094                 r = bus_message_open_variant(m, c, contents);
2095         else if (type == SD_BUS_TYPE_STRUCT)
2096                 r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
2097         else if (type == SD_BUS_TYPE_DICT_ENTRY)
2098                 r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
2099         else
2100                 r = -EINVAL;
2101
2102         if (r < 0) {
2103                 free(signature);
2104                 return r;
2105         }
2106
2107         /* OK, let's fill it in */
2108         w = m->containers + m->n_containers++;
2109         w->enclosing = type;
2110         w->signature = signature;
2111         w->index = 0;
2112         w->array_size = array_size;
2113         w->before = before;
2114         w->begin = begin;
2115         w->n_offsets = w->offsets_allocated = 0;
2116         w->offsets = NULL;
2117         w->need_offsets = need_offsets;
2118
2119         return 0;
2120 }
2121
2122 static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
2123
2124         assert(m);
2125         assert(c);
2126
2127         if (!BUS_MESSAGE_IS_GVARIANT(m))
2128                 return 0;
2129
2130         if (c->need_offsets) {
2131                 size_t payload, sz, i;
2132                 uint8_t *a;
2133
2134                 /* Variable-width arrays */
2135
2136                 payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
2137                 sz = bus_gvariant_determine_word_size(payload, c->n_offsets);
2138
2139                 a = message_extend_body(m, 1, sz * c->n_offsets, true, false);
2140                 if (!a)
2141                         return -ENOMEM;
2142
2143                 for (i = 0; i < c->n_offsets; i++)
2144                         bus_gvariant_write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
2145         } else {
2146                 void *a;
2147
2148                 /* Fixed-width or empty arrays */
2149
2150                 a = message_extend_body(m, 1, 0, true, false); /* let's add offset to parent */
2151                 if (!a)
2152                         return -ENOMEM;
2153         }
2154
2155         return 0;
2156 }
2157
2158 static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
2159         uint8_t *a;
2160         size_t l;
2161
2162         assert(m);
2163         assert(c);
2164         assert(c->signature);
2165
2166         if (!BUS_MESSAGE_IS_GVARIANT(m))
2167                 return 0;
2168
2169         l = strlen(c->signature);
2170
2171         a = message_extend_body(m, 1, 1 + l, true, false);
2172         if (!a)
2173                 return -ENOMEM;
2174
2175         a[0] = 0;
2176         memcpy(a+1, c->signature, l);
2177
2178         return 0;
2179 }
2180
2181 static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
2182         bool fixed_size = true;
2183         size_t n_variable = 0;
2184         unsigned i = 0;
2185         const char *p;
2186         uint8_t *a;
2187         int r;
2188
2189         assert(m);
2190         assert(c);
2191
2192         if (!BUS_MESSAGE_IS_GVARIANT(m))
2193                 return 0;
2194
2195         p = strempty(c->signature);
2196         while (*p != 0) {
2197                 size_t n;
2198
2199                 r = signature_element_length(p, &n);
2200                 if (r < 0)
2201                         return r;
2202                 else {
2203                         char t[n+1];
2204
2205                         memcpy(t, p, n);
2206                         t[n] = 0;
2207
2208                         r = bus_gvariant_is_fixed_size(t);
2209                         if (r < 0)
2210                                 return r;
2211                 }
2212
2213                 assert(!c->need_offsets || i <= c->n_offsets);
2214
2215                 /* We need to add an offset for each item that has a
2216                  * variable size and that is not the last one in the
2217                  * list */
2218                 if (r == 0)
2219                         fixed_size = false;
2220                 if (r == 0 && p[n] != 0)
2221                         n_variable++;
2222
2223                 i++;
2224                 p += n;
2225         }
2226
2227         assert(!c->need_offsets || i == c->n_offsets);
2228         assert(c->need_offsets || n_variable == 0);
2229
2230         if (isempty(c->signature)) {
2231                 /* The unary type is encoded as fixed 1 byte padding */
2232                 a = message_extend_body(m, 1, 1, add_offset, false);
2233                 if (!a)
2234                         return -ENOMEM;
2235
2236                 *a = 0;
2237         } else if (n_variable <= 0) {
2238                 int alignment = 1;
2239
2240                 /* Structures with fixed-size members only have to be
2241                  * fixed-size themselves. But gvariant requires all fixed-size
2242                  * elements to be sized a multiple of their alignment. Hence,
2243                  * we must *always* add final padding after the last member so
2244                  * the overall size of the structure is properly aligned. */
2245                 if (fixed_size)
2246                         alignment = bus_gvariant_get_alignment(strempty(c->signature));
2247
2248                 assert(alignment > 0);
2249
2250                 a = message_extend_body(m, alignment, 0, add_offset, false);
2251                 if (!a)
2252                         return -ENOMEM;
2253         } else {
2254                 size_t sz;
2255                 unsigned j;
2256
2257                 assert(c->offsets[c->n_offsets-1] == m->body_size);
2258
2259                 sz = bus_gvariant_determine_word_size(m->body_size - c->begin, n_variable);
2260
2261                 a = message_extend_body(m, 1, sz * n_variable, add_offset, false);
2262                 if (!a)
2263                         return -ENOMEM;
2264
2265                 p = strempty(c->signature);
2266                 for (i = 0, j = 0; i < c->n_offsets; i++) {
2267                         unsigned k;
2268                         size_t n;
2269
2270                         r = signature_element_length(p, &n);
2271                         if (r < 0)
2272                                 return r;
2273                         else {
2274                                 char t[n+1];
2275
2276                                 memcpy(t, p, n);
2277                                 t[n] = 0;
2278
2279                                 p += n;
2280
2281                                 r = bus_gvariant_is_fixed_size(t);
2282                                 if (r < 0)
2283                                         return r;
2284                                 if (r > 0 || p[0] == 0)
2285                                         continue;
2286                         }
2287
2288                         k = n_variable - 1 - j;
2289
2290                         bus_gvariant_write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
2291
2292                         j++;
2293                 }
2294         }
2295
2296         return 0;
2297 }
2298
2299 _public_ int sd_bus_message_close_container(sd_bus_message *m) {
2300         struct bus_container *c;
2301         int r;
2302
2303         assert_return(m, -EINVAL);
2304         assert_return(!m->sealed, -EPERM);
2305         assert_return(m->n_containers > 0, -EINVAL);
2306         assert_return(!m->poisoned, -ESTALE);
2307
2308         c = message_get_container(m);
2309
2310         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2311                 if (c->signature && c->signature[c->index] != 0)
2312                         return -EINVAL;
2313
2314         m->n_containers--;
2315
2316         if (c->enclosing == SD_BUS_TYPE_ARRAY)
2317                 r = bus_message_close_array(m, c);
2318         else if (c->enclosing == SD_BUS_TYPE_VARIANT)
2319                 r = bus_message_close_variant(m, c);
2320         else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
2321                 r = bus_message_close_struct(m, c, true);
2322         else
2323                 assert_not_reached("Unknown container type");
2324
2325         free(c->signature);
2326         free(c->offsets);
2327
2328         return r;
2329 }
2330
2331 typedef struct {
2332         const char *types;
2333         unsigned n_struct;
2334         unsigned n_array;
2335 } TypeStack;
2336
2337 static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
2338         assert(stack);
2339         assert(max > 0);
2340
2341         if (*i >= max)
2342                 return -EINVAL;
2343
2344         stack[*i].types = types;
2345         stack[*i].n_struct = n_struct;
2346         stack[*i].n_array = n_array;
2347         (*i)++;
2348
2349         return 0;
2350 }
2351
2352 static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
2353         assert(stack);
2354         assert(max > 0);
2355         assert(types);
2356         assert(n_struct);
2357         assert(n_array);
2358
2359         if (*i <= 0)
2360                 return 0;
2361
2362         (*i)--;
2363         *types = stack[*i].types;
2364         *n_struct = stack[*i].n_struct;
2365         *n_array = stack[*i].n_array;
2366
2367         return 1;
2368 }
2369
2370 int bus_message_append_ap(
2371                 sd_bus_message *m,
2372                 const char *types,
2373                 va_list ap) {
2374
2375         unsigned n_array, n_struct;
2376         TypeStack stack[BUS_CONTAINER_DEPTH];
2377         unsigned stack_ptr = 0;
2378         int r;
2379
2380         assert(m);
2381
2382         if (!types)
2383                 return 0;
2384
2385         n_array = (unsigned) -1;
2386         n_struct = strlen(types);
2387
2388         for (;;) {
2389                 const char *t;
2390
2391                 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
2392                         r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
2393                         if (r < 0)
2394                                 return r;
2395                         if (r == 0)
2396                                 break;
2397
2398                         r = sd_bus_message_close_container(m);
2399                         if (r < 0)
2400                                 return r;
2401
2402                         continue;
2403                 }
2404
2405                 t = types;
2406                 if (n_array != (unsigned) -1)
2407                         n_array --;
2408                 else {
2409                         types ++;
2410                         n_struct--;
2411                 }
2412
2413                 switch (*t) {
2414
2415                 case SD_BUS_TYPE_BYTE: {
2416                         uint8_t x;
2417
2418                         x = (uint8_t) va_arg(ap, int);
2419                         r = sd_bus_message_append_basic(m, *t, &x);
2420                         break;
2421                 }
2422
2423                 case SD_BUS_TYPE_BOOLEAN:
2424                 case SD_BUS_TYPE_INT32:
2425                 case SD_BUS_TYPE_UINT32:
2426                 case SD_BUS_TYPE_UNIX_FD: {
2427                         uint32_t x;
2428
2429                         /* We assume a boolean is the same as int32_t */
2430                         assert_cc(sizeof(int32_t) == sizeof(int));
2431
2432                         x = va_arg(ap, uint32_t);
2433                         r = sd_bus_message_append_basic(m, *t, &x);
2434                         break;
2435                 }
2436
2437                 case SD_BUS_TYPE_INT16:
2438                 case SD_BUS_TYPE_UINT16: {
2439                         uint16_t x;
2440
2441                         x = (uint16_t) va_arg(ap, int);
2442                         r = sd_bus_message_append_basic(m, *t, &x);
2443                         break;
2444                 }
2445
2446                 case SD_BUS_TYPE_INT64:
2447                 case SD_BUS_TYPE_UINT64: {
2448                         uint64_t x;
2449
2450                         x = va_arg(ap, uint64_t);
2451                         r = sd_bus_message_append_basic(m, *t, &x);
2452                         break;
2453                 }
2454
2455                 case SD_BUS_TYPE_DOUBLE: {
2456                         double x;
2457
2458                         x = va_arg(ap, double);
2459                         r = sd_bus_message_append_basic(m, *t, &x);
2460                         break;
2461                 }
2462
2463                 case SD_BUS_TYPE_STRING:
2464                 case SD_BUS_TYPE_OBJECT_PATH:
2465                 case SD_BUS_TYPE_SIGNATURE: {
2466                         const char *x;
2467
2468                         x = va_arg(ap, const char*);
2469                         r = sd_bus_message_append_basic(m, *t, x);
2470                         break;
2471                 }
2472
2473                 case SD_BUS_TYPE_ARRAY: {
2474                         size_t k;
2475
2476                         r = signature_element_length(t + 1, &k);
2477                         if (r < 0)
2478                                 return r;
2479
2480                         {
2481                                 char s[k + 1];
2482                                 memcpy(s, t + 1, k);
2483                                 s[k] = 0;
2484
2485                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
2486                                 if (r < 0)
2487                                         return r;
2488                         }
2489
2490                         if (n_array == (unsigned) -1) {
2491                                 types += k;
2492                                 n_struct -= k;
2493                         }
2494
2495                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2496                         if (r < 0)
2497                                 return r;
2498
2499                         types = t + 1;
2500                         n_struct = k;
2501                         n_array = va_arg(ap, unsigned);
2502
2503                         break;
2504                 }
2505
2506                 case SD_BUS_TYPE_VARIANT: {
2507                         const char *s;
2508
2509                         s = va_arg(ap, const char*);
2510                         if (!s)
2511                                 return -EINVAL;
2512
2513                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
2514                         if (r < 0)
2515                                 return r;
2516
2517                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2518                         if (r < 0)
2519                                 return r;
2520
2521                         types = s;
2522                         n_struct = strlen(s);
2523                         n_array = (unsigned) -1;
2524
2525                         break;
2526                 }
2527
2528                 case SD_BUS_TYPE_STRUCT_BEGIN:
2529                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
2530                         size_t k;
2531
2532                         r = signature_element_length(t, &k);
2533                         if (r < 0)
2534                                 return r;
2535
2536                         {
2537                                 char s[k - 1];
2538
2539                                 memcpy(s, t + 1, k - 2);
2540                                 s[k - 2] = 0;
2541
2542                                 r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
2543                                 if (r < 0)
2544                                         return r;
2545                         }
2546
2547                         if (n_array == (unsigned) -1) {
2548                                 types += k - 1;
2549                                 n_struct -= k - 1;
2550                         }
2551
2552                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2553                         if (r < 0)
2554                                 return r;
2555
2556                         types = t + 1;
2557                         n_struct = k - 2;
2558                         n_array = (unsigned) -1;
2559
2560                         break;
2561                 }
2562
2563                 default:
2564                         r = -EINVAL;
2565                 }
2566
2567                 if (r < 0)
2568                         return r;
2569         }
2570
2571         return 1;
2572 }
2573
2574 _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
2575         va_list ap;
2576         int r;
2577
2578         assert_return(m, -EINVAL);
2579         assert_return(types, -EINVAL);
2580         assert_return(!m->sealed, -EPERM);
2581         assert_return(!m->poisoned, -ESTALE);
2582
2583         va_start(ap, types);
2584         r = bus_message_append_ap(m, types, ap);
2585         va_end(ap);
2586
2587         return r;
2588 }
2589
2590 _public_ int sd_bus_message_append_array_space(
2591                 sd_bus_message *m,
2592                 char type,
2593                 size_t size,
2594                 void **ptr) {
2595
2596         ssize_t align, sz;
2597         void *a;
2598         int r;
2599
2600         assert_return(m, -EINVAL);
2601         assert_return(!m->sealed, -EPERM);
2602         assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
2603         assert_return(ptr || size == 0, -EINVAL);
2604         assert_return(!m->poisoned, -ESTALE);
2605
2606         /* alignment and size of the trivial types (except bool) is
2607          * identical for gvariant and dbus1 marshalling */
2608         align = bus_type_get_alignment(type);
2609         sz = bus_type_get_size(type);
2610
2611         assert_se(align > 0);
2612         assert_se(sz > 0);
2613
2614         if (size % sz != 0)
2615                 return -EINVAL;
2616
2617         r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2618         if (r < 0)
2619                 return r;
2620
2621         a = message_extend_body(m, align, size, false, false);
2622         if (!a)
2623                 return -ENOMEM;
2624
2625         r = sd_bus_message_close_container(m);
2626         if (r < 0)
2627                 return r;
2628
2629         *ptr = a;
2630         return 0;
2631 }
2632
2633 _public_ int sd_bus_message_append_array(
2634                 sd_bus_message *m,
2635                 char type,
2636                 const void *ptr,
2637                 size_t size) {
2638         int r;
2639         void *p;
2640
2641         assert_return(m, -EINVAL);
2642         assert_return(!m->sealed, -EPERM);
2643         assert_return(bus_type_is_trivial(type), -EINVAL);
2644         assert_return(ptr || size == 0, -EINVAL);
2645         assert_return(!m->poisoned, -ESTALE);
2646
2647         r = sd_bus_message_append_array_space(m, type, size, &p);
2648         if (r < 0)
2649                 return r;
2650
2651         if (size > 0)
2652                 memcpy(p, ptr, size);
2653
2654         return 0;
2655 }
2656
2657 /// UNNEEDED by elogind
2658 #if 0
2659 _public_ int sd_bus_message_append_array_iovec(
2660                 sd_bus_message *m,
2661                 char type,
2662                 const struct iovec *iov,
2663                 unsigned n) {
2664
2665         size_t size;
2666         unsigned i;
2667         void *p;
2668         int r;
2669
2670         assert_return(m, -EINVAL);
2671         assert_return(!m->sealed, -EPERM);
2672         assert_return(bus_type_is_trivial(type), -EINVAL);
2673         assert_return(iov || n == 0, -EINVAL);
2674         assert_return(!m->poisoned, -ESTALE);
2675
2676         size = IOVEC_TOTAL_SIZE(iov, n);
2677
2678         r = sd_bus_message_append_array_space(m, type, size, &p);
2679         if (r < 0)
2680                 return r;
2681
2682         for (i = 0; i < n; i++) {
2683
2684                 if (iov[i].iov_base)
2685                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
2686                 else
2687                         memzero(p, iov[i].iov_len);
2688
2689                 p = (uint8_t*) p + iov[i].iov_len;
2690         }
2691
2692         return 0;
2693 }
2694
2695 _public_ int sd_bus_message_append_array_memfd(
2696                 sd_bus_message *m,
2697                 char type,
2698                 int memfd,
2699                 uint64_t offset,
2700                 uint64_t size) {
2701
2702         _cleanup_close_ int copy_fd = -1;
2703         struct bus_body_part *part;
2704         ssize_t align, sz;
2705         uint64_t real_size;
2706         void *a;
2707         int r;
2708
2709         assert_return(m, -EINVAL);
2710         assert_return(memfd >= 0, -EBADF);
2711         assert_return(bus_type_is_trivial(type), -EINVAL);
2712         assert_return(size > 0, -EINVAL);
2713         assert_return(!m->sealed, -EPERM);
2714         assert_return(!m->poisoned, -ESTALE);
2715
2716         r = memfd_set_sealed(memfd);
2717         if (r < 0)
2718                 return r;
2719
2720         copy_fd = dup(memfd);
2721         if (copy_fd < 0)
2722                 return copy_fd;
2723
2724         r = memfd_get_size(memfd, &real_size);
2725         if (r < 0)
2726                 return r;
2727
2728         if (offset == 0 && size == (uint64_t) -1)
2729                 size = real_size;
2730         else if (offset + size > real_size)
2731                 return -EMSGSIZE;
2732
2733         align = bus_type_get_alignment(type);
2734         sz = bus_type_get_size(type);
2735
2736         assert_se(align > 0);
2737         assert_se(sz > 0);
2738
2739         if (offset % align != 0)
2740                 return -EINVAL;
2741
2742         if (size % sz != 0)
2743                 return -EINVAL;
2744
2745         if (size > (uint64_t) (uint32_t) -1)
2746                 return -EINVAL;
2747
2748         r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2749         if (r < 0)
2750                 return r;
2751
2752         a = message_extend_body(m, align, 0, false, false);
2753         if (!a)
2754                 return -ENOMEM;
2755
2756         part = message_append_part(m);
2757         if (!part)
2758                 return -ENOMEM;
2759
2760         part->memfd = copy_fd;
2761         part->memfd_offset = offset;
2762         part->sealed = true;
2763         part->size = size;
2764         copy_fd = -1;
2765
2766         m->body_size += size;
2767         message_extend_containers(m, size);
2768
2769         return sd_bus_message_close_container(m);
2770 }
2771
2772 _public_ int sd_bus_message_append_string_memfd(
2773                 sd_bus_message *m,
2774                 int memfd,
2775                 uint64_t offset,
2776                 uint64_t size) {
2777
2778         _cleanup_close_ int copy_fd = -1;
2779         struct bus_body_part *part;
2780         struct bus_container *c;
2781         uint64_t real_size;
2782         void *a;
2783         int r;
2784
2785         assert_return(m, -EINVAL);
2786         assert_return(memfd >= 0, -EBADF);
2787         assert_return(size > 0, -EINVAL);
2788         assert_return(!m->sealed, -EPERM);
2789         assert_return(!m->poisoned, -ESTALE);
2790
2791         r = memfd_set_sealed(memfd);
2792         if (r < 0)
2793                 return r;
2794
2795         copy_fd = dup(memfd);
2796         if (copy_fd < 0)
2797                 return copy_fd;
2798
2799         r = memfd_get_size(memfd, &real_size);
2800         if (r < 0)
2801                 return r;
2802
2803         if (offset == 0 && size == (uint64_t) -1)
2804                 size = real_size;
2805         else if (offset + size > real_size)
2806                 return -EMSGSIZE;
2807
2808         /* We require this to be NUL terminated */
2809         if (size == 0)
2810                 return -EINVAL;
2811
2812         if (size > (uint64_t) (uint32_t) -1)
2813                 return -EINVAL;
2814
2815         c = message_get_container(m);
2816         if (c->signature && c->signature[c->index]) {
2817                 /* Container signature is already set */
2818
2819                 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2820                         return -ENXIO;
2821         } else {
2822                 char *e;
2823
2824                 /* Maybe we can append to the signature? But only if this is the top-level container */
2825                 if (c->enclosing != 0)
2826                         return -ENXIO;
2827
2828                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2829                 if (!e) {
2830                         m->poisoned = true;
2831                         return -ENOMEM;
2832                 }
2833         }
2834
2835         if (!BUS_MESSAGE_IS_GVARIANT(m)) {
2836                 a = message_extend_body(m, 4, 4, false, false);
2837                 if (!a)
2838                         return -ENOMEM;
2839
2840                 *(uint32_t*) a = size - 1;
2841         }
2842
2843         part = message_append_part(m);
2844         if (!part)
2845                 return -ENOMEM;
2846
2847         part->memfd = copy_fd;
2848         part->memfd_offset = offset;
2849         part->sealed = true;
2850         part->size = size;
2851         copy_fd = -1;
2852
2853         m->body_size += size;
2854         message_extend_containers(m, size);
2855
2856         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2857                 r = message_add_offset(m, m->body_size);
2858                 if (r < 0) {
2859                         m->poisoned = true;
2860                         return -ENOMEM;
2861                 }
2862         }
2863
2864         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2865                 c->index++;
2866
2867         return 0;
2868 }
2869 #endif // 0
2870
2871 _public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
2872         char **i;
2873         int r;
2874
2875         assert_return(m, -EINVAL);
2876         assert_return(!m->sealed, -EPERM);
2877         assert_return(!m->poisoned, -ESTALE);
2878
2879         r = sd_bus_message_open_container(m, 'a', "s");
2880         if (r < 0)
2881                 return r;
2882
2883         STRV_FOREACH(i, l) {
2884                 r = sd_bus_message_append_basic(m, 's', *i);
2885                 if (r < 0)
2886                         return r;
2887         }
2888
2889         return sd_bus_message_close_container(m);
2890 }
2891
2892 static int bus_message_close_header(sd_bus_message *m) {
2893
2894         assert(m);
2895
2896         /* The actual user data is finished now, we just complete the
2897            variant and struct now (at least on gvariant). Remember
2898            this position, so that during parsing we know where to to
2899            put the outer container end. */
2900         m->user_body_size = m->body_size;
2901
2902         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2903                 const char *signature;
2904                 size_t sz, l;
2905                 void *d;
2906
2907                 /* Add offset table to end of fields array */
2908                 if (m->n_header_offsets >= 1) {
2909                         uint8_t *a;
2910                         unsigned i;
2911
2912                         assert(m->fields_size == m->header_offsets[m->n_header_offsets-1]);
2913
2914                         sz = bus_gvariant_determine_word_size(m->fields_size, m->n_header_offsets);
2915                         a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2916                         if (!a)
2917                                 return -ENOMEM;
2918
2919                         for (i = 0; i < m->n_header_offsets; i++)
2920                                 bus_gvariant_write_word_le(a + sz*i, sz, m->header_offsets[i]);
2921                 }
2922
2923                 /* Add gvariant NUL byte plus signature to the end of
2924                  * the body, followed by the final offset pointing to
2925                  * the end of the fields array */
2926
2927                 signature = strempty(m->root_container.signature);
2928                 l = strlen(signature);
2929
2930                 sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l + 2, 1);
2931                 d = message_extend_body(m, 1, 1 + l + 2 + sz, false, true);
2932                 if (!d)
2933                         return -ENOMEM;
2934
2935                 *(uint8_t*) d = 0;
2936                 *((uint8_t*) d + 1) = SD_BUS_TYPE_STRUCT_BEGIN;
2937                 memcpy((uint8_t*) d + 2, signature, l);
2938                 *((uint8_t*) d + 1 + l + 1) = SD_BUS_TYPE_STRUCT_END;
2939
2940                 bus_gvariant_write_word_le((uint8_t*) d + 1 + l + 2, sz, sizeof(struct bus_header) + m->fields_size);
2941
2942                 m->footer = d;
2943                 m->footer_accessible = 1 + l + 2 + sz;
2944         } else {
2945                 m->header->dbus1.fields_size = m->fields_size;
2946                 m->header->dbus1.body_size = m->body_size;
2947         }
2948
2949         return 0;
2950 }
2951
2952 int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
2953         struct bus_body_part *part;
2954         size_t a;
2955         unsigned i;
2956         int r;
2957
2958         assert(m);
2959
2960         if (m->sealed)
2961                 return -EPERM;
2962
2963         if (m->n_containers > 0)
2964                 return -EBADMSG;
2965
2966         if (m->poisoned)
2967                 return -ESTALE;
2968
2969         if (cookie > 0xffffffffULL &&
2970             !BUS_MESSAGE_IS_GVARIANT(m))
2971                 return -EOPNOTSUPP;
2972
2973         /* In vtables the return signature of method calls is listed,
2974          * let's check if they match if this is a response */
2975         if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2976             m->enforced_reply_signature &&
2977             !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2978                 return -ENOMSG;
2979
2980         /* If gvariant marshalling is used we need to close the body structure */
2981         r = bus_message_close_struct(m, &m->root_container, false);
2982         if (r < 0)
2983                 return r;
2984
2985         /* If there's a non-trivial signature set, then add it in
2986          * here, but only on dbus1 */
2987         if (!isempty(m->root_container.signature) && !BUS_MESSAGE_IS_GVARIANT(m)) {
2988                 r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2989                 if (r < 0)
2990                         return r;
2991         }
2992
2993         if (m->n_fds > 0) {
2994                 r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2995                 if (r < 0)
2996                         return r;
2997         }
2998
2999         r = bus_message_close_header(m);
3000         if (r < 0)
3001                 return r;
3002
3003         if (BUS_MESSAGE_IS_GVARIANT(m))
3004                 m->header->dbus2.cookie = cookie;
3005         else
3006                 m->header->dbus1.serial = (uint32_t) cookie;
3007
3008         m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
3009
3010         /* Add padding at the end of the fields part, since we know
3011          * the body needs to start at an 8 byte alignment. We made
3012          * sure we allocated enough space for this, so all we need to
3013          * do here is to zero it out. */
3014         a = ALIGN8(m->fields_size) - m->fields_size;
3015         if (a > 0)
3016                 memzero((uint8_t*) BUS_MESSAGE_FIELDS(m) + m->fields_size, a);
3017
3018         /* If this is something we can send as memfd, then let's seal
3019         the memfd now. Note that we can send memfds as payload only
3020         for directed messages, and not for broadcasts. */
3021         if (m->destination && m->bus->use_memfd) {
3022                 MESSAGE_FOREACH_PART(part, i, m)
3023                         if (part->memfd >= 0 &&
3024                             !part->sealed &&
3025                             (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0) &&
3026                             part != m->body_end) { /* The last part may never be sent as memfd */
3027                                 uint64_t sz;
3028
3029                                 /* Try to seal it if that makes
3030                                  * sense. First, unmap our own map to
3031                                  * make sure we don't keep it busy. */
3032                                 bus_body_part_unmap(part);
3033
3034                                 /* Then, sync up real memfd size */
3035                                 sz = part->size;
3036                                 r = memfd_set_size(part->memfd, sz);
3037                                 if (r < 0)
3038                                         return r;
3039
3040                                 /* Finally, try to seal */
3041                                 if (memfd_set_sealed(part->memfd) >= 0)
3042                                         part->sealed = true;
3043                         }
3044         }
3045
3046         m->root_container.end = m->user_body_size;
3047         m->root_container.index = 0;
3048         m->root_container.offset_index = 0;
3049         m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
3050
3051         m->sealed = true;
3052
3053         return 0;
3054 }
3055
3056 int bus_body_part_map(struct bus_body_part *part) {
3057         void *p;
3058         size_t psz, shift;
3059
3060         assert_se(part);
3061
3062         if (part->data)
3063                 return 0;
3064
3065         if (part->size <= 0)
3066                 return 0;
3067
3068         /* For smaller zero parts (as used for padding) we don't need to map anything... */
3069         if (part->memfd < 0 && part->is_zero && part->size < 8) {
3070                 static const uint8_t zeroes[7] = { };
3071                 part->data = (void*) zeroes;
3072                 return 0;
3073         }
3074
3075         shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
3076         psz = PAGE_ALIGN(part->size + shift);
3077
3078         if (part->memfd >= 0)
3079                 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, part->memfd_offset - shift);
3080         else if (part->is_zero)
3081                 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
3082         else
3083                 return -EINVAL;
3084
3085         if (p == MAP_FAILED)
3086                 return -errno;
3087
3088         part->mapped = psz;
3089         part->mmap_begin = p;
3090         part->data = (uint8_t*) p + shift;
3091         part->munmap_this = true;
3092
3093         return 0;
3094 }
3095
3096 void bus_body_part_unmap(struct bus_body_part *part) {
3097
3098         assert_se(part);
3099
3100         if (part->memfd < 0)
3101                 return;
3102
3103         if (!part->mmap_begin)
3104                 return;
3105
3106         if (!part->munmap_this)
3107                 return;
3108
3109         assert_se(munmap(part->mmap_begin, part->mapped) == 0);
3110
3111         part->mmap_begin = NULL;
3112         part->data = NULL;
3113         part->mapped = 0;
3114         part->munmap_this = false;
3115
3116         return;
3117 }
3118
3119 static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
3120         size_t k, start, end;
3121
3122         assert(rindex);
3123         assert(align > 0);
3124
3125         start = ALIGN_TO((size_t) *rindex, align);
3126         end = start + nbytes;
3127
3128         if (end > sz)
3129                 return -EBADMSG;
3130
3131         /* Verify that padding is 0 */
3132         for (k = *rindex; k < start; k++)
3133                 if (((const uint8_t*) p)[k] != 0)
3134                         return -EBADMSG;
3135
3136         if (r)
3137                 *r = (uint8_t*) p + start;
3138
3139         *rindex = end;
3140
3141         return 1;
3142 }
3143
3144 static bool message_end_of_signature(sd_bus_message *m) {
3145         struct bus_container *c;
3146
3147         assert(m);
3148
3149         c = message_get_container(m);
3150         return !c->signature || c->signature[c->index] == 0;
3151 }
3152
3153 static bool message_end_of_array(sd_bus_message *m, size_t index) {
3154         struct bus_container *c;
3155
3156         assert(m);
3157
3158         c = message_get_container(m);
3159         if (c->enclosing != SD_BUS_TYPE_ARRAY)
3160                 return false;
3161
3162         if (BUS_MESSAGE_IS_GVARIANT(m))
3163                 return index >= c->end;
3164         else {
3165                 assert(c->array_size);
3166                 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
3167         }
3168 }
3169
3170 /// UNNEEDED by elogind
3171 #if 0
3172 _public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
3173         assert_return(m, -EINVAL);
3174         assert_return(m->sealed, -EPERM);
3175
3176         if (complete && m->n_containers > 0)
3177                 return false;
3178
3179         if (message_end_of_signature(m))
3180                 return true;
3181
3182         if (message_end_of_array(m, m->rindex))
3183                 return true;
3184
3185         return false;
3186 }
3187 #endif // 0
3188
3189 static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
3190         struct bus_body_part *part;
3191         size_t begin;
3192