summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am47
-rwxr-xr-xsrc/sbus/sbus_codegen506
-rw-r--r--src/sbus/sssd_dbus_meta.c64
-rw-r--r--src/sbus/sssd_dbus_meta.h82
-rw-r--r--src/tests/sbus_codegen_tests.c166
-rwxr-xr-xsrc/tests/sbus_codegen_tests.xml45
-rw-r--r--src/tests/sbus_codegen_tests_generated.c79
-rw-r--r--src/tests/sbus_codegen_tests_generated.h24
8 files changed, 1012 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 8d92326de..de916d3ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -133,7 +133,8 @@ if HAVE_CHECK
debug-tests \
ipa_hbac-tests \
sss_idmap-tests \
- responder_socket_access-tests
+ responder_socket_access-tests \
+ sbus_codegen_tests
if BUILD_SSH
non_interactive_check_based_tests += sysdb_ssh-tests
@@ -437,6 +438,7 @@ dist_noinst_HEADERS = \
src/responder/ssh/sshsrv_private.h \
src/sbus/sbus_client.h \
src/sbus/sssd_dbus.h \
+ src/sbus/sssd_dbus_meta.h \
src/sbus/sssd_dbus_private.h \
src/db/sysdb.h \
src/db/sysdb_sudo.h \
@@ -561,6 +563,7 @@ libsss_util_la_SOURCES = \
src/sbus/sbus_client.c \
src/sbus/sssd_dbus_common.c \
src/sbus/sssd_dbus_connection.c \
+ src/sbus/sssd_dbus_meta.c \
src/sbus/sssd_dbus_server.c \
src/util/util.c \
src/util/memory.c \
@@ -637,6 +640,37 @@ include_HEADERS = \
src/sss_client/idmap/sss_nss_idmap.h
####################
+# Sbus Codegen #
+####################
+
+# Yes, the goal here is that the generated files end up in $(srcdir)
+# not $(builddir). Always use $(srcdir) here.
+CODEGEN_XML = \
+ $(srcdir)/src/tests/sbus_codegen_tests.xml
+
+SBUS_CODEGEN = src/sbus/sbus_codegen
+
+EXTRA_DIST += \
+ $(SBUS_CODEGEN) \
+ $(CODEGEN_XML)
+
+SUFFIXES = .xml _generated.h _generated.c
+
+.xml_generated.h:
+ $(srcdir)/$(SBUS_CODEGEN) --mode=header --output=$@ $<
+.xml_generated.c:
+ $(srcdir)/$(SBUS_CODEGEN) --mode=source --output=$@ $<
+
+# Regenerate when codegen changes
+CODEGEN_CODE = \
+ $(CODEGEN_XML:.xml=_generated.c) \
+ $(CODEGEN_XML:.xml=_generated.h)
+
+$(CODEGEN_CODE): $(SBUS_CODEGEN)
+
+BUILT_SOURCES = $(CODEGEN_CODE)
+
+####################
# Program Binaries #
####################
sssd_SOURCES = \
@@ -1257,6 +1291,17 @@ krb5_child_test_LDADD = \
$(SSSD_INTERNAL_LTLIBS) \
libsss_test_common.la
+sbus_codegen_tests_SOURCES = \
+ src/tests/sbus_codegen_tests.c \
+ src/tests/sbus_codegen_tests_generated.c \
+ src/tests/sbus_codegen_tests_generated.h
+sbus_codegen_tests_CFLAGS = \
+ $(CHECK_CFLAGS)
+sbus_codegen_tests_LDADD = \
+ $(SSSD_INTERNAL_LTLIBS) \
+ $(SSSD_LIBS) \
+ $(CHECK_LIBS)
+
if HAVE_CMOCKA
TEST_MOCK_RESP_OBJ = \
diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
new file mode 100755
index 000000000..a1e2d02a0
--- /dev/null
+++ b/src/sbus/sbus_codegen
@@ -0,0 +1,506 @@
+#!/usr/bin/python
+
+#
+# Authors:
+# Stef Walter <stefw@redhat.com>
+#
+# Copyright (C) 2014 Red Hat
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Some parser code from GLib
+#
+# Copyright (C) 2008-2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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 this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# Portions by: David Zeuthen <davidz@redhat.com>
+#
+
+#
+# DBus interfaces are defined here:
+#
+# http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
+#
+# The introspection data format has become the standard way to represent a
+# DBus interface. For many examples see /usr/share/dbus-1/interfaces/ on a
+# typical linux machine.
+#
+# A word about annotations. These are extra flags or values that can be
+# assigned to anything. So far, the codegen supports this annotation:
+#
+# org.freedesktop.DBus.GLib.CSymbol
+# - An annotation specified in the specification that tells us what C symbol
+# to generate for a given interface or method. By default the codegen will
+# build up a symbol name from the DBus name.
+#
+
+import optparse
+import os
+import re
+import StringIO
+import sys
+import xml.parsers.expat
+
+# -----------------------------------------------------------------------------
+# Objects
+
+class DBusXmlException(Exception):
+ line = 0
+ file = None
+
+ # Lets us print problems like a compiler would
+ def __str__(self):
+ message = Exception.__str__(self)
+ if self.file and self.line:
+ return "%s:%d: %s" % (self.file, self.line, message)
+ elif self.file:
+ return "%s: %s" % (self.file, message)
+ else:
+ return message
+
+class Base:
+ def __init__(self, name):
+ if not name:
+ raise DBusXmlException('No name on element')
+ self.name = name
+ self.annotations = { }
+ def c_name(self):
+ return self.annotations.get("org.freedesktop.DBus.GLib.CSymbol", self.name)
+
+class Arg(Base):
+ def __init__(self, method, name, signature):
+ Base.__init__(self, name)
+ self.method = method
+ self.signature = signature
+
+class Method(Base):
+ def __init__(self, iface, name):
+ Base.__init__(self, name)
+ self.iface = iface
+ self.in_args = []
+ self.out_args = []
+ def fq_c_name(self):
+ return "%s_%s" % (self.iface.c_name(), self.c_name())
+
+class Signal(Base):
+ def __init__(self, iface, name):
+ Base.__init__(self, name)
+ self.iface = iface
+ self.args = []
+ def fq_c_name(self):
+ return "%s_%s" % (self.iface.c_name(), self.c_name())
+
+class Property(Base):
+ def __init__(self, iface, name, signature, access):
+ Base.__init__(self, name)
+ self.iface = iface
+ self.signature = signature
+ self.readable = False
+ self.writable = False
+ if access == 'readwrite':
+ self.readable = True
+ self.writable = True
+ elif access == 'read':
+ self.readable = True
+ elif access == 'write':
+ self.writable = True
+ else:
+ raise DBusXmlException('Invalid access type %s'%self.access)
+ def fq_c_name(self):
+ return "%s_%s" % (self.iface.c_name(), self.c_name())
+
+class Interface(Base):
+ def __init__(self, name):
+ Base.__init__(self, name)
+ self.methods = []
+ self.signals = []
+ self.properties = []
+ def c_name(self):
+ return self.annotations.get("org.freedesktop.DBus.GLib.CSymbol",
+ self.name.replace(".", "_"))
+
+# -----------------------------------------------------------------------------
+# Code Generation
+
+def out(format, *args):
+ str = format % args
+ sys.stdout.write(str)
+ sys.stdout.write("\n")
+
+def source_args(parent, args, suffix):
+ out("")
+ out("/* arguments for %s.%s */", parent.iface.name, parent.name)
+ out("const struct sbus_arg_meta %s%s[] = {", parent.fq_c_name(), suffix)
+ for arg in args:
+ out(" { \"%s\", \"%s\" },", arg.name, arg.signature)
+ out(" { NULL, }")
+ out("};")
+
+def source_methods(iface, methods):
+ for meth in methods:
+ if meth.in_args:
+ source_args(meth, meth.in_args, "__in")
+ if meth.out_args:
+ source_args(meth, meth.out_args, "__out")
+
+ out("")
+ out("/* methods for %s */", iface.name)
+ out("const struct sbus_method_meta %s__methods[] = {", iface.c_name())
+ for meth in methods:
+ out(" {")
+ out(" \"%s\", /* name */", meth.name)
+ if meth.in_args:
+ out(" %s__in,", meth.fq_c_name())
+ else:
+ out(" NULL, /* no in_args */")
+ if meth.out_args:
+ out(" %s__out,", meth.fq_c_name())
+ else:
+ out(" NULL, /* no out_args */")
+ out(" },")
+ out(" { NULL, }")
+ out("};")
+
+def source_signals(iface, signals):
+ for sig in iface.signals:
+ if sig.args:
+ source_args(sig, sig.args, "__args")
+
+ out("")
+ out("/* signals for %s */", iface.name)
+ out("const struct sbus_signal_meta %s__signals[] = {", iface.c_name())
+ for sig in signals:
+ out(" {")
+ out(" \"%s\", /* name */", sig.name)
+ if sig.args:
+ out(" %s__args", sig.fq_c_name())
+ else:
+ out(" NULL, /* no args */")
+ out(" },")
+ out(" { NULL, }")
+ out("};")
+
+def source_properties(iface, properties):
+ out("")
+ out("/* property info for %s */", iface.name)
+ out("const struct sbus_property_meta %s__properties[] = {", iface.c_name())
+ for prop in properties:
+ out(" {")
+ out(" \"%s\", /* name */", prop.name)
+ out(" \"%s\", /* signature */", prop.signature)
+ if prop.readable and prop.writable:
+ out(" SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,")
+ elif prop.readable:
+ out(" SBUS_PROPERTY_READABLE,")
+ elif prop.writable:
+ out(" SBUS_PROPERTY_WRITABLE,")
+ else:
+ assert False, "should not be reached"
+ out(" },")
+ out(" { NULL, }")
+ out("};")
+
+def header_interface(iface):
+ out("")
+ out("/* interface info for %s */", iface.name)
+ out("extern const struct sbus_interface_meta %s_meta;", iface.c_name())
+
+def source_interface(iface):
+ out("")
+ out("/* interface info for %s */", iface.name)
+ out("const struct sbus_interface_meta %s_meta = {", iface.c_name())
+ out(" \"%s\", /* name */", iface.name)
+ if iface.methods:
+ out(" %s__methods,", iface.c_name())
+ else:
+ out(" NULL, /* no methods */")
+ if iface.signals:
+ out(" %s__signals,", iface.c_name())
+ else:
+ out(" NULL, /* no signals */")
+ if iface.properties:
+ out(" %s__properties", iface.c_name())
+ else:
+ out(" NULL, /* no propetries */")
+ out("};")
+
+def generate_source(ifaces, filename):
+ basename = os.path.basename(filename)
+
+ out("/* The following definitions are auto-generated from %s */", basename)
+ out("")
+
+ out("#include \"util/util.h\"")
+ out("#include \"sbus/sssd_dbus.h\"")
+ out("#include \"sbus/sssd_dbus_meta.h\"")
+
+ for iface in ifaces:
+
+ # The methods
+ if iface.methods:
+ source_methods(iface, iface.methods)
+
+ # The signals array
+ if iface.signals:
+ source_signals(iface, iface.signals)
+
+ # The properties array
+ if iface.properties:
+ source_properties(iface, iface.properties)
+
+ # The sbus_interface structure
+ source_interface(iface)
+
+def generate_header(ifaces, filename):
+ basename = os.path.basename(filename)
+ guard = "__%s__" % re.sub(r'([^_A-Z0-9])', "_", basename.upper())
+
+ out("/* The following declarations are auto-generated from %s */", basename)
+ out("")
+ out("#ifndef %s", guard)
+ out("#define %s", guard)
+ out("")
+ out("#include \"sbus/sssd_dbus.h\"")
+
+ out("")
+ out("/* ------------------------------------------------------------------------")
+ out(" * DBus Interface Metadata")
+ out(" *")
+ out(" * These structure definitions are filled in with the information about")
+ out(" * the interfaces, methods, properties and so on.")
+ out(" *")
+ out(" * The actual definitions are found in the accompanying C file next")
+ out(" * to this header.")
+ out(" */")
+
+ for iface in ifaces:
+ header_interface(iface)
+
+ out("")
+ out("#endif /* %s */", guard)
+
+# -----------------------------------------------------------------------------
+# XML Interface Parsing
+
+STATE_TOP = 'top'
+STATE_NODE = 'node'
+STATE_INTERFACE = 'interface'
+STATE_METHOD = 'method'
+STATE_SIGNAL = 'signal'
+STATE_PROPERTY = 'property'
+STATE_ARG = 'arg'
+STATE_ANNOTATION = 'annotation'
+STATE_IGNORED = 'ignored'
+
+def expect_attr(attrs, name):
+ if name not in attrs:
+ raise DBusXmlException("Missing attribute '%s'" % name)
+ if attrs[name] == "":
+ raise DBusXmlException("Empty attribute '%s'" % name)
+ return attrs[name]
+
+class DBusXMLParser:
+ def __init__(self, filename):
+ parser = xml.parsers.expat.ParserCreate()
+ parser.CommentHandler = self.handle_comment
+ parser.CharacterDataHandler = self.handle_char_data
+ parser.StartElementHandler = self.handle_start_element
+ parser.EndElementHandler = self.handle_end_element
+
+ self.parsed_interfaces = []
+ self.cur_object = None
+
+ self.state = STATE_TOP
+ self.state_stack = []
+ self.cur_object = None
+ self.cur_object_stack = []
+ self.arg_count = 0
+
+ try:
+ with open(filename, "r") as f:
+ parser.ParseFile(f)
+ except DBusXmlException, ex:
+ ex.line = parser.CurrentLineNumber
+ ex.file = filename
+ raise
+ except xml.parsers.expat.ExpatError, ex:
+ exc = DBusXmlException(str(ex))
+ exc.line = ex.lineno
+ exc.file = filename
+ raise exc
+
+ def handle_comment(self, data):
+ pass
+
+ def handle_char_data(self, data):
+ pass
+
+ def handle_start_element(self, name, attrs):
+ old_state = self.state
+ old_cur_object = self.cur_object
+ if self.state == STATE_IGNORED:
+ self.state = STATE_IGNORED
+ elif self.cur_object and name == STATE_ANNOTATION:
+ val = attrs.get('value', '')
+ self.cur_object.annotations[expect_attr(attrs, 'name')] = val
+ self.state = STATE_IGNORED
+ elif self.state == STATE_TOP:
+ if name == STATE_NODE:
+ self.state = STATE_NODE
+ else:
+ self.state = STATE_IGNORED
+ elif self.state == STATE_NODE:
+ if name == STATE_INTERFACE:
+ self.state = STATE_INTERFACE
+ iface = Interface(expect_attr(attrs, 'name'))
+ self.cur_object = iface
+ self.parsed_interfaces.append(iface)
+ else:
+ self.state = STATE_IGNORED
+
+ elif self.state == STATE_INTERFACE:
+ if name == STATE_METHOD:
+ self.state = STATE_METHOD
+ method = Method(self.cur_object, expect_attr(attrs, 'name'))
+ self.cur_object.methods.append(method)
+ self.cur_object = method
+ self.arg_count = 0
+ elif name == STATE_SIGNAL:
+ self.state = STATE_SIGNAL
+ signal = Signal(self.cur_object, expect_attr(attrs, 'name'))
+ self.cur_object.signals.append(signal)
+ self.cur_object = signal
+ self.arg_count = 0
+ elif name == STATE_PROPERTY:
+ self.state = STATE_PROPERTY
+ prop = Property(self.cur_object,
+ expect_attr(attrs, 'name'),
+ expect_attr(attrs, 'type'),
+ expect_attr(attrs, 'access'))
+ self.cur_object.properties.append(prop)
+ self.cur_object = prop
+ else:
+ self.state = STATE_IGNORED
+
+ elif self.state == STATE_METHOD:
+ if name == STATE_ARG:
+ self.state = STATE_ARG
+ arg = Arg(self.cur_object,
+ expect_attr(attrs, 'name'),
+ expect_attr(attrs, 'type'))
+ direction = attrs.get('direction', 'in')
+ if direction == 'in':
+ self.cur_object.in_args.append(arg)
+ elif direction == 'out':
+ self.cur_object.out_args.append(arg)
+ else:
+ raise DBusXmlException('Invalid direction "%s"' % direction)
+ self.cur_object = arg
+ else:
+ self.state = STATE_IGNORED
+
+ elif self.state == STATE_SIGNAL:
+ if name == STATE_ARG:
+ self.state = STATE_ARG
+ arg = Arg(self.cur_object,
+ expect_attr(attrs, 'name'),
+ expect_attr(attrs, 'type'))
+ self.cur_object.args.append(arg)
+ self.cur_object = arg
+ else:
+ self.state = STATE_IGNORED
+
+ elif self.state == STATE_PROPERTY:
+ self.state = STATE_IGNORED
+
+ elif self.state == STATE_ARG:
+ self.state = STATE_IGNORED
+
+ else:
+ assert False, 'Unhandled state "%s" while entering element with name "%s"' % (self.state, name)
+
+ self.state_stack.append(old_state)
+ self.cur_object_stack.append(old_cur_object)
+
+ def handle_end_element(self, name):
+ self.state = self.state_stack.pop()
+ self.cur_object = self.cur_object_stack.pop()
+
+def parse_options():
+ parser = optparse.OptionParser("usage: %prog [options] introspect.xml ...")
+ parser.set_description("sbus_codegen generates sbus interface structures \
+ from standard XML Introspect data.")
+ parser.add_option("--mode",
+ dest="mode", default="header",
+ help="'header' or 'source' (default: header)",
+ metavar="MODE")
+ parser.add_option("--output",
+ dest="output", default=None,
+ help="Set output file name (default: stdout)",
+ metavar="FILE")
+ (options, args) = parser.parse_args()
+
+ if not args:
+ print >> sys.stderr, "sbus_codegen: no input file specified"
+ sys.exit(2)
+
+ if options.mode not in ["header", "source"]:
+ print >> sys.stderr, "sbus_codegen: specify --mode=header or --mode=source"
+
+ return options, args
+
+def main():
+ options, args = parse_options()
+
+ if options.output:
+ sys.stdout = buf = StringIO.StringIO()
+
+ for filename in args:
+ parser = DBusXMLParser(filename)
+
+ if options.mode == "header":
+ generate_header(parser.parsed_interfaces, filename)
+ elif options.mode == "source":
+ generate_source(parser.parsed_interfaces, filename)
+ else:
+ assert False, "should not be reached"
+
+ # Write output at end to be nice to 'make'
+ if options.output:
+ output = open(options.output, "w")
+ output.write(buf.getvalue())
+ output.close()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except DBusXmlException, ex:
+ print >> sys.stderr, str(ex)
+ sys.exit(1)
diff --git a/src/sbus/sssd_dbus_meta.c b/src/sbus/sssd_dbus_meta.c
new file mode 100644
index 000000000..57123b743
--- /dev/null
+++ b/src/sbus/sssd_dbus_meta.c
@@ -0,0 +1,64 @@
+/*
+ Authors:
+ Stef Walter <stefw@redhat.com>
+
+ Copyright (C) 2014 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "sbus/sssd_dbus_meta.h"
+
+const struct sbus_method_meta *
+sbus_meta_find_method(const struct sbus_interface_meta *interface,
+ const char *method_name)
+{
+ const struct sbus_method_meta *method;
+
+ for (method = interface->methods; method && method->name; method++) {
+ if (strcmp(method_name, method->name) == 0)
+ return method;
+ }
+
+ return NULL;
+}
+
+const struct sbus_signal_meta *
+sbus_meta_find_signal(const struct sbus_interface_meta *interface,
+ const char *signal_name)
+{
+ const struct sbus_signal_meta *signal;
+
+ for (signal = interface->signals; signal && signal->name; signal++) {
+ if (strcmp(signal_name, signal->name) == 0)
+ return signal;
+ }
+
+ return NULL;
+}
+
+const struct sbus_property_meta *
+sbus_meta_find_property(const struct sbus_interface_meta *interface,
+ const char *property_name)
+{
+ const struct sbus_property_meta *property;
+
+ for (property = interface->properties; property && property->name; property++) {
+ if (strcmp(property_name, property->name) == 0)
+ return property;
+ }
+
+ return NULL;
+}
diff --git a/src/sbus/sssd_dbus_meta.h b/src/sbus/sssd_dbus_meta.h
new file mode 100644
index 000000000..17ea7a507
--- /dev/null
+++ b/src/sbus/sssd_dbus_meta.h
@@ -0,0 +1,82 @@
+/*
+ Authors:
+ Stef Walter <stefw@redhat.com>
+
+ Copyright (C) 2014 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SSSD_DBUS_META_H_
+#define _SSSD_DBUS_META_H_
+
+/*
+ * Interface metadata
+ *
+ * For arrays, the last item in each array will have a
+ * NULL .name field
+ *
+ * Typically these structs will be generated by sbus_codegen
+ * from canonical XML interface data:
+ *
+ * http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
+ */
+
+struct sbus_arg_meta {
+ const char *name;
+ const char *type;
+};
+
+struct sbus_method_meta {
+ const char *name;
+ const struct sbus_arg_meta *in_args;
+ const struct sbus_arg_meta *out_args;
+};
+
+enum {
+ SBUS_PROPERTY_READABLE = 1 << 0,
+ SBUS_PROPERTY_WRITABLE = 1 << 1
+};
+
+struct sbus_property_meta {
+ const char *name;
+ const char *type;
+ int flags;
+};
+
+struct sbus_signal_meta {
+ const char *name;
+ const struct sbus_arg_meta *args;
+};
+
+struct sbus_interface_meta {
+ const char *name;
+ const struct sbus_method_meta *methods;
+ const struct sbus_signal_meta *signals;
+ const struct sbus_property_meta *properties;
+};
+
+const struct sbus_method_meta *
+sbus_meta_find_method (const struct sbus_interface_meta *interface,
+ const char *method_name);
+
+const struct sbus_signal_meta *
+sbus_meta_find_signal (const struct sbus_interface_meta *interface,
+ const char *signal_name);
+
+const struct sbus_property_meta *
+sbus_meta_find_property (const struct sbus_interface_meta *interface,
+ const char *property_name);
+
+#endif /* _SSSD_DBUS_META_H_ */
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
new file mode 100644
index 000000000..6b2abf8bc
--- /dev/null
+++ b/src/tests/sbus_codegen_tests.c
@@ -0,0 +1,166 @@
+/*
+ SSSD
+
+ sbus_codegen tests.
+
+ Authors:
+ Stef Walter <stefw@redhat.com>
+
+ Copyright (C) Red Hat, Inc 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <check.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <popt.h>
+
+#include "sbus/sssd_dbus_meta.h"
+#include "tests/sbus_codegen_tests_generated.h"
+
+static const struct sbus_arg_meta *
+find_arg(const struct sbus_arg_meta *args,
+ const char *name)
+{
+ const struct sbus_arg_meta *arg;
+ for (arg = args; arg->name != NULL; arg++) {
+ if (strcmp (arg->name, name) == 0)
+ return arg;
+ }
+
+ return NULL;
+}
+
+START_TEST(test_interfaces)
+{
+ ck_assert_str_eq(com_planetexpress_Ship_meta.name, "com.planetexpress.Ship");
+ ck_assert(com_planetexpress_Ship_meta.methods != NULL);
+ ck_assert(com_planetexpress_Ship_meta.signals != NULL);
+ ck_assert(com_planetexpress_Ship_meta.properties != NULL);
+
+ /* Explicit C Symbol */
+ ck_assert_str_eq(test_pilot_meta.name, "com.planetexpress.Pilot");
+ ck_assert(test_pilot_meta.methods == NULL); /* no methods */
+ ck_assert(test_pilot_meta.signals == NULL); /* no signals */
+ ck_assert(test_pilot_meta.properties != NULL);
+
+}
+END_TEST
+
+START_TEST(test_methods)
+{
+ const struct sbus_method_meta *method;
+ const struct sbus_arg_meta *arg;
+
+ method = sbus_meta_find_method(&com_planetexpress_Ship_meta, "MoveUniverse");
+ ck_assert(method != NULL);
+ ck_assert_str_eq(method->name, "MoveUniverse");
+ ck_assert(method->in_args != NULL);
+ ck_assert(method->out_args != NULL);
+
+ arg = find_arg(method->in_args, "smoothly");
+ ck_assert(arg != NULL);
+ ck_assert_str_eq(arg->name, "smoothly");
+ ck_assert_str_eq(arg->type, "b");
+
+ arg = find_arg(method->out_args, "where_we_crashed");
+ ck_assert(arg != NULL);
+ ck_assert_str_eq(arg->name, "where_we_crashed");
+ ck_assert_str_eq(arg->type, "s");
+}
+END_TEST
+
+START_TEST(test_properties)
+{
+ const struct sbus_property_meta *prop;
+
+ prop = sbus_meta_find_property(&com_planetexpress_Ship_meta, "Color");
+ ck_assert(prop != NULL);
+ ck_assert_str_eq(prop->name, "Color");
+ ck_assert_str_eq(prop->type, "s");
+ ck_assert_int_eq(prop->flags, SBUS_PROPERTY_READABLE);
+}
+END_TEST
+
+START_TEST(test_signals)
+{
+ const struct sbus_signal_meta *signal;
+ const struct sbus_arg_meta *arg;
+
+ signal = sbus_meta_find_signal(&com_planetexpress_Ship_meta, "BecameSentient");
+ ck_assert(signal != NULL);
+ ck_assert_str_eq(signal->name, "BecameSentient");
+ ck_assert(signal->args != NULL);
+
+ arg = find_arg(signal->args, "gender");
+ ck_assert(arg != NULL);
+ ck_assert_str_eq(arg->name, "gender");
+ ck_assert_str_eq(arg->type, "s");
+}
+END_TEST
+
+Suite *create_suite(void)
+{
+ Suite *s = suite_create("sbus_codegen");
+
+ TCase *tc = tcase_create("defs");
+
+ /* Do some testing */
+ tcase_add_test(tc, test_interfaces);
+ tcase_add_test(tc, test_methods);
+ tcase_add_test(tc, test_properties);
+ tcase_add_test(tc, test_signals);
+
+ /* Add all test cases to the test suite */
+ suite_add_tcase(s, tc);
+
+ return s;
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ int failure_count;
+ Suite *suite;
+ SRunner *sr;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+
+ suite = create_suite();
+ sr = srunner_create(suite);
+ srunner_set_fork_status(sr, CK_FORK);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml
new file mode 100755
index 000000000..0def3585a
--- /dev/null
+++ b/src/tests/sbus_codegen_tests.xml
@@ -0,0 +1,45 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <!--
+ This file should exercise as many aspects of the sbus_codegen as
+ possible. See sbus_codegen_test.c for verification.
+ -->
+
+ <!--
+ This is an interface, it will get a sbus_interface_meta struct.
+ Its name will be com_planetexpress_Ship__meta, since no c symbol
+ is specified.
+ -->
+ <interface name="com.planetexpress.Ship">
+ <!-- A property -->
+ <property name="Color" type="s" access="read"/>
+
+ <!-- A method with two in and one out argument -->
+ <method name="MoveUniverse">
+ <!-- This is a boolean arg -->
+ <arg name="smoothly" type="b" direction="in"/>
+ <!-- This is an uint32 arg -->
+ <arg name="speed_factor" type="u" direction="in"/>
+ <!-- This is a string arg -->
+ <arg name="where_we_crashed" type="s" direction="out"/>
+ </method>
+
+ <!-- A signal with one argument -->
+ <signal name="BecameSentient">
+ <arg name="gender" type="s"/>
+ </signal>
+ </interface>
+
+ <!--
+ Another interface. It's C name will be test_pilot, since we've overridden
+ the c symbol name.
+ -->
+ <interface name="com.planetexpress.Pilot">
+ <annotation value="test_pilot" name="org.freedesktop.DBus.GLib.CSymbol"/>
+
+ <!-- A property -->
+ <property name="FullName" type="s" access="readwrite"/>
+ </interface>
+
+</node>
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
new file mode 100644
index 000000000..556eea12c
--- /dev/null
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -0,0 +1,79 @@
+/* The following definitions are auto-generated from sbus_codegen_tests.xml */
+
+#include "util/util.h"
+#include "sbus/sssd_dbus.h"
+#include "sbus/sssd_dbus_meta.h"
+
+/* arguments for com.planetexpress.Ship.MoveUniverse */
+const struct sbus_arg_meta com_planetexpress_Ship_MoveUniverse__in[] = {
+ { "smoothly", "b" },
+ { "speed_factor", "u" },
+ { NULL, }
+};
+
+/* arguments for com.planetexpress.Ship.MoveUniverse */
+const struct sbus_arg_meta com_planetexpress_Ship_MoveUniverse__out[] = {
+ { "where_we_crashed", "s" },
+ { NULL, }
+};
+
+/* methods for com.planetexpress.Ship */
+const struct sbus_method_meta com_planetexpress_Ship__methods[] = {
+ {
+ "MoveUniverse", /* name */
+ com_planetexpress_Ship_MoveUniverse__in,
+ com_planetexpress_Ship_MoveUniverse__out,
+ },
+ { NULL, }
+};
+
+/* arguments for com.planetexpress.Ship.BecameSentient */
+const struct sbus_arg_meta com_planetexpress_Ship_BecameSentient__args[] = {
+ { "gender", "s" },
+ { NULL, }
+};
+
+/* signals for com.planetexpress.Ship */
+const struct sbus_signal_meta com_planetexpress_Ship__signals[] = {
+ {
+ "BecameSentient", /* name */
+ com_planetexpress_Ship_BecameSentient__args
+ },
+ { NULL, }
+};
+
+/* property info for com.planetexpress.Ship */
+const struct sbus_property_meta com_planetexpress_Ship__properties[] = {
+ {
+ "Color", /* name */
+ "s", /* signature */
+ SBUS_PROPERTY_READABLE,
+ },
+ { NULL, }
+};
+
+/* interface info for com.planetexpress.Ship */
+const struct sbus_interface_meta com_planetexpress_Ship_meta = {
+ "com.planetexpress.Ship", /* name */
+ com_planetexpress_Ship__methods,
+ com_planetexpress_Ship__signals,
+ com_planetexpress_Ship__properties
+};
+
+/* property info for com.planetexpress.Pilot */
+const struct sbus_property_meta test_pilot__properties[] = {
+ {
+ "FullName", /* name */
+ "s", /* signature */
+ SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,
+ },
+ { NULL, }
+};
+
+/* interface info for com.planetexpress.Pilot */
+const struct sbus_interface_meta test_pilot_meta = {
+ "com.planetexpress.Pilot", /* name */
+ NULL, /* no methods */
+ NULL, /* no signals */
+ test_pilot__properties
+};
diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h
new file mode 100644
index 000000000..c3a23c870
--- /dev/null
+++ b/src/tests/sbus_codegen_tests_generated.h
@@ -0,0 +1,24 @@
+/* The following declarations are auto-generated from sbus_codegen_tests.xml */
+
+#ifndef __SBUS_CODEGEN_TESTS_XML__
+#define __SBUS_CODEGEN_TESTS_XML__
+
+#include "sbus/sssd_dbus.h"
+
+/* ------------------------------------------------------------------------
+ * DBus Interface Metadata
+ *
+ * These structure definitions are filled in with the information about
+ * the interfaces, methods, properties and so on.
+ *
+ * The actual definitions are found in the accompanying C file next
+ * to this header.
+ */
+
+/* interface info for com.planetexpress.Ship */
+extern const struct sbus_interface_meta com_planetexpress_Ship_meta;
+
+/* interface info for com.planetexpress.Pilot */
+extern const struct sbus_interface_meta test_pilot_meta;
+
+#endif /* __SBUS_CODEGEN_TESTS_XML__ */