diff --git a/include/crm/services.h b/include/crm/services.h
index e8bc172256..5310709e1b 100644
--- a/include/crm/services.h
+++ b/include/crm/services.h
@@ -1,363 +1,364 @@
 /*
  * Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /**
  * \file
  * \brief Services API
  * \ingroup core
  */
 
 #ifndef __PCMK_SERVICES__
 #  define __PCMK_SERVICES__
 
 #  ifdef __cplusplus
 extern "C" {
 #  endif
 
 #  include <glib.h>
 #  include <stdio.h>
 #  include <string.h>
 #  include <stdbool.h>
 
 #  ifndef OCF_ROOT_DIR
 #    define OCF_ROOT_DIR "/usr/lib/ocf"
 #  endif
 
 #  ifndef LSB_ROOT_DIR
 #    define LSB_ROOT_DIR "/etc/init.d"
 #  endif
 
 /* TODO: Autodetect these two ?*/
 #  ifndef SYSTEMCTL
 #    define SYSTEMCTL "/bin/systemctl"
 #  endif
 
 #  ifndef SERVICE_SCRIPT
 #    define SERVICE_SCRIPT "/sbin/service"
 #  endif
 
 
 /* This is the string passed in the OCF_EXIT_REASON_PREFIX
  * environment variable. The stderr output that occurs
  * after this prefix is encountered is considered the exit
  * reason for a completed operationt */
 #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:"
 
 /* *INDENT-OFF* */
 enum lsb_exitcode {
     PCMK_LSB_OK                  = 0,
     PCMK_LSB_UNKNOWN_ERROR       = 1,
     PCMK_LSB_INVALID_PARAM       = 2,
     PCMK_LSB_UNIMPLEMENT_FEATURE = 3,
     PCMK_LSB_INSUFFICIENT_PRIV   = 4,
     PCMK_LSB_NOT_INSTALLED       = 5,
     PCMK_LSB_NOT_CONFIGURED      = 6,
     PCMK_LSB_NOT_RUNNING         = 7,
 };
 
 /* The return codes for the status operation are not the same for other
  * operatios - go figure
  */
 enum lsb_status_exitcode {
     PCMK_LSB_STATUS_OK             = 0,
     PCMK_LSB_STATUS_VAR_PID        = 1,
     PCMK_LSB_STATUS_VAR_LOCK       = 2,
     PCMK_LSB_STATUS_NOT_RUNNING    = 3,
     PCMK_LSB_STATUS_NOT_INSTALLED  = 4,
 };
 
 /* Uniform exit codes
  * Everything is mapped to its OCF equivalent so that Pacemaker only deals with one set of codes
  */
 enum ocf_exitcode {
     PCMK_OCF_OK                   = 0,
     PCMK_OCF_UNKNOWN_ERROR        = 1,
     PCMK_OCF_INVALID_PARAM        = 2,
     PCMK_OCF_UNIMPLEMENT_FEATURE  = 3,
     PCMK_OCF_INSUFFICIENT_PRIV    = 4,
     PCMK_OCF_NOT_INSTALLED        = 5,
     PCMK_OCF_NOT_CONFIGURED       = 6,
     PCMK_OCF_NOT_RUNNING          = 7,  /* End of overlap with LSB */
     PCMK_OCF_RUNNING_MASTER       = 8,
     PCMK_OCF_FAILED_MASTER        = 9,
 
 
     /* 150-199	reserved for application use */
     PCMK_OCF_EXEC_ERROR    = 192, /* Generic problem invoking the agent */
     PCMK_OCF_UNKNOWN       = 193, /* State of the service is unknown - used for recording in-flight operations */
     PCMK_OCF_SIGNAL        = 194,
     PCMK_OCF_NOT_SUPPORTED = 195,
     PCMK_OCF_PENDING       = 196,
     PCMK_OCF_CANCELLED     = 197,
     PCMK_OCF_TIMEOUT       = 198,
     PCMK_OCF_OTHER_ERROR   = 199, /* Keep the same codes as PCMK_LSB */
 };
 
 enum op_status {
     PCMK_LRM_OP_PENDING = -1,
     PCMK_LRM_OP_DONE,
     PCMK_LRM_OP_CANCELLED,
     PCMK_LRM_OP_TIMEOUT,
     PCMK_LRM_OP_NOTSUPPORTED,
     PCMK_LRM_OP_ERROR,
     PCMK_LRM_OP_ERROR_HARD,
     PCMK_LRM_OP_ERROR_FATAL,
     PCMK_LRM_OP_NOT_INSTALLED,
 };
 
 enum nagios_exitcode {
     NAGIOS_STATE_OK        = 0,
     NAGIOS_STATE_WARNING   = 1,
     NAGIOS_STATE_CRITICAL  = 2,
     NAGIOS_STATE_UNKNOWN   = 3,
     NAGIOS_STATE_DEPENDENT = 4,
 
     NAGIOS_INSUFFICIENT_PRIV = 100,
     NAGIOS_NOT_INSTALLED     = 101,
 };
 /* *INDENT-ON* */
 
     typedef struct svc_action_private_s svc_action_private_t;
     typedef struct svc_action_s {
         char *id;
         char *rsc;
         char *action;
         int interval;
 
         char *standard;
         char *provider;
         char *agent;
 
         int timeout;
         GHashTable *params;
 
         int rc;
         int pid;
         int cancel;
         int status;
         int sequence;
         int expected_rc;
+        int synchronous;
 
         char *stderr_data;
         char *stdout_data;
 
     /**
      * Data stored by the creator of the action.
      *
      * This may be used to hold data that is needed later on by a callback,
      * for example.
      */
         void *cb_data;
 
         svc_action_private_t *opaque;
 
     } svc_action_t;
 
 /**
  * Get a list of files or directories in a given path
  *
  * \param[in] root full path to a directory to read
  * \param[in] files true to get a list of files, false for a list of directories
  *
  * \return a list of what was found.  The list items are gchar *.  This list _must_
  *         be destroyed using g_list_free_full(list, free).
  */
     GList *get_directory_list(const char *root, gboolean files, gboolean executable);
 
 /**
  * Get a list of services
  *
  * \return a list of services.  The list items are gchar *.  This list _must_
  *         be destroyed using g_list_free_full(list, free).
  */
     GList *services_list(void);
 
 /**
  * Get a list of providers
  *
  * \param[in] the standard for providers to check for (such as "ocf")
  *
  * \return a list of providers.  The list items are gchar *.  This list _must_
  *         be destroyed using g_list_free_full(list, free).
  */
     GList *resources_list_providers(const char *standard);
 
 /**
  * Get a list of resource agents
  *
  * \param[in] the standard for research agents to check for
  *            (such as "ocf", "lsb", or "windows")
  *
  * \return a list of resource agents.  The list items are gchar *.  This list _must_
  *         be destroyed using g_list_free_full(list, free).
  */
     GList *resources_list_agents(const char *standard, const char *provider);
 
 /**
  * Get list of available standards
  *
  * \return a list of resource standards. The list items are char *. This list _must_
  *         be destroyed using g_list_free_full(list, free).
  */
     GList *resources_list_standards(void);
 
     svc_action_t *services_action_create(const char *name, const char *action,
                                          int interval /* ms */ , int timeout /* ms */ );
 
 /**
  * Create a resources action.
  *
  * \param[in] timeout the timeout in milliseconds
  * \param[in] interval how often to repeat this action, in milliseconds.
  *            If this value is 0, only execute this action one time.
  *
  * \post After the call, 'params' is owned, and later free'd by the svc_action_t result
  */
     svc_action_t *resources_action_create(const char *name, const char *standard,
                                           const char *provider, const char *agent,
                                           const char *action, int interval /* ms */ ,
                                           int timeout /* ms */ , GHashTable * params);
 
 /**
  * Kick a recurring action so it is scheduled immediately for re-execution
  */
     gboolean services_action_kick(const char *name, const char *action, int interval /* ms */);
 
 /**
  * Find the first class that can provide service::${agent}
  *
  * \param[in] agent which agent to search for
  * \return NULL, or the first class that provides the named agent
  */
     const char *resources_find_service_class(const char *agent);
 
 /**
  * Utilize services API to execute an arbitrary command.
  *
  * This API has useful infrastructure in place to be able to run a command
  * in the background and get notified via a callback when the command finishes.
  *
  * \param[in] exec command to execute
  * \param[in] args arguments to the command, NULL terminated
  *
  * \return a svc_action_t object, used to pass to the execute function
  * (services_action_sync() or services_action_async()) and is
  * provided to the callback.
  */
     svc_action_t *services_action_create_generic(const char *exec, const char *args[]);
 
     void
      services_action_free(svc_action_t * op);
 
     gboolean services_action_sync(svc_action_t * op);
 
 /**
  * Run an action asynchronously.
  *
  * \param[in] op services action data
  * \param[in] action_callback callback for when the action completes
  *
  * \retval TRUE succesfully started execution
  * \retval FALSE failed to start execution, no callback will be received
  */
     gboolean services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *));
 
     gboolean services_action_cancel(const char *name, const char *action, int interval);
 
     static inline const char *services_lrm_status_str(enum op_status status) {
         switch (status) {
             case PCMK_LRM_OP_PENDING:
                 return "pending";
                 case PCMK_LRM_OP_DONE:return "complete";
                 case PCMK_LRM_OP_CANCELLED:return "Cancelled";
                 case PCMK_LRM_OP_TIMEOUT:return "Timed Out";
                 case PCMK_LRM_OP_NOTSUPPORTED:return "NOT SUPPORTED";
                 case PCMK_LRM_OP_ERROR:return "Error";
                 case PCMK_LRM_OP_NOT_INSTALLED:return "Not installed";
                 default:return "UNKNOWN!";
     }} static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) {
         switch (code) {
             case PCMK_OCF_OK:
                 return "ok";
             case PCMK_OCF_UNKNOWN_ERROR:
                 return "unknown error";
             case PCMK_OCF_INVALID_PARAM:
                 return "invalid parameter";
             case PCMK_OCF_UNIMPLEMENT_FEATURE:
                 return "unimplemented feature";
             case PCMK_OCF_INSUFFICIENT_PRIV:
                 return "insufficient privileges";
             case PCMK_OCF_NOT_INSTALLED:
                 return "not installed";
             case PCMK_OCF_NOT_CONFIGURED:
                 return "not configured";
             case PCMK_OCF_NOT_RUNNING:
                 return "not running";
             case PCMK_OCF_RUNNING_MASTER:
                 return "master";
             case PCMK_OCF_FAILED_MASTER:
                 return "master (failed)";
             case PCMK_OCF_SIGNAL:
                 return "OCF_SIGNAL";
             case PCMK_OCF_NOT_SUPPORTED:
                 return "OCF_NOT_SUPPORTED";
             case PCMK_OCF_PENDING:
                 return "OCF_PENDING";
             case PCMK_OCF_CANCELLED:
                 return "OCF_CANCELLED";
             case PCMK_OCF_TIMEOUT:
                 return "OCF_TIMEOUT";
             case PCMK_OCF_OTHER_ERROR:
                 return "OCF_OTHER_ERROR";
             default:
                 return "unknown";
         }
     }
 
     static inline enum ocf_exitcode
      services_get_ocf_exitcode(char *action, int lsb_exitcode) {
         if (action != NULL && strcmp("status", action) == 0) {
             switch (lsb_exitcode) {
                 case PCMK_LSB_STATUS_OK:
                     return PCMK_OCF_OK;
                 case PCMK_LSB_STATUS_VAR_PID:
                     return PCMK_OCF_NOT_RUNNING;
                 case PCMK_LSB_STATUS_VAR_LOCK:
                     return PCMK_OCF_NOT_RUNNING;
                 case PCMK_LSB_STATUS_NOT_RUNNING:
                     return PCMK_OCF_NOT_RUNNING;
                 case PCMK_LSB_STATUS_NOT_INSTALLED:
                     return PCMK_OCF_UNKNOWN_ERROR;
                 default:
                     return PCMK_OCF_UNKNOWN_ERROR;
             }
 
         } else if (lsb_exitcode > PCMK_LSB_NOT_RUNNING) {
             return PCMK_OCF_UNKNOWN_ERROR;
         }
 
         /* For non-status operations, the PCMK_LSB and PCMK_OCF share error code meaning
          * for rc <= 7 */
         return (enum ocf_exitcode)lsb_exitcode;
     }
 
 #  ifdef __cplusplus
 }
 #  endif
 
 #endif                          /* __PCMK_SERVICES__ */
