X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fsd-bus.c;h=870d617ac1e2b962f506f9c34ef9760333c5f641;hp=6eab4a5469cc44d4c71c401696594e5b643e3bd8;hb=3d339fec29178af415cb5367fdf3b53fab3093c2;hpb=a7e3212d89d5aefee67de79c1e7eaccf2f5645ac diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 6eab4a546..870d617ac 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" @@ -176,13 +177,13 @@ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) { return 0; } -int sd_bus_set_hello(sd_bus *bus, int b) { +int sd_bus_set_bus_client(sd_bus *bus, int b) { if (!bus) return -EINVAL; if (bus->state != BUS_UNSET) return -EPERM; - bus->send_hello = !!b; + bus->bus_client = !!b; return 0; } @@ -230,7 +231,7 @@ static int bus_send_hello(sd_bus *bus) { assert(bus); - if (!bus->send_hello) + if (!bus->bus_client) return 0; r = sd_bus_message_new_method_call( @@ -243,17 +244,13 @@ static int bus_send_hello(sd_bus *bus) { if (r < 0) return r; - r = sd_bus_send_with_reply(bus, m, hello_callback, NULL, 0, NULL); - if (r < 0) - return r; - - return r; + return sd_bus_send_with_reply(bus, m, hello_callback, NULL, 0, &bus->hello_serial); } int bus_start_running(sd_bus *bus) { assert(bus); - if (bus->send_hello) { + if (bus->bus_client) { bus->state = BUS_HELLO; return 1; } @@ -506,7 +503,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { errno = 0; ul = strtoul(*p + 4, (char**) p, 10); - if (errno != 0 || **p != '=' || ul > 256) { + if (errno > 0 || **p != '=' || ul > 256) { r = -EINVAL; goto fail; } @@ -538,8 +535,10 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { skip_address_key(p); } - if (!path) + if (!path) { + r = -EINVAL; goto fail; + } /* Make sure there are no holes in the array, with the * exception of argv[0] */ @@ -719,7 +718,7 @@ int sd_bus_start(sd_bus *bus) { if (bus->fd >= 0) r = bus_start_fd(bus); - else if (bus->address) + else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path) r = bus_start_address(bus); else return -EINVAL; @@ -753,7 +752,7 @@ int sd_bus_open_system(sd_bus **ret) { b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/dbus/system_bus_socket") - 1; } - b->send_hello = true; + b->bus_client = true; r = sd_bus_start(b); if (r < 0) @@ -803,7 +802,7 @@ int sd_bus_open_user(sd_bus **ret) { b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l + 4; } - b->send_hello = true; + b->bus_client = true; r = sd_bus_start(b); if (r < 0) @@ -1418,6 +1417,28 @@ static int process_timeout(sd_bus *bus) { return r < 0 ? r : 1; } +static int process_hello(sd_bus *bus, sd_bus_message *m) { + assert(bus); + assert(m); + + if (bus->state != BUS_HELLO) + return 0; + + /* Let's make sure the first message on the bus is the HELLO + * reply. But note that we don't actually parse the message + * here (we leave that to the usual reply handling), we just + * verify we don't let any earlier msg through. */ + + if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN && + m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR) + return -EIO; + + if (m->reply_serial != bus->hello_serial) + return -EIO; + + return 0; +} + static int process_reply(sd_bus *bus, sd_bus_message *m) { struct reply_callback *c; int r; @@ -1553,7 +1574,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,12 +1595,108 @@ 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("\n", f); + fputs(SD_BUS_INTROSPECT_INTERFACE_PEER, f); + fputs(SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE, f); + + while ((node = set_steal_first(s))) { + fprintf(f, " \n", node); + free(node); + } + + fputs("\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; assert(bus); assert(m); + r = process_hello(bus, m); + if (r != 0) + return r; + r = process_reply(bus, m); if (r != 0) return r; @@ -1589,7 +1709,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) { @@ -1842,7 +1966,7 @@ static int bus_add_object( return -ENOMEM; c->path = strdup(path); - if (!path) { + if (!c->path) { free(c); return -ENOMEM; }