Partial revert: channel name and default output
[lttng-tools.git] / src / common / config / session-config.c
index 8fcb75230ad4309e4efddb428ab748c9b6721ab9..f250a6743194ace3424000b2007e42be2e748077 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdbool.h>
 
 #include <common/defaults.h>
 #include <common/error.h>
@@ -37,6 +38,7 @@
 #include <libxml/valid.h>
 #include <libxml/xmlschemas.h>
 #include <libxml/tree.h>
+#include <libxml/xpath.h>
 #include <lttng/lttng.h>
 #include <lttng/snapshot.h>
 
@@ -95,21 +97,23 @@ const char * const config_element_output_type = "output_type";
 const char * const config_element_tracefile_size = "tracefile_size";
 const char * const config_element_tracefile_count = "tracefile_count";
 const char * const config_element_live_timer_interval = "live_timer_interval";
+LTTNG_HIDDEN const char * const config_element_discarded_events = "discarded_events";
+LTTNG_HIDDEN const char * const config_element_lost_packets = "lost_packets";
 const char * const config_element_type = "type";
 const char * const config_element_buffer_type = "buffer_type";
 const char * const config_element_session = "session";
 const char * const config_element_sessions = "sessions";
-const char * const config_element_context_perf = "perf";
-const char * const config_element_context_app = "app";
-const char * const config_element_context_app_provider_name = "provider_name";
-const char * const config_element_context_app_ctx_name = "ctx_name";
+LTTNG_HIDDEN const char * const config_element_context_perf = "perf";
+LTTNG_HIDDEN const char * const config_element_context_app = "app";
+LTTNG_HIDDEN const char * const config_element_context_app_provider_name = "provider_name";
+LTTNG_HIDDEN const char * const config_element_context_app_ctx_name = "ctx_name";
 const char * const config_element_config = "config";
 const char * const config_element_started = "started";
 const char * const config_element_snapshot_mode = "snapshot_mode";
 const char * const config_element_loglevel = "loglevel";
 const char * const config_element_loglevel_type = "loglevel_type";
 const char * const config_element_filter = "filter";
-const char * const config_element_filter_expression = "filter_expression";
+LTTNG_HIDDEN const char * const config_element_filter_expression = "filter_expression";
 const char * const config_element_snapshot_outputs = "snapshot_outputs";
 const char * const config_element_consumer_output = "consumer_output";
 const char * const config_element_destination = "destination";
@@ -125,6 +129,8 @@ const char * const config_element_pid_tracker = "pid_tracker";
 const char * const config_element_trackers = "trackers";
 const char * const config_element_targets = "targets";
 const char * const config_element_target_pid = "pid_target";
+const char * const config_element_omit_name = "omit_name";
+const char * const config_element_omit_output = "omit_output";
 
 const char * const config_domain_type_kernel = "KERNEL";
 const char * const config_domain_type_ust = "UST";
@@ -169,8 +175,19 @@ const char * const config_event_context_pthread_id = "PTHREAD_ID";
 const char * const config_event_context_hostname = "HOSTNAME";
 const char * const config_event_context_ip = "IP";
 const char * const config_event_context_perf_thread_counter = "PERF_THREAD_COUNTER";