diff --git a/lib/services/dbus.c b/lib/services/dbus.c
index 8b8aee1e42..fdcbc01daa 100644
--- a/lib/services/dbus.c
+++ b/lib/services/dbus.c
@@ -1,411 +1,454 @@
 #include <crm_internal.h>
 #include <crm/crm.h>
 #include <crm/services.h>
 #include <dbus/dbus.h>
 #include <pcmk-dbus.h>
 
 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
 
+struct db_query
+{
+        char *target;
+        char *object;
+        char *name;
+};
 
 static bool pcmk_dbus_error_check(DBusError *err, const char *prefix, const char *function, int line) 
 {
     if (err && dbus_error_is_set(err)) {
         do_crm_log_alias(LOG_ERR, __FILE__, function, line, "%s: DBus error '%s'", prefix, err->message);
         dbus_error_free(err);
         return TRUE;
     }
     return FALSE;
 }
 
 DBusConnection *pcmk_dbus_connect(void)
 {
     DBusError err;
     DBusConnection *connection;
 
     dbus_error_init(&err);
     connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
     if(pcmk_dbus_error_check(&err, "Could not connect to System DBus", __FUNCTION__, __LINE__)) {
         return NULL;
     }
 
     if(connection) {
         pcmk_dbus_connection_setup_with_select(connection);
     }
     return connection;
 }
 
 void pcmk_dbus_disconnect(DBusConnection *connection)
 {
 }
 
 bool
 pcmk_dbus_find_error(const char *method, DBusPendingCall* pending, DBusMessage *reply, DBusError *ret)
 {
     DBusError error;
 
     dbus_error_init(&error);
 
     if(pending == NULL) {
         error.name = "org.clusterlabs.pacemaker.NoRequest";
         error.message = "No request sent";
 
     } else if(reply == NULL) {
         error.name = "org.clusterlabs.pacemaker.NoReply";
         error.message = "No reply";
 
     } else {
         DBusMessageIter args;
         int dtype = dbus_message_get_type(reply);
 
         switch(dtype) {
             case DBUS_MESSAGE_TYPE_METHOD_RETURN:
                 dbus_message_iter_init(reply, &args);
                 crm_trace("Call to %s returned '%s'", method, dbus_message_iter_get_signature(&args));
                 break;
             case DBUS_MESSAGE_TYPE_INVALID:
                 error.message = "Invalid reply";
                 error.name = "org.clusterlabs.pacemaker.InvalidReply";
                 crm_err("Error processing %s response: %s", method, error.message);
                 break;
             case DBUS_MESSAGE_TYPE_METHOD_CALL:
                 error.message = "Invalid reply (method call)";
                 error.name = "org.clusterlabs.pacemaker.InvalidReply.Method";
                 crm_err("Error processing %s response: %s", method, error.message);
                 break;
             case DBUS_MESSAGE_TYPE_SIGNAL:
                 error.message = "Invalid reply (signal)";
                 error.name = "org.clusterlabs.pacemaker.InvalidReply.Signal";
                 crm_err("Error processing %s response: %s", method, error.message);
                 break;
 
             case DBUS_MESSAGE_TYPE_ERROR:
                 dbus_set_error_from_message (&error, reply);
                 crm_info("%s error '%s': %s", method, error.name, error.message);
                 break;
             default:
                 error.message = "Unknown reply type";
                 error.name = "org.clusterlabs.pacemaker.InvalidReply.Type";
                 crm_err("Error processing %s response: %s (%d)", method, error.message, dtype);
         }
     }
 
     if(ret && (error.name || error.message)) {
         *ret = error;
         return TRUE;
     }
 
     return FALSE;
 }
 
 DBusMessage *pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error)
 {
     const char *method = NULL;
     DBusMessage *reply = NULL;
     DBusPendingCall* pending = NULL;
 
     CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
     method = dbus_message_get_member (msg);
 
     // send message and get a handle for a reply
     if (!dbus_connection_send_with_reply (connection, msg, &pending, -1)) { // -1 is default timeout
         if(error) {
+            dbus_error_init(error);
             error->message = "Call to dbus_connection_send_with_reply() failed";
             error->name = "org.clusterlabs.pacemaker.SendFailed";
         }
         crm_err("Error sending %s request", method);
         return NULL;
     }
 
     dbus_connection_flush(connection);
 
     if(pending) {
         /* block until we receive a reply */
         dbus_pending_call_block(pending);
 
         /* get the reply message */
         reply = dbus_pending_call_steal_reply(pending);
     }
 
-    if(pcmk_dbus_find_error(method, pending, reply, error)) {
-        crm_trace("Was error: '%s' '%s'", error->name, error->message);
-        if(reply) {
-            dbus_message_unref(reply);
-            reply = NULL;
-        }
-    }
+    pcmk_dbus_find_error(method, pending, reply, error);
 
     if(pending) {
         /* free the pending message handle */
         dbus_pending_call_unref(pending);
     }
 
     return reply;
 }
 
 bool pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection,
                     void(*done)(DBusPendingCall *pending, void *user_data), void *user_data)
 {
     DBusError error;
     const char *method = NULL;
     DBusPendingCall* pending = NULL;
 
     dbus_error_init(&error);
 
     CRM_ASSERT(done);
     CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
     method = dbus_message_get_member (msg);
 
     // send message and get a handle for a reply
     if (!dbus_connection_send_with_reply (connection, msg, &pending, -1)) { // -1 is default timeout
         crm_err("Send with reply failed for %s", method);
         return FALSE;
 
     } else if (pending == NULL) {
         crm_err("No pending call found for %s", method);
         return FALSE;
 
     }
 
     if (dbus_pending_call_get_completed(pending)) {
         crm_info("DBus %s call completed too soon");
 #if 1
         /* This sounds like a good idea, but allegedly it breaks things */
         done(pending, user_data);
 #else
         CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
 #endif
 
     } else {
         CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
     }
     return TRUE;
 }
 
 bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
 {
     int dtype = 0;
     DBusMessageIter lfield;
 
     if(field == NULL) {
         if(dbus_message_iter_init(msg, &lfield)) {
             field = &lfield;
         }
     }
 
     if(field == NULL) {
         do_crm_log_alias(LOG_ERR, __FILE__, function, line,
                          "Empty parameter list in reply expecting '%c'", expected);
         return FALSE;
     }
 
     dtype = dbus_message_iter_get_arg_type(field);
 
     if(dtype != expected) {
         DBusMessageIter args;
 
         dbus_message_iter_init(msg, &args);
         do_crm_log_alias(LOG_ERR, __FILE__, function, line,
                          "Unexepcted DBus type, expected %c instead of %c in '%s'",
                          expected, dtype, dbus_message_iter_get_signature(&args));
         return FALSE;
     }
 
     return TRUE;
 }
 
