#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <stdbool.h>
#include <common/defaults.h>
#include <common/error.h>
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";
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;
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;
}
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;
}
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) {
/*
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);
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;
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)) {
goto end;
}
+ free(filter_expression);
filter_expression = strdup((char *) content);
free(content);
if (!filter_expression) {
}
}
- 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++) {
const char *channel_name)
{
int ret = 0;
+ struct lttng_event event;
xmlNodePtr node;
assert(events_node);
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;
}
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)
{
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);
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;
{
int ret, started = -1, snapshot_mode = -1;
uint64_t live_timer_interval = UINT64_MAX;
- char *name = NULL;
+ xmlChar *name = NULL;
+ xmlChar *shm_path = NULL;
xmlNodePtr domains_node = NULL;
xmlNodePtr output_node = NULL;
xmlNodePtr node;
goto error;
}
- name = (char *) node_content;
+ name = node_content;
} else if (!domains_node && !strcmp((const char *) node->name,
config_element_domains)) {
/* domains */
config_element_output)) {
/* output */
output_node = node;
+ } else if (!shm_path && !strcmp((const char *) node->name,
+ config_element_shared_memory_path)) {
+ /* shared memory path */
+ xmlChar *node_content = xmlNodeGetContent(node);
+ if (!node_content) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto error;
+ }
+
+ shm_path = node_content;
} else {
/* attributes, snapshot_mode or live_timer_interval */
xmlNodePtr attributes_child =
goto error;
}
- if (session_name && strcmp(name, session_name)) {
+ if (session_name && strcmp((char *) name, session_name)) {
/* This is not the session we are looking for */
ret = -LTTNG_ERR_NO_SESSION;
goto error;
if (override) {
/* Destroy session if it exists */
- ret = lttng_destroy_session(name);
+ ret = lttng_destroy_session((const char *) name);
if (ret && ret != -LTTNG_ERR_SESS_NOT_FOUND) {
ERR("Failed to destroy existing session.");
goto error;
/* Create session type depending on output type */
if (snapshot_mode && snapshot_mode != -1) {
- ret = create_snapshot_session(name, output_node);
+ ret = create_snapshot_session((const char *) name, output_node);
} else if (live_timer_interval &&
live_timer_interval != UINT64_MAX) {
- ret = create_session(name, kernel_domain, ust_domain, jul_domain,
- log4j_domain, output_node, live_timer_interval);
+ ret = create_session((const char *) name, kernel_domain,
+ ust_domain, jul_domain, log4j_domain,
+ output_node, live_timer_interval);
} else {
/* regular session */
- ret = create_session(name, kernel_domain, ust_domain, jul_domain,
- log4j_domain, output_node, UINT64_MAX);
+ ret = create_session((const char *) name, kernel_domain,
+ ust_domain, jul_domain, log4j_domain,
+ output_node, UINT64_MAX);
}
if (ret) {
goto error;
}
+ if (shm_path) {
+ ret = lttng_set_session_shm_path((const char *) name,
+ (const char *) shm_path);
+ if (ret) {
+ goto error;
+ }
+ }
+
for (node = xmlFirstElementChild(domains_node); node;
node = xmlNextElementSibling(node)) {
- ret = process_domain_node(node, name);
+ ret = process_domain_node(node, (const char *) name);
if (ret) {
goto end;
}
}
if (started) {
- ret = lttng_start_tracing(name);
+ ret = lttng_start_tracing((const char *) name);
if (ret) {
goto end;
}
end:
if (ret < 0) {
- ERR("Failed to load session %s: %s", name, lttng_strerror(ret));
- lttng_destroy_session(name);
+ ERR("Failed to load session %s: %s", (const char *) name,
+ lttng_strerror(ret));
+ lttng_destroy_session((const char *) name);
}
error:
free(jul_domain);
free(log4j_domain);
free(python_domain);
- free(name);
+ xmlFree(name);
+ xmlFree(shm_path);
return ret;
}
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)
goto end;
}
- entry = zmalloc(sizeof(*entry));
+ entry = alloc_dirent(path);
if (!entry) {
ret = -LTTNG_ERR_NOMEM;
goto end;
}
}
- if (!session_found) {
- ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
+ if (session_found) {
+ ret = 0;
}
return ret;
int override, unsigned int autoload)
{
int ret;
+ bool session_loaded = false;
const char *path_ptr = NULL;
struct session_config_validation_ctx validation_ctx = { 0 };
* Continue even if the session was found since we have to try
* the system wide sessions.
*/
+ session_loaded = true;
}
}
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);
*/
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();
+}