Blob Blame History Raw
diff --git a/GNUmakefile b/GNUmakefile
index f28dea8..7a4c929 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -325,7 +325,7 @@ clang:
 	test -e $(CLANG_analyzer)
 	scan-build $(CLANG_checkers:%=-enable-checker %) make
 
-# V3	= scandir unsetenv alphasort
+# V3	= scandir unsetenv alphasort xalloc
 # V2	= setenv strerror strchrnul strndup
 # http://www.gnu.org/software/gnulib/manual/html_node/Initial-import.html#Initial-import
 GNU_MODS	= crypto/md5
diff --git a/crmd/lrm.c b/crmd/lrm.c
index b68f657..8315f6f 100644
--- a/crmd/lrm.c
+++ b/crmd/lrm.c
@@ -630,7 +630,7 @@ append_restart_list(lrmd_rsc_info_t * rsc, lrmd_event_data_t * op, xmlNode * upd
             crm_xml_add(restart, param, value);
         }
         len += strlen(param) + 2;
-        list = realloc(list, len + 1);
+        list = realloc_safe(list, len + 1);
         sprintf(list + start, " %s ", param);
     }
 
diff --git a/cts/CIB.py b/cts/CIB.py
index d26efdb..7922d8b 100644
--- a/cts/CIB.py
+++ b/cts/CIB.py
@@ -298,7 +298,28 @@ class CIB11(ConfigBase):
         # Group Resource
         g = Group(self.Factory, "group-1")
         g.add_child(self.NewIP())
-        g.add_child(self.NewIP())
+
+        if self.CM.Env["have_systemd"]:
+            dummy_service_file = """
+[Unit]
+Description=Dummy resource that takes a while to start
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/python -c 'import time; import systemd.daemon;time.sleep(10); systemd.daemon.notify("READY=1"); time.sleep(3600)'
+ExecStop=sleep 10
+ExecStop=/bin/kill -KILL $MAINPID
+"""
+
+            os.system("cat <<-END >/tmp/DummySD.service\n%s\nEND" % (dummy_service_file))
+
+            self.CM.install_helper("DummySD.service", destdir="/usr/lib/systemd/system/", sourcedir="/tmp")
+            sysd = Resource(self.Factory, "petulant", "DummySD",  "service")
+            sysd.add_op("monitor", "P10S")
+            g.add_child(sysd)
+        else:
+            g.add_child(self.NewIP())
+
         g.add_child(self.NewIP())
 
         # Group with the master
diff --git a/cts/environment.py b/cts/environment.py
index d741452..2b2a343 100644
--- a/cts/environment.py
+++ b/cts/environment.py
@@ -283,9 +283,9 @@ class Environment:
                 break;
         self["cts-master"] = master
 
-        if self.has_key("have_systemd"):
-            self["have_systemd"] = not rsh(discover, "systemctl list-units")
-
+        if not self.has_key("have_systemd"):
+            self["have_systemd"] = not self.rsh(self.target, "systemctl list-units")
+        
         self.detect_syslog()
         self.detect_at_boot()
         self.detect_ip_offset()
diff --git a/fencing/standalone_config.c b/fencing/standalone_config.c
index 01c22b6..4319c4a 100644
--- a/fencing/standalone_config.c
+++ b/fencing/standalone_config.c
@@ -170,7 +170,7 @@ standalone_cfg_add_node(const char *node, const char *device, const char *ports)
 
     if (tmp) {
         offset = strlen(tmp);
-        tmp = realloc(tmp, len + offset + 1);
+        tmp = realloc_safe(tmp, len + offset + 1);
     } else {
         tmp = malloc(len);
     }
diff --git a/include/crm_internal.h b/include/crm_internal.h
index 3eb88de..169d6d3 100644
--- a/include/crm_internal.h
+++ b/include/crm_internal.h
@@ -341,4 +341,16 @@ void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
         qb_ipcs_service_t *ipcs_rw,
         qb_ipcs_service_t *ipcs_shm);
 
+static inline void *realloc_safe(void *ptr, size_t size)
+{
+    void *ret = realloc(ptr, size);
+
+    if(ret == NULL) {
+        abort();
+    }
+
+    return ret;
+}
+
+
 #endif                          /* CRM_INTERNAL__H */
