diff options
author | Alban Crequy <alban.crequy@gmail.com> | 2015-09-18 13:37:34 +0200 |
---|---|---|
committer | Alban Crequy <alban.crequy@gmail.com> | 2015-09-21 17:32:45 +0200 |
commit | 287419c119ef961db487a281162ab037eba70c61 (patch) | |
tree | e7f4c01e50b7b944b9d9d0ed8290ead8762da906 /src/core/shutdown.c | |
parent | a1b7a5bbdd8da94e41b5e79be7a6e853ae910d2b (diff) |
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
Diffstat (limited to 'src/core/shutdown.c')
-rw-r--r-- | src/core/shutdown.c | 22 |
1 files changed, 22 insertions, 0 deletions
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: |