dbus: Move introspection support into a separate file
This commit is contained in:
parent
64bde6d730
commit
04551ee6d6
5 changed files with 532 additions and 527 deletions
|
@ -1083,6 +1083,7 @@ ifndef DBUS_INCLUDE
|
|||
DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
|
||||
endif
|
||||
ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
|
||||
DBUS_OBJS += dbus/dbus_new_introspect.o
|
||||
DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
|
||||
DBUS_INCLUDE += $(shell xml2-config --cflags)
|
||||
DBUS_LIBS += $(shell xml2-config --libs)
|
||||
|
|
|
@ -70,6 +70,7 @@ LIB_OBJS= \
|
|||
dbus_new.o \
|
||||
dbus_new_handlers.o \
|
||||
dbus_new_helpers.o \
|
||||
dbus_new_introspect.o \
|
||||
dbus_dict_helpers.o
|
||||
|
||||
ifdef CONFIG_WPS
|
||||
|
|
|
@ -16,534 +16,10 @@
|
|||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eloop.h"
|
||||
#include "dbus_common.h"
|
||||
#include "dbus_common_i.h"
|
||||
#include "dbus_new_helpers.h"
|
||||
|
||||
/**
|
||||
* struct wpa_dbus_method_desc - DBus method description
|
||||
*/
|
||||
struct wpa_dbus_method_desc {
|
||||
/* pointer to next description in list */
|
||||
struct wpa_dbus_method_desc *next;
|
||||
|
||||
/* method interface */
|
||||
char *dbus_interface;
|
||||
/* method name */
|
||||
char *dbus_method;
|
||||
|
||||
/* method handling function */
|
||||
WPADBusMethodHandler method_handler;
|
||||
|
||||
/* number of method arguments */
|
||||
int args_num;
|
||||
/* array of arguments */
|
||||
struct wpa_dbus_argument args[];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct wpa_dbus_signal_desc - DBus signal description
|
||||
*/
|
||||
struct wpa_dbus_signal_desc {
|
||||
/* pointer to next description in list */
|
||||
struct wpa_dbus_signal_desc *next;
|
||||
|
||||
/* signal interface */
|
||||
char *dbus_interface;
|
||||
/* signal name */
|
||||
char *dbus_signal;
|
||||
|
||||
/* number of signal arguments */
|
||||
int args_num;
|
||||
/* array of arguments */
|
||||
struct wpa_dbus_argument args[0];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct wpa_dbus_property_desc - DBus property description
|
||||
*/
|
||||
struct wpa_dbus_property_desc {
|
||||
/* pointer to next description in list */
|
||||
struct wpa_dbus_property_desc *next;
|
||||
|
||||
/* property interface */
|
||||
char *dbus_interface;
|
||||
/* property name */
|
||||
char *dbus_property;
|
||||
/* property type signature in DBus type notation */
|
||||
char *type;
|
||||
|
||||
/* property access permissions */
|
||||
enum dbus_prop_access access;
|
||||
|
||||
/* property getter function */
|
||||
WPADBusPropertyAccessor getter;
|
||||
/* property setter function */
|
||||
WPADBusPropertyAccessor setter;
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
|
||||
#include <libxml/tree.h>
|
||||
|
||||
struct interfaces {
|
||||
struct interfaces *next;
|
||||
char *dbus_interface;
|
||||
xmlNodePtr interface_node;
|
||||
};
|
||||
#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
|
||||
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
|
||||
|
||||
/**
|
||||
* extract_interfaces - Extract interfaces from methods, signals and props
|
||||
* @obj_dsc: Description of object from which interfaces will be extracted
|
||||
* @root_node: root node of XML introspection document
|
||||
* Returns: List of interfaces found in object description
|
||||
*
|
||||
* Iterates over all methods, signals and properties registered with
|
||||
* object and collects all declared DBus interfaces and create interface's
|
||||
* node in XML root node for each. Returned list elements contains interface
|
||||
* name and XML node of corresponding interface.
|
||||
*/
|
||||
static struct interfaces * extract_interfaces(
|
||||
struct wpa_dbus_object_desc *obj_dsc, xmlNodePtr root_node)
|
||||
{
|
||||
struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
|
||||
struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
|
||||
struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
|
||||
struct interfaces *head = NULL;
|
||||
struct interfaces *iface, *last;
|
||||
int len;
|
||||
|
||||
/* extract interfaces from methods */
|
||||
while (method_dsc) {
|
||||
iface = head;
|
||||
last = NULL;
|
||||
|
||||
/* go to next method if its interface is already extracted */
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
method_dsc->dbus_interface))
|
||||
break;
|
||||
last = iface;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (iface) {
|
||||
method_dsc = method_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
iface = os_zalloc(sizeof(struct interfaces));
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data");
|
||||
method_dsc = method_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = iface;
|
||||
else
|
||||
head = iface;
|
||||
|
||||
len = os_strlen(method_dsc->dbus_interface) + 1;
|
||||
iface->dbus_interface = os_malloc(len);
|
||||
if (!iface->dbus_interface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data (interface "
|
||||
"name)");
|
||||
method_dsc = method_dsc->next;
|
||||
continue;
|
||||
}
|
||||
os_strncpy(iface->dbus_interface, method_dsc->dbus_interface,
|
||||
len);
|
||||
|
||||
iface->interface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface",
|
||||
NULL);
|
||||
xmlNewProp(iface->interface_node, BAD_CAST "name",
|
||||
BAD_CAST method_dsc->dbus_interface);
|
||||
|
||||
method_dsc = method_dsc->next;
|
||||
}
|
||||
|
||||
/* extract interfaces from signals */
|
||||
while (signal_dsc) {
|
||||
iface = head;
|
||||
last = NULL;
|
||||
|
||||
/* go to next signal if its interface is already extracted */
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
signal_dsc->dbus_interface))
|
||||
break;
|
||||
last = iface;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (iface) {
|
||||
signal_dsc = signal_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
iface = os_zalloc(sizeof(struct interfaces));
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data");
|
||||
signal_dsc = signal_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = iface;
|
||||
else
|
||||
head = iface;
|
||||
|
||||
len = os_strlen(signal_dsc->dbus_interface) + 1;
|
||||
iface->dbus_interface = os_malloc(len);
|
||||
if (!iface->dbus_interface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data (interface "
|
||||
"name)");
|
||||
signal_dsc = signal_dsc->next;
|
||||
continue;
|
||||
}
|
||||
os_strncpy(iface->dbus_interface, signal_dsc->dbus_interface,
|
||||
len);
|
||||
|
||||
iface->interface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface",
|
||||
NULL);
|
||||
xmlNewProp(iface->interface_node, BAD_CAST "name",
|
||||
BAD_CAST signal_dsc->dbus_interface);
|
||||
|
||||
signal_dsc = signal_dsc->next;
|
||||
}
|
||||
|
||||
/* extract interfaces from properties */
|
||||
while (property_dsc) {
|
||||
iface = head;
|
||||
last = NULL;
|
||||
|
||||
/* go to next property if its interface is already extracted */
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
property_dsc->dbus_interface))
|
||||
break;
|
||||
last = iface;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (iface) {
|
||||
property_dsc = property_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
iface = os_zalloc(sizeof(struct interfaces));
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data");
|
||||
property_dsc = property_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = iface;
|
||||
else
|
||||
head = iface;
|
||||
|
||||
len = os_strlen(property_dsc->dbus_interface) + 1;
|
||||
iface->dbus_interface = os_malloc(len);
|
||||
if (!iface->dbus_interface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data (interface "
|
||||
"name)");
|
||||
property_dsc = property_dsc->next;
|
||||
continue;
|
||||
}
|
||||
os_strncpy(iface->dbus_interface, property_dsc->dbus_interface,
|
||||
len);
|
||||
|
||||
iface->interface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface",
|
||||
NULL);
|
||||
xmlNewProp(iface->interface_node, BAD_CAST "name",
|
||||
BAD_CAST property_dsc->dbus_interface);
|
||||
|
||||
property_dsc = property_dsc->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* introspect - Responds for Introspect calls on object
|
||||
* @message: Message with Introspect call
|
||||
* @obj_dsc: Object description on which Introspect was called
|
||||
* Returns: Message with introspection result XML string as only argument
|
||||
*
|
||||
* Iterates over all methods, signals and properties registered with
|
||||
* object and generates introspection data for the object as XML string.
|
||||
*/
|
||||
static DBusMessage * introspect(DBusMessage *message,
|
||||
struct wpa_dbus_object_desc *obj_dsc)
|
||||
{
|
||||
|
||||
DBusMessage *reply;
|
||||
struct interfaces *ifaces, *tmp;
|
||||
struct wpa_dbus_signal_desc *signal_dsc;
|
||||
struct wpa_dbus_method_desc *method_dsc;
|
||||
struct wpa_dbus_property_desc *property_dsc;
|
||||
xmlChar *intro_str;
|
||||
char **children;
|
||||
int i, s;
|
||||
|
||||
xmlDocPtr doc = NULL;
|
||||
xmlNodePtr root_node = NULL, node = NULL, iface_node = NULL;
|
||||
xmlNodePtr method_node = NULL, signal_node = NULL;
|
||||
xmlNodePtr property_node = NULL, arg_node = NULL;
|
||||
|
||||
/* root node and dtd */
|
||||
doc = xmlNewDoc(BAD_CAST "1.0");
|
||||
root_node = xmlNewNode(NULL, BAD_CAST "node");
|
||||
xmlDocSetRootElement(doc, root_node);
|
||||
xmlCreateIntSubset(doc, BAD_CAST "node",
|
||||
BAD_CAST DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER,
|
||||
BAD_CAST DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER);
|
||||
|
||||
/* Add Introspectable interface */
|
||||
iface_node = xmlNewChild(root_node, NULL, BAD_CAST "interface", NULL);
|
||||
xmlNewProp(iface_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_INTROSPECTION_INTERFACE);
|
||||
|
||||
/* Add Introspect method */
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_INTROSPECTION_METHOD);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "data");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
|
||||
|
||||
|
||||
/* Add Properties interface */
|
||||
iface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface", NULL);
|
||||
xmlNewProp(iface_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_INTERFACE);
|
||||
|
||||
/* Add Get method */
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_GET);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
|
||||
/* Add GetAll method */
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_GETALL);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "props");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "a{sv}");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
|
||||
/* Add Set method */
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_SET);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
|
||||
/* get all interfaces registered with object */
|
||||
ifaces = extract_interfaces(obj_dsc, root_node);
|
||||
|
||||
/* create methods' nodes */
|
||||
method_dsc = obj_dsc->methods;
|
||||
while (method_dsc) {
|
||||
|
||||
struct interfaces *iface = ifaces;
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
method_dsc->dbus_interface))
|
||||
break;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (!iface)
|
||||
continue;
|
||||
|
||||
iface_node = iface->interface_node;
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method",
|
||||
NULL);
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST method_dsc->dbus_method);
|
||||
|
||||
/* create args' nodes */
|
||||
for (i = 0; i < method_dsc->args_num; i++) {
|
||||
struct wpa_dbus_argument arg = method_dsc->args[i];
|
||||
arg_node = xmlNewChild(method_node, NULL,
|
||||
BAD_CAST "arg", NULL);
|
||||
if (arg.name && strlen(arg.name)) {
|
||||
xmlNewProp(arg_node, BAD_CAST "name",
|
||||
BAD_CAST arg.name);
|
||||
}
|
||||
xmlNewProp(arg_node, BAD_CAST "type",
|
||||
BAD_CAST arg.type);
|
||||
xmlNewProp(arg_node, BAD_CAST "direction",
|
||||
BAD_CAST (arg.dir == ARG_IN ?
|
||||
"in" : "out"));
|
||||
}
|
||||
method_dsc = method_dsc->next;
|
||||
}
|
||||
|
||||
/* create signals' nodes */
|
||||
signal_dsc = obj_dsc->signals;
|
||||
while (signal_dsc) {
|
||||
|
||||
struct interfaces *iface = ifaces;
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
signal_dsc->dbus_interface))
|
||||
break;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (!iface)
|
||||
continue;
|
||||
|
||||
iface_node = iface->interface_node;
|
||||
signal_node = xmlNewChild(iface_node, NULL, BAD_CAST "signal",
|
||||
NULL);
|
||||
xmlNewProp(signal_node, BAD_CAST "name",
|
||||
BAD_CAST signal_dsc->dbus_signal);
|
||||
|
||||
/* create args' nodes */
|
||||
for (i = 0; i < signal_dsc->args_num; i++) {
|
||||
struct wpa_dbus_argument arg = signal_dsc->args[i];
|
||||
arg_node = xmlNewChild(signal_node, NULL,
|
||||
BAD_CAST "arg", NULL);
|
||||
if (arg.name && strlen(arg.name)) {
|
||||
xmlNewProp(arg_node, BAD_CAST "name",
|
||||
BAD_CAST arg.name);
|
||||
}
|
||||
xmlNewProp(arg_node, BAD_CAST "type",
|
||||
BAD_CAST arg.type);
|
||||
}
|
||||
signal_dsc = signal_dsc->next;
|
||||
}
|
||||
|
||||
/* create properties' nodes */
|
||||
property_dsc = obj_dsc->properties;
|
||||
while (property_dsc) {
|
||||
|
||||
struct interfaces *iface = ifaces;
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
property_dsc->dbus_interface))
|
||||
break;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (!iface)
|
||||
continue;
|
||||
|
||||
iface_node = iface->interface_node;
|
||||
property_node = xmlNewChild(iface_node, NULL,
|
||||
BAD_CAST "property", NULL);
|
||||
xmlNewProp(property_node, BAD_CAST "name",
|
||||
BAD_CAST property_dsc->dbus_property);
|
||||
xmlNewProp(property_node, BAD_CAST "type",
|
||||
BAD_CAST property_dsc->type);
|
||||
xmlNewProp(property_node, BAD_CAST "access", BAD_CAST
|
||||
(property_dsc->access == R ? "read" :
|
||||
(property_dsc->access == W ?
|
||||
"write" : "readwrite")));
|
||||
|
||||
property_dsc = property_dsc->next;
|
||||
}
|
||||
|
||||
/* add child nodes to introspection tree; */
|
||||
dbus_connection_list_registered(obj_dsc->connection,
|
||||
dbus_message_get_path(message),
|
||||
&children);
|
||||
for (i = 0; children[i]; i++) {
|
||||
node = xmlNewChild(root_node, NULL, BAD_CAST "node", NULL);
|
||||
xmlNewProp(node, BAD_CAST "name", BAD_CAST children[i]);
|
||||
}
|
||||
dbus_free_string_array(children);
|
||||
|
||||
|
||||
xmlDocDumpFormatMemory(doc, &intro_str, &s, 1);
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
while (ifaces) {
|
||||
tmp = ifaces;
|
||||
ifaces = ifaces->next;
|
||||
os_free(tmp->dbus_interface);
|
||||
os_free(tmp);
|
||||
}
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (reply == NULL) {
|
||||
xmlFree(intro_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
xmlFree(intro_str);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
|
||||
|
||||
/**
|
||||
* introspect - Responds for Introspect calls on object
|
||||
* @message: Message with Introspect call
|
||||
* @obj_dsc: Object description on which Introspect was called
|
||||
* Returns: Message with introspection result XML string as only argument
|
||||
*
|
||||
* Returns error informing that introspection support was not compiled.
|
||||
*/
|
||||
static DBusMessage * introspect(DBusMessage *message,
|
||||
struct wpa_dbus_object_desc *obj_dsc)
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
|
||||
"wpa_supplicant was compiled without "
|
||||
"introspection support.");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
|
||||
|
||||
|
||||
/**
|
||||
* recursive_iter_copy - Reads arguments from one iterator and
|
||||
|
@ -935,9 +411,16 @@ static DBusHandlerResult message_handler(DBusConnection *connection,
|
|||
if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
|
||||
WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
|
||||
!os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
|
||||
WPAS_DBUS_INTERFACE_MAX))
|
||||
reply = introspect(message, obj_dsc);
|
||||
else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
|
||||
WPAS_DBUS_INTERFACE_MAX)) {
|
||||
#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
|
||||
reply = wpa_dbus_introspect(message, obj_dsc);
|
||||
#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
|
||||
reply = dbus_message_new_error(
|
||||
message, DBUS_ERROR_UNKNOWN_METHOD,
|
||||
"wpa_supplicant was compiled without "
|
||||
"introspection support.");
|
||||
#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
|
||||
} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
|
||||
WPAS_DBUS_INTERFACE_MAX)) {
|
||||
/* if message is properties method call */
|
||||
reply = properties_handler(message, obj_dsc);
|
||||
|
|
|
@ -52,6 +52,69 @@ struct wpa_dbus_argument {
|
|||
|
||||
#define END_ARGS { NULL, NULL, ARG_IN }
|
||||
|
||||
/**
|
||||
* struct wpa_dbus_method_desc - DBus method description
|
||||
*/
|
||||
struct wpa_dbus_method_desc {
|
||||
/* pointer to next description in list */
|
||||
struct wpa_dbus_method_desc *next;
|
||||
|
||||
/* method interface */
|
||||
char *dbus_interface;
|
||||
/* method name */
|
||||
char *dbus_method;
|
||||
|
||||
/* method handling function */
|
||||
WPADBusMethodHandler method_handler;
|
||||
|
||||
/* number of method arguments */
|
||||
int args_num;
|
||||
/* array of arguments */
|
||||
struct wpa_dbus_argument args[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wpa_dbus_signal_desc - DBus signal description
|
||||
*/
|
||||
struct wpa_dbus_signal_desc {
|
||||
/* pointer to next description in list */
|
||||
struct wpa_dbus_signal_desc *next;
|
||||
|
||||
/* signal interface */
|
||||
char *dbus_interface;
|
||||
/* signal name */
|
||||
char *dbus_signal;
|
||||
|
||||
/* number of signal arguments */
|
||||
int args_num;
|
||||
/* array of arguments */
|
||||
struct wpa_dbus_argument args[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wpa_dbus_property_desc - DBus property description
|
||||
*/
|
||||
struct wpa_dbus_property_desc {
|
||||
/* pointer to next description in list */
|
||||
struct wpa_dbus_property_desc *next;
|
||||
|
||||
/* property interface */
|
||||
char *dbus_interface;
|
||||
/* property name */
|
||||
char *dbus_property;
|
||||
/* property type signature in DBus type notation */
|
||||
char *type;
|
||||
|
||||
/* property access permissions */
|
||||
enum dbus_prop_access access;
|
||||
|
||||
/* property getter function */
|
||||
WPADBusPropertyAccessor getter;
|
||||
/* property setter function */
|
||||
WPADBusPropertyAccessor setter;
|
||||
};
|
||||
|
||||
|
||||
#ifndef SIGPOLL
|
||||
#ifdef SIGIO
|
||||
/*
|
||||
|
@ -118,4 +181,7 @@ void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
|
|||
const char *path, const char *interface,
|
||||
DBusMessageIter *dict_iter);
|
||||
|
||||
DBusMessage * wpa_dbus_introspect(DBusMessage *message,
|
||||
struct wpa_dbus_object_desc *obj_dsc);
|
||||
|
||||
#endif /* WPA_DBUS_CTRL_H */
|
||||
|
|
454
wpa_supplicant/dbus/dbus_new_introspect.c
Normal file
454
wpa_supplicant/dbus/dbus_new_introspect.c
Normal file
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* WPA Supplicant / dbus-based control interface
|
||||
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
|
||||
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "dbus_common_i.h"
|
||||
#include "dbus_new_helpers.h"
|
||||
|
||||
|
||||
struct interfaces {
|
||||
struct interfaces *next;
|
||||
char *dbus_interface;
|
||||
xmlNodePtr interface_node;
|
||||
};
|
||||
|
||||
/**
|
||||
* extract_interfaces - Extract interfaces from methods, signals and props
|
||||
* @obj_dsc: Description of object from which interfaces will be extracted
|
||||
* @root_node: root node of XML introspection document
|
||||
* Returns: List of interfaces found in object description
|
||||
*
|
||||
* Iterates over all methods, signals and properties registered with
|
||||
* object and collects all declared DBus interfaces and create interface's
|
||||
* node in XML root node for each. Returned list elements contains interface
|
||||
* name and XML node of corresponding interface.
|
||||
*/
|
||||
static struct interfaces * extract_interfaces(
|
||||
struct wpa_dbus_object_desc *obj_dsc, xmlNodePtr root_node)
|
||||
{
|
||||
struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
|
||||
struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
|
||||
struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
|
||||
struct interfaces *head = NULL;
|
||||
struct interfaces *iface, *last;
|
||||
int len;
|
||||
|
||||
/* extract interfaces from methods */
|
||||
while (method_dsc) {
|
||||
iface = head;
|
||||
last = NULL;
|
||||
|
||||
/* go to next method if its interface is already extracted */
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
method_dsc->dbus_interface))
|
||||
break;
|
||||
last = iface;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (iface) {
|
||||
method_dsc = method_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
iface = os_zalloc(sizeof(struct interfaces));
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data");
|
||||
method_dsc = method_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = iface;
|
||||
else
|
||||
head = iface;
|
||||
|
||||
len = os_strlen(method_dsc->dbus_interface) + 1;
|
||||
iface->dbus_interface = os_malloc(len);
|
||||
if (!iface->dbus_interface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data (interface "
|
||||
"name)");
|
||||
method_dsc = method_dsc->next;
|
||||
continue;
|
||||
}
|
||||
os_strncpy(iface->dbus_interface, method_dsc->dbus_interface,
|
||||
len);
|
||||
|
||||
iface->interface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface",
|
||||
NULL);
|
||||
xmlNewProp(iface->interface_node, BAD_CAST "name",
|
||||
BAD_CAST method_dsc->dbus_interface);
|
||||
|
||||
method_dsc = method_dsc->next;
|
||||
}
|
||||
|
||||
/* extract interfaces from signals */
|
||||
while (signal_dsc) {
|
||||
iface = head;
|
||||
last = NULL;
|
||||
|
||||
/* go to next signal if its interface is already extracted */
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
signal_dsc->dbus_interface))
|
||||
break;
|
||||
last = iface;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (iface) {
|
||||
signal_dsc = signal_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
iface = os_zalloc(sizeof(struct interfaces));
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data");
|
||||
signal_dsc = signal_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = iface;
|
||||
else
|
||||
head = iface;
|
||||
|
||||
len = os_strlen(signal_dsc->dbus_interface) + 1;
|
||||
iface->dbus_interface = os_malloc(len);
|
||||
if (!iface->dbus_interface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data (interface "
|
||||
"name)");
|
||||
signal_dsc = signal_dsc->next;
|
||||
continue;
|
||||
}
|
||||
os_strncpy(iface->dbus_interface, signal_dsc->dbus_interface,
|
||||
len);
|
||||
|
||||
iface->interface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface",
|
||||
NULL);
|
||||
xmlNewProp(iface->interface_node, BAD_CAST "name",
|
||||
BAD_CAST signal_dsc->dbus_interface);
|
||||
|
||||
signal_dsc = signal_dsc->next;
|
||||
}
|
||||
|
||||
/* extract interfaces from properties */
|
||||
while (property_dsc) {
|
||||
iface = head;
|
||||
last = NULL;
|
||||
|
||||
/* go to next property if its interface is already extracted */
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
property_dsc->dbus_interface))
|
||||
break;
|
||||
last = iface;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (iface) {
|
||||
property_dsc = property_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
iface = os_zalloc(sizeof(struct interfaces));
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data");
|
||||
property_dsc = property_dsc->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = iface;
|
||||
else
|
||||
head = iface;
|
||||
|
||||
len = os_strlen(property_dsc->dbus_interface) + 1;
|
||||
iface->dbus_interface = os_malloc(len);
|
||||
if (!iface->dbus_interface) {
|
||||
wpa_printf(MSG_ERROR, "Not enough memory to create "
|
||||
"interface introspection data (interface "
|
||||
"name)");
|
||||
property_dsc = property_dsc->next;
|
||||
continue;
|
||||
}
|
||||
os_strncpy(iface->dbus_interface, property_dsc->dbus_interface,
|
||||
len);
|
||||
|
||||
iface->interface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface",
|
||||
NULL);
|
||||
xmlNewProp(iface->interface_node, BAD_CAST "name",
|
||||
BAD_CAST property_dsc->dbus_interface);
|
||||
|
||||
property_dsc = property_dsc->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_dbus_introspect - Responds for Introspect calls on object
|
||||
* @message: Message with Introspect call
|
||||
* @obj_dsc: Object description on which Introspect was called
|
||||
* Returns: Message with introspection result XML string as only argument
|
||||
*
|
||||
* Iterates over all methods, signals and properties registered with
|
||||
* object and generates introspection data for the object as XML string.
|
||||
*/
|
||||
DBusMessage * wpa_dbus_introspect(DBusMessage *message,
|
||||
struct wpa_dbus_object_desc *obj_dsc)
|
||||
{
|
||||
|
||||
DBusMessage *reply;
|
||||
struct interfaces *ifaces, *tmp;
|
||||
struct wpa_dbus_signal_desc *signal_dsc;
|
||||
struct wpa_dbus_method_desc *method_dsc;
|
||||
struct wpa_dbus_property_desc *property_dsc;
|
||||
xmlChar *intro_str;
|
||||
char **children;
|
||||
int i, s;
|
||||
|
||||
xmlDocPtr doc = NULL;
|
||||
xmlNodePtr root_node = NULL, node = NULL, iface_node = NULL;
|
||||
xmlNodePtr method_node = NULL, signal_node = NULL;
|
||||
xmlNodePtr property_node = NULL, arg_node = NULL;
|
||||
|
||||
/* root node and dtd */
|
||||
doc = xmlNewDoc(BAD_CAST "1.0");
|
||||
root_node = xmlNewNode(NULL, BAD_CAST "node");
|
||||
xmlDocSetRootElement(doc, root_node);
|
||||
xmlCreateIntSubset(doc, BAD_CAST "node",
|
||||
BAD_CAST DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER,
|
||||
BAD_CAST DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER);
|
||||
|
||||
/* Add Introspectable interface */
|
||||
iface_node = xmlNewChild(root_node, NULL, BAD_CAST "interface", NULL);
|
||||
xmlNewProp(iface_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_INTROSPECTION_INTERFACE);
|
||||
|
||||
/* Add Introspect method */
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_INTROSPECTION_METHOD);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "data");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
|
||||
|
||||
|
||||
/* Add Properties interface */
|
||||
iface_node = xmlNewChild(root_node, NULL,
|
||||
BAD_CAST "interface", NULL);
|
||||
xmlNewProp(iface_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_INTERFACE);
|
||||
|
||||
/* Add Get method */
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_GET);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
|
||||
/* Add GetAll method */
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_GETALL);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "props");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "a{sv}");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
|
||||
|
||||
/* Add Set method */
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST WPA_DBUS_PROPERTIES_SET);
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
|
||||
xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
|
||||
xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
|
||||
xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
|
||||
|
||||
/* get all interfaces registered with object */
|
||||
ifaces = extract_interfaces(obj_dsc, root_node);
|
||||
|
||||
/* create methods' nodes */
|
||||
method_dsc = obj_dsc->methods;
|
||||
while (method_dsc) {
|
||||
|
||||
struct interfaces *iface = ifaces;
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
method_dsc->dbus_interface))
|
||||
break;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (!iface)
|
||||
continue;
|
||||
|
||||
iface_node = iface->interface_node;
|
||||
method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method",
|
||||
NULL);
|
||||
xmlNewProp(method_node, BAD_CAST "name",
|
||||
BAD_CAST method_dsc->dbus_method);
|
||||
|
||||
/* create args' nodes */
|
||||
for (i = 0; i < method_dsc->args_num; i++) {
|
||||
struct wpa_dbus_argument arg = method_dsc->args[i];
|
||||
arg_node = xmlNewChild(method_node, NULL,
|
||||
BAD_CAST "arg", NULL);
|
||||
if (arg.name && strlen(arg.name)) {
|
||||
xmlNewProp(arg_node, BAD_CAST "name",
|
||||
BAD_CAST arg.name);
|
||||
}
|
||||
xmlNewProp(arg_node, BAD_CAST "type",
|
||||
BAD_CAST arg.type);
|
||||
xmlNewProp(arg_node, BAD_CAST "direction",
|
||||
BAD_CAST (arg.dir == ARG_IN ?
|
||||
"in" : "out"));
|
||||
}
|
||||
method_dsc = method_dsc->next;
|
||||
}
|
||||
|
||||
/* create signals' nodes */
|
||||
signal_dsc = obj_dsc->signals;
|
||||
while (signal_dsc) {
|
||||
|
||||
struct interfaces *iface = ifaces;
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
signal_dsc->dbus_interface))
|
||||
break;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (!iface)
|
||||
continue;
|
||||
|
||||
iface_node = iface->interface_node;
|
||||
signal_node = xmlNewChild(iface_node, NULL, BAD_CAST "signal",
|
||||
NULL);
|
||||
xmlNewProp(signal_node, BAD_CAST "name",
|
||||
BAD_CAST signal_dsc->dbus_signal);
|
||||
|
||||
/* create args' nodes */
|
||||
for (i = 0; i < signal_dsc->args_num; i++) {
|
||||
struct wpa_dbus_argument arg = signal_dsc->args[i];
|
||||
arg_node = xmlNewChild(signal_node, NULL,
|
||||
BAD_CAST "arg", NULL);
|
||||
if (arg.name && strlen(arg.name)) {
|
||||
xmlNewProp(arg_node, BAD_CAST "name",
|
||||
BAD_CAST arg.name);
|
||||
}
|
||||
xmlNewProp(arg_node, BAD_CAST "type",
|
||||
BAD_CAST arg.type);
|
||||
}
|
||||
signal_dsc = signal_dsc->next;
|
||||
}
|
||||
|
||||
/* create properties' nodes */
|
||||
property_dsc = obj_dsc->properties;
|
||||
while (property_dsc) {
|
||||
|
||||
struct interfaces *iface = ifaces;
|
||||
while (iface) {
|
||||
if (!os_strcmp(iface->dbus_interface,
|
||||
property_dsc->dbus_interface))
|
||||
break;
|
||||
iface = iface->next;
|
||||
}
|
||||
if (!iface)
|
||||
continue;
|
||||
|
||||
iface_node = iface->interface_node;
|
||||
property_node = xmlNewChild(iface_node, NULL,
|
||||
BAD_CAST "property", NULL);
|
||||
xmlNewProp(property_node, BAD_CAST "name",
|
||||
BAD_CAST property_dsc->dbus_property);
|
||||
xmlNewProp(property_node, BAD_CAST "type",
|
||||
BAD_CAST property_dsc->type);
|
||||
xmlNewProp(property_node, BAD_CAST "access", BAD_CAST
|
||||
(property_dsc->access == R ? "read" :
|
||||
(property_dsc->access == W ?
|
||||
"write" : "readwrite")));
|
||||
|
||||
property_dsc = property_dsc->next;
|
||||
}
|
||||
|
||||
/* add child nodes to introspection tree; */
|
||||
dbus_connection_list_registered(obj_dsc->connection,
|
||||
dbus_message_get_path(message),
|
||||
&children);
|
||||
for (i = 0; children[i]; i++) {
|
||||
node = xmlNewChild(root_node, NULL, BAD_CAST "node", NULL);
|
||||
xmlNewProp(node, BAD_CAST "name", BAD_CAST children[i]);
|
||||
}
|
||||
dbus_free_string_array(children);
|
||||
|
||||
|
||||
xmlDocDumpFormatMemory(doc, &intro_str, &s, 1);
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
while (ifaces) {
|
||||
tmp = ifaces;
|
||||
ifaces = ifaces->next;
|
||||
os_free(tmp->dbus_interface);
|
||||
os_free(tmp);
|
||||
}
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (reply == NULL) {
|
||||
xmlFree(intro_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
xmlFree(intro_str);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
Loading…
Reference in a new issue