Blob Blame History Raw
From cb0f29d437ded2557d8ae35970fdadf9da7392c1 Mon Sep 17 00:00:00 2001
From: David Vossel <dvossel@redhat.com>
Date: Fri, 6 Mar 2015 13:19:43 -0500
Subject: [PATCH] Fix: systemd: fix crash caused when canceling in-flight
 operation

---
 lib/services/dbus.c      |  8 ++++++--
 lib/services/pcmk-dbus.h |  3 ++-
 lib/services/systemd.c   | 21 +++++++++++++++++----
 lib/services/upstart.c   | 14 ++++++++++++--
 4 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/lib/services/dbus.c b/lib/services/dbus.c
index f44b590..637f749 100644
--- a/lib/services/dbus.c
+++ b/lib/services/dbus.c
@@ -325,7 +325,7 @@ pcmk_dbus_lookup_cb(DBusPendingCall *pending, void *user_data)
 char *
 pcmk_dbus_get_property(
     DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name,
-    void (*callback)(const char *name, const char *value, void *userdata), void *userdata)
+    void (*callback)(const char *name, const char *value, void *userdata), void *userdata, DBusPendingCall **pending)
 {
     DBusMessage *msg;
     const char *method = "GetAll";
@@ -365,7 +365,11 @@ pcmk_dbus_get_property(
     }
 
     if(query_data->callback) {
-        pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data);
+        DBusPendingCall* _pending;
+        _pending = pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data);
+        if (pending != NULL) {
+            *pending = _pending;
+        }
 
     } else {
         DBusMessage *reply = pcmk_dbus_send_recv(msg, connection, NULL);
diff --git a/lib/services/pcmk-dbus.h b/lib/services/pcmk-dbus.h
index 468020e..63910f6 100644
--- a/lib/services/pcmk-dbus.h
+++ b/lib/services/pcmk-dbus.h
@@ -8,7 +8,8 @@ DBusMessage *pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, D
 bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line);
 char *pcmk_dbus_get_property(
     DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name,
-    void (*callback)(const char *name, const char *value, void *userdata), void *userdata);
+    void (*callback)(const char *name, const char *value, void *userdata), void *userdata,
+    DBusPendingCall **pending);
 
 bool pcmk_dbus_find_error(const char *method, DBusPendingCall* pending, DBusMessage *reply, DBusError *error);
 
diff --git a/lib/services/systemd.c b/lib/services/systemd.c
index c0a1721..10c605a 100644
--- a/lib/services/systemd.c
+++ b/lib/services/systemd.c
@@ -363,7 +363,7 @@ systemd_unit_metadata(const char *name)
 
     if (path) {
         /* TODO: Worth a making blocking call for? Probably not. Possibly if cached. */
-        desc = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, path, BUS_NAME ".Unit", "Description", NULL, NULL);
+        desc = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, path, BUS_NAME ".Unit", "Description", NULL, NULL, NULL);
     } else {
         desc = g_strdup_printf("Systemd unit file for %s", name);
     }
@@ -499,6 +499,9 @@ systemd_unit_check(const char *name, const char *state, void *userdata)
     }
 
     if (op->synchronous == FALSE) {
+        if (op->opaque->pending) {
+            dbus_pending_call_unref(op->opaque->pending);
+        }
         op->opaque->pending = NULL;
         operation_finalize(op);
     }
@@ -521,14 +524,24 @@ systemd_unit_exec_with_unit(svc_action_t * op, const char *unit)
     }
 
     if (safe_str_eq(op->action, "monitor") || safe_str_eq(method, "status")) {
-        char *state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME ".Unit", "ActiveState",
-                                             op->synchronous?NULL:systemd_unit_check, op);
+        DBusPendingCall *pending = NULL;
+        char *state;
+
+        state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit,
+                                       BUS_NAME ".Unit", "ActiveState",
+                                       op->synchronous?NULL:systemd_unit_check,
+                                       op, op->synchronous?NULL:&pending);
         if (op->synchronous) {
             systemd_unit_check("ActiveState", state, op);
             free(state);
             return op->rc == PCMK_OCF_OK;
+        } else if (pending) {
+            dbus_pending_call_ref(pending);
+            op->opaque->pending = pending;
+            return TRUE;
         }
-        return TRUE;
+
+        return FALSE;
 
     } else if (g_strcmp0(method, "start") == 0) {
         FILE *file_strm = NULL;
diff --git a/lib/services/upstart.c b/lib/services/upstart.c
index 01ff817..9894430 100644
--- a/lib/services/upstart.c
+++ b/lib/services/upstart.c
@@ -322,6 +322,10 @@ upstart_job_check(const char *name, const char *state, void *userdata)
     }
 
     if (op->synchronous == FALSE) {
+        if (op->opaque->pending) {
+            dbus_pending_call_unref(op->opaque->pending);
+        }
+        op->opaque->pending = NULL;
         operation_finalize(op);
     }
 }
@@ -465,9 +469,11 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous)
 
         op->rc = PCMK_OCF_NOT_RUNNING;
         if(path) {
+            DBusPendingCall *pending = NULL;
             char *state = pcmk_dbus_get_property(
                 upstart_proxy, BUS_NAME, path, UPSTART_06_API ".Instance", "state",
-                op->synchronous?NULL:upstart_job_check, op);
+                op->synchronous?NULL:upstart_job_check, op,
+                op->synchronous?NULL:&pending);
 
             free(job);
             free(path);
@@ -476,8 +482,12 @@ upstart_job_exec(svc_action_t * op, gboolean synchronous)
                 upstart_job_check("state", state, op);
                 free(state);
                 return op->rc == PCMK_OCF_OK;
+            } else if (pending) {
+                dbus_pending_call_ref(pending);
+                op->opaque->pending = pending;
+                return TRUE;
             }
-            return TRUE;
+            return FALSE;
         }
         goto cleanup;
 
-- 
1.8.4.2