8f24f2
From 2820f1706275acd787c72d9a57892200566f0bbe Mon Sep 17 00:00:00 2001
8f24f2
From: Daan De Meyer <daan.j.demeyer@gmail.com>
8f24f2
Date: Mon, 18 Oct 2021 14:17:02 +0200
8f24f2
Subject: [PATCH] core: Propagate condition failed state to triggering units.
8f24f2
8f24f2
Alternative to https://github.com/systemd/systemd/pull/20531.
8f24f2
8f24f2
Whenever a service triggered by another unit fails condition checks,
8f24f2
stop the triggering unit to prevent systemd busy looping trying to
8f24f2
start the triggered unit.
8f24f2
8f24f2
(cherry picked from commit 12ab94a1e4961a39c32efb60b71866ab588d3ea2)
8f24f2
8f24f2
Resolves: #2065322
8f24f2
---
8f24f2
 src/core/automount.c | 14 ++++++++++----
8f24f2
 src/core/automount.h |  1 +
8f24f2
 src/core/path.c      | 16 +++++++++++-----
8f24f2
 src/core/path.h      |  1 +
8f24f2
 src/core/socket.c    | 28 +++++++++++++++++++---------
8f24f2
 src/core/socket.h    |  1 +
8f24f2
 src/core/timer.c     | 12 +++++++++---
8f24f2
 src/core/timer.h     |  1 +
8f24f2
 src/core/unit.c      | 10 ++++++++++
8f24f2
 src/core/unit.h      |  2 ++
8f24f2
 10 files changed, 65 insertions(+), 21 deletions(-)
8f24f2
8f24f2
diff --git a/src/core/automount.c b/src/core/automount.c
8f24f2
index c1c513d4a5..bac3b2fab7 100644
8f24f2
--- a/src/core/automount.c
8f24f2
+++ b/src/core/automount.c
8f24f2
@@ -776,6 +776,11 @@ static void automount_enter_running(Automount *a) {
8f24f2
                 goto fail;
8f24f2
         }
8f24f2
 
8f24f2
+        if (unit_has_failed_condition_or_assert(trigger)) {
8f24f2
+                automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED);
8f24f2
+                return;
8f24f2
+        }
8f24f2
+
8f24f2
         r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
