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/dbus-manager.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/dbus-manager.c')
-rw-r--r-- | src/core/dbus-manager.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 4e5d67fc19..561b6f8bfa 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1201,8 +1201,10 @@ static int method_exit(sd_bus_message *message, void *userdata, sd_bus_error *er if (r < 0) return r; - if (m->running_as == MANAGER_SYSTEM) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers."); + /* Exit() (in contrast to SetExitCode()) is actually allowed even if + * we are running on the host. It will fall back on reboot() in + * systemd-shutdown if it cannot do the exit() because it isn't a + * container. */ m->exit_code = MANAGER_EXIT; @@ -1450,6 +1452,30 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd return sd_bus_reply_method_return(message, NULL); } +static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_error *error) { + uint8_t code; + Manager *m = userdata; + int r; + + assert(message); + assert(m); + + r = mac_selinux_access_check(message, "exit", error); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(message, 'y', &code); + if (r < 0) + return r; + + if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers."); + + m->return_value = code; + + return sd_bus_reply_method_return(message, NULL); +} + static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; Manager *m = userdata; @@ -1933,6 +1959,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0), SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0), SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0), + SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0), SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), @@ -1986,6 +2013,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetExitCode", "y", NULL, method_set_exit_code, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("UnitNew", "so", 0), SD_BUS_SIGNAL("UnitRemoved", "so", 0), |