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=fb63a2d1cf34b6bffda27b54dd372cc51d917f3f;hp=22e64042099de8235f1eb415981915cb7ce68672;hb=1b492614cb5bec6968fc7126076e7ac9b34c2953;hpb=2c93b4efeca3ccf38d604d85490b796e875e2c31 diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 22e640420..fb63a2d1c 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -302,6 +302,7 @@ 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) @@ -331,7 +332,7 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) { m->header->endian = SD_BUS_NATIVE_ENDIAN; m->header->type = type; m->header->version = bus ? bus->message_version : 1; - m->allow_fds = !bus || bus->can_fds; + m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); return m; } @@ -354,6 +355,8 @@ int sd_bus_message_new_signal( return -EINVAL; if (!m) return -EINVAL; + if (bus && bus->state == BUS_UNSET) + return -ENOTCONN; t = message_new(bus, SD_BUS_MESSAGE_TYPE_SIGNAL); if (!t) @@ -396,6 +399,8 @@ int sd_bus_message_new_method_call( return -EINVAL; if (!m) return -EINVAL; + if (bus && bus->state == BUS_UNSET) + return -ENOTCONN; t = message_new(bus, SD_BUS_MESSAGE_TYPE_METHOD_CALL); if (!t) @@ -445,6 +450,8 @@ static int message_new_reply( return -EINVAL; if (!m) return -EINVAL; + if (bus && bus->state == BUS_UNSET) + return -ENOTCONN; t = message_new(bus, type); if (!t) @@ -778,12 +785,12 @@ static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz) { int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) { struct bus_container *c; - size_t sz, align; + ssize_t align, sz; uint32_t k; void *a; char *e = NULL; int fd = -1; - uint32_t fdi; + uint32_t fdi = 0; int r; if (!m) @@ -1234,18 +1241,89 @@ int sd_bus_message_close_container(sd_bus_message *m) { return 0; } -static int message_append_ap( + +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: { @@ -1307,27 +1385,28 @@ static int 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 = 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; } @@ -1342,11 +1421,14 @@ static int message_append_ap( if (r < 0) return r; - r = 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; } @@ -1367,15 +1449,20 @@ static int 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 = 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; } @@ -1400,10 +1487,10 @@ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) { if (m->sealed) return -EPERM; if (!types) - return -EINVAL; + return 0; va_start(ap, types); - r = message_append_ap(m, types, ap); + r = bus_message_append_ap(m, types, ap); va_end(ap); return r; @@ -1584,10 +1671,12 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { } default: { - size_t sz, align, rindex; + ssize_t sz, align; + size_t rindex; align = bus_type_get_alignment(type); sz = bus_type_get_size(type); + assert(align > 0 && sz > 0); rindex = m->rindex; r = message_peek_body(m, &rindex, align, sz, &q); @@ -2079,15 +2168,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: @@ -2107,6 +2237,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; } @@ -2118,29 +2253,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; } @@ -2157,13 +2293,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; } @@ -2185,29 +2322,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; @@ -2386,10 +2521,11 @@ static int message_skip_fields( (*signature)++; } else if (bus_type_is_basic(t)) { - size_t align, k; + ssize_t align, k; align = bus_type_get_alignment(t); k = bus_type_get_size(t); + assert(align > 0 && k > 0); r = message_peek_fields(m, ri, align, k, NULL); if (r < 0) @@ -2996,3 +3132,38 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) { return 0; } + +const char* bus_message_get_arg(sd_bus_message *m, unsigned i) { + int r; + const char *t; + char type; + + assert(m); + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return NULL; + + while (i > 0) { + r = sd_bus_message_peek_type(m, &type, NULL); + if (r < 0) + return NULL; + + if (type != SD_BUS_TYPE_STRING && + type != SD_BUS_TYPE_OBJECT_PATH && + type != SD_BUS_TYPE_SIGNATURE) + return NULL; + + r = sd_bus_message_read_basic(m, type, &t); + if (r < 0) + return NULL; + + i--; + } + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return NULL; + + return t; +}