summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-03-26 01:54:37 +0100
committerLennart Poettering <lennart@poettering.net>2013-03-26 02:19:34 +0100
commit0a72c2bdef69bae5f4677ee563019e3ccbd3dfe2 (patch)
tree3c9d650c8b2b268c00033778184c13411d82eb79 /src
parent94bbf1ba6d2c8f3c64879c7f1af114ca25edeb8f (diff)
bus: automatically generate minimal introspection data to find installed objects
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd-bus/sd-bus-protocol.h42
-rw-r--r--src/libsystemd-bus/sd-bus.c104
-rw-r--r--src/libsystemd-bus/sd-bus.h5
3 files changed, 147 insertions, 4 deletions
diff --git a/src/libsystemd-bus/sd-bus-protocol.h b/src/libsystemd-bus/sd-bus-protocol.h
index f9a5217dd..ac4d0b1dc 100644
--- a/src/libsystemd-bus/sd-bus-protocol.h
+++ b/src/libsystemd-bus/sd-bus-protocol.h
@@ -100,4 +100,46 @@ enum {
_SD_BUS_MESSAGE_HEADER_MAX
};
+#define SD_BUS_INTROSPECT_DOCTYPE \
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+
+#define SD_BUS_INTROSPECT_INTERFACE_PROPERTIES \
+ " <interface name=\"org.freedesktop.DBus.Properties\">\n" \
+ " <method name=\"Get\">\n" \
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetAll\">\n" \
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
+ " </method>\n" \
+ " <method name=\"Set\">\n" \
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \
+ " </method>\n" \
+ " <signal name=\"PropertiesChanged\">\n" \
+ " <arg type=\"s\" name=\"interface\"/>\n" \
+ " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \
+ " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \
+ " </signal>\n" \
+ " </interface>\n"
+
+#define SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE \
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
+ " <method name=\"Introspect\">\n" \
+ " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " </interface>\n"
+
+#define SD_BUS_INTROSPECT_INTERFACE_PEER \
+ "<interface name=\"org.freedesktop.DBus.Peer\">\n" \
+ " <method name=\"Ping\"/>\n" \
+ " <method name=\"GetMachineId\">\n" \
+ " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ "</interface>\n"
+
#endif
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 6a76db960..c82b738e0 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -30,6 +30,7 @@
#include "util.h"
#include "macro.h"
#include "strv.h"
+#include "set.h"
#include "sd-bus.h"
#include "bus-internal.h"
@@ -1553,7 +1554,10 @@ static int process_object(sd_bus *bus, sd_bus_message *m) {
}
}
- if (!found)
+ /* We found some handlers but none wanted to take this, then
+ * return this -- with one exception, we can handle
+ * introspection minimally ourselves */
+ if (!found || sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect"))
return 0;
sd_bus_error_set(&error,
@@ -1571,6 +1575,98 @@ static int process_object(sd_bus *bus, sd_bus_message *m) {
return 1;
}
+static int process_introspect(sd_bus *bus, sd_bus_message *m) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_free_ char *introspection = NULL;
+ _cleanup_set_free_free_ Set *s = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ struct object_callback *c;
+ Iterator i;
+ size_t size = 0;
+ char *node;
+ int r;
+
+ assert(bus);
+ assert(m);
+
+ if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect"))
+ return 0;
+
+ if (!m->path)
+ return 0;
+
+ s = set_new(string_hash_func, string_compare_func);
+ if (!s)
+ return -ENOMEM;
+
+ HASHMAP_FOREACH(c, bus->object_callbacks, i) {
+ const char *e;
+ char *a, *p;
+
+ if (streq(c->path, "/"))
+ continue;
+
+ if (streq(m->path, "/"))
+ e = c->path;
+ else {
+ e = startswith(c->path, m->path);
+ if (!e || *e != '/')
+ continue;
+ }
+
+ a = strdup(e+1);
+ if (!a)
+ return -ENOMEM;
+
+ p = strchr(a, '/');
+ if (p)
+ *p = 0;
+
+ r = set_put(s, a);
+ if (r < 0) {
+ free(a);
+
+ if (r != -EEXIST)
+ return r;
+ }
+ }
+
+ f = open_memstream(&introspection, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fputs(SD_BUS_INTROSPECT_DOCTYPE, f);
+ fputs("<node>\n", f);
+ fputs(SD_BUS_INTROSPECT_INTERFACE_PEER, f);
+ fputs(SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE, f);
+
+ while ((node = set_steal_first(s))) {
+ fprintf(f, " <node name=\"%s\"/>\n", node);
+ free(node);
+ }
+
+ fputs("</node>\n", f);
+
+ fflush(f);
+
+ if (ferror(f))
+ return -ENOMEM;
+
+ r = sd_bus_message_new_method_return(bus, m, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "s", introspection);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_send(bus, reply, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
static int process_message(sd_bus *bus, sd_bus_message *m) {
int r;
@@ -1589,7 +1685,11 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
if (r != 0)
return r;
- return process_object(bus, m);
+ r = process_object(bus, m);
+ if (r != 0)
+ return r;
+
+ return process_introspect(bus, m);
}
static int process_running(sd_bus *bus, sd_bus_message **ret) {
diff --git a/src/libsystemd-bus/sd-bus.h b/src/libsystemd-bus/sd-bus.h
index d680270c6..08c5e5423 100644
--- a/src/libsystemd-bus/sd-bus.h
+++ b/src/libsystemd-bus/sd-bus.h
@@ -29,9 +29,10 @@
#include "sd-bus-protocol.h"
/* TODO:
- * - implicitly add stub introspection calls
* - server side
- * - allow installing match callbacks,
+ * - allow installing match callbacks
+ * - anonymous auth
+ * - default policy
*
* Later:
* - add page donation logic