summaryrefslogtreecommitdiff
path: root/src/grp-machine
diff options
context:
space:
mode:
Diffstat (limited to 'src/grp-machine')
-rw-r--r--src/grp-machine/grp-import/libimport/Makefile2
-rw-r--r--src/grp-machine/grp-import/libimport/import-common.c8
-rw-r--r--src/grp-machine/grp-import/systemd-export/Makefile2
-rw-r--r--src/grp-machine/grp-import/systemd-import/Makefile3
-rw-r--r--src/grp-machine/grp-import/systemd-import/import.c4
-rw-r--r--src/grp-machine/grp-import/systemd-importd/Makefile4
-rw-r--r--src/grp-machine/grp-import/systemd-importd/importd.c4
-rw-r--r--src/grp-machine/grp-import/systemd-importd/systemd-importd.service.in2
-rw-r--r--src/grp-machine/grp-import/systemd-pull/Makefile2
-rw-r--r--src/grp-machine/grp-import/systemd-pull/pull-common.c4
-rw-r--r--src/grp-machine/grp-import/systemd-pull/pull.c4
-rw-r--r--src/grp-machine/machinectl/Makefile2
-rw-r--r--src/grp-machine/machinectl/machinectl.c153
-rw-r--r--src/grp-machine/machinectl/machinectl.completion.bash2
-rw-r--r--src/grp-machine/machinectl/machinectl.completion.zsh1
-rw-r--r--src/grp-machine/machinectl/machinectl.xml11
-rw-r--r--src/grp-machine/nss-mymachines/Makefile3
-rw-r--r--src/grp-machine/systemd-machined/Makefile16
-rw-r--r--src/grp-machine/systemd-machined/image-dbus.c4
-rw-r--r--src/grp-machine/systemd-machined/machine-dbus.c7
-rw-r--r--src/grp-machine/systemd-machined/machine.c2
-rw-r--r--src/grp-machine/systemd-machined/machined-dbus.c214
-rw-r--r--src/grp-machine/systemd-machined/machined.c2
-rw-r--r--src/grp-machine/systemd-machined/operation.c43
-rw-r--r--src/grp-machine/systemd-machined/operation.h4
-rw-r--r--src/grp-machine/systemd-machined/org.freedesktop.machine1.conf4
-rw-r--r--src/grp-machine/systemd-machined/systemd-machined.service.in2
27 files changed, 387 insertions, 122 deletions
diff --git a/src/grp-machine/grp-import/libimport/Makefile b/src/grp-machine/grp-import/libimport/Makefile
index 5691d0bba1..ee10c0f6df 100644
--- a/src/grp-machine/grp-import/libimport/Makefile
+++ b/src/grp-machine/grp-import/libimport/Makefile
@@ -45,7 +45,7 @@ test_qcow2_CFLAGS = \
$(ZLIB_CFLAGS)
test_qcow2_LDADD = \
- libshared.la \
+ libsystemd-shared.la \
$(ZLIB_LIBS)
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/grp-machine/grp-import/libimport/import-common.c b/src/grp-machine/grp-import/libimport/import-common.c
index cd69e900ec..9061cd4da1 100644
--- a/src/grp-machine/grp-import/libimport/import-common.c
+++ b/src/grp-machine/grp-import/libimport/import-common.c
@@ -126,9 +126,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
if (null_fd != STDOUT_FILENO)
null_fd = safe_close(null_fd);
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
+ stdio_unset_cloexec();
if (unshare(CLONE_NEWNET) < 0)
log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
@@ -200,9 +198,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
if (null_fd != STDIN_FILENO)
null_fd = safe_close(null_fd);
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
+ stdio_unset_cloexec();
if (unshare(CLONE_NEWNET) < 0)
log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
diff --git a/src/grp-machine/grp-import/systemd-export/Makefile b/src/grp-machine/grp-import/systemd-export/Makefile
index f8fcbc3cca..aa8792565a 100644
--- a/src/grp-machine/grp-import/systemd-export/Makefile
+++ b/src/grp-machine/grp-import/systemd-export/Makefile
@@ -39,7 +39,7 @@ systemd_export_CFLAGS = \
$(BZIP2_CFLAGS)
systemd_export_LDADD = \
- libshared.la \
+ libsystemd-shared.la \
libimport.la \
$(XZ_LIBS) \
$(ZLIB_LIBS) \
diff --git a/src/grp-machine/grp-import/systemd-import/Makefile b/src/grp-machine/grp-import/systemd-import/Makefile
index 06fd01fcd7..221659c346 100644
--- a/src/grp-machine/grp-import/systemd-import/Makefile
+++ b/src/grp-machine/grp-import/systemd-import/Makefile
@@ -38,8 +38,7 @@ systemd_import_CFLAGS = \
$(BZIP2_CFLAGS)
systemd_import_LDADD = \
- libshared.la \
- libimport.la \
+ libsystemd-shared.la \
$(XZ_LIBS) \
$(ZLIB_LIBS) \
$(BZIP2_LIBS)
diff --git a/src/grp-machine/grp-import/systemd-import/import.c b/src/grp-machine/grp-import/systemd-import/import.c
index 6744006312..38fe7f8110 100644
--- a/src/grp-machine/grp-import/systemd-import/import.c
+++ b/src/grp-machine/grp-import/systemd-import/import.c
@@ -91,7 +91,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
else if (r > 0) {
- log_error_errno(EEXIST, "Image '%s' already exists.", local);
+ log_error("Image '%s' already exists.", local);
return -EEXIST;
}
}
@@ -186,7 +186,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
else if (r > 0) {
- log_error_errno(EEXIST, "Image '%s' already exists.", local);
+ log_error("Image '%s' already exists.", local);
return -EEXIST;
}
}
diff --git a/src/grp-machine/grp-import/systemd-importd/Makefile b/src/grp-machine/grp-import/systemd-importd/Makefile
index 1f5bae1267..e00f531a0d 100644
--- a/src/grp-machine/grp-import/systemd-importd/Makefile
+++ b/src/grp-machine/grp-import/systemd-importd/Makefile
@@ -34,9 +34,9 @@ systemd_importd_CFLAGS = \
-D SYSTEMD_EXPORT_PATH=\"$(rootlibexecdir)/systemd-export\"
systemd_importd_LDADD = \
- libshared.la
+ libsystemd-shared.la
-dist_rootlibexec_DATA = \
+dist_rootlibexec_DATA += \
src/import/import-pubring.gpg
nodist_systemunit_DATA += \
diff --git a/src/grp-machine/grp-import/systemd-importd/importd.c b/src/grp-machine/grp-import/systemd-importd/importd.c
index e790c0c475..f032f06fcf 100644
--- a/src/grp-machine/grp-import/systemd-importd/importd.c
+++ b/src/grp-machine/grp-import/systemd-importd/importd.c
@@ -448,9 +448,7 @@ static int transfer_start(Transfer *t) {
safe_close(null_fd);
}
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
+ stdio_unset_cloexec();
setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1);
setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1);
diff --git a/src/grp-machine/grp-import/systemd-importd/systemd-importd.service.in b/src/grp-machine/grp-import/systemd-importd/systemd-importd.service.in
index b74ad72cdc..0f5489e7e3 100644
--- a/src/grp-machine/grp-import/systemd-importd/systemd-importd.service.in
+++ b/src/grp-machine/grp-import/systemd-importd/systemd-importd.service.in
@@ -17,3 +17,5 @@ CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_
NoNewPrivileges=yes
WatchdogSec=3min
KillMode=mixed
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io
diff --git a/src/grp-machine/grp-import/systemd-pull/Makefile b/src/grp-machine/grp-import/systemd-pull/Makefile
index 1ee9fa25de..780a5a4610 100644
--- a/src/grp-machine/grp-import/systemd-pull/Makefile
+++ b/src/grp-machine/grp-import/systemd-pull/Makefile
@@ -48,8 +48,8 @@ systemd_pull_CFLAGS = \
-D USER_KEYRING_PATH=\"$(pkgsysconfdir)/import-pubring.gpg\"
systemd_pull_LDADD = \
+ libsystemd-shared.la \
libimport.la \
- libshared.la \
$(LIBCURL_LIBS) \
$(XZ_LIBS) \
$(ZLIB_LIBS) \
diff --git a/src/grp-machine/grp-import/systemd-pull/pull-common.c b/src/grp-machine/grp-import/systemd-pull/pull-common.c
index f5815c216d..bd1623e003 100644
--- a/src/grp-machine/grp-import/systemd-pull/pull-common.c
+++ b/src/grp-machine/grp-import/systemd-pull/pull-common.c
@@ -507,9 +507,7 @@ int pull_verify(PullJob *main_job,
cmd[k++] = "-";
cmd[k++] = NULL;
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
+ stdio_unset_cloexec();
execvp("gpg2", (char * const *) cmd);
execvp("gpg", (char * const *) cmd);
diff --git a/src/grp-machine/grp-import/systemd-pull/pull.c b/src/grp-machine/grp-import/systemd-pull/pull.c
index 166f91d6e1..4153c938d8 100644
--- a/src/grp-machine/grp-import/systemd-pull/pull.c
+++ b/src/grp-machine/grp-import/systemd-pull/pull.c
@@ -98,7 +98,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
else if (r > 0) {
- log_error_errno(EEXIST, "Image '%s' already exists.", local);
+ log_error("Image '%s' already exists.", local);
return -EEXIST;
}
}
@@ -184,7 +184,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
else if (r > 0) {
- log_error_errno(EEXIST, "Image '%s' already exists.", local);
+ log_error("Image '%s' already exists.", local);
return -EEXIST;
}
}
diff --git a/src/grp-machine/machinectl/Makefile b/src/grp-machine/machinectl/Makefile
index a3ad40e59c..f6760f3174 100644
--- a/src/grp-machine/machinectl/Makefile
+++ b/src/grp-machine/machinectl/Makefile
@@ -27,7 +27,7 @@ machinectl_SOURCES = \
src/machine/machinectl.c
machinectl_LDADD = \
- libshared.la
+ libsystemd-shared.la
rootbin_PROGRAMS += \
machinectl
diff --git a/src/grp-machine/machinectl/machinectl.c b/src/grp-machine/machinectl/machinectl.c
index fa607c57e4..d5304dba37 100644
--- a/src/grp-machine/machinectl/machinectl.c
+++ b/src/grp-machine/machinectl/machinectl.c
@@ -50,6 +50,7 @@
#include "basic/util.h"
#include "basic/verbs.h"
#include "basic/web-util.h"
+#include "sd-bus/bus-common-errors.h"
#include "sd-bus/bus-error.h"
#include "shared/bus-unit-util.h"
#include "shared/bus-util.h"
@@ -527,7 +528,7 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
fputs(strna(i->name), stdout);
- if (!sd_id128_equal(i->id, SD_ID128_NULL))
+ if (!sd_id128_is_null(i->id))
printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
else
putchar('\n');
@@ -1523,8 +1524,33 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
return 0;
}
+static int image_exists(sd_bus *bus, const char *name) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ assert(bus);
+ assert(name);
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "GetImage",
+ &error,
+ NULL,
+ "s", name);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_IMAGE))
+ return 0;
+
+ return log_error_errno(r, "Failed to check whether image %s exists: %s", name, bus_error_message(&error, -r));
+ }
+
+ return 1;
+}
+
static int make_service_name(const char *name, char **ret) {
- _cleanup_free_ char *e = NULL;
int r;
assert(name);
@@ -1535,11 +1561,7 @@ static int make_service_name(const char *name, char **ret) {
return -EINVAL;
}
- e = unit_name_escape(name);
- if (!e)
- return log_oom();
-
- r = unit_name_build("systemd-nspawn", e, ".service", ret);
+ r = unit_name_build("systemd-nspawn", name, ".service", ret);
if (r < 0)
return log_error_errno(r, "Failed to build unit name: %m");
@@ -1569,6 +1591,14 @@ static int start_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
+ r = image_exists(bus, argv[i]);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_error("Machine image '%s' does not exist.", argv[1]);
+ return -ENXIO;
+ }
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -1636,6 +1666,14 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
+ r = image_exists(bus, argv[i]);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_error("Machine image '%s' does not exist.", argv[1]);
+ return -ENXIO;
+ }
+
r = sd_bus_message_append(m, "s", unit);
if (r < 0)
return bus_log_create_error(r);
@@ -2379,7 +2417,7 @@ static int set_limit(int argc, char *argv[], void *userdata) {
}
static int clean_images(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
uint64_t usage, total = 0;
char fb[FORMAT_BYTES_MAX];
@@ -2388,15 +2426,22 @@ static int clean_images(int argc, char *argv[], void *userdata) {
unsigned c = 0;
int r;
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "CleanPool",
- &error,
- &reply,
- "s", arg_all ? "all" : "hidden");
+ "CleanPool");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "s", arg_all ? "all" : "hidden");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence permit a longer time for completion. */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, &reply);
if (r < 0)
return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r));
@@ -2540,35 +2585,65 @@ static int parse_argv(int argc, char *argv[]) {
};
bool reorder = false;
- int c, r;
+ int c, r, shell = -1;
assert(argc >= 0);
assert(argv);
for (;;) {
- const char * const option_string = "+hp:als:H:M:qn:o:";
+ static const char option_string[] = "-hp:als:H:M:qn:o:";
c = getopt_long(argc, argv, option_string + reorder, options, NULL);
- if (c < 0) {
+ if (c < 0)
+ break;
+
+ switch (c) {
+
+ case 1: /* getopt_long() returns 1 if "-" was the first character of the option string, and a
+ * non-option argument was discovered. */
+
+ assert(!reorder);
+
/* We generally are fine with the fact that getopt_long() reorders the command line, and looks
* for switches after the main verb. However, for "shell" we really don't want that, since we
- * want that switches passed after that are passed to the program to execute, and not processed
- * by us. To make this possible, we'll first invoke getopt_long() with reordering disabled
- * (i.e. with the "+" prefix in the option string), and as soon as we hit the end (i.e. the
- * verb) we check if that's "shell". If it is, we exit the loop, since we don't want any
- * further options processed. However, if it is anything else, we process the same argument
- * again, but this time allow reordering. */
-
- if (!reorder && optind < argc && !streq(argv[optind], "shell")) {
+ * want that switches specified after the machine name are passed to the program to execute,
+ * and not processed by us. To make this possible, we'll first invoke getopt_long() with
+ * reordering disabled (i.e. with the "-" prefix in the option string), looking for the first
+ * non-option parameter. If it's the verb "shell" we remember its position and continue
+ * processing options. In this case, as soon as we hit the next non-option argument we found
+ * the machine name, and stop further processing. If the first non-option argument is any other
+ * verb than "shell" we switch to normal reordering mode and continue processing arguments
+ * normally. */
+
+ if (shell >= 0) {
+ /* If we already found the "shell" verb on the command line, and now found the next
+ * non-option argument, then this is the machine name and we should stop processing
+ * further arguments. */
+ optind --; /* don't process this argument, go one step back */
+ goto done;
+ }
+ if (streq(optarg, "shell"))
+ /* Remember the position of the "shell" verb, and continue processing normally. */
+ shell = optind - 1;
+ else {
+ int saved_optind;
+
+ /* OK, this is some other verb. In this case, turn on reordering again, and continue
+ * processing normally. */
reorder = true;
- optind--;
- continue;
+
+ /* We changed the option string. getopt_long() only looks at it again if we invoke it
+ * at least once with a reset option index. Hence, let's reset the option index here,
+ * then invoke getopt_long() again (ignoring what it has to say, after all we most
+ * likely already processed it), and the bump the option index so that we read the
+ * intended argument again. */
+ saved_optind = optind;
+ optind = 0;
+ (void) getopt_long(argc, argv, option_string + reorder, options, NULL);
+ optind = saved_optind - 1; /* go one step back, process this argument again */
}
break;
- }
-
- switch (c) {
case 'h':
return help(0, NULL, NULL);
@@ -2704,6 +2779,22 @@ static int parse_argv(int argc, char *argv[]) {
}
}
+done:
+ if (shell >= 0) {
+ char *t;
+ int i;
+
+ /* We found the "shell" verb while processing the argument list. Since we turned off reordering of the
+ * argument list initially let's readjust it now, and move the "shell" verb to the back. */
+
+ optind -= 1; /* place the option index where the "shell" verb will be placed */
+
+ t = argv[shell];
+ for (i = shell; i < optind; i++)
+ argv[i] = argv[i+1];
+ argv[optind] = t;
+ }
+
return 1;
}
@@ -2720,6 +2811,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "terminate", 2, VERB_ANY, 0, terminate_machine },
{ "reboot", 2, VERB_ANY, 0, reboot_machine },
{ "poweroff", 2, VERB_ANY, 0, poweroff_machine },
+ { "stop", 2, VERB_ANY, 0, poweroff_machine }, /* Convenience alias */
{ "kill", 2, VERB_ANY, 0, kill_machine },
{ "login", VERB_ANY, 2, 0, login_machine },
{ "shell", VERB_ANY, VERB_ANY, 0, shell_machine },
@@ -2750,7 +2842,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
}
int main(int argc, char*argv[]) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
@@ -2772,6 +2864,7 @@ int main(int argc, char*argv[]) {
r = machinectl_main(argc, argv, bus);
finish:
+ sd_bus_flush_close_unref(bus);
pager_close();
polkit_agent_close();
diff --git a/src/grp-machine/machinectl/machinectl.completion.bash b/src/grp-machine/machinectl/machinectl.completion.bash
index e7829ca968..aebe48304d 100644
--- a/src/grp-machine/machinectl/machinectl.completion.bash
+++ b/src/grp-machine/machinectl/machinectl.completion.bash
@@ -41,7 +41,7 @@ _machinectl() {
local -A VERBS=(
[STANDALONE]='list list-images pull-tar pull-raw import-tar import-raw export-tar export-raw list-transfers cancel-transfer'
- [MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit'
+ [MACHINES]='status show start stop login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit'
)
_init_completion || return
diff --git a/src/grp-machine/machinectl/machinectl.completion.zsh b/src/grp-machine/machinectl/machinectl.completion.zsh
index 198fa28f7b..92d77109a5 100644
--- a/src/grp-machine/machinectl/machinectl.completion.zsh
+++ b/src/grp-machine/machinectl/machinectl.completion.zsh
@@ -23,6 +23,7 @@ _available_machines() {
"status:Show VM/container status"
"show:Show properties of one or more VMs/containers"
"start:Start container as a service"
+ "stop:Stop container (equal to poweroff)"
"login:Get a login prompt on a VM/container"
"enable:Enable automatic container start at boot"
"disable:Disable automatic container start at boot"
diff --git a/src/grp-machine/machinectl/machinectl.xml b/src/grp-machine/machinectl/machinectl.xml
index 4b7f9a0391..597a5cc583 100644
--- a/src/grp-machine/machinectl/machinectl.xml
+++ b/src/grp-machine/machinectl/machinectl.xml
@@ -333,7 +333,7 @@
<listitem><para>Show properties of one or more registered
virtual machines or containers or the manager itself. If no
argument is specified, properties of the manager will be
- shown. If an NAME is specified, properties of this virtual
+ shown. If a NAME is specified, properties of this virtual
machine or container are shown. By default, empty properties
are suppressed. Use <option>--all</option> to show those too.
To select specific properties to show, use
@@ -373,8 +373,7 @@
<para>To interactively start a container on the command line
with full access to the container's console, please invoke
<command>systemd-nspawn</command> directly. To stop a running
- container use <command>machinectl poweroff</command>, see
- below.</para></listitem>
+ container use <command>machinectl poweroff</command>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -461,8 +460,8 @@
<listitem><para>Power off one or more containers. This will
trigger a reboot by sending SIGRTMIN+4 to the container's init
process, which causes systemd-compatible init systems to shut
- down cleanly. This operation does not work on containers that
- do not run a
+ down cleanly. Use <command>stop</command> as alias for <command>poweroff</command>.
+ This operation does not work on containers that do not run a
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>-compatible
init system, such as sysvinit. Use
<command>terminate</command> (see below) to immediately
@@ -576,7 +575,7 @@
<listitem><para>Show properties of one or more registered
virtual machine or container images, or the manager itself. If
no argument is specified, properties of the manager will be
- shown. If an NAME is specified, properties of this virtual
+ shown. If a NAME is specified, properties of this virtual
machine or container image are shown. By default, empty
properties are suppressed. Use <option>--all</option> to show
those too. To select specific properties to show, use
diff --git a/src/grp-machine/nss-mymachines/Makefile b/src/grp-machine/nss-mymachines/Makefile
index 78cb6419c0..bc7f9e791a 100644
--- a/src/grp-machine/nss-mymachines/Makefile
+++ b/src/grp-machine/nss-mymachines/Makefile
@@ -37,7 +37,8 @@ libnss_mymachines_la_LDFLAGS = \
-Wl,--version-script=$(srcdir)/nss-mymachines.sym
libnss_mymachines_la_LIBADD = \
- libsystemd-internal.la
+ libsystemd-internal.la \
+ libbasic.la
lib_LTLIBRARIES += \
libnss_mymachines.la
diff --git a/src/grp-machine/systemd-machined/Makefile b/src/grp-machine/systemd-machined/Makefile
index 66ac0b9275..97fa68c5f9 100644
--- a/src/grp-machine/systemd-machined/Makefile
+++ b/src/grp-machine/systemd-machined/Makefile
@@ -24,19 +24,19 @@ include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
systemd_machined_SOURCES = \
- $(_libmachine_core_la_SOURCES) \
src/machine/machined.c \
src/machine/machined.h
systemd_machined_LDADD = \
libsystemd-internal.la \
libshared.la \
- libbasic.la
+ libbasic.la \
+ libmachine-core.la
rootlibexec_PROGRAMS += \
systemd-machined
-_libmachine_core_la_SOURCES = \
+libmachine_core_la_SOURCES = \
src/machine/machine.c \
src/machine/machine.h \
src/machine/machined-dbus.c \
@@ -47,10 +47,18 @@ _libmachine_core_la_SOURCES = \
src/machine/operation.c \
src/machine/operation.h
+libmachine_core_la_LIBADD = \
+ libsystemd-shared.la
+
+noinst_LTLIBRARIES += \
+ libmachine-core.la
+
test_machine_tables_SOURCES = \
- $(_libmachine_core_la_SOURCES) \
src/machine/test-machine-tables.c
+test_machine_tables_LDADD = \
+ libmachine-core.la
+
tests += \
test-machine-tables
diff --git a/src/grp-machine/systemd-machined/image-dbus.c b/src/grp-machine/systemd-machined/image-dbus.c
index 584777e5ad..6ab627a710 100644
--- a/src/grp-machine/systemd-machined/image-dbus.c
+++ b/src/grp-machine/systemd-machined/image-dbus.c
@@ -82,7 +82,7 @@ int bus_image_method_remove(
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
- r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL);
if (r < 0) {
(void) sigkill_wait(child);
return r;
@@ -194,7 +194,7 @@ int bus_image_method_clone(
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
- r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL);
if (r < 0) {
(void) sigkill_wait(child);
return r;
diff --git a/src/grp-machine/systemd-machined/machine-dbus.c b/src/grp-machine/systemd-machined/machine-dbus.c
index 95f2084455..91b5dfa993 100644
--- a/src/grp-machine/systemd-machined/machine-dbus.c
+++ b/src/grp-machine/systemd-machined/machine-dbus.c
@@ -656,8 +656,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
r = sd_bus_message_read(message, "ss", &user, &path);
if (r < 0)
return r;
- if (isempty(user))
- user = NULL;
+ user = empty_to_null(user);
if (isempty(path))
path = "/bin/sh";
if (!path_is_absolute(path))
@@ -1202,8 +1201,6 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
child_fail:
(void) write(errno_pipe_fd[1], &r, sizeof(r));
- errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
-
_exit(EXIT_FAILURE);
}
@@ -1211,7 +1208,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
/* Copying might take a while, hence install a watch on the child, and return */
- r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]);
+ r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
if (r < 0) {
(void) sigkill_wait(child);
return r;
diff --git a/src/grp-machine/systemd-machined/machine.c b/src/grp-machine/systemd-machined/machine.c
index 82d8f66395..701fec0e67 100644
--- a/src/grp-machine/systemd-machined/machine.c
+++ b/src/grp-machine/systemd-machined/machine.c
@@ -182,7 +182,7 @@ int machine_save(Machine *m) {
fprintf(f, "ROOT=%s\n", escaped);
}
- if (!sd_id128_equal(m->id, SD_ID128_NULL))
+ if (!sd_id128_is_null(m->id))
fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
if (m->leader != 0)
diff --git a/src/grp-machine/systemd-machined/machined-dbus.c b/src/grp-machine/systemd-machined/machined-dbus.c
index 7caecd43a0..349ffcf298 100644
--- a/src/grp-machine/systemd-machined/machined-dbus.c
+++ b/src/grp-machine/systemd-machined/machined-dbus.c
@@ -27,6 +27,7 @@
#include "basic/btrfs-util.h"
#include "basic/cgroup-util.h"
#include "basic/fd-util.h"
+#include "basic/fileio.h"
#include "basic/formats-util.h"
#include "basic/hostname-util.h"
#include "basic/io-util.h"
@@ -823,22 +824,106 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata,
return bus_image_method_mark_read_only(message, i, error);
}
+static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ bool success;
+ size_t n;
+ int r;
+
+ assert(operation);
+ assert(operation->extra_fd >= 0);
+
+ if (lseek(operation->extra_fd, 0, SEEK_SET) == (off_t) -1)
+ return -errno;
+
+ f = fdopen(operation->extra_fd, "re");
+ if (!f)
+ return -errno;
+
+ operation->extra_fd = -1;
+
+ /* The resulting temporary file starts with a boolean value that indicates success or not. */
+ errno = 0;
+ n = fread(&success, 1, sizeof(success), f);
+ if (n != sizeof(success))
+ return ret < 0 ? ret : (errno != 0 ? -errno : -EIO);
+
+ if (ret < 0) {
+ _cleanup_free_ char *name = NULL;
+
+ /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
+ * set to false followed by the name of the failed image. Let's try to read this and use it for the
+ * error message. If we can't read it, don't mind, and return the naked error. */
+
+ if (success) /* The resulting temporary file could not be updated, ignore it. */
+ return ret;
+
+ r = read_nul_string(f, &name);
+ if (r < 0 || isempty(name)) /* Same here... */
+ return ret;
+
+ return sd_bus_error_set_errnof(error, ret, "Failed to remove image %s: %m", name);
+ }
+
+ assert(success);
+
+ r = sd_bus_message_new_method_return(operation->message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ /* On success the resulting temporary file will contain a list of image names that were removed followed by
+ * their size on disk. Let's read that and turn it into a bus message. */
+ for (;;) {
+ _cleanup_free_ char *name = NULL;
+ uint64_t size;
+
+ r = read_nul_string(f, &name);
+ if (r < 0)
+ return r;
+ if (isempty(name)) /* reached the end */
+ break;
+
+ errno = 0;
+ n = fread(&size, 1, sizeof(size), f);
+ if (n != sizeof(size))
+ return errno != 0 ? -errno : -EIO;
+
+ r = sd_bus_message_append(reply, "(st)", name, size);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
enum {
REMOVE_ALL,
REMOVE_HIDDEN,
} mode;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
+ _cleanup_close_ int result_fd = -1;
Manager *m = userdata;
- Image *image;
+ Operation *operation;
const char *mm;
- Iterator i;
+ pid_t child;
int r;
assert(message);
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+
r = sd_bus_message_read(message, "s", &mm);
if (r < 0)
return r;
@@ -864,50 +949,109 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
if (r == 0)
return 1; /* Will call us back */
- images = hashmap_new(&string_hash_ops);
- if (!images)
- return -ENOMEM;
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
- r = image_discover(images);
- if (r < 0)
- return r;
+ /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
+ * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
+ * continuously */
+ result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC);
+ if (result_fd < 0)
+ return -errno;
- r = sd_bus_message_new_method_return(message, &reply);
- if (r < 0)
- return r;
+ /* This might be a slow operation, run it asynchronously in a background process */
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
- r = sd_bus_message_open_container(reply, 'a', "(st)");
- if (r < 0)
- return r;
+ if (child == 0) {
+ _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+ bool success = true;
+ Image *image;
+ Iterator i;
+ ssize_t l;
- HASHMAP_FOREACH(image, images, i) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
- /* We can't remove vendor images (i.e. those in /usr) */
- if (IMAGE_IS_VENDOR(image))
- continue;
+ images = hashmap_new(&string_hash_ops);
+ if (!images) {
+ r = -ENOMEM;
+ goto child_fail;
+ }
- if (IMAGE_IS_HOST(image))
- continue;
+ r = image_discover(images);
+ if (r < 0)
+ goto child_fail;
- if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
- continue;
+ l = write(result_fd, &success, sizeof(success));
+ if (l < 0) {
+ r = -errno;
+ goto child_fail;
+ }
- r = image_remove(image);
- if (r == -EBUSY) /* keep images that are currently being used. */
- continue;
- if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name);
+ HASHMAP_FOREACH(image, images, i) {
- r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive);
- if (r < 0)
- return r;
+ /* We can't remove vendor images (i.e. those in /usr) */
+ if (IMAGE_IS_VENDOR(image))
+ continue;
+
+ if (IMAGE_IS_HOST(image))
+ continue;
+
+ if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
+ continue;
+
+ r = image_remove(image);
+ if (r == -EBUSY) /* keep images that are currently being used. */
+ continue;
+ if (r < 0) {
+ /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
+ success = false;
+ (void) ftruncate(result_fd, 0);
+ (void) lseek(result_fd, 0, SEEK_SET);
+ (void) write(result_fd, &success, sizeof(success));
+ (void) write(result_fd, image->name, strlen(image->name)+1);
+ goto child_fail;
+ }
+
+ l = write(result_fd, image->name, strlen(image->name)+1);
+ if (l < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+
+ l = write(result_fd, &image->usage_exclusive, sizeof(image->usage_exclusive));
+ if (l < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+ }
+
+ result_fd = safe_close(result_fd);
+ _exit(EXIT_SUCCESS);
+
+ child_fail:
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
}
- r = sd_bus_message_close_container(reply);
- if (r < 0)
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ /* The clean-up might take a while, hence install a watch on the child and return */
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0], &operation);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_send(NULL, reply, NULL);
+ operation->extra_fd = result_fd;
+ operation->done = clean_pool_done;
+
+ result_fd = -1;
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
diff --git a/src/grp-machine/systemd-machined/machined.c b/src/grp-machine/systemd-machined/machined.c
index 83a74e2549..a01d1820a1 100644
--- a/src/grp-machine/systemd-machined/machined.c
+++ b/src/grp-machine/systemd-machined/machined.c
@@ -304,7 +304,7 @@ void manager_gc(Manager *m, bool drop_not_started) {
machine_get_state(machine) != MACHINE_CLOSING)
machine_stop(machine);
- /* Now, the stop stop probably made this referenced
+ /* Now, the stop probably made this referenced
* again, but if it didn't, then it's time to let it
* go entirely. */
if (!machine_check_gc(machine, drop_not_started)) {
diff --git a/src/grp-machine/systemd-machined/operation.c b/src/grp-machine/systemd-machined/operation.c
index f1bcb1d860..f16c38c47a 100644
--- a/src/grp-machine/systemd-machined/operation.c
+++ b/src/grp-machine/systemd-machined/operation.c
@@ -31,7 +31,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
assert(o);
assert(si);
- log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i",
+ log_debug("Operating " PID_FMT " is now complete with code=%s status=%i",
o->pid,
sigchld_code_to_string(si->si_code), si->si_status);
@@ -42,18 +42,33 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
goto fail;
}
- if (si->si_status != EXIT_SUCCESS) {
- if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
- r = sd_bus_error_set_errnof(&error, r, "%m");
- else
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
-
+ if (si->si_status == EXIT_SUCCESS)
+ r = 0;
+ else if (read(o->errno_fd, &r, sizeof(r)) != sizeof(r)) { /* Try to acquire error code for failed operation */
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
goto fail;
}
- r = sd_bus_reply_method_return(o->message, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
+ if (o->done) {
+ /* A completion routine is set for this operation, call it. */
+ r = o->done(o, r, &error);
+ if (r < 0) {
+ if (!sd_bus_error_is_set(&error))
+ sd_bus_error_set_errno(&error, r);
+
+ goto fail;
+ }
+
+ } else {
+ /* The default operation when done is to simply return an error on failure or an empty success
+ * message on success. */
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_reply_method_return(o->message, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+ }
operation_free(o);
return 0;
@@ -67,7 +82,7 @@ fail:
return 0;
}
-int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) {
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) {
Operation *o;
int r;
@@ -80,6 +95,8 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag
if (!o)
return -ENOMEM;
+ o->extra_fd = -1;
+
r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
if (r < 0) {
free(o);
@@ -103,6 +120,9 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag
/* At this point we took ownership of both the child and the errno file descriptor! */
+ if (ret)
+ *ret = o;
+
return 0;
}
@@ -113,6 +133,7 @@ Operation *operation_free(Operation *o) {
sd_event_source_unref(o->event_source);
safe_close(o->errno_fd);
+ safe_close(o->extra_fd);
if (o->pid > 1)
(void) sigkill_wait(o->pid);
diff --git a/src/grp-machine/systemd-machined/operation.h b/src/grp-machine/systemd-machined/operation.h
index 0821466a00..713ffe88c4 100644
--- a/src/grp-machine/systemd-machined/operation.h
+++ b/src/grp-machine/systemd-machined/operation.h
@@ -38,10 +38,12 @@ struct Operation {
pid_t pid;
sd_bus_message *message;
int errno_fd;
+ int extra_fd;
sd_event_source *event_source;
+ int (*done)(Operation *o, int ret, sd_bus_error *error);
LIST_FIELDS(Operation, operations);
LIST_FIELDS(Operation, operations_by_machine);
};
-int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd);
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret);
Operation *operation_free(Operation *o);
diff --git a/src/grp-machine/systemd-machined/org.freedesktop.machine1.conf b/src/grp-machine/systemd-machined/org.freedesktop.machine1.conf
index 9d40b90151..562b9d3cc0 100644
--- a/src/grp-machine/systemd-machined/org.freedesktop.machine1.conf
+++ b/src/grp-machine/systemd-machined/org.freedesktop.machine1.conf
@@ -118,6 +118,10 @@
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Manager"
+ send_member="CleanPool"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
send_member="MapFromMachineUser"/>
<allow send_destination="org.freedesktop.machine1"
diff --git a/src/grp-machine/systemd-machined/systemd-machined.service.in b/src/grp-machine/systemd-machined/systemd-machined.service.in
index 685baab21d..dcf9f347b7 100644
--- a/src/grp-machine/systemd-machined/systemd-machined.service.in
+++ b/src/grp-machine/systemd-machined/systemd-machined.service.in
@@ -17,6 +17,8 @@ ExecStart=@rootlibexecdir@/systemd-machined
BusName=org.freedesktop.machine1
CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD
WatchdogSec=3min
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module @obsolete @raw-io
# Note that machined cannot be placed in a mount namespace, since it
# needs access to the host's mount namespace in order to implement the