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);
}
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);
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;
}
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;
part->mapped = psz;
part->data = n;
- part->munmap_this = true;
}
+
+ part->munmap_this = true;
} else {
n = realloc(part->data, sz);
if (!n) {
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) {
ssize_t align, sz;
uint32_t k;
void *a;
- char *e = NULL;
int fd = -1;
uint32_t fdi = 0;
int r;
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;
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)
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;
}
}
-
a = message_extend_body(m, 4, 4 + size + 1);
if (!a)
return -ENOMEM;
uint32_t **array_size) {
unsigned nindex;
- char *e = NULL;
void *a, *op;
int alignment;
size_t os;
nindex = c->index + 1 + strlen(contents);
} else {
+ char *e;
+
if (c->enclosing != 0)
return -ENXIO;
struct bus_container *c,
const char *contents) {
- char *e = NULL;
size_t l;
void *a;
return -ENXIO;
} else {
+ char *e;
+
if (c->enclosing != 0)
return -ENXIO;
const char *contents) {
size_t nindex;
- char *e = NULL;
assert(m);
assert(c);
nindex = c->index + 1 + l + 1;
} else {
+ char *e;
+
if (c->enclosing != 0)
return -ENXIO;
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));
return sd_bus_message_close_container(m);
}
-static int body_part_map_for_read(struct bus_body_part *part) {
+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;
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)
part->mapped = psz;
part->data = p;
+ part->munmap_this = true;
+
return 0;
}
+void bus_body_part_unmap(struct bus_body_part *part) {
+
+ assert_se(part);
+
+ if (part->memfd < 0)
+ return;
+
+ if (!part->data)
+ return;
+
+ if (!part->munmap_this)
+ return;
+
+ assert_se(munmap(part->data, part->mapped) == 0);
+
+ part->data = NULL;
+ part->mapped = 0;
+ part->munmap_this = false;
+
+ return;
+}
+
static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
size_t k, start, end;
if (index + sz <= begin + part->size) {
- r = body_part_map_for_read(part);
+ r = bus_body_part_map(part);
if (r < 0)
return NULL;
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);
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) {
- ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1);
- part->sealed = true;
- }
+ /* 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->header->serial = serial;
m->sealed = true;
*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);
+}