X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-match.c;h=f7fca5f573de962ec250927bff15a84d648b6a3a;hp=fed25c1a2aeda0576e0a52818cf0a66ac0833746;hb=c1b9d935725103e95901f347b8981647ce4dd546;hpb=7286037fd438e93137571fa68a741cc894d8e549 diff --git a/src/libsystemd-bus/bus-match.c b/src/libsystemd-bus/bus-match.c index fed25c1a2..f7fca5f57 100644 --- a/src/libsystemd-bus/bus-match.c +++ b/src/libsystemd-bus/bus-match.c @@ -22,6 +22,8 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-match.h" +#include "bus-error.h" +#include "bus-util.h" /* Example: * @@ -60,7 +62,7 @@ */ 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) { @@ -142,11 +144,27 @@ static bool value_node_test( case BUS_MATCH_SENDER: case BUS_MATCH_DESTINATION: + if (streq_ptr(node->value.str, value_str)) + return true; + + /* FIXME: So here's an ugliness: if the match is for a + * well-known name then we cannot actually check this + * correctly here. This doesn't matter much for dbus1 + * where no false positives exist, hence we just + * ignore this case here. For kdbus the messages + * should contain all well-known names of the sender, + * hence we can fix things there correctly. */ + + if (node->value.str[0] != ':' && value_str && value_str[0] == ':') + return true; + + return false; + case BUS_MATCH_INTERFACE: case BUS_MATCH_MEMBER: case BUS_MATCH_PATH: case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: - return streq(node->value.str, value_str); + return streq_ptr(node->value.str, value_str); case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: return namespace_simple_pattern(node->value.str, value_str); @@ -199,7 +217,6 @@ static bool value_node_same( int bus_match_run( sd_bus *bus, struct bus_match_node *node, - int ret, sd_bus_message *m) { @@ -230,7 +247,7 @@ int bus_match_run( * we won't call any. The children of the root node * are compares or leaves, they will automatically * call their siblings. */ - return bus_match_run(bus, node->child, ret, m); + return bus_match_run(bus, node->child, m); case BUS_MATCH_VALUE: @@ -240,7 +257,7 @@ int bus_match_run( * automatically call their siblings */ assert(node->child); - return bus_match_run(bus, node->child, ret, m); + return bus_match_run(bus, node->child, m); case BUS_MATCH_LEAF: @@ -251,13 +268,21 @@ int bus_match_run( node->leaf.last_iteration = bus->iteration_counter; } - /* Run the callback. And then invoke siblings. */ - assert(node->leaf.callback); - r = node->leaf.callback(bus, ret, m, node->leaf.userdata); - if (r != 0) + r = sd_bus_message_rewind(m, true); + if (r < 0) return r; - return bus_match_run(bus, node->next, ret, m); + /* Run the callback. And then invoke siblings. */ + if (node->leaf.callback) { + _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; + } + + return bus_match_run(bus, node->next, m); case BUS_MATCH_MESSAGE_TYPE: test_u8 = m->header->type; @@ -314,7 +339,7 @@ int bus_match_run( found = NULL; if (found) { - r = bus_match_run(bus, found, ret, m); + r = bus_match_run(bus, found, m); if (r != 0) return r; } @@ -327,7 +352,7 @@ int bus_match_run( if (!value_node_test(c, node->type, test_u8, test_str)) continue; - r = bus_match_run(bus, c, ret, m); + r = bus_match_run(bus, c, m); if (r != 0) return r; } @@ -337,7 +362,7 @@ int bus_match_run( return 0; /* And now, let's invoke our siblings */ - return bus_match_run(bus, node->next, ret, m); + return bus_match_run(bus, node->next, m); } static int bus_match_add_compare_value( @@ -496,6 +521,7 @@ static int bus_match_add_leaf( struct bus_match_node *where, sd_bus_message_handler_t callback, void *userdata, + uint64_t cookie, struct bus_match_node **ret) { struct bus_match_node *n; @@ -515,6 +541,7 @@ static int bus_match_add_leaf( n->next->prev = n; n->leaf.callback = callback; n->leaf.userdata = userdata; + n->leaf.cookie = cookie; where->child = n; @@ -549,22 +576,22 @@ static int bus_match_find_leaf( 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]); @@ -574,7 +601,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n 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; @@ -590,7 +617,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n 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]); @@ -600,7 +627,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n 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; @@ -616,7 +643,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n 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]); @@ -626,7 +653,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n 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; @@ -645,14 +672,8 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return -EINVAL; } -struct match_component { - enum bus_match_node_type type; - uint8_t value_u8; - char *value_str; -}; - static int match_component_compare(const void *a, const void *b) { - const struct match_component *x = a, *y = b; + const struct bus_match_component *x = a, *y = b; if (x->type < y->type) return -1; @@ -662,7 +683,7 @@ static int match_component_compare(const void *a, const void *b) { return 0; } -static void free_components(struct match_component *components, unsigned n_components) { +void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) { unsigned i; for (i = 0; i < n_components; i++) @@ -671,13 +692,13 @@ static void free_components(struct match_component *components, unsigned n_compo free(components); } -static int parse_match( +int bus_match_parse( const char *match, - struct match_component **_components, + struct bus_match_component **_components, unsigned *_n_components) { const char *p = match; - struct match_component *components = NULL; + struct bus_match_component *components = NULL; size_t components_allocated = 0; unsigned n_components = 0, i; _cleanup_free_ char *value = NULL; @@ -725,7 +746,7 @@ static int parse_match( } } - if (!greedy_realloc((void**) &value, &value_allocated, j + 2)) { + if (!GREEDY_REALLOC(value, value_allocated, j + 2)) { r = -ENOMEM; goto fail; } @@ -744,8 +765,7 @@ static int parse_match( } else u = 0; - if (!greedy_realloc((void**) &components, &components_allocated, - (n_components + 1) * sizeof(struct match_component))) { + if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) { r = -ENOMEM; goto fail; } @@ -769,7 +789,7 @@ static int parse_match( } /* Order the whole thing, so that we always generate the same tree */ - qsort(components, n_components, sizeof(struct 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++) @@ -784,29 +804,24 @@ static int parse_match( return 0; fail: - free_components(components, n_components); + bus_match_parse_free(components, n_components); return r; } int bus_match_add( struct bus_match_node *root, - const char *match, + struct bus_match_component *components, + unsigned n_components, sd_bus_message_handler_t callback, void *userdata, + uint64_t cookie, struct bus_match_node **ret) { - struct match_component *components = NULL; - unsigned n_components = 0, i; + unsigned i; struct bus_match_node *n; int r; assert(root); - assert(match); - assert(callback); - - r = parse_match(match, &components, &n_components); - if (r < 0) - return r; n = root; for (i = 0; i < n_components; i++) { @@ -814,38 +829,32 @@ int bus_match_add( n, components[i].type, components[i].value_u8, components[i].value_str, &n); if (r < 0) - goto finish; + return r; } - r = bus_match_add_leaf(n, callback, userdata, &n); + r = bus_match_add_leaf(n, callback, userdata, cookie, &n); if (r < 0) - goto finish; + return r; if (ret) *ret = n; -finish: - free_components(components, n_components); - return r; + return 0; } int bus_match_remove( struct bus_match_node *root, - const char *match, + struct bus_match_component *components, + unsigned n_components, sd_bus_message_handler_t callback, - void *userdata) { + void *userdata, + uint64_t *cookie) { - struct match_component *components = NULL; - unsigned n_components = 0, i; + unsigned i; struct bus_match_node *n, **gc; int r; assert(root); - assert(match); - - r = parse_match(match, &components, &n_components); - if (r < 0) - return r; gc = newa(struct bus_match_node*, n_components); @@ -856,14 +865,17 @@ int bus_match_remove( components[i].value_u8, components[i].value_str, &n); if (r <= 0) - goto finish; + return r; gc[i] = n; } r = bus_match_find_leaf(n, callback, userdata, &n); if (r <= 0) - goto finish; + return r; + + if (cookie) + *cookie = n->leaf.cookie; /* Free the leaf */ bus_match_node_free(n); @@ -879,8 +891,6 @@ int bus_match_remove( break; } -finish: - free_components(components, n_components); return r; }