| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #include "bus-map-properties.h" |
| #include "alloc-util.h" |
| #include "strv.h" |
| #include "bus-message.h" |
| |
| int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { |
| sd_id128_t *p = userdata; |
| const void *v; |
| size_t n; |
| int r; |
| |
| r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n); |
| if (r < 0) |
| return r; |
| |
| if (n == 0) |
| *p = SD_ID128_NULL; |
| else if (n == 16) |
| memcpy((*p).bytes, v, n); |
| else |
| return -EINVAL; |
| |
| return 0; |
| } |
| |
| int bus_map_strv_sort(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { |
| _cleanup_strv_free_ char **l = NULL; |
| char ***p = userdata; |
| int r; |
| |
| r = bus_message_read_strv_extend(m, &l); |
| if (r < 0) |
| return r; |
| |
| r = strv_extend_strv(p, l, false); |
| if (r < 0) |
| return r; |
| |
| strv_sort(*p); |
| return 0; |
| } |
| |
| static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) { |
| char type; |
| int r; |
| |
| r = sd_bus_message_peek_type(m, &type, NULL); |
| if (r < 0) |
| return r; |
| |
| switch (type) { |
| |
| case SD_BUS_TYPE_STRING: |
| case SD_BUS_TYPE_OBJECT_PATH: { |
| const char **p = userdata; |
| const char *s; |
| |
| r = sd_bus_message_read_basic(m, type, &s); |
| if (r < 0) |
| return r; |
| |
| if (isempty(s)) |
| s = NULL; |
| |
| if (flags & BUS_MAP_STRDUP) |
| return free_and_strdup((char **) userdata, s); |
| |
| *p = s; |
| return 0; |
| } |
| |
| case SD_BUS_TYPE_ARRAY: { |
| _cleanup_strv_free_ char **l = NULL; |
| char ***p = userdata; |
| |
| r = bus_message_read_strv_extend(m, &l); |
| if (r < 0) |
| return r; |
| |
| return strv_extend_strv(p, l, false); |
| } |
| |
| case SD_BUS_TYPE_BOOLEAN: { |
| int b; |
| |
| r = sd_bus_message_read_basic(m, type, &b); |
| if (r < 0) |
| return r; |
| |
| if (flags & BUS_MAP_BOOLEAN_AS_BOOL) |
| *(bool*) userdata = b; |
| else |
| *(int*) userdata = b; |
| |
| return 0; |
| } |
| |
| case SD_BUS_TYPE_INT32: |
| case SD_BUS_TYPE_UINT32: { |
| uint32_t u, *p = userdata; |
| |
| r = sd_bus_message_read_basic(m, type, &u); |
| if (r < 0) |
| return r; |
| |
| *p = u; |
| return 0; |
| } |
| |
| case SD_BUS_TYPE_INT64: |
| case SD_BUS_TYPE_UINT64: { |
| uint64_t t, *p = userdata; |
| |
| r = sd_bus_message_read_basic(m, type, &t); |
| if (r < 0) |
| return r; |
| |
| *p = t; |
| return 0; |
| } |
| |
| case SD_BUS_TYPE_DOUBLE: { |
| double d, *p = userdata; |
| |
| r = sd_bus_message_read_basic(m, type, &d); |
| if (r < 0) |
| return r; |
| |
| *p = d; |
| return 0; |
| }} |
| |
| return -EOPNOTSUPP; |
| } |
| |
| int bus_message_map_all_properties( |
| sd_bus_message *m, |
| const struct bus_properties_map *map, |
| unsigned flags, |
| sd_bus_error *error, |
| void *userdata) { |
| |
| int r; |
| |
| assert(m); |
| assert(map); |
| |
| r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); |
| if (r < 0) |
| return r; |
| |
| while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { |
| const struct bus_properties_map *prop; |
| const char *member; |
| const char *contents; |
| void *v; |
| unsigned i; |
| |
| r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member); |
| if (r < 0) |
| return r; |
| |
| for (i = 0, prop = NULL; map[i].member; i++) |
| if (streq(map[i].member, member)) { |
| prop = &map[i]; |
| break; |
| } |
| |
| if (prop) { |
| r = sd_bus_message_peek_type(m, NULL, &contents); |
| if (r < 0) |
| return r; |
| |
| r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); |
| if (r < 0) |
| return r; |
| |
| v = (uint8_t *)userdata + prop->offset; |
| if (map[i].set) |
| r = prop->set(sd_bus_message_get_bus(m), member, m, error, v); |
| else |
| r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v); |
| if (r < 0) |
| return r; |
| |
| r = sd_bus_message_exit_container(m); |
| if (r < 0) |
| return r; |
| } else { |
| r = sd_bus_message_skip(m, "v"); |
| if (r < 0) |
| return r; |
| } |
| |
| r = sd_bus_message_exit_container(m); |
| if (r < 0) |
| return r; |
| } |
| if (r < 0) |
| return r; |
| |
| return sd_bus_message_exit_container(m); |
| } |
| |
| int bus_map_all_properties( |
| sd_bus *bus, |
| const char *destination, |
| const char *path, |
| const struct bus_properties_map *map, |
| unsigned flags, |
| sd_bus_error *error, |
| sd_bus_message **reply, |
| void *userdata) { |
| |
| _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
| int r; |
| |
| assert(bus); |
| assert(destination); |
| assert(path); |
| assert(map); |
| assert(reply || (flags & BUS_MAP_STRDUP)); |
| |
| r = sd_bus_call_method( |
| bus, |
| destination, |
| path, |
| "org.freedesktop.DBus.Properties", |
| "GetAll", |
| error, |
| &m, |
| "s", ""); |
| if (r < 0) |
| return r; |
| |
| r = bus_message_map_all_properties(m, map, flags, error, userdata); |
| if (r < 0) |
| return r; |
| |
| if (reply) |
| *reply = sd_bus_message_ref(m); |
| |
| return r; |
| } |