-char *
-pcmk_dbus_get_property(
-    DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name)
+static char *
+pcmk_dbus_lookup_result(DBusMessage *reply, struct db_query *data)
 {
-    DBusMessage *msg;
-    DBusMessageIter args;
-    DBusMessageIter dict;
-    DBusMessage *reply = NULL;
-    /* DBusBasicValue value; */
-    const char *method = "GetAll";
-    char *output = NULL;
     DBusError error;
+    char *output = NULL;
+    DBusMessageIter dict;
+    DBusMessageIter args;
 
-        /* desc = systemd_unit_property(path, BUS_NAME ".Unit", "Description"); */
-
-    dbus_error_init(&error);
-    crm_info("Calling: %s on %s", method, target);
-    msg = dbus_message_new_method_call(target, // target for the method call
-                                       obj, // object to call on
-                                       BUS_PROPERTY_IFACE, // interface to call on
-                                       method); // method name
-
-    if (NULL == msg) {
-        crm_err("Call to %s failed: No message", method);
-        return NULL;
-    }
-
-    CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
-
-    reply = pcmk_dbus_send_recv(msg, connection, &error);
-    dbus_message_unref(msg);
-
-    if(error.name) {
-        crm_err("Call to %s for %s failed: No reply", method, iface);
-        return NULL;
-
-    } else if (!dbus_message_iter_init(reply, &args)) {
-        crm_err("Cannot get properties for %s from %s", obj, iface);
-        return NULL;
+    if(pcmk_dbus_find_error("GetAll", (void*)&error, reply, &error)) {
+        crm_err("Cannot get properties from %s for %s", data->target, data->object);
+        goto cleanup;
     }
 
+    dbus_message_iter_init(reply, &args);
     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
-        crm_err("Call to %s failed: Message has invalid arguments", method);
-        dbus_message_unref(reply);
-        return NULL;
+        crm_err("Invalid reply from %s for %s", data->target, data->object);
+        goto cleanup;
     }
 
     dbus_message_iter_recurse(&args, &dict);
     while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
         DBusMessageIter sv;
         DBusMessageIter v;
         DBusBasicValue value;
 
         if(!pcmk_dbus_type_check(reply, &dict, DBUS_TYPE_DICT_ENTRY, __FUNCTION__, __LINE__)) {
             dbus_message_iter_next (&dict);
             continue;
         }
 
         dbus_message_iter_recurse(&dict, &sv);
         while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
             int dtype = dbus_message_iter_get_arg_type(&sv);
 
             switch(dtype) {
                 case DBUS_TYPE_STRING:
                     dbus_message_iter_get_basic(&sv, &value);
 
                     crm_trace("Got: %s", value.str);
-                    if(strcmp(value.str, name) != 0) {
+                    if(strcmp(value.str, data->name) != 0) {
                         dbus_message_iter_next (&sv); /* Skip the value */
                     }
                     break;
                 case DBUS_TYPE_VARIANT:
                     dbus_message_iter_recurse(&sv, &v);
                     if(pcmk_dbus_type_check(reply, &v, DBUS_TYPE_STRING, __FUNCTION__, __LINE__)) {
                         dbus_message_iter_get_basic(&v, &value);
 
                         crm_trace("Result: %s", value.str);
                         output = strdup(value.str);
                     }
                     break;
                 default:
                     pcmk_dbus_type_check(reply, &sv, DBUS_TYPE_STRING, __FUNCTION__, __LINE__);
             }
             dbus_message_iter_next (&sv);
         }
 
         dbus_message_iter_next (&dict);
     }
 
 
