19 #include <libxml/tree.h> 39 const char *
name = NULL;
80 loggable_parent_id(
const xmlNode *xml)
83 const char *parent_id =
"implied";
85 if ((xml != NULL) && (xml->parent != NULL)) {
86 parent_id = pcmk__xe_id(xml->parent);
87 if (parent_id == NULL) {
88 parent_id =
"without ID";
110 check_range(
const xmlNode *date_spec,
const char *
id,
const char *attr,
123 "as not passing because '%s' is not a valid range " 128 }
else if ((low != -1) && (value < low)) {
131 }
else if ((high != -1) && (value > high)) {
136 " %s='%s' for %" PRIu32
": %s",
137 id, attr, pcmk__s(range,
""), value,
pcmk_rc_str(rc));
156 const char *
id = NULL;
157 const char *parent_id = loggable_parent_id(date_spec);
176 if ((date_spec == NULL) || (now == NULL)) {
181 id = pcmk__xe_id(date_spec);
182 if (pcmk__str_empty(
id)) {
205 int rc = check_range(date_spec, parent_id, ranges[i].attr,
217 #define ADD_COMPONENT(component) do { \ 218 int rc = pcmk__add_time_from_xml(*end, component, duration); \ 219 if (rc != pcmk_rc_ok) { \ 220 pcmk__config_err("Treating " PCMK_XE_DATE_EXPRESSION " %s " \ 221 "as not passing because " PCMK_XE_DURATION \ 222 " %s attribute %s is invalid: %s", \ 224 pcmk__time_component_attr(component), \ 226 crm_time_free(*end); \ 248 const char *
id = NULL;
249 const char *parent_id = loggable_parent_id(duration);
251 if ((start == NULL) || (duration == NULL)
252 || (end == NULL) || (*end != NULL)) {
257 id = pcmk__xe_id(duration);
258 if (pcmk__str_empty(
id)) {
292 evaluate_in_range(
const xmlNode *date_expression,
const char *
id,
313 if ((start == NULL) && (end == NULL)) {
326 if (duration != NULL) {
331 " %s as not passing because duration " 354 if (next_change != NULL) {
379 evaluate_gt(
const xmlNode *date_expression,
const char *
id,
425 evaluate_lt(
const xmlNode *date_expression,
const char *
id,
472 const char *
id = NULL;
473 const char *op = NULL;
476 if ((date_expression == NULL) || (now == NULL)) {
481 id = pcmk__xe_id(date_expression);
482 if (pcmk__str_empty(
id)) {
491 rc = evaluate_in_range(date_expression,
id, now, next_change);
498 if (date_spec == NULL) {
510 rc = evaluate_gt(date_expression,
id, now, next_change);
513 rc = evaluate_lt(date_expression,
id, now, next_change);
517 " %s as not passing because '%s' is not a valid " 544 process_submatches(
const char *
string,
const char *match,
545 const regmatch_t submatches[],
int nmatches,
546 char *expansion,
size_t *nbytes)
548 bool expanded =
false;
549 const char *src = string;
551 if (nbytes != NULL) {
555 while (*src !=
'\0') {
557 size_t match_len = 0;
559 if ((src[0] !=
'%') || !isdigit(src[1])) {
563 if (expansion != NULL) {
566 if (nbytes != NULL) {
573 submatch = src[1] -
'0';
578 if ((nmatches <= submatch)
579 || (submatches[submatch].rm_so < 0)
580 || (submatches[submatch].rm_eo
581 <= submatches[submatch].rm_so)) {
585 match_len = submatches[submatch].rm_eo - submatches[submatch].rm_so;
586 if (nbytes != NULL) {
587 *nbytes += match_len;
589 if (expansion != NULL) {
590 memcpy(expansion, match + submatches[submatch].rm_so,
592 expansion += match_len;
614 const regmatch_t submatches[],
int nmatches)
619 if (pcmk__str_empty(
string) || pcmk__str_empty(match)) {
624 if (!process_submatches(
string, match, submatches, nmatches, NULL,
633 (void) process_submatches(
string, match, submatches, nmatches,
result,
694 const char *value1,
const char *value2)
702 if (((value1 != NULL) && (strchr(value1,
'.') != NULL))
703 || ((value2 != NULL) && (strchr(value2,
'.') != NULL))) {
745 if (value2 == NULL) {
746 return (value1 == NULL)? 0 : 1;
748 if (value1 == NULL) {
754 return strcasecmp(value1, value2);
763 crm_warn(
"Comparing '%s' and '%s' as strings because " 764 "invalid as integers", value1, value2);
765 return strcasecmp(value1, value2);
767 return (integer1 < integer2)? -1 : (integer1 > integer2)? 1 : 0;
779 crm_warn(
"Comparing '%s' and '%s' as strings because invalid as " 780 "numbers", value1, value2);
781 return strcasecmp(value1, value2);
783 return (num1 < num2)? -1 : (num1 > num2)? 1 : 0;
859 evaluate_attr_comparison(
const char *actual,
const char *reference,
864 switch (comparison) {
877 switch (comparison) {
888 if ((actual == NULL) || (reference == NULL)) {
892 switch (comparison) {
922 GHashTable *table = NULL;
943 return (
const char *) g_hash_table_lookup(table, value);
960 const char *
id = NULL;
961 const char *op = NULL;
962 const char *attr = NULL;
963 const char *type_s = NULL;
964 const char *value = NULL;
965 const char *actual = NULL;
966 const char *source_s = NULL;
967 const char *reference = NULL;
968 char *expanded_attr = NULL;
975 if ((expression == NULL) || (rule_input == NULL)) {
980 id = pcmk__xe_id(expression);
981 if (pcmk__str_empty(
id)) {
999 if (expanded_attr != NULL) {
1000 attr = expanded_attr;
1014 "passing because '%s' is not a valid " 1035 switch (comparison) {
1038 if (value != NULL) {
1049 if (value == NULL) {
1057 reference = value_from_source(value, source, rule_input);
1063 actual = g_hash_table_lookup(rule_input->
node_attrs, attr);
1072 "because '%s' is not a valid type",
id, type_s);
1077 rc = evaluate_attr_comparison(actual, reference,
type, comparison);
1078 switch (comparison) {
1087 "%s (attribute %s %s '%s' via %s source as %s type)",
1088 id,
pcmk_rc_str(rc), attr, op, pcmk__s(reference,
""),
1089 pcmk__s(source_s,
"default"), pcmk__s(type_s,
"default"));
1094 free(expanded_attr);
1112 const char *
id = NULL;
1113 const char *standard = NULL;
1114 const char *provider = NULL;
1115 const char *
type = NULL;
1117 if ((rsc_expression == NULL) || (rule_input == NULL)) {
1122 id = pcmk__xe_id(rsc_expression);
1123 if (pcmk__str_empty(
id)) {
1132 if ((standard != NULL)
1135 "actual standard '%s' doesn't match '%s'",
1142 if ((provider != NULL)
1145 "actual provider '%s' doesn't match '%s'",
1155 "actual agent '%s' doesn't match '%s'",
1161 id, pcmk__s(standard,
""),
1162 ((provider == NULL)?
"" :
":"), pcmk__s(provider,
""),
1181 const char *
id = NULL;
1182 const char *
name = NULL;
1183 const char *interval_s = NULL;
1184 guint interval_ms = 0U;
1186 if ((op_expression == NULL) || (rule_input == NULL)) {
1191 id = pcmk__xe_id(op_expression);
1192 if (pcmk__str_empty(
id)) {
1210 "passing because '%s' is not a valid " 1219 "actual name '%s' doesn't match '%s'",
1225 if ((interval_s != NULL) && (interval_ms != rule_input->
op_interval_ms)) {
1227 "actual interval %s doesn't match %s",
1256 if ((condition == NULL) || (rule_input == NULL)) {
1285 "because %s is not a valid condition type",
1286 pcmk__s(pcmk__xe_id(condition),
"without ID"),
1287 (
const char *) condition->name);
1308 const char *
id = NULL;
1309 const char *value = NULL;
1312 if ((rule == NULL) || (rule_input == NULL)) {
1323 id = pcmk__xe_id(rule);
1324 if (pcmk__str_empty(
id)) {
1351 condition != NULL; condition =
pcmk__xe_next(condition, NULL)) {
xmlNode * pcmk__xe_resolve_idref(xmlNode *xml, xmlNode *search)
enum pcmk__type pcmk__parse_type(const char *type, enum pcmk__comparison op, const char *value1, const char *value2)
#define PCMK_VALUE_NUMBER
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
Evaluate a single rule, including all its conditions.
int crm_time_get_isoweek(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d)
void crm_time_add_seconds(crm_time_t *dt, int value)
Add a given number of seconds to a date/time or duration.
enum expression_type pcmk__condition_type(const xmlNode *condition)
int pcmk__evaluate_attr_expression(const xmlNode *expression, const pcmk_rule_input_t *rule_input)
enum pcmk_ipc_server type
struct crm_time_s crm_time_t
#define PCMK_VALUE_DATE_SPEC
#define pcmk__config_warn(fmt...)
#define PCMK_XA_WEEKYEARS
#define PCMK_VALUE_NOT_DEFINED
#define pcmk__config_err(fmt...)
enum pcmk__comparison pcmk__parse_comparison(const char *op)
crm_time_t * pcmk_copy_time(const crm_time_t *source)
#define PCMK_XE_EXPRESSION
int pcmk__unpack_duration(const xmlNode *duration, const crm_time_t *start, crm_time_t **end)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d)
#define PCMK_XA_OPERATION
enum pcmk__reference_source pcmk__parse_source(const char *source)
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
int pcmk__xe_get_datetime(const xmlNode *xml, const char *attr, crm_time_t **t)
#define crm_warn(fmt, args...)
int pcmk__evaluate_op_expression(const xmlNode *op_expression, const pcmk_rule_input_t *rule_input)
#define PCMK_XE_OP_EXPRESSION
#define PCMK_XE_DATE_EXPRESSION
#define PCMK_VALUE_LITERAL
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
#define PCMK_XE_DATE_SPEC
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
#define crm_trace(fmt, args...)
int pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now)
enum pcmk__combine pcmk__parse_combine(const char *combine)
#define PCMK_VALUE_IN_RANGE
int pcmk__evaluate_condition(xmlNode *condition, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
#define PCMK_XE_RSC_EXPRESSION
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
int crm_time_compare(const crm_time_t *a, const crm_time_t *b)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
#define PCMK_XA_MONTHDAYS
int pcmk__evaluate_date_expression(const xmlNode *date_expression, const crm_time_t *now, crm_time_t *next_change)
#define PCMK_META_INTERVAL
pcmk__action_result_t result
char * pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches)
G_GNUC_INTERNAL void pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source)
#define PCMK_XE_OPERATION
int compare_version(const char *version1, const char *version2)
#define PCMK_XA_ATTRIBUTE
#define PCMK_VALUE_VERSION
#define PCMK_VALUE_STRING
#define PCMK_XA_BOOLEAN_OP
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
const char * pcmk__readable_interval(guint interval_ms)
#define PCMK_VALUE_INTEGER
int pcmk__cmp_by_type(const char *value1, const char *value2, enum pcmk__type type)
#define PCMK_VALUE_DEFINED
#define pcmk__assert_alloc(nmemb, size)
#define PCMK_XA_VALUE_SOURCE
int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s)
#define ADD_COMPONENT(component)
int pcmk__evaluate_rsc_expression(const xmlNode *rsc_expression, const pcmk_rule_input_t *rule_input)
void crm_time_free(crm_time_t *dt)