From f7962e8fd85af85606cb6579380dd188a9f6a567 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Thu, 23 Jun 2016 17:08:49 -0400 Subject: [PATCH] Add session-config api for array and element manipulation --- src/common/config/session-config.c | 443 +++++++++++++++++++++++++++++ src/common/config/session-config.h | 99 ++++++- 2 files changed, 540 insertions(+), 2 deletions(-) diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 56ba2c4fe..1c8a1e3ed 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -3757,3 +3757,446 @@ void config_element_free(struct config_element *element) { free(element); } + +LTTNG_HIDDEN +void config_element_free_array(struct config_element **array, int size) { + + if (array) { + for (int i = 0; i < size; i++) { + if (!array[i]) { + continue; + } + if (array[i]->element) { + xmlFreeNode(array[i]->element); + } + free(array[i]); + } + } + free(array); +} + +LTTNG_HIDDEN +void config_document_get_element_array(const struct config_document *document, const char *xpath, struct config_element ***element_array, int *array_size) +{ + int xpath_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlChar *internal_value = NULL; + + assert(document); + assert(xpath); + + *element_array=NULL; + *array_size=0; + + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document->document); + if (!xpath_context) { + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size == 0) { + goto end; + } + + /* alloc the array */ + *element_array = calloc(xpath_result_size, sizeof(struct config_element *)); + *array_size = xpath_result_size; + if (!element_array) { + ERR("Calloc config element array"); + goto end; + } + + for (int i = 0; i < xpath_result_size; i++) { + xmlNodePtr node_copy = NULL; + node_copy = xmlCopyNode(xpath_result_set->nodeTab[i], 1); + if (!node_copy) { + ERR("Xml copy of event node"); + goto error; + } + /* Hand off ownership */ + (*element_array)[i] = malloc(sizeof(struct config_element)); + if (!((*element_array)[i])){ + ERR("Malloc config_element array"); + xmlFreeNode(node_copy); + goto error; + }; + (*element_array)[i]->element = node_copy; + } +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + return; +error: + + if (element_array) { + config_element_free_array(*element_array, *array_size); + } + + *array_size = 0; + + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + return; +} + +LTTNG_HIDDEN +void config_element_get_element_array(const struct config_element *element, const char *xpath, struct config_element ***element_array, int *array_size) +{ + int xpath_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlChar *internal_value = NULL; + xmlNodePtr local_copy = NULL; + xmlNodePtr place_holder = NULL; + xmlDocPtr document = NULL; + + assert(element); + assert(element->element); + assert(xpath); + + *element_array=NULL; + *array_size=0; + + /* Create a new doc and set root node as passed element */ + document = xmlNewDoc(BAD_CAST "1.0"); + if (!document) { + ERR("Unable to create xml document"); + goto end; + } + + local_copy = xmlCopyNode(element->element, 1); + if (!local_copy) { + ERR("Unable to copy an xml node"); + goto end; + } + + /* Hand off the local_copy to the xmlDoc */ + place_holder = xmlDocSetRootElement(document, local_copy); + if (place_holder) { + ERR("The document root was already set"); + xmlFreeNode(local_copy); + goto end; + } + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document); + if (!xpath_context) { + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size == 0) { + goto end; + } + + /* alloc the array */ + *element_array = calloc(xpath_result_size, sizeof(struct config_element *)); + *array_size = xpath_result_size; + if (!element_array) { + ERR("Calloc config element array"); + goto end; + } + + for (int i = 0; i < xpath_result_size; i++) { + xmlNodePtr node_copy = NULL; + node_copy = xmlCopyNode(xpath_result_set->nodeTab[i], 1); + if (!node_copy) { + ERR("Xml copy of event node"); + goto error; + } + /* Hand off ownership */ + (*element_array)[i] = malloc(sizeof(struct config_element)); + if (!((*element_array)[i])){ + ERR("Malloc config_element array"); + xmlFreeNode(node_copy); + goto error; + }; + (*element_array)[i]->element = node_copy; + } +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + xmlFreeDoc(document); + return; +error: + + if (element_array) { + config_element_free_array(*element_array, *array_size); + } + + *array_size = 0; + + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + return; +} +/* Create an internal copy of the config_element. + * The users is responsible for the freeing of the passed child. + */ +LTTNG_HIDDEN +int config_element_add_or_replace_child(struct config_element *parent, struct config_element *child) +{ + assert(parent); + assert(child); + assert(parent->element); + assert(child->element); + + int ret = 0; + xmlNodePtr local_copy; + xmlNodePtr x_ret = NULL; + xmlNodePtr iterator = NULL; + + xmlNodePtr x_parent = parent->element; + xmlNodePtr x_child = child->element; + + /* Find and delete the node with the same name if present */ + iterator = x_parent->children; + while (iterator != NULL) { + if ((!xmlStrcmp(iterator->name, x_child->name))){ + xmlNodePtr del = iterator; + iterator = iterator->next; + xmlUnlinkNode(del); + xmlFreeNode(del); + } else { + iterator = iterator->next; + } + } + + /* Add the child */ + local_copy = xmlCopyNode(x_child, 1); + if (!local_copy) { + ret = -1; + ERR("Duplication of node to be insert failed"); + goto end; + } + x_ret = xmlAddChild(x_parent, local_copy); + if (!x_ret) { + xmlFreeNode(local_copy); + } +end: + return ret; +} + +LTTNG_HIDDEN +char *config_element_get_element_value(const struct config_element *element, const char *xpath) +{ + char *value = NULL; + int xpath_result_size; + int value_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlChar *internal_value = NULL; + xmlDocPtr document = NULL; + xmlNodePtr local_copy = NULL; + xmlNodePtr place_holder = NULL; + + assert(element); + assert(element->element); + assert(xpath); + + /* Create a new doc and set root node as passed element */ + document = xmlNewDoc(BAD_CAST "1.0"); + if (!document) { + value = NULL; + ERR("Unable to create xml document"); + goto end; + } + + local_copy = xmlCopyNode(element->element, 1); + if (!local_copy) { + value = NULL; + ERR("Unable to copy an xml node"); + goto end; + } + + /* Hand off the local_copy to the xmlDoc */ + place_holder = xmlDocSetRootElement(document, local_copy); + if (place_holder) { + value = NULL; + ERR("The document root was already set"); + xmlFreeNode(local_copy); + goto end; + } + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + /*TODO set valid error */ + value = NULL; + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document); + if (!xpath_context) { + /*TODO set valid error */ + value = NULL; + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + /*TODO set valid error */ + value = NULL; + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + /*TODO set valid error */ + value = NULL; + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size > 1) { + /*TODO set valid error */ + ERR("To many result while fetching config element value"); + value = NULL; + goto end; + } + + if (xpath_result_size == 0) { + value = NULL; + goto end; + } + + assert(xpath_result_set->nodeTab[0]); + internal_value = xmlNodeGetContent(xpath_result_set->nodeTab[0]); + if (!internal_value) { + value = NULL; + goto end; + } + + value_result_size = xmlStrlen(internal_value); + value = calloc(value_result_size + 1, sizeof(char)); + strncpy(value, (char *) internal_value, value_result_size); + +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + xmlFreeDoc(document); + return value; + +} + +LTTNG_HIDDEN +int config_process_event_element(const struct config_element *element, const char *session_name, int domain_type, const char *channel_name) { + + int ret = 0; + xmlNodePtr node; + struct lttng_domain domain; + struct lttng_handle *handle; + + assert(element); + assert(element->element); + + memset(&domain, 0, sizeof(struct lttng_domain)); + + /* Create handle */ + domain.type = domain_type; + switch (domain.type) { + case LTTNG_DOMAIN_KERNEL: + domain.buf_type = LTTNG_BUFFER_GLOBAL; + break; + case LTTNG_DOMAIN_UST: + case LTTNG_DOMAIN_JUL: + case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_PYTHON: + domain.buf_type = LTTNG_BUFFER_PER_UID; + break; + case LTTNG_DOMAIN_NONE: + default: + assert(0); + } + + handle = lttng_create_handle(session_name, &domain); + if (!handle) { + ERR("Handle creation"); + ret = 1; + goto error; + } + + + node = element->element; + /* Check if element is really and event */ + if (xmlStrcmp(BAD_CAST config_element_event, node->name)) { + ERR("Passed element is not an event"); + ret = 1; + goto error; + } + + ret = process_event_node(node, handle, channel_name, ENABLE); + if (ret) { + goto error; + } +error: + free(handle); + return ret; +} diff --git a/src/common/config/session-config.h b/src/common/config/session-config.h index b6a42483a..c29d40af4 100644 --- a/src/common/config/session-config.h +++ b/src/common/config/session-config.h @@ -38,6 +38,7 @@ struct config_writer; /* Instance of a configuration document */ struct config_document; +/* Instance of a configuration element */ struct config_element; /* @@ -353,13 +354,26 @@ LTTNG_HIDDEN int config_document_element_exist(struct config_document *document, const char *xpath); /* + * Create a configuration element. * + * name The name of the element + * value The value to be assigned to the element. The value can be NULL. + * + * Returns a new configuration element. + * + * The caller is responsible of freeing the allocated element with + * config_element_free. */ LTTNG_HIDDEN -void config_element_free(struct config_element *element); +struct config_element *config_element_create(const char *name, const char *value); +/* + * Free a config_element + * + * element The element to free. + */ LTTNG_HIDDEN -struct config_element *config_element_create(const char *name, const char *value); +void config_element_free(struct config_element *element); /* * Add a child element to an element. @@ -386,5 +400,86 @@ int config_element_add_child(struct config_element *parent, const struct config_ LTTNG_HIDDEN int config_document_insert_element(struct config_document *document, const char *xpath, const struct config_element *element); +/* + * Get an array of elements from a document. + * + * document The source document. + * xpath The xpath string matching the elements path. + * element_array The resulting array + * array_size The resulting array size + * + * element_array is NULL on error. + * + * The caller is responsible of freeing the array with + * config_element_free_array. + */ +LTTNG_HIDDEN +void config_document_get_element_array(const struct config_document *document, const char *xpath, struct config_element ***element_array, int *array_size); + +/* + * Get an array of elements from an element. + * + * element The source element. + * xpath The xpath string matching the elements path. + * element_array The resulting array + * array_size The resulting array size + * + * element_array is NULL on error. + * + * The caller is responsible of freeing the array with + * config_element_free_array. + */ +LTTNG_HIDDEN +void config_element_get_element_array(const struct config_element *element, const char *xpath, struct config_element ***element_array, int *array_size); + +/* + * Free an array of element. + * + * array The array to free + * size The size of the array + */ +LTTNG_HIDDEN +void config_element_free_array(struct config_element **array, int size); + +/* + * Add an element as a child if a equivalent element is present replace it with + * the passed element. + * + * parent The parent element. + * child The child to add. + * + * Returns zero if the session could be loaded successfully. Returns + * a negative LTTNG_ERR code on error. + */ +LTTNG_HIDDEN +int config_element_add_or_replace_child(struct config_element *parent, struct config_element *child); + +/* + * Get the value of an element under an element. + * + * element The base element. + * xpath The xpath string to the element. + * + * Return null if multiple values exists or there is no + * value for the passed path. + */ +LTTNG_HIDDEN +char *config_element_get_element_value(const struct config_element *element, const char *xpath); + +/* + * Process an element matching an event configuration and try to enable it. + * + * element The element to process + * session_name The session name to use for event enabling. + * domain_type The domain type to use for event enabling + * channel_name The channel name to use for event enabling + * A NULL channel name will default to the default domain + * channel. + * + * Returns zero if the session could be loaded successfully. Returns + * a negative LTTNG_ERR code on error. + */ +LTTNG_HIDDEN +int config_process_event_element(const struct config_element *element, const char* session_name, int domain_type, const char *channel_name); #endif /* _CONFIG_H */ -- 2.34.1