-    crm_trace("Property %s[%s] is '%s'", obj, name, output);
+    crm_trace("Property %s[%s] is '%s'", data->object, data->name, output);
+
+  cleanup:
+    free(data->target);
+    free(data->object);
+    free(data->name);
+    free(data);
+
+    return output;
+}
+
+static void
+pcmk_dbus_lookup_cb(DBusPendingCall *pending, void *user_data)
+{
+    DBusMessage *reply = NULL;
+
+    if(pending) {
+        reply = dbus_pending_call_steal_reply(pending);
+    }
+
+    pcmk_dbus_lookup_result(reply, user_data);
+
+    if(reply) {
+        dbus_message_unref(reply);
+    }
+}
+
+char *
+pcmk_dbus_get_property(
+    DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name)
+{
+    DBusMessage *msg;
+    DBusMessage *reply;
+    const char *method = "GetAll";
+    char *output = NULL;
+
+    struct db_query *query_data = NULL;
+
+    /* char *state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME ".Unit", "ActiveState"); */
+
+    crm_debug("Calling: %s on %s", method, target);
+    msg = dbus_message_new_method_call(target, // target for the method call
+                                       obj, // object to call on
+                                       BUS_PROPERTY_IFACE, // interface to call on
+                                       method); // method name
+
+    if (NULL == msg) {
+        crm_err("Call to %s failed: No message", method);
+        return NULL;
+    }
+
+    CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
+
+    query_data = malloc(sizeof(struct db_query));
+    query_data->target = strdup(target);
+    query_data->object = strdup(obj);
+    query_data->name = strdup(name);
+
+    if(/* callback */FALSE) {
+        pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data);
+
+    } else {
+        reply = pcmk_dbus_send_recv(msg, connection, NULL);
+        output = pcmk_dbus_lookup_result(reply, query_data);
+    }
+
+    dbus_message_unref(msg);
+
+    if(reply) {
+        dbus_message_unref(reply);
+    }
     return output;
 }
 
 static void pcmk_dbus_connection_dispatch(DBusConnection *connection, DBusDispatchStatus new_status, void *data){
     crm_trace("status %d for %p", new_status, data);
     if (new_status == DBUS_DISPATCH_DATA_REMAINS){
         dbus_connection_dispatch(connection);
     }
 }
 
 static int
 pcmk_dbus_watch_dispatch(gpointer userdata)
 {
     DBusWatch *watch = userdata;
     int flags = dbus_watch_get_flags(watch);
 
     crm_trace("Dispatching %p with flags %d", watch, flags);
     if(flags & DBUS_WATCH_READABLE) {
         dbus_watch_handle(watch, DBUS_WATCH_READABLE);
     } else {
         dbus_watch_handle(watch, DBUS_WATCH_ERROR);
     }
     return 0;
 }
 
 static void
 pcmk_dbus_watch_destroy(gpointer userdata)
 {
     crm_trace("Destroyed %p", userdata);
 }
 
 
 struct mainloop_fd_callbacks pcmk_dbus_cb = {
     .dispatch = pcmk_dbus_watch_dispatch,
     .destroy = pcmk_dbus_watch_destroy,
 };
 
 static dbus_bool_t
 pcmk_dbus_watch_add(DBusWatch *watch, void *data){
     int fd = dbus_watch_get_unix_fd(watch);
 
     mainloop_io_t *client = mainloop_add_fd(
         "dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
 
     crm_trace("Added %p with fd=%d", watch, fd);
     dbus_watch_set_data(watch, client, NULL);
     return TRUE;
 }
 
 static void
 pcmk_dbus_watch_remove(DBusWatch *watch, void *data){
     mainloop_io_t *client = dbus_watch_get_data(watch);
 
     crm_trace("Removed %p", watch);
     mainloop_del_fd(client);
 }
 
 static gboolean
 pcmk_dbus_timeout_dispatch(gpointer data)
 {
     crm_trace("Timeout for %p");
     dbus_timeout_handle(data);
     return FALSE;
 }
 
 static dbus_bool_t
 pcmk_dbus_timeout_add(DBusTimeout *timeout, void *data){
     guint id = g_timeout_add(dbus_timeout_get_interval(timeout), pcmk_dbus_timeout_dispatch, timeout);
 
     if(id) {
         dbus_timeout_set_data(timeout, GUINT_TO_POINTER(id), NULL);
     }
     return TRUE;
 }
 
 static void
 pcmk_dbus_timeout_remove(DBusTimeout *timeout, void *data){
     void *vid = dbus_timeout_get_data(timeout);
     guint id = GPOINTER_TO_UINT(vid);
 
     if(id) {
         g_source_remove(id);
         dbus_timeout_set_data(timeout, 0, NULL);
     }
 }
 
 static void
 pcmk_dbus_timeout_toggle(DBusTimeout *timeout, void *data){
     if(dbus_timeout_get_enabled(timeout)) {
         pcmk_dbus_timeout_add(timeout, data);
     } else {
         pcmk_dbus_timeout_remove(timeout, data);
     }
 }
 
 /* Inspired by http://www.kolej.mff.cuni.cz/~vesej3am/devel/dbus-select.c */
 
 void pcmk_dbus_connection_setup_with_select(DBusConnection *c){
 	dbus_connection_set_timeout_functions(
             c, pcmk_dbus_timeout_add, pcmk_dbus_timeout_remove, pcmk_dbus_timeout_toggle, NULL, NULL);
 	dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add, pcmk_dbus_watch_remove, NULL, NULL, NULL);
 	dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch, NULL, NULL);
 
 	pcmk_dbus_connection_dispatch(c, dbus_connection_get_dispatch_status(c), NULL);
 }