diff --git a/lib/ais/plugin.c b/lib/ais/plugin.c
index 3d4f369..ab534fa 100644
--- a/lib/ais/plugin.c
+++ b/lib/ais/plugin.c
@@ -1214,7 +1214,7 @@ pcmk_generate_membership_data(void)
 
     g_hash_table_foreach(membership_list, member_loop_fn, &data);
     size = strlen(data.string);
-    data.string = realloc(data.string, size + 9);       /* 9 = </nodes> + nul */
+    data.string = realloc_safe(data.string, size + 9);       /* 9 = </nodes> + nul */
     sprintf(data.string + size, "</nodes>");
     return data.string;
 }
diff --git a/lib/ais/utils.c b/lib/ais/utils.c
index e56fb6d..94a2505 100644
--- a/lib/ais/utils.c
+++ b/lib/ais/utils.c
@@ -409,7 +409,7 @@ append_member(char *data, crm_node_t * node)
     if (node->version) {
         size += (9 + strlen(node->version));
     }
-    data = realloc(data, size);
+    data = realloc_safe(data, size);
 
     offset += snprintf(data + offset, size - offset, "<node id=\"%u\" ", node->id);
     if (node->uname) {
diff --git a/lib/cluster/cpg.c b/lib/cluster/cpg.c
index 6c86e83..cda6326 100644
--- a/lib/cluster/cpg.c
+++ b/lib/cluster/cpg.c
@@ -584,7 +584,7 @@ send_cluster_text(int class, const char *data,
     msg->header.size = sizeof(AIS_Message) + msg->size;
 
     if (msg->size < CRM_BZ2_THRESHOLD) {
-        msg = realloc(msg, msg->header.size);
+        msg = realloc_safe(msg, msg->header.size);
         memcpy(msg->data, data, msg->size);
 
     } else {
@@ -595,14 +595,14 @@ send_cluster_text(int class, const char *data,
         if (crm_compress_string(uncompressed, msg->size, 0, &compressed, &new_size)) {
 
             msg->header.size = sizeof(AIS_Message) + new_size;
-            msg = realloc(msg, msg->header.size);
+            msg = realloc_safe(msg, msg->header.size);
             memcpy(msg->data, compressed, new_size);
 
             msg->is_compressed = TRUE;
             msg->compressed_size = new_size;
 
         } else {
-            msg = realloc(msg, msg->header.size);
+            msg = realloc_safe(msg, msg->header.size);
             memcpy(msg->data, data, msg->size);
         }
 
diff --git a/lib/cluster/heartbeat.c b/lib/cluster/heartbeat.c
index a801c8e..6f6a388 100644
--- a/lib/cluster/heartbeat.c
+++ b/lib/cluster/heartbeat.c
@@ -106,7 +106,7 @@ convert_ha_field(xmlNode * parent, void *msg_v, int lpc)
 
             crm_trace("Trying to decompress %d bytes", (int)orig_len);
   retry:
-            uncompressed = realloc(uncompressed, size);
+            uncompressed = realloc_safe(uncompressed, size);
             memset(uncompressed, 0, size);
             used = size - 1;    /* always leave room for a trailing '\0'
                                  * BZ2_bzBuffToBuffDecompress wont say anything if
diff --git a/lib/common/logging.c b/lib/common/logging.c
index d64b77a..f211d80 100644
--- a/lib/common/logging.c
+++ b/lib/common/logging.c
@@ -956,7 +956,7 @@ crm_log_args(int argc, char **argv)
         }
 
         len = 2 + strlen(argv[lpc]);    /* +1 space, +1 EOS */
-        arg_string = realloc(arg_string, len + existing_len);
+        arg_string = realloc_safe(arg_string, len + existing_len);
         existing_len += sprintf(arg_string + existing_len, "%s ", argv[lpc]);
     }
 
diff --git a/lib/common/remote.c b/lib/common/remote.c
index f11ebcd..2a5b449 100644
--- a/lib/common/remote.c
+++ b/lib/common/remote.c
@@ -520,7 +520,7 @@ crm_remote_recv_once(crm_remote_t * remote)
            remote->buffer_size = 2 * read_len;
         crm_trace("Expanding buffer to %u bytes", remote->buffer_size);
 
-        remote->buffer = realloc(remote->buffer, remote->buffer_size + 1);
+        remote->buffer = realloc_safe(remote->buffer, remote->buffer_size + 1);
         CRM_ASSERT(remote->buffer != NULL);
     }
 
diff --git a/lib/common/utils.c b/lib/common/utils.c
index eacd8e9..d70778d 100644
--- a/lib/common/utils.c
+++ b/lib/common/utils.c
@@ -1712,7 +1712,7 @@ crm_create_long_opts(struct crm_option *long_options)
      * This dummy entry allows us to differentiate between the two in crm_get_option()
      * and exit with the correct error code
      */
-    long_opts = realloc(long_opts, (index + 1) * sizeof(struct option));
+    long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
     long_opts[index].name = "__dummmy__";
     long_opts[index].has_arg = 0;
     long_opts[index].flag = 0;
@@ -1724,7 +1724,7 @@ crm_create_long_opts(struct crm_option *long_options)
             continue;
         }
 
-        long_opts = realloc(long_opts, (index + 1) * sizeof(struct option));
+        long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
         /*fprintf(stderr, "Creating %d %s = %c\n", index,
          * long_options[lpc].name, long_options[lpc].val);      */
         long_opts[index].name = long_options[lpc].name;
@@ -1735,7 +1735,7 @@ crm_create_long_opts(struct crm_option *long_options)
     }
 
     /* Now create the list terminator */
