diff options
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r-- | src/libsystemd-bus/bus-container.c | 128 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-container.h | 26 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-internal.h | 1 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-socket.c | 4 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-socket.h | 2 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 109 |
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; |