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