X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-message.c;h=760a148fadd8f473f110d0a06589d8cdb4255cea;hb=d7bd01b547bd91353513131561de9cc7d9f7d405;hp=b5a311530b623114d38d728d5b0c6a6fda16fcc1;hpb=a392d36195f92eaa2d5b7c1d588ff8e52025a43a;p=elogind.git diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index b5a311530..760a148fa 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -59,12 +59,14 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) { assert(part); if (part->memfd >= 0) { + /* If we can reuse the memfd, try that. For that it + * can't be sealed yet. */ if (!part->sealed) bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped); else { - if (part->size > 0) - assert_se(munmap(part->data, PAGE_ALIGN(part->size)) == 0); + if (part->mapped > 0) + assert_se(munmap(part->data, part->mapped) == 0); close_nointr_nofail(part->memfd); } @@ -123,17 +125,21 @@ static void message_free(sd_bus_message *m) { if (m->free_kdbus) free(m->kdbus); - if (m->release_kdbus) - ioctl(m->bus->input_fd, KDBUS_CMD_MSG_RELEASE, m->kdbus); + if (m->release_kdbus) { + uint64_t off; - if (m->free_fds) { - close_many(m->fds, m->n_fds); - free(m->fds); + off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer; + ioctl(m->bus->input_fd, KDBUS_CMD_MSG_RELEASE, &off); } if (m->bus) sd_bus_unref(m->bus); + if (m->free_fds) { + close_many(m->fds, m->n_fds); + free(m->fds); + } + if (m->iovec != m->iovec_fixed) free(m->iovec); @@ -562,7 +568,7 @@ static int message_new_reply( goto fail; if (call->sender) { - r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->sender); + r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination); if (r < 0) goto fail; } @@ -621,6 +627,43 @@ fail: return r; } +int bus_message_new_synthetic_error( + sd_bus *bus, + uint64_t serial, + const sd_bus_error *e, + sd_bus_message **m) { + + sd_bus_message *t; + int r; + + assert(sd_bus_error_is_set(e)); + assert(m); + + t = message_new(bus, SD_BUS_MESSAGE_TYPE_METHOD_ERROR); + if (!t) + return -ENOMEM; + + t->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED; + t->reply_serial = serial; + + r = message_append_field_uint32(t, SD_BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_serial); + if (r < 0) + goto fail; + + if (bus && bus->unique_name) { + r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination); + if (r < 0) + goto fail; + } + + *m = t; + return 0; + +fail: + message_free(t); + return r; +} + sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { if (!m) return NULL; @@ -1173,8 +1216,9 @@ static int part_make_space( part->mapped = psz; part->data = n; - part->munmap_this = true; } + + part->munmap_this = true; } else { n = realloc(part->data, sz); if (!n) { @@ -1205,7 +1249,6 @@ static void message_extend_containers(sd_bus_message *m, size_t expand) { for (c = m->containers; c < m->containers + m->n_containers; c++) if (c->array_size) *c->array_size += expand; - } static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz) { @@ -1294,7 +1337,6 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void ssize_t align, sz; uint32_t k; void *a; - char *e = NULL; int fd = -1; uint32_t fdi = 0; int r; @@ -1318,6 +1360,8 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void if (c->signature[c->index] != type) return -ENXIO; } else { + char *e; + /* Maybe we can append to the signature? But only if this is the top-level container*/ if (c->enclosing != 0) return -ENXIO; @@ -1450,7 +1494,6 @@ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) { int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s) { struct bus_container *c; - char *e; void *a; if (!m) @@ -1470,6 +1513,8 @@ int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s) if (c->signature[c->index] != SD_BUS_TYPE_STRING) return -ENXIO; } else { + char *e; + /* Maybe we can append to the signature? But only if this is the top-level container*/ if (c->enclosing != 0) return -ENXIO; @@ -1481,7 +1526,6 @@ int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s) } } - a = message_extend_body(m, 4, 4 + size + 1); if (!a) return -ENOMEM; @@ -1504,7 +1548,6 @@ static int bus_message_open_array( uint32_t **array_size) { unsigned nindex; - char *e = NULL; void *a, *op; int alignment; size_t os; @@ -1534,6 +1577,8 @@ static int bus_message_open_array( nindex = c->index + 1 + strlen(contents); } else { + char *e; + if (c->enclosing != 0) return -ENXIO; @@ -1577,7 +1622,6 @@ static int bus_message_open_variant( struct bus_container *c, const char *contents) { - char *e = NULL; size_t l; void *a; @@ -1597,6 +1641,8 @@ static int bus_message_open_variant( return -ENXIO; } else { + char *e; + if (c->enclosing != 0) return -ENXIO; @@ -1627,7 +1673,6 @@ static int bus_message_open_struct( const char *contents) { size_t nindex; - char *e = NULL; assert(m); assert(c); @@ -1648,6 +1693,8 @@ static int bus_message_open_struct( nindex = c->index + 1 + l + 1; } else { + char *e; + if (c->enclosing != 0) return -ENXIO; @@ -2158,7 +2205,7 @@ int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, sd_memfd *me if (size % sz != 0) return -EINVAL; - if (size > (size_t) (uint32_t) -1) + if (size > (uint64_t) (uint32_t) -1) return -EINVAL; r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type)); @@ -2184,6 +2231,86 @@ int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, sd_memfd *me return sd_bus_message_close_container(m); } +int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) { + _cleanup_close_ int copy_fd = -1; + struct bus_body_part *part; + struct bus_container *c; + uint64_t size; + void *a; + int r; + + if (!m) + return -EINVAL; + if (!memfd) + return -EINVAL; + if (m->sealed) + return -EPERM; + if (m->poisoned) + return -ESTALE; + + r = sd_memfd_set_sealed(memfd, true); + if (r < 0) + return r; + + copy_fd = sd_memfd_dup_fd(memfd); + if (copy_fd < 0) + return copy_fd; + + r = sd_memfd_get_size(memfd, &size); + if (r < 0) + return r; + + /* We require this to be NUL terminated */ + if (size == 0) + return -EINVAL; + + if (size > (uint64_t) (uint32_t) -1) + return -EINVAL; + + c = message_get_container(m); + if (c->signature && c->signature[c->index]) { + /* Container signature is already set */ + + if (c->signature[c->index] != SD_BUS_TYPE_STRING) + return -ENXIO; + } else { + char *e; + + /* Maybe we can append to the signature? But only if this is the top-level container*/ + if (c->enclosing != 0) + return -ENXIO; + + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + } + + a = message_extend_body(m, 4, 4); + if (!a) + return -ENOMEM; + + *(uint32_t*) a = size - 1; + + part = message_append_part(m); + if (!part) + return -ENOMEM; + + part->memfd = copy_fd; + part->sealed = true; + part->size = size; + copy_fd = -1; + + message_extend_containers(m, size); + m->header->body_size += size; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + return 0; +} + int bus_body_part_map(struct bus_body_part *part) { void *p; size_t psz; @@ -2196,6 +2323,13 @@ int bus_body_part_map(struct bus_body_part *part) { if (part->size <= 0) return 0; + /* For smaller zero parts (as used for padding) we don't need to map anything... */ + if (part->memfd < 0 && part->is_zero && part->size < 8) { + static const uint8_t zeroes[7] = { }; + part->data = (void*) zeroes; + return 0; + } + psz = PAGE_ALIGN(part->size); if (part->memfd >= 0) @@ -2222,9 +2356,6 @@ void bus_body_part_unmap(struct bus_body_part *part) { if (part->memfd < 0) return; - if (!part->sealed) - return; - if (!part->data) return; @@ -3235,7 +3366,7 @@ int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, si return align; r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type)); - if (r < 0) + if (r <= 0) return r; c = message_get_container(m); @@ -3726,21 +3857,27 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial) { return r; } - /* Add padding at the end, since we know the body - * needs to start at an 8 byte alignment. */ - + /* 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); - MESSAGE_FOREACH_PART(part, i, m) - if (part->memfd >= 0 && !part->sealed) { - bus_body_part_unmap(part); + /* 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; - } + if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0) + part->sealed = true; + } + } m->header->serial = serial; m->sealed = true; @@ -4144,3 +4281,12 @@ int bus_header_message_size(struct bus_header *h, size_t *sum) { *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs; return 0; } + +int bus_message_to_errno(sd_bus_message *m) { + assert(m); + + if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR) + return 0; + + return bus_error_to_errno(&m->error); +}