]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: Propagate condition failed state to triggering units. 21030/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 18 Oct 2021 12:17:02 +0000 (14:17 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 3 Nov 2021 20:25:14 +0000 (20:25 +0000)
Alternative to https://github.com/systemd/systemd/pull/20531.

Whenever a service triggered by another unit fails condition checks,
stop the triggering unit to prevent systemd busy looping trying to
start the triggered unit.

13 files changed:
src/core/automount.c
src/core/automount.h
src/core/path.c
src/core/path.h
src/core/socket.c
src/core/socket.h
src/core/timer.c
src/core/timer.h
src/core/unit.c
src/core/unit.h
test/testsuite-63.units/test63.service
test/units/testsuite-10.service
test/units/testsuite-63.service

index 5a004f82d5225f9e6d36942d21e57b75b02b016d..de470935c7fe859fa4bc8b76cd67b546c24312a0 100644 (file)
@@ -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);
index 91e6c5766cea883eb887ca3c527abcbb53659c23..4b0c633b79e1e83195fdd53077d024e28f12d3d4 100644 (file)
@@ -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;
index 3dd0206e7a8dcdd2e2e8e69c20a7e86eda0ffedd..0a3d86e9dbd04995eec8c6b574be4dc13a263ebd 100644 (file)
@@ -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);
index 66ae857dc40832305c09ff7dbfb1716aeb427a01..973cd594a62ef1c629db1354df57c1a91b689772 100644 (file)
@@ -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;
index 81178e3de267e9d8f608247af89b772a3943ef15..ffa3fe3317380459950b309c40af6524a054fbad 100644 (file)
@@ -2336,6 +2336,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;
@@ -3445,15 +3454,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);
index 6813bdcf8c8e1faed413937db02d638e5b01ae5d..1a50ab5d927930e4ea45df7abeebb1c2efe4b583 100644 (file)
@@ -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;
index 8853121c005666407b233c930845bf6435327486..240a2f473ba2ff45e2aab11b2b5da6ba71fe5a67 100644 (file)
@@ -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);
index a51fbf56f336ccaac13b15cdc0917b328a2271db..91bf03803f35cd39c46aa188d434684d63caf001 100644 (file)
@@ -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;
index a6403002a6fd6b1f3a72f9f6eab25ed446edb7b0..59be3b78eb595061ec6b930428f49d2fc216d3c5 100644 (file)
@@ -5865,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",
index 0dd6a9591d96c464922d224eaefa1f34ddacb190..b49ae7c1b820cee1337ccb675b73f8ea1afab30e 100644 (file)
@@ -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, ...)             \
index 0253943f0ccdfe13c8e1fee82c181b8c69ee75f4..1a8721d82c70da920f69d9820fe998992e97b260 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [Unit]
-ConditionPathExists=!/tmp/nonexistent
+ConditionPathExists=/tmp/nonexistent
 
 [Service]
 ExecStart=true
index 94eeb20781228da312c835c4e24fa0b60fcd8396..1040763276858e48f292b7dee8932b416efcbcc0 100644 (file)
@@ -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'
index 0a8d143be909a785fcb72a6878a36d7e53aee68c..616d8a6acc88389787b7f4e432c55a9bd6445034 100644 (file)
@@ -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'