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)