-    long_opts = realloc(long_opts, (index + 1) * sizeof(struct option));
+    long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
     long_opts[index].name = NULL;
     long_opts[index].has_arg = 0;
     long_opts[index].flag = 0;
@@ -1759,7 +1759,7 @@ crm_set_options(const char *short_options, const char *app_usage, struct crm_opt
 
         for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
             if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
-                local_short_options = realloc(local_short_options, opt_string_len + 4);
+                local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
                 local_short_options[opt_string_len++] = long_options[lpc].val;
                 /* getopt(3) says: Two colons mean an option takes an optional arg; */
                 if (long_options[lpc].has_arg == optional_argument) {
@@ -2517,7 +2517,7 @@ add_list_element(char *list, const char *value)
     }
     len = last + 2;             /* +1 space, +1 EOS */
     len += strlen(value);
-    list = realloc(list, len);
+    list = realloc_safe(list, len);
     sprintf(list + last, " %s", value);
     return list;
 }
diff --git a/lib/common/xml.c b/lib/common/xml.c
index e63a582..0effd47 100644
--- a/lib/common/xml.c
+++ b/lib/common/xml.c
@@ -206,7 +206,7 @@ static inline bool TRACKING_CHANGES(xmlNode *xml)
         } else if(rc >= ((max) - (offset))) {                           \
             char *tmp = NULL;                                           \
             (max) = QB_MAX(CHUNK_SIZE, (max) * 2);                      \
-            tmp = realloc((buffer), (max) + 1);                         \
+            tmp = realloc_safe((buffer), (max) + 1);                         \
             CRM_ASSERT(tmp);                                            \
             (buffer) = tmp;                                             \
         } else {                                                        \
@@ -223,7 +223,7 @@ insert_prefix(int options, char **buffer, int *offset, int *max, int depth)
 
         if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
             (*max) = QB_MAX(CHUNK_SIZE, (*max) * 2);
-            (*buffer) = realloc((*buffer), (*max) + 1);
+            (*buffer) = realloc_safe((*buffer), (*max) + 1);
         }
         memset((*buffer) + (*offset), ' ', spaces);
         (*offset) += spaces;
@@ -305,7 +305,7 @@ static void __xml_schema_add(
     int last = xml_schema_max;
 
     xml_schema_max++;
-    known_schemas = realloc(known_schemas, xml_schema_max*sizeof(struct schema_s));
+    known_schemas = realloc_safe(known_schemas, xml_schema_max*sizeof(struct schema_s));
     CRM_ASSERT(known_schemas != NULL);
     memset(known_schemas+last, 0, sizeof(struct schema_s));
     known_schemas[last].type = type;
@@ -2759,6 +2759,7 @@ create_xml_node(xmlNode * parent, const char *name)
     xmlNode *node = NULL;
 
     if (name == NULL || name[0] == 0) {
+        CRM_CHECK(name != NULL || name[0] == 0, return NULL);
         return NULL;
     }
 
@@ -2905,7 +2906,7 @@ crm_xml_err(void *ctx, const char *msg, ...)
         buf = NULL;
 
     } else {
-        buffer = realloc(buffer, 1 + buffer_len + len);
+        buffer = realloc_safe(buffer, 1 + buffer_len + len);
         memcpy(buffer + buffer_len, buf, len);
         buffer_len += len;
         buffer[buffer_len] = 0;
@@ -2997,7 +2998,7 @@ stdin2xml(void)
             break;
         }
 
