/* * Returned value should be freed with xmlFree(). */ static char *cx_get_text_node_value(xmlXPathContextPtr xpath_ctx, /* {{{ */ char *expr, const char *from_option) { xmlXPathObjectPtr values_node_obj = cx_evaluate_xpath(xpath_ctx, expr); if (values_node_obj == NULL) return NULL; /* Error already logged. */ xmlNodeSetPtr values_node = values_node_obj->nodesetval; size_t tmp_size = (values_node) ? values_node->nodeNr : 0; if (tmp_size == 0) { WARNING("curl_xml plugin: " "relative xpath expression \"%s\" from '%s' doesn't match " "any of the nodes.", expr, from_option); xmlXPathFreeObject(values_node_obj); return NULL; } if (tmp_size > 1) { WARNING("curl_xml plugin: " "relative xpath expression \"%s\" from '%s' is expected to return " "only one text node. Skipping the node.", expr, from_option); xmlXPathFreeObject(values_node_obj); return NULL; } /* ignoring the element if other than textnode/attribute*/ if (cx_if_not_text_node(values_node->nodeTab[0])) { WARNING("curl_xml plugin: " "relative xpath expression \"%s\" from '%s' is expected to return " "only text/attribute node which is not the case. " "Skipping the node.", expr, from_option); xmlXPathFreeObject(values_node_obj); return NULL; } char *node_value = (char *)xmlNodeGetContent(values_node->nodeTab[0]); /* free up object */ xmlXPathFreeObject(values_node_obj); return node_value; } /* }}} char * cx_get_text_node_value */
static int cx_handle_base_xpath (char const *plugin_instance, /* {{{ */ char const *host, xmlXPathContextPtr xpath_ctx, const data_set_t *ds, char *base_xpath, cx_xpath_t *xpath) { int total_nodes; int i; xmlXPathObjectPtr base_node_obj = NULL; xmlNodeSetPtr base_nodes = NULL; value_list_t vl = VALUE_LIST_INIT; base_node_obj = cx_evaluate_xpath (xpath_ctx, BAD_CAST base_xpath); if (base_node_obj == NULL) return -1; /* error is logged already */ base_nodes = base_node_obj->nodesetval; total_nodes = (base_nodes) ? base_nodes->nodeNr : 0; if (total_nodes == 0) { ERROR ("curl_xml plugin: " "xpath expression \"%s\" doesn't match any of the nodes. " "Skipping the xpath block...", base_xpath); xmlXPathFreeObject (base_node_obj); return -1; } /* If base_xpath returned multiple results, then */ /* Instance in the xpath block is required */ if (total_nodes > 1 && xpath->instance == NULL) { ERROR ("curl_xml plugin: " "InstanceFrom is must in xpath block since the base xpath expression \"%s\" " "returned multiple results. Skipping the xpath block...", base_xpath); return -1; } /* set the values for the value_list */ vl.values_len = ds->ds_num; sstrncpy (vl.type, xpath->type, sizeof (vl.type)); sstrncpy (vl.plugin, "curl_xml", sizeof (vl.plugin)); sstrncpy (vl.host, (host != NULL) ? host : hostname_g, sizeof (vl.host)); if (plugin_instance != NULL) sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); for (i = 0; i < total_nodes; i++) { int status; xpath_ctx->node = base_nodes->nodeTab[i]; status = cx_handle_instance_xpath (xpath_ctx, xpath, &vl, /* is_table = */ (total_nodes > 1)); if (status != 0) continue; /* An error has already been reported. */ status = cx_handle_all_value_xpaths (xpath_ctx, xpath, ds, &vl); if (status != 0) continue; /* An error has been logged. */ } /* for (i = 0; i < total_nodes; i++) */ /* free up the allocated memory */ xmlXPathFreeObject (base_node_obj); return (0); } /* }}} cx_handle_base_xpath */
static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ cx_xpath_t *xpath, value_list_t *vl, _Bool is_table) { xmlXPathObjectPtr instance_node_obj = NULL; xmlNodeSetPtr instance_node = NULL; memset (vl->type_instance, 0, sizeof (vl->type_instance)); /* If the base xpath returns more than one block, the result is assumed to be * a table. The `Instance' option is not optional in this case. Check for the * condition and inform the user. */ if (is_table && (xpath->instance == NULL)) { WARNING ("curl_xml plugin: " "Base-XPath %s is a table (more than one result was returned), " "but no instance-XPath has been defined.", xpath->path); return (-1); } /* instance has to be an xpath expression */ if (xpath->instance != NULL) { int tmp_size; instance_node_obj = cx_evaluate_xpath (xpath_ctx, BAD_CAST xpath->instance); if (instance_node_obj == NULL) return (-1); /* error is logged already */ instance_node = instance_node_obj->nodesetval; tmp_size = (instance_node) ? instance_node->nodeNr : 0; if (tmp_size <= 0) { WARNING ("curl_xml plugin: " "relative xpath expression for 'InstanceFrom' \"%s\" doesn't match " "any of the nodes. Skipping the node.", xpath->instance); xmlXPathFreeObject (instance_node_obj); return (-1); } if (tmp_size > 1) { WARNING ("curl_xml plugin: " "relative xpath expression for 'InstanceFrom' \"%s\" is expected " "to return only one text node. Skipping the node.", xpath->instance); xmlXPathFreeObject (instance_node_obj); return (-1); } /* ignoring the element if other than textnode/attribute */ if (cx_if_not_text_node(instance_node->nodeTab[0])) { WARNING ("curl_xml plugin: " "relative xpath expression \"%s\" is expected to return only text node " "which is not the case. Skipping the node.", xpath->instance); xmlXPathFreeObject (instance_node_obj); return (-1); } } /* if (xpath->instance != NULL) */ if (xpath->instance_prefix != NULL) { if (instance_node != NULL) { char *node_value = (char *) xmlNodeGetContent(instance_node->nodeTab[0]); ssnprintf (vl->type_instance, sizeof (vl->type_instance),"%s%s", xpath->instance_prefix, node_value); sfree (node_value); } else sstrncpy (vl->type_instance, xpath->instance_prefix, sizeof (vl->type_instance)); } else { /* If instance_prefix and instance_node are NULL, then * don't set the type_instance */ if (instance_node != NULL) { char *node_value = (char *) xmlNodeGetContent(instance_node->nodeTab[0]); sstrncpy (vl->type_instance, node_value, sizeof (vl->type_instance)); sfree (node_value); } } /* Free `instance_node_obj' this late, because `instance_node' points to * somewhere inside this structure. */ xmlXPathFreeObject (instance_node_obj); return (0); } /* }}} int cx_handle_instance_xpath */
static int cx_handle_single_value_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ cx_xpath_t *xpath, const data_set_t *ds, value_list_t *vl, int index) { xmlXPathObjectPtr values_node_obj; xmlNodeSetPtr values_node; int tmp_size; char *node_value; values_node_obj = cx_evaluate_xpath (xpath_ctx, BAD_CAST xpath->values[index].path); if (values_node_obj == NULL) return (-1); /* Error already logged. */ values_node = values_node_obj->nodesetval; tmp_size = (values_node) ? values_node->nodeNr : 0; if (tmp_size == 0) { WARNING ("curl_xml plugin: " "relative xpath expression \"%s\" doesn't match any of the nodes. " "Skipping...", xpath->values[index].path); xmlXPathFreeObject (values_node_obj); return (-1); } if (tmp_size > 1) { WARNING ("curl_xml plugin: " "relative xpath expression \"%s\" is expected to return " "only one node. Skipping...", xpath->values[index].path); xmlXPathFreeObject (values_node_obj); return (-1); } /* ignoring the element if other than textnode/attribute*/ if (cx_if_not_text_node(values_node->nodeTab[0])) { WARNING ("curl_xml plugin: " "relative xpath expression \"%s\" is expected to return " "only text/attribute node which is not the case. Skipping...", xpath->values[index].path); xmlXPathFreeObject (values_node_obj); return (-1); } node_value = (char *) xmlNodeGetContent(values_node->nodeTab[0]); switch (ds->ds[index].type) { case DS_TYPE_COUNTER: vl->values[index].counter = (counter_t) strtoull (node_value, /* endptr = */ NULL, /* base = */ 0); break; case DS_TYPE_DERIVE: vl->values[index].derive = (derive_t) strtoll (node_value, /* endptr = */ NULL, /* base = */ 0); break; case DS_TYPE_ABSOLUTE: vl->values[index].absolute = (absolute_t) strtoull (node_value, /* endptr = */ NULL, /* base = */ 0); break; case DS_TYPE_GAUGE: vl->values[index].gauge = (gauge_t) strtod (node_value, /* endptr = */ NULL); } /* free up object */ xmlXPathFreeObject (values_node_obj); sfree (node_value); /* We have reached here which means that * we have got something to work */ return (0); } /* }}} int cx_handle_single_value_xpath */
static int cx_handle_xpath(const cx_t *db, /* {{{ */ xmlXPathContextPtr xpath_ctx, cx_xpath_t *xpath) { const data_set_t *ds = plugin_get_ds(xpath->type); if (cx_check_type(ds, xpath) != 0) return -1; xmlXPathObjectPtr base_node_obj = cx_evaluate_xpath(xpath_ctx, xpath->path); if (base_node_obj == NULL) return -1; /* error is logged already */ xmlNodeSetPtr base_nodes = base_node_obj->nodesetval; int total_nodes = (base_nodes) ? base_nodes->nodeNr : 0; if (total_nodes == 0) { ERROR("curl_xml plugin: " "xpath expression \"%s\" doesn't match any of the nodes. " "Skipping the xpath block...", xpath->path); xmlXPathFreeObject(base_node_obj); return -1; } /* If base_xpath returned multiple results, then */ /* InstanceFrom or PluginInstanceFrom in the xpath block is required */ if (total_nodes > 1 && xpath->instance == NULL && xpath->plugin_instance_from == NULL) { ERROR("curl_xml plugin: " "InstanceFrom or PluginInstanceFrom is must in xpath block " "since the base xpath expression \"%s\" " "returned multiple results. Skipping the xpath block...", xpath->path); xmlXPathFreeObject(base_node_obj); return -1; } value_list_t vl = VALUE_LIST_INIT; /* set the values for the value_list */ vl.values_len = ds->ds_num; sstrncpy(vl.type, xpath->type, sizeof(vl.type)); sstrncpy(vl.plugin, (db->plugin_name != NULL) ? db->plugin_name : "curl_xml", sizeof(vl.plugin)); sstrncpy(vl.host, cx_host(db), sizeof(vl.host)); for (int i = 0; i < total_nodes; i++) { xpath_ctx->node = base_nodes->nodeTab[i]; if (db->instance != NULL) sstrncpy(vl.plugin_instance, db->instance, sizeof(vl.plugin_instance)); if (cx_handle_instance_xpath(xpath_ctx, xpath, &vl) != 0) continue; /* An error has already been reported. */ if (cx_handle_all_value_xpaths(xpath_ctx, xpath, ds, &vl) != 0) continue; /* An error has been logged. */ } /* for (i = 0; i < total_nodes; i++) */ /* free up the allocated memory */ xmlXPathFreeObject(base_node_obj); return 0; } /* }}} cx_handle_xpath */