From 287419c119ef961db487a281162ab037eba70c61 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Fri, 18 Sep 2015 13:37:34 +0200 Subject: containers: systemd exits with non-zero code When a systemd service running in a container exits with a non-zero code, it can be useful to terminate the container immediately and get the exit code back to the host, when systemd-nspawn returns. This was not possible to do. This patch adds the following to make it possible: - Add a read-only "ExitCode" property on PID 1's "Manager" bus object. By default, it is 0 so the behaviour stays the same as previously. - Add a method "SetExitCode" on the same object. The method fails when called on baremetal: it is only allowed in containers or in user session. - Add support in systemctl to call "systemctl exit 42". It reuses the existing code for user session. - Add exit.target and systemd-exit.service to the system instance. - Change main() to actually call systemd-shutdown to exit() with the correct value. - Add verb 'exit' in systemd-shutdown with parameter --exit-code - Update systemctl manpage. I used the following to test it: | $ sudo rkt --debug --insecure-skip-verify run \ | --mds-register=false --local docker://busybox \ | --exec=/bin/chroot -- /proc/1/root \ | systemctl --force exit 42 | ... | Container rkt-895a0cba-5c66-4fa5-831c-e3f8ddc5810d failed with error code 42. | $ echo $? | 42 Fixes https://github.com/systemd/systemd/issues/1290 --- src/core/shutdown.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src/core/shutdown.c') diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 8cc6efc5b8..5296efce1d 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -48,6 +48,7 @@ #define FINALIZE_ATTEMPTS 50 static char* arg_verb; +static uint8_t arg_exit_code; static int parse_argv(int argc, char *argv[]) { enum { @@ -55,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_LOG_TARGET, ARG_LOG_COLOR, ARG_LOG_LOCATION, + ARG_EXIT_CODE, }; static const struct option options[] = { @@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) { { "log-target", required_argument, NULL, ARG_LOG_TARGET }, { "log-color", optional_argument, NULL, ARG_LOG_COLOR }, { "log-location", optional_argument, NULL, ARG_LOG_LOCATION }, + { "exit-code", required_argument, NULL, ARG_EXIT_CODE }, {} }; @@ -110,6 +113,13 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_EXIT_CODE: + r = safe_atou8(optarg, &arg_exit_code); + if (r < 0) + log_error("Failed to parse exit code %s, ignoring", optarg); + + break; + case '\001': if (!arg_verb) arg_verb = optarg; @@ -183,6 +193,8 @@ int main(int argc, char *argv[]) { cmd = RB_HALT_SYSTEM; else if (streq(arg_verb, "kexec")) cmd = LINUX_REBOOT_CMD_KEXEC; + else if (streq(arg_verb, "exit")) + cmd = 0; /* ignored, just checking that arg_verb is valid */ else { r = -EINVAL; log_error("Unknown action '%s'.", arg_verb); @@ -339,6 +351,16 @@ int main(int argc, char *argv[]) { if (!in_container) sync(); + if (streq(arg_verb, "exit")) { + if (in_container) + exit(arg_exit_code); + else { + /* We cannot exit() on the host, fallback on another + * method. */ + cmd = RB_POWER_OFF; + } + } + switch (cmd) { case LINUX_REBOOT_CMD_KEXEC: -- cgit v1.2.3-54-g00ecf