-        xml_buffer = realloc(xml_buffer, next);
+        xml_buffer = realloc_safe(xml_buffer, next);
         read_chars = fread(xml_buffer + data_length, 1, XML_BUFFER_SIZE, stdin);
         data_length += read_chars;
     } while (read_chars > 0);
@@ -3043,7 +3044,7 @@ decompress_file(const char *filename)
 
     rc = BZ_OK;
     while (rc == BZ_OK) {
-        buffer = realloc(buffer, XML_BUFFER_SIZE + length + 1);
+        buffer = realloc_safe(buffer, XML_BUFFER_SIZE + length + 1);
         read_len = BZ2_bzRead(&rc, bz_file, buffer + length, XML_BUFFER_SIZE);
 
         crm_trace("Read %ld bytes from file: %d", (long)read_len, rc);
@@ -3301,7 +3302,7 @@ crm_xml_escape_shuffle(char *text, int start, int *length, const char *replace)
     int offset = strlen(replace) - 1;   /* We have space for 1 char already */
 
     *length += offset;
-    text = realloc(text, *length);
+    text = realloc_safe(text, *length);
 
     for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
         text[lpc] = text[lpc - offset];
@@ -5369,7 +5370,7 @@ crm_xml_init(void)
     if(init) {
         init = FALSE;
         /* The default allocator XML_BUFFER_ALLOC_EXACT does far too many
-         * realloc()s and it can take upwards of 18 seconds (yes, seconds)
+         * realloc_safe()s and it can take upwards of 18 seconds (yes, seconds)
          * to dump a 28kb tree which XML_BUFFER_ALLOC_DOUBLEIT can do in
          * less than 1 second.
          */
@@ -5987,7 +5988,7 @@ get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level)
     len += strlen(xpath);
 
     xpath_full = strdup(xpath_prefix);
-    xpath_full = realloc(xpath_full, len + 1);
+    xpath_full = realloc_safe(xpath_full, len + 1);
     strncat(xpath_full, xpath, len);
 
     result = get_xpath_object(xpath_full, xml_obj, error_level);
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
index 06b9492..e51d673 100644
--- a/lib/fencing/st_client.c
+++ b/lib/fencing/st_client.c
@@ -308,7 +308,7 @@ append_arg(gpointer key, gpointer value, gpointer user_data)
         last = strlen(*args);
     }
 
-    *args = realloc(*args, last + len);
+    *args = realloc_safe(*args, last + len);
     crm_trace("Appending: %s=%s", (char *)key, (char *)value);
     sprintf((*args) + last, "%s=%s\n", (char *)key, (char *)value);
 }
@@ -627,7 +627,7 @@ read_output(int fd)
                               * 'more' is always less than our buffer size
                               */
             crm_trace("Got %d more bytes: %.200s...", more, buffer);
-            output = realloc(output, len + more + 1);
+            output = realloc_safe(output, len + more + 1);
             snprintf(output + len, more + 1, "%s", buffer);
             len += more;
         }
diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
index 8d6f450..de29706 100644
--- a/lib/services/services_linux.c
+++ b/lib/services/services_linux.c
@@ -94,7 +94,7 @@ svc_read_output(int fd, svc_action_t * op, bool is_stderr)
         if (rc > 0) {
             crm_trace("Got %d characters starting with %.20s", rc, buf);
             buf[rc] = 0;
-            data = realloc(data, len + rc + 1);
+            data = realloc_safe(data, len + rc + 1);
             len += sprintf(data + len, "%s", buf);
 
         } else if (errno != EINTR) {
diff --git a/lib/services/systemd.c b/lib/services/systemd.c
index a8bf1b4..c0a1721 100644
--- a/lib/services/systemd.c
+++ b/lib/services/systemd.c
@@ -462,10 +462,11 @@ systemd_async_dispatch(DBusPendingCall *pending, void *user_data)
     if(op) {
         crm_trace("Got result: %p for %p for %s, %s", reply, pending, op->rsc, op->action);
         op->opaque->pending = NULL;
+        systemd_exec_result(reply, op);
+
     } else {
         crm_trace("Got result: %p for %p", reply, pending);
     }
-    systemd_exec_result(reply, op);
 
     if(pending) {
         dbus_pending_call_unref(pending);
@@ -491,6 +492,8 @@ systemd_unit_check(const char *name, const char *state, void *userdata)
         op->rc = PCMK_OCF_OK;
     } else if (g_strcmp0(state, "activating") == 0) {
         op->rc = PCMK_OCF_PENDING;
+    } else if (g_strcmp0(state, "deactivating") == 0) {
+        op->rc = PCMK_OCF_PENDING;
     } else {
         op->rc = PCMK_OCF_NOT_RUNNING;
     }
diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
index d3ede18..0f5f529 100644
--- a/lrmd/lrmd.c
+++ b/lrmd/lrmd.c
@@ -790,10 +790,30 @@ action_complete(svc_action_t * action)
             cmd->real_action = cmd->action;
             cmd->action = strdup("monitor");
 
+        } else if(cmd->exec_rc == PCMK_OCF_OK && safe_str_eq(cmd->action, "stop")) {
+            goagain = true;
+            cmd->real_action = cmd->action;
+            cmd->action = strdup("monitor");
+
         } else if(cmd->real_action) {
             /* Ok, so this is the follow up monitor action to check if start actually completed */
             if(cmd->lrmd_op_status == PCMK_LRM_OP_DONE && cmd->exec_rc == PCMK_OCF_PENDING) {
                 goagain = true;
+
+            } else {
+                int time_sum = 0;
+                int timeout_left = 0;
+                struct timeb now = { 0, };
+
+                ftime(&now);
+                time_sum = time_diff_ms(&now, &cmd->t_first_run);
+                timeout_left = cmd->timeout_orig - time_sum;
+                crm_debug("%s %s is now complete (elapsed=%dms, remaining=%dms): %s (%d)",
+                          cmd->rsc_id, cmd->real_action, time_sum, timeout_left, services_ocf_exitcode_str(cmd->exec_rc), cmd->exec_rc);
+
+                if(cmd->lrmd_op_status == PCMK_LRM_OP_DONE && cmd->exec_rc == PCMK_OCF_NOT_RUNNING && safe_str_eq(cmd->real_action, "stop")) {
+                    cmd->exec_rc = PCMK_OCF_OK;
+                }
             }
         }
     }
@@ -827,13 +847,22 @@ action_complete(svc_action_t * action)
             delay = timeout_left/2;
         }
 
+        delay = QB_MIN(2000, delay);
         if (delay < timeout_left) {
             cmd->start_delay = delay;
             cmd->timeout = timeout_left;
 
-            if(cmd->exec_rc != PCMK_OCF_OK) {
-                crm_info("%s %s failed (rc=%d): re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
-                         cmd->rsc_id, cmd->action, cmd->exec_rc, time_sum, timeout_left, delay);
+            if(cmd->exec_rc == PCMK_OCF_OK) {
+                crm_debug("%s %s may still be in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
+                          cmd->rsc_id, cmd->real_action, time_sum, timeout_left, delay);
+
+            } else if(cmd->exec_rc == PCMK_OCF_PENDING) {
+                crm_info("%s %s is still in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
+                         cmd->rsc_id, cmd->action, time_sum, timeout_left, delay);
+
+            } else {
+                crm_notice("%s %s failed '%s' (%d): re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
+                           cmd->rsc_id, cmd->action, services_ocf_exitcode_str(cmd->exec_rc), cmd->exec_rc, time_sum, timeout_left, delay);
             }
 
             cmd_reset(cmd);
diff --git a/pengine/allocate.c b/pengine/allocate.c
index 45e2212..748ca54 100644
--- a/pengine/allocate.c
+++ b/pengine/allocate.c
@@ -1913,7 +1913,7 @@ expand_list(GListPtr list, char **rsc_list, char **node_list)
             }
 
             crm_trace("Adding %s (%dc) at offset %d", rsc_id, len - 2, existing_len);
-            *rsc_list = realloc(*rsc_list, len + existing_len);
+            *rsc_list = realloc_safe(*rsc_list, len + existing_len);
             sprintf(*rsc_list + existing_len, "%s ", rsc_id);
         }
 
