X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fconfig%2Fsession-config.c;h=518fde70b5e63d1d244369ca634d0a647bb75f21;hp=313010d24bb8fd780b10e9245f6602a4dd9b4927;hb=ff86d8d0bd96d3660ad79aa6158fbeb9055652b2;hpb=fbd987c9bced83c0bb725418170a9b43d72b0b0e diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 313010d24..518fde70b 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include "session-config.h" #include "config-internal.h" @@ -91,6 +93,8 @@ const char * const config_element_subbuf_size = "subbuffer_size"; const char * const config_element_num_subbuf = "subbuffer_count"; const char * const config_element_switch_timer_interval = "switch_timer_interval"; const char * const config_element_read_timer_interval = "read_timer_interval"; +LTTNG_HIDDEN const char * const config_element_monitor_timer_interval = "monitor_timer_interval"; +LTTNG_HIDDEN const char * const config_element_blocking_timeout = "blocking_timeout"; const char * const config_element_output = "output"; const char * const config_element_output_type = "output_type"; const char * const config_element_tracefile_size = "tracefile_size"; @@ -129,6 +133,10 @@ const char * const config_element_trackers = "trackers"; const char * const config_element_targets = "targets"; const char * const config_element_target_pid = "pid_target"; +LTTNG_HIDDEN const char * const config_element_rotation_timer_interval = "rotation_schedule_timer_period"; +LTTNG_HIDDEN const char * const config_element_rotation_size = "rotation_schedule_size"; +LTTNG_HIDDEN const char * const config_element_rotation_schedule = "rotation_schedule"; + const char * const config_domain_type_kernel = "KERNEL"; const char * const config_domain_type_ust = "UST"; const char * const config_domain_type_jul = "JUL"; @@ -670,13 +678,12 @@ char *get_session_config_xsd_path() goto end; } - strncpy(xsd_path, base_path, max_path_len); + strcpy(xsd_path, base_path); if (xsd_path[base_path_len - 1] != '/') { xsd_path[base_path_len++] = '/'; } - strncpy(xsd_path + base_path_len, DEFAULT_SESSION_CONFIG_XSD_FILENAME, - max_path_len - base_path_len); + strcpy(xsd_path + base_path_len, DEFAULT_SESSION_CONFIG_XSD_FILENAME); end: return xsd_path; } @@ -1188,7 +1195,8 @@ end: } static -int create_snapshot_session(const char *session_name, xmlNodePtr output_node) +int create_snapshot_session(const char *session_name, xmlNodePtr output_node, + const struct config_load_session_override_attr *overrides) { int ret; xmlNodePtr node = NULL; @@ -1218,6 +1226,9 @@ int create_snapshot_session(const char *session_name, xmlNodePtr output_node) uint64_t max_size = UINT64_MAX; struct consumer_output output = { 0 }; struct lttng_snapshot_output *snapshot_output = NULL; + const char *control_uri = NULL; + const char *data_uri = NULL; + const char *path = NULL; for (node = xmlFirstElementChild(snapshot_output_node); node; node = xmlNextElementSibling(node)) { @@ -1253,6 +1264,30 @@ int create_snapshot_session(const char *session_name, xmlNodePtr output_node) } } + control_uri = output.control_uri; + data_uri = output.data_uri; + path = output.path; + + if (overrides) { + if (overrides->path_url) { + path = overrides->path_url; + /* Control/data_uri are null */ + control_uri = NULL; + data_uri = NULL; + } else { + if (overrides->ctrl_url) { + control_uri = overrides->ctrl_url; + /* path is null */ + path = NULL; + } + if (overrides->data_url) { + data_uri = overrides->data_url; + /* path is null */ + path = NULL; + } + } + } + snapshot_output = lttng_snapshot_output_create(); if (!snapshot_output) { ret = -LTTNG_ERR_NOMEM; @@ -1269,23 +1304,23 @@ int create_snapshot_session(const char *session_name, xmlNodePtr output_node) goto error_snapshot_output; } - if (output.path) { - ret = lttng_snapshot_output_set_ctrl_url(output.path, + if (path) { + ret = lttng_snapshot_output_set_ctrl_url(path, snapshot_output); if (ret) { goto error_snapshot_output; } } else { - if (output.control_uri) { - ret = lttng_snapshot_output_set_ctrl_url(output.control_uri, + if (control_uri) { + ret = lttng_snapshot_output_set_ctrl_url(control_uri, snapshot_output); if (ret) { goto error_snapshot_output; } } - if (output.data_uri) { - ret = lttng_snapshot_output_set_data_url(output.data_uri, + if (data_uri) { + ret = lttng_snapshot_output_set_data_url(data_uri, snapshot_output); if (ret) { goto error_snapshot_output; @@ -1310,16 +1345,16 @@ end: static int create_session(const char *name, - struct lttng_domain *kernel_domain, - struct lttng_domain *ust_domain, - struct lttng_domain *jul_domain, - struct lttng_domain *log4j_domain, xmlNodePtr output_node, - uint64_t live_timer_interval) + uint64_t live_timer_interval, + const struct config_load_session_override_attr *overrides) { int ret; struct consumer_output output = { 0 }; xmlNodePtr consumer_output_node; + const char *control_uri = NULL; + const char *data_uri = NULL; + const char *path = NULL; assert(name); @@ -1344,13 +1379,38 @@ int create_session(const char *name, } } - if (live_timer_interval != UINT64_MAX && - !output.control_uri && !output.data_uri) { + control_uri = output.control_uri; + data_uri = output.data_uri; + path = output.path; + + /* Check for override and apply them */ + if (overrides) { + if (overrides->path_url) { + path = overrides->path_url; + /* control/data_uri are null */; + control_uri = NULL; + data_uri = NULL; + } else { + if (overrides->ctrl_url) { + control_uri = overrides->ctrl_url; + /* path is null */ + path = NULL; + } + if (overrides->data_url) { + data_uri = overrides->data_url; + /* path is null */ + path = NULL; + } + } + } + + + if (live_timer_interval != UINT64_MAX && !control_uri && !data_uri) { ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; goto end; } - if (output.control_uri || output.data_uri) { + if (control_uri || data_uri) { /* network destination */ if (live_timer_interval && live_timer_interval != UINT64_MAX) { /* @@ -1366,15 +1426,14 @@ int create_session(const char *name, goto end; } - ret = create_session_net_output(name, output.control_uri, - output.data_uri); + ret = create_session_net_output(name, control_uri, data_uri); if (ret) { goto end; } } else { /* either local output or no output */ - ret = lttng_create_session(name, output.path); + ret = lttng_create_session(name, path); if (ret) { goto end; } @@ -1437,7 +1496,6 @@ int process_probe_attribute_node(xmlNodePtr probe_attribute_node, } else if (!strcmp((const char *) probe_attribute_node->name, config_element_symbol_name)) { xmlChar *content; - size_t name_len; /* symbol_name */ content = xmlNodeGetContent(probe_attribute_node); @@ -1446,15 +1504,18 @@ int process_probe_attribute_node(xmlNodePtr probe_attribute_node, goto end; } - name_len = strlen((char *) content); - if (name_len >= LTTNG_SYMBOL_NAME_LEN) { - WARN("symbol_name too long."); + ret = lttng_strncpy(attr->symbol_name, + (const char *) content, + LTTNG_SYMBOL_NAME_LEN); + if (ret == -1) { + ERR("symbol name \"%s\"'s length (%zu) exceeds the maximal permitted length (%d) in session configuration", + (const char *) content, + strlen((const char *) content), + LTTNG_SYMBOL_NAME_LEN); ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; free(content); goto end; } - - strncpy(attr->symbol_name, (const char *) content, name_len); free(content); } ret = 0; @@ -1503,7 +1564,6 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle, node = xmlNextElementSibling(node)) { if (!strcmp((const char *) node->name, config_element_name)) { xmlChar *content; - size_t name_len; /* name */ content = xmlNodeGetContent(node); @@ -1512,15 +1572,18 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle, goto end; } - name_len = strlen((char *) content); - if (name_len >= LTTNG_SYMBOL_NAME_LEN) { - WARN("Channel name too long."); + ret = lttng_strncpy(event.name, + (const char *) content, + LTTNG_SYMBOL_NAME_LEN); + if (ret == -1) { + WARN("Event \"%s\"'s name length (%zu) exceeds the maximal permitted length (%d) in session configuration", + (const char *) content, + strlen((const char *) content), + LTTNG_SYMBOL_NAME_LEN); ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; free(content); goto end; } - - strncpy(event.name, (const char *) content, name_len); free(content); } else if (!strcmp((const char *) node->name, config_element_enabled)) { @@ -1611,6 +1674,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) { @@ -1710,8 +1774,14 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle, goto end; } - strncpy(event.attr.ftrace.symbol_name, (char *) content, - sym_len); + ret = lttng_strncpy( + event.attr.ftrace.symbol_name, + (char *) content, sym_len); + if (ret == -1) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + free(content); + goto end; + } free(content); } } @@ -1726,6 +1796,7 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle, goto end; } } + ret = 0; end: for (i = 0; i < exclusion_count; i++) { free(exclusions[i]); @@ -1795,7 +1866,6 @@ int process_channel_attr_node(xmlNodePtr attr_node, if (!strcmp((const char *) attr_node->name, config_element_name)) { xmlChar *content; - size_t name_len; /* name */ content = xmlNodeGetContent(attr_node); @@ -1804,15 +1874,18 @@ int process_channel_attr_node(xmlNodePtr attr_node, goto end; } - name_len = strlen((char *) content); - if (name_len >= LTTNG_SYMBOL_NAME_LEN) { - WARN("Channel name too long."); + ret = lttng_strncpy(channel->name, + (const char *) content, + LTTNG_SYMBOL_NAME_LEN); + if (ret == -1) { + WARN("Channel \"%s\"'s name length (%zu) exceeds the maximal permitted length (%d) in session configuration", + (const char *) content, + strlen((const char *) content), + LTTNG_SYMBOL_NAME_LEN); ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; free(content); goto end; } - - strncpy(channel->name, (const char *) content, name_len); free(content); } else if (!strcmp((const char *) attr_node->name, config_element_enabled)) { @@ -2021,6 +2094,56 @@ int process_channel_attr_node(xmlNodePtr attr_node, channel->attr.live_timer_interval = live_timer_interval; + } else if (!strcmp((const char *) attr_node->name, + config_element_monitor_timer_interval)) { + xmlChar *content; + uint64_t monitor_timer_interval = 0; + + /* monitor_timer_interval */ + content = xmlNodeGetContent(attr_node); + if (!content) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + ret = parse_uint(content, &monitor_timer_interval); + free(content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + ret = lttng_channel_set_monitor_timer_interval(channel, + monitor_timer_interval); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + } else if (!strcmp((const char *) attr_node->name, + config_element_blocking_timeout)) { + xmlChar *content; + int64_t blocking_timeout = 0; + + /* blocking_timeout */ + content = xmlNodeGetContent(attr_node); + if (!content) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + ret = parse_int(content, &blocking_timeout); + free(content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + ret = lttng_channel_set_blocking_timeout(channel, + blocking_timeout); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } } else if (!strcmp((const char *) attr_node->name, config_element_events)) { /* events */ @@ -2130,7 +2253,6 @@ int process_context_node(xmlNodePtr context_node, } else if (!strcmp((const char *) perf_attr_node->name, config_element_name)) { xmlChar *content; - size_t name_len; /* name */ content = xmlNodeGetContent(perf_attr_node); @@ -2139,16 +2261,18 @@ int process_context_node(xmlNodePtr context_node, goto end; } - name_len = strlen((char *) content); - if (name_len >= LTTNG_SYMBOL_NAME_LEN) { - WARN("perf context name too long."); + ret = lttng_strncpy(context.u.perf_counter.name, + (const char *) content, + LTTNG_SYMBOL_NAME_LEN); + if (ret == -1) { + WARN("Perf counter \"%s\"'s name length (%zu) exceeds the maximal permitted length (%d) in session configuration", + (const char *) content, + strlen((const char *) content), + LTTNG_SYMBOL_NAME_LEN); ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; free(content); goto end; } - - strncpy(context.u.perf_counter.name, (const char *) content, - name_len); free(content); } } @@ -2281,13 +2405,13 @@ end: return ret; } - static int process_domain_node(xmlNodePtr domain_node, const char *session_name) { int ret; struct lttng_domain domain = { 0 }; struct lttng_handle *handle = NULL; + struct lttng_channel *channel = NULL; xmlNodePtr channels_node = NULL; xmlNodePtr trackers_node = NULL; xmlNodePtr pid_tracker_node = NULL; @@ -2323,40 +2447,69 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name) /* create all channels */ for (node = xmlFirstElementChild(channels_node); node; node = xmlNextElementSibling(node)) { - struct lttng_channel channel; + const enum lttng_domain_type original_domain = domain.type; xmlNodePtr contexts_node = NULL; xmlNodePtr events_node = NULL; xmlNodePtr channel_attr_node; - memset(&channel, 0, sizeof(channel)); - lttng_channel_set_default_attr(&domain, &channel.attr); + /* + * Channels of the "agent" types cannot be created directly. + * They are meant to be created implicitly through the + * activation of events in their domain. However, a user + * can override the default channel configuration attributes + * by creating the underlying UST channel _before_ enabling + * an agent domain event. + * + * Hence, the channel's type is substituted before the creation + * and restored by the time the events are created. + */ + switch (domain.type) { + case LTTNG_DOMAIN_JUL: + case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_PYTHON: + domain.type = LTTNG_DOMAIN_UST; + default: + break; + } + + channel = lttng_channel_create(&domain); + if (!channel) { + ret = -1; + goto end; + } for (channel_attr_node = xmlFirstElementChild(node); channel_attr_node; channel_attr_node = xmlNextElementSibling(channel_attr_node)) { ret = process_channel_attr_node(channel_attr_node, - &channel, &contexts_node, &events_node); + channel, &contexts_node, &events_node); if (ret) { goto end; } } - ret = lttng_enable_channel(handle, &channel); + ret = lttng_enable_channel(handle, channel); if (ret < 0) { goto end; } - ret = process_events_node(events_node, handle, channel.name); + /* Restore the original channel domain. */ + domain.type = original_domain; + + ret = process_events_node(events_node, handle, channel->name); if (ret) { goto end; } ret = process_contexts_node(contexts_node, handle, - channel.name); + channel->name); if (ret) { goto end; } + + lttng_channel_destroy(channel); } + channel = NULL; /* get the trackers node */ for (node = xmlFirstElementChild(domain_node); node; @@ -2388,21 +2541,26 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name) } end: + lttng_channel_destroy(channel); lttng_destroy_handle(handle); return ret; } static int process_session_node(xmlNodePtr session_node, const char *session_name, - int override) + int overwrite, + const struct config_load_session_override_attr *overrides) { int ret, started = -1, snapshot_mode = -1; - uint64_t live_timer_interval = UINT64_MAX; + uint64_t live_timer_interval = UINT64_MAX, + rotation_timer_interval = 0, + rotation_size = 0; xmlChar *name = NULL; xmlChar *shm_path = NULL; xmlNodePtr domains_node = NULL; xmlNodePtr output_node = NULL; xmlNodePtr node; + xmlNodePtr attributes_child; struct lttng_domain *kernel_domain = NULL; struct lttng_domain *ust_domain = NULL; struct lttng_domain *jul_domain = NULL; @@ -2455,40 +2613,78 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, shm_path = node_content; } else { - /* attributes, snapshot_mode or live_timer_interval */ - xmlNodePtr attributes_child = - xmlFirstElementChild(node); - - if (!strcmp((const char *) attributes_child->name, - config_element_snapshot_mode)) { - /* snapshot_mode */ - xmlChar *snapshot_mode_content = - xmlNodeGetContent(attributes_child); - if (!snapshot_mode_content) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } + /* + * attributes, snapshot_mode, live_timer_interval, rotation_size, + * rotation_timer_interval. + */ + for (attributes_child = xmlFirstElementChild(node); attributes_child; + attributes_child = xmlNextElementSibling(attributes_child)) { + if (!strcmp((const char *) attributes_child->name, + config_element_snapshot_mode)) { + /* snapshot_mode */ + xmlChar *snapshot_mode_content = + xmlNodeGetContent(attributes_child); + if (!snapshot_mode_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } - ret = parse_bool(snapshot_mode_content, &snapshot_mode); - free(snapshot_mode_content); - if (ret) { - ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto error; + ret = parse_bool(snapshot_mode_content, &snapshot_mode); + free(snapshot_mode_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } + } else if (!strcmp((const char *) attributes_child->name, + config_element_live_timer_interval)) { + /* live_timer_interval */ + xmlChar *timer_interval_content = + xmlNodeGetContent(attributes_child); + if (!timer_interval_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + ret = parse_uint(timer_interval_content, &live_timer_interval); + free(timer_interval_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } } - } else { - /* live_timer_interval */ - xmlChar *timer_interval_content = - xmlNodeGetContent(attributes_child); - if (!timer_interval_content) { - ret = -LTTNG_ERR_NOMEM; - goto error; + if (!strcmp((const char *) attributes_child->name, + config_element_rotation_timer_interval)) { + /* rotation_timer_interval */ + xmlChar *timer_interval_content = + xmlNodeGetContent(attributes_child); + if (!timer_interval_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + ret = parse_uint(timer_interval_content, &rotation_timer_interval); + free(timer_interval_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } } + if (!strcmp((const char *) attributes_child->name, + config_element_rotation_size)) { + /* rotation_size */ + xmlChar *rotation_size_content = + xmlNodeGetContent(attributes_child); + if (!rotation_size_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } - ret = parse_uint(timer_interval_content, &live_timer_interval); - free(timer_interval_content); - if (ret) { - ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto error; + ret = parse_uint(rotation_size_content, &rotation_size); + free(rotation_size_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } } } } @@ -2569,7 +2765,22 @@ domain_init_error: goto error; } - if (override) { + /* Apply overrides */ + if (overrides) { + if (overrides->session_name) { + xmlChar *name_override = xmlStrdup(BAD_CAST(overrides->session_name)); + if (!name_override) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + /* Overrides the session name to the provided name */ + xmlFree(name); + name = name_override; + } + } + + if (overwrite) { /* Destroy session if it exists */ ret = lttng_destroy_session((const char *) name); if (ret && ret != -LTTNG_ERR_SESS_NOT_FOUND) { @@ -2580,17 +2791,16 @@ domain_init_error: /* Create session type depending on output type */ if (snapshot_mode && snapshot_mode != -1) { - ret = create_snapshot_session((const char *) name, output_node); + ret = create_snapshot_session((const char *) name, output_node, + overrides); } else if (live_timer_interval && live_timer_interval != UINT64_MAX) { - ret = create_session((const char *) name, kernel_domain, - ust_domain, jul_domain, log4j_domain, - output_node, live_timer_interval); + ret = create_session((const char *) name, + output_node, live_timer_interval, overrides); } else { /* regular session */ - ret = create_session((const char *) name, kernel_domain, - ust_domain, jul_domain, log4j_domain, - output_node, UINT64_MAX); + ret = create_session((const char *) name, + output_node, UINT64_MAX, overrides); } if (ret) { goto error; @@ -2612,6 +2822,27 @@ domain_init_error: } } + if (rotation_timer_interval || rotation_size) { + struct lttng_rotation_schedule_attr *rotation_attr = lttng_rotation_schedule_attr_create(); + + if (!rotation_attr) { + goto error; + } + ret = lttng_rotation_schedule_attr_set_session_name(rotation_attr, (const char *) name); + if (ret) { + lttng_rotation_schedule_attr_destroy(rotation_attr); + goto error; + } + lttng_rotation_schedule_attr_set_timer_period(rotation_attr, + rotation_timer_interval); + lttng_rotation_schedule_attr_set_size(rotation_attr, rotation_size); + ret = lttng_rotation_set_schedule(rotation_attr); + lttng_rotation_schedule_attr_destroy(rotation_attr); + if (ret) { + goto error; + } + } + if (started) { ret = lttng_start_tracing((const char *) name); if (ret) { @@ -2664,7 +2895,8 @@ valid: static int load_session_from_file(const char *path, const char *session_name, - struct session_config_validation_ctx *validation_ctx, int override) + struct session_config_validation_ctx *validation_ctx, int overwrite, + const struct config_load_session_override_attr *overrides) { int ret, session_found = !session_name; xmlDocPtr doc = NULL; @@ -2706,7 +2938,7 @@ int load_session_from_file(const char *path, const char *session_name, session_node; session_node = xmlNextElementSibling(session_node)) { ret = process_session_node(session_node, - session_name, override); + session_name, overwrite, overrides); if (session_name && ret == 0) { /* Target session found and loaded */ session_found = 1; @@ -2721,32 +2953,26 @@ 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) + struct session_config_validation_ctx *validation_ctx, int overwrite, + const struct config_load_session_override_attr *overrides) { int ret, session_found = !session_name; DIR *directory = NULL; + struct lttng_dynamic_buffer file_path; + size_t path_len; assert(path); assert(validation_ctx); + path_len = strlen(path); + lttng_dynamic_buffer_init(&file_path); + if (path_len >= LTTNG_PATH_MAX) { + ERR("Session configuration load path \"%s\" length (%zu) exceeds the maximal length allowed (%d)", + path, path_len, LTTNG_PATH_MAX); + ret = -LTTNG_ERR_INVALID; + goto end; + } directory = opendir(path); if (!directory) { @@ -2763,70 +2989,110 @@ int load_session_from_path(const char *path, const char *session_name, } } if (directory) { - struct dirent *entry; - struct dirent *result; - char *file_path = NULL; - size_t path_len = strlen(path); + size_t file_path_root_len; - if (path_len >= PATH_MAX) { - ret = -LTTNG_ERR_INVALID; - goto end; - } - - entry = alloc_dirent(path); - if (!entry) { + ret = lttng_dynamic_buffer_set_capacity(&file_path, + LTTNG_PATH_MAX); + if (ret) { ret = -LTTNG_ERR_NOMEM; goto end; } - file_path = zmalloc(PATH_MAX); - if (!file_path) { + ret = lttng_dynamic_buffer_append(&file_path, path, path_len); + if (ret) { ret = -LTTNG_ERR_NOMEM; - free(entry); goto end; } - strncpy(file_path, path, path_len); - if (file_path[path_len - 1] != '/') { - file_path[path_len++] = '/'; + if (file_path.data[file_path.size - 1] != '/') { + ret = lttng_dynamic_buffer_append(&file_path, "/", 1); + if (ret) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } } + file_path_root_len = file_path.size; - ret = 0; /* Search for *.lttng files */ - while (!readdir_r(directory, entry, &result) && result) { - size_t file_name_len = strlen(result->d_name); + for (;;) { + size_t file_name_len; + struct dirent *result; + + /* + * When the end of the directory stream is reached, NULL + * is returned and errno is kept unchanged. When an + * error occurs, NULL is returned and errno is set + * accordingly. To distinguish between the two, set + * errno to zero before calling readdir(). + * + * On success, readdir() returns a pointer to a dirent + * structure. This structure may be statically + * allocated, do not attempt to free(3) it. + */ + errno = 0; + result = readdir(directory); + + /* Reached end of dir stream or error out. */ + if (!result) { + if (errno) { + PERROR("Failed to enumerate the contents of path \"%s\" while loading session, readdir returned", path); + ret = -LTTNG_ERR_LOAD_IO_FAIL; + goto end; + } + break; + } + + file_name_len = strlen(result->d_name); if (file_name_len <= sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION)) { continue; } - if (path_len + file_name_len >= PATH_MAX) { + if (file_path.size + file_name_len >= LTTNG_PATH_MAX) { + WARN("Ignoring file \"%s\" since the path's length (%zu) would exceed the maximal permitted size (%d)", + result->d_name, + /* +1 to account for NULL terminator. */ + file_path.size + file_name_len + 1, + LTTNG_PATH_MAX); continue; } + /* Does the file end with .lttng? */ if (strcmp(DEFAULT_SESSION_CONFIG_FILE_EXTENSION, - result->d_name + file_name_len - sizeof( - DEFAULT_SESSION_CONFIG_FILE_EXTENSION) + 1)) { + result->d_name + file_name_len - sizeof( + DEFAULT_SESSION_CONFIG_FILE_EXTENSION) + 1)) { continue; } - strncpy(file_path + path_len, result->d_name, file_name_len); - file_path[path_len + file_name_len] = '\0'; + ret = lttng_dynamic_buffer_append(&file_path, result->d_name, + file_name_len + 1); + if (ret) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } - ret = load_session_from_file(file_path, session_name, - validation_ctx, override); + ret = load_session_from_file(file_path.data, session_name, + validation_ctx, overwrite, overrides); if (session_name && !ret) { session_found = 1; break; } + /* + * Reset the buffer's size to the location of the + * path's trailing '/'. + */ + ret = lttng_dynamic_buffer_set_size(&file_path, + file_path_root_len); + if (ret) { + ret = -LTTNG_ERR_UNK; + goto end; + } } - free(entry); - free(file_path); } else { ret = load_session_from_file(path, session_name, - validation_ctx, override); + validation_ctx, overwrite, overrides); if (ret) { goto end; } else { @@ -2840,11 +3106,10 @@ end: PERROR("closedir"); } } - - if (session_found) { + if (session_found && !ret) { ret = 0; } - + lttng_dynamic_buffer_reset(&file_path); return ret; } @@ -2868,7 +3133,6 @@ static int validate_path_creds(const char *path) if (errno != ENOENT) { PERROR("stat"); } - ret = -LTTNG_ERR_INVALID; goto valid; } @@ -2884,7 +3148,8 @@ invalid: LTTNG_HIDDEN int config_load_session(const char *path, const char *session_name, - int override, unsigned int autoload) + int overwrite, unsigned int autoload, + const struct config_load_session_override_attr *overrides) { int ret; bool session_loaded = false; @@ -2938,7 +3203,7 @@ 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); + &validation_ctx, overwrite, overrides); if (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT) { goto end; } @@ -2968,7 +3233,7 @@ 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); + &validation_ctx, overwrite, overrides); if (!ret) { session_loaded = true; } @@ -2993,7 +3258,7 @@ int config_load_session(const char *path, const char *session_name, } ret = load_session_from_path(path, session_name, - &validation_ctx, override); + &validation_ctx, overwrite, overrides); } end: fini_session_config_validation_ctx(&validation_ctx); @@ -3011,3 +3276,9 @@ end: } return ret; } + +static +void __attribute__((destructor)) session_config_exit(void) +{ + xmlCleanupParser(); +}