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