blob: 5cc8ce222d865f70b7228aaa4f6c8cab8aabe45c [file] [log] [blame] [raw]
/* SPDX-License-Identifier: LGPL-2.1+ */
#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;
}