X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=src%2Fcli%2Fbabeltrace2.c;h=c4b7c29fc1605bc67910bcbdb98608c9c872a309;hp=0a3cb5b9f0a0240e0ed3e40f3aa15b7c7d185496;hb=0235b0db7de5bcacdb3650c92461f2ce5eb2143d;hpb=0d9a3d3edc52d78d00ce114f6c4c50d6d334b9dd diff --git a/src/cli/babeltrace2.c b/src/cli/babeltrace2.c index 0a3cb5b9..c4b7c29f 100644 --- a/src/cli/babeltrace2.c +++ b/src/cli/babeltrace2.c @@ -1,25 +1,7 @@ /* - * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation - * - * Author: Mathieu Desnoyers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * SPDX-License-Identifier: MIT * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation */ #define BT_LOG_TAG "CLI" @@ -27,9 +9,10 @@ #include #include "common/common.h" +#include "string-format/format-error.h" +#include "string-format/format-plugin-comp-cls-name.h" #include #include -#include #include #include #include @@ -39,35 +22,36 @@ #include "babeltrace2-cfg.h" #include "babeltrace2-cfg-cli-args.h" #include "babeltrace2-cfg-cli-args-default.h" +#include "babeltrace2-log-level.h" +#include "babeltrace2-plugins.h" +#include "babeltrace2-query.h" #define ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH "BABELTRACE_CLI_WARN_COMMAND_NAME_DIRECTORY_CLASH" -#define ENV_BABELTRACE_CLI_LOG_LEVEL "BABELTRACE_CLI_LOG_LEVEL" #define NSEC_PER_SEC 1000000000LL -/* - * Known environment variable names for the log levels of the project's - * modules. - */ -static const char* log_level_env_var_names[] = { - "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL", - "BABELTRACE_PLUGIN_CTF_BFCR_LOG_LEVEL", - "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL", - "BABELTRACE_PLUGIN_CTF_MSG_ITER_LOG_LEVEL", - "BABELTRACE_PLUGIN_CTF_UTILS_LOG_LEVEL", - "BABELTRACE_PYTHON_BT2_LOG_LEVEL", - "BABELTRACE_SINK_CTF_FS_LOG_LEVEL", - "BABELTRACE_SINK_TEXT_DETAILS_LOG_LEVEL", - "BABELTRACE_SRC_CTF_FS_LOG_LEVEL", - "BABELTRACE_SRC_CTF_LTTNG_LIVE_LOG_LEVEL", - NULL, +enum bt_cmd_status { + BT_CMD_STATUS_OK = 0, + BT_CMD_STATUS_ERROR = -1, + BT_CMD_STATUS_INTERRUPTED = -2, }; -/* Application's processing graph (weak) */ -static bt_graph *the_graph; -static bt_query_executor *the_query_executor; -static bool canceled = false; +static +const char *bt_cmd_status_string(enum bt_cmd_status cmd_status) +{ + switch (cmd_status) { + case BT_CMD_STATUS_OK: + return "OK"; + case BT_CMD_STATUS_ERROR: + return "ERROR"; + case BT_CMD_STATUS_INTERRUPTED: + return "INTERRUPTED"; + default: + bt_common_abort(); + } +} -GPtrArray *loaded_plugins; +/* Application's interrupter (owned by this) */ +static bt_interrupter *the_interrupter; #ifdef __MINGW32__ @@ -75,12 +59,10 @@ GPtrArray *loaded_plugins; static BOOL WINAPI signal_handler(DWORD signal) { - if (the_graph) { - bt_graph_cancel(the_graph); + if (the_interrupter) { + bt_interrupter_set(the_interrupter); } - canceled = true; - return TRUE; } @@ -101,15 +83,9 @@ void signal_handler(int signum) return; } - if (the_graph) { - bt_graph_cancel(the_graph); - } - - if (the_query_executor) { - bt_query_executor_cancel(the_query_executor); + if (the_interrupter) { + bt_interrupter_set(the_interrupter); } - - canceled = true; } static @@ -129,159 +105,13 @@ void set_signal_handler(void) #endif /* __MINGW32__ */ -static -void init_static_data(void) -{ - loaded_plugins = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_object_put_ref); -} - -static -void fini_static_data(void) -{ - g_ptr_array_free(loaded_plugins, TRUE); -} - -static -int create_the_query_executor(void) -{ - int ret = 0; - - the_query_executor = bt_query_executor_create(); - if (!the_query_executor) { - BT_LOGE_STR("Cannot create a query executor."); - ret = -1; - } - - return ret; -} - -static -void destroy_the_query_executor(void) -{ - BT_QUERY_EXECUTOR_PUT_REF_AND_RESET(the_query_executor); -} - static int query(struct bt_config *cfg, const bt_component_class *comp_cls, const char *obj, const bt_value *params, const bt_value **user_result, const char **fail_reason) { - const bt_value *result = NULL; - bt_query_executor_status status; - *fail_reason = "unknown error"; - int ret = 0; - - BT_ASSERT(fail_reason); - BT_ASSERT(user_result); - ret = create_the_query_executor(); - if (ret) { - /* create_the_query_executor() logs errors */ - goto end; - } - - if (canceled) { - BT_LOGI("Canceled by user before executing the query: " - "comp-cls-addr=%p, comp-cls-name=\"%s\", " - "query-obj=\"%s\"", comp_cls, - bt_component_class_get_name(comp_cls), obj); - *fail_reason = "canceled by user"; - goto error; - } - - while (true) { - status = bt_query_executor_query(the_query_executor, - comp_cls, obj, params, cfg->log_level, &result); - switch (status) { - case BT_QUERY_EXECUTOR_STATUS_OK: - goto ok; - case BT_QUERY_EXECUTOR_STATUS_AGAIN: - { - const uint64_t sleep_time_us = 100000; - - /* Wait 100 ms and retry */ - BT_LOGD("Got BT_QUERY_EXECUTOR_STATUS_AGAIN: sleeping: " - "time-us=%" PRIu64, sleep_time_us); - - if (usleep(sleep_time_us)) { - if (bt_query_executor_is_canceled(the_query_executor)) { - BT_LOGI("Query was canceled by user: " - "comp-cls-addr=%p, comp-cls-name=\"%s\", " - "query-obj=\"%s\"", comp_cls, - bt_component_class_get_name(comp_cls), - obj); - *fail_reason = "canceled by user"; - goto error; - } - } - - continue; - } - case BT_QUERY_EXECUTOR_STATUS_CANCELED: - *fail_reason = "canceled by user"; - goto error; - case BT_QUERY_EXECUTOR_STATUS_ERROR: - goto error; - case BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT: - *fail_reason = "invalid or unknown query object"; - goto error; - case BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS: - *fail_reason = "invalid query parameters"; - goto error; - case BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED: - *fail_reason = "unsupported action"; - goto error; - case BT_QUERY_EXECUTOR_STATUS_NOMEM: - *fail_reason = "not enough memory"; - goto error; - default: - BT_LOGF("Unknown query status: status=%d", status); - abort(); - } - } - -ok: - *user_result = result; - result = NULL; - goto end; - -error: - ret = -1; - -end: - destroy_the_query_executor(); - bt_value_put_ref(result); - return ret; -} - -static -const bt_plugin *find_plugin(const char *name) -{ - int i; - const bt_plugin *plugin = NULL; - - BT_ASSERT(name); - BT_LOGI("Finding plugin: name=\"%s\"", name); - - for (i = 0; i < loaded_plugins->len; i++) { - plugin = g_ptr_array_index(loaded_plugins, i); - - if (strcmp(name, bt_plugin_get_name(plugin)) == 0) { - break; - } - - plugin = NULL; - } - - if (plugin) { - BT_LOGI("Found plugin: name=\"%s\", plugin-addr=%p", - name, plugin); - } else { - BT_LOGI("Cannot find plugin: name=\"%s\"", name); - } - - bt_plugin_get_ref(plugin); - return plugin; + return cli_query(comp_cls, obj, params, cfg->log_level, + the_interrupter, user_result, fail_reason); } typedef const void *(*plugin_borrow_comp_cls_func_t)( @@ -298,14 +128,13 @@ const void *find_component_class_from_plugin(const char *plugin_name, BT_LOGI("Finding component class: plugin-name=\"%s\", " "comp-cls-name=\"%s\"", plugin_name, comp_class_name); - plugin = find_plugin(plugin_name); + plugin = borrow_loaded_plugin_by_name(plugin_name); if (!plugin) { goto end; } comp_class = plugin_borrow_comp_cls_func(plugin, comp_class_name); bt_object_get_ref(comp_class); - BT_PLUGIN_PUT_REF_AND_RESET(plugin); end: if (comp_class) { @@ -368,7 +197,7 @@ const bt_component_class *find_component_class(const char *plugin_name, comp_cls = bt_component_class_sink_as_component_class_const(find_sink_component_class(plugin_name, comp_class_name)); break; default: - abort(); + bt_common_abort(); } return comp_cls; @@ -384,101 +213,60 @@ void print_indent(FILE *fp, size_t indent) } } -static -const char *component_type_str(bt_component_class_type type) -{ - switch (type) { - case BT_COMPONENT_CLASS_TYPE_SOURCE: - return "source"; - case BT_COMPONENT_CLASS_TYPE_SINK: - return "sink"; - case BT_COMPONENT_CLASS_TYPE_FILTER: - return "filter"; - default: - return "(unknown)"; - } -} - -static -void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name, - const char *comp_cls_name, bt_component_class_type type) -{ - GString *shell_plugin_name = NULL; - GString *shell_comp_cls_name = NULL; - - shell_plugin_name = bt_common_shell_quote(plugin_name, false); - if (!shell_plugin_name) { - goto end; - } - - shell_comp_cls_name = bt_common_shell_quote(comp_cls_name, false); - if (!shell_comp_cls_name) { - goto end; - } - - fprintf(fh, "'%s%s%s%s.%s%s%s.%s%s%s'", - bt_common_color_bold(), - bt_common_color_fg_cyan(), - component_type_str(type), - bt_common_color_fg_default(), - bt_common_color_fg_blue(), - shell_plugin_name->str, - bt_common_color_fg_default(), - bt_common_color_fg_yellow(), - shell_comp_cls_name->str, - bt_common_color_reset()); - -end: - if (shell_plugin_name) { - g_string_free(shell_plugin_name, TRUE); - } - - if (shell_comp_cls_name) { - g_string_free(shell_comp_cls_name, TRUE); - } -} - static void print_value(FILE *, const bt_value *, size_t); static void print_value_rec(FILE *, const bt_value *, size_t); -struct print_map_value_data { - size_t indent; - FILE *fp; -}; - static -bt_bool print_map_value(const char *key, const bt_value *object, - void *data) +void print_map_value(const char *key, const bt_value *object, FILE *fp, + size_t indent) { - struct print_map_value_data *print_map_value_data = data; - - print_indent(print_map_value_data->fp, print_map_value_data->indent); - fprintf(print_map_value_data->fp, "%s: ", key); + print_indent(fp, indent); + fprintf(fp, "%s: ", key); BT_ASSERT(object); if (bt_value_is_array(object) && bt_value_array_is_empty(object)) { - fprintf(print_map_value_data->fp, "[ ]\n"); - return true; + fprintf(fp, "[ ]\n"); + goto end; } if (bt_value_is_map(object) && bt_value_map_is_empty(object)) { - fprintf(print_map_value_data->fp, "{ }\n"); - return true; + fprintf(fp, "{ }\n"); + goto end; } if (bt_value_is_array(object) || bt_value_is_map(object)) { - fprintf(print_map_value_data->fp, "\n"); + fprintf(fp, "\n"); } - print_value_rec(print_map_value_data->fp, object, - print_map_value_data->indent + 2); - return BT_TRUE; + print_value_rec(fp, object, indent + 2); + +end: + return; +} + +static +bt_value_map_foreach_entry_const_func_status collect_map_keys( + const char *key, const bt_value *object, void *data) +{ + GPtrArray *map_keys = data; + + g_ptr_array_add(map_keys, (gpointer *) key); + + return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK; +} + +static +gint g_ptr_array_sort_strings(gconstpointer a, gconstpointer b) { + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); + + return g_strcmp0(s1, s2); } static @@ -489,12 +277,9 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) uint64_t uint_val; double dbl_val; const char *str_val; - int size; - int i; + GPtrArray *map_keys = NULL; - if (!value) { - return; - } + BT_ASSERT(value); switch (bt_value_get_type(value)) { case BT_VALUE_TYPE_NULL: @@ -504,39 +289,37 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) case BT_VALUE_TYPE_BOOL: bool_val = bt_value_bool_get(value); fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(), - bt_common_color_fg_cyan(), bool_val ? "yes" : "no", + bt_common_color_fg_bright_cyan(), bool_val ? "yes" : "no", bt_common_color_reset()); break; case BT_VALUE_TYPE_UNSIGNED_INTEGER: - uint_val = bt_value_unsigned_integer_get(value); + uint_val = bt_value_integer_unsigned_get(value); fprintf(fp, "%s%s%" PRIu64 "%s\n", bt_common_color_bold(), - bt_common_color_fg_red(), uint_val, + bt_common_color_fg_bright_red(), uint_val, bt_common_color_reset()); break; case BT_VALUE_TYPE_SIGNED_INTEGER: - int_val = bt_value_signed_integer_get(value); + int_val = bt_value_integer_signed_get(value); fprintf(fp, "%s%s%" PRId64 "%s\n", bt_common_color_bold(), - bt_common_color_fg_red(), int_val, + bt_common_color_fg_bright_red(), int_val, bt_common_color_reset()); break; case BT_VALUE_TYPE_REAL: dbl_val = bt_value_real_get(value); fprintf(fp, "%s%s%lf%s\n", bt_common_color_bold(), - bt_common_color_fg_red(), dbl_val, + bt_common_color_fg_bright_red(), dbl_val, bt_common_color_reset()); break; case BT_VALUE_TYPE_STRING: str_val = bt_value_string_get(value); fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(), - bt_common_color_fg_green(), str_val, + bt_common_color_fg_bright_green(), str_val, bt_common_color_reset()); break; case BT_VALUE_TYPE_ARRAY: - size = bt_value_array_get_size(value); - if (size < 0) { - goto error; - } - + { + uint64_t i, size; + size = bt_value_array_get_length(value); if (size == 0) { print_indent(fp, indent); fprintf(fp, "[ ]\n"); @@ -548,9 +331,6 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) bt_value_array_borrow_element_by_index_const( value, i); - if (!element) { - goto error; - } print_indent(fp, indent); fprintf(fp, "- "); @@ -574,12 +354,11 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) print_value_rec(fp, element, indent + 2); } break; + } case BT_VALUE_TYPE_MAP: { - struct print_map_value_data data = { - .indent = indent, - .fp = fp, - }; + guint i; + bt_value_map_foreach_entry_const_status foreach_status; if (bt_value_map_is_empty(value)) { print_indent(fp, indent); @@ -587,17 +366,48 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) break; } - bt_value_map_foreach_entry_const(value, print_map_value, &data); + map_keys = g_ptr_array_new(); + if (!map_keys) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to allocated on GPtrArray."); + goto end; + } + + /* + * We want to print the map entries in a stable order. Collect + * all the map's keys in a GPtrArray, sort it, then print the + * entries in that order. + */ + foreach_status = bt_value_map_foreach_entry_const(value, + collect_map_keys, map_keys); + if (foreach_status != BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to iterator on map value."); + goto end; + } + + g_ptr_array_sort(map_keys, g_ptr_array_sort_strings); + + for (i = 0; i < map_keys->len; i++) { + const char *map_key = g_ptr_array_index(map_keys, i); + const bt_value *map_value; + + map_value = bt_value_map_borrow_entry_value_const(value, map_key); + BT_ASSERT(map_value); + + print_map_value(map_key, map_value, fp, indent); + } + break; } default: - abort(); + bt_common_abort(); } - return; -error: - BT_LOGE("Error printing value of type %s.", - bt_common_value_type_string(bt_value_get_type(value))); + goto end; + +end: + if (map_keys) { + g_ptr_array_free(map_keys, TRUE); + } } static @@ -613,11 +423,16 @@ void print_value(FILE *fp, const bt_value *value, size_t indent) static void print_bt_config_component(struct bt_config_component *bt_config_component) { - fprintf(stderr, " "); - print_plugin_comp_cls_opt(stderr, bt_config_component->plugin_name->str, + gchar *comp_cls_str; + + comp_cls_str = format_plugin_comp_cls_opt( + bt_config_component->plugin_name->str, bt_config_component->comp_cls_name->str, - bt_config_component->type); - fprintf(stderr, ":\n"); + bt_config_component->type, + BT_COMMON_COLOR_WHEN_AUTO); + BT_ASSERT(comp_cls_str); + + fprintf(stderr, " %s:\n", comp_cls_str); if (bt_config_component->instance_name->len > 0) { fprintf(stderr, " Name: %s\n", @@ -626,6 +441,8 @@ void print_bt_config_component(struct bt_config_component *bt_config_component) fprintf(stderr, " Parameters:\n"); print_value(stderr, bt_config_component->params, 8); + + g_free(comp_cls_str); } static @@ -726,8 +543,6 @@ void print_cfg(struct bt_config *cfg) } BT_LOGI_STR("CLI configuration:"); - BT_LOGI(" Debug mode: %s\n", cfg->debug ? "yes" : "no"); - BT_LOGI(" Verbose mode: %s\n", cfg->verbose ? "yes" : "no"); switch (cfg->command) { case BT_CONFIG_COMMAND_RUN: @@ -749,133 +564,8 @@ void print_cfg(struct bt_config *cfg) print_cfg_print_lttng_live_sessions(cfg); break; default: - abort(); - } -} - -static -void add_to_loaded_plugins(const bt_plugin_set *plugin_set) -{ - int64_t i; - int64_t count; - - count = bt_plugin_set_get_plugin_count(plugin_set); - BT_ASSERT(count >= 0); - - for (i = 0; i < count; i++) { - const bt_plugin *plugin = - bt_plugin_set_borrow_plugin_by_index_const(plugin_set, i); - const bt_plugin *loaded_plugin = - find_plugin(bt_plugin_get_name(plugin)); - - BT_ASSERT(plugin); - - if (loaded_plugin) { - BT_LOGI("Not using plugin: another one already exists with the same name: " - "plugin-name=\"%s\", plugin-path=\"%s\", " - "existing-plugin-path=\"%s\"", - bt_plugin_get_name(plugin), - bt_plugin_get_path(plugin), - bt_plugin_get_path(loaded_plugin)); - bt_plugin_put_ref(loaded_plugin); - } else { - /* Add to global array. */ - BT_LOGD("Adding plugin to loaded plugins: plugin-path=\"%s\"", - bt_plugin_get_name(plugin)); - bt_plugin_get_ref(plugin); - g_ptr_array_add(loaded_plugins, (void *) plugin); - } - } -} - -static -int load_dynamic_plugins(const bt_value *plugin_paths) -{ - int nr_paths, i, ret = 0; - - nr_paths = bt_value_array_get_size(plugin_paths); - if (nr_paths < 0) { - BT_LOGE_STR("Cannot load dynamic plugins: no plugin path."); - ret = -1; - goto end; - } - - BT_LOGI_STR("Loading dynamic plugins."); - - for (i = 0; i < nr_paths; i++) { - const bt_value *plugin_path_value = NULL; - const char *plugin_path; - const bt_plugin_set *plugin_set; - - plugin_path_value = - bt_value_array_borrow_element_by_index_const( - plugin_paths, i); - plugin_path = bt_value_string_get(plugin_path_value); - - /* - * Skip this if the directory does not exist because - * bt_plugin_find_all_from_dir() expects an existing - * directory. - */ - if (!g_file_test(plugin_path, G_FILE_TEST_IS_DIR)) { - BT_LOGI("Skipping nonexistent directory path: " - "path=\"%s\"", plugin_path); - continue; - } - - plugin_set = bt_plugin_find_all_from_dir(plugin_path, false); - if (!plugin_set) { - BT_LOGI("Unable to load dynamic plugins from directory: " - "path=\"%s\"", plugin_path); - continue; - } - - add_to_loaded_plugins(plugin_set); - bt_plugin_set_put_ref(plugin_set); + bt_common_abort(); } -end: - return ret; -} - -static -int load_static_plugins(void) -{ - int ret = 0; - const bt_plugin_set *plugin_set; - - BT_LOGI("Loading static plugins."); - plugin_set = bt_plugin_find_all_from_static(); - if (!plugin_set) { - BT_LOGE("Unable to load static plugins."); - ret = -1; - goto end; - } - - add_to_loaded_plugins(plugin_set); - bt_plugin_set_put_ref(plugin_set); -end: - return ret; -} - -static -int load_all_plugins(const bt_value *plugin_paths) -{ - int ret = 0; - - if (load_dynamic_plugins(plugin_paths)) { - ret = -1; - goto end; - } - - if (load_static_plugins()) { - ret = -1; - goto end; - } - - BT_LOGI("Loaded all plugins: count=%u", loaded_plugins->len); - -end: - return ret; } static @@ -898,7 +588,7 @@ void print_plugin_info(const bt_plugin *plugin) version_avail = bt_plugin_get_version(plugin, &major, &minor, &patch, &extra); printf("%s%s%s%s:\n", bt_common_color_bold(), - bt_common_color_fg_blue(), plugin_name, + bt_common_color_fg_bright_blue(), plugin_name, bt_common_color_reset()); if (path) { printf(" %sPath%s: %s\n", bt_common_color_bold(), @@ -930,9 +620,10 @@ void print_plugin_info(const bt_plugin *plugin) } static -int cmd_query(struct bt_config *cfg) +enum bt_cmd_status cmd_query(struct bt_config *cfg) { int ret = 0; + enum bt_cmd_status cmd_status; const bt_component_class *comp_cls = NULL; const bt_value *results = NULL; const char *fail_reason = NULL; @@ -942,62 +633,41 @@ int cmd_query(struct bt_config *cfg) cfg->cmd_data.query.cfg_component->comp_cls_name->str, cfg->cmd_data.query.cfg_component->type); if (!comp_cls) { - BT_LOGE("Cannot find component class: plugin-name=\"%s\", " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find component class: plugin-name=\"%s\", " "comp-cls-name=\"%s\", comp-cls-type=%d", cfg->cmd_data.query.cfg_component->plugin_name->str, cfg->cmd_data.query.cfg_component->comp_cls_name->str, cfg->cmd_data.query.cfg_component->type); - fprintf(stderr, "%s%sCannot find component class %s", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); - print_plugin_comp_cls_opt(stderr, - cfg->cmd_data.query.cfg_component->plugin_name->str, - cfg->cmd_data.query.cfg_component->comp_cls_name->str, - cfg->cmd_data.query.cfg_component->type); - fprintf(stderr, "\n"); - ret = -1; - goto end; + goto error; } ret = query(cfg, comp_cls, cfg->cmd_data.query.object->str, cfg->cmd_data.query.cfg_component->params, &results, &fail_reason); if (ret) { - goto failed; + BT_CLI_LOGE_APPEND_CAUSE( + "Failed to query component class: %s: plugin-name=\"%s\", " + "comp-cls-name=\"%s\", comp-cls-type=%d " + "object=\"%s\"", fail_reason, + cfg->cmd_data.query.cfg_component->plugin_name->str, + cfg->cmd_data.query.cfg_component->comp_cls_name->str, + cfg->cmd_data.query.cfg_component->type, + cfg->cmd_data.query.object->str); + goto error; } print_value(stdout, results, 0); + cmd_status = BT_CMD_STATUS_OK; goto end; -failed: - BT_LOGE("Failed to query component class: %s: plugin-name=\"%s\", " - "comp-cls-name=\"%s\", comp-cls-type=%d " - "object=\"%s\"", fail_reason, - cfg->cmd_data.query.cfg_component->plugin_name->str, - cfg->cmd_data.query.cfg_component->comp_cls_name->str, - cfg->cmd_data.query.cfg_component->type, - cfg->cmd_data.query.object->str); - fprintf(stderr, "%s%sFailed to query info to %s", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); - print_plugin_comp_cls_opt(stderr, - cfg->cmd_data.query.cfg_component->plugin_name->str, - cfg->cmd_data.query.cfg_component->comp_cls_name->str, - cfg->cmd_data.query.cfg_component->type); - fprintf(stderr, "%s%s with object `%s`: %s%s\n", - bt_common_color_bold(), - bt_common_color_fg_red(), - cfg->cmd_data.query.object->str, - fail_reason, - bt_common_color_reset()); - ret = -1; +error: + cmd_status = BT_CMD_STATUS_ERROR; end: bt_component_class_put_ref(comp_cls); bt_value_put_ref(results); - return ret; + return cmd_status; } static @@ -1012,9 +682,13 @@ void print_component_class_help(const char *plugin_name, bt_component_class_get_help(comp_cls); bt_component_class_type type = bt_component_class_get_type(comp_cls); + gchar *comp_cls_str; - print_plugin_comp_cls_opt(stdout, plugin_name, comp_class_name, type); - printf("\n"); + comp_cls_str = format_plugin_comp_cls_opt(plugin_name, comp_class_name, + type, BT_COMMON_COLOR_WHEN_AUTO); + BT_ASSERT(comp_cls_str); + + printf("%s\n", comp_cls_str); printf(" %sDescription%s: %s\n", bt_common_color_bold(), bt_common_color_reset(), comp_class_description ? comp_class_description : "(None)"); @@ -1022,26 +696,23 @@ void print_component_class_help(const char *plugin_name, if (comp_class_help) { printf("\n%s\n", comp_class_help); } + + g_free(comp_cls_str); } static -int cmd_help(struct bt_config *cfg) +enum bt_cmd_status cmd_help(struct bt_config *cfg) { - int ret = 0; + enum bt_cmd_status cmd_status; const bt_plugin *plugin = NULL; const bt_component_class *needed_comp_cls = NULL; - plugin = find_plugin(cfg->cmd_data.help.cfg_component->plugin_name->str); + plugin = borrow_loaded_plugin_by_name(cfg->cmd_data.help.cfg_component->plugin_name->str); if (!plugin) { - BT_LOGE("Cannot find plugin: plugin-name=\"%s\"", + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find plugin: plugin-name=\"%s\"", cfg->cmd_data.help.cfg_component->plugin_name->str); - fprintf(stderr, "%s%sCannot find plugin %s%s%s\n", - bt_common_color_bold(), bt_common_color_fg_red(), - bt_common_color_fg_blue(), - cfg->cmd_data.help.cfg_component->plugin_name->str, - bt_common_color_reset()); - ret = -1; - goto end; + goto error; } print_plugin_info(plugin); @@ -1060,6 +731,7 @@ int cmd_help(struct bt_config *cfg) if (strlen(cfg->cmd_data.help.cfg_component->comp_cls_name->str) == 0) { /* Plugin help only */ + cmd_status = BT_CMD_STATUS_OK; goto end; } @@ -1068,33 +740,28 @@ int cmd_help(struct bt_config *cfg) cfg->cmd_data.help.cfg_component->comp_cls_name->str, cfg->cmd_data.help.cfg_component->type); if (!needed_comp_cls) { - BT_LOGE("Cannot find component class: plugin-name=\"%s\", " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find component class: plugin-name=\"%s\", " "comp-cls-name=\"%s\", comp-cls-type=%d", cfg->cmd_data.help.cfg_component->plugin_name->str, cfg->cmd_data.help.cfg_component->comp_cls_name->str, cfg->cmd_data.help.cfg_component->type); - fprintf(stderr, "\n%s%sCannot find component class %s", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); - print_plugin_comp_cls_opt(stderr, - cfg->cmd_data.help.cfg_component->plugin_name->str, - cfg->cmd_data.help.cfg_component->comp_cls_name->str, - cfg->cmd_data.help.cfg_component->type); - fprintf(stderr, "\n"); - ret = -1; - goto end; + goto error; } printf("\n"); print_component_class_help( cfg->cmd_data.help.cfg_component->plugin_name->str, needed_comp_cls); + cmd_status = BT_CMD_STATUS_OK; + goto end; + +error: + cmd_status = BT_CMD_STATUS_ERROR; end: bt_component_class_put_ref(needed_comp_cls); - bt_plugin_put_ref(plugin); - return ret; + return cmd_status; } typedef void *(* plugin_borrow_comp_cls_by_index_func_t)(const bt_plugin *, @@ -1102,12 +769,14 @@ typedef void *(* plugin_borrow_comp_cls_by_index_func_t)(const bt_plugin *, typedef const bt_component_class *(* spec_comp_cls_borrow_comp_cls_func_t)( void *); +static void cmd_list_plugins_print_component_classes(const bt_plugin *plugin, const char *cc_type_name, uint64_t count, plugin_borrow_comp_cls_by_index_func_t borrow_comp_cls_by_index_func, spec_comp_cls_borrow_comp_cls_func_t spec_comp_cls_borrow_comp_cls_func) { uint64_t i; + gchar *comp_cls_str = NULL; if (count == 0) { printf(" %s%s component classes%s: (none)\n", @@ -1133,10 +802,11 @@ void cmd_list_plugins_print_component_classes(const bt_plugin *plugin, bt_component_class_type type = bt_component_class_get_type(comp_class); - printf(" "); - print_plugin_comp_cls_opt(stdout, - bt_plugin_get_name(plugin), comp_class_name, - type); + g_free(comp_cls_str); + comp_cls_str = format_plugin_comp_cls_opt( + bt_plugin_get_name(plugin), comp_class_name, type, + BT_COMMON_COLOR_WHEN_AUTO); + printf(" %s", comp_cls_str); if (comp_class_description) { printf(": %s", comp_class_description); @@ -1146,26 +816,25 @@ void cmd_list_plugins_print_component_classes(const bt_plugin *plugin, } end: - return; + g_free(comp_cls_str); } static -int cmd_list_plugins(struct bt_config *cfg) +enum bt_cmd_status cmd_list_plugins(struct bt_config *cfg) { - int ret = 0; int plugins_count, component_classes_count = 0, i; printf("From the following plugin paths:\n\n"); print_value(stdout, cfg->plugin_paths, 2); printf("\n"); - plugins_count = loaded_plugins->len; + plugins_count = get_loaded_plugins_count(); if (plugins_count == 0) { printf("No plugins found.\n"); goto end; } for (i = 0; i < plugins_count; i++) { - const bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i); + const bt_plugin *plugin = borrow_loaded_plugin_by_index(i); component_classes_count += bt_plugin_get_source_component_class_count(plugin) + @@ -1182,7 +851,7 @@ int cmd_list_plugins(struct bt_config *cfg) bt_common_color_reset()); for (i = 0; i < plugins_count; i++) { - const bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i); + const bt_plugin *plugin = borrow_loaded_plugin_by_index(i); printf("\n"); print_plugin_info(plugin); @@ -1207,13 +876,14 @@ int cmd_list_plugins(struct bt_config *cfg) } end: - return ret; + return BT_CMD_STATUS_OK; } static -int cmd_print_lttng_live_sessions(struct bt_config *cfg) +enum bt_cmd_status cmd_print_lttng_live_sessions(struct bt_config *cfg) { int ret = 0; + enum bt_cmd_status cmd_status; const bt_component_class *comp_cls = NULL; const bt_value *results = NULL; bt_value *params = NULL; @@ -1223,7 +893,7 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg) static const char * const comp_cls_name = "lttng-live"; static const bt_component_class_type comp_cls_type = BT_COMPONENT_CLASS_TYPE_SOURCE; - int64_t array_size, i; + uint64_t array_size, i; const char *fail_reason = NULL; FILE *out_stream = stdout; @@ -1231,17 +901,11 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg) comp_cls = find_component_class(plugin_name, comp_cls_name, comp_cls_type); if (!comp_cls) { - BT_LOGE("Cannot find component class: plugin-name=\"%s\", " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find component class: plugin-name=\"%s\", " "comp-cls-name=\"%s\", comp-cls-type=%d", plugin_name, comp_cls_name, BT_COMPONENT_CLASS_TYPE_SOURCE); - fprintf(stderr, "%s%sCannot find component class %s", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); - print_plugin_comp_cls_opt(stderr, plugin_name, - comp_cls_name, comp_cls_type); - fprintf(stderr, "\n"); goto error; } @@ -1259,17 +923,16 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg) ret = query(cfg, comp_cls, "sessions", params, &results, &fail_reason); if (ret) { - goto failed; + BT_CLI_LOGE_APPEND_CAUSE("Failed to query `sessions` object: %s", + fail_reason); + goto error; } BT_ASSERT(results); if (!bt_value_is_array(results)) { - BT_LOGE_STR("Expecting an array for sessions query."); - fprintf(stderr, "%s%sUnexpected type returned by session query%s\n", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); + BT_CLI_LOGE_APPEND_CAUSE( + "Expecting an array for LTTng live `sessions` query."); goto error; } @@ -1278,71 +941,65 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg) fopen(cfg->cmd_data.print_lttng_live_sessions.output_path->str, "w"); if (!out_stream) { - ret = -1; BT_LOGE_ERRNO("Cannot open file for writing", ": path=\"%s\"", cfg->cmd_data.print_lttng_live_sessions.output_path->str); - goto end; + (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( + "Babeltrace CLI", + "Cannot open file for writing: path=\"%s\"", + cfg->cmd_data.print_lttng_live_sessions.output_path->str); + goto error; } } - array_size = bt_value_array_get_size(results); + array_size = bt_value_array_get_length(results); for (i = 0; i < array_size; i++) { const char *url_text; int64_t timer_us, streams, clients; map = bt_value_array_borrow_element_by_index_const(results, i); - if (!map) { - BT_LOGE_STR("Unexpected empty array entry."); - goto error; - } if (!bt_value_is_map(map)) { - BT_LOGE_STR("Unexpected entry type."); + BT_CLI_LOGE_APPEND_CAUSE("Unexpected entry type."); goto error; } v = bt_value_map_borrow_entry_value_const(map, "url"); if (!v) { - BT_LOGE_STR("Unexpected empty array \"url\" entry."); + BT_CLI_LOGE_APPEND_CAUSE("Missing `url` entry."); goto error; } url_text = bt_value_string_get(v); fprintf(out_stream, "%s", url_text); v = bt_value_map_borrow_entry_value_const(map, "timer-us"); if (!v) { - BT_LOGE_STR("Unexpected empty array \"timer-us\" entry."); + BT_CLI_LOGE_APPEND_CAUSE("Missing `timer-us` entry."); goto error; } - timer_us = bt_value_signed_integer_get(v); + timer_us = bt_value_integer_unsigned_get(v); fprintf(out_stream, " (timer = %" PRIu64 ", ", timer_us); v = bt_value_map_borrow_entry_value_const(map, "stream-count"); if (!v) { - BT_LOGE_STR("Unexpected empty array \"stream-count\" entry."); + BT_CLI_LOGE_APPEND_CAUSE( + "Missing `stream-count` entry."); goto error; } - streams = bt_value_signed_integer_get(v); + streams = bt_value_integer_unsigned_get(v); fprintf(out_stream, "%" PRIu64 " stream(s), ", streams); v = bt_value_map_borrow_entry_value_const(map, "client-count"); if (!v) { - BT_LOGE_STR("Unexpected empty array \"client-count\" entry."); + BT_CLI_LOGE_APPEND_CAUSE( + "Missing `client-count` entry."); goto error; } - clients = bt_value_signed_integer_get(v); + clients = bt_value_integer_unsigned_get(v); fprintf(out_stream, "%" PRIu64 " client(s) connected)\n", clients); } + cmd_status = BT_CMD_STATUS_OK; goto end; -failed: - BT_LOGE("Failed to query for sessions: %s", fail_reason); - fprintf(stderr, "%s%sFailed to request sessions: %s%s\n", - bt_common_color_bold(), - bt_common_color_fg_red(), - fail_reason, - bt_common_color_reset()); - error: - ret = -1; + cmd_status = BT_CMD_STATUS_ERROR; end: bt_value_put_ref(results); @@ -1359,13 +1016,14 @@ end: } } - return ret; + return cmd_status; } static -int cmd_print_ctf_metadata(struct bt_config *cfg) +enum bt_cmd_status cmd_print_ctf_metadata(struct bt_config *cfg) { int ret = 0; + enum bt_cmd_status cmd_status; const bt_component_class *comp_cls = NULL; const bt_value *results = NULL; bt_value *params = NULL; @@ -1382,46 +1040,39 @@ int cmd_print_ctf_metadata(struct bt_config *cfg) comp_cls = find_component_class(plugin_name, comp_cls_name, comp_cls_type); if (!comp_cls) { - BT_LOGE("Cannot find component class: plugin-name=\"%s\", " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find component class: plugin-name=\"%s\", " "comp-cls-name=\"%s\", comp-cls-type=%d", plugin_name, comp_cls_name, BT_COMPONENT_CLASS_TYPE_SOURCE); - fprintf(stderr, "%s%sCannot find component class %s", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); - print_plugin_comp_cls_opt(stderr, plugin_name, - comp_cls_name, comp_cls_type); - fprintf(stderr, "\n"); - ret = -1; - goto end; + goto error; } params = bt_value_map_create(); if (!params) { - ret = -1; - goto end; + goto error; } ret = bt_value_map_insert_string_entry(params, "path", cfg->cmd_data.print_ctf_metadata.path->str); if (ret) { - ret = -1; - goto end; + goto error; } ret = query(cfg, comp_cls, "metadata-info", params, &results, &fail_reason); if (ret) { - goto failed; + BT_CLI_LOGE_APPEND_CAUSE( + "Failed to query `metadata-info` object: %s", fail_reason); + goto error; } metadata_text_value = bt_value_map_borrow_entry_value_const(results, - "text"); + "text"); if (!metadata_text_value) { - BT_LOGE_STR("Cannot find `text` string value in the resulting metadata info object."); - ret = -1; - goto end; + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find `text` string value in the resulting metadata info object."); + goto error; } metadata_text = bt_value_string_get(metadata_text_value); @@ -1431,34 +1082,31 @@ int cmd_print_ctf_metadata(struct bt_config *cfg) fopen(cfg->cmd_data.print_ctf_metadata.output_path->str, "w"); if (!out_stream) { - ret = -1; BT_LOGE_ERRNO("Cannot open file for writing", ": path=\"%s\"", cfg->cmd_data.print_ctf_metadata.output_path->str); - goto end; + (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( + "Babeltrace CLI", + "Cannot open file for writing: path=\"%s\"", + cfg->cmd_data.print_ctf_metadata.output_path->str); + goto error; } } ret = fprintf(out_stream, "%s\n", metadata_text); if (ret < 0) { - BT_LOGE("Cannot write whole metadata text to output stream: " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot write whole metadata text to output stream: " "ret=%d", ret); - goto end; + goto error; } - ret = 0; - + cmd_status = BT_CMD_STATUS_OK; goto end; -failed: - ret = -1; - BT_LOGE("Failed to query for metadata info: %s", fail_reason); - fprintf(stderr, "%s%sFailed to request metadata info: %s%s\n", - bt_common_color_bold(), - bt_common_color_fg_red(), - fail_reason, - bt_common_color_reset()); - +error: + cmd_status = BT_CMD_STATUS_ERROR; + end: bt_value_put_ref(results); bt_value_put_ref(params); @@ -1474,7 +1122,7 @@ end: } } - return ret; + return cmd_status; } struct port_id { @@ -1504,8 +1152,8 @@ gboolean port_id_equal(gconstpointer v1, gconstpointer v2) const struct port_id *id1 = v1; const struct port_id *id2 = v2; - return !strcmp(id1->instance_name, id2->instance_name) && - !strcmp(id1->port_name, id2->port_name); + return strcmp(id1->instance_name, id2->instance_name) == 0 && + strcmp(id1->port_name, id2->port_name) == 0; } static @@ -1615,7 +1263,8 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( uint64_t i; input_port_count_func_t port_count_fn; borrow_input_port_by_index_func_t port_by_index_fn; - bt_graph_status status = BT_GRAPH_STATUS_ERROR; + bt_graph_connect_ports_status connect_ports_status = + BT_GRAPH_CONNECT_PORTS_STATUS_OK; bool insert_trimmer = false; bt_value *trimmer_params = NULL; char *intersection_begin = NULL; @@ -1641,14 +1290,15 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( range = (struct trace_range *) g_hash_table_lookup( ctx->intersections, &port_id); if (range) { - bt_value_status status; + bt_value_map_insert_entry_status insert_status; intersection_begin = s_from_ns( range->intersection_range_begin_ns); intersection_end = s_from_ns( range->intersection_range_end_ns); if (!intersection_begin || !intersection_end) { - BT_LOGE_STR("Cannot create trimmer argument timestamp string."); + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot create trimmer argument timestamp string."); goto error; } @@ -1658,15 +1308,15 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( goto error; } - status = bt_value_map_insert_string_entry( + insert_status = bt_value_map_insert_string_entry( trimmer_params, "begin", intersection_begin); - if (status != BT_VALUE_STATUS_OK) { + if (insert_status < 0) { goto error; } - status = bt_value_map_insert_string_entry( + insert_status = bt_value_map_insert_string_entry( trimmer_params, "end", intersection_end); - if (status != BT_VALUE_STATUS_OK) { + if (insert_status < 0) { goto error; } } @@ -1703,10 +1353,9 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( } if (!downstream_comp) { - BT_LOGE("Cannot find downstream component: comp-name=\"%s\", " - "conn-arg=\"%s\"", cfg_conn->downstream_comp_name->str, - cfg_conn->arg->str); - fprintf(stderr, "Cannot create connection: cannot find downstream component: %s\n", + BT_CLI_LOGE_APPEND_CAUSE("Cannot find downstream component: " + "comp-name=\"%s\", conn-arg=\"%s\"", + cfg_conn->downstream_comp_name->str, cfg_conn->arg->str); goto error; } @@ -1760,7 +1409,7 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( * source and the trimmer. */ char *trimmer_name = NULL; - bt_graph_status graph_status; + bt_graph_add_component_status add_comp_status; ret = asprintf(&trimmer_name, "stream-intersection-trimmer-%s", @@ -1771,12 +1420,14 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( ret = 0; ctx->connect_ports = false; - graph_status = bt_graph_add_filter_component( + add_comp_status = bt_graph_add_filter_component( ctx->graph, trimmer_class, trimmer_name, trimmer_params, ctx->cfg->log_level, &trimmer); + bt_component_filter_get_ref(trimmer); free(trimmer_name); - if (graph_status != BT_GRAPH_STATUS_OK) { + if (add_comp_status != + BT_GRAPH_ADD_COMPONENT_STATUS_OK) { goto error; } BT_ASSERT(trimmer); @@ -1807,36 +1458,15 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( } /* We have a winner! */ - status = bt_graph_connect_ports(ctx->graph, + connect_ports_status = bt_graph_connect_ports(ctx->graph, out_upstream_port, in_downstream_port, NULL); downstream_port = NULL; - switch (status) { - case BT_GRAPH_STATUS_OK: - break; - case BT_GRAPH_STATUS_CANCELED: - BT_LOGI_STR("Graph was canceled by user."); - status = BT_GRAPH_STATUS_OK; - break; - case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION: - BT_LOGE("A component refused a connection to one of its ports: " - "upstream-comp-addr=%p, upstream-comp-name=\"%s\", " - "upstream-port-addr=%p, upstream-port-name=\"%s\", " - "downstream-comp-addr=%p, downstream-comp-name=\"%s\", " - "downstream-port-addr=%p, downstream-port-name=\"%s\", " - "conn-arg=\"%s\"", - upstream_comp, bt_component_get_name(upstream_comp), - upstream_port, bt_port_get_name(upstream_port), - downstream_comp, cfg_conn->downstream_comp_name->str, - downstream_port, downstream_port_name, - cfg_conn->arg->str); - fprintf(stderr, - "A component refused a connection to one of its ports (`%s` to `%s`): %s\n", - bt_port_get_name(upstream_port), - downstream_port_name, - cfg_conn->arg->str); + switch (connect_ports_status) { + case BT_GRAPH_CONNECT_PORTS_STATUS_OK: break; default: - BT_LOGE("Cannot create connection: graph refuses to connect ports: " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot create connection: graph refuses to connect ports: " "upstream-comp-addr=%p, upstream-comp-name=\"%s\", " "upstream-port-addr=%p, upstream-port-name=\"%s\", " "downstream-comp-addr=%p, downstream-comp-name=\"%s\", " @@ -1847,11 +1477,6 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( downstream_comp, cfg_conn->downstream_comp_name->str, downstream_port, downstream_port_name, cfg_conn->arg->str); - fprintf(stderr, - "Cannot create connection: graph refuses to connect ports (`%s` to `%s`): %s\n", - bt_port_get_name(upstream_port), - downstream_port_name, - cfg_conn->arg->str); goto error; } @@ -1891,15 +1516,13 @@ int cmd_run_ctx_connect_upstream_port_to_downstream_component( } /* No downstream port found */ - BT_LOGE("Cannot create connection: cannot find a matching downstream port for upstream port: " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot create connection: cannot find a matching downstream port for upstream port: " "upstream-port-addr=%p, upstream-port-name=\"%s\", " "downstream-comp-name=\"%s\", conn-arg=\"%s\"", upstream_port, bt_port_get_name(upstream_port), cfg_conn->downstream_comp_name->str, cfg_conn->arg->str); - fprintf(stderr, - "Cannot create connection: cannot find a matching downstream port for upstream port `%s`: %s\n", - bt_port_get_name(upstream_port), cfg_conn->arg->str); error: ret = -1; @@ -1930,14 +1553,7 @@ int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx, BT_ASSERT(upstream_port_name); upstream_comp = bt_port_borrow_component_const( bt_port_output_as_port_const(upstream_port)); - if (!upstream_comp) { - BT_LOGW("Upstream port to connect is not part of a component: " - "port-addr=%p, port-name=\"%s\"", - upstream_port, upstream_port_name); - ret = -1; - goto end; - } - + BT_ASSERT(upstream_comp); upstream_comp_name = bt_component_get_name(upstream_comp); BT_ASSERT(upstream_comp_name); BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", " @@ -1964,26 +1580,20 @@ int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx, ret = cmd_run_ctx_connect_upstream_port_to_downstream_component( ctx, upstream_comp, upstream_port, cfg_conn); if (ret) { - BT_LOGE("Cannot connect upstream port: " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot connect upstream port: " "port-addr=%p, port-name=\"%s\"", upstream_port, upstream_port_name); - fprintf(stderr, - "Cannot connect port `%s` of component `%s` to a downstream port: %s\n", - upstream_port_name, - upstream_comp_name, - cfg_conn->arg->str); goto error; } goto end; } - BT_LOGE("Cannot connect upstream port: port does not match any connection argument: " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot connect upstream port: port does not match any connection argument: " "port-addr=%p, port-name=\"%s\"", upstream_port, upstream_port_name); - fprintf(stderr, - "Cannot create connection: upstream port `%s` does not match any connection\n", - upstream_port_name); error: ret = -1; @@ -1993,13 +1603,14 @@ end: } static -bt_graph_listener_status +bt_graph_listener_func_status graph_output_port_added_listener(struct cmd_run_ctx *ctx, const bt_port_output *out_port) { const bt_component *comp; const bt_port *port = bt_port_output_as_port_const(out_port); - bt_graph_listener_status ret = BT_GRAPH_LISTENER_STATUS_OK; + bt_graph_listener_func_status ret = + BT_GRAPH_LISTENER_FUNC_STATUS_OK; comp = bt_port_borrow_component_const(port); BT_LOGI("Port added to a graph's component: comp-addr=%p, " @@ -2011,10 +1622,7 @@ graph_output_port_added_listener(struct cmd_run_ctx *ctx, goto end; } - if (!comp) { - BT_LOGW_STR("Port has no component."); - goto end; - } + BT_ASSERT(comp); if (bt_port_is_connected(port)) { BT_LOGW_STR("Port is already connected."); @@ -2022,9 +1630,8 @@ graph_output_port_added_listener(struct cmd_run_ctx *ctx, } if (cmd_run_ctx_connect_upstream_port(ctx, out_port)) { - BT_LOGF_STR("Cannot connect upstream port."); - fprintf(stderr, "Added port could not be connected: aborting\n"); - ret = BT_GRAPH_LISTENER_STATUS_ERROR; + BT_CLI_LOGE_APPEND_CAUSE("Cannot connect upstream port."); + ret = BT_GRAPH_LISTENER_FUNC_STATUS_ERROR; goto end; } @@ -2033,7 +1640,7 @@ end: } static -bt_graph_listener_status graph_source_output_port_added_listener( +bt_graph_listener_func_status graph_source_output_port_added_listener( const bt_component_source *component, const bt_port_output *port, void *data) { @@ -2041,7 +1648,7 @@ bt_graph_listener_status graph_source_output_port_added_listener( } static -bt_graph_listener_status graph_filter_output_port_added_listener( +bt_graph_listener_func_status graph_filter_output_port_added_listener( const bt_component_filter *component, const bt_port_output *port, void *data) { @@ -2076,15 +1683,141 @@ void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx) } BT_GRAPH_PUT_REF_AND_RESET(ctx->graph); - the_graph = NULL; ctx->cfg = NULL; } +static +int add_descriptor_to_component_descriptor_set( + bt_component_descriptor_set *comp_descr_set, + const char *plugin_name, const char *comp_cls_name, + bt_component_class_type comp_cls_type, + const bt_value *params) +{ + const bt_component_class *comp_cls; + int status = 0; + + comp_cls = find_component_class(plugin_name, comp_cls_name, + comp_cls_type); + if (!comp_cls) { + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find component class: plugin-name=\"%s\", " + "comp-cls-name=\"%s\", comp-cls-type=%d", + plugin_name, comp_cls_name, comp_cls_type); + status = -1; + goto end; + } + + status = bt_component_descriptor_set_add_descriptor( + comp_descr_set, comp_cls, params); + if (status != BT_COMPONENT_DESCRIPTOR_SET_ADD_DESCRIPTOR_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot append descriptor to component descriptor set: " + "status=%s", bt_common_func_status_string(status)); + goto end; + } + +end: + bt_component_class_put_ref(comp_cls); + return status; +} + +static +int append_descriptors_from_bt_config_component_array( + bt_component_descriptor_set *comp_descr_set, + GPtrArray *component_configs) +{ + int ret = 0; + uint64_t i; + + for (i = 0; i < component_configs->len; i++) { + struct bt_config_component *cfg_comp = + component_configs->pdata[i]; + + ret = add_descriptor_to_component_descriptor_set( + comp_descr_set, + cfg_comp->plugin_name->str, + cfg_comp->comp_cls_name->str, + cfg_comp->type, cfg_comp->params); + if (ret) { + goto end; + } + } + +end: + return ret; +} + +static +bt_get_greatest_operative_mip_version_status get_greatest_operative_mip_version( + struct bt_config *cfg, uint64_t *mip_version) +{ + bt_get_greatest_operative_mip_version_status status = + BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK; + bt_component_descriptor_set *comp_descr_set = NULL; + int ret; + + BT_ASSERT(cfg); + BT_ASSERT(mip_version); + comp_descr_set = bt_component_descriptor_set_create(); + if (!comp_descr_set) { + BT_CLI_LOGE_APPEND_CAUSE( + "Failed to create a component descriptor set object."); + status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_MEMORY_ERROR; + goto end; + } + + ret = append_descriptors_from_bt_config_component_array( + comp_descr_set, cfg->cmd_data.run.sources); + if (ret) { + status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR; + goto end; + } + + ret = append_descriptors_from_bt_config_component_array( + comp_descr_set, cfg->cmd_data.run.filters); + if (ret) { + status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR; + goto end; + } + + ret = append_descriptors_from_bt_config_component_array( + comp_descr_set, cfg->cmd_data.run.sinks); + if (ret) { + status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR; + goto end; + } + + if (cfg->cmd_data.run.stream_intersection_mode) { + /* + * Stream intersection mode adds `flt.utils.trimmer` + * components; we need to include this type of component + * in the component descriptor set to get the real + * greatest operative MIP version. + */ + ret = add_descriptor_to_component_descriptor_set( + comp_descr_set, "utils", "trimmer", + BT_COMPONENT_CLASS_TYPE_FILTER, NULL); + if (ret) { + status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR; + goto end; + } + } + + status = bt_get_greatest_operative_mip_version(comp_descr_set, + bt_cli_log_level, mip_version); + +end: + bt_component_descriptor_set_put_ref(comp_descr_set); + return status; +} + static int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg) { int ret = 0; - bt_graph_status status; + bt_graph_add_listener_status add_listener_status; + bt_get_greatest_operative_mip_version_status mip_version_status; + uint64_t mip_version = UINT64_C(-1); ctx->cfg = cfg; ctx->connect_ports = false; @@ -2115,25 +1848,52 @@ int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg) } } - ctx->graph = bt_graph_create(); + /* + * Get the greatest operative MIP version to use to configure + * the graph to create. + */ + mip_version_status = get_greatest_operative_mip_version( + cfg, &mip_version); + if (mip_version_status == BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_NO_MATCH) { + BT_CLI_LOGE_APPEND_CAUSE( + "Failed to find an operative message interchange " + "protocol version to use to create the `run` command's " + "graph (components are not interoperable)."); + goto error; + } else if (mip_version_status < 0) { + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find an operative message interchange " + "protocol version to use to create the `run` command's " + "graph: status=%s", + bt_common_func_status_string(mip_version_status)); + goto error; + } + + BT_ASSERT(mip_version_status == BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK); + BT_LOGI("Found operative message interchange protocol version to " + "configure the `run` command's graph: mip-version=%" PRIu64, + mip_version); + ctx->graph = bt_graph_create(mip_version); if (!ctx->graph) { goto error; } - the_graph = ctx->graph; - status = bt_graph_add_source_component_output_port_added_listener( - ctx->graph, graph_source_output_port_added_listener, NULL, ctx, + bt_graph_add_interrupter(ctx->graph, the_interrupter); + add_listener_status = bt_graph_add_source_component_output_port_added_listener( + ctx->graph, graph_source_output_port_added_listener, ctx, NULL); - if (status != BT_GRAPH_STATUS_OK) { - BT_LOGE_STR("Cannot add \"port added\" listener to graph."); + if (add_listener_status != BT_GRAPH_ADD_LISTENER_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot add \"port added\" listener to graph."); goto error; } - status = bt_graph_add_filter_component_output_port_added_listener( - ctx->graph, graph_filter_output_port_added_listener, NULL, ctx, + add_listener_status = bt_graph_add_filter_component_output_port_added_listener( + ctx->graph, graph_filter_output_port_added_listener, ctx, NULL); - if (status != BT_GRAPH_STATUS_OK) { - BT_LOGE_STR("Cannot add \"port added\" listener to graph."); + if (add_listener_status != BT_GRAPH_ADD_LISTENER_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot add \"port added\" listener to graph."); goto error; } @@ -2147,6 +1907,116 @@ end: return ret; } +/* + * Compute the intersection of all streams in the array `streams`, write it + * in `range`. + */ + +static +int compute_stream_intersection(const bt_value *streams, + struct trace_range *range) +{ + uint64_t i, stream_count; + int ret; + + BT_ASSERT(bt_value_get_type(streams) == BT_VALUE_TYPE_ARRAY); + + stream_count = bt_value_array_get_length(streams); + + BT_ASSERT(stream_count > 0); + + range->intersection_range_begin_ns = 0; + range->intersection_range_end_ns = UINT64_MAX; + + for (i = 0; i < stream_count; i++) { + int64_t begin_ns, end_ns; + uint64_t begin_ns_u, end_ns_u; + const bt_value *stream_value; + const bt_value *range_ns_value; + const bt_value *begin_value; + const bt_value *end_value; + + stream_value = bt_value_array_borrow_element_by_index_const(streams, i); + if (bt_value_get_type(stream_value) != BT_VALUE_TYPE_MAP) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "expected streams array element to be a map, got %s.", + bt_common_value_type_string(bt_value_get_type(stream_value))); + goto error; + } + + range_ns_value = bt_value_map_borrow_entry_value_const( + stream_value, "range-ns"); + if (!range_ns_value) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "missing expected `range-ns` key in stream map."); + goto error; + } + + if (bt_value_get_type(range_ns_value) != BT_VALUE_TYPE_MAP) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "expected `range-ns` entry value of stream map to be a map, got %s.", + bt_common_value_type_string(bt_value_get_type(range_ns_value))); + goto error; + } + + begin_value = bt_value_map_borrow_entry_value_const(range_ns_value, "begin"); + if (!begin_value) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "missing expected `begin` key in range-ns map."); + goto error; + } + + if (bt_value_get_type(begin_value) != BT_VALUE_TYPE_SIGNED_INTEGER) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "expected `begin` entry value of range-ns map to be a signed integer, got %s.", + bt_common_value_type_string(bt_value_get_type(range_ns_value))); + goto error; + } + + end_value = bt_value_map_borrow_entry_value_const(range_ns_value, "end"); + if (!end_value) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "missing expected `end` key in range-ns map."); + goto error; + } + + if (bt_value_get_type(end_value) != BT_VALUE_TYPE_SIGNED_INTEGER) { + BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: " + "expected `end` entry value of range-ns map to be a signed integer, got %s.", + bt_common_value_type_string(bt_value_get_type(range_ns_value))); + goto error; + } + + begin_ns = bt_value_integer_signed_get(begin_value); + end_ns = bt_value_integer_signed_get(end_value); + + if (begin_ns < 0 || end_ns < 0 || end_ns < begin_ns) { + BT_CLI_LOGE_APPEND_CAUSE( + "Invalid stream range values: " + "range-ns:begin=%" PRId64 ", " + "range-ns:end=%" PRId64, + begin_ns, end_ns); + goto error; + } + + begin_ns_u = begin_ns; + end_ns_u = end_ns; + + range->intersection_range_begin_ns = + MAX(range->intersection_range_begin_ns, begin_ns_u); + range->intersection_range_end_ns = + MIN(range->intersection_range_end_ns, end_ns_u); + } + + ret = 0; + goto end; +error: + ret = -1; + +end: + return ret; +} + static int set_stream_intersections(struct cmd_run_ctx *ctx, struct bt_config_component *cfg_comp, @@ -2154,109 +2024,95 @@ int set_stream_intersections(struct cmd_run_ctx *ctx, { int ret = 0; uint64_t trace_idx; - int64_t trace_count; - const char *path = NULL; + uint64_t trace_count; const bt_value *query_result = NULL; const bt_value *trace_info = NULL; - const bt_value *intersection_range = NULL; - const bt_value *intersection_begin = NULL; - const bt_value *intersection_end = NULL; const bt_value *stream_infos = NULL; const bt_value *stream_info = NULL; struct port_id *port_id = NULL; - struct trace_range *trace_range = NULL; + struct trace_range *stream_intersection = NULL; const char *fail_reason = NULL; const bt_component_class *comp_cls = bt_component_class_source_as_component_class_const(src_comp_cls); - ret = query(ctx->cfg, comp_cls, "trace-info", + ret = query(ctx->cfg, comp_cls, "babeltrace.trace-infos", cfg_comp->params, &query_result, &fail_reason); if (ret) { - BT_LOGD("Component class does not support the `trace-info` query: %s: " + BT_CLI_LOGE_APPEND_CAUSE("Failed to execute `babeltrace.trace-infos` query: %s: " "comp-class-name=\"%s\"", fail_reason, bt_component_class_get_name(comp_cls)); ret = -1; - goto error; + goto end; } BT_ASSERT(query_result); if (!bt_value_is_array(query_result)) { - BT_LOGD("Unexpected format of \'trace-info\' query result: " - "component-class-name=%s", - bt_component_class_get_name(comp_cls)); + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: expecting result to be an array: " + "component-class-name=%s, actual-type=%s", + bt_component_class_get_name(comp_cls), + bt_common_value_type_string(bt_value_get_type(query_result))); ret = -1; - goto error; + goto end; } - trace_count = bt_value_array_get_size(query_result); - if (trace_count < 0) { + trace_count = bt_value_array_get_length(query_result); + if (trace_count == 0) { + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: result is empty: " + "component-class-name=%s", bt_component_class_get_name(comp_cls)); ret = -1; - goto error; + goto end; } for (trace_idx = 0; trace_idx < trace_count; trace_idx++) { - int64_t begin, end; uint64_t stream_idx; int64_t stream_count; + struct trace_range trace_intersection; trace_info = bt_value_array_borrow_element_by_index_const( query_result, trace_idx); - if (!trace_info || !bt_value_is_map(trace_info)) { - ret = -1; - BT_LOGD_STR("Cannot retrieve trace from query result."); - goto error; - } - - intersection_range = bt_value_map_borrow_entry_value_const( - trace_info, "intersection-range-ns"); - if (!intersection_range) { - ret = -1; - BT_LOGD_STR("Cannot retrieve \'intersetion-range-ns\' field from query result."); - goto error; - } - - intersection_begin = bt_value_map_borrow_entry_value_const(intersection_range, - "begin"); - if (!intersection_begin) { + if (!bt_value_is_map(trace_info)) { ret = -1; - BT_LOGD_STR("Cannot retrieve intersection-range-ns \'begin\' field from query result."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: expecting element to be a map: " + "component-class-name=%s, actual-type=%s", + bt_component_class_get_name(comp_cls), + bt_common_value_type_string(bt_value_get_type(trace_info))); + goto end; } - intersection_end = bt_value_map_borrow_entry_value_const(intersection_range, - "end"); - if (!intersection_end) { + stream_infos = bt_value_map_borrow_entry_value_const( + trace_info, "stream-infos"); + if (!stream_infos) { ret = -1; - BT_LOGD_STR("Cannot retrieve intersection-range-ns \'end\' field from query result."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: missing `streams` key in trace info map: " + "component-class-name=%s", + bt_component_class_get_name(comp_cls)); + goto end; } - begin = bt_value_signed_integer_get(intersection_begin); - end = bt_value_signed_integer_get(intersection_end); - - if (begin < 0 || end < 0 || end < begin) { - BT_LOGW("Invalid trace stream intersection values: " - "intersection-range-ns:begin=%" PRId64 - ", intersection-range-ns:end=%" PRId64, - begin, end); + if (!bt_value_is_array(stream_infos)) { ret = -1; - goto error; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: expecting `streams` entry of trace info map to be an array: " + "component-class-name=%s, actual-type=%s", + bt_component_class_get_name(comp_cls), + bt_common_value_type_string(bt_value_get_type(stream_infos))); + goto end; } - stream_infos = bt_value_map_borrow_entry_value_const(trace_info, - "streams"); - if (!stream_infos || !bt_value_is_array(stream_infos)) { + stream_count = bt_value_array_get_length(stream_infos); + if (stream_count == 0) { ret = -1; - BT_LOGD_STR("Cannot retrieve stream information from trace in query result."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: list of streams is empty: " + "component-class-name=%s", + bt_component_class_get_name(comp_cls)); + goto end; } - stream_count = bt_value_array_get_size(stream_infos); - if (stream_count < 0) { - ret = -1; - goto error; + ret = compute_stream_intersection(stream_infos, &trace_intersection); + if (ret != 0) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to compute trace streams intersection."); + goto end; } for (stream_idx = 0; stream_idx < stream_count; stream_idx++) { @@ -2265,68 +2121,83 @@ int set_stream_intersections(struct cmd_run_ctx *ctx, port_id = g_new0(struct port_id, 1); if (!port_id) { ret = -1; - BT_LOGE_STR("Cannot allocate memory for port_id structure."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot allocate memory for port_id structure."); + goto end; } port_id->instance_name = strdup(cfg_comp->instance_name->str); if (!port_id->instance_name) { ret = -1; - BT_LOGE_STR("Cannot allocate memory for port_id component instance name."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot allocate memory for port_id component instance name."); + goto end; } - trace_range = g_new0(struct trace_range, 1); - if (!trace_range) { + stream_intersection = g_new0(struct trace_range, 1); + if (!stream_intersection) { ret = -1; - BT_LOGE_STR("Cannot allocate memory for trace_range structure."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot allocate memory for trace_range structure."); + goto end; } - trace_range->intersection_range_begin_ns = begin; - trace_range->intersection_range_end_ns = end; + + *stream_intersection = trace_intersection; stream_info = bt_value_array_borrow_element_by_index_const( stream_infos, stream_idx); - if (!stream_info || !bt_value_is_map(stream_info)) { + if (!bt_value_is_map(stream_info)) { ret = -1; - BT_LOGE_STR("Cannot retrieve stream informations from trace in query result."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: " + "expecting element of stream list to be a map: " + "component-class-name=%s, actual-type=%s", + bt_component_class_get_name(comp_cls), + bt_common_value_type_string(bt_value_get_type(stream_info))); + goto end; } port_name = bt_value_map_borrow_entry_value_const(stream_info, "port-name"); - if (!port_name || !bt_value_is_string(port_name)) { + if (!port_name) { ret = -1; - BT_LOGE_STR("Cannot retrieve port name in query result."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: " + "missing `port-name` key in stream info map: " + "component-class-name=%s", + bt_component_class_get_name(comp_cls)); + goto end; + } + + if (!bt_value_is_string(port_name)) { + ret = -1; + BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: " + "expecting `port-name` entry of stream info map to be a string: " + "component-class-name=%s, actual-type=%s", + bt_component_class_get_name(comp_cls), + bt_common_value_type_string(bt_value_get_type(port_name))); + goto end; } port_id->port_name = g_strdup(bt_value_string_get(port_name)); if (!port_id->port_name) { ret = -1; - BT_LOGE_STR("Cannot allocate memory for port_id port_name."); - goto error; + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot allocate memory for port_id port_name."); + goto end; } BT_LOGD("Inserting stream intersection "); - g_hash_table_insert(ctx->intersections, port_id, trace_range); + g_hash_table_insert(ctx->intersections, port_id, stream_intersection); port_id = NULL; - trace_range = NULL; + stream_intersection = NULL; } } - goto end; + ret = 0; -error: - fprintf(stderr, "%s%sCannot determine stream intersection of trace at path \'%s\'.%s\n", - bt_common_color_bold(), - bt_common_color_fg_yellow(), - path ? path : "(unknown)", - bt_common_color_reset()); end: bt_value_put_ref(query_result); g_free(port_id); - g_free(trace_range); + g_free(stream_intersection); return ret; } @@ -2361,28 +2232,20 @@ int cmd_run_ctx_create_components_from_config_components( cfg_comp->comp_cls_name->str); break; default: - abort(); + bt_common_abort(); } if (!comp_cls) { - BT_LOGE("Cannot find component class: plugin-name=\"%s\", " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot find component class: plugin-name=\"%s\", " "comp-cls-name=\"%s\", comp-cls-type=%d", cfg_comp->plugin_name->str, cfg_comp->comp_cls_name->str, cfg_comp->type); - fprintf(stderr, "%s%sCannot find component class %s", - bt_common_color_bold(), - bt_common_color_fg_red(), - bt_common_color_reset()); - print_plugin_comp_cls_opt(stderr, - cfg_comp->plugin_name->str, - cfg_comp->comp_cls_name->str, - cfg_comp->type); - fprintf(stderr, "\n"); goto error; } - BT_ASSERT(cfg_comp->log_level >= BT_LOG_VERBOSE); + BT_ASSERT(cfg_comp->log_level >= BT_LOG_TRACE); switch (cfg_comp->type) { case BT_COMPONENT_CLASS_TYPE_SOURCE: @@ -2390,35 +2253,34 @@ int cmd_run_ctx_create_components_from_config_components( comp_cls, cfg_comp->instance_name->str, cfg_comp->params, cfg_comp->log_level, (void *) &comp); + bt_component_source_get_ref(comp); break; case BT_COMPONENT_CLASS_TYPE_FILTER: ret = bt_graph_add_filter_component(ctx->graph, comp_cls, cfg_comp->instance_name->str, cfg_comp->params, cfg_comp->log_level, (void *) &comp); + bt_component_filter_get_ref(comp); break; case BT_COMPONENT_CLASS_TYPE_SINK: ret = bt_graph_add_sink_component(ctx->graph, comp_cls, cfg_comp->instance_name->str, cfg_comp->params, cfg_comp->log_level, (void *) &comp); + bt_component_sink_get_ref(comp); break; default: - abort(); + bt_common_abort(); } if (ret) { - BT_LOGE("Cannot create component: plugin-name=\"%s\", " + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot create component: plugin-name=\"%s\", " "comp-cls-name=\"%s\", comp-cls-type=%d, " "comp-name=\"%s\"", cfg_comp->plugin_name->str, cfg_comp->comp_cls_name->str, cfg_comp->type, cfg_comp->instance_name->str); - fprintf(stderr, "%s%sCannot create component `%s`%s\n", - bt_common_color_bold(), - bt_common_color_fg_red(), - cfg_comp->instance_name->str, - bt_common_color_reset()); goto error; } @@ -2426,6 +2288,8 @@ int cmd_run_ctx_create_components_from_config_components( cfg_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) { ret = set_stream_intersections(ctx, cfg_comp, comp_cls); if (ret) { + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot determine stream intersection of trace."); goto error; } } @@ -2449,7 +2313,7 @@ int cmd_run_ctx_create_components_from_config_components( GUINT_TO_POINTER(quark), (void *) comp); break; default: - abort(); + bt_common_abort(); } comp = NULL; @@ -2572,44 +2436,22 @@ end: return ret; } -static inline -const char *bt_graph_status_str(bt_graph_status status) -{ - switch (status) { - case BT_GRAPH_STATUS_OK: - return "BT_GRAPH_STATUS_OK"; - case BT_GRAPH_STATUS_END: - return "BT_GRAPH_STATUS_END"; - case BT_GRAPH_STATUS_AGAIN: - return "BT_GRAPH_STATUS_AGAIN"; - case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION: - return "BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION"; - case BT_GRAPH_STATUS_CANCELED: - return "BT_GRAPH_STATUS_CANCELED"; - case BT_GRAPH_STATUS_ERROR: - return "BT_GRAPH_STATUS_ERROR"; - case BT_GRAPH_STATUS_NOMEM: - return "BT_GRAPH_STATUS_NOMEM"; - default: - return "(unknown)"; - } -} - static -int cmd_run(struct bt_config *cfg) +enum bt_cmd_status cmd_run(struct bt_config *cfg) { - int ret = 0; + enum bt_cmd_status cmd_status; struct cmd_run_ctx ctx = { 0 }; /* Initialize the command's context and the graph object */ if (cmd_run_ctx_init(&ctx, cfg)) { - BT_LOGE_STR("Cannot initialize the command's context."); - fprintf(stderr, "Cannot initialize the command's context\n"); + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot initialize the command's context."); goto error; } - if (canceled) { - BT_LOGI_STR("Canceled by user before creating components."); + if (bt_interrupter_is_set(the_interrupter)) { + BT_CLI_LOGW_APPEND_CAUSE( + "Interrupted by user before creating components."); goto error; } @@ -2617,13 +2459,13 @@ int cmd_run(struct bt_config *cfg) /* Create the requested component instances */ if (cmd_run_ctx_create_components(&ctx)) { - BT_LOGE_STR("Cannot create components."); - fprintf(stderr, "Cannot create components\n"); + BT_CLI_LOGE_APPEND_CAUSE("Cannot create components."); goto error; } - if (canceled) { - BT_LOGI_STR("Canceled by user before connecting components."); + if (bt_interrupter_is_set(the_interrupter)) { + BT_CLI_LOGW_APPEND_CAUSE( + "Interrupted by user before connecting components."); goto error; } @@ -2631,13 +2473,8 @@ int cmd_run(struct bt_config *cfg) /* Connect the initially visible component ports */ if (cmd_run_ctx_connect_ports(&ctx)) { - BT_LOGE_STR("Cannot connect initial component ports."); - fprintf(stderr, "Cannot connect initial component ports\n"); - goto error; - } - - if (canceled) { - BT_LOGI_STR("Canceled by user before running the graph."); + BT_CLI_LOGE_APPEND_CAUSE( + "Cannot connect initial component ports."); goto error; } @@ -2645,7 +2482,7 @@ int cmd_run(struct bt_config *cfg) /* Run the graph */ while (true) { - bt_graph_status graph_status = bt_graph_run(ctx.graph); + bt_graph_run_status run_status = bt_graph_run(ctx.graph); /* * Reset console in case something messed with console @@ -2654,53 +2491,52 @@ int cmd_run(struct bt_config *cfg) printf("%s", bt_common_color_reset()); fflush(stdout); fprintf(stderr, "%s", bt_common_color_reset()); - BT_LOGV("bt_graph_run() returned: status=%s", - bt_graph_status_str(graph_status)); + BT_LOGT("bt_graph_run() returned: status=%s", + bt_common_func_status_string(run_status)); - switch (graph_status) { - case BT_GRAPH_STATUS_OK: - break; - case BT_GRAPH_STATUS_CANCELED: - BT_LOGI_STR("Graph was canceled by user."); - goto error; - case BT_GRAPH_STATUS_AGAIN: - if (bt_graph_is_canceled(ctx.graph)) { - BT_LOGI_STR("Graph was canceled by user."); - goto error; + switch (run_status) { + case BT_GRAPH_RUN_STATUS_OK: + cmd_status = BT_CMD_STATUS_OK; + goto end; + case BT_GRAPH_RUN_STATUS_AGAIN: + if (bt_interrupter_is_set(the_interrupter)) { + /* + * The graph was interrupted by a SIGINT. + */ + cmd_status = BT_CMD_STATUS_INTERRUPTED; + goto end; } if (cfg->cmd_data.run.retry_duration_us > 0) { - BT_LOGV("Got BT_GRAPH_STATUS_AGAIN: sleeping: " + BT_LOGT("Got BT_GRAPH_RUN_STATUS_AGAIN: sleeping: " "time-us=%" PRIu64, cfg->cmd_data.run.retry_duration_us); if (usleep(cfg->cmd_data.run.retry_duration_us)) { - if (bt_graph_is_canceled(ctx.graph)) { - BT_LOGI_STR("Graph was canceled by user."); - goto error; + if (bt_interrupter_is_set(the_interrupter)) { + cmd_status = BT_CMD_STATUS_INTERRUPTED; + goto end; } } } break; - case BT_GRAPH_STATUS_END: - goto end; default: - BT_LOGE_STR("Graph failed to complete successfully"); - fprintf(stderr, "Graph failed to complete successfully\n"); + if (bt_interrupter_is_set(the_interrupter)) { + cmd_status = BT_CMD_STATUS_INTERRUPTED; + goto end; + } + + BT_CLI_LOGE_APPEND_CAUSE( + "Graph failed to complete successfully"); goto error; } } - - goto end; - error: - if (ret == 0) { - ret = -1; - } + cmd_status = BT_CMD_STATUS_ERROR; end: cmd_run_ctx_destroy(&ctx); - return ret; + return cmd_status; } static @@ -2719,13 +2555,14 @@ void warn_command_name_and_directory_clash(struct bt_config *cfg) if (g_file_test(cfg->command_name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n", - cfg->command_name); - fprintf(stderr, "trace located in the local `%s` directory, please use:\n", - cfg->command_name); - fprintf(stderr, "\n"); - fprintf(stderr, " babeltrace2 convert %s [OPTIONS]\n", - cfg->command_name); + _bt_log_write_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, + BT_LOG_WARNING, BT_LOG_TAG, + "The `%s` command was executed. " + "If you meant to convert a trace located in " + "the local `%s` directory, please use:\n\n" + " babeltrace2 convert %s [OPTIONS]", + cfg->command_name, cfg->command_name, + cfg->command_name); } } @@ -2736,96 +2573,65 @@ void init_log_level(void) } static -void set_auto_log_levels(struct bt_config *cfg) +void print_error_causes(void) { - const char **env_var_name; - - /* - * Override the configuration's default log level if - * BABELTRACE_VERBOSE or BABELTRACE_DEBUG environment variables - * are found for backward compatibility with legacy Babetrace 1. - */ - if (getenv("BABELTRACE_DEBUG") && - strcmp(getenv("BABELTRACE_DEBUG"), "1") == 0) { - cfg->log_level = BT_LOG_VERBOSE; - } else if (getenv("BABELTRACE_VERBOSE") && - strcmp(getenv("BABELTRACE_VERBOSE"), "1") == 0) { - cfg->log_level = BT_LOG_INFO; - } + const bt_error *error = bt_current_thread_take_error(); + unsigned int columns; + gchar *error_str = NULL; - /* - * Set log levels according to --debug or --verbose. For - * backward compatibility, --debug is more verbose than - * --verbose. So: - * - * --verbose: INFO log level - * --debug: VERBOSE log level (includes DEBUG, which is - * is less verbose than VERBOSE in the internal - * logging framework) - */ - if (!getenv("BABELTRACE_LOGGING_GLOBAL_LEVEL")) { - if (cfg->verbose) { - bt_logging_set_global_level(BT_LOG_INFO); - } else if (cfg->debug) { - bt_logging_set_global_level(BT_LOG_VERBOSE); - } else { - /* - * Set library's default log level if not - * explicitly specified. - */ - bt_logging_set_global_level(cfg->log_level); - } + if (!error || bt_error_get_cause_count(error) == 0) { + fprintf(stderr, "%s%sUnknown command-line error.%s\n", + bt_common_color_bold(), bt_common_color_fg_bright_red(), + bt_common_color_reset()); + goto end; } - if (!getenv(ENV_BABELTRACE_CLI_LOG_LEVEL)) { - if (cfg->verbose) { - bt_cli_log_level = BT_LOG_INFO; - } else if (cfg->debug) { - bt_cli_log_level = BT_LOG_VERBOSE; - } else { - /* - * Set CLI's default log level if not explicitly - * specified. - */ - bt_cli_log_level = cfg->log_level; - } + /* Try to get terminal width to fold the error cause messages */ + if (bt_common_get_term_size(&columns, NULL) < 0) { + /* Width not found: default to 80 */ + columns = 80; } - env_var_name = log_level_env_var_names; + /* + * This helps visually separate the error causes from the last + * logging statement. + */ + fputc('\n', stderr); - while (*env_var_name) { - if (!getenv(*env_var_name)) { - if (cfg->verbose) { - g_setenv(*env_var_name, "I", 1); - } else if (cfg->debug) { - g_setenv(*env_var_name, "V", 1); - } else { - char val[2] = { 0 }; + error_str = format_bt_error(error, columns, bt_cli_log_level, + BT_COMMON_COLOR_WHEN_AUTO); + BT_ASSERT(error_str); - /* - * Set module's default log level if not - * explicitly specified. - */ - val[0] = bt_log_get_letter_from_level( - cfg->log_level); - g_setenv(*env_var_name, val, 1); - } - } + fprintf(stderr, "%s\n", error_str); - env_var_name++; +end: + if (error) { + bt_error_release(error); } + + g_free(error_str); } int main(int argc, const char **argv) { - int ret; - int retcode; - struct bt_config *cfg; + int ret, retcode; + enum bt_cmd_status cmd_status; + struct bt_config *cfg = NULL; init_log_level(); set_signal_handler(); - init_static_data(); - cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode); + init_loaded_plugins(); + + BT_ASSERT(!the_interrupter); + the_interrupter = bt_interrupter_create(); + if (!the_interrupter) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to create an interrupter object."); + retcode = 1; + goto end; + } + + cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode, + the_interrupter); if (retcode < 0) { /* Quit without errors; typically usage/version */ @@ -2835,24 +2641,25 @@ int main(int argc, const char **argv) } if (retcode > 0) { - BT_LOGE("Command-line error: retcode=%d", retcode); + BT_CLI_LOGE_APPEND_CAUSE( + "Command-line error: retcode=%d", retcode); goto end; } if (!cfg) { - BT_LOGE_STR("Failed to create a valid Babeltrace configuration."); - fprintf(stderr, "Failed to create Babeltrace configuration\n"); + BT_CLI_LOGE_APPEND_CAUSE( + "Failed to create a valid Babeltrace CLI configuration."); retcode = 1; goto end; } - set_auto_log_levels(cfg); print_cfg(cfg); if (cfg->command_needs_plugins) { - ret = load_all_plugins(cfg->plugin_paths); + ret = require_loaded_plugins(cfg->plugin_paths); if (ret) { - BT_LOGE("Failed to load plugins: ret=%d", ret); + BT_CLI_LOGE_APPEND_CAUSE( + "Failed to load plugins: ret=%d", ret); retcode = 1; goto end; } @@ -2863,35 +2670,60 @@ int main(int argc, const char **argv) switch (cfg->command) { case BT_CONFIG_COMMAND_RUN: - ret = cmd_run(cfg); + cmd_status = cmd_run(cfg); break; case BT_CONFIG_COMMAND_LIST_PLUGINS: - ret = cmd_list_plugins(cfg); + cmd_status = cmd_list_plugins(cfg); break; case BT_CONFIG_COMMAND_HELP: - ret = cmd_help(cfg); + cmd_status = cmd_help(cfg); break; case BT_CONFIG_COMMAND_QUERY: - ret = cmd_query(cfg); + cmd_status = cmd_query(cfg); break; case BT_CONFIG_COMMAND_PRINT_CTF_METADATA: - ret = cmd_print_ctf_metadata(cfg); + cmd_status = cmd_print_ctf_metadata(cfg); break; case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS: - ret = cmd_print_lttng_live_sessions(cfg); + cmd_status = cmd_print_lttng_live_sessions(cfg); break; default: BT_LOGF("Invalid/unknown command: cmd=%d", cfg->command); - abort(); + bt_common_abort(); } - BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", ret=%d", - cfg->command, cfg->command_name, ret); + BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", command-status=\"%s\"", + cfg->command, cfg->command_name, bt_cmd_status_string(cmd_status)); warn_command_name_and_directory_clash(cfg); - retcode = ret ? 1 : 0; + + switch (cmd_status) { + case BT_CMD_STATUS_OK: + retcode = 0; + break; + case BT_CMD_STATUS_ERROR: + retcode = 1; + break; + case BT_CMD_STATUS_INTERRUPTED: + retcode = 2; + break; + default: + BT_LOGF("Invalid command status: cmd-status=%d", cmd_status); + bt_common_abort(); + } end: + if (retcode == 1) { + print_error_causes(); + } + BT_OBJECT_PUT_REF_AND_RESET(cfg); - fini_static_data(); + fini_loaded_plugins(); + bt_interrupter_put_ref(the_interrupter); + + /* + * Clear current thread's error in case there is one to avoid a + * memory leak. + */ + bt_current_thread_clear_error(); return retcode; }