bus-match.c revision 2a0e0692565f0435657c93498e09cbb2d3517152
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/***
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann This file is part of systemd.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann Copyright 2013 Lennart Poettering
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann systemd is free software; you can redistribute it and/or modify it
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann under the terms of the GNU Lesser General Public License as published by
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann the Free Software Foundation; either version 2.1 of the License, or
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann (at your option) any later version.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann systemd is distributed in the hope that it will be useful, but
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann WITHOUT ANY WARRANTY; without even the implied warranty of
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann Lesser General Public License for more details.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann You should have received a copy of the GNU Lesser General Public License
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann along with systemd; If not, see <http://www.gnu.org/licenses/>.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann***/
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann#include "bus-internal.h"
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann#include "bus-message.h"
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann#include "bus-match.h"
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/* Example:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * A: type=signal,sender=foo,interface=bar
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * B: type=signal,sender=quux,interface=fips
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * C: type=signal,sender=quux,interface=waldo
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * D: type=signal,member=test
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * E: sender=miau
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * F: type=signal
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * G: type=signal
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * results in this tree:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * BUS_MATCH_ROOT
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * + BUS_MATCH_MESSAGE_TYPE
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | ` BUS_MATCH_VALUE: value == signal
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | + DBUS_MATCH_SENDER
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | + BUS_MATCH_VALUE: value == foo
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | | ` DBUS_MATCH_INTERFACE
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | | ` BUS_MATCH_VALUE: value == bar
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | | ` BUS_MATCH_LEAF: A
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | ` BUS_MATCH_VALUE: value == quux
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | ` DBUS_MATCH_INTERFACE
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | | BUS_MATCH_VALUE: value == fips
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | | ` BUS_MATCH_LEAF: B
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | ` BUS_MATCH_VALUE: value == waldo
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | ` BUS_MATCH_LEAF: C
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | + DBUS_MATCH_MEMBER
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | ` BUS_MATCH_VALUE: value == test
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | | ` BUS_MATCH_LEAF: D
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | + BUS_MATCH_LEAF: F
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * | ` BUS_MATCH_LEAF: G
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * ` BUS_MATCH_SENDER
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * ` BUS_MATCH_VALUE: value == miau
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * ` BUS_MATCH_LEAF: E
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void bus_match_node_free(struct bus_match_node *node) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node->parent);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(!node->child);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node->type != BUS_MATCH_ROOT);
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (node->parent->child) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* We are apparently linked into the parent's child
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * list. Let's remove us from there. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (node->prev) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node->prev->next == node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann node->prev->next = node->next;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else {
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmann assert(node->parent->child == node);
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmann node->parent->child = node->next;
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmann if (node->next)
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmann node->next->prev = node->prev;
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (node->type == BUS_MATCH_VALUE) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* We might be in the parent's hash table, so clean
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * this up */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann hashmap_remove(node->parent->compare.children, node->value.str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(node->value.str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (BUS_MATCH_IS_COMPARE(node->type)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(hashmap_isempty(node->compare.children));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann hashmap_free(node->compare.children);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic bool bus_match_node_maybe_free(struct bus_match_node *node) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (node->child)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return true;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann bus_match_node_free(node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return true;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic bool value_node_test(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *node,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type parent_type,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint8_t value_u8,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *value_str) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node->type == BUS_MATCH_VALUE);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Tests parameters against this value node, doing prefix
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * magic and stuff. */
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann switch (parent_type) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_MESSAGE_TYPE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return node->value.u8 == value_u8;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_SENDER:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_DESTINATION:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_INTERFACE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_MEMBER:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_PATH:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return streq_ptr(node->value.str, value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return namespace_simple_pattern(node->value.str, value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_PATH_NAMESPACE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return path_simple_pattern(node->value.str, value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return path_complex_pattern(node->value.str, value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann default:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_not_reached("Invalid node type");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic bool value_node_same(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *node,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type parent_type,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint8_t value_u8,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *value_str) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Tests parameters against this value node, not doing prefix
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * magic and stuff, i.e. this one actually compares the match
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * itself.*/
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node->type == BUS_MATCH_VALUE);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann switch (parent_type) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_MESSAGE_TYPE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return node->value.u8 == value_u8;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_SENDER:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_DESTINATION:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_INTERFACE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_MEMBER:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_PATH:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_PATH_NAMESPACE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return streq(node->value.str, value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann default:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_not_reached("Invalid node type");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannint bus_match_run(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann sd_bus *bus,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *node,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann sd_bus_message *m) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *test_str = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint8_t test_u8 = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!node)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (bus && bus->match_callbacks_modified)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Not these special semantics: when traversing the tree we
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * usually let bus_match_run() when called for a node
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * recursively invoke bus_match_run(). There's are two
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * exceptions here though, which are BUS_NODE_ROOT (which
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * are invoked anyway by its parent. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann switch (node->type) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ROOT:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Run all children. Since we cannot have any siblings
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * we won't call any. The children of the root node
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * are compares or leaves, they will automatically
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * call their siblings. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_match_run(bus, node->child, m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_VALUE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Run all children. We don't execute any siblings, we
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * assume our caller does that. The children of value
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * nodes are compares or leaves, they will
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * automatically call their siblings */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(node->child);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_match_run(bus, node->child, m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_LEAF:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (bus) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (node->leaf.last_iteration == bus->iteration_counter)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann node->leaf.last_iteration = bus->iteration_counter;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_rewind(m, true);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Run the callback. And then invoke siblings. */
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann if (node->leaf.callback) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = node->leaf.callback(bus, m, node->leaf.userdata);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann if (r != 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann return bus_match_run(bus, node->next, m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_MESSAGE_TYPE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_u8 = m->header->type;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann case BUS_MATCH_SENDER:
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann test_str = m->sender;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann /* FIXME: resolve test_str from a well-known to a unique name first */
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann break;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann case BUS_MATCH_DESTINATION:
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann test_str = m->destination;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann break;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_INTERFACE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_str = m->interface;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_MEMBER:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_str = m->member;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_PATH:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_PATH_NAMESPACE:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_str = m->path;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann default:
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann assert_not_reached("Unknown match type.");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (BUS_MATCH_CAN_HASH(node->type)) {
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann struct bus_match_node *found;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann /* Lookup via hash table, nice! So let's jump directly. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (test_str)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann found = hashmap_get(node->compare.children, test_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann else if (node->type == BUS_MATCH_MESSAGE_TYPE)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann else
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann found = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (found) {
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann r = bus_match_run(bus, found, m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r != 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else {
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann struct bus_match_node *c;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann /* No hash table, so let's iterate manually... */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (c = node->child; c; c = c->next) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!value_node_test(c, node->type, test_u8, test_str))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann continue;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = bus_match_run(bus, c, m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r != 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (bus && bus->match_callbacks_modified)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* And now, let's invoke our siblings */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_match_run(bus, node->next, m);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int bus_match_add_compare_value(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *where,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type t,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint8_t value_u8,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *value_str,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node **ret) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *c = NULL, *n = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(where);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(BUS_MATCH_IS_COMPARE(t));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(ret);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (c = where->child; c && c->type != t; c = c->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann ;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (c) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Comparison node already exists? Then let's see if
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * the value node exists too. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t == BUS_MATCH_MESSAGE_TYPE)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann else if (BUS_MATCH_CAN_HASH(t))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n = hashmap_get(c->compare.children, value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann else {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann ;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *ret = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Comparison node, doesn't exist yet? Then let's
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * create it. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c = new0(struct bus_match_node, 1);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!c) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->type = t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->parent = where;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->next = where->child;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (c->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->next->prev = c;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann where->child = c;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t == BUS_MATCH_MESSAGE_TYPE) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!c->compare.children) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else if (BUS_MATCH_CAN_HASH(t)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->compare.children = hashmap_new(string_hash_func, string_compare_func);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!c->compare.children) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n = new0(struct bus_match_node, 1);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!n) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->type = BUS_MATCH_VALUE;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->value.u8 = value_u8;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (value_str) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->value.str = strdup(value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!n->value.str) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->parent = c;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (c->compare.children) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t == BUS_MATCH_MESSAGE_TYPE)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann else
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann r = hashmap_put(c->compare.children, n->value.str, n);
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->next = c->child;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->next->prev = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->child = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *ret = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 1;
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannfail:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (c)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann bus_match_node_maybe_free(c);
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann if (n) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(n->value.str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(n);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann return r;
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int bus_match_find_compare_value(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *where,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type t,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint8_t value_u8,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *value_str,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node **ret) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *c, *n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(where);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(BUS_MATCH_IS_COMPARE(t));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(ret);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann for (c = where->child; c && c->type != t; c = c->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann ;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!c)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t == BUS_MATCH_MESSAGE_TYPE)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann else if (BUS_MATCH_CAN_HASH(t))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n = hashmap_get(c->compare.children, value_str);
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann else {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann ;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *ret = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 1;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann}
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int bus_match_add_leaf(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *where,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann sd_bus_message_handler_t callback,
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann void *userdata,
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann uint64_t cookie,
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann struct bus_match_node **ret) {
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann struct bus_match_node *n;
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann assert(where);
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann assert(ret);
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann n = new0(struct bus_match_node, 1);
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann if (!n)
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann return -ENOMEM;
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann n->type = BUS_MATCH_LEAF;
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann n->parent = where;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->next = where->child;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n->next)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->next->prev = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->leaf.callback = callback;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->leaf.userdata = userdata;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n->leaf.cookie = cookie;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann where->child = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *ret = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 1;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmannstatic int bus_match_find_leaf(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *where,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann sd_bus_message_handler_t callback,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann void *userdata,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node **ret) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *c;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(where);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(ret);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (c = where->child; c; c = c->next) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (c->type == BUS_MATCH_LEAF &&
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann c->leaf.callback == callback &&
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann c->leaf.userdata == userdata) {
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann *ret = c;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann return 1;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann }
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann }
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann return 0;
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann}
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmannenum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann assert(k);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann if (n == 4 && startswith(k, "type"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_MESSAGE_TYPE;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 6 && startswith(k, "sender"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_SENDER;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 11 && startswith(k, "destination"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_DESTINATION;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 9 && startswith(k, "interface"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_INTERFACE;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 6 && startswith(k, "member"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_MEMBER;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 4 && startswith(k, "path"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_PATH;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 14 && startswith(k, "path_namespace"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_PATH_NAMESPACE;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 4 && startswith(k, "arg")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int j;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann j = undecchar(k[3]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (j < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_ARG + j;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 5 && startswith(k, "arg")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int a, b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann a = undecchar(k[3]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann b = undecchar(k[4]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (a <= 0 || b < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann t = BUS_MATCH_ARG + a * 10 + b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t > BUS_MATCH_ARG_LAST)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int j;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann j = undecchar(k[3]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (j < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_ARG_PATH + j;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int a, b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann a = undecchar(k[3]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann b = undecchar(k[4]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (a <= 0 || b < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann t = BUS_MATCH_ARG_PATH + a * 10 + b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t > BUS_MATCH_ARG_PATH_LAST)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int j;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann j = undecchar(k[3]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (j < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return BUS_MATCH_ARG_NAMESPACE + j;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int a, b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann a = undecchar(k[3]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann b = undecchar(k[4]);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (a <= 0 || b < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int match_component_compare(const void *a, const void *b) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const struct bus_match_component *x = a, *y = b;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (x->type < y->type)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -1;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (x->type > y->type)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 1;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannvoid bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned i;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (i = 0; i < n_components; i++)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(components[i].value_str);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(components);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannint bus_match_parse(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *match,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_component **_components,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned *_n_components) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *p = match;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_component *components = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann size_t components_allocated = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned n_components = 0, i;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_free_ char *value = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(match);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(_components);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(_n_components);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann while (*p != 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *eq, *q;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann enum bus_match_node_type t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned j = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann size_t value_allocated = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann bool escaped = false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint8_t u;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann eq = strchr(p, '=');
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!eq)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (eq[1] != '\'')
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann t = bus_match_node_type_from_string(p, eq - p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (q = eq + 2;; q++) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (*q == 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!escaped) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (*q == '\\') {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann escaped = true;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann continue;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (*q == '\'') {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (value)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann value[j] = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann value[j++] = *q;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann escaped = false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (t == BUS_MATCH_MESSAGE_TYPE) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = bus_message_type_from_string(value, &u);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann free(value);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann value = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann u = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -ENOMEM;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann components[n_components].type = t;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann components[n_components].value_str = value;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann components[n_components].value_u8 = u;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n_components++;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann value = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (q[1] == 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann break;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (q[1] != ',') {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann p = q + 2;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Order the whole thing, so that we always generate the same tree */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann qsort(components, n_components, sizeof(struct bus_match_component), match_component_compare);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Check for duplicates */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (i = 0; i+1 < n_components; i++)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (components[i].type == components[i+1].type) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = -EINVAL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann goto fail;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *_components = components;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *_n_components = n_components;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannfail:
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann bus_match_parse_free(components, n_components);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannint bus_match_add(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *root,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_component *components,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned n_components,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann sd_bus_message_handler_t callback,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann void *userdata,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint64_t cookie,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node **ret) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned i;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann int r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert(root);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n = root;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (i = 0; i < n_components; i++) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = bus_match_add_compare_value(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann n, components[i].type,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann components[i].value_u8, components[i].value_str, &n);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann }
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (r < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return r;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (ret)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann *ret = n;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann}
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannint bus_match_remove(
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_node *root,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct bus_match_component *components,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned n_components,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann sd_bus_message_handler_t callback,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann void *userdata,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann uint64_t *cookie) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann
unsigned i;
struct bus_match_node *n, **gc;
int r;
assert(root);
gc = newa(struct bus_match_node*, n_components);
n = root;
for (i = 0; i < n_components; i++) {
r = bus_match_find_compare_value(
n, components[i].type,
components[i].value_u8, components[i].value_str,
&n);
if (r <= 0)
return r;
gc[i] = n;
}
r = bus_match_find_leaf(n, callback, userdata, &n);
if (r <= 0)
return r;
if (cookie)
*cookie = n->leaf.cookie;
/* Free the leaf */
bus_match_node_free(n);
/* Prune the tree above */
for (i = n_components; i > 0; i --) {
struct bus_match_node *p = gc[i-1]->parent;
if (!bus_match_node_maybe_free(gc[i-1]))
break;
if (!bus_match_node_maybe_free(p))
break;
}
return r;
}
void bus_match_free(struct bus_match_node *node) {
struct bus_match_node *c;
if (!node)
return;
if (BUS_MATCH_CAN_HASH(node->type)) {
Iterator i;
HASHMAP_FOREACH(c, node->compare.children, i)
bus_match_free(c);
assert(hashmap_isempty(node->compare.children));
}
while ((c = node->child))
bus_match_free(c);
if (node->type != BUS_MATCH_ROOT)
bus_match_node_free(node);
}
const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
switch (t) {
case BUS_MATCH_ROOT:
return "root";
case BUS_MATCH_VALUE:
return "value";
case BUS_MATCH_LEAF:
return "leaf";
case BUS_MATCH_MESSAGE_TYPE:
return "type";
case BUS_MATCH_SENDER:
return "sender";
case BUS_MATCH_DESTINATION:
return "destination";
case BUS_MATCH_INTERFACE:
return "interface";
case BUS_MATCH_MEMBER:
return "member";
case BUS_MATCH_PATH:
return "path";
case BUS_MATCH_PATH_NAMESPACE:
return "path_namespace";
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
return buf;
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
return buf;
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
return buf;
default:
return NULL;
}
}
void bus_match_dump(struct bus_match_node *node, unsigned level) {
struct bus_match_node *c;
_cleanup_free_ char *pfx = NULL;
char buf[32];
if (!node)
return;
pfx = strrep(" ", level);
printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
if (node->type == BUS_MATCH_VALUE) {
if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
printf(" <%u>\n", node->value.u8);
else
printf(" <%s>\n", node->value.str);
} else if (node->type == BUS_MATCH_ROOT)
puts(" root");
else if (node->type == BUS_MATCH_LEAF)
printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
else
putchar('\n');
if (BUS_MATCH_CAN_HASH(node->type)) {
Iterator i;
HASHMAP_FOREACH(c, node->compare.children, i)
bus_match_dump(c, level + 1);
}
for (c = node->child; c; c = c->next)
bus_match_dump(c, level + 1);
}