84b277
From 469d48cf685bd0157fa44ff7ebd3bd0302746ab0 Mon Sep 17 00:00:00 2001
84b277
From: Lennart Poettering <lennart@poettering.net>
84b277
Date: Mon, 18 Aug 2014 22:21:42 +0200
84b277
Subject: [PATCH] units: fix BindsTo= logic when applied relative to services
84b277
 with Type=oneshot
84b277
MIME-Version: 1.0
84b277
Content-Type: text/plain; charset=UTF-8
84b277
Content-Transfer-Encoding: 8bit
84b277
84b277
Start jobs for Type=oneshot units are successful when the unit state
84b277
transition activating → inactive took place. In such a case all units
84b277
that BindsTo= on it previously would continue to run, even though the unit
84b277
they dependet on was actually already gone.
84b277
84b277
(cherry-picked from ff50244582bf69e8489bba6ce59a21663d7f8274)
84b277
84b277
Resolves: #1147524
84b277
---
84b277
 src/core/unit.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----
84b277
 1 file changed, 44 insertions(+), 4 deletions(-)
84b277
84b277
diff --git a/src/core/unit.c b/src/core/unit.c
84b277
index b51e351..f221b9a 100644
84b277
--- a/src/core/unit.c
84b277
+++ b/src/core/unit.c
84b277
@@ -1302,12 +1302,44 @@ static void unit_check_unneeded(Unit *u) {
84b277
                 if (unit_active_or_pending(other))
84b277
                         return;
84b277
 
84b277
-        log_info_unit(u->id, "Service %s is not needed anymore. Stopping.", u->id);
84b277
+        log_info_unit(u->id, "Unit %s is not needed anymore. Stopping.", u->id);
84b277
 
84b277
         /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
84b277
         manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
84b277
 }
84b277
 
84b277
+static void unit_check_binds_to(Unit *u) {
84b277
+        bool stop = false;
84b277
+        Unit *other;
84b277
+        Iterator i;
84b277
+
84b277
+        assert(u);
84b277
+
84b277
+        if (u->job)
84b277
+                return;
84b277
+
84b277
+        if (unit_active_state(u) != UNIT_ACTIVE)
84b277
+                return;
84b277
+
84b277
+        SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) {
84b277
+                if (other->job)
84b277
+                        continue;
84b277
+
84b277
+                if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
84b277
+                        continue;
84b277
+
84b277
+                stop = true;
84b277
+        }
84b277
+
84b277
+        if (!stop)
84b277
+                return;
84b277
+
84b277
+        log_info_unit(u->id, "Unit %s is bound to inactive service. Stopping, too.", u->id);
84b277
+
84b277
+        /* A unit we need to run is gone. Sniff. Let's stop this. */
84b277
+        manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
84b277
+}
84b277
+
84b277
 static void retroactively_start_dependencies(Unit *u) {
84b277
         Iterator i;
84b277
         Unit *other;
84b277
@@ -1611,11 +1643,19 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
84b277
         manager_recheck_journal(m);
84b277
         unit_trigger_notify(u);
84b277
 
84b277
-        /* Maybe we finished startup and are now ready for being
84b277
-         * stopped because unneeded? */
84b277
-        if (u->manager->n_reloading <= 0)
84b277
+        if (u->manager->n_reloading <= 0) {
84b277
+                /* Maybe we finished startup and are now ready for
84b277
+                 * being stopped because unneeded? */
84b277
                 unit_check_unneeded(u);
84b277
 
84b277
+                /* Maybe we finished startup, but something we needed
84b277
+                 * has vanished? Let's die then. (This happens when
84b277
+                 * something BindsTo= to a Type=oneshot unit, as these
84b277
+                 * units go directly from starting to inactive,
84b277
+                 * without ever entering started.) */
84b277
+                unit_check_binds_to(u);
84b277
+        }
84b277
+
84b277
         unit_add_to_dbus_queue(u);
84b277
         unit_add_to_gc_queue(u);
84b277
 }