-const char * const config_event_context_app = "APP";
-
+LTTNG_HIDDEN const char * const config_event_context_app = "APP";
+LTTNG_HIDDEN const char * const config_event_context_interruptible = "INTERRUPTIBLE";
+LTTNG_HIDDEN const char * const config_event_context_preemptible = "PREEMPTIBLE";
+LTTNG_HIDDEN const char * const config_event_context_need_reschedule = "NEED_RESCHEDULE";
+LTTNG_HIDDEN const char * const config_event_context_migratable = "MIGRATABLE";
+
+/* Deprecated symbols */
+const char * const config_element_perf;
+
+enum process_event_node_phase {
+       CREATION = 0,
+       ENABLE = 1,
+};
 
 struct consumer_output {
        int enabled;
@@ -455,7 +472,40 @@ int config_writer_open_element(struct config_writer *writer,
        ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
        xmlFree(encoded_element_name);
 end:
-       return ret > 0 ? 0 : ret;
+       return ret >= 0 ? 0 : ret;
+}
+
+LTTNG_HIDDEN
+int config_writer_write_attribute(struct config_writer *writer,
+               const char *name, const char *value)
+{
+       int ret;
+       xmlChar *encoded_name = NULL;
+       xmlChar *encoded_value = NULL;
+
+       if (!writer || !writer->writer || !name || !name[0]) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_name = encode_string(name);
+       if (!encoded_name) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_value = encode_string(value);
+       if (!encoded_value) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlTextWriterWriteAttribute(writer->writer, encoded_name,
+                       encoded_value);
+end:
+       xmlFree(encoded_name);
+       xmlFree(encoded_value);
+       return ret >= 0 ? 0 : ret;
 }
 
 LTTNG_HIDDEN
@@ -470,7 +520,7 @@ int config_writer_close_element(struct config_writer *writer)
 
        ret = xmlTextWriterEndElement(writer->writer);
 end:
-       return ret > 0 ? 0 : ret;
+       return ret >= 0 ? 0 : ret;
 }
 
 LTTNG_HIDDEN
@@ -495,7 +545,7 @@ int config_writer_write_element_unsigned_int(struct config_writer *writer,
                encoded_element_name, "%" PRIu64, value);
        xmlFree(encoded_element_name);
 end:
-       return ret > 0 ? 0 : ret;
+       return ret >= 0 ? 0 : ret;
 }
 
 LTTNG_HIDDEN
@@ -520,7 +570,7 @@ int config_writer_write_element_signed_int(struct config_writer *writer,
                encoded_element_name, "%" PRIi64, value);
        xmlFree(encoded_element_name);
 end:
-       return ret > 0 ? 0 : ret;
+       return ret >= 0 ? 0 : ret;
 }
 
 LTTNG_HIDDEN
@@ -562,7 +612,7 @@ int config_writer_write_element_string(struct config_writer *writer,
 end:
        xmlFree(encoded_element_name);
        xmlFree(encoded_value);
-       return ret > 0 ? 0 : ret;
+       return ret >= 0 ? 0 : ret;
 }
 
 static
@@ -952,6 +1002,18 @@ int get_context_type(xmlChar *context_type)
        } else if (!strcmp((char *) context_type,
                config_event_context_ip)) {
                ret = LTTNG_EVENT_CONTEXT_IP;
+       } else if (!strcmp((char *) context_type,
+               config_event_context_interruptible)) {
+               ret = LTTNG_EVENT_CONTEXT_INTERRUPTIBLE;
+       } else if (!strcmp((char *) context_type,
+               config_event_context_preemptible)) {
+               ret = LTTNG_EVENT_CONTEXT_PREEMPTIBLE;
+       } else if (!strcmp((char *) context_type,
+               config_event_context_need_reschedule)) {
+               ret = LTTNG_EVENT_CONTEXT_NEED_RESCHEDULE;
+       } else if (!strcmp((char *) context_type,
+               config_event_context_migratable)) {
+               ret = LTTNG_EVENT_CONTEXT_MIGRATABLE;
        } else {
                goto error;
        }
@@ -1101,17 +1163,16 @@ end:
 }
 
 static
