diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 181da27f7a..8f0dc422ad 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -4,6 +4,7 @@ #include "ansi-color.h" #include "emergency-action.h" +#include "exit-status.h" #include "manager.h" #include "reboot-util.h" #include "special.h" @@ -154,6 +155,10 @@ void emergency_action( if (exit_status >= 0) m->return_value = exit_status; + else if (FLAGS_SET(flags, EMERGENCY_ACTION_IS_FAILURE) && m->return_value == EXIT_SUCCESS) + /* Nothing to propagate, but we act on a failure: don't report success. An exit + * status set explicitly via SetExitCode() stays. */ + m->return_value = EXIT_EXCEPTION; if (MANAGER_IS_USER(m) || detect_container() > 0) { log_and_status(m, action, flags, "Exiting", reason); @@ -173,6 +178,10 @@ void emergency_action( if (exit_status >= 0) m->return_value = exit_status; + else if (FLAGS_SET(flags, EMERGENCY_ACTION_IS_FAILURE) && m->return_value == EXIT_SUCCESS) + /* Nothing to propagate, but we act on a failure: don't report success. An exit + * status set explicitly via SetExitCode() stays. */ + m->return_value = EXIT_EXCEPTION; if (MANAGER_IS_USER(m) || detect_container() > 0) { log_and_status(m, action, flags, "Exiting immediately", reason); diff --git a/src/core/emergency-action.h b/src/core/emergency-action.h index 17f306507f..3d9029414b 100644 --- a/src/core/emergency-action.h +++ b/src/core/emergency-action.h @@ -29,7 +29,8 @@ typedef enum EmergencyActionFlags { EMERGENCY_ACTION_IS_WATCHDOG = 1 << 0, /* this action triggered by a watchdog or other kind of timeout */ EMERGENCY_ACTION_WARN = 1 << 1, /* log at LOG_WARNING + write to system console */ EMERGENCY_ACTION_SLEEP_5S = 1 << 2, /* wait 5s before executing action; only honoured together with EMERGENCY_ACTION_WARN */ - _EMERGENCY_ACTION_FLAGS_MAX = (1 << 3) - 1, + EMERGENCY_ACTION_IS_FAILURE = 1 << 3, /* this action is triggered by a failure, hence must not make us exit 0 */ + _EMERGENCY_ACTION_FLAGS_MAX = (1 << 4) - 1, } EmergencyActionFlags; void emergency_action( diff --git a/src/core/job.c b/src/core/job.c index 2388d1de95..70e14b517f 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1141,7 +1141,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user emergency_action( u->manager, u->job_timeout_action, - EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN|EMERGENCY_ACTION_SLEEP_5S, + EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN|EMERGENCY_ACTION_SLEEP_5S|EMERGENCY_ACTION_IS_FAILURE, u->job_timeout_reboot_arg, /* exit_status= */ -1, "job timed out"); diff --git a/src/core/unit.c b/src/core/unit.c index 44d5c8dea9..28a4af186b 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1888,7 +1888,7 @@ int unit_test_start_limit(Unit *u) { emergency_action( u->manager, u->start_limit_action, - EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN|EMERGENCY_ACTION_SLEEP_5S, + EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN|EMERGENCY_ACTION_SLEEP_5S|EMERGENCY_ACTION_IS_FAILURE, u->reboot_arg, /* exit_status= */ -1, reason); @@ -2844,7 +2844,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (os != UNIT_FAILED && ns == UNIT_FAILED) { reason = strjoina("unit ", u->id, " failed"); - emergency_action(m, u->failure_action, EMERGENCY_ACTION_WARN|EMERGENCY_ACTION_SLEEP_5S, u->reboot_arg, unit_failure_action_exit_status(u), reason); + emergency_action(m, u->failure_action, EMERGENCY_ACTION_WARN|EMERGENCY_ACTION_SLEEP_5S|EMERGENCY_ACTION_IS_FAILURE, u->reboot_arg, unit_failure_action_exit_status(u), reason); } else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && ns == UNIT_INACTIVE) { reason = strjoina("unit ", u->id, " succeeded"); emergency_action(m, u->success_action, /* flags= */ 0, u->reboot_arg, unit_success_action_exit_status(u), reason);