X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-message.c;h=fb4718085bb6a73288ba5b3b928686a6669c6389;hp=7acab50979336b4e464dc9f0b403bac6a221af05;hb=2100fa1099b086411270a2876dde0532ea2806fa;hpb=917b5dc7075a15bded4948efba8e686dba4509f8 diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 7acab5097..fb4718085 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -265,7 +265,7 @@ int bus_message_from_malloc( } else return -EBADMSG; - total = sizeof(struct bus_header) + ALIGN_TO(fs, 8) + bs; + total = sizeof(struct bus_header) + ALIGN8(fs) + bs; if (length != total) return -EBADMSG; @@ -283,7 +283,7 @@ int bus_message_from_malloc( m->sealed = true; m->header = h; m->fields = (uint8_t*) buffer + sizeof(struct bus_header); - m->body = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN_TO(fs, 8); + m->body = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(fs); m->fds = fds; m->n_fds = n_fds; @@ -302,7 +302,6 @@ int bus_message_from_malloc( m->n_iovec = 1; m->iovec[0].iov_base = buffer; m->iovec[0].iov_len = length; - m->size = length; r = message_parse_fields(m); if (r < 0) @@ -1241,18 +1240,89 @@ int sd_bus_message_close_container(sd_bus_message *m) { return 0; } + +typedef struct { + const char *types; + unsigned n_struct; + unsigned n_array; +} TypeStack; + +static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) { + assert(stack); + assert(max > 0); + + if (*i >= max) + return -EINVAL; + + stack[*i].types = types; + stack[*i].n_struct = n_struct; + stack[*i].n_array = n_array; + (*i)++; + + return 0; +} + +static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) { + assert(stack); + assert(max > 0); + assert(types); + assert(n_struct); + assert(n_array); + + if (*i <= 0) + return 0; + + (*i)--; + *types = stack[*i].types; + *n_struct = stack[*i].n_struct; + *n_array = stack[*i].n_array; + + return 1; +} + int bus_message_append_ap( sd_bus_message *m, const char *types, va_list ap) { - const char *t; + unsigned n_array, n_struct; + TypeStack stack[BUS_CONTAINER_DEPTH]; + unsigned stack_ptr = 0; int r; assert(m); - assert(types); - for (t = types; *t; t++) { + if (!types) + return 0; + + n_array = (unsigned) -1; + n_struct = strlen(types); + + for (;;) { + const char *t; + + if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { + r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + continue; + } + + t = types; + if (n_array != (unsigned) -1) + n_array --; + else { + types ++; + n_struct--; + } + switch (*t) { case SD_BUS_TYPE_BYTE: { @@ -1314,27 +1384,28 @@ int bus_message_append_ap( return r; { - unsigned i, n; char s[k + 1]; - memcpy(s, t + 1, k); s[k] = 0; - t += k; r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s); if (r < 0) return r; + } - n = va_arg(ap, unsigned); - for (i = 0; i < n; i++) { - r = bus_message_append_ap(m, s, ap); - if (r < 0) - return r; - } - - r = sd_bus_message_close_container(m); + if (n_array == (unsigned) -1) { + types += k; + n_struct -= k; } + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = t + 1; + n_struct = k; + n_array = va_arg(ap, unsigned); + break; } @@ -1349,11 +1420,14 @@ int bus_message_append_ap( if (r < 0) return r; - r = bus_message_append_ap(m, s, ap); + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); if (r < 0) return r; - r = sd_bus_message_close_container(m); + types = s; + n_struct = strlen(s); + n_array = (unsigned) -1; + break; } @@ -1374,15 +1448,20 @@ int bus_message_append_ap( r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s); if (r < 0) return r; + } - t += k - 1; + if (n_array == (unsigned) -1) { + types += k - 1; + n_struct -= k - 1; + } - r = bus_message_append_ap(m, s, ap); - if (r < 0) - return r; + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; - r = sd_bus_message_close_container(m); - } + types = t + 1; + n_struct = k - 2; + n_array = (unsigned) -1; break; } @@ -1630,18 +1709,13 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { break; case SD_BUS_TYPE_UNIX_FD: { - int copy; uint32_t j; j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); if (j >= m->n_fds) return -EBADMSG; - copy = fcntl(m->fds[j], F_DUPFD_CLOEXEC, 3); - if (copy < 0) - return -errno; - - *(int*) p = copy; + *(int*) p = m->fds[j]; break; } @@ -2088,15 +2162,56 @@ int sd_bus_message_rewind(sd_bus_message *m, int complete) { return !isempty(c->signature); } +static int message_read_ap( + sd_bus_message *m, + const char *types, + va_list ap) { -static int message_read_ap(sd_bus_message *m, const char *types, va_list ap) { - const char *t; + unsigned n_array, n_struct; + TypeStack stack[BUS_CONTAINER_DEPTH]; + unsigned stack_ptr = 0; int r; assert(m); - assert(types); - for (t = types; *t; t++) { + if (!types) + return 0; + + /* Ideally, we'd just call ourselves recursively on every + * complex type. However, the state of a va_list that is + * passed to a function is undefined after that function + * returns. This means we need to docode the va_list linearly + * in a single stackframe. We hence implement our own + * home-grown stack in an array. */ + + n_array = (unsigned) -1; + n_struct = strlen(types); + + for (;;) { + const char *t; + + if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { + r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + continue; + } + + t = types; + if (n_array != (unsigned) -1) + n_array --; + else { + types ++; + n_struct--; + } + switch (*t) { case SD_BUS_TYPE_BYTE: @@ -2116,6 +2231,11 @@ static int message_read_ap(sd_bus_message *m, const char *types, va_list ap) { p = va_arg(ap, void*); r = sd_bus_message_read_basic(m, *t, p); + if (r < 0) + return r; + if (r == 0) + return -ENXIO; + break; } @@ -2127,29 +2247,30 @@ static int message_read_ap(sd_bus_message *m, const char *types, va_list ap) { return r; { - unsigned i, n; char s[k + 1]; - memcpy(s, t + 1, k); s[k] = 0; - t += k; r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s); if (r < 0) return r; if (r == 0) return -ENXIO; + } - n = va_arg(ap, unsigned); - for (i = 0; i < n; i++) { - r = message_read_ap(m, s, ap); - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); + if (n_array == (unsigned) -1) { + types += k; + n_struct -= k; } + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = t + 1; + n_struct = k; + n_array = va_arg(ap, unsigned); + break; } @@ -2166,13 +2287,14 @@ static int message_read_ap(sd_bus_message *m, const char *types, va_list ap) { if (r == 0) return -ENXIO; - r = message_read_ap(m, s, ap); + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); if (r < 0) return r; - if (r == 0) - return -ENXIO; - r = sd_bus_message_exit_container(m); + types = s; + n_struct = strlen(s); + n_array = (unsigned) -1; + break; } @@ -2194,29 +2316,27 @@ static int message_read_ap(sd_bus_message *m, const char *types, va_list ap) { return r; if (r == 0) return -ENXIO; + } - t += k - 1; + if (n_array == (unsigned) -1) { + types += k - 1; + n_struct -= k - 1; + } - r = message_read_ap(m, s, ap); - if (r < 0) - return r; - if (r == 0) - return -ENXIO; + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; - r = sd_bus_message_exit_container(m); - } + types = t + 1; + n_struct = k - 2; + n_array = (unsigned) -1; break; } default: - r = -EINVAL; + return -EINVAL; } - - if (r < 0) - return r; - if (r == 0) - return -ENXIO; } return 1; @@ -2673,42 +2793,6 @@ static int message_parse_fields(sd_bus_message *m) { return 0; } -static void setup_iovec(sd_bus_message *m) { - assert(m); - assert(m->sealed); - - m->n_iovec = 0; - m->size = 0; - - m->iovec[m->n_iovec].iov_base = m->header; - m->iovec[m->n_iovec].iov_len = sizeof(*m->header); - m->size += m->iovec[m->n_iovec].iov_len; - m->n_iovec++; - - if (m->fields) { - m->iovec[m->n_iovec].iov_base = m->fields; - m->iovec[m->n_iovec].iov_len = m->header->fields_size; - m->size += m->iovec[m->n_iovec].iov_len; - m->n_iovec++; - - if (m->header->fields_size % 8 != 0) { - static const uint8_t padding[7] = { 0, 0, 0, 0, 0, 0, 0 }; - - m->iovec[m->n_iovec].iov_base = (void*) padding; - m->iovec[m->n_iovec].iov_len = 8 - m->header->fields_size % 8; - m->size += m->iovec[m->n_iovec].iov_len; - m->n_iovec++; - } - } - - if (m->body) { - m->iovec[m->n_iovec].iov_base = m->body; - m->iovec[m->n_iovec].iov_len = m->header->body_size; - m->size += m->iovec[m->n_iovec].iov_len; - m->n_iovec++; - } -} - int bus_message_seal(sd_bus_message *m, uint64_t serial) { int r; @@ -2736,8 +2820,6 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial) { m->header->serial = serial; m->sealed = true; - setup_iovec(m); - return 0; } @@ -2953,22 +3035,31 @@ int bus_message_dump(sd_bus_message *m) { int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) { size_t total; - unsigned i; void *p, *e; assert(m); assert(buffer); assert(sz); - for (i = 0, total = 0; i < m->n_iovec; i++) - total += m->iovec[i].iov_len; + total = bus_message_size(m); p = malloc(total); if (!p) return -ENOMEM; - for (i = 0, e = p; i < m->n_iovec; i++) - e = mempcpy(e, m->iovec[i].iov_base, m->iovec[i].iov_len); + e = mempcpy(p, m->header, sizeof(*m->header)); + + if (m->fields) { + e = mempcpy(e, m->fields, m->header->fields_size); + + if (m->header->fields_size % 8 != 0) + e = mempset(e, 0, 8 - (m->header->fields_size % 8)); + } + + if (m->body) + e = mempcpy(e, m->body, m->header->body_size); + + assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p)); *buffer = p; *sz = total; @@ -3041,3 +3132,13 @@ const char* bus_message_get_arg(sd_bus_message *m, unsigned i) { return t; } + +size_t bus_message_size(sd_bus_message *m) { + assert(m); + assert(m->sealed); + + return + sizeof(*m->header) + + ALIGN8(m->header->fields_size) + + m->header->body_size; +}