LCOV - code coverage report
Current view: top level - busctl - busctl-introspect.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 391 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 5 0.0 %

          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