Fix: call xmlCleanupParser to free global libxml2 allocations
[lttng-tools.git] / src / common / config / config.c
index a4b59ff0865e559e3f2dea86bbc8c3cc022bcec2..f0d38ef92f647c5a81f2eceafbb5240442d7ea6a 100644 (file)
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdbool.h>
 
 #include <common/defaults.h>
 #include <common/error.h>
@@ -118,6 +119,10 @@ const char * const config_element_max_size = "max_size";
 const char * const config_element_pid = "pid";
 const char * const config_element_pids = "pids";
 const char * const config_element_shared_memory_path = "shared_memory_path";
+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_domain_type_kernel = "KERNEL";
 const char * const config_domain_type_ust = "UST";
@@ -163,6 +168,11 @@ 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";
 
+enum process_event_node_phase {
+       CREATION = 0,
+       ENABLE = 1,
+};
+
 struct consumer_output {
        int enabled;
        char *path;
@@ -336,11 +346,10 @@ static xmlChar *encode_string(const char *in_str)
 
        in_len = strlen(in_str);
        /*
-        * Add 1 byte for the NULL terminted character. The factor 2 here is
-        * because UTF-8 can be on two bytes so this fits the worst case for each
-        * bytes.
+        * Add 1 byte for the NULL terminted character. The factor 4 here is
+        * used because UTF-8 characters can take up to 4 bytes.
         */
-       out_len = (in_len * 2) + 1;
+       out_len = (in_len * 4) + 1;
        out_str = xmlMalloc(out_len);
        if (!out_str) {
                goto end;
@@ -1093,17 +1102,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;
@@ -1285,11 +1293,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) {
                        /*
@@ -1305,18 +1308,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);
@@ -1409,9 +1406,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;
@@ -1424,6 +1421,26 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle,
 
        memset(&event, 0, sizeof(event));
 
+       /* Initialize default log level which varies by domain */
+       switch (handle->domain.type)
+       {
+       case LTTNG_DOMAIN_JUL:
+               event.loglevel = LTTNG_LOGLEVEL_JUL_ALL;
+               break;
+       case LTTNG_DOMAIN_LOG4J:
+               event.loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
+               break;
+       case LTTNG_DOMAIN_PYTHON:
+               event.loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
+               break;
+       case LTTNG_DOMAIN_UST:
+       case LTTNG_DOMAIN_KERNEL:
+               event.loglevel = LTTNG_LOGLEVEL_DEBUG;
+               break;
+       default:
+               assert(0);
+       }
+
        for (node = xmlFirstElementChild(event_node); node;
                node = xmlNextElementSibling(node)) {
                if (!strcmp((const char *) node->name, config_element_name)) {
@@ -1536,6 +1553,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) {
@@ -1642,25 +1660,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++) {
@@ -1677,6 +1684,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);
@@ -1685,11 +1693,33 @@ 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;
 }
@@ -2088,6 +2118,79 @@ end:
        return ret;
 }
 
+static
+int process_pid_tracker_node(xmlNodePtr pid_tracker_node,
+       struct lttng_handle *handle)
+{
+       int ret, child;
+       xmlNodePtr targets_node = NULL;
+       xmlNodePtr node;
+
+       assert(handle);
+       assert(pid_tracker_node);
+       /* get the targets node */
+       for (node = xmlFirstElementChild(pid_tracker_node); node;
+               node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *) node->name,
+                               config_element_targets)) {
+                       targets_node = node;
+                       break;
+               }
+       }
+
+       if (!targets_node) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       /* Go through all pid_target node */
+       child = xmlChildElementCount(targets_node);
+       if (child == 0) {
+               /* The session is explicitly set to target nothing. */
+               ret = lttng_untrack_pid(handle, -1);
+               if (ret) {
+                       goto end;
+               }
+       }
+       for (node = xmlFirstElementChild(targets_node); node;
+                       node = xmlNextElementSibling(node)) {
+               xmlNodePtr pid_target_node = node;
+
+               /* get pid node and track it */
+               for (node = xmlFirstElementChild(pid_target_node); node;
+                       node = xmlNextElementSibling(node)) {
+                       if (!strcmp((const char *) node->name,
+                                       config_element_pid)) {
+                               int64_t pid;
+                               xmlChar *content = NULL;
+
+                               content = xmlNodeGetContent(node);
+                               if (!content) {
+                                       ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
+                                       goto end;
+                               }
+
+                               ret = parse_int(content, &pid);
+                               free(content);
+                               if (ret) {
+                                       ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
+                                       goto end;
+                               }
+
+                               ret = lttng_track_pid(handle, (int) pid);
+                               if (ret) {
+                                       goto end;
+                               }
+                       }
+               }
+               node = pid_target_node;
+       }
+
+end:
+       return ret;
+}
+
+
 static
 int process_domain_node(xmlNodePtr domain_node, const char *session_name)
 {
@@ -2095,6 +2198,8 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
        struct lttng_domain domain = { 0 };
        struct lttng_handle *handle = NULL;
        xmlNodePtr channels_node = NULL;
+       xmlNodePtr trackers_node = NULL;
+       xmlNodePtr pid_tracker_node = NULL;
        xmlNodePtr node;
 
        assert(session_name);
@@ -2161,6 +2266,36 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
                        goto end;
                }
        }
+
+       /* get the trackers node */
+       for (node = xmlFirstElementChild(domain_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *) node->name,
+                                       config_element_trackers)) {
+                       trackers_node = node;
+                       break;
+               }
+       }
+
+       if (!trackers_node) {
+               goto end;
+       }
+
+       for (node = xmlFirstElementChild(trackers_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *)node->name,config_element_pid_tracker)) {
+                       pid_tracker_node = node;
+                       ret = process_pid_tracker_node(pid_tracker_node, handle);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+
+       if (!pid_tracker_node) {
+               lttng_track_pid(handle, -1);
+       }
+
 end:
        lttng_destroy_handle(handle);
        return ret;
@@ -2495,6 +2630,23 @@ end:
        return ret;
 }
 
+/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
+static
+struct dirent *alloc_dirent(const char *path)
+{
+       size_t len;
+       long name_max;
+       struct dirent *entry;
+
+       name_max = pathconf(path, _PC_NAME_MAX);
+       if (name_max == -1) {
+               name_max = PATH_MAX;
+       }
+       len = offsetof(struct dirent, d_name) + name_max + 1;
+       entry = zmalloc(len);
+       return entry;
+}
+
 static
 int load_session_from_path(const char *path, const char *session_name,
        struct session_config_validation_ctx *validation_ctx, int override)
@@ -2530,7 +2682,7 @@ int load_session_from_path(const char *path, const char *session_name,
                        goto end;
                }
 
-               entry = zmalloc(sizeof(*entry));
+               entry = alloc_dirent(path);
                if (!entry) {
                        ret = -LTTNG_ERR_NOMEM;
                        goto end;
@@ -2598,8 +2750,8 @@ end:
                }
        }
 
-       if (!session_found) {
-               ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
+       if (session_found) {
+               ret = 0;
        }
 
        return ret;
@@ -2644,6 +2796,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 };
 
@@ -2702,6 +2855,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;
                        }
                }
 
@@ -2724,6 +2878,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);
@@ -2756,5 +2913,16 @@ 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();
+}
This page took 0.028756 seconds and 4 git commands to generate.