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