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