diff --git a/lib/services/services.c b/lib/services/services.c
index 7b32405d3e..8590b56427 100644
--- a/lib/services/services.c
+++ b/lib/services/services.c
@@ -1,645 +1,647 @@
 /*
  * Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <crm_internal.h>
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdio.h>
 
 #include <errno.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <fcntl.h>
 
 #include <crm/crm.h>
 #include <crm/common/mainloop.h>
 #include <crm/services.h>
 #include <crm/msg_xml.h>
 #include "services_private.h"
 
 #if SUPPORT_UPSTART
 #  include <upstart.h>
 #endif
 
 #if SUPPORT_SYSTEMD
 #  include <systemd.h>
 #endif
 
 /* TODO: Develop a rollover strategy */
 
 static int operations = 0;
 GHashTable *recurring_actions = NULL;
 
 svc_action_t *
 services_action_create(const char *name, const char *action, int interval, int timeout)
 {
     return resources_action_create(name, "lsb", NULL, name, action, interval, timeout, NULL);
 }
 
 const char *
 resources_find_service_class(const char *agent)
 {
     /* Priority is:
      * - lsb
      * - systemd
      * - upstart
      */
     int rc = 0;
     struct stat st;
     char *path = NULL;
 
 #ifdef LSB_ROOT_DIR
     rc = asprintf(&path, "%s/%s", LSB_ROOT_DIR, agent);
     if (rc > 0 && stat(path, &st) == 0) {
         free(path);
         return "lsb";
     }
     free(path);
 #endif
 
 #if SUPPORT_SYSTEMD
     if (systemd_unit_exists(agent)) {
         return "systemd";
     }
 #endif
 
 #if SUPPORT_UPSTART
     if (upstart_job_exists(agent)) {
         return "upstart";
     }
 #endif
     return NULL;
 }
 
 
 svc_action_t *
 resources_action_create(const char *name, const char *standard, const char *provider,
                         const char *agent, const char *action, int interval, int timeout,
                         GHashTable * params)
 {
     svc_action_t *op = NULL;
 
     /*
      * Do some up front sanity checks before we go off and
      * build the svc_action_t instance.
      */
 
     if (crm_strlen_zero(name)) {
         crm_err("A service or resource action must have a name.");
         goto return_error;
     }
 
     if (crm_strlen_zero(standard)) {
         crm_err("A service action must have a valid standard.");
         goto return_error;
     }
 
     if (!strcasecmp(standard, "ocf") && crm_strlen_zero(provider)) {
         crm_err("An OCF resource action must have a provider.");
         goto return_error;
     }
 
     if (crm_strlen_zero(agent)) {
         crm_err("A service or resource action must have an agent.");
         goto return_error;
     }
 
     if (crm_strlen_zero(action)) {
         crm_err("A service or resource action must specify an action.");
         goto return_error;
     }
 
     if (safe_str_eq(action, "monitor")
         && (safe_str_eq(standard, "lsb") || safe_str_eq(standard, "service"))) {
         action = "status";
     }
 
     /*
      * Sanity checks passed, proceed!
      */
 
     op = calloc(1, sizeof(svc_action_t));
     op->opaque = calloc(1, sizeof(svc_action_private_t));
     op->rsc = strdup(name);
     op->action = strdup(action);
     op->interval = interval;
     op->timeout = timeout;
     op->standard = strdup(standard);
     op->agent = strdup(agent);
     op->sequence = ++operations;
     if (asprintf(&op->id, "%s_%s_%d", name, action, interval) == -1) {
         goto return_error;
     }
 
     if (strcasecmp(op->standard, "service") == 0) {
         const char *expanded = resources_find_service_class(op->agent);
 
         if(expanded) {
             crm_debug("Found a %s agent for %s/%s", expanded, op->rsc, op->agent);
             free(op->standard);
             op->standard = strdup(expanded);
 
         } else {
             crm_info("Cannot determine the standard for %s (%s)", op->rsc, op->agent);
             free(op->standard);
             op->standard = strdup("lsb");
         }
         CRM_ASSERT(op->standard);
     }
 
     if (strcasecmp(op->standard, "ocf") == 0) {
         op->provider = strdup(provider);
         op->params = params;
         params = NULL;
 
         if (asprintf(&op->opaque->exec, "%s/resource.d/%s/%s", OCF_ROOT_DIR, provider, agent) == -1) {
             crm_err("Internal error: cannot create agent path");
             goto return_error;
         }
         op->opaque->args[0] = strdup(op->opaque->exec);
         op->opaque->args[1] = strdup(action);
 
     } else if (strcasecmp(op->standard, "lsb") == 0) {
         if (op->agent[0] == '/') {
             /* if given an absolute path, use that instead
              * of tacking on the LSB_ROOT_DIR path to the front */
             op->opaque->exec = strdup(op->agent);
         } else if (asprintf(&op->opaque->exec, "%s/%s", LSB_ROOT_DIR, op->agent) == -1) {
             crm_err("Internal error: cannot create agent path");
             goto return_error;
         }
         op->opaque->args[0] = strdup(op->opaque->exec);
         op->opaque->args[1] = strdup(op->action);
         op->opaque->args[2] = NULL;
 
 #if SUPPORT_SYSTEMD
     } else if (strcasecmp(op->standard, "systemd") == 0) {
         op->opaque->exec = strdup("systemd-dbus");
 #endif
 #if SUPPORT_UPSTART
     } else if (strcasecmp(op->standard, "upstart") == 0) {
         op->opaque->exec = strdup("upstart-dbus");
 #endif
     } else if (strcasecmp(op->standard, "service") == 0) {
         op->opaque->exec = strdup(SERVICE_SCRIPT);
         op->opaque->args[0] = strdup(SERVICE_SCRIPT);
         op->opaque->args[1] = strdup(agent);
         op->opaque->args[2] = strdup(action);
 
 #if SUPPORT_NAGIOS
     } else if (strcasecmp(op->standard, "nagios") == 0) {
         int index = 0;
 
         if (op->agent[0] == '/') {
             /* if given an absolute path, use that instead
              * of tacking on the NAGIOS_PLUGIN_DIR path to the front */
             op->opaque->exec = strdup(op->agent);
 
         } else if (asprintf(&op->opaque->exec, "%s/%s", NAGIOS_PLUGIN_DIR, op->agent) == -1) {
             crm_err("Internal error: cannot create agent path");
             goto return_error;
         }
 
         op->opaque->args[0] = strdup(op->opaque->exec);
         index = 1;
 
         if (safe_str_eq(op->action, "monitor") && op->interval == 0) {
             /* Invoke --version for a nagios probe */
             op->opaque->args[index] = strdup("--version");
             index++;
 
         } else if (params) {
             GHashTableIter iter;
             char *key = NULL;
             char *value = NULL;
             static int args_size = sizeof(op->opaque->args) / sizeof(char *);
 
             g_hash_table_iter_init(&iter, params);
 
             while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
                    index <= args_size - 3) {
                 int len = 3;
                 char *long_opt = NULL;
 
                 if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
                     continue;
                 }
 
                 len += strlen(key);
                 long_opt = calloc(1, len);
                 sprintf(long_opt, "--%s", key);
                 long_opt[len - 1] = 0;
 
                 op->opaque->args[index] = long_opt;
                 op->opaque->args[index + 1] = strdup(value);
                 index += 2;
             }
         }
         op->opaque->args[index] = NULL;
 #endif
 
     } else {
         crm_err("Unknown resource standard: %s", op->standard);
         services_action_free(op);
         op = NULL;
     }
 
     if(params) {
         g_hash_table_destroy(params);
     }
     return op;
 
   return_error:
     if(params) {
         g_hash_table_destroy(params);
     }
     services_action_free(op);
 
     return NULL;
 }
 
 svc_action_t *
 services_action_create_generic(const char *exec, const char *args[])
 {
     svc_action_t *op;
     unsigned int cur_arg;
 
     op = calloc(1, sizeof(*op));
     op->opaque = calloc(1, sizeof(svc_action_private_t));
 
     op->opaque->exec = strdup(exec);
     op->opaque->args[0] = strdup(exec);
 
     for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
         op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
 
         if (cur_arg == DIMOF(op->opaque->args) - 1) {
             crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
             break;
         }
     }
 
     return op;
 }
 
 void
 services_action_free(svc_action_t * op)
 {
     unsigned int i;
 
     if (op == NULL) {
         return;
     }
 
     if (op->opaque->repeat_timer) {
         g_source_remove(op->opaque->repeat_timer);
     }
     if (op->opaque->stderr_gsource) {
         mainloop_del_fd(op->opaque->stderr_gsource);
         op->opaque->stderr_gsource = NULL;
     }
 
     if (op->opaque->stdout_gsource) {
         mainloop_del_fd(op->opaque->stdout_gsource);
         op->opaque->stdout_gsource = NULL;
     }
 
     free(op->id);
     free(op->opaque->exec);
 
     for (i = 0; i < DIMOF(op->opaque->args); i++) {
         free(op->opaque->args[i]);
     }
 
     free(op->opaque);
     free(op->rsc);
     free(op->action);
 
     free(op->standard);
     free(op->agent);
     free(op->provider);
 
     free(op->stdout_data);
     free(op->stderr_data);
 
     if (op->params) {
         g_hash_table_destroy(op->params);
         op->params = NULL;
     }
 
     free(op);
 }
 
 gboolean
 cancel_recurring_action(svc_action_t * op)
 {
     crm_info("Cancelling operation %s", op->id);
 
     if (recurring_actions) {
         g_hash_table_remove(recurring_actions, op->id);
     }
 
     if (op->opaque->repeat_timer) {
         g_source_remove(op->opaque->repeat_timer);
         op->opaque->repeat_timer = 0;
     }
 
     return TRUE;
 }
 
 gboolean
 services_action_cancel(const char *name, const char *action, int interval)
 {
     svc_action_t *op = NULL;
     char id[512];
 
     snprintf(id, sizeof(id), "%s_%s_%d", name, action, interval);
 
     if (!(op = g_hash_table_lookup(recurring_actions, id))) {
         return FALSE;
     }
 
     /* Always kill the recurring timer */
     cancel_recurring_action(op);
 
     if (op->pid == 0) {
         op->status = PCMK_LRM_OP_CANCELLED;
         if (op->opaque->callback) {
             op->opaque->callback(op);
         }
         services_action_free(op);
 
     } else {
         crm_info("Cancelling in-flight op: performing early termination of %s (pid=%d)", id, op->pid);
         op->cancel = 1;
         if (mainloop_child_kill(op->pid) == FALSE) {
             /* even though the early termination failed,
              * the op will be marked as cancelled once it completes. */
             crm_err("Termination of %s (pid=%d) failed", id, op->pid);
             return FALSE;
         }
     }
 
     return TRUE;
 }
 
 gboolean
 services_action_kick(const char *name, const char *action, int interval /* ms */)
 {
     svc_action_t * op = NULL;
     char *id = NULL;
 
     if (asprintf(&id, "%s_%s_%d", name, action, interval) == -1) {
         return FALSE;
     }
 
     op = g_hash_table_lookup(recurring_actions, id);
     free(id);
 
     if (op == NULL) {
         return FALSE;
     }
 
     if (op->pid) {
         return TRUE;
     } else {
         if (op->opaque->repeat_timer) {
             g_source_remove(op->opaque->repeat_timer);
         }
         recurring_action_timer(op);
         return TRUE;
     }
 
 }
 
 /* add new recurring operation, check for duplicates. 
  * - if duplicate found, return TRUE, immediately reschedule op.
  * - if no dup, return FALSE, inserve into recurring op list.*/
 static gboolean
 handle_duplicate_recurring(svc_action_t * op, void (*action_callback) (svc_action_t *))
 {
     svc_action_t * dup = NULL;
 
     if (recurring_actions == NULL) {
         recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
         return FALSE;
     }
 
     /* check for duplicates */
     dup = g_hash_table_lookup(recurring_actions, op->id);
 
     if (dup && (dup != op)) {
         /* update user data */
         if (op->opaque->callback) {
             dup->opaque->callback = op->opaque->callback;
             dup->cb_data = op->cb_data;
             op->cb_data = NULL;
         }
         /* immediately execute the next interval */
         if (dup->pid != 0) {
             if (op->opaque->repeat_timer) {
                 g_source_remove(op->opaque->repeat_timer);
             }
             recurring_action_timer(dup);
         }
         /* free the dup.  */
         services_action_free(op);
         return TRUE;
     }
 
     return FALSE;
 }
 
 gboolean
 services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *))
 {
+    op->synchronous = false;
     if (action_callback) {
         op->opaque->callback = action_callback;
     }
 
     if (op->interval > 0) {
         if (handle_duplicate_recurring(op, action_callback) == TRUE) {
             /* entry rescheduled, dup freed */
             return TRUE;
         }
         g_hash_table_replace(recurring_actions, op->id, op);
     }
     if (op->standard && strcasecmp(op->standard, "upstart") == 0) {
 #if SUPPORT_UPSTART
         return upstart_job_exec(op, FALSE);
 #endif
     }
     if (op->standard && strcasecmp(op->standard, "systemd") == 0) {
 #if SUPPORT_SYSTEMD
-        return systemd_unit_exec(op, FALSE);
+        return systemd_unit_exec(op);
 #endif
     }
     return services_os_action_execute(op, FALSE);
 }
 
 gboolean
 services_action_sync(svc_action_t * op)
 {
     gboolean rc = TRUE;
 
+    op->synchronous = true;
     if (op == NULL) {
         crm_trace("No operation to execute");
         return FALSE;
 
     } else if (op->standard && strcasecmp(op->standard, "upstart") == 0) {
 #if SUPPORT_UPSTART
         rc = upstart_job_exec(op, TRUE);
 #endif
     } else if (op->standard && strcasecmp(op->standard, "systemd") == 0) {
 #if SUPPORT_SYSTEMD
-        rc = systemd_unit_exec(op, TRUE);
+        rc = systemd_unit_exec(op);
 #endif
     } else {
         rc = services_os_action_execute(op, TRUE);
     }
     crm_trace(" > %s_%s_%d: %s = %d", op->rsc, op->action, op->interval, op->opaque->exec, op->rc);
     if (op->stdout_data) {
         crm_trace(" >  stdout: %s", op->stdout_data);
     }
     if (op->stderr_data) {
         crm_trace(" >  stderr: %s", op->stderr_data);
     }
     return rc;
 }
 
 GList *
 get_directory_list(const char *root, gboolean files, gboolean executable)
 {
     return services_os_get_directory_list(root, files, executable);
 }
 
 GList *
 services_list(void)
 {
     return resources_list_agents("lsb", NULL);
 }
 
 GList *
 resources_list_standards(void)
 {
     GList *standards = NULL;
     GList *agents = NULL;
 
     standards = g_list_append(standards, strdup("ocf"));
     standards = g_list_append(standards, strdup("lsb"));
     standards = g_list_append(standards, strdup("service"));
 
 #if SUPPORT_SYSTEMD
     agents = systemd_unit_listall();
 #else
     agents = NULL;
 #endif
 
     if (agents) {
         standards = g_list_append(standards, strdup("systemd"));
         g_list_free_full(agents, free);
     }
 #if SUPPORT_UPSTART
     agents = upstart_job_listall();
 #else
     agents = NULL;
 #endif
 
     if (agents) {
         standards = g_list_append(standards, strdup("upstart"));
         g_list_free_full(agents, free);
     }
 #if SUPPORT_NAGIOS
     agents = resources_os_list_nagios_agents();
     if (agents) {
         standards = g_list_append(standards, strdup("nagios"));
         g_list_free_full(agents, free);
     }
 #endif
 
     return standards;
 }
 
 GList *
 resources_list_providers(const char *standard)
 {
     if (strcasecmp(standard, "ocf") == 0) {
         return resources_os_list_ocf_providers();
     }
 
     return NULL;
 }
 
 GList *
 resources_list_agents(const char *standard, const char *provider)
 {
     if (standard == NULL || strcasecmp(standard, "service") == 0) {
         GList *tmp1;
         GList *tmp2;
         GList *result = resources_os_list_lsb_agents();
 
         if (standard == NULL) {
             tmp1 = result;
             tmp2 = resources_os_list_ocf_agents(NULL);
             if (tmp2) {
                 result = g_list_concat(tmp1, tmp2);
             }
         }
 #if SUPPORT_SYSTEMD
         tmp1 = result;
         tmp2 = systemd_unit_listall();
         if (tmp2) {
             result = g_list_concat(tmp1, tmp2);
         }
 #endif
 
 #if SUPPORT_UPSTART
         tmp1 = result;
         tmp2 = upstart_job_listall();
         if (tmp2) {
             result = g_list_concat(tmp1, tmp2);
         }
 #endif
 
         return result;
 
     } else if (strcasecmp(standard, "ocf") == 0) {
         return resources_os_list_ocf_agents(provider);
     } else if (strcasecmp(standard, "lsb") == 0) {
         return resources_os_list_lsb_agents();
 #if SUPPORT_SYSTEMD
     } else if (strcasecmp(standard, "systemd") == 0) {
         return systemd_unit_listall();
 #endif
 #if SUPPORT_UPSTART
     } else if (strcasecmp(standard, "upstart") == 0) {
         return upstart_job_listall();
 #endif
 #if SUPPORT_NAGIOS
     } else if (strcasecmp(standard, "nagios") == 0) {
         return resources_os_list_nagios_agents();
 #endif
     }
 
     return NULL;
 }
