" in state %s", operation ,	(rsc ? crm_str(rsc->id) : "no rsc") ,	fsa_state2string(fsa_state));
" in state %s", operation, rid, fsa_state2string(fsa_state));
do_lrm_rsc_op(	lrm_rsc_t *rsc, char *rid, const char *operation, crm_data_t *msg){	int call_id  = 0;	char *op_id  = NULL;	lrm_op_t* op = NULL;	const char *type = NULL;	const char *class = NULL;	const char *provider = NULL;		GHashTable *params   = NULL;	fsa_data_t *msg_data = NULL;		if(rsc != NULL) {		class = rsc->class;		type = rsc->type;			} else if(msg != NULL) {		class = get_xml_attr_nested(			msg, rsc_path, DIMOF(rsc_path) -2,			XML_AGENT_ATTR_CLASS, TRUE);				type = get_xml_attr_nested(			msg, rsc_path, DIMOF(rsc_path) -2,			XML_ATTR_TYPE, TRUE);		provider = get_xml_attr_nested(			msg, rsc_path, DIMOF(rsc_path) -2,			XML_AGENT_ATTR_PROVIDER, FALSE);	}	if(safe_str_neq(operation, CRMD_RSCSTATE_STOP)) {		if(fsa_state == S_STARTING		   || fsa_state == S_STOPPING		   || fsa_state == S_TERMINATE) {			crm_err("Discarding attempt to perform action %s on %s"				" while in state %s", operation				,	(rsc ? crm_str(rsc->id) : "no rsc")				,	fsa_state2string(fsa_state));			return I_NULL;					} else if(AM_I_DC == FALSE && fsa_state != S_NOT_DC) {			crm_warn("Discarding attempt to perform action %s on %s"				 " in state %s", operation				,	(rsc ? crm_str(rsc->id) : "no rsc")				,	fsa_state2string(fsa_state));			return I_NULL;		}	}		if(rsc == NULL) {		/* check if its already there */		CRM_DEV_ASSERT(rid != NULL);		rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);	}	if(rsc == NULL) {		/* add it to the list */		crm_verbose("adding rsc %s before operation", rid);		if(msg != NULL) {			params = xml2list(msg);		} else {			CRM_DEV_ASSERT(safe_str_eq(CRMD_RSCSTATE_STOP, operation));		}		fsa_lrm_conn->lrm_ops->add_rsc(			fsa_lrm_conn, rid, class, type, provider, params);				rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);	}		if(rsc == NULL) {		crm_err("Could not add resource %s to LRM", rid);		register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);		return I_NULL;	}	/* stop the monitor before stopping the resource */	if(safe_str_eq(operation, CRMD_RSCSTATE_STOP)) {		g_hash_table_foreach(monitors, stop_recurring_action, rsc);		g_hash_table_foreach_remove(			monitors, remove_recurring_action, rsc);	}			/* now do the op */	crm_info("Performing op %s on %s", operation, rid);	crm_malloc0(op, sizeof(lrm_op_t));	op->op_type   = crm_strdup(operation);	op->op_status = LRM_OP_PENDING;	op->user_data = NULL;		if(params == NULL) {		if(msg != NULL) {			params = xml2list(msg);		} else {			CRM_DEV_ASSERT(safe_str_eq(					       CRMD_RSCSTATE_STOP, operation));		}	}	op->params = params;	op->interval = crm_get_msec(g_hash_table_lookup(op->params,"interval"));	op->timeout  = crm_get_msec(g_hash_table_lookup(op->params, "timeout"));	op->start_delay = crm_get_msec(		g_hash_table_lookup(op->params,"start_delay"));	/* sanity */	if(op->interval < 0) {		op->interval = 0;	}	if(op->timeout < 0) {		op->timeout = 0;	}	if(op->start_delay < 0) {		op->start_delay = 0;	}	if(g_hash_table_lookup(op->params, "timeout") != NULL) {		char *timeout_ms = crm_itoa(op->timeout);		g_hash_table_replace(			op->params, crm_strdup("timeout"), timeout_ms);	}	if(g_hash_table_lookup(op->params, "interval") != NULL) {		char *interval_ms = crm_itoa(op->interval);		g_hash_table_replace(			op->params, crm_strdup("interval"), interval_ms);	}	if(g_hash_table_lookup(op->params, "start_delay") != NULL) {		char *delay_ms = crm_itoa(op->start_delay);		g_hash_table_replace(			op->params, crm_strdup("start_delay"), delay_ms);	}	if(op->interval > 0) {		struct recurring_op_s *existing_op = NULL;		op_id = generate_op_key(rsc->id, op->op_type, op->interval);		existing_op = g_hash_table_lookup(monitors, op_id);		if(existing_op != NULL) {			crm_debug("Cancelling previous invocation of"				  " %s on %s (%d)",				  crm_str(op_id), rsc->id,existing_op->call_id);			/*cancel it so we can then restart it without conflict*/			rsc->ops->cancel_op(rsc, existing_op->call_id);			g_hash_table_remove(monitors, op_id);		}	}	op->app_name = crm_strdup(CRM_SYSTEM_CRMD);		if(safe_str_eq(operation, CRMD_RSCSTATE_MON)) {		op->target_rc = CHANGED;	} else {		op->target_rc = EVERYTIME;	}	if(safe_str_eq(CRMD_RSCSTATE_START, operation)) {		op->user_data = crm_strdup(CRMD_RSCSTATE_START_OK);	} else if(safe_str_eq(CRMD_RSCSTATE_STOP, operation)) {		op->user_data = crm_strdup(CRMD_RSCSTATE_STOP_OK);			} else if(safe_str_eq(CRMD_RSCSTATE_MON, operation)) {		const char *last_op = g_hash_table_lookup(resources, rsc->id);		op->user_data = crm_strdup(CRMD_RSCSTATE_MON_OK);		if(safe_str_eq(last_op, CRMD_RSCSTATE_STOP)) {			crm_err("Attempting to schedule %s _after_ a stop.",				op_id);			free_lrm_op(op);			crm_free(op_id);			return I_NULL;					}			} else {		crm_warn("Using status \"%s\" for op \"%s\""			 "... this is still in the experimental stage.",			 CRMD_RSCSTATE_GENERIC_OK, operation);		op->user_data = crm_strdup(CRMD_RSCSTATE_GENERIC_OK);	}		g_hash_table_replace(		resources, crm_strdup(rsc->id), crm_strdup(operation));	op->user_data_len = 1+strlen(op->user_data);	call_id = rsc->ops->perform_op(rsc, op);	if(call_id <= 0) {		crm_err("Operation %s on %s failed: %d",			operation, rid, call_id);		register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);	} else {		if(call_id > 0 && op->interval > 0) {			struct recurring_op_s *op = NULL;			crm_malloc0(op, sizeof(struct recurring_op_s));			crm_debug("Adding recurring %s op for %s (%d)",				  op_id, rsc->id, call_id);						op->call_id = call_id;			op->rsc_id  = crm_strdup(rsc->id);			g_hash_table_insert(monitors, op_id, op);			op_id = NULL;		}		/* record all operations so we can wait for them to complete */		char *call_id_s = make_stop_id(rsc->id, call_id);		g_hash_table_replace(			shutdown_ops, call_id_s, crm_strdup(rsc->id));		crm_debug("Recording shutdown op: %s", call_id_s);	}	crm_free(op_id);	free_lrm_op(op);			return I_NULL;}