diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-11-04 15:20:00 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-04 15:20:00 +0100 |
commit | 71bb9594e9b01d669cd527f4e581c1f22605004b (patch) | |
tree | 77953ec2a3d9fc935d317868601c2ab18d3d3b21 | |
parent | a4eba5d8cfaabbd87687c651fcdd06df9e267931 (diff) | |
parent | 12ab94a1e4961a39c32efb60b71866ab588d3ea2 (diff) | |
download | systemd-71bb9594e9b01d669cd527f4e581c1f22605004b.tar.gz |
Merge pull request #21030 from DaanDeMeyer/path-skipped
core: Propagate condition failed state from service to path unit.
-rw-r--r-- | mkosi.default.d/fedora/10-mkosi.fedora | 1 | ||||
-rw-r--r-- | src/core/automount.c | 16 | ||||
-rw-r--r-- | src/core/automount.h | 1 | ||||
-rw-r--r-- | src/core/path.c | 16 | ||||
-rw-r--r-- | src/core/path.h | 1 | ||||
-rw-r--r-- | src/core/socket.c | 28 | ||||
-rw-r--r-- | src/core/socket.h | 1 | ||||
-rw-r--r-- | src/core/timer.c | 12 | ||||
-rw-r--r-- | src/core/timer.h | 1 | ||||
-rw-r--r-- | src/core/unit.c | 25 | ||||
-rw-r--r-- | src/core/unit.h | 2 | ||||
-rw-r--r-- | test/testsuite-63.units/test63.service | 2 | ||||
-rw-r--r-- | test/units/testsuite-10.service | 2 | ||||
-rw-r--r-- | test/units/testsuite-63.service | 8 |
14 files changed, 81 insertions, 35 deletions
diff --git a/mkosi.default.d/fedora/10-mkosi.fedora b/mkosi.default.d/fedora/10-mkosi.fedora index 3701f9163b..c348d66c34 100644 --- a/mkosi.default.d/fedora/10-mkosi.fedora +++ b/mkosi.default.d/fedora/10-mkosi.fedora @@ -72,3 +72,4 @@ Packages= strace tpm2-tss less + netcat diff --git a/src/core/automount.c b/src/core/automount.c index 5a004f82d5..de470935c7 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -786,6 +786,11 @@ static void automount_enter_running(Automount *a) { goto fail; } + if (unit_has_failed_condition_or_assert(trigger)) { + automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED); + return; + } + r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL); if (r < 0) { log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); @@ -1074,11 +1079,12 @@ static int automount_test_start_limit(Unit *u) { } static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { - [AUTOMOUNT_SUCCESS] = "success", - [AUTOMOUNT_FAILURE_RESOURCES] = "resources", - [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", - [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted", + [AUTOMOUNT_SUCCESS] = "success", + [AUTOMOUNT_FAILURE_RESOURCES] = "resources", + [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", + [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted", + [AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED] = "mount-condition-failed", }; DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); diff --git a/src/core/automount.h b/src/core/automount.h index 91e6c5766c..4b0c633b79 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -11,6 +11,7 @@ typedef enum AutomountResult { AUTOMOUNT_FAILURE_UNMOUNTED, AUTOMOUNT_FAILURE_START_LIMIT_HIT, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT, + AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED, _AUTOMOUNT_RESULT_MAX, _AUTOMOUNT_RESULT_INVALID = -EINVAL, } AutomountResult; diff --git a/src/core/path.c b/src/core/path.c index 3dd0206e7a..0a3d86e9db 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -480,7 +480,7 @@ static void path_enter_dead(Path *p, PathResult f) { p->result = f; unit_log_result(UNIT(p), p->result == PATH_SUCCESS, path_result_to_string(p->result)); - path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD); + path_set_state(p, p->result == PATH_SUCCESS ? PATH_DEAD : PATH_FAILED); } static void path_enter_running(Path *p) { @@ -780,6 +780,11 @@ static void path_trigger_notify(Unit *u, Unit *other) { return; } + if (unit_has_failed_condition_or_assert(other)) { + path_enter_dead(p, PATH_FAILURE_UNIT_CONDITION_FAILED); + return; + } + /* Don't propagate anything if there's still a job queued */ if (other->job) return; @@ -832,10 +837,11 @@ static const char* const path_type_table[_PATH_TYPE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); static const char* const path_result_table[_PATH_RESULT_MAX] = { - [PATH_SUCCESS] = "success", - [PATH_FAILURE_RESOURCES] = "resources", - [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", + [PATH_SUCCESS] = "success", + [PATH_FAILURE_RESOURCES] = "resources", + [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", + [PATH_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed", }; DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); diff --git a/src/core/path.h b/src/core/path.h index 66ae857dc4..973cd594a6 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -46,6 +46,7 @@ typedef enum PathResult { PATH_FAILURE_RESOURCES, PATH_FAILURE_START_LIMIT_HIT, PATH_FAILURE_UNIT_START_LIMIT_HIT, + PATH_FAILURE_UNIT_CONDITION_FAILED, _PATH_RESULT_MAX, _PATH_RESULT_INVALID = -EINVAL, } PathResult; diff --git a/src/core/socket.c b/src/core/socket.c index ba3df32997..6534311bef 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2335,6 +2335,15 @@ static void socket_enter_running(Socket *s, int cfd_in) { goto refuse; } + if (UNIT_ISSET(s->service) && cfd < 0) { + Unit *service = UNIT_DEREF(s->service); + + if (unit_has_failed_condition_or_assert(service)) { + socket_enter_dead(s, SOCKET_FAILURE_SERVICE_CONDITION_FAILED); + return; + } + } + if (cfd < 0) { bool pending = false; Unit *other; @@ -3444,15 +3453,16 @@ static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { - [SOCKET_SUCCESS] = "success", - [SOCKET_FAILURE_RESOURCES] = "resources", - [SOCKET_FAILURE_TIMEOUT] = "timeout", - [SOCKET_FAILURE_EXIT_CODE] = "exit-code", - [SOCKET_FAILURE_SIGNAL] = "signal", - [SOCKET_FAILURE_CORE_DUMP] = "core-dump", - [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", - [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" + [SOCKET_SUCCESS] = "success", + [SOCKET_FAILURE_RESOURCES] = "resources", + [SOCKET_FAILURE_TIMEOUT] = "timeout", + [SOCKET_FAILURE_EXIT_CODE] = "exit-code", + [SOCKET_FAILURE_SIGNAL] = "signal", + [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", + [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit", + [SOCKET_FAILURE_SERVICE_CONDITION_FAILED] = "service-condition-failed", }; DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); diff --git a/src/core/socket.h b/src/core/socket.h index 6813bdcf8c..1a50ab5d92 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -38,6 +38,7 @@ typedef enum SocketResult { SOCKET_FAILURE_START_LIMIT_HIT, SOCKET_FAILURE_TRIGGER_LIMIT_HIT, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, + SOCKET_FAILURE_SERVICE_CONDITION_FAILED, _SOCKET_RESULT_MAX, _SOCKET_RESULT_INVALID = -EINVAL, } SocketResult; diff --git a/src/core/timer.c b/src/core/timer.c index 8853121c00..240a2f473b 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -598,6 +598,11 @@ static void timer_enter_running(Timer *t) { return; } + if (unit_has_failed_condition_or_assert(trigger)) { + timer_enter_dead(t, TIMER_FAILURE_UNIT_CONDITION_FAILED); + return; + } + r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL); if (r < 0) goto fail; @@ -911,9 +916,10 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); static const char* const timer_result_table[_TIMER_RESULT_MAX] = { - [TIMER_SUCCESS] = "success", - [TIMER_FAILURE_RESOURCES] = "resources", - [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [TIMER_SUCCESS] = "success", + [TIMER_FAILURE_RESOURCES] = "resources", + [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [TIMER_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed", }; DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); diff --git a/src/core/timer.h b/src/core/timer.h index a51fbf56f3..91bf03803f 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -32,6 +32,7 @@ typedef enum TimerResult { TIMER_SUCCESS, TIMER_FAILURE_RESOURCES, TIMER_FAILURE_START_LIMIT_HIT, + TIMER_FAILURE_UNIT_CONDITION_FAILED, _TIMER_RESULT_MAX, _TIMER_RESULT_INVALID = -EINVAL, } TimerResult; diff --git a/src/core/unit.c b/src/core/unit.c index 4c55827a65..59be3b78eb 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1851,16 +1851,10 @@ static bool unit_verify_deps(Unit *u) { int unit_start(Unit *u) { UnitActiveState state; Unit *following; + int r; assert(u); - /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */ - if (UNIT_VTABLE(u)->test_start_limit) { - int r = UNIT_VTABLE(u)->test_start_limit(u); - if (r < 0) - return r; - } - /* If this is already started, then this will succeed. Note that this will even succeed if this unit * is not startable by the user. This is relied on to detect when we need to wait for units and when * waiting is finished. */ @@ -1910,6 +1904,13 @@ int unit_start(Unit *u) { return unit_start(following); } + /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */ + if (UNIT_VTABLE(u)->test_start_limit) { + r = UNIT_VTABLE(u)->test_start_limit(u); + if (r < 0) + return r; + } + /* If it is stopped, but we cannot start it, then fail */ if (!UNIT_VTABLE(u)->start) return -EBADR; @@ -5864,6 +5865,16 @@ Condition *unit_find_failed_condition(Unit *u) { return failed_trigger && !has_succeeded_trigger ? failed_trigger : NULL; } +bool unit_has_failed_condition_or_assert(Unit *u) { + if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result) + return true; + + if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result) + return true; + + return false; +} + static const char* const collect_mode_table[_COLLECT_MODE_MAX] = { [COLLECT_INACTIVE] = "inactive", [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed", diff --git a/src/core/unit.h b/src/core/unit.h index 0dd6a9591d..b49ae7c1b8 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -988,6 +988,8 @@ int unit_thaw_vtable_common(Unit *u); Condition *unit_find_failed_condition(Unit *u); +bool unit_has_failed_condition_or_assert(Unit *u); + /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full_errno_zerook(unit, level, error, ...) \ diff --git a/test/testsuite-63.units/test63.service b/test/testsuite-63.units/test63.service index 0253943f0c..1a8721d82c 100644 --- a/test/testsuite-63.units/test63.service +++ b/test/testsuite-63.units/test63.service @@ -1,6 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Unit] -ConditionPathExists=!/tmp/nonexistent +ConditionPathExists=/tmp/nonexistent [Service] ExecStart=true diff --git a/test/units/testsuite-10.service b/test/units/testsuite-10.service index 94eeb20781..1040763276 100644 --- a/test/units/testsuite-10.service +++ b/test/units/testsuite-10.service @@ -13,5 +13,5 @@ ExecStart=-socat -T20 OPEN:test.file UNIX-CONNECT:/run/test.ctl # systemd enough time even on slower machines, to reach the trigger limit. ExecStart=sleep 10 ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P ActiveState)" = failed' -ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = trigger-limit-hit' +ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = service-condition-failed' ExecStart=sh -x -c 'echo OK >/testok' diff --git a/test/units/testsuite-63.service b/test/units/testsuite-63.service index 0a8d143be9..616d8a6acc 100644 --- a/test/units/testsuite-63.service +++ b/test/units/testsuite-63.service @@ -8,10 +8,10 @@ Type=oneshot ExecStart=rm -f /tmp/nonexistent ExecStart=systemctl start test63.path ExecStart=touch /tmp/test63 -# Make sure systemd has sufficient time to hit the start limit for test63.service. ExecStart=sleep 2 -ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = failed' -ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = start-limit-hit' +# Ensure both the service and the corresponding path unit go inactive due to the failed condition check. +ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = inactive' +ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success' ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = failed' -ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = unit-start-limit-hit' +ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = unit-condition-failed' ExecStart=sh -x -c 'echo OK >/testok' |