break;
}
- case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
+ case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
+ char buf[sizeof("arg")-1 + 2 + sizeof("has")];
+
+ xsprintf(buf, "arg%ihas", c->type - BUS_MATCH_ARG_HAS);
+ bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
+ using_bloom = true;
+ break;
+ }
+
+ case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
/*
* XXX: DBus spec defines arg[0..63]path= matching to be
* a two-way glob. That is, if either string is a prefix
* to properly support multiple-matches here.
*/
break;
- }
case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
break;
}
- case BUS_MATCH_DESTINATION: {
+ case BUS_MATCH_DESTINATION:
/*
* Kernel only supports matching on destination IDs, but
* not on destination names. So just skip the
matches_name_change = false;
break;
- }
case BUS_MATCH_ROOT:
case BUS_MATCH_VALUE:
bloom_add_prefixes(data, size, n_hash, buf, t, '/');
}
+static void add_bloom_arg_has(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) {
+ char buf[sizeof("arg")-1 + 2 + sizeof("has")];
+ char *e;
+
+ assert(data);
+ assert(size > 0);
+ assert(i < 64);
+ assert(t);
+
+ e = stpcpy(buf, "arg");
+ if (i < 10)
+ *(e++) = '0' + (char) i;
+ else {
+ *(e++) = '0' + (char) (i / 10);
+ *(e++) = '0' + (char) (i % 10);
+ }
+
+ strcpy(e, "has");
+ bloom_add_pair(data, size, n_hash, buf, t);
+}
+
static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
void *data;
unsigned i;
return r;
while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0)
- add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
+ add_bloom_arg_has(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
if (r < 0)
return r;
*/
static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
- return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
+ return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
}
static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
- (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
+ (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
+ (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
}
static void bus_match_node_free(struct bus_match_node *node) {
case BUS_MATCH_INTERFACE:
case BUS_MATCH_MEMBER:
case BUS_MATCH_PATH:
- case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
- char **i;
+ case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
if (value_str)
return streq_ptr(node->value.str, value_str);
+ return false;
+
+ case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
+ char **i;
+
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;
-
+ case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
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:
return path_simple_pattern(node->value.str, value_str);
- case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
- char **i;
-
+ case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
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:
assert_not_reached("Invalid node type");
case BUS_MATCH_MEMBER:
case BUS_MATCH_PATH:
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
+ case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
case BUS_MATCH_PATH_NAMESPACE:
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
break;
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
- (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
break;
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
- (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
break;
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
- (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
+ break;
+
+ case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
+ (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
break;
default:
return t;
}
+ if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
+ int j;
+
+ j = undecchar(k[3]);
+ if (j < 0)
+ return -EINVAL;
+
+ return BUS_MATCH_ARG_HAS + j;
+ }
+
+ if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
+ enum bus_match_node_type t;
+ int a, b;
+
+ a = undecchar(k[3]);
+ b = undecchar(k[4]);
+ if (a <= 0 || b < 0)
+ return -EINVAL;
+
+ t = BUS_MATCH_ARG_HAS + a * 10 + b;
+ if (t > BUS_MATCH_ARG_HAS_LAST)
+ return -EINVAL;
+
+ return t;
+ }
+
return -EINVAL;
}
snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
return buf;
+ case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
+ snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
+ return buf;
+
default:
return NULL;
}
BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63,
BUS_MATCH_ARG_NAMESPACE,
BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63,
+ BUS_MATCH_ARG_HAS,
+ BUS_MATCH_ARG_HAS_LAST = BUS_MATCH_ARG_HAS + 63,
_BUS_MATCH_NODE_TYPE_MAX,
_BUS_MATCH_NODE_TYPE_INVALID = -1
};
return 1;
}
-int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv) {
- const char *contents;
+static int bus_message_get_arg_skip(
+ sd_bus_message *m,
+ unsigned i,
+ char *_type,
+ const char **_contents) {
+
unsigned j;
- char type;
int r;
- assert(m);
- assert(str);
- assert(strv);
-
r = sd_bus_message_rewind(m, true);
if (r < 0)
return r;
for (j = 0;; j++) {
+ const char *contents;
+ char type;
+
r = sd_bus_message_peek_type(m, &type, &contents);
if (r < 0)
return r;
!(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
return -ENXIO;
- if (j >= i)
- break;
+ if (j >= i) {
+ if (_contents)
+ *_contents = contents;
+ if (_type)
+ *_type = type;
+ return 0;
+ }
r = sd_bus_message_skip(m, NULL);
if (r < 0)
return r;
}
- if (type == SD_BUS_TYPE_ARRAY) {
+}
- r = sd_bus_message_read_strv(m, strv);
- if (r < 0)
- return r;
+int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) {
+ char type;
+ int r;
- *str = NULL;
+ assert(m);
+ assert(str);
- } else {
- r = sd_bus_message_read_basic(m, type, str);
- if (r < 0)
- return r;
+ r = bus_message_get_arg_skip(m, i, &type, NULL);
+ if (r < 0)
+ return r;
- *strv = NULL;
- }
+ if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE))
+ return -ENXIO;
- return 0;
+ return sd_bus_message_read_basic(m, type, str);
+}
+
+int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) {
+ const char *contents;
+ char type;
+ int r;
+
+ assert(m);
+ assert(strv);
+
+ r = bus_message_get_arg_skip(m, i, &type, &contents);
+ if (r < 0)
+ return r;
+
+ if (type != SD_BUS_TYPE_ARRAY)
+ return -ENXIO;
+ if (!STR_IN_SET(contents, "s", "o", "g"))
+ return -ENXIO;
+
+ return sd_bus_message_read_strv(m, strv);
}
_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
const char *label,
sd_bus_message **ret);
-int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv);
+int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str);
+int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv);
int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Pi_ep'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foobar'", true);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foo_bar'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foo_bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foo_bar'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
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,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);
+ assert_se(match_add(slots, &root, "arg4has='pi'", 15) >= 0);
+ assert_se(match_add(slots, &root, "arg4has='pa'", 16) >= 0);
+ assert_se(match_add(slots, &root, "arg4has='po'", 17) >= 0);
+ assert_se(match_add(slots, &root, "arg4='pi'", 18) >= 0);
bus_match_dump(&root, 0);