gboolean add_node_attrs(xmlNodePtr attrs, node_t *node) { const char *name  = NULL; const char *value = NULL;  while(attrs != NULL){ name  = xmlGetProp(attrs, XML_NVPAIR_ATTR_NAME); value = xmlGetProp(attrs, XML_NVPAIR_ATTR_VALUE);  if(name != NULL && value != NULL && safe_val(NULL, node, details) != NULL) { crm_verbose("Adding %s => %s", name, value);   g_hash_table_insert(node->details->attrs, crm_strdup(name), crm_strdup(value)); } attrs = attrs->next; } g_hash_table_insert(node->details->attrs, crm_strdup("uname"), crm_strdup(node->details->uname)); g_hash_table_insert(node->details->attrs, crm_strdup("id"), crm_strdup(node->details->id)); return TRUE; }    gboolean unpack_rsc_location(xmlNodePtr xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *node_constraints) {  xmlNodePtr rules    = xml_obj->children; const char *id_lh   = xmlGetProp(xml_obj, "rsc"); const char *id      = xmlGetProp(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);  if(rsc_lh == NULL) { crm_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; }  if(rules == NULL) { crm_err("no rules for constraint %s", id); }  while(rules != NULL) { gboolean first_expr = TRUE; gboolean   can_run  = FALSE; gboolean   do_and   = TRUE; xmlNodePtr rule     = rules; xmlNodePtr expr     = rule->children; const char *rule_id = xmlGetProp(rule, XML_ATTR_ID); const char *score   = xmlGetProp(rule, "score"); const char *result  = xmlGetProp(rule, "result"); const char *boolean = xmlGetProp(rule, "boolean_op"); float score_f       = atof(score?score:"0.0");  rsc_to_node_t *new_con = NULL;  if(safe_str_eq(boolean, "or")) { do_and = FALSE; }  rules = rules->next; if(result == NULL || (safe_str_eq(result, "can"))) { can_run = TRUE; }  new_con = rsc2node_new(rule_id, rsc_lh, score_f, can_run, NULL, node_constraints);  if(new_con == NULL) { crm_err("couldnt create constraint %s", rule_id); continue; }   if(expr == NULL && can_run) { new_con->node_list_rh = node_list_dup(node_list,FALSE); }  while(expr != NULL) { const char *attr  = xmlGetProp(expr, "attribute"); const char *op    = xmlGetProp(expr, "operation"); const char *value = xmlGetProp(expr, "value"); const char *type  = xmlGetProp(expr, "type");  crm_trace("processing expression: %s", xmlGetProp(expr, "id"));  expr = expr->next;  GListPtr match_L = match_attrs( attr, op, value, type, node_list);  if(first_expr) { new_con->node_list_rh =	node_list_dup( match_L, FALSE); first_expr = FALSE; continue; }  GListPtr old_list = new_con->node_list_rh;  if(do_and) { crm_trace("do_and");  new_con->node_list_rh = node_list_and( old_list, match_L, FALSE); } else { crm_trace("do_or");  new_con->node_list_rh = node_list_or( old_list, match_L, FALSE); } pe_free_shallow_adv(match_L,  FALSE); pe_free_shallow_adv(old_list, TRUE);  }  if(new_con->node_list_rh == NULL) { crm_warn("No matching nodes for constraint/rule %s/%s", id, xmlGetProp(rule, "id")); } crm_debug_action(print_rsc_to_node("Added", new_con, FALSE)); } return TRUE; }
match_attrs(const char *attr, const char *op, const char *value,	    const char *type, GListPtr node_list){	int lpc = 0;	GListPtr result = NULL;		if(attr == NULL || op == NULL) {		crm_err("Invlaid attribute or operation in expression"			" (\'%s\' \'%s\' \'%s\')", attr, op, value);		return NULL;	}	slist_iter(		node, node_t, node_list, lpc,		gboolean accept = FALSE;				int cmp = 0;		const char *h_val = (const char*)g_hash_table_lookup(			node->details->attrs, attr);		if(value != NULL && h_val != NULL) {			if(type == NULL || (safe_str_eq(type, "string"))) {				cmp = strcmp(h_val, value);			} else if(safe_str_eq(type, "number")) {				float value_f = atof(value);				float h_val_f = atof(h_val);				if(h_val_f < value_f) {					cmp = -1;				} else if(h_val_f > value_f)  {					cmp = 1;				} else {					cmp = 0;				}							} else if(safe_str_eq(type, "version")) {				crm_err("Version comparisions are not yet supported");				continue;			}					} else if(value == NULL && h_val == NULL) {			cmp = 0;		} else if(value == NULL) {			cmp = 1;		} else {			cmp = -1;		}				if(safe_str_eq(op, "exists")) {			if(h_val != NULL) accept = TRUE;			} else if(safe_str_eq(op, "notexists")) {			if(h_val == NULL) accept = TRUE;		} else if(safe_str_eq(op, "eq")) {			if((h_val == value) || cmp == 0)				accept = TRUE;		} else if(safe_str_eq(op, "ne")) {			if((h_val == NULL && value != NULL)			   || (h_val != NULL && value == NULL)			   || cmp != 0)				accept = TRUE;		} else if(value == NULL || h_val == NULL) {			// the comparision is meaningless from this point on			accept = FALSE;					} else if(safe_str_eq(op, "lt")) {			if(cmp < 0) accept = TRUE;					} else if(safe_str_eq(op, "lte")) {			if(cmp <= 0) accept = TRUE;					} else if(safe_str_eq(op, "gt")) {			if(cmp > 0) accept = TRUE;					} else if(safe_str_eq(op, "gte")) {			if(cmp >= 0) accept = TRUE;					}				if(accept) {			crm_trace("node %s matched", node->details->uname);			result = g_list_append(result, node);		} else {			crm_trace("node %s did not match", node->details->uname);		}		   		);		return result;}