diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-03-26 01:54:37 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-03-26 02:19:34 +0100 |
commit | 0a72c2bdef69bae5f4677ee563019e3ccbd3dfe2 (patch) | |
tree | 3c9d650c8b2b268c00033778184c13411d82eb79 /src | |
parent | 94bbf1ba6d2c8f3c64879c7f1af114ca25edeb8f (diff) |
bus: automatically generate minimal introspection data to find installed objects
Diffstat (limited to 'src')
-rw-r--r-- | src/libsystemd-bus/sd-bus-protocol.h | 42 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 104 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.h | 5 |
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 f9a5217dda..ac4d0b1dc5 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 6a76db960d..c82b738e02 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 d680270c64..08c5e54230 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 |