dd65c9
From d7b2f6efd02375af4cf043ef9db6d316b65d4779 Mon Sep 17 00:00:00 2001
dd65c9
From: Jan Synacek <jsynacek@redhat.com>
dd65c9
Date: Fri, 16 Feb 2018 09:56:50 +0100
dd65c9
Subject: [PATCH] core: don't choke if a unit another unit triggers vanishes
dd65c9
 during reload
dd65c9
dd65c9
Fixes: #1981
dd65c9
dd65c9
(cherry picked from e903182e5b0daa941de47a9c08c824106cec7fe0)
dd65c9
Resolves: #1545676
dd65c9
---
dd65c9
 src/core/automount.c | 25 +++++++++++++++++++++----
dd65c9
 src/core/path.c      | 18 +++++++++++++++---
dd65c9
 src/core/timer.c     | 30 ++++++++++++++++++++++++++----
dd65c9
 3 files changed, 62 insertions(+), 11 deletions(-)
dd65c9
dd65c9
diff --git a/src/core/automount.c b/src/core/automount.c
Pablo Greco 48fc63
index 182ba5240f..679fe071e7 100644
dd65c9
--- a/src/core/automount.c
dd65c9
+++ b/src/core/automount.c
dd65c9
@@ -715,6 +715,7 @@ static int automount_start_expire(Automount *a) {
dd65c9
 static void automount_enter_running(Automount *a) {
dd65c9
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
dd65c9
         struct stat st;
dd65c9
+        Unit *trigger;
dd65c9
         int r;
dd65c9
 
dd65c9
         assert(a);
dd65c9
@@ -753,8 +754,13 @@ static void automount_enter_running(Automount *a) {
dd65c9
                 return;
dd65c9
         }
dd65c9
 
dd65c9
-        r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
dd65c9
-                        JOB_REPLACE, true, &error, NULL);
dd65c9
+        trigger = UNIT_TRIGGER(UNIT(a));
dd65c9
+        if (!trigger) {
dd65c9
+                log_unit_error(UNIT(a)->id, "Unit to trigger vanished.");
dd65c9
+                goto fail;
dd65c9
+        }
dd65c9
+
dd65c9
+        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, true, &error, NULL);
dd65c9
         if (r < 0) {
dd65c9
                 log_unit_warning(UNIT(a)->id,
dd65c9
                                 "%s failed to queue mount startup job: %s",
dd65c9
@@ -775,6 +781,7 @@ fail:
dd65c9
 
dd65c9
 static int automount_start(Unit *u) {
dd65c9
         Automount *a = AUTOMOUNT(u);
dd65c9
+        Unit *trigger;
dd65c9
 
dd65c9
         assert(a);
dd65c9
         assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
dd65c9
@@ -786,8 +793,11 @@ static int automount_start(Unit *u) {
dd65c9
                 return -EEXIST;
dd65c9
         }
dd65c9
 
dd65c9
-        if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
dd65c9
+        trigger = UNIT_TRIGGER(u);
dd65c9
+        if (!trigger || trigger->load_state != UNIT_LOADED) {
dd65c9
+                log_unit_error(u->id, "Refusing to start, unit to trigger not loaded.");
dd65c9
                 return -ENOENT;
dd65c9
+        }
dd65c9
 
dd65c9
         a->result = AUTOMOUNT_SUCCESS;
dd65c9
         automount_enter_waiting(a);
dd65c9
@@ -936,6 +946,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
dd65c9
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
dd65c9
         union autofs_v5_packet_union packet;
dd65c9
         Automount *a = AUTOMOUNT(userdata);
dd65c9
+        Unit *trigger;
dd65c9
         ssize_t l;
dd65c9
         int r;
dd65c9
 
dd65c9
@@ -1002,7 +1013,13 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
dd65c9
                         log_unit_error_errno(UNIT(a)->id, r, "Failed to remember token: %m");
dd65c9
                         goto fail;
dd65c9
                 }
dd65c9
-                r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
dd65c9
+
dd65c9
+                trigger = UNIT_TRIGGER(UNIT(a));
dd65c9
+                if (!trigger) {
dd65c9
+                        log_unit_error(UNIT(a)->id, "Unit to trigger vanished.");
dd65c9
+                        goto fail;
dd65c9
+                }
dd65c9
+                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, true, &error, NULL);
dd65c9
                 if (r < 0) {
dd65c9
                         log_unit_warning(UNIT(a)->id,
dd65c9
                                          "%s failed to queue umount startup job: %s",
dd65c9
diff --git a/src/core/path.c b/src/core/path.c
Pablo Greco 48fc63
index 51e36fa8be..0533bb4e21 100644
dd65c9
--- a/src/core/path.c
dd65c9
+++ b/src/core/path.c
dd65c9
@@ -475,6 +475,7 @@ static void path_enter_dead(Path *p, PathResult f) {
dd65c9
 
dd65c9
 static void path_enter_running(Path *p) {
dd65c9
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
dd65c9
+        Unit *trigger;
dd65c9
         int r;
dd65c9
 
dd65c9
         assert(p);
dd65c9
@@ -483,8 +484,14 @@ static void path_enter_running(Path *p) {
dd65c9
         if (unit_stop_pending(UNIT(p)))
dd65c9
                 return;
dd65c9
 
dd65c9
-        r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
dd65c9
-                            JOB_REPLACE, true, &error, NULL);
dd65c9
+        trigger = UNIT_TRIGGER(UNIT(p));
dd65c9
+        if (!trigger) {
dd65c9
+                log_unit_error(UNIT(p)->id, "Unit to trigger vanished.");
dd65c9
+                path_enter_dead(p, TIMER_FAILURE_RESOURCES);
dd65c9
+                return;
dd65c9
+        }
dd65c9
+
dd65c9
+        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, true, &error, NULL);
dd65c9
         if (r < 0)
dd65c9
                 goto fail;
dd65c9
 
dd65c9
@@ -566,12 +573,17 @@ static void path_mkdir(Path *p) {
dd65c9
 
dd65c9
 static int path_start(Unit *u) {
dd65c9
         Path *p = PATH(u);
dd65c9
+        Unit *trigger;
dd65c9
 
dd65c9
         assert(p);
dd65c9
         assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
dd65c9
 
dd65c9
-        if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
dd65c9
+
dd65c9
+        trigger = UNIT_TRIGGER(u);
dd65c9
+        if (!trigger || trigger->load_state != UNIT_LOADED) {
dd65c9
+                log_unit_error(u->id, "Refusing to start, unit to trigger not loaded.");
dd65c9
                 return -ENOENT;
dd65c9
+        }
dd65c9
 
dd65c9
         path_mkdir(p);
dd65c9
 
dd65c9
diff --git a/src/core/timer.c b/src/core/timer.c
Pablo Greco 48fc63
index f318dc6f44..91d8db67e8 100644
dd65c9
--- a/src/core/timer.c
dd65c9
+++ b/src/core/timer.c
dd65c9
@@ -343,8 +343,18 @@ static void timer_enter_waiting(Timer *t, bool initial) {
dd65c9
         usec_t ts_realtime, ts_monotonic;
dd65c9
         usec_t base = 0;
dd65c9
         TimerValue *v;
dd65c9
+        Unit *trigger;
dd65c9
         int r;
dd65c9
 
dd65c9
+        assert(t);
dd65c9
+
dd65c9
+        trigger = UNIT_TRIGGER(UNIT(t));
dd65c9
+        if (!trigger) {
dd65c9
+                log_unit_error(UNIT(t)->id, "Unit to trigger vanished.");
dd65c9
+                timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
dd65c9
+                return;
dd65c9
+        }
dd65c9
+
dd65c9
         /* If we shall wake the system we use the boottime clock
dd65c9
          * rather than the monotonic clock. */
dd65c9
 
dd65c9
@@ -399,7 +409,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
dd65c9
 
dd65c9
                         case TIMER_UNIT_ACTIVE:
dd65c9
 
dd65c9
-                                base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
dd65c9
+                                base = trigger->inactive_exit_timestamp.monotonic;
dd65c9
 
dd65c9
                                 if (base <= 0)
dd65c9
                                         base = t->last_trigger.monotonic;
dd65c9
@@ -523,6 +533,7 @@ fail:
dd65c9
 
dd65c9
 static void timer_enter_running(Timer *t) {
dd65c9
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
dd65c9
+        Unit *trigger;
dd65c9
         int r;
dd65c9
 
dd65c9
         assert(t);
dd65c9
@@ -531,8 +542,15 @@ static void timer_enter_running(Timer *t) {
dd65c9
         if (unit_stop_pending(UNIT(t)))
dd65c9
                 return;
dd65c9
 
dd65c9
-        r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
dd65c9
-                            JOB_REPLACE, true, &error, NULL);
dd65c9
+
dd65c9
+        trigger = UNIT_TRIGGER(UNIT(t));
dd65c9
+        if (!trigger) {
dd65c9
+                log_unit_error(UNIT(t)->id, "Unit to trigger vanished.");
dd65c9
+                timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
dd65c9
+                return;
dd65c9
+        }
dd65c9
+
dd65c9
+        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, true, &error, NULL);
dd65c9
         if (r < 0)
dd65c9
                 goto fail;
dd65c9
 
dd65c9
@@ -554,12 +572,16 @@ fail:
dd65c9
 static int timer_start(Unit *u) {
dd65c9
         Timer *t = TIMER(u);
dd65c9
         TimerValue *v;
dd65c9
+        Unit *trigger;
dd65c9
 
dd65c9
         assert(t);
dd65c9
         assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
dd65c9
 
dd65c9
-        if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
dd65c9
+        trigger = UNIT_TRIGGER(u);
dd65c9
+        if (!trigger || trigger->load_state != UNIT_LOADED) {
dd65c9
+                log_unit_error(u->id, "Refusing to start, unit to trigger not loaded.");
dd65c9
                 return -ENOENT;
dd65c9
+        }
dd65c9
 
dd65c9
         t->last_trigger = DUAL_TIMESTAMP_NULL;
dd65c9