summaryrefslogtreecommitdiff
path: root/src/libsystemd-bus
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-10-30 15:34:50 +0100
committerLennart Poettering <lennart@poettering.net>2013-10-30 15:37:02 +0100
commita7893c6b28772edbc7e1fea3c209caa54d465648 (patch)
treeae9e44874c63592f44321b9fc9ed07b2c808ef58 /src/libsystemd-bus
parent0f8bd8debb0ff7f5bff7738841931f6c41e40bc1 (diff)
bus: add API call to create bus connection to the system bus of local containers
Also, add support for this to machinectl, so that we can enumerate the machines that run inside a container. We must go deeper!
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r--src/libsystemd-bus/bus-container.c128
-rw-r--r--src/libsystemd-bus/bus-container.h26
-rw-r--r--src/libsystemd-bus/bus-internal.h1
-rw-r--r--src/libsystemd-bus/bus-socket.c4
-rw-r--r--src/libsystemd-bus/bus-socket.h2
-rw-r--r--src/libsystemd-bus/sd-bus.c109
6 files changed, 261 insertions, 9 deletions
diff --git a/src/libsystemd-bus/bus-container.c b/src/libsystemd-bus/bus-container.c
new file mode 100644
index 0000000000..eac1863244
--- /dev/null
+++ b/src/libsystemd-bus/bus-container.c
@@ -0,0 +1,128 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "fileio.h"
+#include "bus-internal.h"
+#include "bus-socket.h"
+#include "bus-container.h"
+
+int bus_container_connect(sd_bus *b) {
+ _cleanup_free_ char *p = NULL, *s = NULL, *ns = NULL, *root = NULL, *class = NULL;
+ _cleanup_close_ int nsfd = -1, rootfd = -1;
+ siginfo_t si;
+ pid_t leader, child;
+ int r;
+
+ assert(b);
+ assert(b->input_fd < 0);
+ assert(b->output_fd < 0);
+
+ p = strappend("/run/systemd/machines/", b->machine);
+ if (!p)
+ return -ENOMEM;
+
+ r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
+ if (r < 0)
+ return r;
+ if (!s)
+ return -EIO;
+
+ if (!streq_ptr(class, "container"))
+ return -EIO;
+
+ r = parse_pid(s, &leader);
+ if (r < 0)
+ return r;
+ if (leader <= 1)
+ return -EIO;
+
+ r = asprintf(&ns, "/proc/%lu/ns/mnt", (unsigned long) leader);
+ if (r < 0)
+ return -ENOMEM;
+
+ nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (nsfd < 0)
+ return -errno;
+
+ r = asprintf(&root, "/proc/%lu/root", (unsigned long) leader);
+ if (r < 0)
+ return -ENOMEM;
+
+ rootfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (rootfd < 0)
+ return -errno;
+
+ b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (b->input_fd < 0)
+ return -errno;
+
+ b->output_fd = b->input_fd;
+
+ r = bus_socket_setup(b);
+ if (r < 0)
+ return r;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ r = setns(nsfd, CLONE_NEWNS);
+ if (r < 0)
+ _exit(255);
+
+ if (fchdir(rootfd) < 0)
+ _exit(255);
+
+ if (chroot(".") < 0)
+ _exit(255);
+
+
+ r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
+ if (r < 0) {
+ if (errno == EINPROGRESS)
+ _exit(1);
+
+ _exit(255);
+ }
+
+ _exit(0);
+ }
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+
+ if (si.si_code != CLD_EXITED)
+ return -EIO;
+
+ if (si.si_status == 1)
+ return 1;
+
+ if (si.si_status != 0)
+ return -EIO;
+
+ return bus_socket_start_auth(b);
+}
diff --git a/src/libsystemd-bus/bus-container.h b/src/libsystemd-bus/bus-container.h
new file mode 100644
index 0000000000..65f43ab4fd
--- /dev/null
+++ b/src/libsystemd-bus/bus-container.h
@@ -0,0 +1,26 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+
+int bus_container_connect(sd_bus *b);
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index 2ae7961915..913f281316 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -196,6 +196,7 @@ struct sd_bus {
socklen_t sockaddr_size;
char *kernel;
+ char *machine;
sd_id128_t server_id;
diff --git a/src/libsystemd-bus/bus-socket.c b/src/libsystemd-bus/bus-socket.c
index b60facb20f..b7e816ea80 100644
--- a/src/libsystemd-bus/bus-socket.c
+++ b/src/libsystemd-bus/bus-socket.c
@@ -600,7 +600,7 @@ static int bus_socket_read_auth(sd_bus *b) {
return 1;
}
-static int bus_socket_setup(sd_bus *b) {
+int bus_socket_setup(sd_bus *b) {
int enable;
socklen_t l;
@@ -668,7 +668,7 @@ static int bus_socket_start_auth_client(sd_bus *b) {
return bus_socket_write_auth(b);
}
-static int bus_socket_start_auth(sd_bus *b) {
+int bus_socket_start_auth(sd_bus *b) {
assert(b);
b->state = BUS_AUTHENTICATING;
diff --git a/src/libsystemd-bus/bus-socket.h b/src/libsystemd-bus/bus-socket.h
index a9c43f82df..c61b90f473 100644
--- a/src/libsystemd-bus/bus-socket.h
+++ b/src/libsystemd-bus/bus-socket.h
@@ -23,9 +23,11 @@
#include "sd-bus.h"
+int bus_socket_setup(sd_bus *b);
int bus_socket_connect(sd_bus *b);
int bus_socket_exec(sd_bus *b);
int bus_socket_take_fd(sd_bus *b);
+int bus_socket_start_auth(sd_bus *b);
int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx);
int bus_socket_read_message(sd_bus *bus, sd_bus_message **m);
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 383b035b7e..f42d5d0ee1 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -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) {
@@ -824,6 +867,14 @@ static int bus_parse_next_address(sd_bus *b) {
return r;
break;
+ } else if (startswith(a, "x-container:")) {
+
+ a += 12;
+ r = parse_container_address(b, &a, &guid);
+ if (r < 0)
+ return r;
+
+ break;
}
a = strchr(a, ';');
@@ -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) {
- } else if (b->exec_path) {
+ r = bus_kernel_connect(b);
+ if (r >= 0)
+ return r;
- r = bus_socket_exec(b);
+ b->last_connect_error = -r;
+
+ } else if (b->machine) {
+
+ 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;
@@ -1069,6 +1128,42 @@ int sd_bus_open_system_remote(const char *host, sd_bus **ret) {
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;