diff options
Diffstat (limited to 'src')
-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 | ||||
-rw-r--r-- | src/machine/machinectl.c | 90 | ||||
-rw-r--r-- | src/systemd/sd-bus.h | 1 |
8 files changed, 305 insertions, 56 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; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 241e360d49..83c5da3806 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -47,12 +47,12 @@ static bool arg_no_pager = false; static const char *arg_kill_who = NULL; static int arg_signal = SIGTERM; static enum transport { - TRANSPORT_NORMAL, - TRANSPORT_SSH, -} arg_transport = TRANSPORT_NORMAL; + TRANSPORT_LOCAL, + TRANSPORT_REMOTE, + TRANSPORT_CONTAINER +} arg_transport = TRANSPORT_LOCAL; static bool arg_ask_password = true; static char *arg_host = NULL; -static char *arg_user = NULL; static void pager_open_if_enabled(void) { @@ -94,9 +94,6 @@ static int list_machines(sd_bus *bus, char **args, unsigned n) { goto fail; while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) { - if (r < 0) - goto fail; - printf("%-32s %-9s %-16s\n", name, class, service); k++; @@ -115,7 +112,7 @@ static int list_machines(sd_bus *bus, char **args, unsigned n) { fail: log_error("Failed to parse reply: %s", strerror(-r)); - return -EIO; + return r; } static int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) { @@ -129,30 +126,28 @@ static int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) { assert(bus); assert(unit); - if (arg_transport == TRANSPORT_SSH) + if (arg_transport == TRANSPORT_REMOTE) return 0; path = unit_dbus_path_from_name(unit); if (!path) return log_oom(); - r = sd_bus_call_method( + r = sd_bus_get_property( bus, "org.freedesktop.systemd1", path, - "org.freedesktop.DBus.Properties", - "Get", + "org.freedesktop.systemd1.Scope", + "ControlGroup", &error, &reply, - "ss", - "org.freedesktop.systemd1.Scope", - "ControlGroup"); + "s"); if (r < 0) { log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); return r; } - r = sd_bus_message_read(reply, "v", "s", &cgroup); + r = sd_bus_message_read(reply, "s", &cgroup); if (r < 0) { log_error("Failed to parse reply: %s", strerror(-r)); return r; @@ -371,9 +366,6 @@ static int show_one(const char *verb, sd_bus *bus, const char *path, bool show_p const char *name; const char *contents; - if (r < 0) - goto fail; - r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name); if (r < 0) goto fail; @@ -415,7 +407,7 @@ static int show_one(const char *verb, sd_bus *bus, const char *path, bool show_p fail: log_error("Failed to parse reply: %s", strerror(-r)); - return -EIO; + return r; } static int show(sd_bus *bus, char **args, unsigned n) { @@ -460,7 +452,7 @@ static int show(sd_bus *bus, char **args, unsigned n) { r = sd_bus_message_read(reply, "o", &path); if (r < 0) { log_error("Failed to parse reply: %s", strerror(-r)); - return -EIO; + return r; } r = show_one(args[0], bus, path, show_properties, &new_line); @@ -534,14 +526,15 @@ static int help(void) { "Send control commands to or query the virtual machine and container registration manager.\n\n" " -h --help Show this help\n" " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --no-ask-password Don't prompt for password\n" + " -H --host=[USER@]HOST Show information for remote host\n" + " -M --machine=CONTAINER Show information for local container\n" " -p --property=NAME Show only properties by this name\n" " -a --all Show all properties, including empty ones\n" - " --kill-who=WHO Who to send signal to\n" " -l --full Do not ellipsize output\n" - " -s --signal=SIGNAL Which signal to send\n" - " --no-ask-password Don't prompt for password\n" - " -H --host=[USER@]HOST Show information for remote host\n" - " --no-pager Do not pipe output into a pager\n\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n\n" "Commands:\n" " list List running VMs and containers\n" " status [NAME...] Show VM/container status\n" @@ -572,16 +565,17 @@ static int parse_argv(int argc, char *argv[]) { { "kill-who", required_argument, NULL, ARG_KILL_WHO }, { "signal", required_argument, NULL, 's' }, { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, { NULL, 0, NULL, 0 } }; - int c; + int c, r; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hp:als:H:P", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) { switch (c) { @@ -594,22 +588,16 @@ static int parse_argv(int argc, char *argv[]) { puts(SYSTEMD_FEATURES); return 0; - case 'p': { - char **l; - - l = strv_append(arg_property, optarg); - if (!l) - return -ENOMEM; - - strv_free(arg_property); - arg_property = l; + case 'p': + r = strv_extend(&arg_property, optarg); + if (r < 0) + return log_oom(); /* If the user asked for a particular * property, show it to him, even if it is * empty. */ arg_all = true; break; - } case 'a': arg_all = true; @@ -640,8 +628,13 @@ static int parse_argv(int argc, char *argv[]) { break; case 'H': - arg_transport = TRANSPORT_SSH; - parse_user_at_host(optarg, &arg_user, &arg_host); + arg_transport = TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = TRANSPORT_CONTAINER; + arg_host = optarg; break; case '?': @@ -741,7 +734,7 @@ static int machinectl_main(sd_bus *bus, int argc, char *argv[], const int r) { } int main(int argc, char*argv[]) { - int r, retval = EXIT_FAILURE; + int r, ret = EXIT_FAILURE; _cleanup_bus_unref_ sd_bus *bus = NULL; setlocale(LC_ALL, ""); @@ -752,28 +745,31 @@ int main(int argc, char*argv[]) { if (r < 0) goto finish; else if (r == 0) { - retval = EXIT_SUCCESS; + ret = EXIT_SUCCESS; goto finish; } - if (arg_transport == TRANSPORT_NORMAL) + if (arg_transport == TRANSPORT_LOCAL) r = sd_bus_open_system(&bus); - else if (arg_transport == TRANSPORT_SSH) + else if (arg_transport == TRANSPORT_REMOTE) r = sd_bus_open_system_remote(arg_host, &bus); + else if (arg_transport == TRANSPORT_CONTAINER) + r = sd_bus_open_system_container(arg_host, &bus); else assert_not_reached("Uh, invalid transport..."); if (r < 0) { - retval = EXIT_FAILURE; + log_error("Failed to connect to machined: %s", strerror(-r)); + ret = EXIT_FAILURE; goto finish; } r = machinectl_main(bus, argc, argv, r); - retval = r < 0 ? EXIT_FAILURE : r; + ret = r < 0 ? EXIT_FAILURE : r; finish: strv_free(arg_property); pager_close(); - return retval; + return ret; } diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 7b6c86dd39..7163b0c408 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -61,6 +61,7 @@ typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *path, char *** int sd_bus_open_user(sd_bus **ret); int sd_bus_open_system(sd_bus **ret); int sd_bus_open_system_remote(const char *host, sd_bus **ret); +int sd_bus_open_system_container(const char *machine, sd_bus **ret); int sd_bus_new(sd_bus **ret); int sd_bus_set_address(sd_bus *bus, const char *address); |