#include "bus-type.h"
#include "bus-signature.h"
#include "bus-gvariant.h"
+#include "bus-util.h"
static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
* can't be sealed yet. */
if (!part->sealed)
- bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped);
+ bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
else {
if (part->mapped > 0)
assert_se(munmap(part->data, part->mapped) == 0);
free(m->containers);
m->containers = NULL;
- m->n_containers = 0;
+ m->n_containers = m->containers_allocated = 0;
m->root_container.index = 0;
}
}
_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
- assert_return(m, NULL);
+
+ if (!m)
+ return NULL;
assert(m->n_ref > 0);
m->n_ref--;
return -ENOMEM;
if (!part->data && part->memfd < 0)
- part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped);
+ part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
if (part->memfd >= 0) {
- uint64_t u = sz;
- r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &u);
- if (r < 0) {
- m->poisoned = true;
- return -errno;
+ if (part->allocated == 0 || sz > part->allocated) {
+ uint64_t new_allocated;
+
+ new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
+ r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated);
+ if (r < 0) {
+ m->poisoned = true;
+ return -errno;
+ }
+
+ part->allocated = new_allocated;
}
if (!part->data || sz > part->mapped) {
- size_t psz = PAGE_ALIGN(sz > 0 ? sz : 1);
+ size_t psz;
+ psz = PAGE_ALIGN(sz > 0 ? sz : 1);
if (part->mapped <= 0)
n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
else
part->munmap_this = true;
} else {
- n = realloc(part->data, MAX(sz, 1u));
- if (!n) {
- m->poisoned = true;
- return -ENOMEM;
- }
+ if (part->allocated == 0 || sz > part->allocated) {
+ size_t new_allocated;
+
+ new_allocated = sz > 0 ? 2 * sz : 64;
+ n = realloc(part->data, new_allocated);
+ if (!n) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
- part->data = n;
- part->free_this = true;
+ part->data = n;
+ part->allocated = new_allocated;
+ part->free_this = true;
+ }
}
if (q)
if (!c->need_offsets)
return 0;
- if (!GREEDY_REALLOC(c->offsets, c->n_offsets_allocated, c->n_offsets + 1))
+ if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
return -ENOMEM;
c->offsets[c->n_offsets++] = offset;
}
static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
- struct bus_body_part *part = NULL;
- size_t start_body, end_body, padding, start_part, end_part, added;
- bool add_new_part;
+ size_t start_body, end_body, padding, added;
void *p;
int r;
return NULL;
}
- add_new_part =
- m->n_body_parts <= 0 ||
- m->body_end->sealed ||
- padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
+ if (added > 0) {
+ struct bus_body_part *part = NULL;
+ bool add_new_part;
+
+ add_new_part =
+ m->n_body_parts <= 0 ||
+ m->body_end->sealed ||
+ padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
+
+ if (add_new_part) {
+ if (padding > 0) {
+ part = message_append_part(m);
+ if (!part)
+ return NULL;
+
+ part_zero(part, padding);
+ }
- if (add_new_part) {
- if (padding > 0) {
part = message_append_part(m);
if (!part)
return NULL;
- part_zero(part, padding);
- }
+ r = part_make_space(m, part, sz, &p);
+ if (r < 0)
+ return NULL;
+ } else {
+ struct bus_container *c;
+ void *op;
+ size_t os, start_part, end_part;
- part = message_append_part(m);
- if (!part)
- return NULL;
+ part = m->body_end;
+ op = part->data;
+ os = part->size;
- r = part_make_space(m, part, sz, &p);
- if (r < 0)
- return NULL;
- } else {
- struct bus_container *c;
- void *op;
- size_t os;
+ start_part = ALIGN_TO(part->size, align);
+ end_part = start_part + sz;
- part = m->body_end;
- op = part->data;
- os = part->size;
+ r = part_make_space(m, part, end_part, &p);
+ if (r < 0)
+ return NULL;
- start_part = ALIGN_TO(part->size, align);
- end_part = start_part + sz;
+ if (padding > 0) {
+ memset(p, 0, padding);
+ p = (uint8_t*) p + padding;
+ }
- r = part_make_space(m, part, end_part, &p);
- if (r < 0)
- return NULL;
+ /* Readjust pointers */
+ for (c = m->containers; c < m->containers + m->n_containers; c++)
+ c->array_size = adjust_pointer(c->array_size, op, os, part->data);
- if (padding > 0) {
- memset(p, 0, padding);
- p = (uint8_t*) p + padding;
+ m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
}
-
- /* Readjust pointers */
- for (c = m->containers; c < m->containers + m->n_containers; c++)
- c->array_size = adjust_pointer(c->array_size, op, os, part->data);
-
- m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
- }
+ } else
+ /* Return something that is not NULL and is aligned */
+ p = (uint8_t *) NULL + align;
m->header->body_size = end_body;
message_extend_containers(m, added);
assert_return(!m->poisoned, -ESTALE);
/* Make sure we have space for one more container */
- w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
- if (!w) {
+ if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
m->poisoned = true;
return -ENOMEM;
}
- m->containers = w;
-
c = message_get_container(m);
signature = strdup(contents);
}
/* OK, let's fill it in */
- w += m->n_containers++;
+ w = m->containers + m->n_containers++;
w->enclosing = type;
w->signature = signature;
w->index = 0;
w->array_size = array_size;
w->before = before;
w->begin = begin;
- w->n_offsets = w->n_offsets_allocated = 0;
+ w->n_offsets = w->offsets_allocated = 0;
w->offsets = NULL;
w->need_offsets = need_offsets;
}
static size_t determine_word_size(size_t sz, size_t extra) {
- if (sz <= 0 && extra == 0)
- return 0;
- else if (sz + extra <= 0xFF)
+ if (sz + extra <= 0xFF)
return 1;
else if (sz + extra*2 <= 0xFFFF)
return 2;
if (!BUS_MESSAGE_IS_GVARIANT(m))
return 0;
- p = c->signature;
+ p = strempty(c->signature);
while (*p != 0) {
size_t n;
if (!a)
return -ENOMEM;
- p = c->signature;
+ p = strempty(c->signature);
for (i = 0, j = 0; i < c->n_offsets; i++) {
unsigned k;
size_t n;
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
- assert_return(bus_type_is_trivial(type), -EINVAL);
+ assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
assert_return(ptr || size == 0, -EINVAL);
assert_return(!m->poisoned, -ESTALE);
+ /* alignment and size of the trivial types (except bool) is
+ * identical for gvariant and dbus1 marshalling */
align = bus_type_get_alignment(type);
sz = bus_type_get_size(type);
part->size = size;
copy_fd = -1;
- message_extend_containers(m, size);
m->header->body_size += size;
+ message_extend_containers(m, size);
return sd_bus_message_close_container(m);
}
return sd_bus_message_close_container(m);
}
+static int bus_message_close_header(sd_bus_message *m) {
+ uint8_t *a;
+ size_t sz, i;
+
+ assert(m);
+
+ if (!BUS_MESSAGE_IS_GVARIANT(m))
+ return 0;
+
+ if (m->n_header_offsets < 1)
+ return 0;
+
+ assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
+
+ sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
+
+ a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
+ if (!a)
+ return -ENOMEM;
+
+ for (i = 0; i < m->n_header_offsets; i++)
+ write_word_le(a + sz*i, sz, m->header_offsets[i]);
+
+ return 0;
+}
+
+int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout) {
+ struct bus_body_part *part;
+ size_t l, a;
+ unsigned i;
+ int r;
+
+ assert(m);
+
+ if (m->sealed)
+ return -EPERM;
+
+ if (m->n_containers > 0)
+ return -EBADMSG;
+
+ if (m->poisoned)
+ return -ESTALE;
+
+ /* In vtables the return signature of method calls is listed,
+ * let's check if they match if this is a response */
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
+ m->enforced_reply_signature &&
+ !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
+ return -ENOMSG;
+
+ /* If gvariant marshalling is used we need to close the body structure */
+ r = bus_message_close_struct(m, &m->root_container, false);
+ if (r < 0)
+ return r;
+
+ /* If there's a non-trivial signature set, then add it in here */
+ if (!isempty(m->root_container.signature)) {
+ r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
+ if (r < 0)
+ return r;
+ }
+
+ if (m->n_fds > 0) {
+ r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
+ if (r < 0)
+ return r;
+ }
+
+ r = bus_message_close_header(m);
+ if (r < 0)
+ return r;
+
+ m->header->serial = serial;
+ m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
+
+ /* Add padding at the end of the fields part, since we know
+ * the body needs to start at an 8 byte alignment. We made
+ * sure we allocated enough space for this, so all we need to
+ * do here is to zero it out. */
+ l = BUS_MESSAGE_FIELDS_SIZE(m);
+ a = ALIGN8(l) - l;
+ if (a > 0)
+ memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
+
+ /* If this is something we can send as memfd, then let's seal
+ the memfd now. Note that we can send memfds as payload only
+ for directed messages, and not for broadcasts. */
+ if (m->destination && m->bus && m->bus->use_memfd) {
+ MESSAGE_FOREACH_PART(part, i, m)
+ if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
+ uint64_t sz;
+
+ /* Try to seal it if that makes
+ * sense. First, unmap our own map to
+ * make sure we don't keep it busy. */
+ bus_body_part_unmap(part);
+
+ /* Then, sync up real memfd size */
+ sz = part->size;
+ if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0)
+ return -errno;
+
+ /* Finally, try to seal */
+ if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
+ part->sealed = true;
+ }
+ }
+
+ m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
+ m->root_container.index = 0;
+ m->root_container.offset_index = 0;
+ m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
+
+ m->sealed = true;
+
+ return 0;
+}
+
int bus_body_part_map(struct bus_body_part *part) {
void *p;
size_t psz;
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
c->item_size = c->offsets[c->offset_index+1] - *rindex;
} else {
+
+ if (c->offset_index+1 >= (c->end-c->begin)/sz)
+ goto end;
+
/* Fixed-size array */
- *rindex += sz;
+ *rindex = c->begin + (c->offset_index+1) * sz;
c->item_size = sz;
}
assert(rindex);
assert(align > 0);
- if (message_end_of_array(m, *rindex))
- return 0;
-
start = ALIGN_TO((size_t) *rindex, align);
padding = start - *rindex;
end = start + nbytes;
}
part = find_part(m, start, nbytes, (void**) &q);
- if (!part || !q)
+ if (!part || (nbytes > 0 && !q))
return -EBADMSG;
*rindex = end;
if (ret)
*ret = q;
- return 1;
+ return 0;
}
static bool validate_nul(const char *s, size_t l) {
bool ok;
r = message_peek_body(m, &rindex, 1, c->item_size, &q);
- if (r <= 0)
+ if (r < 0)
return r;
if (type == SD_BUS_TYPE_STRING)
assert(align > 0);
r = message_peek_body(m, &rindex, align, c->item_size, &q);
- if (r <= 0)
+ if (r < 0)
return r;
switch (type) {
bool ok;
r = message_peek_body(m, &rindex, 4, 4, &q);
- if (r <= 0)
+ if (r < 0)
return r;
l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
if (type == SD_BUS_TYPE_OBJECT_PATH)
ok = validate_object_path(q, l);
uint8_t l;
r = message_peek_body(m, &rindex, 1, 1, &q);
- if (r <= 0)
+ if (r < 0)
return r;
l = *(uint8_t*) q;
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
if (!validate_signature(q, l))
return -EBADMSG;
assert(sz > 0);
r = message_peek_body(m, &rindex, align, sz, &q);
- if (r <= 0)
+ if (r < 0)
return r;
switch (type) {
/* dbus1 */
r = message_peek_body(m, &rindex, 4, 4, &q);
- if (r <= 0)
+ if (r < 0)
return r;
if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
r = message_peek_body(m, &rindex, alignment, 0, NULL);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
*array_size = (uint32_t*) q;
r = message_peek_body(m, &where, 1, sz, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
framing = read_word_le(q, sz);
if (framing > c->item_size - sz)
r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
*offsets = new(size_t, *n_offsets);
if (!*offsets)
r = message_peek_body(m, &where, 1, 1+k, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
if (*(char*) q != 0)
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, 1, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
l = *(uint8_t*) q;
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
if (!validate_signature(q, l))
return -EBADMSG;
int r;
assert(m);
- assert(signature);
assert(item_size);
assert(offsets);
assert(n_offsets);
+ if (isempty(signature)) {
+ *item_size = 0;
+ *offsets = NULL;
+ *n_offsets = 0;
+ return 0;
+ }
+
sz = determine_word_size(size, 0);
+ if (sz <= 0)
+ return -EBADMSG;
/* First, loop over signature and count variable elements and
* elements in general. We use this to know how large the
r = message_peek_body(m, &where, 1, n_variable * sz, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
v = n_variable;
/* dbus1 */
r = message_peek_body(m, &m->rindex, 8, 0, NULL);
- if (r <= 0)
+ if (r < 0)
return r;
} else if (c->item_size <= 0) {
/* Allow entering into anonymous containers */
r = sd_bus_message_peek_type(m, &tt, &cc);
- if (r <= 0)
+ if (r < 0)
return r;
if (type != 0 && type != tt)
if (m->n_containers >= BUS_CONTAINER_DEPTH)
return -EBADMSG;
- w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
- if (!w)
+ if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
return -ENOMEM;
- m->containers = w;
if (message_end_of_signature(m))
return -ENXIO;
}
/* OK, let's fill it in */
- w += m->n_containers++;
+ w = m->containers + m->n_containers++;
w->enclosing = type;
w->signature = signature;
w->index = 0;
_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
struct bus_container *c;
+ unsigned saved;
int r;
assert_return(m, -EINVAL);
c = message_get_container(m);
+ saved = c->index;
+ c->index = c->saved_index;
r = container_next_item(m, c, &m->rindex);
+ c->index = saved;
if (r < 0)
return r;
r = message_peek_body(m, &where, 1, k, &q);
if (r < 0)
return r;
- if (r == 0)
- goto eof;
if (*(char*) q == 0)
break;
r = message_peek_body(m, &rindex, 1, 1, &q);
if (r < 0)
return r;
- if (r == 0)
- goto eof;
l = *(uint8_t*) q;
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
- if (r == 0)
- return -EBADMSG;
if (!validate_signature(q, l))
return -EBADMSG;
m->rindex = c->begin;
}
+ c->offset_index = 0;
+ c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
+
return !isempty(c->signature);
}
if (align < 0)
return align;
- sz = c->item_size;
+ sz = c->end - c->begin;
} else {
align = bus_type_get_alignment(type);
if (align < 0)
r = message_peek_body(m, &m->rindex, align, sz, &p);
if (r < 0)
goto fail;
- if (r == 0) {
- r = -EBADMSG;
- goto fail;
- }
}
r = sd_bus_message_exit_container(m);
uint32_t unix_fds = 0;
void *offsets = NULL;
unsigned n_offsets = 0;
- size_t sz;
+ size_t sz = 0;
unsigned i = 0;
assert(m);
if (m->n_fds != unix_fds)
return -EBADMSG;
- if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
- return -EBADMSG;
-
switch (m->header->type) {
case SD_BUS_MESSAGE_SIGNAL:
return 0;
}
-static int bus_message_close_header(sd_bus_message *m) {
- uint8_t *a;
- size_t sz, i;
-
- assert(m);
-
- if (!BUS_MESSAGE_IS_GVARIANT(m))
- return 0;
-
- if (m->n_header_offsets < 1)
- return 0;
-
- assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
-
- sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
-
- a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
- if (!a)
- return -ENOMEM;
-
- for (i = 0; i < m->n_header_offsets; i++)
- write_word_le(a + sz*i, sz, m->header_offsets[i]);
-
- return 0;
-}
-
-int bus_message_seal(sd_bus_message *m, uint64_t serial) {
- struct bus_body_part *part;
- size_t l, a;
- unsigned i;
- int r;
-
- assert(m);
-
- if (m->sealed)
- return -EPERM;
-
- if (m->n_containers > 0)
- return -EBADMSG;
-
- if (m->poisoned)
- return -ESTALE;
-
- /* In vtables the return signature of method calls is listed,
- * let's check if they match if this is a response */
- if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
- m->enforced_reply_signature &&
- !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
- return -ENOMSG;
-
- /* If gvariant marshalling is used we need to close the body structure */
- r = bus_message_close_struct(m, &m->root_container, false);
- if (r < 0)
- return r;
-
- /* If there's a non-trivial signature set, then add it in here */
- if (!isempty(m->root_container.signature)) {
- r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
- if (r < 0)
- return r;
- }
-
- if (m->n_fds > 0) {
- r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
- if (r < 0)
- return r;
- }
-
- r = bus_message_close_header(m);
- if (r < 0)
- return r;
-
- m->header->serial = serial;
-
- /* Add padding at the end of the fields part, since we know
- * the body needs to start at an 8 byte alignment. We made
- * sure we allocated enough space for this, so all we need to
- * do here is to zero it out. */
- l = BUS_MESSAGE_FIELDS_SIZE(m);
- a = ALIGN8(l) - l;
- if (a > 0)
- memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
-
- /* If this is something we can send as memfd, then let's seal
- the memfd now. Note that we can send memfds as payload only
- for directed messages, and not for broadcasts. */
- if (m->destination && m->bus && m->bus->use_memfd) {
- MESSAGE_FOREACH_PART(part, i, m)
- if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
- bus_body_part_unmap(part);
-
- if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
- part->sealed = true;
- }
- }
-
- m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
- m->root_container.index = 0;
- m->root_container.offset_index = 0;
- m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
-
- m->sealed = true;
-
- return 0;
-}
-
_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
assert_return(m, -EINVAL);
assert_return(destination, -EINVAL);
assert_return(m, NULL);
c = complete ? &m->root_container : message_get_container(m);
- return c->signature ?: "";
+ return strempty(c->signature);
}
_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
return m->bus;
}
+
+int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
+ _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
+ usec_t timeout;
+ int r;
+
+ assert(bus);
+ assert(m);
+ assert(*m);
+
+ switch ((*m)->header->type) {
+
+ case SD_BUS_MESSAGE_SIGNAL:
+ r = sd_bus_message_new_signal(bus, (*m)->path, (*m)->interface, (*m)->member, &n);
+ if (r < 0)
+ return r;
+
+ break;
+
+ case SD_BUS_MESSAGE_METHOD_CALL:
+ r = sd_bus_message_new_method_call(bus, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member, &n);
+ if (r < 0)
+ return r;
+
+ break;
+
+ case SD_BUS_MESSAGE_METHOD_RETURN:
+ case SD_BUS_MESSAGE_METHOD_ERROR:
+
+ n = message_new(bus, (*m)->header->type);
+ if (!n)
+ return -ENOMEM;
+
+ n->reply_serial = (*m)->reply_serial;
+ r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_serial);
+ if (r < 0)
+ return r;
+
+ if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
+ r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
+ if (r < 0)
+ return r;
+
+ n->error._need_free = -1;
+ }
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((*m)->destination && !n->destination) {
+ r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
+ if (r < 0)
+ return r;
+ }
+
+ if ((*m)->sender && !n->sender) {
+ r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
+ if (r < 0)
+ return r;
+ }
+
+ n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
+
+ r = sd_bus_message_copy(n, *m, true);
+ if (r < 0)
+ return r;
+
+ timeout = (*m)->timeout;
+ if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED))
+ timeout = BUS_DEFAULT_TIMEOUT;
+
+ r = bus_message_seal(n, (*m)->header->serial, timeout);
+ if (r < 0)
+ return r;
+
+ sd_bus_message_unref(*m);
+ *m = n;
+ n = NULL;
+
+ return 0;
+}