8f24f2
         if (r < 0) {
8f24f2
                 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
8f24f2
@@ -1087,10 +1092,11 @@ static int automount_can_start(Unit *u) {
8f24f2
 }
8f24f2
 
8f24f2
 static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
8f24f2
-        [AUTOMOUNT_SUCCESS] = "success",
8f24f2
-        [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
8f24f2
-        [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
8f24f2
-        [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
8f24f2
+        [AUTOMOUNT_SUCCESS]                        = "success",
8f24f2
+        [AUTOMOUNT_FAILURE_RESOURCES]              = "resources",
8f24f2
+        [AUTOMOUNT_FAILURE_START_LIMIT_HIT]        = "start-limit-hit",
8f24f2
+        [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT]  = "mount-start-limit-hit",
8f24f2
+        [AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED] = "mount-condition-failed",
8f24f2
 };
8f24f2
 
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
8f24f2
diff --git a/src/core/automount.h b/src/core/automount.h
8f24f2
index 21dd1c0774..a7417d195c 100644
8f24f2
--- a/src/core/automount.h
8f24f2
+++ b/src/core/automount.h
8f24f2
@@ -10,6 +10,7 @@ typedef enum AutomountResult {
8f24f2
         AUTOMOUNT_FAILURE_RESOURCES,
8f24f2
         AUTOMOUNT_FAILURE_START_LIMIT_HIT,
8f24f2
         AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT,
8f24f2
+        AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED,
8f24f2
         _AUTOMOUNT_RESULT_MAX,
8f24f2
         _AUTOMOUNT_RESULT_INVALID = -1
8f24f2
 } AutomountResult;
8f24f2
diff --git a/src/core/path.c b/src/core/path.c
8f24f2
index c2facf0b16..bf7e1bf3c2 100644
8f24f2
--- a/src/core/path.c
8f24f2
+++ b/src/core/path.c
8f24f2
@@ -453,7 +453,7 @@ static void path_enter_dead(Path *p, PathResult f) {
8f24f2
         else
8f24f2
                 unit_log_failure(UNIT(p), path_result_to_string(p->result));
8f24f2
 
8f24f2
-        path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
8f24f2
+        path_set_state(p, p->result == PATH_SUCCESS ? PATH_DEAD : PATH_FAILED);
8f24f2
 }
8f24f2
 
8f24f2
 static void path_enter_running(Path *p) {
8f24f2
@@ -711,6 +711,11 @@ static void path_trigger_notify(Unit *u, Unit *other) {
8f24f2
                 return;
8f24f2
         }
8f24f2
 
8f24f2
+        if (unit_has_failed_condition_or_assert(other)) {
8f24f2
+                path_enter_dead(p, PATH_FAILURE_UNIT_CONDITION_FAILED);
8f24f2
+                return;
8f24f2
+        }
8f24f2
+
8f24f2
         /* Don't propagate anything if there's still a job queued */
8f24f2
         if (other->job)
8f24f2
                 return;
8f24f2
@@ -763,10 +768,11 @@ static const char* const path_type_table[_PATH_TYPE_MAX] = {
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
8f24f2
 
8f24f2
 static const char* const path_result_table[_PATH_RESULT_MAX] = {
8f24f2
-        [PATH_SUCCESS] = "success",
8f24f2
-        [PATH_FAILURE_RESOURCES] = "resources",
8f24f2
-        [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
8f24f2
-        [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
8f24f2
+        [PATH_SUCCESS]                       = "success",
8f24f2
+        [PATH_FAILURE_RESOURCES]             = "resources",
8f24f2
+        [PATH_FAILURE_START_LIMIT_HIT]       = "start-limit-hit",
8f24f2
+        [PATH_FAILURE_UNIT_START_LIMIT_HIT]  = "unit-start-limit-hit",
8f24f2
+        [PATH_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed",
8f24f2
 };
8f24f2
 
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
8f24f2
diff --git a/src/core/path.h b/src/core/path.h
8f24f2
index 8a69f06c13..0ad6bd12c6 100644
8f24f2
--- a/src/core/path.h
8f24f2
+++ b/src/core/path.h
8f24f2
@@ -46,6 +46,7 @@ typedef enum PathResult {
8f24f2
         PATH_FAILURE_RESOURCES,
8f24f2
         PATH_FAILURE_START_LIMIT_HIT,
8f24f2
         PATH_FAILURE_UNIT_START_LIMIT_HIT,
8f24f2
+        PATH_FAILURE_UNIT_CONDITION_FAILED,
8f24f2
         _PATH_RESULT_MAX,
8f24f2
         _PATH_RESULT_INVALID = -1
8f24f2
 } PathResult;
8f24f2
diff --git a/src/core/socket.c b/src/core/socket.c
8f24f2
index 74c1cc70cb..6f9a0f7575 100644
8f24f2
--- a/src/core/socket.c
8f24f2
+++ b/src/core/socket.c
8f24f2
@@ -2272,6 +2272,15 @@ static void socket_enter_running(Socket *s, int cfd) {
8f24f2
                 goto refuse;
8f24f2
         }
8f24f2
 
8f24f2
+        if (UNIT_ISSET(s->service) && cfd < 0) {
8f24f2
+                Unit *service = UNIT_DEREF(s->service);
8f24f2
+
8f24f2
+                if (unit_has_failed_condition_or_assert(service)) {
8f24f2
+                        socket_enter_dead(s, SOCKET_FAILURE_SERVICE_CONDITION_FAILED);
8f24f2
+                        return;
8f24f2
+                }
8f24f2
+        }
8f24f2
+
8f24f2
         if (cfd < 0) {
8f24f2
                 bool pending = false;
8f24f2
                 Unit *other;
8f24f2
@@ -3287,15 +3296,16 @@ static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
8f24f2
 
8f24f2
 static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
8f24f2
-        [SOCKET_SUCCESS] = "success",
8f24f2
-        [SOCKET_FAILURE_RESOURCES] = "resources",
8f24f2
-        [SOCKET_FAILURE_TIMEOUT] = "timeout",
8f24f2
-        [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
8f24f2
-        [SOCKET_FAILURE_SIGNAL] = "signal",
8f24f2
-        [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
8f24f2
-        [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
8f24f2
-        [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
8f24f2
-        [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
8f24f2
+        [SOCKET_SUCCESS]                          = "success",
8f24f2
+        [SOCKET_FAILURE_RESOURCES]                = "resources",
8f24f2
+        [SOCKET_FAILURE_TIMEOUT]                  = "timeout",
8f24f2
+        [SOCKET_FAILURE_EXIT_CODE]                = "exit-code",
8f24f2
+        [SOCKET_FAILURE_SIGNAL]                   = "signal",
8f24f2
+        [SOCKET_FAILURE_CORE_DUMP]                = "core-dump",
8f24f2
+        [SOCKET_FAILURE_START_LIMIT_HIT]          = "start-limit-hit",
8f24f2
+        [SOCKET_FAILURE_TRIGGER_LIMIT_HIT]        = "trigger-limit-hit",
8f24f2
+        [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT]  = "service-start-limit-hit",
8f24f2
+        [SOCKET_FAILURE_SERVICE_CONDITION_FAILED] = "service-condition-failed",
8f24f2
 };
8f24f2
 
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
8f24f2
diff --git a/src/core/socket.h b/src/core/socket.h
8f24f2
index 2409dbf2a0..b171b94316 100644
8f24f2
--- a/src/core/socket.h
8f24f2
+++ b/src/core/socket.h
8f24f2
@@ -39,6 +39,7 @@ typedef enum SocketResult {
8f24f2
         SOCKET_FAILURE_START_LIMIT_HIT,
8f24f2
         SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
8f24f2
         SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
8f24f2
+        SOCKET_FAILURE_SERVICE_CONDITION_FAILED,
8f24f2
         _SOCKET_RESULT_MAX,
8f24f2
         _SOCKET_RESULT_INVALID = -1
8f24f2
 } SocketResult;
8f24f2
diff --git a/src/core/timer.c b/src/core/timer.c
8f24f2
index 990f05fee4..3c8d89771d 100644
8f24f2
--- a/src/core/timer.c
8f24f2
+++ b/src/core/timer.c
8f24f2
@@ -567,6 +567,11 @@ static void timer_enter_running(Timer *t) {
8f24f2
                 return;
8f24f2
         }
8f24f2
 
8f24f2
+        if (unit_has_failed_condition_or_assert(trigger)) {
8f24f2
+                timer_enter_dead(t, TIMER_FAILURE_UNIT_CONDITION_FAILED);
8f24f2
+                return;
8f24f2
+        }
8f24f2
+
8f24f2
         r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
8f24f2
         if (r < 0)
8f24f2
                 goto fail;
8f24f2
@@ -850,9 +855,10 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = {
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
8f24f2
 
8f24f2
 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
8f24f2
-        [TIMER_SUCCESS] = "success",
8f24f2
-        [TIMER_FAILURE_RESOURCES] = "resources",
8f24f2
-        [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
8f24f2
+        [TIMER_SUCCESS]                       = "success",
8f24f2
+        [TIMER_FAILURE_RESOURCES]             = "resources",
8f24f2
+        [TIMER_FAILURE_START_LIMIT_HIT]       = "start-limit-hit",
8f24f2
+        [TIMER_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed",
8f24f2
 };
8f24f2
 
8f24f2
 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
8f24f2
diff --git a/src/core/timer.h b/src/core/timer.h
8f24f2
index 833aadb0b8..d23e19d622 100644
8f24f2
--- a/src/core/timer.h
8f24f2
+++ b/src/core/timer.h
8f24f2
@@ -32,6 +32,7 @@ typedef enum TimerResult {
8f24f2
         TIMER_SUCCESS,
8f24f2
         TIMER_FAILURE_RESOURCES,
8f24f2
         TIMER_FAILURE_START_LIMIT_HIT,
8f24f2
+        TIMER_FAILURE_UNIT_CONDITION_FAILED,
8f24f2
         _TIMER_RESULT_MAX,
8f24f2
         _TIMER_RESULT_INVALID = -1
8f24f2
 } TimerResult;
8f24f2
diff --git a/src/core/unit.c b/src/core/unit.c
8f24f2
index b825e2418c..c00d30e837 100644
8f24f2
--- a/src/core/unit.c
8f24f2
+++ b/src/core/unit.c
8f24f2
@@ -5657,6 +5657,16 @@ int unit_thaw_vtable_common(Unit *u) {
8f24f2
         return unit_cgroup_freezer_action(u, FREEZER_THAW);
8f24f2
 }
8f24f2
 
8f24f2
+bool unit_has_failed_condition_or_assert(Unit *u) {
8f24f2
+        if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result)
8f24f2
+                return true;
8f24f2
+
8f24f2
+        if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result)
8f24f2
+                return true;
8f24f2
+
8f24f2
+        return false;
8f24f2
+}
8f24f2
+
8f24f2
 static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
8f24f2
         [COLLECT_INACTIVE] = "inactive",
8f24f2
         [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
8f24f2
diff --git a/src/core/unit.h b/src/core/unit.h
8f24f2
index b8b914711f..a924bd2e83 100644
8f24f2
--- a/src/core/unit.h
8f24f2
+++ b/src/core/unit.h
8f24f2
@@ -847,6 +847,8 @@ void unit_thawed(Unit *u);
8f24f2
 int unit_freeze_vtable_common(Unit *u);
8f24f2
 int unit_thaw_vtable_common(Unit *u);
8f24f2
 
8f24f2
+bool unit_has_failed_condition_or_assert(Unit *u);
8f24f2
+
8f24f2
 /* Macros which append UNIT= or USER_UNIT= to the message */
8f24f2
 
8f24f2
 #define log_unit_full(unit, level, error, ...)                          \