This source file includes following definitions.
- test_ruleset
- test_rule
- pe_test_rule_re
- pe_test_rule_full
- test_expression
- pe_test_expression_re
- pe_test_expression_full
- find_expression_type
- test_role_expression
- test_attr_expression
- pe_test_attr_expression_full
- phase_of_the_moon
- decodeNVpair
- cron_range_satisfied
- parse_xml_duration
- test_date_expression
- sort_pairs
- populate_hash
- get_versioned_rule
- add_versioned_attributes
- unpack_attr_set
- unpack_versioned_attr_set
- make_pairs_and_populate_data
- unpack_instance_attributes
- pe_unpack_versioned_attributes
- pe_expand_re_matches
- pe_unpack_versioned_parameters
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20 #include <crm/crm.h>
21 #include <crm/msg_xml.h>
22 #include <crm/common/xml.h>
23
24 #include <glib.h>
25
26 #include <crm/pengine/rules.h>
27 #include <crm/pengine/internal.h>
28
29 #include <sys/types.h>
30 #include <regex.h>
31 #include <ctype.h>
32
33 CRM_TRACE_INIT_DATA(pe_rules);
34
35 crm_time_t *parse_xml_duration(crm_time_t * start, xmlNode * duration_spec);
36
37 gboolean test_date_expression(xmlNode * time_expr, crm_time_t * now);
38 gboolean cron_range_satisfied(crm_time_t * now, xmlNode * cron_spec);
39 gboolean test_attr_expression(xmlNode * expr, GHashTable * hash, crm_time_t * now);
40 gboolean pe_test_attr_expression_full(xmlNode * expr, GHashTable * hash, crm_time_t * now, pe_match_data_t * match_data);
41 gboolean test_role_expression(xmlNode * expr, enum rsc_role_e role, crm_time_t * now);
42
43 gboolean
44 test_ruleset(xmlNode * ruleset, GHashTable * node_hash, crm_time_t * now)
45 {
46 gboolean ruleset_default = TRUE;
47 xmlNode *rule = NULL;
48
49 for (rule = __xml_first_child(ruleset); rule != NULL; rule = __xml_next_element(rule)) {
50 if (crm_str_eq((const char *)rule->name, XML_TAG_RULE, TRUE)) {
51 ruleset_default = FALSE;
52 if (test_rule(rule, node_hash, RSC_ROLE_UNKNOWN, now)) {
53 return TRUE;
54 }
55 }
56 }
57
58 return ruleset_default;
59 }
60
61 gboolean
62 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
63 {
64 return pe_test_rule_full(rule, node_hash, role, now, NULL);
65 }
66
67 gboolean
68 pe_test_rule_re(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data)
69 {
70 pe_match_data_t match_data = {
71 .re = re_match_data,
72 .params = NULL,
73 .meta = NULL,
74 };
75 return pe_test_rule_full(rule, node_hash, role, now, &match_data);
76 }
77
78 gboolean
79 pe_test_rule_full(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_match_data_t * match_data)
80 {
81 xmlNode *expr = NULL;
82 gboolean test = TRUE;
83 gboolean empty = TRUE;
84 gboolean passed = TRUE;
85 gboolean do_and = TRUE;
86 const char *value = NULL;
87
88 rule = expand_idref(rule, NULL);
89 value = crm_element_value(rule, XML_RULE_ATTR_BOOLEAN_OP);
90 if (safe_str_eq(value, "or")) {
91 do_and = FALSE;
92 passed = FALSE;
93 }
94
95 crm_trace("Testing rule %s", ID(rule));
96 for (expr = __xml_first_child(rule); expr != NULL; expr = __xml_next_element(expr)) {
97 test = pe_test_expression_full(expr, node_hash, role, now, match_data);
98 empty = FALSE;
99
100 if (test && do_and == FALSE) {
101 crm_trace("Expression %s/%s passed", ID(rule), ID(expr));
102 return TRUE;
103
104 } else if (test == FALSE && do_and) {
105 crm_trace("Expression %s/%s failed", ID(rule), ID(expr));
106 return FALSE;
107 }
108 }
109
110 if (empty) {
111 crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule));
112 }
113
114 crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed");
115 return passed;
116 }
117
118 gboolean
119 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
120 {
121 return pe_test_expression_full(expr, node_hash, role, now, NULL);
122 }
123
124 gboolean
125 pe_test_expression_re(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data)
126 {
127 pe_match_data_t match_data = {
128 .re = re_match_data,
129 .params = NULL,
130 .meta = NULL,
131 };
132 return pe_test_expression_full(expr, node_hash, role, now, &match_data);
133 }
134
135 gboolean
136 pe_test_expression_full(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_match_data_t * match_data)
137 {
138 gboolean accept = FALSE;
139 const char *uname = NULL;
140
141 switch (find_expression_type(expr)) {
142 case nested_rule:
143 accept = pe_test_rule_full(expr, node_hash, role, now, match_data);
144 break;
145 case attr_expr:
146 case loc_expr:
147
148
149
150 if (node_hash != NULL) {
151 accept = pe_test_attr_expression_full(expr, node_hash, now, match_data);
152 }
153 break;
154
155 case time_expr:
156 accept = test_date_expression(expr, now);
157 break;
158
159 case role_expr:
160 accept = test_role_expression(expr, role, now);
161 break;
162
163 #ifdef ENABLE_VERSIONED_ATTRS
164 case version_expr:
165 if (node_hash && g_hash_table_lookup_extended(node_hash,
166 CRM_ATTR_RA_VERSION,
167 NULL, NULL)) {
168 accept = test_attr_expression(expr, node_hash, now);
169 } else {
170
171 accept = TRUE;
172 }
173 break;
174 #endif
175
176 default:
177 CRM_CHECK(FALSE , return FALSE);
178 accept = FALSE;
179 }
180 if (node_hash) {
181 uname = g_hash_table_lookup(node_hash, CRM_ATTR_UNAME);
182 }
183
184 crm_trace("Expression %s %s on %s",
185 ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes");
186 return accept;
187 }
188
189 enum expression_type
190 find_expression_type(xmlNode * expr)
191 {
192 const char *tag = NULL;
193 const char *attr = NULL;
194
195 attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE);
196 tag = crm_element_name(expr);
197
198 if (safe_str_eq(tag, "date_expression")) {
199 return time_expr;
200
201 } else if (safe_str_eq(tag, XML_TAG_RULE)) {
202 return nested_rule;
203
204 } else if (safe_str_neq(tag, "expression")) {
205 return not_expr;
206
207 } else if (safe_str_eq(attr, CRM_ATTR_UNAME)
208 || safe_str_eq(attr, CRM_ATTR_KIND)
209 || safe_str_eq(attr, CRM_ATTR_ID)) {
210 return loc_expr;
211
212 } else if (safe_str_eq(attr, CRM_ATTR_ROLE)) {
213 return role_expr;
214
215 #ifdef ENABLE_VERSIONED_ATTRS
216 } else if (safe_str_eq(attr, CRM_ATTR_RA_VERSION)) {
217 return version_expr;
218 #endif
219 }
220
221 return attr_expr;
222 }
223
224 gboolean
225 test_role_expression(xmlNode * expr, enum rsc_role_e role, crm_time_t * now)
226 {
227 gboolean accept = FALSE;
228 const char *op = NULL;
229 const char *value = NULL;
230
231 if (role == RSC_ROLE_UNKNOWN) {
232 return accept;
233 }
234
235 value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
236 op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION);
237
238 if (safe_str_eq(op, "defined")) {
239 if (role > RSC_ROLE_STARTED) {
240 accept = TRUE;
241 }
242
243 } else if (safe_str_eq(op, "not_defined")) {
244 if (role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) {
245 accept = TRUE;
246 }
247
248 } else if (safe_str_eq(op, "eq")) {
249 if (text2role(value) == role) {
250 accept = TRUE;
251 }
252
253 } else if (safe_str_eq(op, "ne")) {
254
255 if (role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) {
256 accept = FALSE;
257
258 } else if (text2role(value) != role) {
259 accept = TRUE;
260 }
261 }
262 return accept;
263 }
264
265 gboolean
266 test_attr_expression(xmlNode * expr, GHashTable * hash, crm_time_t * now)
267 {
268 return pe_test_attr_expression_full(expr, hash, now, NULL);
269 }
270
271 gboolean
272 pe_test_attr_expression_full(xmlNode * expr, GHashTable * hash, crm_time_t * now, pe_match_data_t * match_data)
273 {
274 gboolean accept = FALSE;
275 gboolean attr_allocated = FALSE;
276 int cmp = 0;
277 const char *h_val = NULL;
278 GHashTable *table = NULL;
279
280 const char *op = NULL;
281 const char *type = NULL;
282 const char *attr = NULL;
283 const char *value = NULL;
284 const char *value_source = NULL;
285
286 attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE);
287 op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION);
288 value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
289 type = crm_element_value(expr, XML_EXPR_ATTR_TYPE);
290 value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE);
291
292 if (attr == NULL || op == NULL) {
293 pe_err("Invalid attribute or operation in expression"
294 " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value));
295 return FALSE;
296 }
297
298 if (match_data) {
299 if (match_data->re) {
300 char *resolved_attr = pe_expand_re_matches(attr, match_data->re);
301
302 if (resolved_attr) {
303 attr = (const char *) resolved_attr;
304 attr_allocated = TRUE;
305 }
306 }
307
308 if (safe_str_eq(value_source, "param")) {
309 table = match_data->params;
310 } else if (safe_str_eq(value_source, "meta")) {
311 table = match_data->meta;
312 }
313 }
314
315 if (table) {
316 const char *param_name = value;
317 const char *param_value = NULL;
318
319 if (param_name && param_name[0]) {
320 if ((param_value = (const char *)g_hash_table_lookup(table, param_name))) {
321 value = param_value;
322 }
323 }
324 }
325
326 if (hash != NULL) {
327 h_val = (const char *)g_hash_table_lookup(hash, attr);
328 }
329
330 if (attr_allocated) {
331 free((char *)attr);
332 attr = NULL;
333 }
334
335 if (value != NULL && h_val != NULL) {
336 if (type == NULL) {
337 if (safe_str_eq(op, "lt")
338 || safe_str_eq(op, "lte")
339 || safe_str_eq(op, "gt")
340 || safe_str_eq(op, "gte")) {
341 type = "number";
342
343 } else {
344 type = "string";
345 }
346 crm_trace("Defaulting to %s based comparison for '%s' op", type, op);
347 }
348
349 if (safe_str_eq(type, "string")) {
350 cmp = strcasecmp(h_val, value);
351
352 } else if (safe_str_eq(type, "number")) {
353 int h_val_f = crm_parse_int(h_val, NULL);
354 int value_f = crm_parse_int(value, NULL);
355
356 if (h_val_f < value_f) {
357 cmp = -1;
358 } else if (h_val_f > value_f) {
359 cmp = 1;
360 } else {
361 cmp = 0;
362 }
363
364 } else if (safe_str_eq(type, "version")) {
365 cmp = compare_version(h_val, value);
366
367 }
368
369 } else if (value == NULL && h_val == NULL) {
370 cmp = 0;
371 } else if (value == NULL) {
372 cmp = 1;
373 } else {
374 cmp = -1;
375 }
376
377 if (safe_str_eq(op, "defined")) {
378 if (h_val != NULL) {
379 accept = TRUE;
380 }
381
382 } else if (safe_str_eq(op, "not_defined")) {
383 if (h_val == NULL) {
384 accept = TRUE;
385 }
386
387 } else if (safe_str_eq(op, "eq")) {
388 if ((h_val == value) || cmp == 0) {
389 accept = TRUE;
390 }
391
392 } else if (safe_str_eq(op, "ne")) {
393 if ((h_val == NULL && value != NULL)
394 || (h_val != NULL && value == NULL)
395 || cmp != 0) {
396 accept = TRUE;
397 }
398
399 } else if (value == NULL || h_val == NULL) {
400
401 accept = FALSE;
402
403 } else if (safe_str_eq(op, "lt")) {
404 if (cmp < 0) {
405 accept = TRUE;
406 }
407
408 } else if (safe_str_eq(op, "lte")) {
409 if (cmp <= 0) {
410 accept = TRUE;
411 }
412
413 } else if (safe_str_eq(op, "gt")) {
414 if (cmp > 0) {
415 accept = TRUE;
416 }
417
418 } else if (safe_str_eq(op, "gte")) {
419 if (cmp >= 0) {
420 accept = TRUE;
421 }
422 }
423
424 return accept;
425 }
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444 static int
445 phase_of_the_moon(crm_time_t * now)
446 {
447 uint32_t epact, diy, goldn;
448 uint32_t y;
449
450 crm_time_get_ordinal(now, &y, &diy);
451
452 goldn = (y % 19) + 1;
453 epact = (11 * goldn + 18) % 30;
454 if ((epact == 25 && goldn > 11) || epact == 24)
455 epact++;
456
457 return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
458 }
459
460 static gboolean
461 decodeNVpair(const char *srcstring, char separator, char **name, char **value)
462 {
463 int lpc = 0;
464 int len = 0;
465 const char *temp = NULL;
466
467 CRM_ASSERT(name != NULL && value != NULL);
468 *name = NULL;
469 *value = NULL;
470
471 crm_trace("Attempting to decode: [%s]", srcstring);
472 if (srcstring != NULL) {
473 len = strlen(srcstring);
474 while (lpc <= len) {
475 if (srcstring[lpc] == separator) {
476 *name = calloc(1, lpc + 1);
477 if (*name == NULL) {
478 break;
479 }
480 memcpy(*name, srcstring, lpc);
481 (*name)[lpc] = '\0';
482
483
484
485
486 len = len - lpc;
487 len--;
488 if (len <= 0) {
489 *value = NULL;
490 } else {
491
492 *value = calloc(1, len + 1);
493 if (*value == NULL) {
494 break;
495 }
496 temp = srcstring + lpc + 1;
497 memcpy(*value, temp, len);
498 (*value)[len] = '\0';
499 }
500 return TRUE;
501 }
502 lpc++;
503 }
504 }
505
506 if (*name != NULL) {
507 free(*name);
508 *name = NULL;
509 }
510 *name = NULL;
511 *value = NULL;
512
513 return FALSE;
514 }
515
516 #define cron_check(xml_field, time_field) \
517 value = crm_element_value(cron_spec, xml_field); \
518 if(value != NULL) { \
519 gboolean pass = TRUE; \
520 decodeNVpair(value, '-', &value_low, &value_high); \
521 if(value_low == NULL) { \
522 value_low = strdup(value); \
523 } \
524 value_low_i = crm_parse_int(value_low, "0"); \
525 value_high_i = crm_parse_int(value_high, "-1"); \
526 if(value_high_i < 0) { \
527 if(value_low_i != time_field) { \
528 pass = FALSE; \
529 } \
530 } else if(value_low_i > time_field) { \
531 pass = FALSE; \
532 } else if(value_high_i < time_field) { \
533 pass = FALSE; \
534 } \
535 free(value_low); \
536 free(value_high); \
537 if(pass == FALSE) { \
538 crm_debug("Condition '%s' in %s: failed", value, xml_field); \
539 return pass; \
540 } \
541 crm_debug("Condition '%s' in %s: passed", value, xml_field); \
542 }
543
544 gboolean
545 cron_range_satisfied(crm_time_t * now, xmlNode * cron_spec)
546 {
547 const char *value = NULL;
548 char *value_low = NULL;
549 char *value_high = NULL;
550
551 int value_low_i = 0;
552 int value_high_i = 0;
553
554 uint32_t h, m, s, y, d, w;
555
556 CRM_CHECK(now != NULL, return FALSE);
557
558 crm_time_get_timeofday(now, &h, &m, &s);
559
560 cron_check("seconds", s);
561 cron_check("minutes", m);
562 cron_check("hours", h);
563
564 crm_time_get_gregorian(now, &y, &m, &d);
565
566 cron_check("monthdays", d);
567 cron_check("months", m);
568 cron_check("years", y);
569
570 crm_time_get_ordinal(now, &y, &d);
571
572 cron_check("yeardays", d);
573
574 crm_time_get_isoweek(now, &y, &w, &d);
575
576 cron_check("weekyears", y);
577 cron_check("weeks", w);
578 cron_check("weekdays", d);
579
580 cron_check("moon", phase_of_the_moon(now));
581
582 return TRUE;
583 }
584
585 #define update_field(xml_field, time_fn) \
586 value = crm_element_value(duration_spec, xml_field); \
587 if(value != NULL) { \
588 int value_i = crm_parse_int(value, "0"); \
589 time_fn(end, value_i); \
590 }
591
592 crm_time_t *
593 parse_xml_duration(crm_time_t * start, xmlNode * duration_spec)
594 {
595 crm_time_t *end = NULL;
596 const char *value = NULL;
597
598 end = crm_time_new(NULL);
599 crm_time_set(end, start);
600
601 update_field("years", crm_time_add_years);
602 update_field("months", crm_time_add_months);
603 update_field("weeks", crm_time_add_weeks);
604 update_field("days", crm_time_add_days);
605 update_field("hours", crm_time_add_hours);
606 update_field("minutes", crm_time_add_minutes);
607 update_field("seconds", crm_time_add_seconds);
608
609 return end;
610 }
611
612 gboolean
613 test_date_expression(xmlNode * time_expr, crm_time_t * now)
614 {
615 crm_time_t *start = NULL;
616 crm_time_t *end = NULL;
617 const char *value = NULL;
618 const char *op = crm_element_value(time_expr, "operation");
619
620 xmlNode *duration_spec = NULL;
621 xmlNode *date_spec = NULL;
622
623 gboolean passed = FALSE;
624
625 crm_trace("Testing expression: %s", ID(time_expr));
626
627 duration_spec = first_named_child(time_expr, "duration");
628 date_spec = first_named_child(time_expr, "date_spec");
629
630 value = crm_element_value(time_expr, "start");
631 if (value != NULL) {
632 start = crm_time_new(value);
633 }
634 value = crm_element_value(time_expr, "end");
635 if (value != NULL) {
636 end = crm_time_new(value);
637 }
638
639 if (start != NULL && end == NULL && duration_spec != NULL) {
640 end = parse_xml_duration(start, duration_spec);
641 }
642 if (op == NULL) {
643 op = "in_range";
644 }
645
646 if (safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range")) {
647 if (start != NULL && crm_time_compare(start, now) > 0) {
648 passed = FALSE;
649 } else if (end != NULL && crm_time_compare(end, now) < 0) {
650 passed = FALSE;
651 } else if (safe_str_eq(op, "in_range")) {
652 passed = TRUE;
653 } else {
654 passed = cron_range_satisfied(now, date_spec);
655 }
656
657 } else if (safe_str_eq(op, "gt") && crm_time_compare(start, now) < 0) {
658 passed = TRUE;
659
660 } else if (safe_str_eq(op, "lt") && crm_time_compare(end, now) > 0) {
661 passed = TRUE;
662
663 } else if (safe_str_eq(op, "eq") && crm_time_compare(start, now) == 0) {
664 passed = TRUE;
665
666 } else if (safe_str_eq(op, "neq") && crm_time_compare(start, now) != 0) {
667 passed = TRUE;
668 }
669
670 crm_time_free(start);
671 crm_time_free(end);
672 return passed;
673 }
674
675 typedef struct sorted_set_s {
676 int score;
677 const char *name;
678 const char *special_name;
679 xmlNode *attr_set;
680 } sorted_set_t;
681
682 static gint
683 sort_pairs(gconstpointer a, gconstpointer b)
684 {
685 const sorted_set_t *pair_a = a;
686 const sorted_set_t *pair_b = b;
687
688 if (a == NULL && b == NULL) {
689 return 0;
690 } else if (a == NULL) {
691 return 1;
692 } else if (b == NULL) {
693 return -1;
694 }
695
696 if (safe_str_eq(pair_a->name, pair_a->special_name)) {
697 return -1;
698
699 } else if (safe_str_eq(pair_b->name, pair_a->special_name)) {
700 return 1;
701 }
702
703 if (pair_a->score < pair_b->score) {
704 return 1;
705 } else if (pair_a->score > pair_b->score) {
706 return -1;
707 }
708 return 0;
709 }
710
711 static void
712 populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlNode * top)
713 {
714 const char *name = NULL;
715 const char *value = NULL;
716 const char *old_value = NULL;
717 xmlNode *list = nvpair_list;
718 xmlNode *an_attr = NULL;
719
720 name = crm_element_name(list->children);
721 if (safe_str_eq(XML_TAG_ATTRS, name)) {
722 list = list->children;
723 }
724
725 for (an_attr = __xml_first_child(list); an_attr != NULL; an_attr = __xml_next_element(an_attr)) {
726 if (crm_str_eq((const char *)an_attr->name, XML_CIB_TAG_NVPAIR, TRUE)) {
727 xmlNode *ref_nvpair = expand_idref(an_attr, top);
728
729 name = crm_element_value(an_attr, XML_NVPAIR_ATTR_NAME);
730 if (name == NULL) {
731 name = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_NAME);
732 }
733
734 crm_trace("Setting attribute: %s", name);
735 value = crm_element_value(an_attr, XML_NVPAIR_ATTR_VALUE);
736 if (value == NULL) {
737 value = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_VALUE);
738 }
739
740 if (name == NULL || value == NULL) {
741 continue;
742
743 }
744
745 old_value = g_hash_table_lookup(hash, name);
746
747 if (safe_str_eq(value, "#default")) {
748 if (old_value) {
749 crm_trace("Removing value for %s (%s)", name, value);
750 g_hash_table_remove(hash, name);
751 }
752 continue;
753
754 } else if (old_value == NULL) {
755 g_hash_table_insert(hash, strdup(name), strdup(value));
756
757 } else if (overwrite) {
758 crm_debug("Overwriting value of %s: %s -> %s", name, old_value, value);
759 g_hash_table_replace(hash, strdup(name), strdup(value));
760 }
761 }
762 }
763 }
764
765 #ifdef ENABLE_VERSIONED_ATTRS
766 static xmlNode*
767 get_versioned_rule(xmlNode * attr_set)
768 {
769 xmlNode * rule = NULL;
770 xmlNode * expr = NULL;
771
772 for (rule = __xml_first_child(attr_set); rule != NULL; rule = __xml_next_element(rule)) {
773 if (crm_str_eq((const char *)rule->name, XML_TAG_RULE, TRUE)) {
774 for (expr = __xml_first_child(rule); expr != NULL; expr = __xml_next_element(expr)) {
775 if (find_expression_type(expr) == version_expr) {
776 return rule;
777 }
778 }
779 }
780 }
781
782 return NULL;
783 }
784
785 static void
786 add_versioned_attributes(xmlNode * attr_set, xmlNode * versioned_attrs)
787 {
788 xmlNode *attr_set_copy = NULL;
789 xmlNode *rule = NULL;
790 xmlNode *expr = NULL;
791
792 if (!attr_set || !versioned_attrs) {
793 return;
794 }
795
796 attr_set_copy = copy_xml(attr_set);
797
798 rule = get_versioned_rule(attr_set_copy);
799 if (!rule) {
800 free_xml(attr_set_copy);
801 return;
802 }
803
804 expr = __xml_first_child(rule);
805 while (expr != NULL) {
806 if (find_expression_type(expr) != version_expr) {
807 xmlNode *node = expr;
808
809 expr = __xml_next_element(expr);
810 free_xml(node);
811 } else {
812 expr = __xml_next_element(expr);
813 }
814 }
815
816 add_node_nocopy(versioned_attrs, NULL, attr_set_copy);
817 }
818 #endif
819
820 typedef struct unpack_data_s {
821 gboolean overwrite;
822 GHashTable *node_hash;
823 void *hash;
824 crm_time_t *now;
825 xmlNode *top;
826 } unpack_data_t;
827
828 static void
829 unpack_attr_set(gpointer data, gpointer user_data)
830 {
831 sorted_set_t *pair = data;
832 unpack_data_t *unpack_data = user_data;
833
834 if (test_ruleset(pair->attr_set, unpack_data->node_hash, unpack_data->now) == FALSE) {
835 return;
836 }
837
838 #ifdef ENABLE_VERSIONED_ATTRS
839 if (get_versioned_rule(pair->attr_set) && !(unpack_data->node_hash &&
840 g_hash_table_lookup_extended(unpack_data->node_hash,
841 CRM_ATTR_RA_VERSION, NULL, NULL))) {
842
843 return;
844 }
845 #endif
846
847 crm_trace("Adding attributes from %s", pair->name);
848 populate_hash(pair->attr_set, unpack_data->hash, unpack_data->overwrite, unpack_data->top);
849 }
850
851 #ifdef ENABLE_VERSIONED_ATTRS
852 static void
853 unpack_versioned_attr_set(gpointer data, gpointer user_data)
854 {
855 sorted_set_t *pair = data;
856 unpack_data_t *unpack_data = user_data;
857
858 if (test_ruleset(pair->attr_set, unpack_data->node_hash, unpack_data->now) == FALSE) {
859 return;
860 }
861
862 add_versioned_attributes(pair->attr_set, unpack_data->hash);
863 }
864 #endif
865
866 static GListPtr
867 make_pairs_and_populate_data(xmlNode * top, xmlNode * xml_obj, const char *set_name,
868 GHashTable * node_hash, void * hash, const char *always_first,
869 gboolean overwrite, crm_time_t * now, unpack_data_t * data)
870 {
871 GListPtr unsorted = NULL;
872 const char *score = NULL;
873 sorted_set_t *pair = NULL;
874 xmlNode *attr_set = NULL;
875
876 if (xml_obj == NULL) {
877 crm_trace("No instance attributes");
878 return NULL;
879 }
880
881 crm_trace("Checking for attributes");
882 for (attr_set = __xml_first_child(xml_obj); attr_set != NULL; attr_set = __xml_next_element(attr_set)) {
883
884 if (set_name == NULL || crm_str_eq((const char *)attr_set->name, set_name, TRUE)) {
885 pair = NULL;
886 attr_set = expand_idref(attr_set, top);
887 if (attr_set == NULL) {
888 continue;
889 }
890
891 pair = calloc(1, sizeof(sorted_set_t));
892 pair->name = ID(attr_set);
893 pair->special_name = always_first;
894 pair->attr_set = attr_set;
895
896 score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE);
897 pair->score = char2score(score);
898
899 unsorted = g_list_prepend(unsorted, pair);
900 }
901 }
902
903 if (pair != NULL) {
904 data->hash = hash;
905 data->node_hash = node_hash;
906 data->now = now;
907 data->overwrite = overwrite;
908 data->top = top;
909 }
910
911 if (unsorted) {
912 return g_list_sort(unsorted, sort_pairs);
913 }
914
915 return NULL;
916 }
917
918 void
919 unpack_instance_attributes(xmlNode * top, xmlNode * xml_obj, const char *set_name,
920 GHashTable * node_hash, GHashTable * hash, const char *always_first,
921 gboolean overwrite, crm_time_t * now)
922 {
923 unpack_data_t data;
924 GListPtr pairs = make_pairs_and_populate_data(top, xml_obj, set_name, node_hash, hash,
925 always_first, overwrite, now, &data);
926
927 if (pairs) {
928 g_list_foreach(pairs, unpack_attr_set, &data);
929 g_list_free_full(pairs, free);
930 }
931 }
932
933 #ifdef ENABLE_VERSIONED_ATTRS
934 void
935 pe_unpack_versioned_attributes(xmlNode * top, xmlNode * xml_obj, const char *set_name,
936 GHashTable * node_hash, xmlNode * hash, crm_time_t * now)
937 {
938 unpack_data_t data;
939 GListPtr pairs = make_pairs_and_populate_data(top, xml_obj, set_name, node_hash, hash,
940 NULL, FALSE, now, &data);
941
942 if (pairs) {
943 g_list_foreach(pairs, unpack_versioned_attr_set, &data);
944 g_list_free_full(pairs, free);
945 }
946 }
947 #endif
948
949 char *
950 pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
951 {
952 size_t len = 0;
953 int i;
954 const char *p, *last_match_index;
955 char *p_dst, *result = NULL;
956
957 if (!string || string[0] == '\0' || !match_data) {
958 return NULL;
959 }
960
961 p = last_match_index = string;
962
963 while (*p) {
964 if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
965 i = *(p + 1) - '0';
966 if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
967 match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
968 len += p - last_match_index + (match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so);
969 last_match_index = p + 2;
970 }
971 p++;
972 }
973 p++;
974 }
975 len += p - last_match_index + 1;
976
977
978 if (len - 1 <= 0) {
979 return NULL;
980 }
981
982 p_dst = result = calloc(1, len);
983 p = string;
984
985 while (*p) {
986 if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
987 i = *(p + 1) - '0';
988 if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
989 match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
990
991 int match_len = match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so;
992 memcpy(p_dst, match_data->string + match_data->pmatch[i].rm_so, match_len);
993 p_dst += match_len;
994 }
995 p++;
996 } else {
997 *(p_dst) = *(p);
998 p_dst++;
999 }
1000 p++;
1001 }
1002
1003 return result;
1004 }
1005
1006 #ifdef ENABLE_VERSIONED_ATTRS
1007 GHashTable*
1008 pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version)
1009 {
1010 GHashTable *hash = crm_str_table_new();
1011
1012 if (versioned_params && ra_version) {
1013 GHashTable *node_hash = crm_str_table_new();
1014 xmlNode *attr_set = __xml_first_child(versioned_params);
1015
1016 if (attr_set) {
1017 g_hash_table_insert(node_hash, strdup(CRM_ATTR_RA_VERSION),
1018 strdup(ra_version));
1019 unpack_instance_attributes(NULL, versioned_params, crm_element_name(attr_set),
1020 node_hash, hash, NULL, FALSE, NULL);
1021 }
1022
1023 g_hash_table_destroy(node_hash);
1024 }
1025
1026 return hash;
1027 }
1028 #endif