X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-message.c;h=d6888738e1063989594f2bc762146551f16a3925;hp=007fab4e438d382f9cff94d733e7d19552a66046;hb=8e959fbf3862172b53d200cda659795c3744fa78;hpb=0039a203b1fc343bb280d512396886a4aefa4a01 diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 007fab4e4..d6888738e 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -35,6 +35,7 @@ #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); @@ -64,7 +65,7 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) { * 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); @@ -113,7 +114,7 @@ static void message_reset_containers(sd_bus_message *m) { free(m->containers); m->containers = NULL; - m->n_containers = 0; + m->n_containers = m->containers_allocated = 0; m->root_container.index = 0; } @@ -791,7 +792,9 @@ _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { } _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--; @@ -1046,20 +1049,27 @@ static int part_make_space( 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 @@ -1076,14 +1086,20 @@ static int part_make_space( 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; - part->data = n; - part->free_this = true; + new_allocated = sz > 0 ? 2 * sz : 64; + n = realloc(part->data, new_allocated); + if (!n) { + m->poisoned = true; + return -ENOMEM; + } + + part->data = n; + part->allocated = new_allocated; + part->free_this = true; + } } if (q) @@ -1107,7 +1123,7 @@ static int message_add_offset(sd_bus_message *m, size_t offset) { 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; @@ -1841,14 +1857,11 @@ _public_ int sd_bus_message_open_container( 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); @@ -1879,14 +1892,14 @@ _public_ int sd_bus_message_open_container( } /* 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; @@ -1894,9 +1907,7 @@ _public_ int sd_bus_message_open_container( } 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; @@ -2695,7 +2706,7 @@ static int bus_message_close_header(sd_bus_message *m) { return 0; } -int bus_message_seal(sd_bus_message *m, uint64_t serial) { +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; @@ -2742,6 +2753,7 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial) { 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 @@ -2758,8 +2770,19 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial) { 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; } @@ -3063,7 +3086,7 @@ static int message_peek_body( } part = find_part(m, start, nbytes, (void**) &q); - if (!part || !q) + if (!part || (nbytes > 0 && !q)) return -EBADMSG; *rindex = end; @@ -3853,10 +3876,8 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, 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; @@ -3891,7 +3912,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, } /* 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; @@ -3911,6 +3932,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, _public_ int sd_bus_message_exit_container(sd_bus_message *m) { struct bus_container *c; + unsigned saved; int r; assert_return(m, -EINVAL); @@ -3942,7 +3964,10 @@ _public_ int sd_bus_message_exit_container(sd_bus_message *m) { 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; @@ -4146,6 +4171,9 @@ _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) { 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); } @@ -4844,7 +4872,7 @@ int bus_message_parse_fields(sd_bus_message *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); @@ -5078,9 +5106,6 @@ int bus_message_parse_fields(sd_bus_message *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: @@ -5407,3 +5432,87 @@ _public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) { 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; +}