busctl-introspect.c revision a1e58e8ee1c84b633d6d6d651d5328d4dd4eba5b
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2014 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "util.h"
#include "xml.h"
#include "sd-bus-vtable.h"
#include "busctl-introspect.h"
#define NODE_DEPTH_MAX 16
typedef struct Context {
const XMLIntrospectOps *ops;
void *userdata;
char *interface_name;
char *member_name;
char *member_signature;
char *member_result;
bool member_writable;
const char *current;
void *xml_state;
} Context;
static void context_reset_member(Context *c) {
free(c->member_name);
free(c->member_signature);
free(c->member_result);
c->member_flags = 0;
c->member_writable = false;
}
static void context_reset_interface(Context *c) {
c->interface_flags = 0;
}
enum {
} state = STATE_ANNOTATION;
for (;;) {
int t;
if (t < 0) {
log_error("XML parse error.");
return t;
}
if (t == XML_END) {
log_error("Premature end of XML data.");
return -EBADMSG;
}
switch (state) {
case STATE_ANNOTATION:
if (t == XML_ATTRIBUTE_NAME) {
state = STATE_NAME;
state = STATE_VALUE;
else {
return -EBADMSG;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (flags) {
*flags = (*flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) | SD_BUS_VTABLE_PROPERTY_CONST;
*flags = (*flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_CONST)) | SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
*flags = *flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION);
}
}
return 0;
log_error("Unexpected token in <annotation>. (1)");
return -EINVAL;
}
break;
case STATE_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
} else {
log_error("Unexpected token in <annotation>. (2)");
return -EINVAL;
}
break;
case STATE_VALUE:
if (t == XML_ATTRIBUTE_VALUE) {
} else {
log_error("Unexpected token in <annotation>. (3)");
return -EINVAL;
}
break;
default:
assert_not_reached("Bad state");
}
}
}
enum {
} state = STATE_NODE;
int r;
if (n_depth > NODE_DEPTH_MAX) {
log_error("<node> depth too high.");
return -EINVAL;
}
for (;;) {
int t;
if (t < 0) {
log_error("XML parse error.");
return t;
}
if (t == XML_END) {
log_error("Premature end of XML data.");
return -EBADMSG;
}
switch (state) {
case STATE_NODE:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EBADMSG;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (r < 0)
return r;
}
return 0;
log_error("Unexpected token in <node>. (1)");
return -EINVAL;
}
break;
case STATE_NODE_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
if (name[0] == '/') {
} else {
else
if (!node_path)
return log_oom();
}
state = STATE_NODE;
} else {
log_error("Unexpected token in <node>. (2)");
return -EINVAL;
}
break;
case STATE_INTERFACE:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EINVAL;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (n_depth == 0) {
r = context->ops->on_interface(context->interface_name, context->interface_flags, context->userdata);
if (r < 0)
return r;
}
}
state = STATE_NODE;
log_error("Unexpected token in <interface>. (1)");
return -EINVAL;
}
break;
case STATE_INTERFACE_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
if (n_depth == 0) {
}
} else {
log_error("Unexpected token in <interface>. (2)");
return -EINVAL;
}
break;
case STATE_METHOD:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EINVAL;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (n_depth == 0) {
r = context->ops->on_method(context->interface_name, context->member_name, context->member_signature, context->member_result, context->member_flags, context->userdata);
if (r < 0)
return r;
}
}
log_error("Unexpected token in <method> (1).");
return -EINVAL;
}
break;
case STATE_METHOD_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
if (n_depth == 0) {
}
} else {
log_error("Unexpected token in <method> (2).");
return -EINVAL;
}
break;
case STATE_METHOD_ARG:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EINVAL;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (n_depth == 0) {
if (argument_type) {
return log_oom();
return log_oom();
}
}
}
log_error("Unexpected token in method <arg>. (1)");
return -EINVAL;
}
break;
case STATE_METHOD_ARG_NAME:
if (t == XML_ATTRIBUTE_VALUE)
else {
log_error("Unexpected token in method <arg>. (2)");
return -EINVAL;
}
break;
case STATE_METHOD_ARG_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
} else {
log_error("Unexpected token in method <arg>. (3)");
return -EINVAL;
}
break;
if (t == XML_ATTRIBUTE_VALUE) {
} else {
log_error("Unexpected token in method <arg>. (4)");
return -EINVAL;
}
break;
case STATE_SIGNAL:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EINVAL;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (n_depth == 0) {
r = context->ops->on_signal(context->interface_name, context->member_name, context->member_signature, context->member_flags, context->userdata);
if (r < 0)
return r;
}
}
log_error("Unexpected token in <signal>. (1)");
return -EINVAL;
}
break;
case STATE_SIGNAL_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
if (n_depth == 0) {
}
} else {
log_error("Unexpected token in <signal>. (2)");
return -EINVAL;
}
break;
case STATE_SIGNAL_ARG:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EINVAL;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (argument_type) {
return log_oom();
}
log_error("Unexpected token in signal <arg> (1).");
return -EINVAL;
}
break;
case STATE_SIGNAL_ARG_NAME:
if (t == XML_ATTRIBUTE_VALUE)
else {
log_error("Unexpected token in signal <arg> (2).");
return -EINVAL;
}
break;
case STATE_SIGNAL_ARG_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
} else {
log_error("Unexpected token in signal <arg> (3).");
return -EINVAL;
}
break;
case STATE_PROPERTY:
if (t == XML_ATTRIBUTE_NAME) {
else {
return -EBADMSG;
}
} else if (t == XML_TAG_OPEN) {
if (r < 0)
return r;
} else {
return -EINVAL;
}
} else if (t == XML_TAG_CLOSE_EMPTY ||
if (n_depth == 0) {
r = context->ops->on_property(context->interface_name, context->member_name, context->member_signature, context->member_writable, context->member_flags, context->userdata);
if (r < 0)
return r;
}
}
log_error("Unexpected token in <property>. (1)");
return -EINVAL;
}
break;
case STATE_PROPERTY_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
if (n_depth == 0) {
}
} else {
log_error("Unexpected token in <property>. (2)");
return -EINVAL;
}
break;
case STATE_PROPERTY_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
if (n_depth == 0) {
}
} else {
log_error("Unexpected token in <property>. (3)");
return -EINVAL;
}
break;
case STATE_PROPERTY_ACCESS:
if (t == XML_ATTRIBUTE_VALUE) {
context->member_writable = true;
} else {
log_error("Unexpected token in <property>. (4)");
return -EINVAL;
}
break;
}
}
}
int parse_xml_introspect(const char *prefix, const char *xml, const XMLIntrospectOps *ops, void *userdata) {
};
int r;
for (;;) {
if (r < 0) {
log_error("XML parse error");
goto finish;
}
if (r == XML_END) {
r = 0;
break;
}
if (r == XML_TAG_OPEN) {
if (r < 0)
goto finish;
} else {
r = -EBADMSG;
goto finish;
}
log_error("Unexpected token.");
r = -EBADMSG;
goto finish;
}
}
return r;
}