LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-match.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 451 572 78.8 %
Date: 2019-08-23 13:36:53 Functions: 19 20 95.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 359 518 69.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "alloc-util.h"
       4                 :            : #include "bus-internal.h"
       5                 :            : #include "bus-match.h"
       6                 :            : #include "bus-message.h"
       7                 :            : #include "bus-util.h"
       8                 :            : #include "fd-util.h"
       9                 :            : #include "fileio.h"
      10                 :            : #include "hexdecoct.h"
      11                 :            : #include "sort-util.h"
      12                 :            : #include "string-util.h"
      13                 :            : #include "strv.h"
      14                 :            : 
      15                 :            : /* Example:
      16                 :            :  *
      17                 :            :  *  A: type=signal,sender=foo,interface=bar
      18                 :            :  *  B: type=signal,sender=quux,interface=fips
      19                 :            :  *  C: type=signal,sender=quux,interface=waldo
      20                 :            :  *  D: type=signal,member=test
      21                 :            :  *  E: sender=miau
      22                 :            :  *  F: type=signal
      23                 :            :  *  G: type=signal
      24                 :            :  *
      25                 :            :  *  results in this tree:
      26                 :            :  *
      27                 :            :  *  BUS_MATCH_ROOT
      28                 :            :  *  + BUS_MATCH_MESSAGE_TYPE
      29                 :            :  *  | ` BUS_MATCH_VALUE: value == signal
      30                 :            :  *  |   + DBUS_MATCH_SENDER
      31                 :            :  *  |   | + BUS_MATCH_VALUE: value == foo
      32                 :            :  *  |   | | ` DBUS_MATCH_INTERFACE
      33                 :            :  *  |   | |   ` BUS_MATCH_VALUE: value == bar
      34                 :            :  *  |   | |     ` BUS_MATCH_LEAF: A
      35                 :            :  *  |   | ` BUS_MATCH_VALUE: value == quux
      36                 :            :  *  |   |   ` DBUS_MATCH_INTERFACE
      37                 :            :  *  |   |     | BUS_MATCH_VALUE: value == fips
      38                 :            :  *  |   |     | ` BUS_MATCH_LEAF: B
      39                 :            :  *  |   |     ` BUS_MATCH_VALUE: value == waldo
      40                 :            :  *  |   |       ` BUS_MATCH_LEAF: C
      41                 :            :  *  |   + DBUS_MATCH_MEMBER
      42                 :            :  *  |   | ` BUS_MATCH_VALUE: value == test
      43                 :            :  *  |   |   ` BUS_MATCH_LEAF: D
      44                 :            :  *  |   + BUS_MATCH_LEAF: F
      45                 :            :  *  |   ` BUS_MATCH_LEAF: G
      46                 :            :  *  ` BUS_MATCH_SENDER
      47                 :            :  *    ` BUS_MATCH_VALUE: value == miau
      48                 :            :  *      ` BUS_MATCH_LEAF: E
      49                 :            :  */
      50                 :            : 
      51                 :       3088 : static bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
      52   [ +  +  +  - ]:       3088 :         return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
      53                 :            : }
      54                 :            : 
      55                 :       2245 : static bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
      56   [ +  +  +  + ]:       2245 :         return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
      57   [ +  +  +  +  :       4534 :                 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
                   +  + ]
      58         [ +  - ]:         44 :                 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
      59                 :            : }
      60                 :            : 
      61                 :       1376 : static void bus_match_node_free(struct bus_match_node *node) {
      62         [ -  + ]:       1376 :         assert(node);
      63         [ -  + ]:       1376 :         assert(node->parent);
      64         [ -  + ]:       1376 :         assert(!node->child);
      65         [ -  + ]:       1376 :         assert(node->type != BUS_MATCH_ROOT);
      66         [ -  + ]:       1376 :         assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
      67                 :            : 
      68         [ +  + ]:       1376 :         if (node->parent->child) {
      69                 :            :                 /* We are apparently linked into the parent's child
      70                 :            :                  * list. Let's remove us from there. */
      71         [ +  + ]:        844 :                 if (node->prev) {
      72         [ -  + ]:          4 :                         assert(node->prev->next == node);
      73                 :          4 :                         node->prev->next = node->next;
      74                 :            :                 } else {
      75         [ -  + ]:        840 :                         assert(node->parent->child == node);
      76                 :        840 :                         node->parent->child = node->next;
      77                 :            :                 }
      78                 :            : 
      79         [ +  + ]:        844 :                 if (node->next)
      80                 :         96 :                         node->next->prev = node->prev;
      81                 :            :         }
      82                 :            : 
      83         [ +  + ]:       1376 :         if (node->type == BUS_MATCH_VALUE) {
      84                 :            :                 /* We might be in the parent's hash table, so clean
      85                 :            :                  * this up */
      86                 :            : 
      87         [ +  + ]:        608 :                 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
      88                 :        120 :                         hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
      89   [ +  +  +  - ]:        488 :                 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
      90                 :        412 :                         hashmap_remove(node->parent->compare.children, node->value.str);
      91                 :            : 
      92                 :        608 :                 free(node->value.str);
      93                 :            :         }
      94                 :            : 
      95         [ +  + ]:       1376 :         if (BUS_MATCH_IS_COMPARE(node->type)) {
      96         [ -  + ]:        576 :                 assert(hashmap_isempty(node->compare.children));
      97                 :        576 :                 hashmap_free(node->compare.children);
      98                 :            :         }
      99                 :            : 
     100                 :       1376 :         free(node);
     101                 :       1376 : }
     102                 :            : 
     103                 :       1168 : static bool bus_match_node_maybe_free(struct bus_match_node *node) {
     104         [ -  + ]:       1168 :         assert(node);
     105                 :            : 
     106         [ +  + ]:       1168 :         if (node->type == BUS_MATCH_ROOT)
     107                 :        112 :                 return false;
     108                 :            : 
     109         [ +  + ]:       1056 :         if (node->child)
     110                 :         16 :                 return false;
     111                 :            : 
     112   [ +  +  +  + ]:       1040 :         if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
     113                 :          8 :                 return true;
     114                 :            : 
     115                 :       1032 :         bus_match_node_free(node);
     116                 :       1032 :         return true;
     117                 :            : }
     118                 :            : 
     119                 :         59 : static bool value_node_test(
     120                 :            :                 struct bus_match_node *node,
     121                 :            :                 enum bus_match_node_type parent_type,
     122                 :            :                 uint8_t value_u8,
     123                 :            :                 const char *value_str,
     124                 :            :                 char **value_strv,
     125                 :            :                 sd_bus_message *m) {
     126                 :            : 
     127         [ -  + ]:         59 :         assert(node);
     128         [ -  + ]:         59 :         assert(node->type == BUS_MATCH_VALUE);
     129                 :            : 
     130                 :            :         /* Tests parameters against this value node, doing prefix
     131                 :            :          * magic and stuff. */
     132                 :            : 
     133   [ -  +  -  -  :         59 :         switch (parent_type) {
             +  +  +  - ]
     134                 :            : 
     135                 :          0 :         case BUS_MATCH_MESSAGE_TYPE:
     136                 :          0 :                 return node->value.u8 == value_u8;
     137                 :            : 
     138                 :         31 :         case BUS_MATCH_SENDER:
     139         [ +  + ]:         31 :                 if (streq_ptr(node->value.str, value_str))
     140                 :         12 :                         return true;
     141                 :            : 
     142         [ -  + ]:         19 :                 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
     143                 :            :                         char **i;
     144                 :            : 
     145                 :            :                         /* on kdbus we have the well known names list
     146                 :            :                          * in the credentials, let's make use of that
     147                 :            :                          * for an accurate match */
     148                 :            : 
     149   [ #  #  #  # ]:          0 :                         STRV_FOREACH(i, m->creds.well_known_names)
     150         [ #  # ]:          0 :                                 if (streq_ptr(node->value.str, *i))
     151                 :          0 :                                         return true;
     152                 :            : 
     153                 :            :                 } else {
     154                 :            : 
     155                 :            :                         /* If we don't have kdbus, we don't know the
     156                 :            :                          * well-known names of the senders. In that,
     157                 :            :                          * let's just hope that dbus-daemon doesn't
     158                 :            :                          * send us stuff we didn't want. */
     159                 :            : 
     160   [ +  -  +  +  :         19 :                         if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
                   -  + ]
     161                 :          0 :                                 return true;
     162                 :            :                 }
     163                 :            : 
     164                 :         19 :                 return false;
     165                 :            : 
     166                 :          0 :         case BUS_MATCH_DESTINATION:
     167                 :            :         case BUS_MATCH_INTERFACE:
     168                 :            :         case BUS_MATCH_MEMBER:
     169                 :            :         case BUS_MATCH_PATH:
     170                 :            :         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
     171                 :            : 
     172         [ #  # ]:          0 :                 if (value_str)
     173                 :          0 :                         return streq_ptr(node->value.str, value_str);
     174                 :            : 
     175                 :          0 :                 return false;
     176                 :            : 
     177                 :          0 :         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
     178                 :            :                 char **i;
     179                 :            : 
     180   [ #  #  #  # ]:          0 :                 STRV_FOREACH(i, value_strv)
     181         [ #  # ]:          0 :                         if (streq_ptr(node->value.str, *i))
     182                 :          0 :                                 return true;
     183                 :            : 
     184                 :          0 :                 return false;
     185                 :            :         }
     186                 :            : 
     187                 :          8 :         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
     188         [ +  - ]:          8 :                 if (value_str)
     189                 :          8 :                         return namespace_simple_pattern(node->value.str, value_str);
     190                 :            : 
     191                 :          0 :                 return false;
     192                 :            : 
     193                 :         16 :         case BUS_MATCH_PATH_NAMESPACE:
     194                 :         16 :                 return path_simple_pattern(node->value.str, value_str);
     195                 :            : 
     196                 :          4 :         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
     197         [ +  - ]:          4 :                 if (value_str)
     198                 :          4 :                         return path_complex_pattern(node->value.str, value_str);
     199                 :            : 
     200                 :          0 :                 return false;
     201                 :            : 
     202                 :          0 :         default:
     203                 :          0 :                 assert_not_reached("Invalid node type");
     204                 :            :         }
     205                 :            : }
     206                 :            : 
     207                 :         20 : static bool value_node_same(
     208                 :            :                 struct bus_match_node *node,
     209                 :            :                 enum bus_match_node_type parent_type,
     210                 :            :                 uint8_t value_u8,
     211                 :            :                 const char *value_str) {
     212                 :            : 
     213                 :            :         /* Tests parameters against this value node, not doing prefix
     214                 :            :          * magic and stuff, i.e. this one actually compares the match
     215                 :            :          * itself. */
     216                 :            : 
     217         [ -  + ]:         20 :         assert(node);
     218         [ -  + ]:         20 :         assert(node->type == BUS_MATCH_VALUE);
     219                 :            : 
     220      [ -  +  - ]:         20 :         switch (parent_type) {
     221                 :            : 
     222                 :          0 :         case BUS_MATCH_MESSAGE_TYPE:
     223                 :          0 :                 return node->value.u8 == value_u8;
     224                 :            : 
     225                 :         20 :         case BUS_MATCH_SENDER:
     226                 :            :         case BUS_MATCH_DESTINATION:
     227                 :            :         case BUS_MATCH_INTERFACE:
     228                 :            :         case BUS_MATCH_MEMBER:
     229                 :            :         case BUS_MATCH_PATH:
     230                 :            :         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
     231                 :            :         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
     232                 :            :         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
     233                 :            :         case BUS_MATCH_PATH_NAMESPACE:
     234                 :            :         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
     235                 :         20 :                 return streq(node->value.str, value_str);
     236                 :            : 
     237                 :          0 :         default:
     238                 :          0 :                 assert_not_reached("Invalid node type");
     239                 :            :         }
     240                 :            : }
     241                 :            : 
     242                 :       1305 : int bus_match_run(
     243                 :            :                 sd_bus *bus,
     244                 :            :                 struct bus_match_node *node,
     245                 :            :                 sd_bus_message *m) {
     246                 :            : 
     247                 :       1305 :         _cleanup_strv_free_ char **test_strv = NULL;
     248                 :       1305 :         const char *test_str = NULL;
     249                 :       1305 :         uint8_t test_u8 = 0;
     250                 :            :         int r;
     251                 :            : 
     252         [ -  + ]:       1305 :         assert(m);
     253                 :            : 
     254         [ +  + ]:       1305 :         if (!node)
     255                 :        446 :                 return 0;
     256                 :            : 
     257   [ +  +  -  + ]:        859 :         if (bus && bus->match_callbacks_modified)
     258                 :          0 :                 return 0;
     259                 :            : 
     260                 :            :         /* Not these special semantics: when traversing the tree we
     261                 :            :          * usually let bus_match_run() when called for a node
     262                 :            :          * recursively invoke bus_match_run(). There's are two
     263                 :            :          * exceptions here though, which are BUS_NODE_ROOT (which
     264                 :            :          * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
     265                 :            :          * are invoked anyway by its parent. */
     266                 :            : 
     267   [ +  +  +  +  :        859 :         switch (node->type) {
          +  -  +  +  +  
             +  +  +  +  
                      - ]
     268                 :            : 
     269                 :        259 :         case BUS_MATCH_ROOT:
     270                 :            : 
     271                 :            :                 /* Run all children. Since we cannot have any siblings
     272                 :            :                  * we won't call any. The children of the root node
     273                 :            :                  * are compares or leaves, they will automatically
     274                 :            :                  * call their siblings. */
     275                 :        259 :                 return bus_match_run(bus, node->child, m);
     276                 :            : 
     277                 :        215 :         case BUS_MATCH_VALUE:
     278                 :            : 
     279                 :            :                 /* Run all children. We don't execute any siblings, we
     280                 :            :                  * assume our caller does that. The children of value
     281                 :            :                  * nodes are compares or leaves, they will
     282                 :            :                  * automatically call their siblings */
     283                 :            : 
     284         [ -  + ]:        215 :                 assert(node->child);
     285                 :        215 :                 return bus_match_run(bus, node->child, m);
     286                 :            : 
     287                 :        100 :         case BUS_MATCH_LEAF:
     288                 :            : 
     289         [ +  + ]:        100 :                 if (bus) {
     290                 :            :                         /* Don't run this match as long as the AddMatch() call is not complete yet.
     291                 :            :                          *
     292                 :            :                          * Don't run this match unless the 'after' counter has been reached.
     293                 :            :                          *
     294                 :            :                          * Don't run this match more than once per iteration */
     295                 :            : 
     296         [ +  - ]:         20 :                         if (node->leaf.callback->install_slot ||
     297         [ +  - ]:         20 :                             m->read_counter <= node->leaf.callback->after ||
     298         [ -  + ]:         20 :                             node->leaf.callback->last_iteration == bus->iteration_counter)
     299                 :          0 :                                 return bus_match_run(bus, node->next, m);
     300                 :            : 
     301                 :         20 :                         node->leaf.callback->last_iteration = bus->iteration_counter;
     302                 :            :                 }
     303                 :            : 
     304                 :        100 :                 r = sd_bus_message_rewind(m, true);
     305         [ -  + ]:        100 :                 if (r < 0)
     306                 :          0 :                         return r;
     307                 :            : 
     308                 :            :                 /* Run the callback. And then invoke siblings. */
     309         [ +  - ]:        100 :                 if (node->leaf.callback->callback) {
     310         [ +  + ]:        100 :                         _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
     311                 :            :                         sd_bus_slot *slot;
     312                 :            : 
     313                 :        100 :                         slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
     314         [ +  + ]:        100 :                         if (bus) {
     315                 :         20 :                                 bus->current_slot = sd_bus_slot_ref(slot);
     316                 :         20 :                                 bus->current_handler = node->leaf.callback->callback;
     317                 :         20 :                                 bus->current_userdata = slot->userdata;
     318                 :            :                         }
     319                 :        100 :                         r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
     320         [ +  + ]:        100 :                         if (bus) {
     321                 :         20 :                                 bus->current_userdata = NULL;
     322                 :         20 :                                 bus->current_handler = NULL;
     323                 :         20 :                                 bus->current_slot = sd_bus_slot_unref(slot);
     324                 :            :                         }
     325                 :            : 
     326                 :        100 :                         r = bus_maybe_reply_error(m, r, &error_buffer);
     327         [ -  + ]:        100 :                         if (r != 0)
     328                 :          0 :                                 return r;
     329                 :            : 
     330   [ +  +  +  + ]:        100 :                         if (bus && bus->match_callbacks_modified)
     331                 :          4 :                                 return 0;
     332                 :            :                 }
     333                 :            : 
     334                 :         96 :                 return bus_match_run(bus, node->next, m);
     335                 :            : 
     336                 :         79 :         case BUS_MATCH_MESSAGE_TYPE:
     337                 :         79 :                 test_u8 = m->header->type;
     338                 :         79 :                 break;
     339                 :            : 
     340                 :         31 :         case BUS_MATCH_SENDER:
     341                 :         31 :                 test_str = m->sender;
     342                 :            :                 /* FIXME: resolve test_str from a well-known to a unique name first */
     343                 :         31 :                 break;
     344                 :            : 
     345                 :          0 :         case BUS_MATCH_DESTINATION:
     346                 :          0 :                 test_str = m->destination;
     347                 :          0 :                 break;
     348                 :            : 
     349                 :         55 :         case BUS_MATCH_INTERFACE:
     350                 :         55 :                 test_str = m->interface;
     351                 :         55 :                 break;
     352                 :            : 
     353                 :         44 :         case BUS_MATCH_MEMBER:
     354                 :         44 :                 test_str = m->member;
     355                 :         44 :                 break;
     356                 :            : 
     357                 :         32 :         case BUS_MATCH_PATH:
     358                 :            :         case BUS_MATCH_PATH_NAMESPACE:
     359                 :         32 :                 test_str = m->path;
     360                 :         32 :                 break;
     361                 :            : 
     362                 :         24 :         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
     363                 :         24 :                 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
     364                 :         24 :                 break;
     365                 :            : 
     366                 :          4 :         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
     367                 :          4 :                 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
     368                 :          4 :                 break;
     369                 :            : 
     370                 :          8 :         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
     371                 :          8 :                 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
     372                 :          8 :                 break;
     373                 :            : 
     374                 :          8 :         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
     375                 :          8 :                 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
     376                 :          8 :                 break;
     377                 :            : 
     378                 :          0 :         default:
     379                 :          0 :                 assert_not_reached("Unknown match type.");
     380                 :            :         }
     381                 :            : 
     382         [ +  + ]:        285 :         if (BUS_MATCH_CAN_HASH(node->type)) {
     383                 :            :                 struct bus_match_node *found;
     384                 :            : 
     385                 :            :                 /* Lookup via hash table, nice! So let's jump directly. */
     386                 :            : 
     387         [ +  + ]:        234 :                 if (test_str)
     388                 :        139 :                         found = hashmap_get(node->compare.children, test_str);
     389         [ +  + ]:         95 :                 else if (test_strv) {
     390                 :            :                         char **i;
     391                 :            : 
     392   [ +  -  +  + ]:         32 :                         STRV_FOREACH(i, test_strv) {
     393                 :         24 :                                 found = hashmap_get(node->compare.children, *i);
     394         [ +  - ]:         24 :                                 if (found) {
     395                 :         24 :                                         r = bus_match_run(bus, found, m);
     396         [ -  + ]:         24 :                                         if (r != 0)
     397                 :          0 :                                                 return r;
     398                 :            :                                 }
     399                 :            :                         }
     400                 :            : 
     401                 :          8 :                         found = NULL;
     402         [ +  + ]:         87 :                 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
     403                 :         79 :                         found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
     404                 :            :                 else
     405                 :          8 :                         found = NULL;
     406                 :            : 
     407         [ +  + ]:        234 :                 if (found) {
     408                 :        159 :                         r = bus_match_run(bus, found, m);
     409         [ -  + ]:        159 :                         if (r != 0)
     410                 :          0 :                                 return r;
     411                 :            :                 }
     412                 :            :         } else {
     413                 :            :                 struct bus_match_node *c;
     414                 :            : 
     415                 :            :                 /* No hash table, so let's iterate manually... */
     416                 :            : 
     417         [ +  + ]:        106 :                 for (c = node->child; c; c = c->next) {
     418         [ +  + ]:         59 :                         if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
     419                 :         27 :                                 continue;
     420                 :            : 
     421                 :         32 :                         r = bus_match_run(bus, c, m);
     422         [ -  + ]:         32 :                         if (r != 0)
     423                 :          0 :                                 return r;
     424                 :            : 
     425   [ +  +  +  + ]:         32 :                         if (bus && bus->match_callbacks_modified)
     426                 :          4 :                                 return 0;
     427                 :            :                 }
     428                 :            :         }
     429                 :            : 
     430   [ +  +  +  + ]:        281 :         if (bus && bus->match_callbacks_modified)
     431                 :         20 :                 return 0;
     432                 :            : 
     433                 :            :         /* And now, let's invoke our siblings */
     434                 :        261 :         return bus_match_run(bus, node->next, m);
     435                 :            : }
     436                 :            : 
     437                 :        672 : static int bus_match_add_compare_value(
     438                 :            :                 struct bus_match_node *where,
     439                 :            :                 enum bus_match_node_type t,
     440                 :            :                 uint8_t value_u8,
     441                 :            :                 const char *value_str,
     442                 :            :                 struct bus_match_node **ret) {
     443                 :            : 
     444                 :        672 :         struct bus_match_node *c = NULL, *n = NULL;
     445                 :            :         int r;
     446                 :            : 
     447         [ -  + ]:        672 :         assert(where);
     448   [ +  -  -  + ]:        672 :         assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
     449         [ -  + ]:        672 :         assert(BUS_MATCH_IS_COMPARE(t));
     450         [ -  + ]:        672 :         assert(ret);
     451                 :            : 
     452   [ +  +  +  + ]:        904 :         for (c = where->child; c && c->type != t; c = c->next)
     453                 :            :                 ;
     454                 :            : 
     455         [ +  + ]:        672 :         if (c) {
     456                 :            :                 /* Comparison node already exists? Then let's see if
     457                 :            :                  * the value node exists too. */
     458                 :            : 
     459         [ +  + ]:         96 :                 if (t == BUS_MATCH_MESSAGE_TYPE)
     460                 :         20 :                         n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
     461         [ +  + ]:         76 :                 else if (BUS_MATCH_CAN_HASH(t))
     462                 :         56 :                         n = hashmap_get(c->compare.children, value_str);
     463                 :            :                 else {
     464   [ +  +  +  + ]:         24 :                         for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
     465                 :            :                                 ;
     466                 :            :                 }
     467                 :            : 
     468         [ +  + ]:         96 :                 if (n) {
     469                 :         64 :                         *ret = n;
     470                 :         64 :                         return 0;
     471                 :            :                 }
     472                 :            :         } else {
     473                 :            :                 /* Comparison node, doesn't exist yet? Then let's
     474                 :            :                  * create it. */
     475                 :            : 
     476                 :        576 :                 c = new0(struct bus_match_node, 1);
     477         [ -  + ]:        576 :                 if (!c) {
     478                 :          0 :                         r = -ENOMEM;
     479                 :          0 :                         goto fail;
     480                 :            :                 }
     481                 :            : 
     482                 :        576 :                 c->type = t;
     483                 :        576 :                 c->parent = where;
     484                 :        576 :                 c->next = where->child;
     485         [ +  + ]:        576 :                 if (c->next)
     486                 :         92 :                         c->next->prev = c;
     487                 :        576 :                 where->child = c;
     488                 :            : 
     489         [ +  + ]:        576 :                 if (t == BUS_MATCH_MESSAGE_TYPE) {
     490                 :        116 :                         c->compare.children = hashmap_new(NULL);
     491         [ -  + ]:        116 :                         if (!c->compare.children) {
     492                 :          0 :                                 r = -ENOMEM;
     493                 :          0 :                                 goto fail;
     494                 :            :                         }
     495         [ +  + ]:        460 :                 } else if (BUS_MATCH_CAN_HASH(t)) {
     496                 :        388 :                         c->compare.children = hashmap_new(&string_hash_ops);
     497         [ -  + ]:        388 :                         if (!c->compare.children) {
     498                 :          0 :                                 r = -ENOMEM;
     499                 :          0 :                                 goto fail;
     500                 :            :                         }
     501                 :            :                 }
     502                 :            :         }
     503                 :            : 
     504                 :        608 :         n = new0(struct bus_match_node, 1);
     505         [ -  + ]:        608 :         if (!n) {
     506                 :          0 :                 r = -ENOMEM;
     507                 :          0 :                 goto fail;
     508                 :            :         }
     509                 :            : 
     510                 :        608 :         n->type = BUS_MATCH_VALUE;
     511                 :        608 :         n->value.u8 = value_u8;
     512         [ +  + ]:        608 :         if (value_str) {
     513                 :        488 :                 n->value.str = strdup(value_str);
     514         [ -  + ]:        488 :                 if (!n->value.str) {
     515                 :          0 :                         r = -ENOMEM;
     516                 :          0 :                         goto fail;
     517                 :            :                 }
     518                 :            :         }
     519                 :            : 
     520                 :        608 :         n->parent = c;
     521         [ +  + ]:        608 :         if (c->compare.children) {
     522                 :            : 
     523         [ +  + ]:        532 :                 if (t == BUS_MATCH_MESSAGE_TYPE)
     524                 :        120 :                         r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
     525                 :            :                 else
     526                 :        412 :                         r = hashmap_put(c->compare.children, n->value.str, n);
     527                 :            : 
     528         [ -  + ]:        532 :                 if (r < 0)
     529                 :          0 :                         goto fail;
     530                 :            :         } else {
     531                 :         76 :                 n->next = c->child;
     532         [ +  + ]:         76 :                 if (n->next)
     533                 :          4 :                         n->next->prev = n;
     534                 :         76 :                 c->child = n;
     535                 :            :         }
     536                 :            : 
     537                 :        608 :         *ret = n;
     538                 :        608 :         return 1;
     539                 :            : 
     540                 :          0 : fail:
     541         [ #  # ]:          0 :         if (c)
     542                 :          0 :                 bus_match_node_maybe_free(c);
     543                 :            : 
     544         [ #  # ]:          0 :         if (n) {
     545                 :          0 :                 free(n->value.str);
     546                 :          0 :                 free(n);
     547                 :            :         }
     548                 :            : 
     549                 :          0 :         return r;
     550                 :            : }
     551                 :            : 
     552                 :        192 : static int bus_match_add_leaf(
     553                 :            :                 struct bus_match_node *where,
     554                 :            :                 struct match_callback *callback) {
     555                 :            : 
     556                 :            :         struct bus_match_node *n;
     557                 :            : 
     558         [ -  + ]:        192 :         assert(where);
     559   [ +  -  -  + ]:        192 :         assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
     560         [ -  + ]:        192 :         assert(callback);
     561                 :            : 
     562                 :        192 :         n = new0(struct bus_match_node, 1);
     563         [ -  + ]:        192 :         if (!n)
     564                 :          0 :                 return -ENOMEM;
     565                 :            : 
     566                 :        192 :         n->type = BUS_MATCH_LEAF;
     567                 :        192 :         n->parent = where;
     568                 :        192 :         n->next = where->child;
     569         [ +  + ]:        192 :         if (n->next)
     570                 :          4 :                 n->next->prev = n;
     571                 :            : 
     572                 :        192 :         n->leaf.callback = callback;
     573                 :        192 :         callback->match_node = n;
     574                 :            : 
     575                 :        192 :         where->child = n;
     576                 :            : 
     577                 :        192 :         return 1;
     578                 :            : }
     579                 :            : 
     580                 :       1752 : enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
     581         [ -  + ]:       1752 :         assert(k);
     582                 :            : 
     583   [ +  +  +  + ]:       1752 :         if (n == 4 && startswith(k, "type"))
     584                 :        140 :                 return BUS_MATCH_MESSAGE_TYPE;
     585   [ +  +  +  + ]:       1612 :         if (n == 6 && startswith(k, "sender"))
     586                 :         84 :                 return BUS_MATCH_SENDER;
     587   [ +  +  +  - ]:       1528 :         if (n == 11 && startswith(k, "destination"))
     588                 :          4 :                 return BUS_MATCH_DESTINATION;
     589   [ +  +  +  + ]:       1524 :         if (n == 9 && startswith(k, "interface"))
     590                 :        156 :                 return BUS_MATCH_INTERFACE;
     591   [ +  +  +  - ]:       1368 :         if (n == 6 && startswith(k, "member"))
     592                 :        144 :                 return BUS_MATCH_MEMBER;
     593   [ +  +  +  + ]:       1224 :         if (n == 4 && startswith(k, "path"))
     594                 :        132 :                 return BUS_MATCH_PATH;
     595   [ +  +  +  + ]:       1092 :         if (n == 14 && startswith(k, "path_namespace"))
     596                 :         12 :                 return BUS_MATCH_PATH_NAMESPACE;
     597                 :            : 
     598   [ +  +  +  - ]:       1080 :         if (n == 4 && startswith(k, "arg")) {
     599                 :            :                 int j;
     600                 :            : 
     601                 :         76 :                 j = undecchar(k[3]);
     602         [ -  + ]:         76 :                 if (j < 0)
     603                 :          0 :                         return -EINVAL;
     604                 :            : 
     605                 :         76 :                 return BUS_MATCH_ARG + j;
     606                 :            :         }
     607                 :            : 
     608   [ +  +  +  - ]:       1004 :         if (n == 5 && startswith(k, "arg")) {
     609                 :            :                 int a, b;
     610                 :            :                 enum bus_match_node_type t;
     611                 :            : 
     612                 :        216 :                 a = undecchar(k[3]);
     613                 :        216 :                 b = undecchar(k[4]);
     614   [ +  -  -  + ]:        216 :                 if (a <= 0 || b < 0)
     615                 :          0 :                         return -EINVAL;
     616                 :            : 
     617                 :        216 :                 t = BUS_MATCH_ARG + a * 10 + b;
     618         [ -  + ]:        216 :                 if (t > BUS_MATCH_ARG_LAST)
     619                 :          0 :                         return -EINVAL;
     620                 :            : 
     621                 :        216 :                 return t;
     622                 :            :         }
     623                 :            : 
     624   [ +  +  +  -  :        788 :         if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
                   +  + ]
     625                 :            :                 int j;
     626                 :            : 
     627                 :         44 :                 j = undecchar(k[3]);
     628         [ -  + ]:         44 :                 if (j < 0)
     629                 :          0 :                         return -EINVAL;
     630                 :            : 
     631                 :         44 :                 return BUS_MATCH_ARG_PATH + j;
     632                 :            :         }
     633                 :            : 
     634   [ +  +  +  -  :        744 :         if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
                   +  - ]
     635                 :            :                 enum bus_match_node_type t;
     636                 :            :                 int a, b;
     637                 :            : 
     638                 :        216 :                 a = undecchar(k[3]);
     639                 :        216 :                 b = undecchar(k[4]);
     640   [ +  -  -  + ]:        216 :                 if (a <= 0 || b < 0)
     641                 :          0 :                         return -EINVAL;
     642                 :            : 
     643                 :        216 :                 t = BUS_MATCH_ARG_PATH + a * 10 + b;
     644         [ -  + ]:        216 :                 if (t > BUS_MATCH_ARG_PATH_LAST)
     645                 :          0 :                         return -EINVAL;
     646                 :            : 
     647                 :        216 :                 return t;
     648                 :            :         }
     649                 :            : 
     650   [ +  +  +  -  :        528 :         if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
                   +  - ]
     651                 :            :                 int j;
     652                 :            : 
     653                 :         44 :                 j = undecchar(k[3]);
     654         [ -  + ]:         44 :                 if (j < 0)
     655                 :          0 :                         return -EINVAL;
     656                 :            : 
     657                 :         44 :                 return BUS_MATCH_ARG_NAMESPACE + j;
     658                 :            :         }
     659                 :            : 
     660   [ +  +  +  -  :        484 :         if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
                   +  - ]
     661                 :            :                 enum bus_match_node_type t;
     662                 :            :                 int a, b;
     663                 :            : 
     664                 :        216 :                 a = undecchar(k[3]);
     665                 :        216 :                 b = undecchar(k[4]);
     666   [ +  -  -  + ]:        216 :                 if (a <= 0 || b < 0)
     667                 :          0 :                         return -EINVAL;
     668                 :            : 
     669                 :        216 :                 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
     670         [ -  + ]:        216 :                 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
     671                 :          0 :                         return -EINVAL;
     672                 :            : 
     673                 :        216 :                 return t;
     674                 :            :         }
     675                 :            : 
     676   [ +  +  +  -  :        268 :         if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
                   +  - ]
     677                 :            :                 int j;
     678                 :            : 
     679                 :         52 :                 j = undecchar(k[3]);
     680         [ -  + ]:         52 :                 if (j < 0)
     681                 :          0 :                         return -EINVAL;
     682                 :            : 
     683                 :         52 :                 return BUS_MATCH_ARG_HAS + j;
     684                 :            :         }
     685                 :            : 
     686   [ +  -  +  -  :        216 :         if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
                   +  - ]
     687                 :            :                 enum bus_match_node_type t;
     688                 :            :                 int a, b;
     689                 :            : 
     690                 :        216 :                 a = undecchar(k[3]);
     691                 :        216 :                 b = undecchar(k[4]);
     692   [ +  -  -  + ]:        216 :                 if (a <= 0 || b < 0)
     693                 :          0 :                         return -EINVAL;
     694                 :            : 
     695                 :        216 :                 t = BUS_MATCH_ARG_HAS + a * 10 + b;
     696         [ -  + ]:        216 :                 if (t > BUS_MATCH_ARG_HAS_LAST)
     697                 :          0 :                         return -EINVAL;
     698                 :            : 
     699                 :        216 :                 return t;
     700                 :            :         }
     701                 :            : 
     702                 :          0 :         return -EINVAL;
     703                 :            : }
     704                 :            : 
     705                 :        780 : static int match_component_compare(const struct bus_match_component *a, const struct bus_match_component *b) {
     706         [ +  + ]:        780 :         return CMP(a->type, b->type);
     707                 :            : }
     708                 :            : 
     709                 :        216 : void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
     710                 :            :         unsigned i;
     711                 :            : 
     712         [ +  + ]:        920 :         for (i = 0; i < n_components; i++)
     713                 :        704 :                 free(components[i].value_str);
     714                 :            : 
     715                 :        216 :         free(components);
     716                 :        216 : }
     717                 :            : 
     718                 :        216 : int bus_match_parse(
     719                 :            :                 const char *match,
     720                 :            :                 struct bus_match_component **_components,
     721                 :            :                 unsigned *_n_components) {
     722                 :            : 
     723                 :        216 :         const char *p = match;
     724                 :        216 :         struct bus_match_component *components = NULL;
     725                 :        216 :         size_t components_allocated = 0;
     726                 :        216 :         unsigned n_components = 0, i;
     727                 :        216 :         _cleanup_free_ char *value = NULL;
     728                 :            :         int r;
     729                 :            : 
     730         [ -  + ]:        216 :         assert(match);
     731         [ -  + ]:        216 :         assert(_components);
     732         [ -  + ]:        216 :         assert(_n_components);
     733                 :            : 
     734         [ +  + ]:        728 :         while (*p != 0) {
     735                 :            :                 const char *eq, *q;
     736                 :            :                 enum bus_match_node_type t;
     737                 :        704 :                 unsigned j = 0;
     738                 :        704 :                 size_t value_allocated = 0;
     739                 :        704 :                 bool escaped = false, quoted;
     740                 :            :                 uint8_t u;
     741                 :            : 
     742                 :            :                 /* Avahi's match rules appear to include whitespace, skip over it */
     743                 :        704 :                 p += strspn(p, " ");
     744                 :            : 
     745                 :        704 :                 eq = strchr(p, '=');
     746         [ -  + ]:        704 :                 if (!eq)
     747                 :          0 :                         return -EINVAL;
     748                 :            : 
     749                 :        704 :                 t = bus_match_node_type_from_string(p, eq - p);
     750         [ -  + ]:        704 :                 if (t < 0)
     751                 :          0 :                         return -EINVAL;
     752                 :            : 
     753                 :        704 :                 quoted = eq[1] == '\'';
     754                 :            : 
     755                 :        704 :                 for (q = eq + 1 + quoted;; q++) {
     756                 :            : 
     757         [ -  + ]:      11776 :                         if (*q == 0) {
     758                 :            : 
     759         [ #  # ]:          0 :                                 if (quoted) {
     760                 :          0 :                                         r = -EINVAL;
     761                 :          0 :                                         goto fail;
     762                 :            :                                 } else {
     763         [ #  # ]:          0 :                                         if (value)
     764                 :          0 :                                                 value[j] = 0;
     765                 :          0 :                                         break;
     766                 :            :                                 }
     767                 :            :                         }
     768                 :            : 
     769         [ +  + ]:      11776 :                         if (!escaped) {
     770         [ +  + ]:      11768 :                                 if (*q == '\\') {
     771                 :          8 :                                         escaped = true;
     772                 :          8 :                                         continue;
     773                 :            :                                 }
     774                 :            : 
     775         [ +  + ]:      11760 :                                 if (quoted) {
     776         [ +  + ]:      11736 :                                         if (*q == '\'') {
     777         [ +  - ]:        700 :                                                 if (value)
     778                 :        700 :                                                         value[j] = 0;
     779                 :        700 :                                                 break;
     780                 :            :                                         }
     781                 :            :                                 } else {
     782         [ +  + ]:         24 :                                         if (*q == ',') {
     783         [ +  - ]:          4 :                                                 if (value)
     784                 :          4 :                                                         value[j] = 0;
     785                 :            : 
     786                 :          4 :                                                 break;
     787                 :            :                                         }
     788                 :            :                                 }
     789                 :            :                         }
     790                 :            : 
     791         [ -  + ]:      11064 :                         if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
     792                 :          0 :                                 r = -ENOMEM;
     793                 :          0 :                                 goto fail;
     794                 :            :                         }
     795                 :            : 
     796                 :      11064 :                         value[j++] = *q;
     797                 :      11064 :                         escaped = false;
     798                 :            :                 }
     799                 :            : 
     800         [ -  + ]:        704 :                 if (!value) {
     801                 :          0 :                         value = strdup("");
     802         [ #  # ]:          0 :                         if (!value) {
     803                 :          0 :                                 r = -ENOMEM;
     804                 :          0 :                                 goto fail;
     805                 :            :                         }
     806                 :            :                 }
     807                 :            : 
     808         [ +  + ]:        704 :                 if (t == BUS_MATCH_MESSAGE_TYPE) {
     809                 :        136 :                         r = bus_message_type_from_string(value, &u);
     810         [ -  + ]:        136 :                         if (r < 0)
     811                 :          0 :                                 goto fail;
     812                 :            : 
     813                 :        136 :                         value = mfree(value);
     814                 :            :                 } else
     815                 :        568 :                         u = 0;
     816                 :            : 
     817         [ -  + ]:        704 :                 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
     818                 :          0 :                         r = -ENOMEM;
     819                 :          0 :                         goto fail;
     820                 :            :                 }
     821                 :            : 
     822                 :        704 :                 components[n_components].type = t;
     823                 :        704 :                 components[n_components].value_str = TAKE_PTR(value);
     824                 :        704 :                 components[n_components].value_u8 = u;
     825                 :        704 :                 n_components++;
     826                 :            : 
     827         [ +  + ]:        704 :                 if (q[quoted] == 0)
     828                 :        192 :                         break;
     829                 :            : 
     830         [ -  + ]:        512 :                 if (q[quoted] != ',') {
     831                 :          0 :                         r = -EINVAL;
     832                 :          0 :                         goto fail;
     833                 :            :                 }
     834                 :            : 
     835                 :        512 :                 p = q + 1 + quoted;
     836                 :            :         }
     837                 :            : 
     838                 :            :         /* Order the whole thing, so that we always generate the same tree */
     839                 :        216 :         typesafe_qsort(components, n_components, match_component_compare);
     840                 :            : 
     841                 :            :         /* Check for duplicates */
     842         [ +  + ]:        712 :         for (i = 0; i+1 < n_components; i++)
     843         [ -  + ]:        496 :                 if (components[i].type == components[i+1].type) {
     844                 :          0 :                         r = -EINVAL;
     845                 :          0 :                         goto fail;
     846                 :            :                 }
     847                 :            : 
     848                 :        216 :         *_components = components;
     849                 :        216 :         *_n_components = n_components;
     850                 :            : 
     851                 :        216 :         return 0;
     852                 :            : 
     853                 :          0 : fail:
     854                 :          0 :         bus_match_parse_free(components, n_components);
     855                 :          0 :         return r;
     856                 :            : }
     857                 :            : 
     858                 :          0 : char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
     859                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     860                 :          0 :         char *buffer = NULL;
     861                 :          0 :         size_t size = 0;
     862                 :            :         unsigned i;
     863                 :            :         int r;
     864                 :            : 
     865         [ #  # ]:          0 :         if (n_components <= 0)
     866                 :          0 :                 return strdup("");
     867                 :            : 
     868         [ #  # ]:          0 :         assert(components);
     869                 :            : 
     870                 :          0 :         f = open_memstream_unlocked(&buffer, &size);
     871         [ #  # ]:          0 :         if (!f)
     872                 :          0 :                 return NULL;
     873                 :            : 
     874         [ #  # ]:          0 :         for (i = 0; i < n_components; i++) {
     875                 :            :                 char buf[32];
     876                 :            : 
     877         [ #  # ]:          0 :                 if (i != 0)
     878                 :          0 :                         fputc(',', f);
     879                 :            : 
     880                 :          0 :                 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
     881                 :          0 :                 fputc('=', f);
     882                 :          0 :                 fputc('\'', f);
     883                 :            : 
     884         [ #  # ]:          0 :                 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
     885                 :          0 :                         fputs(bus_message_type_to_string(components[i].value_u8), f);
     886                 :            :                 else
     887                 :          0 :                         fputs(components[i].value_str, f);
     888                 :            : 
     889                 :          0 :                 fputc('\'', f);
     890                 :            :         }
     891                 :            : 
     892                 :          0 :         r = fflush_and_check(f);
     893         [ #  # ]:          0 :         if (r < 0)
     894                 :          0 :                 return NULL;
     895                 :            : 
     896                 :          0 :         return buffer;
     897                 :            : }
     898                 :            : 
     899                 :        192 : int bus_match_add(
     900                 :            :                 struct bus_match_node *root,
     901                 :            :                 struct bus_match_component *components,
     902                 :            :                 unsigned n_components,
     903                 :            :                 struct match_callback *callback) {
     904                 :            : 
     905                 :            :         unsigned i;
     906                 :            :         struct bus_match_node *n;
     907                 :            :         int r;
     908                 :            : 
     909         [ -  + ]:        192 :         assert(root);
     910         [ -  + ]:        192 :         assert(callback);
     911                 :            : 
     912                 :        192 :         n = root;
     913         [ +  + ]:        864 :         for (i = 0; i < n_components; i++) {
     914                 :       1344 :                 r = bus_match_add_compare_value(
     915                 :        672 :                                 n, components[i].type,
     916                 :        672 :                                 components[i].value_u8, components[i].value_str, &n);
     917         [ -  + ]:        672 :                 if (r < 0)
     918                 :          0 :                         return r;
     919                 :            :         }
     920                 :            : 
     921                 :        192 :         return bus_match_add_leaf(n, callback);
     922                 :            : }
     923                 :            : 
     924                 :        128 : int bus_match_remove(
     925                 :            :                 struct bus_match_node *root,
     926                 :            :                 struct match_callback *callback) {
     927                 :            : 
     928                 :            :         struct bus_match_node *node, *pp;
     929                 :            : 
     930         [ -  + ]:        128 :         assert(root);
     931         [ -  + ]:        128 :         assert(callback);
     932                 :            : 
     933                 :        128 :         node = callback->match_node;
     934         [ -  + ]:        128 :         if (!node)
     935                 :          0 :                 return 0;
     936                 :            : 
     937         [ -  + ]:        128 :         assert(node->type == BUS_MATCH_LEAF);
     938                 :            : 
     939                 :        128 :         callback->match_node = NULL;
     940                 :            : 
     941                 :            :         /* Free the leaf */
     942                 :        128 :         pp = node->parent;
     943                 :        128 :         bus_match_node_free(node);
     944                 :            : 
     945                 :            :         /* Prune the tree above */
     946         [ +  - ]:       1168 :         while (pp) {
     947                 :       1168 :                 node = pp;
     948                 :       1168 :                 pp = node->parent;
     949                 :            : 
     950         [ +  + ]:       1168 :                 if (!bus_match_node_maybe_free(node))
     951                 :        128 :                         break;
     952                 :            :         }
     953                 :            : 
     954                 :        128 :         return 1;
     955                 :            : }
     956                 :            : 
     957                 :        432 : void bus_match_free(struct bus_match_node *node) {
     958                 :            :         struct bus_match_node *c;
     959                 :            : 
     960         [ -  + ]:        432 :         if (!node)
     961                 :          0 :                 return;
     962                 :            : 
     963         [ +  + ]:        432 :         if (BUS_MATCH_CAN_HASH(node->type)) {
     964                 :            :                 Iterator i;
     965                 :            : 
     966         [ +  + ]:        124 :                 HASHMAP_FOREACH(c, node->compare.children, i)
     967                 :         72 :                         bus_match_free(c);
     968                 :            : 
     969         [ -  + ]:         52 :                 assert(hashmap_isempty(node->compare.children));
     970                 :            :         }
     971                 :            : 
     972         [ +  + ]:        576 :         while ((c = node->child))
     973                 :        144 :                 bus_match_free(c);
     974                 :            : 
     975         [ +  + ]:        432 :         if (node->type != BUS_MATCH_ROOT)
     976                 :        216 :                 bus_match_node_free(node);
     977                 :            : }
     978                 :            : 
     979                 :       1568 : const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
     980   [ +  +  +  +  :       1568 :         switch (t) {
          +  +  +  +  +  
          +  +  +  +  +  
                      - ]
     981                 :            : 
     982                 :         16 :         case BUS_MATCH_ROOT:
     983                 :         16 :                 return "root";
     984                 :            : 
     985                 :        204 :         case BUS_MATCH_VALUE:
     986                 :        204 :                 return "value";
     987                 :            : 
     988                 :        148 :         case BUS_MATCH_LEAF:
     989                 :        148 :                 return "leaf";
     990                 :            : 
     991                 :         16 :         case BUS_MATCH_MESSAGE_TYPE:
     992                 :         16 :                 return "type";
     993                 :            : 
     994                 :         12 :         case BUS_MATCH_SENDER:
     995                 :         12 :                 return "sender";
     996                 :            : 
     997                 :          4 :         case BUS_MATCH_DESTINATION:
     998                 :          4 :                 return "destination";
     999                 :            : 
    1000                 :         32 :         case BUS_MATCH_INTERFACE:
    1001                 :         32 :                 return "interface";
    1002                 :            : 
    1003                 :         20 :         case BUS_MATCH_MEMBER:
    1004                 :         20 :                 return "member";
    1005                 :            : 
    1006                 :         20 :         case BUS_MATCH_PATH:
    1007                 :         20 :                 return "path";
    1008                 :            : 
    1009                 :         12 :         case BUS_MATCH_PATH_NAMESPACE:
    1010                 :         12 :                 return "path_namespace";
    1011                 :            : 
    1012                 :        296 :         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
    1013                 :        296 :                 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
    1014                 :        296 :                 return buf;
    1015                 :            : 
    1016                 :        260 :         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
    1017                 :        260 :                 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
    1018                 :        260 :                 return buf;
    1019                 :            : 
    1020                 :        264 :         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
    1021                 :        264 :                 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
    1022                 :        264 :                 return buf;
    1023                 :            : 
    1024                 :        264 :         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
    1025                 :        264 :                 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
    1026                 :        264 :                 return buf;
    1027                 :            : 
    1028                 :          0 :         default:
    1029                 :          0 :                 return NULL;
    1030                 :            :         }
    1031                 :            : }
    1032                 :            : 
    1033                 :        504 : void bus_match_dump(struct bus_match_node *node, unsigned level) {
    1034                 :            :         struct bus_match_node *c;
    1035         [ +  - ]:        504 :         _cleanup_free_ char *pfx = NULL;
    1036                 :            :         char buf[32];
    1037                 :            : 
    1038         [ -  + ]:        504 :         if (!node)
    1039                 :          0 :                 return;
    1040                 :            : 
    1041                 :        504 :         pfx = strrep("  ", level);
    1042                 :        504 :         printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
    1043                 :            : 
    1044         [ +  + ]:        504 :         if (node->type == BUS_MATCH_VALUE) {
    1045         [ +  + ]:        200 :                 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
    1046                 :         20 :                         printf(" <%u>\n", node->value.u8);
    1047                 :            :                 else
    1048                 :        180 :                         printf(" <%s>\n", node->value.str);
    1049         [ +  + ]:        304 :         } else if (node->type == BUS_MATCH_ROOT)
    1050                 :         12 :                 puts(" root");
    1051         [ +  + ]:        292 :         else if (node->type == BUS_MATCH_LEAF)
    1052                 :        144 :                 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
    1053                 :            :         else
    1054                 :        148 :                 putchar('\n');
    1055                 :            : 
    1056         [ +  + ]:        504 :         if (BUS_MATCH_CAN_HASH(node->type)) {
    1057                 :            :                 Iterator i;
    1058                 :            : 
    1059         [ +  + ]:        284 :                 HASHMAP_FOREACH(c, node->compare.children, i)
    1060                 :        164 :                         bus_match_dump(c, level + 1);
    1061                 :            :         }
    1062                 :            : 
    1063         [ +  + ]:        832 :         for (c = node->child; c; c = c->next)
    1064                 :        328 :                 bus_match_dump(c, level + 1);
    1065                 :            : }
    1066                 :            : 
    1067                 :        144 : enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
    1068                 :        144 :         bool found_driver = false;
    1069                 :            :         unsigned i;
    1070                 :            : 
    1071         [ +  + ]:        144 :         if (n_components <= 0)
    1072                 :          4 :                 return BUS_MATCH_GENERIC;
    1073                 :            : 
    1074         [ -  + ]:        140 :         assert(components);
    1075                 :            : 
    1076                 :            :         /* Checks whether the specified match can only match the
    1077                 :            :          * pseudo-service for local messages, which we detect by
    1078                 :            :          * sender, interface or path. If a match is not restricted to
    1079                 :            :          * local messages, then we check if it only matches on the
    1080                 :            :          * driver. */
    1081                 :            : 
    1082         [ +  + ]:        440 :         for (i = 0; i < n_components; i++) {
    1083                 :        364 :                 const struct bus_match_component *c = components + i;
    1084                 :            : 
    1085         [ +  + ]:        364 :                 if (c->type == BUS_MATCH_SENDER) {
    1086         [ +  + ]:         68 :                         if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
    1087                 :         56 :                                 return BUS_MATCH_LOCAL;
    1088                 :            : 
    1089         [ +  - ]:         12 :                         if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
    1090                 :         12 :                                 found_driver = true;
    1091                 :            :                 }
    1092                 :            : 
    1093   [ +  +  +  + ]:        308 :                 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
    1094                 :          4 :                         return BUS_MATCH_LOCAL;
    1095                 :            : 
    1096   [ +  +  +  + ]:        304 :                 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
    1097                 :          4 :                         return BUS_MATCH_LOCAL;
    1098                 :            :         }
    1099                 :            : 
    1100         [ +  + ]:         76 :         return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
    1101                 :            : 
    1102                 :            : }

Generated by: LCOV version 1.14