LCOV - code coverage report
Current view: top level - busctl - busctl-introspect.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 391 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 5 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 462 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "sd-bus.h"
       4                 :            : 
       5                 :            : #include "alloc-util.h"
       6                 :            : #include "busctl-introspect.h"
       7                 :            : #include "path-util.h"
       8                 :            : #include "string-util.h"
       9                 :            : #include "util.h"
      10                 :            : #include "xml.h"
      11                 :            : 
      12                 :            : #define NODE_DEPTH_MAX 16
      13                 :            : 
      14                 :            : typedef struct Context {
      15                 :            :         const XMLIntrospectOps *ops;
      16                 :            :         void *userdata;
      17                 :            : 
      18                 :            :         char *interface_name;
      19                 :            :         uint64_t interface_flags;
      20                 :            : 
      21                 :            :         char *member_name;
      22                 :            :         char *member_signature;
      23                 :            :         char *member_result;
      24                 :            :         uint64_t member_flags;
      25                 :            :         bool member_writable;
      26                 :            : 
      27                 :            :         const char *current;
      28                 :            :         void *xml_state;
      29                 :            : } Context;
      30                 :            : 
      31                 :          0 : static void context_reset_member(Context *c) {
      32                 :          0 :         free(c->member_name);
      33                 :          0 :         free(c->member_signature);
      34                 :          0 :         free(c->member_result);
      35                 :            : 
      36                 :          0 :         c->member_name = c->member_signature = c->member_result = NULL;
      37                 :          0 :         c->member_flags = 0;
      38                 :          0 :         c->member_writable = false;
      39                 :          0 : }
      40                 :            : 
      41                 :          0 : static void context_reset_interface(Context *c) {
      42                 :          0 :         c->interface_name = mfree(c->interface_name);
      43                 :          0 :         c->interface_flags = 0;
      44                 :            : 
      45                 :          0 :         context_reset_member(c);
      46                 :          0 : }
      47                 :            : 
      48                 :          0 : static int parse_xml_annotation(Context *context, uint64_t *flags) {
      49                 :            : 
      50                 :            :         enum {
      51                 :            :                 STATE_ANNOTATION,
      52                 :            :                 STATE_NAME,
      53                 :            :                 STATE_VALUE
      54                 :          0 :         } state = STATE_ANNOTATION;
      55                 :            : 
      56                 :          0 :         _cleanup_free_ char *field = NULL, *value = NULL;
      57                 :            : 
      58         [ #  # ]:          0 :         assert(context);
      59                 :            : 
      60                 :          0 :         for (;;) {
      61         [ #  # ]:          0 :                 _cleanup_free_ char *name = NULL;
      62                 :            : 
      63                 :            :                 int t;
      64                 :            : 
      65                 :          0 :                 t = xml_tokenize(&context->current, &name, &context->xml_state, NULL);
      66         [ #  # ]:          0 :                 if (t < 0) {
      67         [ #  # ]:          0 :                         log_error("XML parse error.");
      68                 :          0 :                         return t;
      69                 :            :                 }
      70                 :            : 
      71         [ #  # ]:          0 :                 if (t == XML_END)
      72         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
      73                 :            :                                                "Premature end of XML data.");
      74                 :            : 
      75   [ #  #  #  # ]:          0 :                 switch (state) {
      76                 :            : 
      77                 :          0 :                 case STATE_ANNOTATION:
      78                 :            : 
      79         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
      80                 :            : 
      81         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
      82                 :          0 :                                         state = STATE_NAME;
      83                 :            : 
      84         [ #  # ]:          0 :                                 else if (streq_ptr(name, "value"))
      85                 :          0 :                                         state = STATE_VALUE;
      86                 :            : 
      87                 :            :                                 else
      88         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
      89                 :            :                                                                "Unexpected <annotation> attribute %s.",
      90                 :            :                                                                name);
      91                 :            : 
      92   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
      93         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "annotation"))) {
      94                 :            : 
      95         [ #  # ]:          0 :                                 if (flags) {
      96         [ #  # ]:          0 :                                         if (streq_ptr(field, "org.freedesktop.DBus.Deprecated")) {
      97                 :            : 
      98         [ #  # ]:          0 :                                                 if (streq_ptr(value, "true"))
      99                 :          0 :                                                         *flags |= SD_BUS_VTABLE_DEPRECATED;
     100                 :            : 
     101         [ #  # ]:          0 :                                         } else if (streq_ptr(field, "org.freedesktop.DBus.Method.NoReply")) {
     102                 :            : 
     103         [ #  # ]:          0 :                                                 if (streq_ptr(value, "true"))
     104                 :          0 :                                                         *flags |= SD_BUS_VTABLE_METHOD_NO_REPLY;
     105                 :            : 
     106         [ #  # ]:          0 :                                         } else if (streq_ptr(field, "org.freedesktop.DBus.Property.EmitsChangedSignal")) {
     107                 :            : 
     108         [ #  # ]:          0 :                                                 if (streq_ptr(value, "const"))
     109                 :          0 :                                                         *flags = (*flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) | SD_BUS_VTABLE_PROPERTY_CONST;
     110         [ #  # ]:          0 :                                                 else if (streq_ptr(value, "invalidates"))
     111                 :          0 :                                                         *flags = (*flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_CONST)) | SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
     112         [ #  # ]:          0 :                                                 else if (streq_ptr(value, "false"))
     113                 :          0 :                                                         *flags = *flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION);
     114                 :            :                                         }
     115                 :            :                                 }
     116                 :            : 
     117                 :          0 :                                 return 0;
     118                 :            : 
     119   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     120         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     121                 :            :                                                        "Unexpected token in <annotation>. (1)");
     122                 :            : 
     123                 :          0 :                         break;
     124                 :            : 
     125                 :          0 :                 case STATE_NAME:
     126                 :            : 
     127         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     128                 :          0 :                                 free_and_replace(field, name);
     129                 :            : 
     130                 :          0 :                                 state = STATE_ANNOTATION;
     131                 :            :                         } else
     132         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     133                 :            :                                                        "Unexpected token in <annotation>. (2)");
     134                 :            : 
     135                 :          0 :                         break;
     136                 :            : 
     137                 :          0 :                 case STATE_VALUE:
     138                 :            : 
     139         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     140                 :          0 :                                 free_and_replace(value, name);
     141                 :            : 
     142                 :          0 :                                 state = STATE_ANNOTATION;
     143                 :            :                         } else
     144         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     145                 :            :                                                        "Unexpected token in <annotation>. (3)");
     146                 :            : 
     147                 :          0 :                         break;
     148                 :            : 
     149                 :          0 :                 default:
     150                 :          0 :                         assert_not_reached("Bad state");
     151                 :            :                 }
     152                 :            :         }
     153                 :            : }
     154                 :            : 
     155                 :          0 : static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth) {
     156                 :            : 
     157                 :            :         enum {
     158                 :            :                 STATE_NODE,
     159                 :            :                 STATE_NODE_NAME,
     160                 :            :                 STATE_INTERFACE,
     161                 :            :                 STATE_INTERFACE_NAME,
     162                 :            :                 STATE_METHOD,
     163                 :            :                 STATE_METHOD_NAME,
     164                 :            :                 STATE_METHOD_ARG,
     165                 :            :                 STATE_METHOD_ARG_NAME,
     166                 :            :                 STATE_METHOD_ARG_TYPE,
     167                 :            :                 STATE_METHOD_ARG_DIRECTION,
     168                 :            :                 STATE_SIGNAL,
     169                 :            :                 STATE_SIGNAL_NAME,
     170                 :            :                 STATE_SIGNAL_ARG,
     171                 :            :                 STATE_SIGNAL_ARG_NAME,
     172                 :            :                 STATE_SIGNAL_ARG_TYPE,
     173                 :            :                 STATE_SIGNAL_ARG_DIRECTION,
     174                 :            :                 STATE_PROPERTY,
     175                 :            :                 STATE_PROPERTY_NAME,
     176                 :            :                 STATE_PROPERTY_TYPE,
     177                 :            :                 STATE_PROPERTY_ACCESS,
     178                 :          0 :         } state = STATE_NODE;
     179                 :            : 
     180                 :          0 :         _cleanup_free_ char *node_path = NULL, *argument_type = NULL, *argument_direction = NULL;
     181                 :          0 :         const char *np = prefix;
     182                 :            :         int r;
     183                 :            : 
     184         [ #  # ]:          0 :         assert(context);
     185         [ #  # ]:          0 :         assert(prefix);
     186                 :            : 
     187         [ #  # ]:          0 :         if (n_depth > NODE_DEPTH_MAX)
     188         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "<node> depth too high.");
     189                 :            : 
     190                 :          0 :         for (;;) {
     191         [ #  # ]:          0 :                 _cleanup_free_ char *name = NULL;
     192                 :            :                 int t;
     193                 :            : 
     194                 :          0 :                 t = xml_tokenize(&context->current, &name, &context->xml_state, NULL);
     195         [ #  # ]:          0 :                 if (t < 0) {
     196         [ #  # ]:          0 :                         log_error("XML parse error.");
     197                 :          0 :                         return t;
     198                 :            :                 }
     199                 :            : 
     200         [ #  # ]:          0 :                 if (t == XML_END)
     201         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Premature end of XML data.");
     202                 :            : 
     203   [ #  #  #  #  :          0 :                 switch (state) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     204                 :            : 
     205                 :          0 :                 case STATE_NODE:
     206         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     207                 :            : 
     208         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     209                 :          0 :                                         state = STATE_NODE_NAME;
     210                 :            :                                 else
     211         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     212                 :            :                                                                "Unexpected <node> attribute %s.", name);
     213                 :            : 
     214         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     215                 :            : 
     216         [ #  # ]:          0 :                                 if (streq_ptr(name, "interface"))
     217                 :          0 :                                         state = STATE_INTERFACE;
     218         [ #  # ]:          0 :                                 else if (streq_ptr(name, "node")) {
     219                 :            : 
     220                 :          0 :                                         r = parse_xml_node(context, np, n_depth+1);
     221         [ #  # ]:          0 :                                         if (r < 0)
     222                 :          0 :                                                 return r;
     223                 :            :                                 } else
     224         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     225                 :            :                                                                "Unexpected <node> tag %s.", name);
     226                 :            : 
     227   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     228         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "node"))) {
     229                 :            : 
     230         [ #  # ]:          0 :                                 if (context->ops->on_path) {
     231         [ #  # ]:          0 :                                         r = context->ops->on_path(node_path ? node_path : np, context->userdata);
     232         [ #  # ]:          0 :                                         if (r < 0)
     233                 :          0 :                                                 return r;
     234                 :            :                                 }
     235                 :            : 
     236                 :          0 :                                 return 0;
     237                 :            : 
     238   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     239         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     240                 :            :                                                        "Unexpected token in <node>. (1)");
     241                 :            : 
     242                 :          0 :                         break;
     243                 :            : 
     244                 :          0 :                 case STATE_NODE_NAME:
     245                 :            : 
     246         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     247                 :            : 
     248                 :          0 :                                 free(node_path);
     249                 :            : 
     250         [ #  # ]:          0 :                                 if (name[0] == '/')
     251                 :          0 :                                         node_path = TAKE_PTR(name);
     252                 :            :                                 else {
     253                 :            : 
     254                 :          0 :                                         node_path = path_join(prefix, name);
     255         [ #  # ]:          0 :                                         if (!node_path)
     256                 :          0 :                                                 return log_oom();
     257                 :            :                                 }
     258                 :            : 
     259                 :          0 :                                 np = node_path;
     260                 :          0 :                                 state = STATE_NODE;
     261                 :            :                         } else
     262         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     263                 :            :                                                        "Unexpected token in <node>. (2)");
     264                 :            : 
     265                 :          0 :                         break;
     266                 :            : 
     267                 :          0 :                 case STATE_INTERFACE:
     268                 :            : 
     269         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     270         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     271                 :          0 :                                         state = STATE_INTERFACE_NAME;
     272                 :            :                                 else
     273         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     274                 :            :                                                                "Unexpected <interface> attribute %s.",
     275                 :            :                                                                name);
     276                 :            : 
     277         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     278         [ #  # ]:          0 :                                 if (streq_ptr(name, "method"))
     279                 :          0 :                                         state = STATE_METHOD;
     280         [ #  # ]:          0 :                                 else if (streq_ptr(name, "signal"))
     281                 :          0 :                                         state = STATE_SIGNAL;
     282         [ #  # ]:          0 :                                 else if (streq_ptr(name, "property")) {
     283                 :          0 :                                         context->member_flags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
     284                 :          0 :                                         state = STATE_PROPERTY;
     285         [ #  # ]:          0 :                                 } else if (streq_ptr(name, "annotation")) {
     286                 :          0 :                                         r = parse_xml_annotation(context, &context->interface_flags);
     287         [ #  # ]:          0 :                                         if (r < 0)
     288                 :          0 :                                                 return r;
     289                 :            :                                 } else
     290         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     291                 :            :                                                                "Unexpected <interface> tag %s.", name);
     292   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     293         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "interface"))) {
     294                 :            : 
     295         [ #  # ]:          0 :                                 if (n_depth == 0) {
     296         [ #  # ]:          0 :                                         if (context->ops->on_interface) {
     297                 :          0 :                                                 r = context->ops->on_interface(context->interface_name, context->interface_flags, context->userdata);
     298         [ #  # ]:          0 :                                                 if (r < 0)
     299                 :          0 :                                                         return r;
     300                 :            :                                         }
     301                 :            : 
     302                 :          0 :                                         context_reset_interface(context);
     303                 :            :                                 }
     304                 :            : 
     305                 :          0 :                                 state = STATE_NODE;
     306                 :            : 
     307   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     308         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     309                 :            :                                                        "Unexpected token in <interface>. (1)");
     310                 :            : 
     311                 :          0 :                         break;
     312                 :            : 
     313                 :          0 :                 case STATE_INTERFACE_NAME:
     314                 :            : 
     315         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     316         [ #  # ]:          0 :                                 if (n_depth == 0)
     317                 :          0 :                                         free_and_replace(context->interface_name, name);
     318                 :            : 
     319                 :          0 :                                 state = STATE_INTERFACE;
     320                 :            :                         } else
     321         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     322                 :            :                                                        "Unexpected token in <interface>. (2)");
     323                 :            : 
     324                 :          0 :                         break;
     325                 :            : 
     326                 :          0 :                 case STATE_METHOD:
     327                 :            : 
     328         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     329         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     330                 :          0 :                                         state = STATE_METHOD_NAME;
     331                 :            :                                 else
     332         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     333                 :            :                                                                "Unexpected <method> attribute %s",
     334                 :            :                                                                name);
     335         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     336         [ #  # ]:          0 :                                 if (streq_ptr(name, "arg"))
     337                 :          0 :                                         state = STATE_METHOD_ARG;
     338         [ #  # ]:          0 :                                 else if (streq_ptr(name, "annotation")) {
     339                 :          0 :                                         r = parse_xml_annotation(context, &context->member_flags);
     340         [ #  # ]:          0 :                                         if (r < 0)
     341                 :          0 :                                                 return r;
     342                 :            :                                 } else
     343         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     344                 :            :                                                                "Unexpected <method> tag %s.",
     345                 :            :                                                                name);
     346   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     347         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "method"))) {
     348                 :            : 
     349         [ #  # ]:          0 :                                 if (n_depth == 0) {
     350         [ #  # ]:          0 :                                         if (context->ops->on_method) {
     351                 :          0 :                                                 r = context->ops->on_method(context->interface_name, context->member_name, context->member_signature, context->member_result, context->member_flags, context->userdata);
     352         [ #  # ]:          0 :                                                 if (r < 0)
     353                 :          0 :                                                         return r;
     354                 :            :                                         }
     355                 :            : 
     356                 :          0 :                                         context_reset_member(context);
     357                 :            :                                 }
     358                 :            : 
     359                 :          0 :                                 state = STATE_INTERFACE;
     360                 :            : 
     361   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     362         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     363                 :            :                                                        "Unexpected token in <method> (1).");
     364                 :            : 
     365                 :          0 :                         break;
     366                 :            : 
     367                 :          0 :                 case STATE_METHOD_NAME:
     368                 :            : 
     369         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     370         [ #  # ]:          0 :                                 if (n_depth == 0)
     371                 :          0 :                                         free_and_replace(context->member_name, name);
     372                 :            : 
     373                 :          0 :                                 state = STATE_METHOD;
     374                 :            :                         } else
     375         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     376                 :            :                                                        "Unexpected token in <method> (2).");
     377                 :            : 
     378                 :          0 :                         break;
     379                 :            : 
     380                 :          0 :                 case STATE_METHOD_ARG:
     381                 :            : 
     382         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     383         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     384                 :          0 :                                         state = STATE_METHOD_ARG_NAME;
     385         [ #  # ]:          0 :                                 else if (streq_ptr(name, "type"))
     386                 :          0 :                                         state = STATE_METHOD_ARG_TYPE;
     387         [ #  # ]:          0 :                                 else if (streq_ptr(name, "direction"))
     388                 :          0 :                                         state = STATE_METHOD_ARG_DIRECTION;
     389                 :            :                                 else
     390         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     391                 :            :                                                                "Unexpected method <arg> attribute %s.",
     392                 :            :                                                                name);
     393         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     394         [ #  # ]:          0 :                                 if (streq_ptr(name, "annotation")) {
     395                 :          0 :                                         r = parse_xml_annotation(context, NULL);
     396         [ #  # ]:          0 :                                         if (r < 0)
     397                 :          0 :                                                 return r;
     398                 :            :                                 } else
     399         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     400                 :            :                                                                "Unexpected method <arg> tag %s.",
     401                 :            :                                                                name);
     402   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     403         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "arg"))) {
     404                 :            : 
     405         [ #  # ]:          0 :                                 if (n_depth == 0) {
     406                 :            : 
     407         [ #  # ]:          0 :                                         if (argument_type) {
     408   [ #  #  #  # ]:          0 :                                                 if (!argument_direction || streq(argument_direction, "in")) {
     409         [ #  # ]:          0 :                                                         if (!strextend(&context->member_signature, argument_type, NULL))
     410                 :          0 :                                                                 return log_oom();
     411         [ #  # ]:          0 :                                                 } else if (streq(argument_direction, "out")) {
     412         [ #  # ]:          0 :                                                         if (!strextend(&context->member_result, argument_type, NULL))
     413                 :          0 :                                                                 return log_oom();
     414                 :            :                                                 } else
     415         [ #  # ]:          0 :                                                         log_error("Unexpected method <arg> direction value '%s'.", argument_direction);
     416                 :            :                                         }
     417                 :            : 
     418                 :          0 :                                         argument_type = mfree(argument_type);
     419                 :          0 :                                         argument_direction = mfree(argument_direction);
     420                 :            :                                 }
     421                 :            : 
     422                 :          0 :                                 state = STATE_METHOD;
     423   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     424         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     425                 :            :                                                        "Unexpected token in method <arg>. (1)");
     426                 :            : 
     427                 :          0 :                         break;
     428                 :            : 
     429                 :          0 :                 case STATE_METHOD_ARG_NAME:
     430                 :            : 
     431         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE)
     432                 :          0 :                                 state = STATE_METHOD_ARG;
     433                 :            :                         else
     434         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     435                 :            :                                                        "Unexpected token in method <arg>. (2)");
     436                 :            : 
     437                 :          0 :                         break;
     438                 :            : 
     439                 :          0 :                 case STATE_METHOD_ARG_TYPE:
     440                 :            : 
     441         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     442                 :          0 :                                 free_and_replace(argument_type, name);
     443                 :            : 
     444                 :          0 :                                 state = STATE_METHOD_ARG;
     445                 :            :                         } else
     446         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     447                 :            :                                                        "Unexpected token in method <arg>. (3)");
     448                 :            : 
     449                 :          0 :                         break;
     450                 :            : 
     451                 :          0 :                 case STATE_METHOD_ARG_DIRECTION:
     452                 :            : 
     453         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     454                 :          0 :                                 free_and_replace(argument_direction, name);
     455                 :            : 
     456                 :          0 :                                 state = STATE_METHOD_ARG;
     457                 :            :                         } else
     458         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     459                 :            :                                                        "Unexpected token in method <arg>. (4)");
     460                 :            : 
     461                 :          0 :                         break;
     462                 :            : 
     463                 :          0 :                 case STATE_SIGNAL:
     464                 :            : 
     465         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     466         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     467                 :          0 :                                         state = STATE_SIGNAL_NAME;
     468                 :            :                                 else
     469         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     470                 :            :                                                                "Unexpected <signal> attribute %s.",
     471                 :            :                                                                name);
     472         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     473         [ #  # ]:          0 :                                 if (streq_ptr(name, "arg"))
     474                 :          0 :                                         state = STATE_SIGNAL_ARG;
     475         [ #  # ]:          0 :                                 else if (streq_ptr(name, "annotation")) {
     476                 :          0 :                                         r = parse_xml_annotation(context, &context->member_flags);
     477         [ #  # ]:          0 :                                         if (r < 0)
     478                 :          0 :                                                 return r;
     479                 :            :                                 } else
     480         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     481                 :            :                                                                "Unexpected <signal> tag %s.",
     482                 :            :                                                                name);
     483   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     484         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "signal"))) {
     485                 :            : 
     486         [ #  # ]:          0 :                                 if (n_depth == 0) {
     487         [ #  # ]:          0 :                                         if (context->ops->on_signal) {
     488                 :          0 :                                                 r = context->ops->on_signal(context->interface_name, context->member_name, context->member_signature, context->member_flags, context->userdata);
     489         [ #  # ]:          0 :                                                 if (r < 0)
     490                 :          0 :                                                         return r;
     491                 :            :                                         }
     492                 :            : 
     493                 :          0 :                                         context_reset_member(context);
     494                 :            :                                 }
     495                 :            : 
     496                 :          0 :                                 state = STATE_INTERFACE;
     497                 :            : 
     498   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     499         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     500                 :            :                                                        "Unexpected token in <signal>. (1)");
     501                 :            : 
     502                 :          0 :                         break;
     503                 :            : 
     504                 :          0 :                 case STATE_SIGNAL_NAME:
     505                 :            : 
     506         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     507         [ #  # ]:          0 :                                 if (n_depth == 0)
     508                 :          0 :                                         free_and_replace(context->member_name, name);
     509                 :            : 
     510                 :          0 :                                 state = STATE_SIGNAL;
     511                 :            :                         } else
     512         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     513                 :            :                                                        "Unexpected token in <signal>. (2)");
     514                 :            : 
     515                 :          0 :                         break;
     516                 :            : 
     517                 :          0 :                 case STATE_SIGNAL_ARG:
     518                 :            : 
     519         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     520         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     521                 :          0 :                                         state = STATE_SIGNAL_ARG_NAME;
     522         [ #  # ]:          0 :                                 else if (streq_ptr(name, "type"))
     523                 :          0 :                                         state = STATE_SIGNAL_ARG_TYPE;
     524         [ #  # ]:          0 :                                 else if (streq_ptr(name, "direction"))
     525                 :          0 :                                         state = STATE_SIGNAL_ARG_DIRECTION;
     526                 :            :                                 else
     527         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     528                 :            :                                                                "Unexpected signal <arg> attribute %s.",
     529                 :            :                                                                name);
     530         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     531         [ #  # ]:          0 :                                 if (streq_ptr(name, "annotation")) {
     532                 :          0 :                                         r = parse_xml_annotation(context, NULL);
     533         [ #  # ]:          0 :                                         if (r < 0)
     534                 :          0 :                                                 return r;
     535                 :            :                                 } else
     536         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     537                 :            :                                                                "Unexpected signal <arg> tag %s.",
     538                 :            :                                                                name);
     539   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     540         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "arg"))) {
     541                 :            : 
     542         [ #  # ]:          0 :                                 if (argument_type) {
     543   [ #  #  #  # ]:          0 :                                         if (!argument_direction || streq(argument_direction, "out")) {
     544         [ #  # ]:          0 :                                                 if (!strextend(&context->member_signature, argument_type, NULL))
     545                 :          0 :                                                         return log_oom();
     546                 :            :                                         } else
     547         [ #  # ]:          0 :                                                 log_error("Unexpected signal <arg> direction value '%s'.", argument_direction);
     548                 :            : 
     549                 :          0 :                                         argument_type = mfree(argument_type);
     550                 :            :                                 }
     551                 :            : 
     552                 :          0 :                                 state = STATE_SIGNAL;
     553   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     554         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     555                 :            :                                                        "Unexpected token in signal <arg> (1).");
     556                 :            : 
     557                 :          0 :                         break;
     558                 :            : 
     559                 :          0 :                 case STATE_SIGNAL_ARG_NAME:
     560                 :            : 
     561         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE)
     562                 :          0 :                                 state = STATE_SIGNAL_ARG;
     563                 :            :                         else
     564         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     565                 :            :                                                        "Unexpected token in signal <arg> (2).");
     566                 :            : 
     567                 :          0 :                         break;
     568                 :            : 
     569                 :          0 :                 case STATE_SIGNAL_ARG_TYPE:
     570                 :            : 
     571         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     572                 :          0 :                                 free_and_replace(argument_type, name);
     573                 :            : 
     574                 :          0 :                                 state = STATE_SIGNAL_ARG;
     575                 :            :                         } else
     576         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     577                 :            :                                                        "Unexpected token in signal <arg> (3).");
     578                 :            : 
     579                 :          0 :                         break;
     580                 :            : 
     581                 :          0 :                 case STATE_SIGNAL_ARG_DIRECTION:
     582                 :            : 
     583         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     584                 :          0 :                                 free_and_replace(argument_direction, name);
     585                 :            : 
     586                 :          0 :                                 state = STATE_SIGNAL_ARG;
     587                 :            :                         } else
     588         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     589                 :            :                                                        "Unexpected token in signal <arg>. (4)");
     590                 :            : 
     591                 :          0 :                         break;
     592                 :            : 
     593                 :          0 :                 case STATE_PROPERTY:
     594                 :            : 
     595         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_NAME) {
     596         [ #  # ]:          0 :                                 if (streq_ptr(name, "name"))
     597                 :          0 :                                         state = STATE_PROPERTY_NAME;
     598         [ #  # ]:          0 :                                 else if (streq_ptr(name, "type"))
     599                 :          0 :                                         state  = STATE_PROPERTY_TYPE;
     600         [ #  # ]:          0 :                                 else if (streq_ptr(name, "access"))
     601                 :          0 :                                         state  = STATE_PROPERTY_ACCESS;
     602                 :            :                                 else
     603         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
     604                 :            :                                                                "Unexpected <property> attribute %s.",
     605                 :            :                                                                name);
     606         [ #  # ]:          0 :                         } else if (t == XML_TAG_OPEN) {
     607                 :            : 
     608         [ #  # ]:          0 :                                 if (streq_ptr(name, "annotation")) {
     609                 :          0 :                                         r = parse_xml_annotation(context, &context->member_flags);
     610         [ #  # ]:          0 :                                         if (r < 0)
     611                 :          0 :                                                 return r;
     612                 :            :                                 } else
     613         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     614                 :            :                                                                "Unexpected <property> tag %s.",
     615                 :            :                                                                name);
     616                 :            : 
     617   [ #  #  #  # ]:          0 :                         } else if (t == XML_TAG_CLOSE_EMPTY ||
     618         [ #  # ]:          0 :                                    (t == XML_TAG_CLOSE && streq_ptr(name, "property"))) {
     619                 :            : 
     620         [ #  # ]:          0 :                                 if (n_depth == 0) {
     621         [ #  # ]:          0 :                                         if (context->ops->on_property) {
     622                 :          0 :                                                 r = context->ops->on_property(context->interface_name, context->member_name, context->member_signature, context->member_writable, context->member_flags, context->userdata);
     623         [ #  # ]:          0 :                                                 if (r < 0)
     624                 :          0 :                                                         return r;
     625                 :            :                                         }
     626                 :            : 
     627                 :          0 :                                         context_reset_member(context);
     628                 :            :                                 }
     629                 :            : 
     630                 :          0 :                                 state = STATE_INTERFACE;
     631                 :            : 
     632   [ #  #  #  # ]:          0 :                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE))
     633         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     634                 :            :                                                        "Unexpected token in <property>. (1)");
     635                 :            : 
     636                 :          0 :                         break;
     637                 :            : 
     638                 :          0 :                 case STATE_PROPERTY_NAME:
     639                 :            : 
     640         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     641         [ #  # ]:          0 :                                 if (n_depth == 0)
     642                 :          0 :                                         free_and_replace(context->member_name, name);
     643                 :            : 
     644                 :          0 :                                 state = STATE_PROPERTY;
     645                 :            :                         } else
     646         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     647                 :            :                                                        "Unexpected token in <property>. (2)");
     648                 :            : 
     649                 :          0 :                         break;
     650                 :            : 
     651                 :          0 :                 case STATE_PROPERTY_TYPE:
     652                 :            : 
     653         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     654         [ #  # ]:          0 :                                 if (n_depth == 0)
     655                 :          0 :                                         free_and_replace(context->member_signature, name);
     656                 :            : 
     657                 :          0 :                                 state = STATE_PROPERTY;
     658                 :            :                         } else
     659         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     660                 :            :                                                        "Unexpected token in <property>. (3)");
     661                 :            : 
     662                 :          0 :                         break;
     663                 :            : 
     664                 :          0 :                 case STATE_PROPERTY_ACCESS:
     665                 :            : 
     666         [ #  # ]:          0 :                         if (t == XML_ATTRIBUTE_VALUE) {
     667                 :            : 
     668   [ #  #  #  # ]:          0 :                                 if (streq(name, "readwrite") || streq(name, "write"))
     669                 :          0 :                                         context->member_writable = true;
     670                 :            : 
     671                 :          0 :                                 state = STATE_PROPERTY;
     672                 :            :                         } else
     673         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     674                 :            :                                                        "Unexpected token in <property>. (4)");
     675                 :            : 
     676                 :          0 :                         break;
     677                 :            :                 }
     678                 :          0 :         }
     679                 :            : }
     680                 :            : 
     681                 :          0 : int parse_xml_introspect(const char *prefix, const char *xml, const XMLIntrospectOps *ops, void *userdata) {
     682                 :          0 :         Context context = {
     683                 :            :                 .ops = ops,
     684                 :            :                 .userdata = userdata,
     685                 :            :                 .current = xml,
     686                 :            :         };
     687                 :            : 
     688                 :            :         int r;
     689                 :            : 
     690         [ #  # ]:          0 :         assert(prefix);
     691         [ #  # ]:          0 :         assert(xml);
     692         [ #  # ]:          0 :         assert(ops);
     693                 :            : 
     694                 :          0 :         for (;;) {
     695      [ #  #  # ]:          0 :                 _cleanup_free_ char *name = NULL;
     696                 :            : 
     697                 :          0 :                 r = xml_tokenize(&context.current, &name, &context.xml_state, NULL);
     698         [ #  # ]:          0 :                 if (r < 0) {
     699         [ #  # ]:          0 :                         log_error("XML parse error");
     700                 :          0 :                         goto finish;
     701                 :            :                 }
     702                 :            : 
     703         [ #  # ]:          0 :                 if (r == XML_END) {
     704                 :          0 :                         r = 0;
     705                 :          0 :                         break;
     706                 :            :                 }
     707                 :            : 
     708         [ #  # ]:          0 :                 if (r == XML_TAG_OPEN) {
     709                 :            : 
     710         [ #  # ]:          0 :                         if (streq(name, "node")) {
     711                 :          0 :                                 r = parse_xml_node(&context, prefix, 0);
     712         [ #  # ]:          0 :                                 if (r < 0)
     713                 :          0 :                                         goto finish;
     714                 :            :                         } else {
     715         [ #  # ]:          0 :                                 log_error("Unexpected tag '%s' in introspection data.", name);
     716                 :          0 :                                 r = -EBADMSG;
     717                 :          0 :                                 goto finish;
     718                 :            :                         }
     719   [ #  #  #  # ]:          0 :                 } else if (r != XML_TEXT || !in_charset(name, WHITESPACE)) {
     720         [ #  # ]:          0 :                         log_error("Unexpected token.");
     721                 :          0 :                         r = -EBADMSG;
     722                 :          0 :                         goto finish;
     723                 :            :                 }
     724                 :            :         }
     725                 :            : 
     726                 :          0 : finish:
     727                 :          0 :         context_reset_interface(&context);
     728                 :            : 
     729                 :          0 :         return r;
     730                 :            : }

Generated by: LCOV version 1.14