chiark / gitweb /
bus: add sd_bus_message_skip() to skip over multiple fields
[elogind.git] / src / libsystemd-bus / sd-bus.c
index 665f1e6c8bae11c7035eed493f168389ac0bb0a9..f42d5d0ee133fde80b7a6ba27f78795198c21e1f 100644 (file)
@@ -46,6 +46,7 @@
 #include "bus-signature.h"
 #include "bus-objects.h"
 #include "bus-util.h"
+#include "bus-container.h"
 
 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
 
@@ -117,6 +118,7 @@ static void bus_free(sd_bus *b) {
         free(b->auth_buffer);
         free(b->address);
         free(b->kernel);
+        free(b->machine);
 
         free(b->exec_path);
         strv_free(b->exec_argv);
@@ -753,6 +755,45 @@ static int parse_kernel_address(sd_bus *b, const char **p, char **guid) {
         return 0;
 }
 
+static int parse_container_address(sd_bus *b, const char **p, char **guid) {
+        _cleanup_free_ char *machine = NULL;
+        int r;
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "machine", &machine);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                skip_address_key(p);
+        }
+
+        if (!machine)
+                return -EINVAL;
+
+        free(b->machine);
+        b->machine = machine;
+        machine = NULL;
+
+        b->sockaddr.un.sun_family = AF_UNIX;
+        strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
+        b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/var/run/dbus/system_bus_socket") - 1;
+
+        return 0;
+}
+
 static void bus_reset_parsed_address(sd_bus *b) {
         assert(b);
 
@@ -765,6 +806,8 @@ static void bus_reset_parsed_address(sd_bus *b) {
         b->server_id = SD_ID128_NULL;
         free(b->kernel);
         b->kernel = NULL;
+        free(b->machine);
+        b->machine = NULL;
 }
 
 static int bus_parse_next_address(sd_bus *b) {
@@ -823,6 +866,14 @@ static int bus_parse_next_address(sd_bus *b) {
                         if (r < 0)
                                 return r;
 
+                        break;
+                } else if (startswith(a, "x-container:")) {
+
+                        a += 12;
+                        r = parse_container_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+
                         break;
                 }
 
@@ -849,24 +900,32 @@ static int bus_start_address(sd_bus *b) {
         for (;;) {
                 sd_bus_close(b);
 
-                if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
+                if (b->exec_path) {
 
-                        r = bus_socket_connect(b);
+                        r = bus_socket_exec(b);
+                        if (r >= 0)
+                                return r;
+
+                        b->last_connect_error = -r;
+                } else if (b->kernel) {
+
+                        r = bus_kernel_connect(b);
                         if (r >= 0)
                                 return r;
 
                         b->last_connect_error = -r;
 
-                } else if (b->exec_path) {
+                } else if (b->machine) {
 
-                        r = bus_socket_exec(b);
+                        r = bus_container_connect(b);
                         if (r >= 0)
                                 return r;
 
                         b->last_connect_error = -r;
-                } else if (b->kernel) {
 
-                        r = bus_kernel_connect(b);
+                } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
+
+                        r = bus_socket_connect(b);
                         if (r >= 0)
                                 return r;
 
@@ -937,7 +996,7 @@ int sd_bus_start(sd_bus *bus) {
 
         if (bus->input_fd >= 0)
                 r = bus_start_fd(bus);
-        else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel)
+        else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel || bus->machine)
                 r = bus_start_address(bus);
         else
                 return -EINVAL;
@@ -1033,6 +1092,78 @@ fail:
         return r;
 }
 
+int sd_bus_open_system_remote(const char *host, sd_bus **ret) {
+        _cleanup_free_ char *e = NULL;
+        char *p = NULL;
+        sd_bus *bus;
+        int r;
+
+        assert_return(host, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        e = bus_address_escape(host);
+        if (!e)
+                return -ENOMEM;
+
+        p = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL);
+        if (!p)
+                return -ENOMEM;
+
+        r = sd_bus_new(&bus);
+        if (r < 0) {
+                free(p);
+                return r;
+        }
+
+        bus->address = p;
+        bus->bus_client = true;
+
+        r = sd_bus_start(bus);
+        if (r < 0) {
+                bus_free(bus);
+                return r;
+        }
+
+        *ret = bus;
+        return 0;
+}
+
+int sd_bus_open_system_container(const char *machine, sd_bus **ret) {
+        _cleanup_free_ char *e = NULL;
+        sd_bus *bus;
+        char *p;
+        int r;
+
+        assert_return(machine, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        e = bus_address_escape(machine);
+        if (!e)
+                return -ENOMEM;
+
+        p = strjoin("x-container:machine=", e, NULL);
+        if (!p)
+                return -ENOMEM;
+
+        r = sd_bus_new(&bus);
+        if (r < 0) {
+                free(p);
+                return r;
+        }
+
+        bus->address = p;
+        bus->bus_client = true;
+
+        r = sd_bus_start(bus);
+        if (r < 0) {
+                bus_free(bus);
+                return r;
+        }
+
+        *ret = bus;
+        return 0;
+}
+
 void sd_bus_close(sd_bus *bus) {
         if (!bus)
                 return;
@@ -2208,6 +2339,16 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
         return 1;
 }
 
+static int quit_callback(sd_event_source *event, void *userdata) {
+        sd_bus *bus = userdata;
+
+        assert(event);
+
+        sd_bus_flush(bus);
+
+        return 1;
+}
+
 int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
         int r;
 
@@ -2251,6 +2392,10 @@ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
         if (r < 0)
                 goto fail;
 
+        r = sd_event_add_quit(event, quit_callback, bus, &bus->quit_event_source);
+        if (r < 0)
+                goto fail;
+
         return 0;
 
 fail:
@@ -2271,6 +2416,9 @@ int sd_bus_detach_event(sd_bus *bus) {
         if (bus->time_event_source)
                 bus->time_event_source = sd_event_source_unref(bus->time_event_source);
 
+        if (bus->quit_event_source)
+                bus->quit_event_source = sd_event_source_unref(bus->quit_event_source);
+
         if (bus->event)
                 bus->event = sd_event_unref(bus->event);