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";
119 uint32_t epact, diy, goldn;
123 goldn = (y % 19) + 1;
124 epact = (11 * goldn + 18) % 30;
125 if (((epact == 25) && (goldn > 11)) || (epact == 24)) {
128 return (((((diy + epact) * 6) + 11) % 177) / 22) & 7;
147 check_range(
const xmlNode *date_spec,
const char *
id,
const char *attr,
164 " %s attribute %s because '%s' is not a valid range",
167 }
else if ((low != -1) && (value < low)) {
170 }
else if ((high != -1) && (value > high)) {
176 id, attr, pcmk__s(range,
""), value,
pcmk_rc_str(rc));
195 const char *
id = NULL;
196 const char *parent_id = loggable_parent_id(date_spec);
216 if ((date_spec == NULL) || (now == NULL)) {
221 id = pcmk__xe_id(date_spec);
222 if (pcmk__str_empty(
id)) {
248 ranges[10].value = phase_of_the_moon(now);
252 "deprecated and will be removed in a future release " 257 int rc = check_range(date_spec,
id, ranges[i].attr, ranges[i].value);
268 #define ADD_COMPONENT(component) do { \ 269 int sub_rc = pcmk__add_time_from_xml(*end, component, duration); \ 270 if (sub_rc != pcmk_rc_ok) { \ 272 pcmk__config_warn("Ignoring %s in " PCMK_XE_DURATION " %s " \ 273 "because it is invalid", \ 274 pcmk__time_component_attr(component), id); \ 296 const char *
id = NULL;
297 const char *parent_id = loggable_parent_id(duration);
299 if ((start == NULL) || (duration == NULL)
300 || (end == NULL) || (*end != NULL)) {
305 id = pcmk__xe_id(duration);
306 if (pcmk__str_empty(
id)) {
343 evaluate_in_range(
const xmlNode *date_expression,
const char *
id,
369 if ((start == NULL) && (end == NULL)) {
375 "passing because in_range requires at least one of " 384 if (duration != NULL) {
407 if (next_change != NULL) {
432 evaluate_gt(
const xmlNode *date_expression,
const char *
id,
484 evaluate_lt(
const xmlNode *date_expression,
const char *
id,
537 const char *
id = NULL;
538 const char *op = NULL;
541 if ((date_expression == NULL) || (now == NULL)) {
546 id = pcmk__xe_id(date_expression);
547 if (pcmk__str_empty(
id)) {
559 rc = evaluate_in_range(date_expression,
id, now, next_change);
566 if (date_spec == NULL) {
580 rc = evaluate_gt(date_expression,
id, now, next_change);
583 rc = evaluate_lt(date_expression,
id, now, next_change);
590 " %s as not passing because '%s' is not a valid " 616 process_submatches(
const char *
string,
const char *match,
617 const regmatch_t submatches[],
int nmatches,
618 char *expansion,
size_t *nbytes)
620 bool expanded =
false;
621 const char *src = string;
623 if (nbytes != NULL) {
627 while (*src !=
'\0') {
629 size_t match_len = 0;
631 if ((src[0] !=
'%') || !isdigit(src[1])) {
635 if (expansion != NULL) {
638 if (nbytes != NULL) {
645 submatch = src[1] -
'0';
650 if ((nmatches <= submatch)
651 || (submatches[submatch].rm_so < 0)
652 || (submatches[submatch].rm_eo
653 <= submatches[submatch].rm_so)) {
657 match_len = submatches[submatch].rm_eo - submatches[submatch].rm_so;
658 if (nbytes != NULL) {
659 *nbytes += match_len;
661 if (expansion != NULL) {
662 memcpy(expansion, match + submatches[submatch].rm_so,
664 expansion += match_len;
686 const regmatch_t submatches[],
int nmatches)
691 if (pcmk__str_empty(
string) || pcmk__str_empty(match)) {
696 if (!process_submatches(
string, match, submatches, nmatches, NULL,
705 (void) process_submatches(
string, match, submatches, nmatches,
result,
766 const char *value1,
const char *value2)
774 if (((value1 != NULL) && (strchr(value1,
'.') != NULL))
775 || ((value2 != NULL) && (strchr(value2,
'.') != NULL))) {
817 if (value2 == NULL) {
818 return (value1 == NULL)? 0 : 1;
820 if (value1 == NULL) {
826 return strcasecmp(value1, value2);
835 crm_warn(
"Comparing '%s' and '%s' as strings because " 836 "invalid as integers", value1, value2);
837 return strcasecmp(value1, value2);
839 return (integer1 < integer2)? -1 : (integer1 > integer2)? 1 : 0;
851 crm_warn(
"Comparing '%s' and '%s' as strings because invalid as " 852 "numbers", value1, value2);
853 return strcasecmp(value1, value2);
855 return (num1 < num2)? -1 : (num1 > num2)? 1 : 0;
931 evaluate_attr_comparison(
const char *actual,
const char *reference,
936 switch (comparison) {
949 switch (comparison) {
960 if ((actual == NULL) || (reference == NULL)) {
964 switch (comparison) {
994 GHashTable *table = NULL;
996 if (pcmk__str_empty(value)) {
1021 if (table == NULL) {
1024 return (
const char *) g_hash_table_lookup(table, value);
1041 const char *
id = NULL;
1042 const char *op = NULL;
1043 const char *attr = NULL;
1044 const char *type_s = NULL;
1045 const char *value = NULL;
1046 const char *actual = NULL;
1047 const char *source_s = NULL;
1048 const char *reference = NULL;
1049 char *expanded_attr = NULL;
1056 if ((expression == NULL) || (rule_input == NULL)) {
1061 id = pcmk__xe_id(expression);
1062 if (pcmk__str_empty(
id)) {
1082 if (expanded_attr != NULL) {
1083 attr = expanded_attr;
1097 "passing because '%s' is not a valid " 1111 " value '%s', using default " 1118 switch (comparison) {
1121 if (value != NULL) {
1129 if (value == NULL) {
1135 reference = value_from_source(value, source, rule_input);
1139 actual = g_hash_table_lookup(rule_input->
node_attrs, attr);
1153 "is not a valid type",
id, type_s);
1156 rc = evaluate_attr_comparison(actual, reference,
type, comparison);
1157 switch (comparison) {
1166 "%s (attribute %s %s '%s' via %s source as %s type)",
1167 id,
pcmk_rc_str(rc), attr, op, pcmk__s(reference,
""),
1168 pcmk__s(source_s,
"default"), pcmk__s(type_s,
"default"));
1173 free(expanded_attr);
1191 const char *
id = NULL;
1192 const char *standard = NULL;
1193 const char *provider = NULL;
1194 const char *
type = NULL;
1196 if ((rsc_expression == NULL) || (rule_input == NULL)) {
1201 id = pcmk__xe_id(rsc_expression);
1202 if (pcmk__str_empty(
id)) {
1213 if ((standard != NULL)
1216 "actual standard '%s' doesn't match '%s'",
1223 if ((provider != NULL)
1226 "actual provider '%s' doesn't match '%s'",
1236 "actual agent '%s' doesn't match '%s'",
1242 id, pcmk__s(standard,
""),
1243 ((provider == NULL)?
"" :
":"), pcmk__s(provider,
""),
1262 const char *
id = NULL;
1263 const char *
name = NULL;
1264 const char *interval_s = NULL;
1265 guint interval_ms = 0U;
1267 if ((op_expression == NULL) || (rule_input == NULL)) {
1272 id = pcmk__xe_id(op_expression);
1273 if (pcmk__str_empty(
id)) {
1293 "passing because '%s' is not a valid interval",
1301 "actual name '%s' doesn't match '%s'",
1307 if ((interval_s != NULL) && (interval_ms != rule_input->
op_interval_ms)) {
1309 "actual interval %s doesn't match %s",
1338 if ((condition == NULL) || (rule_input == NULL)) {
1367 "because %s is not a valid condition type",
1368 pcmk__s(pcmk__xe_id(condition),
"without ID"),
1369 (
const char *) condition->name);
1390 const char *
id = NULL;
1391 const char *value = NULL;
1394 if ((rule == NULL) || (rule_input == NULL)) {
1405 id = pcmk__xe_id(rule);
1406 if (pcmk__str_empty(
id)) {
1432 pcmk__xe_id(rule), value);
1439 condition != NULL; condition = pcmk__xe_next(condition)) {
1491 bool have_rule =
false;
1498 "Support for multiple top-level rules is " 1499 "deprecated (replace with a single rule containing "
enum pcmk__type pcmk__parse_type(const char *type, enum pcmk__comparison op, const char *value1, const char *value2)
#define PCMK_VALUE_NUMBER
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.
int pcmk__xe_get_datetime(const xmlNode *xml, const char *attr, crm_time_t **t)
enum expression_type pcmk__condition_type(const xmlNode *condition)
int pcmk__evaluate_attr_expression(const xmlNode *expression, const pcmk_rule_input_t *rule_input)
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
enum crm_ais_msg_types type
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)
char int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
#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
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
#define PCMK_XE_DATE_EXPRESSION
#define PCMK_VALUE_LITERAL
#define PCMK_XE_DATE_SPEC
#define crm_trace(fmt, args...)
int pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now)
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
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)
#define pcmk__warn_once(wo_flag, fmt...)
int crm_time_compare(const crm_time_t *a, const crm_time_t *b)
#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
int pcmk__evaluate_rules(xmlNode *xml, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
#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
xmlNode * pcmk__xe_next_same(const xmlNode *node)
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)