#include "bus-internal.h"
#include "bus-message.h"
#include "bus-match.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "strv.h"
/* Example:
*
*/
static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
- return t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
+ return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
}
static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
struct bus_match_node *node,
enum bus_match_node_type parent_type,
uint8_t value_u8,
- const char *value_str) {
+ const char *value_str,
+ sd_bus_message *m) {
assert(node);
assert(node->type == BUS_MATCH_VALUE);
return node->value.u8 == value_u8;
case BUS_MATCH_SENDER:
+ if (streq_ptr(node->value.str, value_str))
+ return true;
+
+ if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
+ char **i;
+
+ /* on kdbus we have the well known names list
+ * in the credentials, let's make use of that
+ * for an accurate match */
+
+ STRV_FOREACH(i, m->creds.well_known_names)
+ if (streq_ptr(node->value.str, *i))
+ return true;
+
+ } else {
+
+ /* If we don't have kdbus, we don't know the
+ * well-known names of the senders. In that,
+ * let's just hope that dbus-daemon doesn't
+ * send us stuff we didn't want. */
+
+ if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
+ return true;
+ }
+
+ return false;
+
case BUS_MATCH_DESTINATION:
case BUS_MATCH_INTERFACE:
case BUS_MATCH_MEMBER:
/* Run the callback. And then invoke siblings. */
if (node->leaf.callback) {
- r = node->leaf.callback(bus, m, node->leaf.userdata);
+ _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+
+ r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
+ r = bus_maybe_reply_error(m, r, &error_buffer);
if (r != 0)
return r;
}
/* No hash table, so let's iterate manually... */
for (c = node->child; c; c = c->next) {
- if (!value_node_test(c, node->type, test_u8, test_str))
+ if (!value_node_test(c, node->type, test_u8, test_str, m))
continue;
r = bus_match_run(bus, c, m);
enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
assert(k);
- if (n == 4 && memcmp(k, "type", 4) == 0)
+ if (n == 4 && startswith(k, "type"))
return BUS_MATCH_MESSAGE_TYPE;
- if (n == 6 && memcmp(k, "sender", 6) == 0)
+ if (n == 6 && startswith(k, "sender"))
return BUS_MATCH_SENDER;
- if (n == 11 && memcmp(k, "destination", 11) == 0)
+ if (n == 11 && startswith(k, "destination"))
return BUS_MATCH_DESTINATION;
- if (n == 9 && memcmp(k, "interface", 9) == 0)
+ if (n == 9 && startswith(k, "interface"))
return BUS_MATCH_INTERFACE;
- if (n == 6 && memcmp(k, "member", 6) == 0)
+ if (n == 6 && startswith(k, "member"))
return BUS_MATCH_MEMBER;
- if (n == 4 && memcmp(k, "path", 4) == 0)
+ if (n == 4 && startswith(k, "path"))
return BUS_MATCH_PATH;
- if (n == 14 && memcmp(k, "path_namespace", 14) == 0)
+ if (n == 14 && startswith(k, "path_namespace"))
return BUS_MATCH_PATH_NAMESPACE;
- if (n == 4 && memcmp(k, "arg", 3) == 0) {
+ if (n == 4 && startswith(k, "arg")) {
int j;
j = undecchar(k[3]);
return BUS_MATCH_ARG + j;
}
- if (n == 5 && memcmp(k, "arg", 3) == 0) {
+ if (n == 5 && startswith(k, "arg")) {
int a, b;
enum bus_match_node_type t;
return t;
}
- if (n == 8 && memcmp(k, "arg", 3) == 0 && memcmp(k + 4, "path", 4) == 0) {
+ if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
int j;
j = undecchar(k[3]);
return BUS_MATCH_ARG_PATH + j;
}
- if (n == 9 && memcmp(k, "arg", 3) == 0 && memcmp(k + 5, "path", 4) == 0) {
+ if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
enum bus_match_node_type t;
int a, b;
return t;
}
- if (n == 13 && memcmp(k, "arg", 3) == 0 && memcmp(k + 4, "namespace", 9) == 0) {
+ if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
int j;
j = undecchar(k[3]);
return BUS_MATCH_ARG_NAMESPACE + j;
}
- if (n == 14 && memcmp(k, "arg", 3) == 0 && memcmp(k + 5, "namespace", 9) == 0) {
+ if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
enum bus_match_node_type t;
int a, b;
escaped = false;
}
+ if (!value) {
+ value = strdup("");
+ if (!value) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
if (t == BUS_MATCH_MESSAGE_TYPE) {
r = bus_message_type_from_string(value, &u);
if (r < 0)
}
/* Order the whole thing, so that we always generate the same tree */
- qsort(components, n_components, sizeof(struct bus_match_component), match_component_compare);
+ qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
/* Check for duplicates */
for (i = 0; i+1 < n_components; i++)
return r;
}
+char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
+ _cleanup_free_ FILE *f = NULL;
+ char *buffer = NULL;
+ size_t size = 0;
+ unsigned i;
+
+ if (n_components <= 0)
+ return strdup("");
+
+ assert(components);
+
+ f = open_memstream(&buffer, &size);
+ if (!f)
+ return NULL;
+
+ for (i = 0; i < n_components; i++) {
+ char buf[32];
+
+ if (i != 0)
+ fputc(',', f);
+
+ fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
+ fputc('=', f);
+ fputc('\'', f);
+
+ if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
+ fputs(bus_message_type_to_string(components[i].value_u8), f);
+ else
+ fputs(components[i].value_str, f);
+
+ fputc('\'', f);
+ }
+
+ fflush(f);
+ if (ferror(f))
+ return NULL;
+
+ return buffer;
+}
+
int bus_match_add(
struct bus_match_node *root,
struct bus_match_component *components,