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