summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
-rw-r--r--src/machine/machinectl.c90
-rw-r--r--src/systemd/sd-bus.h1
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);