-int create_session_net_output(const char *name, struct lttng_domain *domain,
-       const char *control_uri, const char *data_uri)
+int create_session_net_output(const char *name, const char *control_uri,
+               const char *data_uri)
 {
        int ret;
        struct lttng_handle *handle;
        const char *uri = NULL;
 
        assert(name);
-       assert(domain);
 
-       handle = lttng_create_handle(name, domain);
+       handle = lttng_create_handle(name, NULL);
        if (!handle) {
                ret = -LTTNG_ERR_NOMEM;
                goto end;
@@ -1157,7 +1218,7 @@ int create_snapshot_session(const char *session_name, xmlNodePtr output_node)
                        snapshot_output_node; snapshot_output_node =
                        xmlNextElementSibling(snapshot_output_node)) {
                char *name = NULL;
-               uint64_t max_size = UINT64_MAX;
+               uint64_t max_size = DEFAULT_SNAPSHOT_MAX_SIZE;
                struct consumer_output output = { 0 };
                struct lttng_snapshot_output *snapshot_output = NULL;
 
@@ -1201,6 +1262,18 @@ int create_snapshot_session(const char *session_name, xmlNodePtr output_node)
                        goto error_snapshot_output;
                }
 
+               if (!name) {
+                       /* Generate a default name */
+                       int pret;
+                       pret = asprintf(&name, DEFAULT_SNAPSHOT_NAME "-%" PRIu32,
+                                       lttng_snapshot_output_get_id(snapshot_output));
+                       if (pret < 0) {
+                               name = NULL;
+                               PERROR("snprintf output name");
+                               goto error_snapshot_output;
+                       }
+               }
+
                ret = lttng_snapshot_output_set_name(name, snapshot_output);
                if (ret) {
                        goto error_snapshot_output;
@@ -1293,11 +1366,6 @@ int create_session(const char *name,
        }
 
        if (output.control_uri || output.data_uri) {
-               int i;
-               struct lttng_domain *domain;
-               struct lttng_domain *domains[] =
-                       { kernel_domain, ust_domain, jul_domain, log4j_domain };
-
                /* network destination */
                if (live_timer_interval && live_timer_interval != UINT64_MAX) {
                        /*
@@ -1313,18 +1381,12 @@ int create_session(const char *name,
                        goto end;
                }
 
-               for (i = 0; i < (sizeof(domains) / sizeof(domains[0])); i++) {
-                       domain = domains[i];
-                       if (!domain) {
-                               continue;
-                       }
-
-                       ret = create_session_net_output(name, domain, output.control_uri,
-                                       output.data_uri);
-                       if (ret) {
-                               goto end;
-                       }
+               ret = create_session_net_output(name, output.control_uri,
+                               output.data_uri);
+               if (ret) {
+                       goto end;
                }
+
        } else {
                /* either local output or no output */
                ret = lttng_create_session(name, output.path);
@@ -1417,9 +1479,9 @@ end:
 
 static
 int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle,
-       const char *channel_name)
+       const char *channel_name, const enum process_event_node_phase phase)
 {
-       int ret, i;
+       int ret = 0, i;
        xmlNodePtr node;
        struct lttng_event event;
        char **exclusions = NULL;
@@ -1564,6 +1626,7 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle,
                                goto end;
                        }
 
+                       free(filter_expression);
                        filter_expression = strdup((char *) content);
                        free(content);
                        if (!filter_expression) {
@@ -1670,25 +1733,14 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle,
                }
        }
 
-       ret = lttng_enable_event_with_exclusions(handle, &event, channel_name,
-                       filter_expression, exclusion_count, exclusions);
-       if (ret) {
-               goto end;
-       }
-
-       if (!event.enabled) {
-               /*
-                * Note that we should use lttng_disable_event_ext() (2.6+) to
-                * eliminate the risk of clashing on events of the same
-                * name (with different event types and loglevels).
-                *
-                * Unfortunately, lttng_disable_event_ext() only performs a
-                * match on the name and event type and errors out if any other
-                * event attribute is not set to its default value.
-                *
-                * This will disable all events that match this name.
-                */
-               ret = lttng_disable_event(handle, event.name, channel_name);
+       if ((event.enabled && phase == ENABLE) || phase == CREATION) {
+               ret = lttng_enable_event_with_exclusions(handle, &event, channel_name,
+                               filter_expression, exclusion_count, exclusions);
+               if (ret < 0) {
+                       WARN("Enabling event (name:%s) on load failed.", event.name);
+                       ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+                       goto end;
+               }
        }
 end:
        for (i = 0; i < exclusion_count; i++) {
@@ -1705,6 +1757,7 @@ int process_events_node(xmlNodePtr events_node, struct lttng_handle *handle,
        const char *channel_name)
 {
        int ret = 0;
+       struct lttng_event event;
        xmlNodePtr node;
 
        assert(events_node);
@@ -1713,19 +1766,41 @@ int process_events_node(xmlNodePtr events_node, struct lttng_handle *handle,
 
        for (node = xmlFirstElementChild(events_node); node;
                node = xmlNextElementSibling(node)) {
-               ret = process_event_node(node, handle, channel_name);
+               ret = process_event_node(node, handle, channel_name, CREATION);
                if (ret) {
                        goto end;
                }
        }
+
+       /*
+        * Disable all events to enable only the necessary events.
+        * Limitations regarding lttng_disable_events and tuple descriptor
+        * force this approach.
+        */
+       memset(&event, 0, sizeof(event));
+       event.loglevel = -1;
+       event.type = LTTNG_EVENT_ALL;
+       ret = lttng_disable_event_ext(handle, &event, channel_name, NULL);
+       if (ret) {
+               goto end;
+       }
+
+       for (node = xmlFirstElementChild(events_node); node;
+                       node = xmlNextElementSibling(node)) {
+               ret = process_event_node(node, handle, channel_name, ENABLE);
+               if (ret) {
+                       goto end;
+               }
+       }
+
 end:
        return ret;
 }
 
 static
-int process_channel_attr_node(xmlNodePtr attr_node,
-               struct lttng_channel *channel, xmlNodePtr *contexts_node,
-               xmlNodePtr *events_node)
+int process_channel_attr_node(xmlNodePtr attr_node, bool snapshot_mode,
+               enum lttng_domain_type domain, struct lttng_channel *channel,
+               xmlNodePtr *contexts_node, xmlNodePtr *events_node)
 {
        int ret;
 
@@ -1970,6 +2045,7 @@ int process_channel_attr_node(xmlNodePtr attr_node,
                /* contexts */
                *contexts_node = attr_node;
        }
+
        ret = 0;
 end:
        return ret;
@@ -2224,7 +2300,8 @@ end:
 
 
 static
-int process_domain_node(xmlNodePtr domain_node, const char *session_name)
+int process_domain_node(xmlNodePtr domain_node, const char *session_name,
+               bool snapshot_mode)
 {
        int ret;
        struct lttng_domain domain = { 0 };
@@ -2276,12 +2353,19 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
                        channel_attr_node; channel_attr_node =
                        xmlNextElementSibling(channel_attr_node)) {
                        ret = process_channel_attr_node(channel_attr_node,
-                               &channel, &contexts_node, &events_node);
+                               snapshot_mode, domain.type, &channel,
+                               &contexts_node, &events_node);
                        if (ret) {
                                goto end;
                        }
                }
 
+               if (!channel.name) {
+                       ERR("Encountered a channel with no name attribute.");
+                       ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+                       goto end;
+               }
+
                ret = lttng_enable_channel(handle, &channel);
                if (ret < 0) {
                        goto end;
@@ -2547,7 +2631,8 @@ domain_init_error:
 
        for (node = xmlFirstElementChild(domains_node); node;
                node = xmlNextElementSibling(node)) {
-               ret = process_domain_node(node, (const char *) name);
+               ret = process_domain_node(node, (const char *) name,
+                               snapshot_mode == 1);
                if (ret) {
                        goto end;
                }
@@ -2662,6 +2747,46 @@ end:
        return ret;
 }
 
+static
+int load_session_from_document(struct config_document *document, const char *session_name,
+               struct session_config_validation_ctx *validation_ctx, int override)
+{
+       int ret, session_found = !session_name;
+       xmlNodePtr sessions_node;
+       xmlNodePtr session_node;
+
+       assert(validation_ctx);
+
+       ret = xmlSchemaValidateDoc(validation_ctx->schema_validation_ctx, document->document);
+       if (ret) {
+               ERR("Session configuration file validation failed");
+               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+               goto end;
+       }
+
+       sessions_node = xmlDocGetRootElement(document->document);
+       if (!sessions_node) {
+               goto end;
+       }
+
+       for (session_node = xmlFirstElementChild(sessions_node);
+               session_node; session_node =
+                       xmlNextElementSibling(session_node)) {
+               ret = process_session_node(session_node,
+                       session_name, override);
+               if (session_name && ret == 0) {
+                       /* Target session found and loaded */
+                       session_found = 1;
+                       break;
+               }
+       }
+end:
+       if (!ret) {
+               ret = session_found ? 0 : -LTTNG_ERR_LOAD_SESSION_NOENT;
+       }
+       return ret;
+}
+
 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
 static
 struct dirent *alloc_dirent(const char *path)
@@ -2782,8 +2907,8 @@ end:
                }
        }
 
-       if (!session_found) {
-               ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
+       if (session_found) {
+               ret = 0;
        }
 
        return ret;
@@ -2828,6 +2953,7 @@ int config_load_session(const char *path, const char *session_name,
                int override, unsigned int autoload)
 {
        int ret;
+       bool session_loaded = false;
        const char *path_ptr = NULL;
        struct session_config_validation_ctx validation_ctx = { 0 };
 
@@ -2886,6 +3012,7 @@ int config_load_session(const char *path, const char *session_name,
                                 * Continue even if the session was found since we have to try
                                 * the system wide sessions.
                                 */
+                               session_loaded = true;
                        }
                }
 
@@ -2908,6 +3035,9 @@ int config_load_session(const char *path, const char *session_name,
                if (path_ptr) {
                        ret = load_session_from_path(path_ptr, session_name,
                                        &validation_ctx, override);
+                       if (!ret) {
+                               session_loaded = true;
+                       }
                }
        } else {
                ret = access(path, F_OK);
@@ -2940,5 +3070,585 @@ end:
                 */
                ret = 0;
        }
+
+       if (session_loaded && ret == -LTTNG_ERR_LOAD_SESSION_NOENT) {
+               /* A matching session was found in one of the search paths. */
+               ret = 0;
+       }
        return ret;
 }
+
+static
+void __attribute__((destructor)) session_config_exit(void)
+{
+       xmlCleanupParser();
+}
+
+LTTNG_HIDDEN
+struct config_document *config_document_get(const char *path)
+{
+       int ret;
+       struct config_document *document = NULL;
+       struct session_config_validation_ctx validation_ctx = { 0 };
+
+       assert(path);
+
+       ret = access(path, F_OK);
+       if (ret < 0) {
+               PERROR("access");
+               switch (errno) {
+               case ENOENT:
+                       ERR("Configuration document path does not exist.");
+                       break;
+               case EACCES:
+                       ERR("Configuration document permission denied.");
+                       break;
+               default:
+                       ERR("Configuration document unknown error.");
+                       break;
+               }
+               goto end;
+       }
+
+       ret = init_session_config_validation_ctx(&validation_ctx);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_file_read_creds(path);
+       if (ret != 1) {
+               if (ret == -1) {
+                       ERR("Configuration document permission denied.");
+               } else {
+                       ERR("Configuration document does not exist.");
+               }
+               goto end;
+       }
+
+       document = zmalloc(sizeof(struct config_document));
+       if (!document) {
+               PERROR("zmalloc");
+               goto end;
+       }
+
+       document->document = xmlParseFile(path);
+       if (!document->document) {
+               ERR("Configuration document parsing failed.");
+               goto error;
+       }
+
+       ret = xmlSchemaValidateDoc(validation_ctx.schema_validation_ctx,
+                       document->document);
+       if (ret) {
+               ERR("Session configuration file validation failed");
+               goto error;
+       }
+
+end:
+       fini_session_config_validation_ctx(&validation_ctx);
+       return document;
+error:
+       xmlFreeDoc(document->document);
+       free(document);
+       return NULL;
+}
+
+LTTNG_HIDDEN
+void config_document_free(struct config_document *document)
+{
+       if (document) {
+               xmlFreeDoc(document->document);
+               document->document = NULL;
+       }
+
+       free(document);
+}
+
+LTTNG_HIDDEN
+int config_document_replace_element_value(struct config_document *document,
+               const char *xpath, const char *value)
+{
+       int ret = 0;
+       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);
+       assert(value);
+
+       internal_xpath = encode_string(xpath);
+       if (!internal_xpath) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Unable to encode xpath string");
+               goto end;
+       }
+
+       internal_value = encode_string(value);
+       if (!internal_value) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Unable to encode xpath replace value string");
+               goto end;
+       }
+
+       /* Initialize xpath context */
+       xpath_context = xmlXPathNewContext(document->document);
+       if (!xpath_context) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Unable to create xpath context");
+               goto end;
+       }
+
+       /* Evaluate de xpath expression */
+       xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context);
+       if (!xpath_object) {
+               ret = -LTTNG_ERR_CONFIG_INVALID_QUERY;
+               goto end;
+       }
+
+       /* TODO: from here could be extracted and previopus could be a step in
+        * subsequent operation, modify/substitute/delete node.
+        */
+       xpath_result_set = xpath_object->nodesetval;
+       if (!xpath_result_set) {
+               ret = -LTTNG_ERR_CONFIG_EMPTY_SET;
+               goto end;
+       }
+
+       xpath_result_size = xpath_result_set->nodeNr;
+
+       /*
+        * Reverse traversal since last element could be nested under parent
+        * element present in the result set.
+        */
+       for (int i = xpath_result_size - 1; i >=0; i--) {
+               assert(xpath_result_set->nodeTab[i]);
+               xmlNodeSetContent(xpath_result_set->nodeTab[i], internal_value);
+
+               /*
+                * Libxml2 quirk regarding the freing and namesplace node see
+                * libxml2 example and documentation for more details.
+                */
+               if (xpath_result_set->nodeTab[i]->type != XML_NAMESPACE_DECL) {
+                       xpath_result_set->nodeTab[i] = NULL;
+               }
+       }
+
+end:
+       xmlXPathFreeContext(xpath_context);
+       xmlXPathFreeObject(xpath_object);
+       xmlFree(internal_xpath);
+       xmlFree(internal_value);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int config_load_configuration_sessions(struct config_document *document,
+               const char *session_name, int override)
+{
+       int ret;
+       struct session_config_validation_ctx validation_ctx = { 0 };
+
+       ret = init_session_config_validation_ctx(&validation_ctx);
+       if (ret) {
+               goto end;
+       }
+       ret = load_session_from_document(document, session_name,
+                       &validation_ctx, override);
+end:
+       fini_session_config_validation_ctx(&validation_ctx);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int config_document_replace_element(struct config_document *document,
+               const char *xpath, const struct config_element *element)
+{
+       int ret = 0;
+       int xpath_result_size;
+
+       xmlXPathContextPtr xpath_context = NULL;
+       xmlXPathObjectPtr xpath_object = NULL;
+       xmlNodeSetPtr xpath_result_set = NULL;
+       xmlChar *internal_xpath = NULL;
+       xmlNodePtr old_node = NULL;
+       xmlNodePtr copy = NULL;
+
+       assert(document);
+       assert(xpath);
+       assert(element);
+       assert(element->element);
+
+       internal_xpath = encode_string(xpath);
+       if (!internal_xpath) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Unable to encode xpath string");
+               goto end;
+       }
+
+       /* Initialize xpath context */
+       xpath_context = xmlXPathNewContext(document->document);
+       if (!xpath_context) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Unable to create xpath context");
+               goto end;
+       }
+
+       /* Evaluate the xpath expression */
+       xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context);
+       if (!xpath_object) {
+               ret = -LTTNG_ERR_CONFIG_INVALID_QUERY;
+               goto end;
+       }
+
+       xpath_result_set = xpath_object->nodesetval;
+       if (!xpath_result_set) {
+               ret = -LTTNG_ERR_CONFIG_EMPTY_SET;
+               goto end;
+       }
+
+       xpath_result_size = xpath_result_set->nodeNr;
+
+       if (xpath_result_size > 1) {
+               ret = -LTTNG_ERR_CONFIG_INVALID_COUNT;
+               goto end;
+       }
+
+       if (xpath_result_size == 0) {
+               ret = -LTTNG_ERR_CONFIG_REPLACEMENT;
+               goto end;
+       }
+
+       assert(xpath_result_set->nodeTab[0]);
+
+       /* Do a copy of the element to ease caller memory management */
+       copy = xmlCopyNode(element->element, 1);
+       if (!copy) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Copy failed for node replacement");
+               goto end;
+       }
+
+       old_node = xmlReplaceNode(xpath_result_set->nodeTab[0], copy);
+       if (xpath_result_set->nodeTab[0]->type != XML_NAMESPACE_DECL)
+                  xpath_result_set->nodeTab[0] = NULL;
+       if (!old_node) {
+               ret = -LTTNG_ERR_CONFIG_REPLACEMENT;
+               xmlFreeNode(copy);
+               goto end;
+       }
+       xmlUnlinkNode(old_node);
+       xmlFreeNode(old_node);
+end:
+       xmlXPathFreeContext(xpath_context);
+       xmlXPathFreeObject(xpath_object);
+       xmlFree(internal_xpath);
+       return ret;
+}
+
+LTTNG_HIDDEN
+char *config_document_get_element_value(struct config_document *document,
+               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;
+
+       assert(document);
+       assert(xpath);
+
+       internal_xpath = encode_string(xpath);
+       if (!internal_xpath) {
+               value = NULL;
+               ERR("Unable to encode xpath string");
+               goto end;
+       }
+
+       /* Initialize xpath context */
+       xpath_context = xmlXPathNewContext(document->document);
+       if (!xpath_context) {
+               value = NULL;
+               ERR("Unable to create xpath context");
+               goto end;
+       }
+
+       /* Evaluate the xpath expression */
+       xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context);
+       if (!xpath_object) {
+               value = NULL;
+               ERR("Unable to evaluate xpath query (invalid query format)");
+               goto end;
+       }
+
+       xpath_result_set = xpath_object->nodesetval;
+       if (!xpath_result_set) {
+               value = NULL;
+               goto end;
+       }
+
+       xpath_result_size = xpath_result_set->nodeNr;
+
+       if (xpath_result_size > 1) {
+               ERR("To many result while fetching config element value");
+               value = NULL;
+               goto end;
+       }
+
+       if (xpath_result_size == 0) {
+               value = NULL;
+               goto end;
+       }
+
+       /*
+        * Reverse traversal since last element could be nested under parent
+        * element present in the result set.
+        */
+       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);
+       return value;
+}
+
+LTTNG_HIDDEN
+int config_document_element_exist(struct config_document *document,
+               const char *xpath)
+{
+       int exist = 0;
+       int xpath_result_size;
+
+       xmlXPathContextPtr xpath_context = NULL;
+       xmlXPathObjectPtr xpath_object = NULL;
+       xmlNodeSetPtr xpath_result_set = NULL;
+       xmlChar *internal_xpath = NULL;
+
+       assert(document);
+       assert(document->document);
+       assert(xpath);
+
+       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) {
+               exist = 1;
+       }
+end:
+       xmlXPathFreeContext(xpath_context);
+       xmlXPathFreeObject(xpath_object);
+       xmlFree(internal_xpath);
+       return exist;
+
+}
+
+LTTNG_HIDDEN
+struct config_element *config_element_create(const char *name,
+               const char* value)
+{
+       struct config_element *element;
+
+       assert(name);
+
+       xmlChar *internal_name = NULL;
+       xmlChar *internal_value = NULL;
+
+       internal_name = encode_string(name);
+       if (!internal_name) {
+               ERR("Unable to encode config element name string");
+               element = NULL;
+               goto end;
+       }
+
+
+       if (value) {
+               internal_value = encode_string(value);
+               if (!internal_value) {
+                       ERR("Unable to encode config_element value string");
+                       element = NULL;
+                       goto end;
+               }
+       }
+
+       element = zmalloc(sizeof(struct config_element));
+       if (!element) {
+               goto end;
+       }
+
+       element->element = xmlNewNode(NULL, internal_name);
+       if (!element->element) {
+               free(element);
+               element = NULL;
+               goto end;
+       }
+
+       if (internal_value) {
+               xmlNodeAddContent(element->element, internal_value);
+       }
+end:
+       xmlFree(internal_name);
+       xmlFree(internal_value);
+       return element;
+}
+
+LTTNG_HIDDEN
+int config_element_add_child(struct config_element *parent,
+               const struct config_element *child)
+{
+       assert(parent);
+       assert(child);
+       assert(parent->element);
+       assert(child->element);
+
+       int ret = 0;
+       xmlNodePtr node = NULL;
+       xmlNodePtr copy = NULL;
+
+       /* Do a copy to ease the memory management for caller */
+       copy = xmlCopyNode(child->element, 1);
+       if (!copy) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto error;
+       }
+       node = xmlAddChild(parent->element, copy);
+       if (!node) {
+               xmlFreeNode(copy);
+               ret = -LTTNG_ERR_CONFIG_ADD_CHILD;
+               goto error;
+       }
+error:
+       return ret;
+}
+
+
+LTTNG_HIDDEN
+int config_document_insert_element(struct config_document *document,
+               const char *xpath, const struct config_element *element)
+{
+       int ret = 0;
+       int xpath_result_size;
+
+       xmlXPathContextPtr xpath_context = NULL;
+       xmlXPathObjectPtr xpath_object = NULL;
+       xmlNodeSetPtr xpath_result_set = NULL;
+       xmlChar *internal_xpath = NULL;
+       xmlNodePtr child_node = NULL;
+       xmlNodePtr local_copy = NULL;
+
+       assert(document);
+       assert(xpath);
+       assert(element);
+       assert(element->element);
+
+       internal_xpath = encode_string(xpath);
+       if (!internal_xpath) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Initialize xpath context */
+       xpath_context = xmlXPathNewContext(document->document);
+       if (!xpath_context) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Evaluate the xpath expression */
+       xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context);
+       if (!xpath_object) {
+               ret = -LTTNG_ERR_CONFIG_INVALID_QUERY;
+               goto end;
+       }
+
+       xpath_result_set = xpath_object->nodesetval;
+       if (!xpath_result_set) {
+               ret = -LTTNG_ERR_CONFIG_EMPTY_SET;
+               goto end;
+       }
+
+       xpath_result_size = xpath_result_set->nodeNr;
+
+       if (xpath_result_size > 1) {
+               ret = -LTTNG_ERR_CONFIG_INVALID_COUNT;
+               goto end;
+       }
+
+       if (xpath_result_size == 0) {
+               ret = -LTTNG_ERR_CONFIG_INVALID_COUNT;
+               goto end;
+       }
+
+       assert(xpath_result_set->nodeTab[0]);
+       /* Do a copy to simply memory management */
+       local_copy = xmlCopyNode(element->element, 1);
+       if (!local_copy) {
+               ret = -LTTNG_ERR_NOMEM;
+               ERR("Duplication of node to be insert failed");
+               goto end;
+       }
+
+       child_node = xmlAddChild(xpath_result_set->nodeTab[0], local_copy);
+       if (!child_node) {
+               ret = -LTTNG_ERR_CONFIG_ADD_CHILD;
+               xmlFreeNode(local_copy);
+               goto end;
+       }
+end:
+       xmlXPathFreeContext(xpath_context);
+       xmlXPathFreeObject(xpath_object);
+       xmlFree(internal_xpath);
+       return ret;
+}
+
+LTTNG_HIDDEN
+void config_element_free(struct config_element *element) {
+       if (element && element->element) {
+               xmlFreeNode(element->element);
+       }
+
+       free(element);
+}
This page took 0.038745 seconds and 5 git commands to generate.