From cb0f29d437ded2557d8ae35970fdadf9da7392c1 Mon Sep 17 00:00:00 2001 From: David Vossel 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