diff --git a/lib/services/systemd.c b/lib/services/systemd.c
index e81d178a72..c1a9237f39 100644
--- a/lib/services/systemd.c
+++ b/lib/services/systemd.c
@@ -1,535 +1,587 @@
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Copyright (C) 2012 Andrew Beekhof <andrew@beekhof.net>
  */
 
 #include <crm_internal.h>
 #include <crm/crm.h>
 #include <crm/services.h>
 #include <crm/common/mainloop.h>
 
 #include <gio/gio.h>
 #include <services_private.h>
 #include <systemd.h>
 #include <dbus/dbus.h>
 #include <pcmk-dbus.h>
 
 #define BUS_NAME "org.freedesktop.systemd1"
 #define BUS_PATH "/org/freedesktop/systemd1"
 
 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
 
 /*
    /usr/share/dbus-1/interfaces/org.freedesktop.systemd1.Manager.xml
 */
+gboolean
+systemd_unit_exec_with_unit(svc_action_t * op, const char *unit);
+
 
 struct unit_info {
     const char *id;
     const char *description;
     const char *load_state;
     const char *active_state;
     const char *sub_state;
     const char *following;
     const char *unit_path;
     uint32_t job_id;
     const char *job_type;
     const char *job_path;
 };
 
+struct pcmk_dbus_data 
+{
+        char *name;
+        char *unit;
+        DBusError error;
+        svc_action_t *op;
+        void (*callback)(DBusMessage *reply, svc_action_t *op);
+};
+
 static DBusMessage *systemd_new_method(const char *iface, const char *method)
 {
     crm_trace("Calling: %s on %s", method, iface);
     return dbus_message_new_method_call(BUS_NAME, // target for the method call
                                         BUS_PATH, // object to call on
                                         iface, // interface to call on
                                         method); // method name
 }
 
 
 static DBusConnection* systemd_proxy = NULL;
 static gboolean
 systemd_init(void)
 {
     static int need_init = 1;
     /* http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html */
 
     if (need_init) {
         need_init = 0;
         systemd_proxy = pcmk_dbus_connect();
     }
     if (systemd_proxy == NULL) {
         return FALSE;
     }
     return TRUE;
 }
 
 void
 systemd_cleanup(void)
 {
     if (systemd_proxy) {
         pcmk_dbus_disconnect(systemd_proxy);
         systemd_proxy = NULL;
     }
 }
 
 static char *
 systemd_service_name(const char *name)
 {
     if (name == NULL) {
         return NULL;
 
     } else if (strstr(name, ".service")) {
         return strdup(name);
     }
 
     return g_strdup_printf("%s.service", name);
 }
 
 static bool
 systemd_daemon_reload(void)
 {
+    /* TODO: Make this asynchronous */
     const char *method = "Reload";
     DBusMessage *reply = NULL;
     DBusMessage *msg = systemd_new_method(BUS_NAME".Manager", method);
 
     CRM_ASSERT(msg != NULL);
     reply = pcmk_dbus_send_recv(msg, systemd_proxy, NULL);
     dbus_message_unref(msg);
     if(reply) {
         dbus_message_unref(reply);
     }
     return TRUE;
 }
 
