X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fcurl_xml.c;h=9483738bcf637e8178f99c739688be30c73fa954;hb=5b1caeeadcecd798ee4b386b15c17cb7591a8bfe;hp=db5cd61167cbd18a8395964fb5566662a286a3c3;hpb=c45ba8debef82d3785b83e35c5f7b0991b57a97e;p=collectd.git diff --git a/src/curl_xml.c b/src/curl_xml.c index db5cd611..9483738b 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -59,6 +59,14 @@ struct cx_xpath_s /* {{{ */ typedef struct cx_xpath_s cx_xpath_t; /* }}} */ +struct cx_namespace_s /* {{{ */ +{ + char *prefix; + char *url; +}; +typedef struct cx_namespace_s cx_namespace_t; +/* }}} */ + struct cx_s /* {{{ */ { char *instance; @@ -73,7 +81,9 @@ struct cx_s /* {{{ */ char *cacert; char *post_body; struct curl_slist *headers; - char *namespaces; + + cx_namespace_t *namespaces; + size_t namespaces_num; CURL *curl; char curl_errbuf[CURL_ERROR_SIZE]; @@ -164,6 +174,7 @@ static void cx_list_free (llist_t *list) /* {{{ */ static void cx_free (void *arg) /* {{{ */ { cx_t *db; + size_t i; DEBUG ("curl_xml plugin: cx_free (arg = %p);", arg); @@ -190,6 +201,12 @@ static void cx_free (void *arg) /* {{{ */ sfree (db->cacert); sfree (db->post_body); curl_slist_free_all (db->headers); + + for (i = 0; i < db->namespaces_num; i++) + { + sfree (db->namespaces[i].prefix); + sfree (db->namespaces[i].url); + } sfree (db->namespaces); sfree (db); @@ -198,16 +215,19 @@ static void cx_free (void *arg) /* {{{ */ static int cx_config_append_string (const char *name, struct curl_slist **dest, /* {{{ */ oconfig_item_t *ci) { + struct curl_slist *temp = NULL; if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING ("curl_xml plugin: `%s' needs exactly one string argument.", name); return (-1); } - *dest = curl_slist_append(*dest, ci->values[0].value.string); - if (*dest == NULL) + temp = curl_slist_append(*dest, ci->values[0].value.string); + if (temp == NULL) return (-1); + *dest = temp; + return (0); } /* }}} int cx_config_append_string */ @@ -257,98 +277,6 @@ static int cx_if_not_text_node (xmlNodePtr node) /* {{{ */ return -1; } /* }}} cx_if_not_text_node */ -/** - * cx_register_namespaces: - * @xpath_ctx: the pointer to an XPath context. - * @nslist: the list of known namespaces in - * "= =href2> ..." format. - * - * Registers namespaces from @nslist in @xpath_ctx. - * - * Returns 0 on success and a negative value otherwise. - * - * author: Aleksey Sanin - * - * The following license statement applies to the function - * cx_register_namespaces only: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is fur- - * nished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- - * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- - * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of Daniel Veillard shall not - * be used in advertising or otherwise to promote the sale, use or other deal- - * ings in this Software without prior written authorization from him. - */ -static int cx_register_namespaces(xmlXPathContextPtr xpath_ctx, /* {{{ */ - const xmlChar* nslist) -{ - xmlChar* nslistdup; - xmlChar* prefix; - xmlChar* href; - xmlChar* next; - - assert(xpath_ctx); - assert(nslist); - - nslistdup = xmlStrdup(nslist); - if(nslistdup == NULL) { - ERROR ("curl_xml plugin: " - "unable to strdup namespaces list"); - return (-1); - } - - next = nslistdup; - while(next != NULL) { - /* skip spaces */ - while((*next) == ' ') next++; - if((*next) == '\0') break; - - /* find prefix */ - prefix = next; - next = (xmlChar*)xmlStrchr(next, '='); - if(next == NULL) { - ERROR ("curl_xml plugin: " - "invalid namespaces list format"); - xmlFree(nslistdup); - return (-1); - } - *(next++) = '\0'; - - /* find href */ - href = next; - next = (xmlChar*)xmlStrchr(next, ' '); - if(next != NULL) { - *(next++) = '\0'; - } - - /* do register namespace */ - if(xmlXPathRegisterNs(xpath_ctx, prefix, href) != 0) { - ERROR ("curl_xml plugin: " - "unable to register NS with prefix=\"%s\" and href=\"%s\"\n", - prefix, href); - xmlFree(nslistdup); - return (-1); - } - } - - xmlFree(nslistdup); - return (0); -} /* }}} cx_register_namespaces */ - 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) @@ -416,6 +344,7 @@ static int cx_handle_single_value_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ /* free up object */ xmlXPathFreeObject (values_node_obj); + sfree (node_value); /* We have reached here which means that * we have got something to work */ @@ -460,7 +389,7 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ /* 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 && (vl->type_instance == NULL)) + if (is_table && (xpath->instance == NULL)) { WARNING ("curl_xml plugin: " "Base-XPath %s is a table (more than one result was returned), " @@ -513,8 +442,12 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ 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, (char *) xmlNodeGetContent(instance_node->nodeTab[0])); + xpath->instance_prefix, node_value); + sfree (node_value); + } else sstrncpy (vl->type_instance, xpath->instance_prefix, sizeof (vl->type_instance)); @@ -524,8 +457,11 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ /* If instance_prefix and instance_node are NULL, then * don't set the type_instance */ if (instance_node != NULL) - sstrncpy (vl->type_instance, (char *) xmlNodeGetContent(instance_node->nodeTab[0]), - sizeof (vl->type_instance)); + { + 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 @@ -636,6 +572,7 @@ static int cx_parse_stats_xml(xmlChar* xml, cx_t *db) /* {{{ */ int status; xmlDocPtr doc; xmlXPathContextPtr xpath_ctx; + size_t i; /* Load the XML */ doc = xmlParseDoc(xml); @@ -653,11 +590,20 @@ static int cx_parse_stats_xml(xmlChar* xml, cx_t *db) /* {{{ */ return (-1); } - if((db->namespaces != NULL) && - (cx_register_namespaces(xpath_ctx, BAD_CAST db->namespaces) < 0)) + for (i = 0; i < db->namespaces_num; i++) { - xmlFreeDoc(doc); - return (-1); + cx_namespace_t const *ns = db->namespaces + i; + status = xmlXPathRegisterNs (xpath_ctx, + BAD_CAST ns->prefix, BAD_CAST ns->url); + if (status != 0) + { + ERROR ("curl_xml plugin: " + "unable to register NS with prefix=\"%s\" and href=\"%s\"\n", + ns->prefix, ns->url); + xmlXPathFreeContext(xpath_ctx); + xmlFreeDoc (doc); + return (status); + } } status = cx_handle_parsed_xml (doc, xpath_ctx, db); @@ -673,6 +619,7 @@ static int cx_curl_perform (cx_t *db, CURL *curl) /* {{{ */ long rc; char *ptr; char *url; + url = db->url; db->buffer_fill = 0; status = curl_easy_perform (curl); @@ -752,17 +699,18 @@ static int cx_config_add_values (const char *name, cx_xpath_t *xpath, /* {{{ */ sstrncpy (xpath->values[i].path, ci->values[i].value.string, sizeof (xpath->values[i].path)); } - return (0); + return (0); } /* }}} cx_config_add_values */ -static int cx_config_add_xpath (cx_t *db, /* {{{ */ - oconfig_item_t *ci) +static int cx_config_add_xpath (cx_t *db, oconfig_item_t *ci) /* {{{ */ { cx_xpath_t *xpath; + char *name; + llentry_t *le; int status; int i; - xpath = (cx_xpath_t *) malloc (sizeof (*xpath)); + xpath = malloc (sizeof (*xpath)); if (xpath == NULL) { ERROR ("curl_xml plugin: malloc failed."); @@ -773,15 +721,16 @@ static int cx_config_add_xpath (cx_t *db, /* {{{ */ status = cf_util_get_string (ci, &xpath->path); if (status != 0) { - sfree (xpath); + cx_xpath_free (xpath); return (status); } /* error out if xpath->path is an empty string */ - if (*xpath->path == 0) + if (strlen (xpath->path) == 0) { ERROR ("curl_xml plugin: invalid xpath. " "xpath value can't be an empty string"); + cx_xpath_free (xpath); return (-1); } @@ -808,47 +757,91 @@ static int cx_config_add_xpath (cx_t *db, /* {{{ */ break; } /* for (i = 0; i < ci->children_num; i++) */ - if (status == 0 && xpath->type == NULL) + if (status != 0) { - WARNING ("curl_xml plugin: `Type' missing in `xpath' block."); - status = -1; + cx_xpath_free (xpath); + return status; } - if (status == 0) + if (xpath->type == NULL) { - char *name; - llentry_t *le; + WARNING ("curl_xml plugin: `Type' missing in `xpath' block."); + cx_xpath_free (xpath); + return -1; + } + if (db->list == NULL) + { + db->list = llist_create(); if (db->list == NULL) { - db->list = llist_create(); - if (db->list == NULL) - { - ERROR ("curl_xml plugin: list creation failed."); - return (-1); - } - } - - name = strdup(xpath->path); - if (name == NULL) - { - ERROR ("curl_xml plugin: strdup failed."); - return (-1); - } - - le = llentry_create (name, xpath); - if (le == NULL) - { - ERROR ("curl_xml plugin: llentry_create failed."); + ERROR ("curl_xml plugin: list creation failed."); + cx_xpath_free (xpath); return (-1); } + } + + name = strdup (xpath->path); + if (name == NULL) + { + ERROR ("curl_xml plugin: strdup failed."); + cx_xpath_free (xpath); + return (-1); + } - llist_append (db->list, le); + le = llentry_create (name, xpath); + if (le == NULL) + { + ERROR ("curl_xml plugin: llentry_create failed."); + cx_xpath_free (xpath); + sfree (name); + return (-1); } - return (status); + llist_append (db->list, le); + return (0); } /* }}} int cx_config_add_xpath */ +static int cx_config_add_namespace (cx_t *db, /* {{{ */ + oconfig_item_t *ci) +{ + cx_namespace_t *ns; + + if ((ci->values_num != 2) + || (ci->values[0].type != OCONFIG_TYPE_STRING) + || (ci->values[1].type != OCONFIG_TYPE_STRING)) + { + WARNING ("curl_xml plugin: The `Namespace' option " + "needs exactly two string arguments."); + return (EINVAL); + } + + ns = realloc (db->namespaces, sizeof (*db->namespaces) + * (db->namespaces_num + 1)); + if (ns == NULL) + { + ERROR ("curl_xml plugin: realloc failed."); + return (ENOMEM); + } + db->namespaces = ns; + ns = db->namespaces + db->namespaces_num; + memset (ns, 0, sizeof (*ns)); + + ns->prefix = strdup (ci->values[0].value.string); + ns->url = strdup (ci->values[1].value.string); + + if ((ns->prefix == NULL) || (ns->url == NULL)) + { + sfree (ns->prefix); + sfree (ns->url); + ERROR ("curl_xml plugin: strdup failed."); + return (ENOMEM); + } + + db->namespaces_num++; + return (0); +} /* }}} int cx_config_add_namespace */ + /* Initialize db->curl */ static int cx_init_curl (cx_t *db) /* {{{ */ { @@ -935,6 +928,7 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ { ERROR ("curl_xml plugin: cx_config: " "Invalid key: %s", ci->key); + cx_free (db); return (-1); } @@ -963,8 +957,8 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ status = cx_config_append_string ("Header", &db->headers, child); else if (strcasecmp ("Post", child->key) == 0) status = cf_util_get_string (child, &db->post_body); - else if (strcasecmp ("Namespaces", child->key) == 0) - status = cf_util_get_string (child, &db->namespaces); + else if (strcasecmp ("Namespace", child->key) == 0) + status = cx_config_add_namespace (db, child); else { WARNING ("curl_xml plugin: Option `%s' not allowed here.", child->key); @@ -991,7 +985,7 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ if (status == 0) { user_data_t ud; - char cb_name[DATA_MAX_NAME_LEN]; + char *cb_name; if (db->instance == NULL) db->instance = strdup("default"); @@ -1003,11 +997,10 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ ud.data = (void *) db; ud.free_func = cx_free; - ssnprintf (cb_name, sizeof (cb_name), "curl_xml-%s-%s", - db->instance, db->url); - - plugin_register_complex_read (/* group = */ NULL, cb_name, cx_read, + cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url); + plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read, /* interval = */ NULL, &ud); + sfree (cb_name); } else { @@ -1058,9 +1051,18 @@ static int cx_config (oconfig_item_t *ci) /* {{{ */ return (0); } /* }}} int cx_config */ +static int cx_init (void) /* {{{ */ +{ + /* Call this while collectd is still single-threaded to avoid + * initialization issues in libgcrypt. */ + curl_global_init (CURL_GLOBAL_SSL); + return (0); +} /* }}} int cx_init */ + void module_register (void) { plugin_register_complex_config ("curl_xml", cx_config); + plugin_register_init ("curl_xml", cx_init); } /* void module_register */ /* vim: set sw=2 sts=2 et fdm=marker : */