@@ -1930,7 +1930,7 @@ expand_list(GListPtr list, char **rsc_list, char **node_list)
             }
 
             crm_trace("Adding %s (%dc) at offset %d", uname, len - 2, existing_len);
-            *node_list = realloc(*node_list, len + existing_len);
+            *node_list = realloc_safe(*node_list, len + existing_len);
             sprintf(*node_list + existing_len, "%s ", uname);
         }
     }
diff --git a/replace/scandir.c b/replace/scandir.c
index 7a8efea..0011630 100644
--- a/replace/scandir.c
+++ b/replace/scandir.c
@@ -202,7 +202,7 @@ scandir(const char *directory_name,
             if (counter + 1 == allocated) {
                 allocated <<= 1;
                 array = (struct dirent **)
-                    realloc((char *)array, allocated * sizeof(struct dirent *));
+                    realloc_safe((char *)array, allocated * sizeof(struct dirent *));
                 if (array == NULL) {
                     closedir(directory);
                     free(array);
diff --git a/tools/crm_resource.c b/tools/crm_resource.c
index 6e510e1..236d43c 100644
--- a/tools/crm_resource.c
+++ b/tools/crm_resource.c
@@ -1399,16 +1399,20 @@ static void display_list(GList *items, const char *tag)
 static int
 update_dataset(cib_t *cib, pe_working_set_t * data_set, bool simulate)
 {
+    char *pid = NULL;
+    char *shadow_file = NULL;
+    cib_t *shadow_cib = NULL;
     xmlNode *cib_xml_copy = NULL;
     int rc = cib->cmds->query(cib, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
 
     if(rc != pcmk_ok) {
         fprintf(stdout, "Could not obtain the current CIB: %s (%d)\n", pcmk_strerror(rc), rc);
-        return crm_exit(rc);
+        goto cleanup;
 
     } else if (cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) {
         fprintf(stderr, "Could not upgrade the current CIB\n");
-        return -ENOKEY;
+        rc = -ENOKEY;
+        goto cleanup;
     }
 
     set_working_set_defaults(data_set);
@@ -1416,70 +1420,103 @@ update_dataset(cib_t *cib, pe_working_set_t * data_set, bool simulate)
     data_set->now = crm_time_new(NULL);
 
     if(simulate) {
-        char *pid = crm_itoa(getpid());
-        cib_t *shadow_cib = cib_shadow_new(pid);
-        char *shadow_file = get_shadow_file(pid);
+        pid = crm_itoa(getpid());
+        shadow_cib = cib_shadow_new(pid);
+        shadow_file = get_shadow_file(pid);
 
         if (shadow_cib == NULL) {
             fprintf(stderr, "Could not create shadow cib: '%s'\n", pid);
-            crm_exit(-ENXIO);
+            rc = -ENXIO;
+            goto cleanup;
         }
 
+        free(pid);
         rc = write_xml_file(cib_xml_copy, shadow_file, FALSE);
 
         if (rc < 0) {
             fprintf(stderr, "Could not populate shadow cib: %s (%d)\n", pcmk_strerror(rc), rc);
-            free_xml(cib_xml_copy);
-            return rc;
+            goto cleanup;
         }
 
         rc = shadow_cib->cmds->signon(shadow_cib, crm_system_name, cib_command);
         if(rc != pcmk_ok) {
             fprintf(stderr, "Could not connect to shadow cib: %s (%d)\n", pcmk_strerror(rc), rc);
-            free_xml(cib_xml_copy);
-            return rc;
+            goto cleanup;
         }
 
         do_calculations(data_set, cib_xml_copy, NULL);
         run_simulation(data_set, shadow_cib, NULL, TRUE);
         rc = update_dataset(shadow_cib, data_set, FALSE);
 
-        cib_delete(shadow_cib);
-        /* unlink(shadow_file); */
-        free(shadow_file);
-
     } else {
         cluster_status(data_set);
     }
 
+  cleanup:
+    cib_delete(shadow_cib);
+    free_xml(cib_xml_copy);
+    free(pid);
+
+    if(shadow_file) {
+        unlink(shadow_file);
+        free(shadow_file);
+    }
+
     return rc;
 }
 
 static int
-max_delay_in(pe_working_set_t * data_set, GList *resources) 
+max_delay_for_resource(pe_working_set_t * data_set, resource_t *rsc) 
 {
+    int delay = 0;
     int max_delay = 0;
-    GList *item = NULL;
 
-    for (item = resources; item != NULL; item = item->next) {
-        resource_t *rsc = pe_find_resource(data_set->resources, (const char *)item->data);
+    if(rsc && rsc->children) {
+        GList *iter = NULL;
 
-        if(rsc) {
-            char *key = g_strdup_printf("%s_%s_0", rsc->id, RSC_STOP);
-            action_t *stop = custom_action(rsc, key, RSC_STOP, NULL, TRUE, FALSE, data_set);
-            const char *value = g_hash_table_lookup(stop->meta, XML_ATTR_TIMEOUT);
-            int delay = crm_int_helper(value, NULL);
+        for(iter = rsc->children; iter; iter = iter->next) {
+            resource_t *child = (resource_t *)iter->data;
 
+            delay = max_delay_for_resource(data_set, child);
             if(delay > max_delay) {
-                crm_trace("Calculated new delay of %s ms due to %s", value, rsc->id);
+                double seconds = delay / 1000;
+                crm_trace("Calculated new delay of %.1fs due to %s", seconds, child->id);
                 max_delay = delay;
             }
-
-            pe_free_action(stop);
         }
+
+    } else if(rsc) {
+        char *key = g_strdup_printf("%s_%s_0", rsc->id, RSC_STOP);
+        action_t *stop = custom_action(rsc, key, RSC_STOP, NULL, TRUE, FALSE, data_set);
+        const char *value = g_hash_table_lookup(stop->meta, XML_ATTR_TIMEOUT);
+
+        max_delay = crm_int_helper(value, NULL);
+        pe_free_action(stop);
     }
 
 
+    return max_delay;
+}
+
+static int
+max_delay_in(pe_working_set_t * data_set, GList *resources) 
+{
+    int max_delay = 0;
+    GList *item = NULL;
+
+    for (item = resources; item != NULL; item = item->next) {
+        int delay = 0;
+        resource_t *rsc = pe_find_resource(data_set->resources, (const char *)item->data);
+
+        delay = max_delay_for_resource(data_set, rsc);
+
+        if(delay > max_delay) {
+            double seconds = delay / 1000;
+            crm_trace("Calculated new delay of %.1fs due to %s", seconds, rsc->id);
+            max_delay = delay;
+        }
+    }
+
     return 5 + (max_delay / 1000);
 }
 
@@ -1507,7 +1544,7 @@ resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib
         return -ENXIO;
     }
 
-
+    attr_set_type = XML_TAG_META_SETS;
     rsc_id = strdup(rsc->id);
     if(rsc->variant > pe_group) {
         is_clone = TRUE;
@@ -1536,6 +1573,7 @@ resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib
     rc = update_dataset(cib, &data_set, FALSE);
     if(rc != pcmk_ok) {
         fprintf(stdout, "Could not get new resource list: %s (%d)\n", pcmk_strerror(rc), rc);
+        free(rsc_id);
         return rc;
     }
 
@@ -1553,6 +1591,7 @@ resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib
     }
     if(rc != pcmk_ok) {
         fprintf(stderr, "Could not set target-role for %s: %s (%d)\n", rsc_id, pcmk_strerror(rc), rc);
+        free(rsc_id);
         return crm_exit(rc);
     }
 
@@ -1615,6 +1654,7 @@ resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib
 
     if(rc != pcmk_ok) {
         fprintf(stderr, "Could not unset target-role for %s: %s (%d)\n", rsc_id, pcmk_strerror(rc), rc);
+        free(rsc_id);
         return crm_exit(rc);
     }
 
@@ -1659,6 +1699,7 @@ resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib
 
     } while(g_list_length(list_delta) > 0);
 
+    free(rsc_id);
     return pcmk_ok;
 
   failure:
@@ -1668,6 +1709,7 @@ resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib
     } else {
         delete_resource_attr(rsc_id, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, cib, &data_set);
     }
+    free(rsc_id);
     return rc;
 }