-static gboolean
-systemd_unit_by_name(const gchar * arg_name, gchar ** out_unit)
+static const char *
+systemd_loadunit_result(DBusMessage *reply, svc_action_t * op)
+{
+    const char *path = NULL;
+
+    if(pcmk_dbus_find_error("LoadUnit", (void*)&path, reply, NULL)) {
+        if(op) {
+            crm_warn("No unit found for %s", op->rsc);
+        }
+
+    } else if(pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
+        dbus_message_get_args (reply, NULL,
+                               DBUS_TYPE_OBJECT_PATH, &path,
+                               DBUS_TYPE_INVALID);
+    }
+
+    if(op) {
+        systemd_unit_exec_with_unit(op, path);
+    }
+
+    return path;
+}
+
+
+static void
+systemd_loadunit_cb(DBusPendingCall *pending, void *user_data)
+{
+    DBusMessage *reply = NULL;
+
+    if(pending) {
+        reply = dbus_pending_call_steal_reply(pending);
+    }
+
+    systemd_loadunit_result(reply, user_data);
+
+    if(reply) {
+        dbus_message_unref(reply);
+    }
+}
+
+static char *
+systemd_unit_by_name(const gchar * arg_name, svc_action_t *op)
 {
     DBusMessage *msg;
     DBusMessage *reply = NULL;
-    const char *method = "GetUnit";
     char *name = NULL;
-    DBusError error;
 
 /*
-  <method name="GetUnit">
-   <arg name="name" type="s" direction="in"/>
-   <arg name="unit" type="o" direction="out"/>
-  </method>
-
+  Equivalent to GetUnit if its already loaded
   <method name="LoadUnit">
    <arg name="name" type="s" direction="in"/>
    <arg name="unit" type="o" direction="out"/>
   </method>
  */
 
     if (systemd_init() == FALSE) {
         return FALSE;
     }
 
-    name = systemd_service_name(arg_name);
+    msg = systemd_new_method(BUS_NAME".Manager", "LoadUnit");
+    CRM_ASSERT(msg != NULL);
 
-    while(TRUE) {
-        msg = systemd_new_method(BUS_NAME".Manager", method);
-        CRM_ASSERT(msg != NULL);
+    name = systemd_service_name(arg_name);
+    CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
+    free(name);
 
-        CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
+    if(op == NULL || op->synchronous) {
+        const char *unit = NULL;
+        char *munit = NULL;
+        DBusError error;
 
         dbus_error_init(&error);
         reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
         dbus_message_unref(msg);
 
-        if(error.name) {
-            crm_info("Call to %s failed: %s", method, error.name);
-
-        } else if(pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
-            if(out_unit) {
-                char *path = NULL;
-
-                dbus_message_get_args (reply, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID);
-
-                *out_unit = strdup(path);
-            }
-            dbus_message_unref(reply);
-            free(name);
-            return TRUE;
+        unit = systemd_loadunit_result(reply, op);
+        if(unit) {
+            munit = strdup(unit);
         }
 
-        if(strcmp(method, "LoadUnit") != 0) {
-            method = "LoadUnit";
-            crm_debug("Cannot find %s, reloading the systemd manager configuration", name);
-            systemd_daemon_reload();
-            if(reply) {
-                dbus_message_unref(reply);
-                reply = NULL;
-            }
-
-        } else {
-            free(name);
-            return FALSE;
-        }
+        dbus_message_unref(reply);
+        return munit;
     }
-    return FALSE;
+
+    pcmk_dbus_send(msg, systemd_proxy, systemd_loadunit_cb, op);
+    return NULL;
 }
 
 GList *
 systemd_unit_listall(void)
 {
     int lpc = 0;
     GList *units = NULL;
     DBusMessageIter args;
     DBusMessageIter unit;
     DBusMessageIter elem;
     DBusMessage *msg = NULL;
     DBusMessage *reply = NULL;
     const char *method = "ListUnits";
     DBusError error;
 
     if (systemd_init() == FALSE) {
         return NULL;
     }
 
 /*
         "  <method name=\"ListUnits\">\n"                               \
         "   <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
         "  </method>\n"                                                 \
 */
 
     dbus_error_init(&error);
     msg = systemd_new_method(BUS_NAME".Manager", method);
     CRM_ASSERT(msg != NULL);
 
     reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
     dbus_message_unref(msg);
 
     if(error.name) {
         crm_err("Call to %s failed: %s", method, error.name);
         return NULL;
 
     } else if (!dbus_message_iter_init(reply, &args)) {
         crm_err("Call to %s failed: Message has no arguments", method);
         dbus_message_unref(reply);
         return NULL;
     }
 
     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
         crm_err("Call to %s failed: Message has invalid arguments", method);
         dbus_message_unref(reply);
         return NULL;
     }
 
     dbus_message_iter_recurse(&args, &unit);
     while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
         DBusBasicValue value;
 
         if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __FUNCTION__, __LINE__)) {
             continue;
         }
 
         dbus_message_iter_recurse(&unit, &elem);
         if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __FUNCTION__, __LINE__)) {
             continue;
         }
 
         dbus_message_iter_get_basic(&elem, &value);
         crm_trace("Got: %s", value.str);
         if(value.str) {
             char *match = strstr(value.str, ".service");
 
             if (match) {
                 lpc++;
                 match[0] = 0;
 
                 units = g_list_append(units, strdup(value.str));
             }
         }
         dbus_message_iter_next (&unit);
     }
 
     dbus_message_unref(reply);
 
     crm_trace("Found %d systemd services", lpc);
     return units;
 }
 
 gboolean
 systemd_unit_exists(const char *name)
 {
-    return systemd_unit_by_name(name, NULL);
+    /* Note: Makes a blocking dbus calls
+     * Used by resources_find_service_class() when resource class=service
+     */
+    if(systemd_unit_by_name(name, NULL)) {
+        return TRUE;
+    }
+    return FALSE;
 }
 
 static char *
 systemd_unit_metadata(const char *name)
 {
-    char *path = NULL;
     char *meta = NULL;
     char *desc = NULL;
+    char *path = systemd_unit_by_name(name, NULL);
 
-    if (systemd_unit_by_name(name, &path)) {
-        CRM_ASSERT(path);
+    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");
     } else {
-        desc = g_strdup_printf("systemd unit file for %s", name);
+        desc = g_strdup_printf("Systemd unit file for %s", name);
     }
 
     meta = g_strdup_printf("<?xml version=\"1.0\"?>\n"
                            "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
                            "<resource-agent name=\"%s\" version=\"0.1\">\n"
                            "  <version>1.0</version>\n"
                            "  <longdesc lang=\"en\">\n"
                            "    %s\n"
                            "  </longdesc>\n"
                            "  <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"
                            "  <parameters>\n"
                            "  </parameters>\n"
                            "  <actions>\n"
                            "    <action name=\"start\"   timeout=\"15\" />\n"
                            "    <action name=\"stop\"    timeout=\"15\" />\n"
                            "    <action name=\"status\"  timeout=\"15\" />\n"
                            "    <action name=\"restart\"  timeout=\"15\" />\n"
                            "    <action name=\"monitor\" timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n"
                            "    <action name=\"meta-data\"  timeout=\"5\" />\n"
                            "  </actions>\n"
                            "  <special tag=\"systemd\">\n"
                            "  </special>\n" "</resource-agent>\n", name, desc, name);
     free(desc);
     free(path);
     return meta;
 }
 
 static bool
 systemd_mask_error(svc_action_t *op, const char *error)
 {
     crm_trace("Could not issue %s for %s: %s", op->action, op->rsc, error);
     if(strstr(error, "org.freedesktop.systemd1.InvalidName")
        || strstr(error, "org.freedesktop.systemd1.LoadFailed")
        || strstr(error, "org.freedesktop.systemd1.NoSuchUnit")) {
 
         if (safe_str_eq(op->action, "stop")) {
             crm_trace("Masking %s failure for %s: unknown services are stopped", op->action, op->rsc);
             op->rc = PCMK_OCF_OK;
 
         } else {
             crm_trace("Mapping %s failure for %s: unknown services are not installed", op->action, op->rsc);
             op->rc = PCMK_OCF_NOT_INSTALLED;
             op->status = PCMK_LRM_OP_NOT_INSTALLED;
         }
         return TRUE;
     }
 
     return FALSE;
 }
 
 static void
-systemd_async_dispatch(DBusPendingCall *pending, void *user_data)
+systemd_exec_result(DBusMessage *reply, svc_action_t *op)
 {
     DBusError error;
-    DBusMessage *reply = NULL;
-    svc_action_t *op = user_data;
-
-    dbus_error_init(&error);
-    if(pending) {
-        reply = dbus_pending_call_steal_reply(pending);
-    }
-    if(reply == NULL) {
-        crm_err("No reply for %s action on %s", op->action, op->rsc);
 
-    } else if(pcmk_dbus_find_error(op->action, pending, reply, &error)) {
+    if(pcmk_dbus_find_error(op->action, (void*)&error, reply, &error)) {
 
         /* ignore "already started" or "not running" errors */
         if (!systemd_mask_error(op, error.name)) {
-            crm_err("%s for %s: %s", op->action, op->rsc, error.message);
+            crm_err("Could not issue %s for %s: %s (%s)", op->action, op->rsc, error.message);
         }
 
     } else {
         if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
             crm_warn("Call to %s passed but return type was unexpected", op->action);
             op->rc = PCMK_OCF_OK;
 
         } else {
             const char *path = NULL;
 
             dbus_message_get_args (reply, NULL,
                                    DBUS_TYPE_OBJECT_PATH, &path,
                                    DBUS_TYPE_INVALID);
             crm_info("Call to %s passed: %s", op->action, path);
             op->rc = PCMK_OCF_OK;
         }
     }
 
     operation_finalize(op);
+}
+
+static void
+systemd_async_dispatch(DBusPendingCall *pending, void *user_data)
+{
+    DBusError error;
+    DBusMessage *reply = NULL;
+    svc_action_t *op = user_data;
+
+    dbus_error_init(&error);
+    if(pending) {
+        reply = dbus_pending_call_steal_reply(pending);
+    }
+
+    systemd_exec_result(reply, op);
 
     if(pending) {
         dbus_pending_call_unref(pending);
     }
     if(reply) {
         dbus_message_unref(reply);
     }
 }
 
 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
 
