mirror of
https://github.com/systemd/systemd.git
synced 2024-11-02 10:51:20 +03:00
sd-bus: add support for matches against arrays of strings in messages
This commit is contained in:
parent
d9fba53316
commit
198b158f49
@ -134,6 +134,7 @@ static bool value_node_test(
|
|||||||
enum bus_match_node_type parent_type,
|
enum bus_match_node_type parent_type,
|
||||||
uint8_t value_u8,
|
uint8_t value_u8,
|
||||||
const char *value_str,
|
const char *value_str,
|
||||||
|
char **value_strv,
|
||||||
sd_bus_message *m) {
|
sd_bus_message *m) {
|
||||||
|
|
||||||
assert(node);
|
assert(node);
|
||||||
@ -179,17 +180,46 @@ static bool value_node_test(
|
|||||||
case BUS_MATCH_INTERFACE:
|
case BUS_MATCH_INTERFACE:
|
||||||
case BUS_MATCH_MEMBER:
|
case BUS_MATCH_MEMBER:
|
||||||
case BUS_MATCH_PATH:
|
case BUS_MATCH_PATH:
|
||||||
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
|
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
|
||||||
return streq_ptr(node->value.str, value_str);
|
char **i;
|
||||||
|
|
||||||
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
|
if (value_str)
|
||||||
return namespace_simple_pattern(node->value.str, value_str);
|
return streq_ptr(node->value.str, value_str);
|
||||||
|
|
||||||
|
STRV_FOREACH(i, value_strv)
|
||||||
|
if (streq_ptr(node->value.str, *i))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
|
||||||
|
char **i;
|
||||||
|
|
||||||
|
if (value_str)
|
||||||
|
return namespace_simple_pattern(node->value.str, value_str);
|
||||||
|
|
||||||
|
STRV_FOREACH(i, value_strv)
|
||||||
|
if (namespace_simple_pattern(node->value.str, *i))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
case BUS_MATCH_PATH_NAMESPACE:
|
case BUS_MATCH_PATH_NAMESPACE:
|
||||||
return path_simple_pattern(node->value.str, value_str);
|
return path_simple_pattern(node->value.str, value_str);
|
||||||
|
|
||||||
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
|
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
|
||||||
return path_complex_pattern(node->value.str, value_str);
|
char **i;
|
||||||
|
|
||||||
|
if (value_str)
|
||||||
|
return path_complex_pattern(node->value.str, value_str);
|
||||||
|
|
||||||
|
STRV_FOREACH(i, value_strv)
|
||||||
|
if (path_complex_pattern(node->value.str, *i))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert_not_reached("Invalid node type");
|
assert_not_reached("Invalid node type");
|
||||||
@ -235,7 +265,7 @@ int bus_match_run(
|
|||||||
struct bus_match_node *node,
|
struct bus_match_node *node,
|
||||||
sd_bus_message *m) {
|
sd_bus_message *m) {
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **test_strv = NULL;
|
||||||
const char *test_str = NULL;
|
const char *test_str = NULL;
|
||||||
uint8_t test_u8 = 0;
|
uint8_t test_u8 = 0;
|
||||||
int r;
|
int r;
|
||||||
@ -343,15 +373,15 @@ int bus_match_run(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
|
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
|
||||||
test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
|
(void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
|
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
|
||||||
test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
|
(void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
|
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
|
||||||
test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
|
(void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -365,7 +395,20 @@ int bus_match_run(
|
|||||||
|
|
||||||
if (test_str)
|
if (test_str)
|
||||||
found = hashmap_get(node->compare.children, test_str);
|
found = hashmap_get(node->compare.children, test_str);
|
||||||
else if (node->type == BUS_MATCH_MESSAGE_TYPE)
|
else if (test_strv) {
|
||||||
|
char **i;
|
||||||
|
|
||||||
|
STRV_FOREACH(i, test_strv) {
|
||||||
|
found = hashmap_get(node->compare.children, *i);
|
||||||
|
if (found) {
|
||||||
|
r = bus_match_run(bus, found, m);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found = NULL;
|
||||||
|
} else if (node->type == BUS_MATCH_MESSAGE_TYPE)
|
||||||
found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
|
found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
|
||||||
else
|
else
|
||||||
found = NULL;
|
found = NULL;
|
||||||
@ -381,7 +424,7 @@ int bus_match_run(
|
|||||||
/* No hash table, so let's iterate manually... */
|
/* No hash table, so let's iterate manually... */
|
||||||
|
|
||||||
for (c = node->child; c; c = c->next) {
|
for (c = node->child; c; c = c->next) {
|
||||||
if (!value_node_test(c, node->type, test_u8, test_str, m))
|
if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = bus_match_run(bus, c, m);
|
r = bus_match_run(bus, c, m);
|
||||||
|
@ -5333,35 +5333,57 @@ _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
|
int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv) {
|
||||||
int r;
|
const char *contents;
|
||||||
const char *t = NULL;
|
|
||||||
unsigned j;
|
unsigned j;
|
||||||
|
char type;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
assert(str);
|
||||||
|
assert(strv);
|
||||||
|
|
||||||
r = sd_bus_message_rewind(m, true);
|
r = sd_bus_message_rewind(m, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return NULL;
|
return r;
|
||||||
|
|
||||||
for (j = 0; j <= i; j++) {
|
for (j = 0;; j++) {
|
||||||
char type;
|
r = sd_bus_message_peek_type(m, &type, &contents);
|
||||||
|
|
||||||
r = sd_bus_message_peek_type(m, &type, NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return NULL;
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
if (type != SD_BUS_TYPE_STRING &&
|
/* Don't match against arguments after the first one we don't understand */
|
||||||
type != SD_BUS_TYPE_OBJECT_PATH &&
|
if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
|
||||||
type != SD_BUS_TYPE_SIGNATURE)
|
!(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
|
||||||
return NULL;
|
return -ENXIO;
|
||||||
|
|
||||||
r = sd_bus_message_read_basic(m, type, &t);
|
if (j >= i)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r = sd_bus_message_skip(m, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return NULL;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
if (type == SD_BUS_TYPE_ARRAY) {
|
||||||
|
|
||||||
|
r = sd_bus_message_read_strv(m, strv);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*str = NULL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
r = sd_bus_message_read_basic(m, type, str);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*strv = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bus_header_is_complete(struct bus_header *h, size_t size) {
|
bool bus_header_is_complete(struct bus_header *h, size_t size) {
|
||||||
|
@ -223,7 +223,7 @@ int bus_message_from_malloc(
|
|||||||
const char *label,
|
const char *label,
|
||||||
sd_bus_message **ret);
|
sd_bus_message **ret);
|
||||||
|
|
||||||
const char* bus_message_get_arg(sd_bus_message *m, unsigned i);
|
int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv);
|
||||||
|
|
||||||
int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
|
int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
|
||||||
|
|
||||||
|
@ -33,8 +33,9 @@
|
|||||||
static bool mask[32];
|
static bool mask[32];
|
||||||
|
|
||||||
static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||||
log_info("Ran %i", PTR_TO_INT(userdata));
|
log_info("Ran %u", PTR_TO_UINT(userdata));
|
||||||
mask[PTR_TO_INT(userdata)] = true;
|
assert(PTR_TO_UINT(userdata) < ELEMENTSOF(mask));
|
||||||
|
mask[PTR_TO_UINT(userdata)] = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,9 +86,9 @@ int main(int argc, char *argv[]) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
||||||
_cleanup_bus_unref_ sd_bus *bus = NULL;
|
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
|
||||||
enum bus_match_node_type i;
|
enum bus_match_node_type i;
|
||||||
sd_bus_slot slots[15];
|
sd_bus_slot slots[19];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = sd_bus_open_system(&bus);
|
r = sd_bus_open_system(&bus);
|
||||||
@ -108,16 +109,20 @@ int main(int argc, char *argv[]) {
|
|||||||
assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0);
|
assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0);
|
||||||
assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
|
assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
|
||||||
assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
|
assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
|
||||||
|
assert_se(match_add(slots, &root, "arg4='pi'", 15) >= 0);
|
||||||
|
assert_se(match_add(slots, &root, "arg4='pa'", 16) >= 0);
|
||||||
|
assert_se(match_add(slots, &root, "arg4='po'", 17) >= 0);
|
||||||
|
assert_se(match_add(slots, &root, "arg4='pu'", 18) >= 0);
|
||||||
|
|
||||||
bus_match_dump(&root, 0);
|
bus_match_dump(&root, 0);
|
||||||
|
|
||||||
assert_se(sd_bus_message_new_signal(bus, &m, "/foo/bar", "bar.x", "waldo") >= 0);
|
assert_se(sd_bus_message_new_signal(bus, &m, "/foo/bar", "bar.x", "waldo") >= 0);
|
||||||
assert_se(sd_bus_message_append(m, "ssss", "one", "two", "/prefix/three", "prefix.four") >= 0);
|
assert_se(sd_bus_message_append(m, "ssssas", "one", "two", "/prefix/three", "prefix.four", 3, "pi", "pa", "po") >= 0);
|
||||||
assert_se(bus_message_seal(m, 1, 0) >= 0);
|
assert_se(bus_message_seal(m, 1, 0) >= 0);
|
||||||
|
|
||||||
zero(mask);
|
zero(mask);
|
||||||
assert_se(bus_match_run(NULL, &root, m) == 0);
|
assert_se(bus_match_run(NULL, &root, m) == 0);
|
||||||
assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
|
assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14, 15, 16, 17 }, 11));
|
||||||
|
|
||||||
assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0);
|
assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0);
|
||||||
assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0);
|
assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0);
|
||||||
@ -126,7 +131,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
zero(mask);
|
zero(mask);
|
||||||
assert_se(bus_match_run(NULL, &root, m) == 0);
|
assert_se(bus_match_run(NULL, &root, m) == 0);
|
||||||
assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7 }, 6));
|
assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7, 15, 16, 17 }, 9));
|
||||||
|
|
||||||
for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
|
for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
Loading…
Reference in New Issue
Block a user