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: %s", \ 274 pcmk__time_component_attr(component), id, \ 275 pcmk_rc_str(sub_rc)); \ 297 const char *
id = NULL;
298 const char *parent_id = loggable_parent_id(duration);
300 if ((start == NULL) || (duration == NULL)
301 || (end == NULL) || (*end != NULL)) {
306 id = pcmk__xe_id(duration);
307 if (pcmk__str_empty(
id)) {
344 evaluate_in_range(
const xmlNode *date_expression,
const char *
id,
370 if ((start == NULL) && (end == NULL)) {
376 "passing because in_range requires at least one of " 385 if (duration != NULL) {
408 if (next_change != NULL) {
433 evaluate_gt(
const xmlNode *date_expression,
const char *
id,
485 evaluate_lt(
const xmlNode *date_expression,
const char *
id,
538 const char *
id = NULL;
539 const char *op = NULL;
542 if ((date_expression == NULL) || (now == NULL)) {
547 id = pcmk__xe_id(date_expression);
548 if (pcmk__str_empty(
id)) {
560 rc = evaluate_in_range(date_expression,
id, now, next_change);
567 if (date_spec == NULL) {
581 rc = evaluate_gt(date_expression,
id, now, next_change);
584 rc = evaluate_lt(date_expression,
id, now, next_change);
591 " %s as not passing because '%s' is not a valid " 617 process_submatches(
const char *
string,
const char *match,
618 const regmatch_t submatches[],
int nmatches,
619 char *expansion,
size_t *nbytes)
621 bool expanded =
false;
622 const char *src = string;
624 if (nbytes != NULL) {
628 while (*src !=
'\0') {
630 size_t match_len = 0;
632 if ((src[0] !=
'%') || !isdigit(src[1])) {
636 if (expansion != NULL) {
639 if (nbytes != NULL) {
646 submatch = src[1] -
'0';
651 if ((nmatches <= submatch)
652 || (submatches[submatch].rm_so < 0)
653 || (submatches[submatch].rm_eo
654 <= submatches[submatch].rm_so)) {
658 match_len = submatches[submatch].rm_eo - submatches[submatch].rm_so;
659 if (nbytes != NULL) {
660 *nbytes += match_len;
662 if (expansion != NULL) {
663 memcpy(expansion, match + submatches[submatch].rm_so,
665 expansion += match_len;
687 const regmatch_t submatches[],
int nmatches)
692 if (pcmk__str_empty(
string) || pcmk__str_empty(match)) {
697 if (!process_submatches(
string, match, submatches, nmatches, NULL,
706 (void) process_submatches(
string, match, submatches, nmatches,
result,
767 const char *value1,
const char *value2)
775 if (((value1 != NULL) && (strchr(value1,
'.') != NULL))
776 || ((value2 != NULL) && (strchr(value2,
'.') != NULL))) {
818 if (value2 == NULL) {
819 return (value1 == NULL)? 0 : 1;
821 if (value1 == NULL) {
827 return strcasecmp(value1, value2);
836 crm_warn(
"Comparing '%s' and '%s' as strings because " 837 "invalid as integers", value1, value2);
838 return strcasecmp(value1, value2);
840 return (integer1 < integer2)? -1 : (integer1 > integer2)? 1 : 0;
852 crm_warn(
"Comparing '%s' and '%s' as strings because invalid as " 853 "numbers", value1, value2);
854 return strcasecmp(value1, value2);
856 return (num1 < num2)? -1 : (num1 > num2)? 1 : 0;
932 evaluate_attr_comparison(
const char *actual,
const char *reference,
937 switch (comparison) {
950 switch (comparison) {
961 if ((actual == NULL) || (reference == NULL)) {
965 switch (comparison) {
995 GHashTable *table = NULL;
997 if (pcmk__str_empty(value)) {
1022 if (table == NULL) {
1025 return (
const char *) g_hash_table_lookup(table, value);
1042 const char *
id = NULL;
1043 const char *op = NULL;
1044 const char *attr = NULL;
1045 const char *type_s = NULL;
1046 const char *value = NULL;
1047 const char *actual = NULL;
1048 const char *source_s = NULL;
1049 const char *reference = NULL;
1050 char *expanded_attr = NULL;
1057 if ((expression == NULL) || (rule_input == NULL)) {
1062 id = pcmk__xe_id(expression);
1063 if (pcmk__str_empty(
id)) {
1083 if (expanded_attr != NULL) {
1084 attr = expanded_attr;
1098 "passing because '%s' is not a valid " 1112 " value '%s', using default " 1119 switch (comparison) {
1122 if (value != NULL) {
1130 if (value == NULL) {
1136 reference = value_from_source(value, source, rule_input);
1140 actual = g_hash_table_lookup(rule_input->
node_attrs, attr);
1154 "is not a valid type",
id, type_s);
1157 rc = evaluate_attr_comparison(actual, reference,
type, comparison);
1158 switch (comparison) {
1167 "%s (attribute %s %s '%s' via %s source as %s type)",
1168 id,
pcmk_rc_str(rc), attr, op, pcmk__s(reference,
""),
1169 pcmk__s(source_s,
"default"), pcmk__s(type_s,
"default"));
1174 free(expanded_attr);
1192 const char *
id = NULL;
1193 const char *standard = NULL;
1194 const char *provider = NULL;
1195 const char *
type = NULL;
1197 if ((rsc_expression == NULL) || (rule_input == NULL)) {
1202 id = pcmk__xe_id(rsc_expression);
1203 if (pcmk__str_empty(
id)) {
1214 if ((standard != NULL)
1217 "actual standard '%s' doesn't match '%s'",
1224 if ((provider != NULL)
1227 "actual provider '%s' doesn't match '%s'",
1237 "actual agent '%s' doesn't match '%s'",
1243 id, pcmk__s(standard,
""),
1244 ((provider == NULL)?
"" :
":"), pcmk__s(provider,
""),
1263 const char *
id = NULL;
1264 const char *
name = NULL;
1265 const char *interval_s = NULL;
1266 guint interval_ms = 0U;
1268 if ((op_expression == NULL) || (rule_input == NULL)) {
1273 id = pcmk__xe_id(op_expression);
1274 if (pcmk__str_empty(
id)) {
1294 "passing because '%s' is not a valid interval",
1302 "actual name '%s' doesn't match '%s'",
1308 if ((interval_s != NULL) && (interval_ms != rule_input->
op_interval_ms)) {
1310 "actual interval %s doesn't match %s",
1339 if ((condition == NULL) || (rule_input == NULL)) {
1368 "because %s is not a valid condition type",
1369 pcmk__s(pcmk__xe_id(condition),
"without ID"),
1370 (
const char *) condition->name);
1391 const char *
id = NULL;
1392 const char *value = NULL;
1395 if ((rule == NULL) || (rule_input == NULL)) {
1406 id = pcmk__xe_id(rule);
1407 if (pcmk__str_empty(
id)) {
1433 pcmk__xe_id(rule), value);
1440 condition != NULL; condition = pcmk__xe_next(condition)) {
1492 bool have_rule =
false;
1499 "Support for multiple top-level rules is " 1500 "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)