chiark / gitweb /
bus: fix rewind logic
[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
795         if (!m)
796                 return NULL;
797
798         assert(m->n_ref > 0);
799         m->n_ref--;
800
801         if (m->n_ref <= 0)
802                 message_free(m);
803
804         return NULL;
805 }
806
807 _public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
808         assert_return(m, -EINVAL);
809         assert_return(type, -EINVAL);
810
811         *type = m->header->type;
812         return 0;
813 }
814
815 _public_ int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial) {
816         assert_return(m, -EINVAL);
817         assert_return(serial, -EINVAL);
818         assert_return(m->header->serial != 0, -ENOENT);
819
820         *serial = BUS_MESSAGE_SERIAL(m);
821         return 0;
822 }
823
824 _public_ int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial) {
825         assert_return(m, -EINVAL);
826         assert_return(serial, -EINVAL);
827         assert_return(m->reply_serial != 0, -ENOENT);
828
829         *serial = m->reply_serial;
830         return 0;
831 }
832
833 _public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
834         assert_return(m, -EINVAL);
835
836         return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
837 }
838
839 _public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
840         assert_return(m, -EINVAL);
841
842         return !!(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
843 }
844
845 _public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
846         assert_return(m, NULL);
847
848         return m->path;
849 }
850
851 _public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
852         assert_return(m, NULL);
853
854         return m->interface;
855 }
856
857 _public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
858         assert_return(m, NULL);
859
860         return m->member;
861 }
862
863 _public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
864         assert_return(m, NULL);
865
866         return m->destination;
867 }
868
869 _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
870         assert_return(m, NULL);
871
872         return m->sender;
873 }
874
875 _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
876         assert_return(m, NULL);
877         assert_return(sd_bus_error_is_set(&m->error), NULL);
878
879         return &m->error;
880 }
881
882 _public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) {
883         assert_return(m, -EINVAL);
884         assert_return(usec, -EINVAL);
885         assert_return(m->monotonic > 0, -ENODATA);
886
887         *usec = m->monotonic;
888         return 0;
889 }
890
891 _public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) {
892         assert_return(m, -EINVAL);
893         assert_return(usec, -EINVAL);
894         assert_return(m->realtime > 0, -ENODATA);
895
896         *usec = m->realtime;
897         return 0;
898 }
899
900 _public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
901         assert_return(m, NULL);
902
903         if (m->creds.mask == 0)
904                 return NULL;
905
906         return &m->creds;
907 }
908
909 _public_ int sd_bus_message_is_signal(sd_bus_message *m,
910                                       const char *interface,
911                                       const char *member) {
912         assert_return(m, -EINVAL);
913
914         if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
915                 return 0;
916
917         if (interface && (!m->interface || !streq(m->interface, interface)))
918                 return 0;
919
920         if (member &&  (!m->member || !streq(m->member, member)))
921                 return 0;
922
923         return 1;
924 }
925
926 _public_ int sd_bus_message_is_method_call(sd_bus_message *m,
927                                            const char *interface,
928                                            const char *member) {
929         assert_return(m, -EINVAL);
930
931         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
932                 return 0;
933
934         if (interface && (!m->interface || !streq(m->interface, interface)))
935                 return 0;
936
937         if (member &&  (!m->member || !streq(m->member, member)))
938                 return 0;
939
940         return 1;
941 }
942
943 _public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
944         assert_return(m, -EINVAL);
945
946         if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
947                 return 0;
948
949         if (name && (!m->error.name || !streq(m->error.name, name)))
950                 return 0;
951
952         return 1;
953 }
954
955 _public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
956         assert_return(m, -EINVAL);
957         assert_return(!m->sealed, -EPERM);
958         assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
959
960         if (b)
961                 m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
962         else
963                 m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
964
965         return 0;
966 }
967
968 _public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
969         assert_return(m, -EINVAL);
970         assert_return(!m->sealed, -EPERM);
971
972         if (b)
973                 m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
974         else
975                 m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
976
977         return 0;
978 }
979
980 static struct bus_container *message_get_container(sd_bus_message *m) {
981         assert(m);
982
983         if (m->n_containers == 0)
984                 return &m->root_container;
985
986         assert(m->containers);
987         return m->containers + m->n_containers - 1;
988 }
989
990 struct bus_body_part *message_append_part(sd_bus_message *m) {
991         struct bus_body_part *part;
992
993         assert(m);
994
995         if (m->poisoned)
996                 return NULL;
997
998         if (m->n_body_parts <= 0) {
999                 part = &m->body;
1000                 zero(*part);
1001         } else {
1002                 assert(m->body_end);
1003
1004                 part = new0(struct bus_body_part, 1);
1005                 if (!part) {
1006                         m->poisoned = true;
1007                         return NULL;
1008                 }
1009
1010                 m->body_end->next = part;
1011         }
1012
1013         part->memfd = -1;
1014         m->body_end = part;
1015         m->n_body_parts ++;
1016
1017         return part;
1018 }
1019
1020 static void part_zero(struct bus_body_part *part, size_t sz) {
1021         assert(part);
1022         assert(sz > 0);
1023         assert(sz < 8);
1024
1025         /* All other fields can be left in their defaults */
1026         assert(!part->data);
1027         assert(part->memfd < 0);
1028
1029         part->size = sz;
1030         part->is_zero = true;
1031         part->sealed = true;
1032 }
1033
1034 static int part_make_space(
1035                 struct sd_bus_message *m,
1036                 struct bus_body_part *part,
1037                 size_t sz,
1038                 void **q) {
1039
1040         void *n;
1041         int r;
1042
1043         assert(m);
1044         assert(part);
1045         assert(!part->sealed);
1046
1047         if (m->poisoned)
1048                 return -ENOMEM;
1049
1050         if (!part->data && part->memfd < 0)
1051                 part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped);
1052
1053         if (part->memfd >= 0) {
1054                 uint64_t u = sz;
1055
1056                 r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &u);
1057                 if (r < 0) {
1058                         m->poisoned = true;
1059                         return -errno;
1060                 }
1061
1062                 if (!part->data || sz > part->mapped) {
1063                         size_t psz = PAGE_ALIGN(sz > 0 ? sz : 1);
1064
1065                         if (part->mapped <= 0)
1066                                 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
1067                         else
1068                                 n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
1069
1070                         if (n == MAP_FAILED) {
1071                                 m->poisoned = true;
1072                                 return -errno;
1073                         }
1074
1075                         part->mapped = psz;
1076                         part->data = n;
1077                 }
1078
1079                 part->munmap_this = true;
1080         } else {
1081                 n = realloc(part->data, MAX(sz, 1u));
1082                 if (!n) {
1083                         m->poisoned = true;
1084                         return -ENOMEM;
1085                 }
1086
1087                 part->data = n;
1088                 part->free_this = true;
1089         }
1090
1091         if (q)
1092                 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1093
1094         part->size = sz;
1095         return 0;
1096 }
1097
1098 static int message_add_offset(sd_bus_message *m, size_t offset) {
1099         struct bus_container *c;
1100
1101         assert(m);
1102         assert(BUS_MESSAGE_IS_GVARIANT(m));
1103
1104         /* Add offset to current container, unless this is the first
1105          * item in it, which will have the 0 offset, which we can
1106          * ignore. */
1107         c = message_get_container(m);
1108
1109         if (!c->need_offsets)
1110                 return 0;
1111
1112         if (!GREEDY_REALLOC(c->offsets, c->n_offsets_allocated, c->n_offsets + 1))
1113                 return -ENOMEM;
1114
1115         c->offsets[c->n_offsets++] = offset;
1116         return 0;
1117 }
1118
1119 static void message_extend_containers(sd_bus_message *m, size_t expand) {
1120         struct bus_container *c;
1121
1122         assert(m);
1123
1124         if (expand <= 0)
1125                 return;
1126
1127         /* Update counters */
1128         for (c = m->containers; c < m->containers + m->n_containers; c++) {
1129
1130                 if (c->array_size)
1131                         *c->array_size += expand;
1132         }
1133 }
1134
1135 static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
1136         size_t start_body, end_body, padding, added;
1137         void *p;
1138         int r;
1139
1140         assert(m);
1141         assert(align > 0);
1142         assert(!m->sealed);
1143
1144         if (m->poisoned)
1145                 return NULL;
1146
1147         start_body = ALIGN_TO((size_t) m->header->body_size, align);
1148         end_body = start_body + sz;
1149
1150         padding = start_body - m->header->body_size;
1151         added = padding + sz;
1152
1153         /* Check for 32bit overflows */
1154         if (end_body > (size_t) ((uint32_t) -1)) {
1155                 m->poisoned = true;
1156                 return NULL;
1157         }
1158
1159         if (added > 0) {
1160                 struct bus_body_part *part = NULL;
1161                 bool add_new_part;
1162
1163                 add_new_part =
1164                         m->n_body_parts <= 0 ||
1165                         m->body_end->sealed ||
1166                         padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
1167
1168                 if (add_new_part) {
1169                         if (padding > 0) {
1170                                 part = message_append_part(m);
1171                                 if (!part)
1172                                         return NULL;
1173
1174                                 part_zero(part, padding);
1175                         }
1176
1177                         part = message_append_part(m);
1178                         if (!part)
1179                                 return NULL;
1180
1181                         r = part_make_space(m, part, sz, &p);
1182                         if (r < 0)
1183                                 return NULL;
1184                 } else {
1185                         struct bus_container *c;
1186                         void *op;
1187                         size_t os, start_part, end_part;
1188
1189                         part = m->body_end;
1190                         op = part->data;
1191                         os = part->size;
1192
1193                         start_part = ALIGN_TO(part->size, align);
1194                         end_part = start_part + sz;
1195
1196                         r = part_make_space(m, part, end_part, &p);
1197                         if (r < 0)
1198                                 return NULL;
1199
1200                         if (padding > 0) {
1201                                 memset(p, 0, padding);
1202                                 p = (uint8_t*) p + padding;
1203                         }
1204
1205                         /* Readjust pointers */
1206                         for (c = m->containers; c < m->containers + m->n_containers; c++)
1207                                 c->array_size = adjust_pointer(c->array_size, op, os, part->data);
1208
1209                         m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
1210                 }
1211         } else
1212                 /* Return something that is not NULL and is aligned */
1213                 p = (uint8_t *) NULL + align;
1214
1215         m->header->body_size = end_body;
1216         message_extend_containers(m, added);
1217
1218         if (add_offset) {
1219                 r = message_add_offset(m, end_body);
1220                 if (r < 0) {
1221                         m->poisoned = true;
1222                         return NULL;
1223                 }
1224         }
1225
1226         return p;
1227 }
1228
1229 static int message_push_fd(sd_bus_message *m, int fd) {
1230         int *f, copy;
1231
1232         assert(m);
1233
1234         if (fd < 0)
1235                 return -EINVAL;
1236
1237         if (!m->allow_fds)
1238                 return -ENOTSUP;
1239
1240         copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
1241         if (copy < 0)
1242                 return -errno;
1243
1244         f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
1245         if (!f) {
1246                 m->poisoned = true;
1247                 close_nointr_nofail(copy);
1248                 return -ENOMEM;
1249         }
1250
1251         m->fds = f;
1252         m->fds[m->n_fds] = copy;
1253         m->free_fds = true;
1254
1255         return copy;
1256 }
1257
1258 int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
1259         _cleanup_close_ int fd = -1;
1260         struct bus_container *c;
1261         ssize_t align, sz;
1262         void *a;
1263
1264         assert_return(m, -EINVAL);
1265         assert_return(!m->sealed, -EPERM);
1266         assert_return(bus_type_is_basic(type), -EINVAL);
1267         assert_return(!m->poisoned, -ESTALE);
1268
1269         c = message_get_container(m);
1270
1271         if (c->signature && c->signature[c->index]) {
1272                 /* Container signature is already set */
1273
1274                 if (c->signature[c->index] != type)
1275                         return -ENXIO;
1276         } else {
1277                 char *e;
1278
1279                 /* Maybe we can append to the signature? But only if this is the top-level container*/
1280                 if (c->enclosing != 0)
1281                         return -ENXIO;
1282
1283                 e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
1284                 if (!e) {
1285                         m->poisoned = true;
1286                         return -ENOMEM;
1287                 }
1288         }
1289
1290         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1291                 uint8_t u8;
1292                 uint32_t u32;
1293
1294                 switch (type) {
1295
1296                 case SD_BUS_TYPE_SIGNATURE:
1297                 case SD_BUS_TYPE_STRING:
1298                         p = strempty(p);
1299
1300                         /* Fall through... */
1301                 case SD_BUS_TYPE_OBJECT_PATH:
1302                         if (!p)
1303                                 return -EINVAL;
1304
1305                         align = 1;
1306                         sz = strlen(p) + 1;
1307                         break;
1308
1309                 case SD_BUS_TYPE_BOOLEAN:
1310
1311                         u8 = p && *(int*) p;
1312                         p = &u8;
1313
1314                         align = sz = 1;
1315                         break;
1316
1317                 case SD_BUS_TYPE_UNIX_FD:
1318
1319                         if (!p)
1320                                 return -EINVAL;
1321
1322                         fd = message_push_fd(m, *(int*) p);
1323                         if (fd < 0)
1324                                 return fd;
1325
1326                         u32 = m->n_fds;
1327                         p = &u32;
1328
1329                         align = sz = 4;
1330                         break;
1331
1332                 default:
1333                         align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
1334                         sz = bus_gvariant_get_size(CHAR_TO_STR(type));
1335                         break;
1336                 }
1337
1338                 assert(align > 0);
1339                 assert(sz > 0);
1340
1341                 a = message_extend_body(m, align, sz, true);
1342                 if (!a)
1343                         return -ENOMEM;
1344
1345                 memcpy(a, p, sz);
1346
1347                 if (stored)
1348                         *stored = (const uint8_t*) a;
1349
1350         } else {
1351                 uint32_t u32;
1352
1353                 switch (type) {
1354
1355                 case SD_BUS_TYPE_STRING:
1356                         /* To make things easy we'll serialize a NULL string
1357                          * into the empty string */
1358                         p = strempty(p);
1359
1360                         /* Fall through... */
1361                 case SD_BUS_TYPE_OBJECT_PATH:
1362
1363                         if (!p)
1364                                 return -EINVAL;
1365
1366                         align = 4;
1367                         sz = 4 + strlen(p) + 1;
1368                         break;
1369
1370                 case SD_BUS_TYPE_SIGNATURE:
1371
1372                         p = strempty(p);
1373
1374                         align = 1;
1375                         sz = 1 + strlen(p) + 1;
1376                         break;
1377
1378                 case SD_BUS_TYPE_BOOLEAN:
1379
1380                         u32 = p && *(int*) p;
1381                         p = &u32;
1382
1383                         align = sz = 4;
1384                         break;
1385
1386                 case SD_BUS_TYPE_UNIX_FD:
1387
1388                         if (!p)
1389                                 return -EINVAL;
1390
1391                         fd = message_push_fd(m, *(int*) p);
1392                         if (fd < 0)
1393                                 return fd;
1394
1395                         u32 = m->n_fds;
1396                         p = &u32;
1397
1398                         align = sz = 4;
1399                         break;
1400
1401                 default:
1402                         align = bus_type_get_alignment(type);
1403                         sz = bus_type_get_size(type);
1404                         break;
1405                 }
1406
1407                 assert(align > 0);
1408                 assert(sz > 0);
1409
1410                 a = message_extend_body(m, align, sz, false);
1411                 if (!a)
1412                         return -ENOMEM;
1413
1414                 if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
1415                         *(uint32_t*) a = sz - 5;
1416                         memcpy((uint8_t*) a + 4, p, sz - 4);
1417
1418                         if (stored)
1419                                 *stored = (const uint8_t*) a + 4;
1420
1421                 } else if (type == SD_BUS_TYPE_SIGNATURE) {
1422                         *(uint8_t*) a = sz - 1;
1423                         memcpy((uint8_t*) a + 1, p, sz - 1);
1424
1425                         if (stored)
1426                                 *stored = (const uint8_t*) a + 1;
1427                 } else {
1428                         memcpy(a, p, sz);
1429
1430                         if (stored)
1431                                 *stored = a;
1432                 }
1433         }
1434
1435         if (type == SD_BUS_TYPE_UNIX_FD)
1436                 m->n_fds ++;
1437
1438         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1439                 c->index++;
1440
1441         fd = -1;
1442         return 0;
1443 }
1444
1445 _public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
1446         return message_append_basic(m, type, p, NULL);
1447 }
1448
1449 _public_ int sd_bus_message_append_string_space(
1450                 sd_bus_message *m,
1451                 size_t size,
1452                 char **s) {
1453
1454         struct bus_container *c;
1455         void *a;
1456
1457         assert_return(m, -EINVAL);
1458         assert_return(s, -EINVAL);
1459         assert_return(!m->sealed, -EPERM);
1460         assert_return(!m->poisoned, -ESTALE);
1461
1462         c = message_get_container(m);
1463
1464         if (c->signature && c->signature[c->index]) {
1465                 /* Container signature is already set */
1466
1467                 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1468                         return -ENXIO;
1469         } else {
1470                 char *e;
1471
1472                 /* Maybe we can append to the signature? But only if this is the top-level container*/
1473                 if (c->enclosing != 0)
1474                         return -ENXIO;
1475
1476                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
1477                 if (!e) {
1478                         m->poisoned = true;
1479                         return -ENOMEM;
1480                 }
1481         }
1482
1483         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1484                 a = message_extend_body(m, 1, size + 1, true);
1485                 if (!a)
1486                         return -ENOMEM;
1487
1488                 *s = a;
1489         } else {
1490                 a = message_extend_body(m, 4, 4 + size + 1, false);
1491                 if (!a)
1492                         return -ENOMEM;
1493
1494                 *(uint32_t*) a = size;
1495                 *s = (char*) a + 4;
1496         }
1497
1498         (*s)[size] = 0;
1499
1500         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1501                 c->index++;
1502
1503         return 0;
1504 }
1505
1506 _public_ int sd_bus_message_append_string_iovec(
1507                 sd_bus_message *m,
1508                 const struct iovec *iov,
1509                 unsigned n) {
1510
1511         size_t size;
1512         unsigned i;
1513         char *p;
1514         int r;
1515
1516         assert_return(m, -EINVAL);
1517         assert_return(!m->sealed, -EPERM);
1518         assert_return(iov || n == 0, -EINVAL);
1519         assert_return(!m->poisoned, -ESTALE);
1520
1521         size = IOVEC_TOTAL_SIZE(iov, n);
1522
1523         r = sd_bus_message_append_string_space(m, size, &p);
1524         if (r < 0)
1525                 return r;
1526
1527         for (i = 0; i < n; i++) {
1528
1529                 if (iov[i].iov_base)
1530                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
1531                 else
1532                         memset(p, ' ', iov[i].iov_len);
1533
1534                 p += iov[i].iov_len;
1535         }
1536
1537         return 0;
1538 }
1539
1540 static int bus_message_open_array(
1541                 sd_bus_message *m,
1542                 struct bus_container *c,
1543                 const char *contents,
1544                 uint32_t **array_size,
1545                 size_t *begin,
1546                 bool *need_offsets) {
1547
1548         unsigned nindex;
1549         int alignment, r;
1550
1551         assert(m);
1552         assert(c);
1553         assert(contents);
1554         assert(array_size);
1555         assert(begin);
1556         assert(need_offsets);
1557
1558         if (!signature_is_single(contents, true))
1559                 return -EINVAL;
1560
1561         if (c->signature && c->signature[c->index]) {
1562
1563                 /* Verify the existing signature */
1564
1565                 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
1566                         return -ENXIO;
1567
1568                 if (!startswith(c->signature + c->index + 1, contents))
1569                         return -ENXIO;
1570
1571                 nindex = c->index + 1 + strlen(contents);
1572         } else {
1573                 char *e;
1574
1575                 if (c->enclosing != 0)
1576                         return -ENXIO;
1577
1578                 /* Extend the existing signature */
1579
1580                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
1581                 if (!e) {
1582                         m->poisoned = true;
1583                         return -ENOMEM;
1584                 }
1585
1586                 nindex = e - c->signature;
1587         }
1588
1589         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1590                 alignment = bus_gvariant_get_alignment(contents);
1591                 if (alignment < 0)
1592                         return alignment;
1593
1594                 /* Add alignment padding and add to offset list */
1595                 if (!message_extend_body(m, alignment, 0, false))
1596                         return -ENOMEM;
1597
1598                 r = bus_gvariant_is_fixed_size(contents);
1599                 if (r < 0)
1600                         return r;
1601
1602                 *begin = m->header->body_size;
1603                 *need_offsets = r == 0;
1604         } else {
1605                 void *a, *op;
1606                 size_t os;
1607                 struct bus_body_part *o;
1608
1609                 alignment = bus_type_get_alignment(contents[0]);
1610                 if (alignment < 0)
1611                         return alignment;
1612
1613                 a = message_extend_body(m, 4, 4, false);
1614                 if (!a)
1615                         return -ENOMEM;
1616
1617                 o = m->body_end;
1618                 op = m->body_end->data;
1619                 os = m->body_end->size;
1620
1621                 /* Add alignment between size and first element */
1622                 if (!message_extend_body(m, alignment, 0, false))
1623                         return -ENOMEM;
1624
1625                 /* location of array size might have changed so let's readjust a */
1626                 if (o == m->body_end)
1627                         a = adjust_pointer(a, op, os, m->body_end->data);
1628
1629                 *(uint32_t*) a = 0;
1630                 *array_size = a;
1631         }
1632
1633         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1634                 c->index = nindex;
1635
1636         return 0;
1637 }
1638
1639 static int bus_message_open_variant(
1640                 sd_bus_message *m,
1641                 struct bus_container *c,
1642                 const char *contents) {
1643
1644         assert(m);
1645         assert(c);
1646         assert(contents);
1647
1648         if (!signature_is_single(contents, false))
1649                 return -EINVAL;
1650
1651         if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1652                 return -EINVAL;
1653
1654         if (c->signature && c->signature[c->index]) {
1655
1656                 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
1657                         return -ENXIO;
1658
1659         } else {
1660                 char *e;
1661
1662                 if (c->enclosing != 0)
1663                         return -ENXIO;
1664
1665                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
1666                 if (!e) {
1667                         m->poisoned = true;
1668                         return -ENOMEM;
1669                 }
1670         }
1671
1672         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1673                 /* Variants are always aligned to 8 */
1674
1675                 if (!message_extend_body(m, 8, 0, false))
1676                         return -ENOMEM;
1677
1678         } else {
1679                 size_t l;
1680                 void *a;
1681
1682                 l = strlen(contents);
1683                 a = message_extend_body(m, 1, 1 + l + 1, false);
1684                 if (!a)
1685                         return -ENOMEM;
1686
1687                 *(uint8_t*) a = l;
1688                 memcpy((uint8_t*) a + 1, contents, l + 1);
1689         }
1690
1691         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1692                 c->index++;
1693
1694         return 0;
1695 }
1696
1697 static int bus_message_open_struct(
1698                 sd_bus_message *m,
1699                 struct bus_container *c,
1700                 const char *contents,
1701                 size_t *begin,
1702                 bool *need_offsets) {
1703
1704         size_t nindex;
1705         int r;
1706
1707         assert(m);
1708         assert(c);
1709         assert(contents);
1710         assert(begin);
1711         assert(need_offsets);
1712
1713         if (!signature_is_valid(contents, false))
1714                 return -EINVAL;
1715
1716         if (c->signature && c->signature[c->index]) {
1717                 size_t l;
1718
1719                 l = strlen(contents);
1720
1721                 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1722                     !startswith(c->signature + c->index + 1, contents) ||
1723                     c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
1724                         return -ENXIO;
1725
1726                 nindex = c->index + 1 + l + 1;
1727         } else {
1728                 char *e;
1729
1730                 if (c->enclosing != 0)
1731                         return -ENXIO;
1732
1733                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
1734                 if (!e) {
1735                         m->poisoned = true;
1736                         return -ENOMEM;
1737                 }
1738
1739                 nindex = e - c->signature;
1740         }
1741
1742         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1743                 int alignment;
1744
1745                 alignment = bus_gvariant_get_alignment(contents);
1746                 if (alignment < 0)
1747                         return alignment;
1748
1749                 if (!message_extend_body(m, alignment, 0, false))
1750                         return -ENOMEM;
1751
1752                 r = bus_gvariant_is_fixed_size(contents);
1753                 if (r < 0)
1754                         return r;
1755
1756                 *begin = m->header->body_size;
1757                 *need_offsets = r == 0;
1758         } else {
1759                 /* Align contents to 8 byte boundary */
1760                 if (!message_extend_body(m, 8, 0, false))
1761                         return -ENOMEM;
1762         }
1763
1764         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1765                 c->index = nindex;
1766
1767         return 0;
1768 }
1769
1770 static int bus_message_open_dict_entry(
1771                 sd_bus_message *m,
1772                 struct bus_container *c,
1773                 const char *contents,
1774                 size_t *begin,
1775                 bool *need_offsets) {
1776
1777         int r;
1778
1779         assert(m);
1780         assert(c);
1781         assert(contents);
1782         assert(begin);
1783         assert(need_offsets);
1784
1785         if (!signature_is_pair(contents))
1786                 return -EINVAL;
1787
1788         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1789                 return -ENXIO;
1790
1791         if (c->signature && c->signature[c->index]) {
1792                 size_t l;
1793
1794                 l = strlen(contents);
1795
1796                 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
1797                     !startswith(c->signature + c->index + 1, contents) ||
1798                     c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
1799                         return -ENXIO;
1800         } else
1801                 return -ENXIO;
1802
1803         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1804                 int alignment;
1805
1806                 alignment = bus_gvariant_get_alignment(contents);
1807                 if (alignment < 0)
1808                         return alignment;
1809
1810                 if (!message_extend_body(m, alignment, 0, false))
1811                         return -ENOMEM;
1812
1813                 r = bus_gvariant_is_fixed_size(contents);
1814                 if (r < 0)
1815                         return r;
1816
1817                 *begin = m->header->body_size;
1818                 *need_offsets = r == 0;
1819         } else {
1820                 /* Align contents to 8 byte boundary */
1821                 if (!message_extend_body(m, 8, 0, false))
1822                         return -ENOMEM;
1823         }
1824
1825         return 0;
1826 }
1827
1828 _public_ int sd_bus_message_open_container(
1829                 sd_bus_message *m,
1830                 char type,
1831                 const char *contents) {
1832
1833         struct bus_container *c, *w;
1834         uint32_t *array_size = NULL;
1835         char *signature;
1836         size_t before, begin;
1837         bool need_offsets = false;
1838         int r;
1839
1840         assert_return(m, -EINVAL);
1841         assert_return(!m->sealed, -EPERM);
1842         assert_return(contents, -EINVAL);
1843         assert_return(!m->poisoned, -ESTALE);
1844
1845         /* Make sure we have space for one more container */
1846         w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
1847         if (!w) {
1848                 m->poisoned = true;
1849                 return -ENOMEM;
1850         }
1851
1852         m->containers = w;
1853
1854         c = message_get_container(m);
1855
1856         signature = strdup(contents);
1857         if (!signature) {
1858                 m->poisoned = true;
1859                 return -ENOMEM;
1860         }
1861
1862         /* Save old index in the parent container, in case we have to
1863          * abort this container */
1864         c->saved_index = c->index;
1865         before = m->header->body_size;
1866
1867         if (type == SD_BUS_TYPE_ARRAY)
1868                 r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
1869         else if (type == SD_BUS_TYPE_VARIANT)
1870                 r = bus_message_open_variant(m, c, contents);
1871         else if (type == SD_BUS_TYPE_STRUCT)
1872                 r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
1873         else if (type == SD_BUS_TYPE_DICT_ENTRY)
1874                 r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
1875         else
1876                 r = -EINVAL;
1877
1878         if (r < 0) {
1879                 free(signature);
1880                 return r;
1881         }
1882
1883         /* OK, let's fill it in */
1884         w += m->n_containers++;
1885         w->enclosing = type;
1886         w->signature = signature;
1887         w->index = 0;
1888         w->array_size = array_size;
1889         w->before = before;
1890         w->begin = begin;
1891         w->n_offsets = w->n_offsets_allocated = 0;
1892         w->offsets = NULL;
1893         w->need_offsets = need_offsets;
1894
1895         return 0;
1896 }
1897
1898 static size_t determine_word_size(size_t sz, size_t extra) {
1899         if (sz + extra <= 0xFF)
1900                 return 1;
1901         else if (sz + extra*2 <= 0xFFFF)
1902                 return 2;
1903         else if (sz + extra*4 <= 0xFFFFFFFF)
1904                 return 4;
1905         else
1906                 return 8;
1907 }
1908
1909 static size_t read_word_le(void *p, size_t sz) {
1910         union {
1911                 uint16_t u16;
1912                 uint32_t u32;
1913                 uint64_t u64;
1914         } x;
1915
1916         assert(p);
1917
1918         if (sz == 1)
1919                 return *(uint8_t*) p;
1920
1921         memcpy(&x, p, sz);
1922
1923         if (sz == 2)
1924                 return le16toh(x.u16);
1925         else if (sz == 4)
1926                 return le32toh(x.u32);
1927         else if (sz == 4)
1928                 return le64toh(x.u64);
1929
1930         assert_not_reached("unknown word width");
1931 }
1932
1933 static void write_word_le(void *p, size_t sz, size_t value) {
1934         union {
1935                 uint16_t u16;
1936                 uint32_t u32;
1937                 uint64_t u64;
1938         } x;
1939
1940         assert(p);
1941         assert(sz == 8 || (value < (1ULL << (sz*8))));
1942
1943         if (sz == 1) {
1944                 *(uint8_t*) p = value;
1945                 return;
1946         } else if (sz == 2)
1947                 x.u16 = htole16((uint16_t) value);
1948         else if (sz == 4)
1949                 x.u32 = htole32((uint32_t) value);
1950         else if (sz == 8)
1951                 x.u64 = htole64((uint64_t) value);
1952         else
1953                 assert_not_reached("unknown word width");
1954
1955         memcpy(p, &x, sz);
1956 }
1957
1958 static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
1959
1960         assert(m);
1961         assert(c);
1962
1963         if (!BUS_MESSAGE_IS_GVARIANT(m))
1964                 return 0;
1965
1966         if (c->need_offsets) {
1967                 size_t payload, sz, i;
1968                 uint8_t *a;
1969
1970                 /* Variable-width arrays */
1971
1972                 payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
1973                 sz = determine_word_size(payload, c->n_offsets);
1974
1975                 a = message_extend_body(m, 1, sz * c->n_offsets, true);
1976                 if (!a)
1977                         return -ENOMEM;
1978
1979                 for (i = 0; i < c->n_offsets; i++)
1980                         write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
1981         } else {
1982                 void *a;
1983
1984                 /* Fixed-width or empty arrays */
1985
1986                 a = message_extend_body(m, 1, 0, true); /* let's add offset to parent */
1987                 if (!a)
1988                         return -ENOMEM;
1989         }
1990
1991         return 0;
1992 }
1993
1994 static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
1995         uint8_t *a;
1996         size_t l;
1997
1998         assert(m);
1999         assert(c);
2000
2001         if (!BUS_MESSAGE_IS_GVARIANT(m))
2002                 return 0;
2003
2004         l = strlen(c->signature);
2005
2006         a = message_extend_body(m, 1, 1 + l, true);
2007         if (!a)
2008                 return -ENOMEM;
2009
2010         a[0] = 0;
2011         memcpy(a+1, c->signature, l);
2012
2013         return 0;
2014 }
2015
2016 static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
2017         size_t n_variable = 0;
2018         unsigned i = 0;
2019         const char *p;
2020         uint8_t *a;
2021         int r;
2022
2023         assert(m);
2024         assert(c);
2025
2026         if (!BUS_MESSAGE_IS_GVARIANT(m))
2027                 return 0;
2028
2029         p = strempty(c->signature);
2030         while (*p != 0) {
2031                 size_t n;
2032
2033                 r = signature_element_length(p, &n);
2034                 if (r < 0)
2035                         return r;
2036                 else {
2037                         char t[n+1];
2038
2039                         memcpy(t, p, n);
2040                         t[n] = 0;
2041
2042                         r = bus_gvariant_is_fixed_size(t);
2043                         if (r < 0)
2044                                 return r;
2045                 }
2046
2047                 assert(i <= c->n_offsets);
2048
2049                 /* We need to add an offset for each item that has a
2050                  * variable size and that is not the last one in the
2051                  * list */
2052                 if (r == 0 && p[n] != 0)
2053                         n_variable++;
2054
2055                 i++;
2056                 p += n;
2057         }
2058
2059         assert(i == c->n_offsets);
2060
2061         if (n_variable <= 0) {
2062                 a = message_extend_body(m, 1, 0, add_offset);
2063                 if (!a)
2064                         return -ENOMEM;
2065         } else {
2066                 size_t sz;
2067                 unsigned j;
2068
2069                 assert(c->offsets[c->n_offsets-1] == m->header->body_size);
2070
2071                 sz = determine_word_size(m->header->body_size - c->begin, n_variable);
2072
2073                 a = message_extend_body(m, 1, sz * n_variable, add_offset);
2074                 if (!a)
2075                         return -ENOMEM;
2076
2077                 p = strempty(c->signature);
2078                 for (i = 0, j = 0; i < c->n_offsets; i++) {
2079                         unsigned k;
2080                         size_t n;
2081
2082                         r = signature_element_length(p, &n);
2083                         if (r < 0)
2084                                 return r;
2085                         else {
2086                                 char t[n+1];
2087
2088                                 memcpy(t, p, n);
2089                                 t[n] = 0;
2090
2091                                 p += n;
2092
2093                                 r = bus_gvariant_is_fixed_size(t);
2094                                 if (r < 0)
2095                                         return r;
2096                                 if (r > 0 || p[0] == 0)
2097                                         continue;
2098                         }
2099
2100                         k = n_variable - 1 - j;
2101
2102                         write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
2103
2104                         j++;
2105                 }
2106         }
2107
2108         return 0;
2109 }
2110
2111 _public_ int sd_bus_message_close_container(sd_bus_message *m) {
2112         struct bus_container *c;
2113         int r;
2114
2115         assert_return(m, -EINVAL);
2116         assert_return(!m->sealed, -EPERM);
2117         assert_return(m->n_containers > 0, -EINVAL);
2118         assert_return(!m->poisoned, -ESTALE);
2119
2120         c = message_get_container(m);
2121
2122         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2123                 if (c->signature && c->signature[c->index] != 0)
2124                         return -EINVAL;
2125
2126         m->n_containers--;
2127
2128         if (c->enclosing == SD_BUS_TYPE_ARRAY)
2129                 r = bus_message_close_array(m, c);
2130         else if (c->enclosing == SD_BUS_TYPE_VARIANT)
2131                 r = bus_message_close_variant(m, c);
2132         else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
2133                 r = bus_message_close_struct(m, c, true);
2134         else
2135                 assert_not_reached("Unknown container type");
2136
2137         free(c->signature);
2138         free(c->offsets);
2139
2140         return r;
2141 }
2142
2143 typedef struct {
2144         const char *types;
2145         unsigned n_struct;
2146         unsigned n_array;
2147 } TypeStack;
2148
2149 static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
2150         assert(stack);
2151         assert(max > 0);
2152
2153         if (*i >= max)
2154                 return -EINVAL;
2155
2156         stack[*i].types = types;
2157         stack[*i].n_struct = n_struct;
2158         stack[*i].n_array = n_array;
2159         (*i)++;
2160
2161         return 0;
2162 }
2163
2164 static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
2165         assert(stack);
2166         assert(max > 0);
2167         assert(types);
2168         assert(n_struct);
2169         assert(n_array);
2170
2171         if (*i <= 0)
2172                 return 0;
2173
2174         (*i)--;
2175         *types = stack[*i].types;
2176         *n_struct = stack[*i].n_struct;
2177         *n_array = stack[*i].n_array;
2178
2179         return 1;
2180 }
2181
2182 int bus_message_append_ap(
2183                 sd_bus_message *m,
2184                 const char *types,
2185                 va_list ap) {
2186
2187         unsigned n_array, n_struct;
2188         TypeStack stack[BUS_CONTAINER_DEPTH];
2189         unsigned stack_ptr = 0;
2190         int r;
2191
2192         assert(m);
2193
2194         if (!types)
2195                 return 0;
2196
2197         n_array = (unsigned) -1;
2198         n_struct = strlen(types);
2199
2200         for (;;) {
2201                 const char *t;
2202
2203                 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
2204                         r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
2205                         if (r < 0)
2206                                 return r;
2207                         if (r == 0)
2208                                 break;
2209
2210                         r = sd_bus_message_close_container(m);
2211                         if (r < 0)
2212                                 return r;
2213
2214                         continue;
2215                 }
2216
2217                 t = types;
2218                 if (n_array != (unsigned) -1)
2219                         n_array --;
2220                 else {
2221                         types ++;
2222                         n_struct--;
2223                 }
2224
2225                 switch (*t) {
2226
2227                 case SD_BUS_TYPE_BYTE: {
2228                         uint8_t x;
2229
2230                         x = (uint8_t) va_arg(ap, int);
2231                         r = sd_bus_message_append_basic(m, *t, &x);
2232                         break;
2233                 }
2234
2235                 case SD_BUS_TYPE_BOOLEAN:
2236                 case SD_BUS_TYPE_INT32:
2237                 case SD_BUS_TYPE_UINT32:
2238                 case SD_BUS_TYPE_UNIX_FD: {
2239                         uint32_t x;
2240
2241                         /* We assume a boolean is the same as int32_t */
2242                         assert_cc(sizeof(int32_t) == sizeof(int));
2243
2244                         x = va_arg(ap, uint32_t);
2245                         r = sd_bus_message_append_basic(m, *t, &x);
2246                         break;
2247                 }
2248
2249                 case SD_BUS_TYPE_INT16:
2250                 case SD_BUS_TYPE_UINT16: {
2251                         uint16_t x;
2252
2253                         x = (uint16_t) va_arg(ap, int);
2254                         r = sd_bus_message_append_basic(m, *t, &x);
2255                         break;
2256                 }
2257
2258                 case SD_BUS_TYPE_INT64:
2259                 case SD_BUS_TYPE_UINT64:
2260                 case SD_BUS_TYPE_DOUBLE: {
2261                         uint64_t x;
2262
2263                         x = va_arg(ap, uint64_t);
2264                         r = sd_bus_message_append_basic(m, *t, &x);
2265                         break;
2266                 }
2267
2268                 case SD_BUS_TYPE_STRING:
2269                 case SD_BUS_TYPE_OBJECT_PATH:
2270                 case SD_BUS_TYPE_SIGNATURE: {
2271                         const char *x;
2272
2273                         x = va_arg(ap, const char*);
2274                         r = sd_bus_message_append_basic(m, *t, x);
2275                         break;
2276                 }
2277
2278                 case SD_BUS_TYPE_ARRAY: {
2279                         size_t k;
2280
2281                         r = signature_element_length(t + 1, &k);
2282                         if (r < 0)
2283                                 return r;
2284
2285                         {
2286                                 char s[k + 1];
2287                                 memcpy(s, t + 1, k);
2288                                 s[k] = 0;
2289
2290                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
2291                                 if (r < 0)
2292                                         return r;
2293                         }
2294
2295                         if (n_array == (unsigned) -1) {
2296                                 types += k;
2297                                 n_struct -= k;
2298                         }
2299
2300                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2301                         if (r < 0)
2302                                 return r;
2303
2304                         types = t + 1;
2305                         n_struct = k;
2306                         n_array = va_arg(ap, unsigned);
2307
2308                         break;
2309                 }
2310
2311                 case SD_BUS_TYPE_VARIANT: {
2312                         const char *s;
2313
2314                         s = va_arg(ap, const char*);
2315                         if (!s)
2316                                 return -EINVAL;
2317
2318                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
2319                         if (r < 0)
2320                                 return r;
2321
2322                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2323                         if (r < 0)
2324                                 return r;
2325
2326                         types = s;
2327                         n_struct = strlen(s);
2328                         n_array = (unsigned) -1;
2329
2330                         break;
2331                 }
2332
2333                 case SD_BUS_TYPE_STRUCT_BEGIN:
2334                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
2335                         size_t k;
2336
2337                         r = signature_element_length(t, &k);
2338                         if (r < 0)
2339                                 return r;
2340
2341                         {
2342                                 char s[k - 1];
2343
2344                                 memcpy(s, t + 1, k - 2);
2345                                 s[k - 2] = 0;
2346
2347                                 r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
2348                                 if (r < 0)
2349                                         return r;
2350                         }
2351
2352                         if (n_array == (unsigned) -1) {
2353                                 types += k - 1;
2354                                 n_struct -= k - 1;
2355                         }
2356
2357                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2358                         if (r < 0)
2359                                 return r;
2360
2361                         types = t + 1;
2362                         n_struct = k - 2;
2363                         n_array = (unsigned) -1;
2364
2365                         break;
2366                 }
2367
2368                 default:
2369                         r = -EINVAL;
2370                 }
2371
2372                 if (r < 0)
2373                         return r;
2374         }
2375
2376         return 1;
2377 }
2378
2379 _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
2380         va_list ap;
2381         int r;
2382
2383         assert_return(m, -EINVAL);
2384         assert_return(types, -EINVAL);
2385         assert_return(!m->sealed, -EPERM);
2386         assert_return(!m->poisoned, -ESTALE);
2387
2388         va_start(ap, types);
2389         r = bus_message_append_ap(m, types, ap);
2390         va_end(ap);
2391
2392         return r;
2393 }
2394
2395 _public_ int sd_bus_message_append_array_space(
2396                 sd_bus_message *m,
2397                 char type,
2398                 size_t size,
2399                 void **ptr) {
2400
2401         ssize_t align, sz;
2402         void *a;
2403         int r;
2404
2405         assert_return(m, -EINVAL);
2406         assert_return(!m->sealed, -EPERM);
2407         assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
2408         assert_return(ptr || size == 0, -EINVAL);
2409         assert_return(!m->poisoned, -ESTALE);
2410
2411         /* alignment and size of the trivial types (except bool) is
2412          * identical for gvariant and dbus1 marshalling */
2413         align = bus_type_get_alignment(type);
2414         sz = bus_type_get_size(type);
2415
2416         assert_se(align > 0);
2417         assert_se(sz > 0);
2418
2419         if (size % sz != 0)
2420                 return -EINVAL;
2421
2422         r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2423         if (r < 0)
2424                 return r;
2425
2426         a = message_extend_body(m, align, size, false);
2427         if (!a)
2428                 return -ENOMEM;
2429
2430         r = sd_bus_message_close_container(m);
2431         if (r < 0)
2432                 return r;
2433
2434         *ptr = a;
2435         return 0;
2436 }
2437
2438 _public_ int sd_bus_message_append_array(sd_bus_message *m,
2439                                          char type,
2440                                          const void *ptr,
2441                                          size_t size) {
2442         int r;
2443         void *p;
2444
2445         assert_return(m, -EINVAL);
2446         assert_return(!m->sealed, -EPERM);
2447         assert_return(bus_type_is_trivial(type), -EINVAL);
2448         assert_return(ptr || size == 0, -EINVAL);
2449         assert_return(!m->poisoned, -ESTALE);
2450
2451         r = sd_bus_message_append_array_space(m, type, size, &p);
2452         if (r < 0)
2453                 return r;
2454
2455         if (size > 0)
2456                 memcpy(p, ptr, size);
2457
2458         return 0;
2459 }
2460
2461 _public_ int sd_bus_message_append_array_iovec(
2462                 sd_bus_message *m,
2463                 char type,
2464                 const struct iovec *iov,
2465                 unsigned n) {
2466
2467         size_t size;
2468         unsigned i;
2469         void *p;
2470         int r;
2471
2472         assert_return(m, -EINVAL);
2473         assert_return(!m->sealed, -EPERM);
2474         assert_return(bus_type_is_trivial(type), -EINVAL);
2475         assert_return(iov || n == 0, -EINVAL);
2476         assert_return(!m->poisoned, -ESTALE);
2477
2478         size = IOVEC_TOTAL_SIZE(iov, n);
2479
2480         r = sd_bus_message_append_array_space(m, type, size, &p);
2481         if (r < 0)
2482                 return r;
2483
2484         for (i = 0; i < n; i++) {
2485
2486                 if (iov[i].iov_base)
2487                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
2488                 else
2489                         memset(p, 0, iov[i].iov_len);
2490
2491                 p = (uint8_t*) p + iov[i].iov_len;
2492         }
2493
2494         return 0;
2495 }
2496
2497 _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
2498                                                char type,
2499                                                sd_memfd *memfd) {
2500         _cleanup_close_ int copy_fd = -1;
2501         struct bus_body_part *part;
2502         ssize_t align, sz;
2503         uint64_t size;
2504         void *a;
2505         int r;
2506
2507         if (!m)
2508                 return -EINVAL;
2509         if (!memfd)
2510                 return -EINVAL;
2511         if (m->sealed)
2512                 return -EPERM;
2513         if (!bus_type_is_trivial(type))
2514                 return -EINVAL;
2515         if (m->poisoned)
2516                 return -ESTALE;
2517
2518         r = sd_memfd_set_sealed(memfd, true);
2519         if (r < 0)
2520                 return r;
2521
2522         copy_fd = sd_memfd_dup_fd(memfd);
2523         if (copy_fd < 0)
2524                 return copy_fd;
2525
2526         r = sd_memfd_get_size(memfd, &size);
2527         if (r < 0)
2528                 return r;
2529
2530         align = bus_type_get_alignment(type);
2531         sz = bus_type_get_size(type);
2532
2533         assert_se(align > 0);
2534         assert_se(sz > 0);
2535
2536         if (size % sz != 0)
2537                 return -EINVAL;
2538
2539         if (size > (uint64_t) (uint32_t) -1)
2540                 return -EINVAL;
2541
2542         r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2543         if (r < 0)
2544                 return r;
2545
2546         a = message_extend_body(m, align, 0, false);
2547         if (!a)
2548                 return -ENOMEM;
2549
2550         part = message_append_part(m);
2551         if (!part)
2552                 return -ENOMEM;
2553
2554         part->memfd = copy_fd;
2555         part->sealed = true;
2556         part->size = size;
2557         copy_fd = -1;
2558
2559         m->header->body_size += size;
2560         message_extend_containers(m, size);
2561
2562         return sd_bus_message_close_container(m);
2563 }
2564
2565 _public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
2566         _cleanup_close_ int copy_fd = -1;
2567         struct bus_body_part *part;
2568         struct bus_container *c;
2569         uint64_t size;
2570         void *a;
2571         int r;
2572
2573         assert_return(m, -EINVAL);
2574         assert_return(memfd, -EINVAL);
2575         assert_return(!m->sealed, -EPERM);
2576         assert_return(!m->poisoned, -ESTALE);
2577
2578         r = sd_memfd_set_sealed(memfd, true);
2579         if (r < 0)
2580                 return r;
2581
2582         copy_fd = sd_memfd_dup_fd(memfd);
2583         if (copy_fd < 0)
2584                 return copy_fd;
2585
2586         r = sd_memfd_get_size(memfd, &size);
2587         if (r < 0)
2588                 return r;
2589
2590         /* We require this to be NUL terminated */
2591         if (size == 0)
2592                 return -EINVAL;
2593
2594         if (size > (uint64_t) (uint32_t) -1)
2595                 return -EINVAL;
2596
2597         c = message_get_container(m);
2598         if (c->signature && c->signature[c->index]) {
2599                 /* Container signature is already set */
2600
2601                 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2602                         return -ENXIO;
2603         } else {
2604                 char *e;
2605
2606                 /* Maybe we can append to the signature? But only if this is the top-level container*/
2607                 if (c->enclosing != 0)
2608                         return -ENXIO;
2609
2610                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2611                 if (!e) {
2612                         m->poisoned = true;
2613                         return -ENOMEM;
2614                 }
2615         }
2616
2617         if (!BUS_MESSAGE_IS_GVARIANT(m)) {
2618                 a = message_extend_body(m, 4, 4, false);
2619                 if (!a)
2620                         return -ENOMEM;
2621
2622                 *(uint32_t*) a = size - 1;
2623         }
2624
2625         part = message_append_part(m);
2626         if (!part)
2627                 return -ENOMEM;
2628
2629         part->memfd = copy_fd;
2630         part->sealed = true;
2631         part->size = size;
2632         copy_fd = -1;
2633
2634         m->header->body_size += size;
2635         message_extend_containers(m, size);
2636
2637         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2638                 r = message_add_offset(m, m->header->body_size);
2639                 if (r < 0) {
2640                         m->poisoned = true;
2641                         return -ENOMEM;
2642                 }
2643         }
2644
2645         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2646                 c->index++;
2647
2648         return 0;
2649 }
2650
2651 _public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
2652         char **i;
2653         int r;
2654
2655         assert_return(m, -EINVAL);
2656         assert_return(!m->sealed, -EPERM);
2657         assert_return(!m->poisoned, -ESTALE);
2658
2659         r = sd_bus_message_open_container(m, 'a', "s");
2660         if (r < 0)
2661                 return r;
2662
2663         STRV_FOREACH(i, l) {
2664                 r = sd_bus_message_append_basic(m, 's', *i);
2665                 if (r < 0)
2666                         return r;
2667         }
2668
2669         return sd_bus_message_close_container(m);
2670 }
2671
2672 static int bus_message_close_header(sd_bus_message *m) {
2673         uint8_t *a;
2674         size_t sz, i;
2675
2676         assert(m);
2677
2678         if (!BUS_MESSAGE_IS_GVARIANT(m))
2679                 return 0;
2680
2681         if (m->n_header_offsets < 1)
2682                 return 0;
2683
2684         assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
2685
2686         sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
2687
2688         a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2689         if (!a)
2690                 return -ENOMEM;
2691
2692         for (i = 0; i < m->n_header_offsets; i++)
2693                 write_word_le(a + sz*i, sz, m->header_offsets[i]);
2694
2695         return 0;
2696 }
2697
2698 int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout) {
2699         struct bus_body_part *part;
2700         size_t l, a;
2701         unsigned i;
2702         int r;
2703
2704         assert(m);
2705
2706         if (m->sealed)
2707                 return -EPERM;
2708
2709         if (m->n_containers > 0)
2710                 return -EBADMSG;
2711
2712         if (m->poisoned)
2713                 return -ESTALE;
2714
2715         /* In vtables the return signature of method calls is listed,
2716          * let's check if they match if this is a response */
2717         if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2718             m->enforced_reply_signature &&
2719             !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2720                 return -ENOMSG;
2721
2722         /* If gvariant marshalling is used we need to close the body structure */
2723         r = bus_message_close_struct(m, &m->root_container, false);
2724         if (r < 0)
2725                 return r;
2726
2727         /* If there's a non-trivial signature set, then add it in here */
2728         if (!isempty(m->root_container.signature)) {
2729                 r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2730                 if (r < 0)
2731                         return r;
2732         }
2733
2734         if (m->n_fds > 0) {
2735                 r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2736                 if (r < 0)
2737                         return r;
2738         }
2739
2740         r = bus_message_close_header(m);
2741         if (r < 0)
2742                 return r;
2743
2744         m->header->serial = serial;
2745         m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
2746
2747         /* Add padding at the end of the fields part, since we know
2748          * the body needs to start at an 8 byte alignment. We made
2749          * sure we allocated enough space for this, so all we need to
2750          * do here is to zero it out. */
2751         l = BUS_MESSAGE_FIELDS_SIZE(m);
2752         a = ALIGN8(l) - l;
2753         if (a > 0)
2754                 memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
2755
2756         /* If this is something we can send as memfd, then let's seal
2757         the memfd now. Note that we can send memfds as payload only
2758         for directed messages, and not for broadcasts. */
2759         if (m->destination && m->bus && m->bus->use_memfd) {
2760                 MESSAGE_FOREACH_PART(part, i, m)
2761                         if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
2762                                 bus_body_part_unmap(part);
2763
2764                                 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
2765                                         part->sealed = true;
2766                         }
2767         }
2768
2769         m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
2770         m->root_container.index = 0;
2771         m->root_container.offset_index = 0;
2772         m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
2773
2774         m->sealed = true;
2775
2776         return 0;
2777 }
2778
2779 int bus_body_part_map(struct bus_body_part *part) {
2780         void *p;
2781         size_t psz;
2782
2783         assert_se(part);
2784
2785         if (part->data)
2786                 return 0;
2787
2788         if (part->size <= 0)
2789                 return 0;
2790
2791         /* For smaller zero parts (as used for padding) we don't need to map anything... */
2792         if (part->memfd < 0 && part->is_zero && part->size < 8) {
2793                 static const uint8_t zeroes[7] = { };
2794                 part->data = (void*) zeroes;
2795                 return 0;
2796         }
2797
2798         psz = PAGE_ALIGN(part->size);
2799
2800         if (part->memfd >= 0)
2801                 p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
2802         else if (part->is_zero)
2803                 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
2804         else
2805                 return -EINVAL;
2806
2807         if (p == MAP_FAILED)
2808                 return -errno;
2809
2810         part->mapped = psz;
2811         part->data = p;
2812         part->munmap_this = true;
2813
2814         return 0;
2815 }
2816
2817 void bus_body_part_unmap(struct bus_body_part *part) {
2818
2819         assert_se(part);
2820
2821         if (part->memfd < 0)
2822                 return;
2823
2824         if (!part->data)
2825                 return;
2826
2827         if (!part->munmap_this)
2828                 return;
2829
2830         assert_se(munmap(part->data, part->mapped) == 0);
2831
2832         part->data = NULL;
2833         part->mapped = 0;
2834         part->munmap_this = false;
2835
2836         return;
2837 }
2838
2839 static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
2840         size_t k, start, end;
2841
2842         assert(rindex);
2843         assert(align > 0);
2844
2845         start = ALIGN_TO((size_t) *rindex, align);
2846         end = start + nbytes;
2847
2848         if (end > sz)
2849                 return -EBADMSG;
2850
2851         /* Verify that padding is 0 */
2852         for (k = *rindex; k < start; k++)
2853                 if (((const uint8_t*) p)[k] != 0)
2854                         return -EBADMSG;
2855
2856         if (r)
2857                 *r = (uint8_t*) p + start;
2858
2859         *rindex = end;
2860
2861         return 1;
2862 }
2863
2864 static bool message_end_of_signature(sd_bus_message *m) {
2865         struct bus_container *c;
2866
2867         assert(m);
2868
2869         c = message_get_container(m);
2870         return !c->signature || c->signature[c->index] == 0;
2871 }
2872
2873 static bool message_end_of_array(sd_bus_message *m, size_t index) {
2874         struct bus_container *c;
2875
2876         assert(m);
2877
2878         c = message_get_container(m);
2879         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2880                 return false;
2881
2882         if (BUS_MESSAGE_IS_GVARIANT(m))
2883                 return index >= c->end;
2884         else {
2885                 assert(c->array_size);
2886                 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
2887         }
2888 }
2889
2890 _public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
2891         assert_return(m, -EINVAL);
2892         assert_return(m->sealed, -EPERM);
2893
2894         if (complete && m->n_containers > 0)
2895                 return false;
2896
2897         if (message_end_of_signature(m))
2898                 return true;
2899
2900         if (message_end_of_array(m, m->rindex))
2901                 return true;
2902
2903         return false;
2904 }
2905
2906 static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
2907         struct bus_body_part *part;
2908         size_t begin;
2909         int r;
2910
2911         assert(m);
2912
2913         if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
2914                 part = m->cached_rindex_part;
2915                 begin = m->cached_rindex_part_begin;
2916         } else {
2917                 part = &m->body;
2918                 begin = 0;
2919         }
2920
2921         while (part) {
2922                 if (index < begin)
2923                         return NULL;
2924
2925                 if (index + sz <= begin + part->size) {
2926
2927                         r = bus_body_part_map(part);
2928                         if (r < 0)
2929                                 return NULL;
2930
2931                         if (p)
2932                                 *p = (uint8_t*) part->data + index - begin;
2933
2934                         m->cached_rindex_part = part;
2935                         m->cached_rindex_part_begin = begin;
2936
2937                         return part;
2938                 }
2939
2940                 begin += part->size;
2941                 part = part->next;
2942         }
2943
2944         return NULL;
2945 }
2946
2947 static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
2948         int r;
2949
2950         assert(m);
2951         assert(c);
2952         assert(rindex);
2953
2954         if (!BUS_MESSAGE_IS_GVARIANT(m))
2955                 return 0;
2956
2957         if (c->enclosing == SD_BUS_TYPE_ARRAY) {
2958                 int sz;
2959
2960                 sz = bus_gvariant_get_size(c->signature);
2961                 if (sz < 0) {
2962                         int alignment;
2963
2964                         if (c->offset_index+1 >= c->n_offsets)
2965                                 goto end;
2966
2967                         /* Variable-size array */
2968
2969                         alignment = bus_gvariant_get_alignment(c->signature);
2970                         assert(alignment > 0);
2971
2972                         *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
2973                         c->item_size = c->offsets[c->offset_index+1] - *rindex;
2974                 } else {
2975
2976                         if (c->offset_index+1 >= (c->end-c->begin)/sz)
2977                                 goto end;
2978
2979                         /* Fixed-size array */
2980                         *rindex = c->begin + (c->offset_index+1) * sz;
2981                         c->item_size = sz;
2982                 }
2983
2984                 c->offset_index++;
2985
2986         } else if (c->enclosing == 0 ||
2987                    c->enclosing == SD_BUS_TYPE_STRUCT ||
2988                    c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
2989
2990                 int alignment;
2991                 size_t n, j;
2992
2993                 if (c->offset_index+1 >= c->n_offsets)
2994                         goto end;
2995
2996                 r = signature_element_length(c->signature + c->index, &n);
2997                 if (r < 0)
2998                         return r;
2999
3000                 r = signature_element_length(c->signature + c->index + n, &j);
3001                 if (r < 0)
3002                         return r;
3003                 else {
3004                         char t[j+1];
3005                         memcpy(t, c->signature + c->index + n, j);
3006                         t[j] = 0;
3007
3008                         alignment = bus_gvariant_get_alignment(t);
3009                 }
3010
3011                 assert(alignment > 0);
3012
3013                 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3014                 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3015
3016                 c->offset_index++;
3017
3018         } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3019                 goto end;
3020         else
3021                 assert_not_reached("Unknown container type");
3022
3023         return 0;
3024
3025 end:
3026         /* Reached the end */
3027         *rindex = c->end;
3028         c->item_size = 0;
3029         return 0;
3030 }
3031
3032
3033 static int message_peek_body(
3034                 sd_bus_message *m,
3035                 size_t *rindex,
3036                 size_t align,
3037                 size_t nbytes,
3038                 void **ret) {
3039
3040         size_t k, start, end, padding;
3041         struct bus_body_part *part;
3042         uint8_t *q;
3043
3044         assert(m);
3045         assert(rindex);
3046         assert(align > 0);
3047
3048         start = ALIGN_TO((size_t) *rindex, align);
3049         padding = start - *rindex;
3050         end = start + nbytes;
3051
3052         if (end > BUS_MESSAGE_BODY_SIZE(m))
3053                 return -EBADMSG;
3054
3055         part = find_part(m, *rindex, padding, (void**) &q);
3056         if (!part)
3057                 return -EBADMSG;
3058
3059         if (q) {
3060                 /* Verify padding */
3061                 for (k = 0; k < padding; k++)
3062                         if (q[k] != 0)
3063                                 return -EBADMSG;
3064         }
3065
3066         part = find_part(m, start, nbytes, (void**) &q);
3067         if (!part || (nbytes > 0 && !q))
3068                 return -EBADMSG;
3069
3070         *rindex = end;
3071
3072         if (ret)
3073                 *ret = q;
3074
3075         return 0;
3076 }
3077
3078 static bool validate_nul(const char *s, size_t l) {
3079
3080         /* Check for NUL chars in the string */
3081         if (memchr(s, 0, l))
3082                 return false;
3083
3084         /* Check for NUL termination */
3085         if (s[l] != 0)
3086                 return false;
3087
3088         return true;
3089 }
3090
3091 static bool validate_string(const char *s, size_t l) {
3092
3093         if (!validate_nul(s, l))
3094                 return false;
3095
3096         /* Check if valid UTF8 */
3097         if (!utf8_is_valid(s))
3098                 return false;
3099
3100         return true;
3101 }
3102
3103 static bool validate_signature(const char *s, size_t l) {
3104
3105         if (!validate_nul(s, l))
3106                 return false;
3107
3108         /* Check if valid signature */
3109         if (!signature_is_valid(s, true))
3110                 return false;
3111
3112         return true;
3113 }
3114
3115 static bool validate_object_path(const char *s, size_t l) {
3116
3117         if (!validate_nul(s, l))
3118                 return false;
3119
3120         if (!object_path_is_valid(s))
3121                 return false;
3122
3123         return true;
3124 }
3125
3126 _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
3127         struct bus_container *c;
3128         size_t rindex;
3129         void *q;
3130         int r;
3131
3132         assert_return(m, -EINVAL);
3133         assert_return(m->sealed, -EPERM);
3134         assert_return(bus_type_is_basic(type), -EINVAL);
3135
3136         if (message_end_of_signature(m))
3137                 return -ENXIO;
3138
3139         if (message_end_of_array(m, m->rindex))
3140                 return 0;
3141
3142         c = message_get_container(m);
3143         if (c->signature[c->index] != type)
3144                 return -ENXIO;
3145
3146         rindex = m->rindex;
3147
3148         if (BUS_MESSAGE_IS_GVARIANT(m)) {
3149
3150                 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3151                         bool ok;
3152
3153                         r = message_peek_body(m, &rindex, 1, c->item_size, &q);
3154                         if (r < 0)
3155                                 return r;
3156
3157                         if (type == SD_BUS_TYPE_STRING)
3158                                 ok = validate_string(q, c->item_size-1);
3159                         else if (type == SD_BUS_TYPE_OBJECT_PATH)
3160                                 ok = validate_object_path(q, c->item_size-1);
3161                         else
3162                                 ok = validate_signature(q, c->item_size-1);
3163
3164                         if (!ok)
3165                                 return -EBADMSG;
3166
3167                         if (p)
3168                                 *(const char**) p = q;
3169                 } else {
3170                         int sz, align;
3171
3172                         sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3173                         assert(sz > 0);
3174                         if ((size_t) sz != c->item_size)
3175                                 return -EBADMSG;
3176
3177                         align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3178                         assert(align > 0);
3179
3180                         r = message_peek_body(m, &rindex, align, c->item_size, &q);
3181                         if (r < 0)
3182                                 return r;
3183
3184                         switch (type) {
3185
3186                         case SD_BUS_TYPE_BYTE:
3187                                 if (p)
3188                                         *(uint8_t*) p = *(uint8_t*) q;
3189                                 break;
3190
3191                         case SD_BUS_TYPE_BOOLEAN:
3192                                 if (p)
3193                                         *(int*) p = !!*(uint8_t*) q;
3194                                 break;
3195
3196                         case SD_BUS_TYPE_INT16:
3197                         case SD_BUS_TYPE_UINT16:
3198                                 if (p)
3199                                         *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3200                                 break;
3201
3202                         case SD_BUS_TYPE_INT32:
3203                         case SD_BUS_TYPE_UINT32:
3204                                 if (p)
3205                                         *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3206                                 break;
3207
3208                         case SD_BUS_TYPE_INT64:
3209                         case SD_BUS_TYPE_UINT64:
3210                         case SD_BUS_TYPE_DOUBLE:
3211                                 if (p)
3212                                         *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3213                                 break;
3214
3215                         case SD_BUS_TYPE_UNIX_FD: {
3216                                 uint32_t j;
3217
3218                                 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3219                                 if (j >= m->n_fds)
3220                                         return -EBADMSG;
3221
3222                                 if (p)
3223                                         *(int*) p = m->fds[j];
3224
3225                                 break;
3226                         }
3227