summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-10-13 03:03:31 +0200
committerLennart Poettering <lennart@poettering.net>2010-10-13 03:03:31 +0200
commit2cccbca4fdf1cc6b46da105f6588a6bbdcbbb4df (patch)
treed958403ea30d5e1b24716d6e4edac2fa7cc7b27e
parent37072578da23266e72e3b7846059a11ff35f412e (diff)
dbus: add introspection to midlevel paths
-rw-r--r--TODO2
-rw-r--r--src/dbus-job.c67
-rw-r--r--src/dbus-unit.c81
3 files changed, 148 insertions, 2 deletions
diff --git a/TODO b/TODO
index c1008ab525..e09d4d3e5e 100644
--- a/TODO
+++ b/TODO
@@ -56,8 +56,6 @@
* passphrase agent https://bugs.freedesktop.org/show_bug.cgi?id=30038
-* support dbus introspection in mid-level object paths, i.e. in /org/freedesktop/systemd/units/.
-
* systemctl auto-pager a la git
* fsck setup
diff --git a/src/dbus-job.c b/src/dbus-job.c
index 0f76c7d843..667eb04a69 100644
--- a/src/dbus-job.c
+++ b/src/dbus-job.c
@@ -122,11 +122,72 @@ static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBu
Manager *m = data;
Job *j;
int r;
+ DBusMessage *reply;
assert(connection);
assert(message);
assert(m);
+ if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) {
+ /* Be nice to gdbus and return introspection data for our mid-level paths */
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ char *introspection = NULL;
+ FILE *f;
+ Iterator i;
+ size_t size;
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ /* We roll our own introspection code here, instead of
+ * relying on bus_default_message_handler() because we
+ * need to generate our introspection string
+ * dynamically. */
+
+ if (!(f = open_memstream(&introspection, &size)))
+ goto oom;
+
+ fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>\n", f);
+
+ fputs(BUS_INTROSPECTABLE_INTERFACE, f);
+ fputs(BUS_PEER_INTERFACE, f);
+
+ HASHMAP_FOREACH(j, m->jobs, i)
+ fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
+
+ fputs("</node>\n", f);
+
+ if (ferror(f)) {
+ fclose(f);
+ free(introspection);
+ goto oom;
+ }
+
+ fclose(f);
+
+ if (!introspection)
+ goto oom;
+
+ if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
+ free(introspection);
+ goto oom;
+ }
+
+ free(introspection);
+
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
if ((r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j)) < 0) {
if (r == -ENOMEM)
@@ -139,6 +200,12 @@ static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBu
}
return bus_job_message_dispatch(j, connection, message);
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
const DBusObjectPathVTable bus_job_vtable = {
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index b65481d193..45eba8ab55 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -454,11 +454,86 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB
Manager *m = data;
Unit *u;
int r;
+ DBusMessage *reply;
assert(connection);
assert(message);
assert(m);
+ if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) {
+ /* Be nice to gdbus and return introspection data for our mid-level paths */
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ char *introspection = NULL;
+ FILE *f;
+ Iterator i;
+ const char *k;
+ size_t size;
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ /* We roll our own introspection code here, instead of
+ * relying on bus_default_message_handler() because we
+ * need to generate our introspection string
+ * dynamically. */
+
+ if (!(f = open_memstream(&introspection, &size)))
+ goto oom;
+
+ fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>\n", f);
+
+ fputs(BUS_INTROSPECTABLE_INTERFACE, f);
+ fputs(BUS_PEER_INTERFACE, f);
+
+ HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+ char *p;
+
+ if (k != u->meta.id)
+ continue;
+
+ if (!(p = bus_path_escape(k))) {
+ fclose(f);
+ free(introspection);
+ goto oom;
+ }
+
+ fprintf(f, "<node name=\"%s\"/>", p);
+ free(p);
+ }
+
+ fputs("</node>\n", f);
+
+ if (ferror(f)) {
+ fclose(f);
+ free(introspection);
+ goto oom;
+ }
+
+ fclose(f);
+
+ if (!introspection)
+ goto oom;
+
+ if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
+ free(introspection);
+ goto oom;
+ }
+
+ free(introspection);
+
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) {
if (r == -ENOMEM)
@@ -471,6 +546,12 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB
}
return bus_unit_message_dispatch(u, connection, message);
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
const DBusObjectPathVTable bus_unit_vtable = {