+static gboolean
+systemd_unit_check(svc_action_t * op, const char *unit)
+{
+    char *state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME ".Unit", "ActiveState");
+
+    CRM_ASSERT(state != NULL);
+
+    if (g_strcmp0(state, "active") == 0) {
+        op->rc = PCMK_OCF_OK;
+    } else if (g_strcmp0(state, "activating") == 0) {
+        op->rc = PCMK_OCF_PENDING;
+    } else {
+        op->rc = PCMK_OCF_NOT_RUNNING;
+    }
+
+    free(state);
+
+    if (op->synchronous == FALSE) {
+        operation_finalize(op);
+        return TRUE;
+    }
+    return op->rc == PCMK_OCF_OK;
+}
+
 gboolean
-systemd_unit_exec(svc_action_t * op, gboolean synchronous)
+systemd_unit_exec_with_unit(svc_action_t * op, const char *unit)
 {
-    DBusError error;
-    char *unit = NULL;
-    const char *replace_s = "replace";
-    gboolean pass = FALSE;
     const char *method = op->action;
-    char *name = systemd_service_name(op->agent);
     DBusMessage *msg = NULL;
     DBusMessage *reply = NULL;
 
-    dbus_error_init(&error);
-    op->rc = PCMK_OCF_UNKNOWN_ERROR;
-    CRM_ASSERT(systemd_init());
-
-    crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
-              synchronous ? "" : "a", op->action, op->agent, op->rsc);
-
-    if (safe_str_eq(op->action, "meta-data")) {
-        op->stdout_data = systemd_unit_metadata(op->agent);
-        op->rc = PCMK_OCF_OK;
-        goto cleanup;
-    }
+    CRM_ASSERT(unit);
 
-    pass = systemd_unit_by_name(op->agent, &unit);
-    if (pass == FALSE) {
+    if (unit == NULL) {
         crm_debug("Could not obtain unit named '%s'", op->agent);
+        op->rc = PCMK_OCF_NOT_INSTALLED;
+        op->status = PCMK_LRM_OP_NOT_INSTALLED;
 #if 0
         if (error && strstr(error->message, "systemd1.NoSuchUnit")) {
             op->rc = PCMK_OCF_NOT_INSTALLED;
             op->status = PCMK_LRM_OP_NOT_INSTALLED;
         }
 #endif
         goto cleanup;
     }
 
     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");
-
-        if (g_strcmp0(state, "active") == 0) {
-            op->rc = PCMK_OCF_OK;
-        } else if (g_strcmp0(state, "activating") == 0) {
-            op->rc = PCMK_OCF_PENDING;
-        } else {
-            op->rc = PCMK_OCF_NOT_RUNNING;
-        }
-
-        free(state);
-        goto cleanup;
+        return systemd_unit_check(op, unit);
 
     } else if (g_strcmp0(method, "start") == 0) {
         FILE *file_strm = NULL;
         char *override_dir = g_strdup_printf("%s/%s", SYSTEMD_OVERRIDE_ROOT, unit);
-        char *override_file = g_strdup_printf("%s/50-pacemaker.conf", override_dir);
+        char *override_file = g_strdup_printf("%s/%s/50-pacemaker.conf", SYSTEMD_OVERRIDE_ROOT, unit);
 
         method = "StartUnit";
         crm_build_path(override_dir, 0755);
 
         file_strm = fopen(override_file, "w");
         if (file_strm != NULL) {
             int rc = fprintf(file_strm, "[Service]\nRestart=no");
             if (rc < 0) {
-                crm_perror(LOG_ERR, "Cannot write to systemd override file %s: %s (%d)", override_file, pcmk_strerror(errno), errno);
+                crm_perror(LOG_ERR, "Cannot write to systemd override file %s", override_file);
             }
 
         } else {
-            crm_err("Cannot open systemd override file %s for writing: %s (%d)", override_file, pcmk_strerror(errno), errno);
+            crm_err("Cannot open systemd override file %s for writing", override_file);
         }
 
         if (file_strm != NULL) {
             fflush(file_strm);
             fclose(file_strm);
         }
         systemd_daemon_reload();
         free(override_file);
         free(override_dir);
 
     } else if (g_strcmp0(method, "stop") == 0) {
         char *override_file = g_strdup_printf("%s/%s/50-pacemaker.conf", SYSTEMD_OVERRIDE_ROOT, unit);
 
         method = "StopUnit";
         unlink(override_file);
         free(override_file);
         systemd_daemon_reload();
 
     } else if (g_strcmp0(method, "restart") == 0) {
         method = "RestartUnit";
+
     } else {
         op->rc = PCMK_OCF_UNIMPLEMENT_FEATURE;
         goto cleanup;
     }
 
     crm_debug("Calling %s for %s: %s", method, op->rsc, unit);
 
     msg = systemd_new_method(BUS_NAME".Manager", method);
     CRM_ASSERT(msg != NULL);
 
     /* (ss) */
-    CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
-    CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
+    {
+        const char *replace_s = "replace";
+        char *name = systemd_service_name(op->agent);
+
+        CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
+        CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
 
-    if (synchronous == FALSE) {
-        free(unit);
         free(name);
-        return pcmk_dbus_send(msg, systemd_proxy, systemd_async_dispatch, op);
     }
 
-    dbus_error_init(&error);
-    reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
-
-    if(error.name) {
-        /* ignore "already started" or "not running" errors */
-        if(!systemd_mask_error(op, error.name)) {
-            crm_err("Could not issue %s for %s: %s (%s)", method, op->rsc, error.name, unit);
-        }
-        goto cleanup;
-
-    } else if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
-        crm_warn("Call to %s passed but return type was unexpected", op->action);
-        op->rc = PCMK_OCF_OK;
+    if (op->synchronous == FALSE) {
+        return pcmk_dbus_send(msg, systemd_proxy, systemd_async_dispatch, op);
 
     } else {
-        const char *path = NULL;
+        DBusError error;
 
-        dbus_message_get_args (reply, NULL,
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-        crm_info("Call to %s passed: %s", op->action, path);
-        op->rc = PCMK_OCF_OK;
+        reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
+        systemd_exec_result(reply, op);
+        if(reply) {
+            dbus_message_unref(reply);
+        }
     }
 
-  cleanup:
-    free(unit);
-    free(name);
-
     if(msg) {
         dbus_message_unref(msg);
     }
 
-    if(reply) {
-        dbus_message_unref(reply);
+  cleanup:
+    if (op->synchronous == FALSE) {
+        operation_finalize(op);
+        return TRUE;
     }
 
-    if (synchronous == FALSE) {
-        operation_finalize(op);
+    return op->rc == PCMK_OCF_OK;
+}
+
+gboolean
+systemd_unit_exec(svc_action_t * op)
+{
+    CRM_ASSERT(op);
+    CRM_ASSERT(systemd_init());
+    op->rc = PCMK_OCF_UNKNOWN_ERROR;
+    crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
+              op->synchronous ? "" : "a", op->action, op->agent, op->rsc);
+
+    if (safe_str_eq(op->action, "meta-data")) {
+        /* TODO: See if we can teach the lrmd not to make these calls synchronously */
+        op->stdout_data = systemd_unit_metadata(op->agent);
+        op->rc = PCMK_OCF_OK;
+
+        if (op->synchronous == FALSE) {
+            operation_finalize(op);
+        }
         return TRUE;
     }
+
+    systemd_unit_by_name(op->agent, op);
+    if (op->synchronous) {
+        return TRUE;
+    }
+
     return op->rc == PCMK_OCF_OK;
 }
diff --git a/lib/services/systemd.h b/lib/services/systemd.h
index 6e1b80b12e..c86bafe5b8 100644
--- a/lib/services/systemd.h
+++ b/lib/services/systemd.h
@@ -1,23 +1,23 @@
 /* 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Copyright (C) 2012 Andrew Beekhof <andrew@beekhof.net>
  */
 
 G_GNUC_INTERNAL GList *systemd_unit_listall(void);
-G_GNUC_INTERNAL int systemd_unit_exec(svc_action_t * op, gboolean synchronous);
+G_GNUC_INTERNAL int systemd_unit_exec(svc_action_t * op);
 G_GNUC_INTERNAL gboolean systemd_unit_exists(const gchar * name);
 G_GNUC_INTERNAL gboolean systemd_unit_running(const gchar * name);
 G_GNUC_INTERNAL void systemd_cleanup(void);