cli: automatically detect sources for leftover arguments
[babeltrace.git] / src / cli / babeltrace2-cfg-cli-args.c
index c4cb1756ce7361aa8db1af36513634e150233477..7fc0488455b565b143ca9b8e9521d25d34d3130c 100644 (file)
 #include "babeltrace2-cfg.h"
 #include "babeltrace2-cfg-cli-args.h"
 #include "babeltrace2-cfg-cli-args-connect.h"
+#include "babeltrace2-cfg-cli-params-arg.h"
+#include "babeltrace2-plugins.h"
+#include "babeltrace2-cfg-src-auto-disc.h"
 #include "common/version.h"
 
-/*
- * Error printf() macro which prepends "Error: " the first time it's
- * called. This gives a nicer feel than having a bunch of error prefixes
- * (since the following lines usually describe the error and possible
- * solutions), or the error prefix just at the end.
- */
-#define printf_err(fmt, args...)                                       \
-       do {                                                            \
-               if (is_first_error) {                                   \
-                       fprintf(stderr, "Command line error: ");        \
-                       is_first_error = false;                         \
-               }                                                       \
-               fprintf(stderr, fmt, ##args);                           \
-       } while (0)
-
-static bool is_first_error = true;
-static const int cli_default_log_level = BT_LOG_WARN;
+static const int cli_default_log_level = BT_LOG_WARNING;
 
 /* INI-style parsing FSM states */
 enum ini_parsing_fsm_state {
@@ -145,542 +132,7 @@ enum legacy_output_format {
        LEGACY_OUTPUT_FORMAT_DUMMY,
 };
 
-/*
- * Prints the "out of memory" error.
- */
-static
-void print_err_oom(void)
-{
-       printf_err("Out of memory\n");
-}
-
-/*
- * Appends an "expecting token" error to the INI-style parsing state's
- * error buffer.
- */
-static
-void ini_append_error_expecting(struct ini_parsing_state *state,
-               GScanner *scanner, const char *expecting)
-{
-       size_t i;
-       size_t pos;
-
-       g_string_append_printf(state->ini_error, "Expecting %s:\n", expecting);
-
-       /* Only print error if there's one line */
-       if (strchr(state->arg, '\n') != NULL || strlen(state->arg) == 0) {
-               return;
-       }
-
-       g_string_append_printf(state->ini_error, "\n    %s\n", state->arg);
-       pos = g_scanner_cur_position(scanner) + 4;
-
-       if (!g_scanner_eof(scanner)) {
-               pos--;
-       }
-
-       for (i = 0; i < pos; ++i) {
-               g_string_append_printf(state->ini_error, " ");
-       }
-
-       g_string_append_printf(state->ini_error, "^\n\n");
-}
-
-/* Parse the next token as an unsigned integer. */
-static
-bt_value *ini_parse_uint(struct ini_parsing_state *state)
-{
-       bt_value *value = NULL;
-       GTokenType token_type = g_scanner_get_next_token(state->scanner);
-
-       if (token_type != G_TOKEN_INT) {
-               ini_append_error_expecting(state, state->scanner,
-                       "integer value");
-               goto end;
-       }
-
-       value = bt_value_unsigned_integer_create_init(
-               state->scanner->value.v_int64);
-
-end:
-       return value;
-}
-
-/* Parse the next token as a number and return its negation. */
-static
-bt_value *ini_parse_neg_number(struct ini_parsing_state *state)
-{
-       bt_value *value = NULL;
-       GTokenType token_type = g_scanner_get_next_token(state->scanner);
-
-       switch (token_type) {
-       case G_TOKEN_INT:
-       {
-               /* Negative integer */
-               uint64_t int_val = state->scanner->value.v_int64;
-
-               if (int_val > (((uint64_t) INT64_MAX) + 1)) {
-                       g_string_append_printf(state->ini_error,
-                               "Integer value -%" PRIu64 " is outside the range of a 64-bit signed integer\n",
-                               int_val);
-               } else {
-                       value = bt_value_signed_integer_create_init(
-                               -((int64_t) int_val));
-               }
-
-               break;
-       }
-       case G_TOKEN_FLOAT:
-               /* Negative floating point number */
-               value = bt_value_real_create_init(-state->scanner->value.v_float);
-               break;
-       default:
-               ini_append_error_expecting(state, state->scanner, "value");
-               break;
-       }
-
-       return value;
-}
-
-static bt_value *ini_parse_value(struct ini_parsing_state *state);
-
-/*
- * Parse the current and following tokens as an array.  Arrays are formatted as
- * an opening `[`, a list of comma-separated values and a closing `]`.  For
- * convenience we support an optional trailing comma, after the last value.
- *
- * The current token of the parser must be the opening square bracket of the
- * array.
- */
-static
-bt_value *ini_parse_array(struct ini_parsing_state *state)
-{
-       /* The [ character must have already been ingested. */
-       BT_ASSERT(g_scanner_cur_token(state->scanner) == G_TOKEN_CHAR);
-       BT_ASSERT(g_scanner_cur_value(state->scanner).v_char == '[');
-
-       bt_value *array_value;
-       GTokenType token_type;
-
-       array_value = bt_value_array_create ();
-       token_type = g_scanner_get_next_token(state->scanner);
-
-       /* While the current token is not a ]... */
-       while (!(token_type == G_TOKEN_CHAR && g_scanner_cur_value(state->scanner).v_char == ']')) {
-               /* Parse the item... */
-               bt_value *item_value;
-               bt_value_status status;
-
-               item_value = ini_parse_value(state);
-               if (!item_value) {
-                       goto error;
-               }
-
-               /* ... and add it to the result array. */
-               status = bt_value_array_append_element(array_value, item_value);
-               BT_VALUE_PUT_REF_AND_RESET(item_value);
-
-               if (status != BT_VALUE_STATUS_OK) {
-                       goto error;
-               }
-
-               /*
-                * Ingest the token following the value, it should be either a
-                * comma or closing square brace.
-                */
-               token_type = g_scanner_get_next_token(state->scanner);
-
-               if (token_type == G_TOKEN_CHAR && g_scanner_cur_value(state->scanner).v_char == ',') {
-                       /*
-                        * Ingest the token following the comma.  If it happens
-                        * to be a closing square bracket, we'll exit the loop
-                        * and we are done (we allow trailing commas).
-                        * Otherwise, we are ready for the next ini_parse_value call.
-                        */
-                       token_type = g_scanner_get_next_token(state->scanner);
-               } else if (token_type != G_TOKEN_CHAR || g_scanner_cur_value(state->scanner).v_char != ']') {
-                       ini_append_error_expecting(state, state->scanner, ", or ]");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(array_value);
-
-end:
-       return array_value;
-}
-
-/*
- * Parse the current token (and the following ones if needed) as a value, return
- * it as a bt_value.
- */
-static
-bt_value *ini_parse_value(struct ini_parsing_state *state)
-{
-       bt_value *value = NULL;
-       GTokenType token_type = state->scanner->token;
-
-       switch (token_type) {
-       case G_TOKEN_CHAR:
-               if (state->scanner->value.v_char == '-') {
-                       /* Negative number */
-                       value = ini_parse_neg_number(state);
-               } else if (state->scanner->value.v_char == '+') {
-                       /* Unsigned integer */
-                       value = ini_parse_uint(state);
-               } else if (state->scanner->value.v_char == '[') {
-                       /* Array */
-                       value = ini_parse_array(state);
-               } else {
-                       ini_append_error_expecting(state, state->scanner, "value");
-               }
-               break;
-       case G_TOKEN_INT:
-       {
-               /* Positive, signed integer */
-               uint64_t int_val = state->scanner->value.v_int64;
-
-               if (int_val > INT64_MAX) {
-                       g_string_append_printf(state->ini_error,
-                               "Integer value %" PRIu64 " is outside the range of a 64-bit signed integer\n",
-                               int_val);
-               } else {
-                       value = bt_value_signed_integer_create_init(
-                               (int64_t) int_val);
-               }
-               break;
-       }
-       case G_TOKEN_FLOAT:
-               /* Positive floating point number */
-               value = bt_value_real_create_init(state->scanner->value.v_float);
-               break;
-       case G_TOKEN_STRING:
-               /* Quoted string */
-               value = bt_value_string_create_init(state->scanner->value.v_string);
-               break;
-       case G_TOKEN_IDENTIFIER:
-       {
-               /*
-                * Using symbols would be appropriate here,
-                * but said symbols are allowed as map key,
-                * so it's easier to consider everything an
-                * identifier.
-                *
-                * If one of the known symbols is not
-                * recognized here, then fall back to creating
-                * a string value.
-                */
-               const char *id = state->scanner->value.v_identifier;
-
-               if (!strcmp(id, "null") || !strcmp(id, "NULL") ||
-                               !strcmp(id, "nul")) {
-                       value = bt_value_null;
-               } else if (!strcmp(id, "true") || !strcmp(id, "TRUE") ||
-                               !strcmp(id, "yes") ||
-                               !strcmp(id, "YES")) {
-                       value = bt_value_bool_create_init(true);
-               } else if (!strcmp(id, "false") ||
-                               !strcmp(id, "FALSE") ||
-                               !strcmp(id, "no") ||
-                               !strcmp(id, "NO")) {
-                       value = bt_value_bool_create_init(false);
-               } else {
-                       value = bt_value_string_create_init(id);
-               }
-               break;
-       }
-       default:
-               /* Unset value variable will trigger the error */
-               ini_append_error_expecting(state, state->scanner, "value");
-               break;
-       }
-
-       return value;
-}
-
-static
-int ini_handle_state(struct ini_parsing_state *state)
-{
-       int ret = 0;
-       GTokenType token_type;
-       bt_value *value = NULL;
-
-       token_type = g_scanner_get_next_token(state->scanner);
-       if (token_type == G_TOKEN_EOF) {
-               if (state->expecting != INI_EXPECT_COMMA) {
-                       switch (state->expecting) {
-                       case INI_EXPECT_EQUAL:
-                               ini_append_error_expecting(state,
-                                       state->scanner, "'='");
-                               break;
-                       case INI_EXPECT_VALUE:
-                               ini_append_error_expecting(state,
-                                       state->scanner, "value");
-                               break;
-                       case INI_EXPECT_MAP_KEY:
-                               ini_append_error_expecting(state,
-                                       state->scanner, "unquoted map key");
-                               break;
-                       default:
-                               break;
-                       }
-                       goto error;
-               }
-
-               /* We're done! */
-               ret = 1;
-               goto success;
-       }
-
-       switch (state->expecting) {
-       case INI_EXPECT_MAP_KEY:
-               if (token_type != G_TOKEN_IDENTIFIER) {
-                       ini_append_error_expecting(state, state->scanner,
-                               "unquoted map key");
-                       goto error;
-               }
-
-               free(state->last_map_key);
-               state->last_map_key =
-                       strdup(state->scanner->value.v_identifier);
-               if (!state->last_map_key) {
-                       g_string_append(state->ini_error,
-                               "Out of memory\n");
-                       goto error;
-               }
-
-               if (bt_value_map_has_entry(state->params,
-                                          state->last_map_key)) {
-                       g_string_append_printf(state->ini_error,
-                               "Duplicate parameter key: `%s`\n",
-                               state->last_map_key);
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_EQUAL;
-               goto success;
-       case INI_EXPECT_EQUAL:
-               if (token_type != G_TOKEN_CHAR) {
-                       ini_append_error_expecting(state,
-                               state->scanner, "'='");
-                       goto error;
-               }
-
-               if (state->scanner->value.v_char != '=') {
-                       ini_append_error_expecting(state,
-                               state->scanner, "'='");
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_VALUE;
-               goto success;
-       case INI_EXPECT_VALUE:
-       {
-               value = ini_parse_value(state);
-               if (!value) {
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_COMMA;
-               goto success;
-       }
-       case INI_EXPECT_COMMA:
-               if (token_type != G_TOKEN_CHAR) {
-                       ini_append_error_expecting(state,
-                               state->scanner, "','");
-                       goto error;
-               }
-
-               if (state->scanner->value.v_char != ',') {
-                       ini_append_error_expecting(state,
-                               state->scanner, "','");
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_MAP_KEY;
-               goto success;
-       default:
-               abort();
-       }
-
-error:
-       ret = -1;
-       goto end;
-
-success:
-       if (value) {
-               if (bt_value_map_insert_entry(state->params,
-                               state->last_map_key, value)) {
-                       /* Only override return value on error */
-                       ret = -1;
-               }
-       }
-
-end:
-       BT_VALUE_PUT_REF_AND_RESET(value);
-       return ret;
-}
-
-/*
- * Converts an INI-style argument to an equivalent map value object.
- *
- * Return value is owned by the caller.
- */
-static
-bt_value *bt_value_from_ini(const char *arg,
-               GString *ini_error)
-{
-       /* Lexical scanner configuration */
-       GScannerConfig scanner_config = {
-               /* Skip whitespaces */
-               .cset_skip_characters = " \t\n",
-
-               /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
-               .cset_identifier_first =
-                       G_CSET_a_2_z
-                       "_"
-                       G_CSET_A_2_Z,
-               .cset_identifier_nth =
-                       G_CSET_a_2_z
-                       "_0123456789-.:"
-                       G_CSET_A_2_Z,
-
-               /* "hello" and "Hello" two different keys */
-               .case_sensitive = TRUE,
-
-               /* No comments */
-               .cpair_comment_single = NULL,
-               .skip_comment_multi = TRUE,
-               .skip_comment_single = TRUE,
-               .scan_comment_multi = FALSE,
-
-               /*
-                * Do scan identifiers, including 1-char identifiers,
-                * but NULL is a normal identifier.
-                */
-               .scan_identifier = TRUE,
-               .scan_identifier_1char = TRUE,
-               .scan_identifier_NULL = FALSE,
-
-               /*
-                * No specific symbols: null and boolean "symbols" are
-                * scanned as plain identifiers.
-                */
-               .scan_symbols = FALSE,
-               .symbol_2_token = FALSE,
-               .scope_0_fallback = FALSE,
-
-               /*
-                * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
-                * integers prefixed with "$".
-                */
-               .scan_binary = TRUE,
-               .scan_octal = TRUE,
-               .scan_float = TRUE,
-               .scan_hex = TRUE,
-               .scan_hex_dollar = FALSE,
-
-               /* Convert scanned numbers to integer tokens */
-               .numbers_2_int = TRUE,
-
-               /* Support both integers and floating-point numbers */
-               .int_2_float = FALSE,
-
-               /* Scan integers as 64-bit signed integers */
-               .store_int64 = TRUE,
-
-               /* Only scan double-quoted strings */
-               .scan_string_sq = FALSE,
-               .scan_string_dq = TRUE,
-
-               /* Do not converter identifiers to string tokens */
-               .identifier_2_string = FALSE,
-
-               /* Scan characters as G_TOKEN_CHAR token */
-               .char_2_token = FALSE,
-       };
-       struct ini_parsing_state state = {
-               .scanner = NULL,
-               .params = NULL,
-               .expecting = INI_EXPECT_MAP_KEY,
-               .arg = arg,
-               .ini_error = ini_error,
-       };
-
-       state.params = bt_value_map_create();
-       if (!state.params) {
-               goto error;
-       }
-
-       state.scanner = g_scanner_new(&scanner_config);
-       if (!state.scanner) {
-               goto error;
-       }
-
-       /* Let the scan begin */
-       g_scanner_input_text(state.scanner, arg, strlen(arg));
-
-       while (true) {
-               int ret = ini_handle_state(&state);
-
-               if (ret < 0) {
-                       /* Error */
-                       goto error;
-               } else if (ret > 0) {
-                       /* Done */
-                       break;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(state.params);
-
-end:
-       if (state.scanner) {
-               g_scanner_destroy(state.scanner);
-       }
-
-       free(state.last_map_key);
-       return state.params;
-}
-
-/*
- * Returns the parameters map value object from a command-line
- * parameter option's argument.
- *
- * Return value is owned by the caller.
- */
-static
-bt_value *bt_value_from_arg(const char *arg)
-{
-       bt_value *params = NULL;
-       GString *ini_error = NULL;
-
-       ini_error = g_string_new(NULL);
-       if (!ini_error) {
-               print_err_oom();
-               goto end;
-       }
-
-       /* Try INI-style parsing */
-       params = bt_value_from_ini(arg, ini_error);
-       if (!params) {
-               printf_err("%s", ini_error->str);
-               goto end;
-       }
-
-end:
-       if (ini_error) {
-               g_string_free(ini_error, TRUE);
-       }
-
-       return params;
-}
+#define BT_CLI_LOGE_APPEND_CAUSE_OOM() BT_CLI_LOGE_APPEND_CAUSE("Out of memory.")
 
 /*
  * Returns the plugin name, component class name, component class type,
@@ -714,7 +166,7 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
        BT_ASSERT(comp_cls_type);
 
        if (!bt_common_string_is_printable(arg)) {
-               printf_err("Argument contains a non-printable character\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Argument contains a non-printable character.");
                goto error;
        }
 
@@ -734,7 +186,7 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
        /* Parse the component class type */
        gs_comp_cls_type = bt_common_string_until(at, ".:\\", ".", &end_pos);
        if (!gs_comp_cls_type || at[end_pos] == '\0') {
-               printf_err("Missing component class type (`source`, `filter`, or `sink`)\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Missing component class type (`source`, `filter`, or `sink`).");
                goto error;
        }
 
@@ -747,7 +199,7 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
        } else if (strcmp(gs_comp_cls_type->str, "sink") == 0) {
                *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SINK;
        } else {
-               printf_err("Unknown component class type: `%s`\n",
+               BT_CLI_LOGE_APPEND_CAUSE("Unknown component class type: `%s`.",
                        gs_comp_cls_type->str);
                goto error;
        }
@@ -757,7 +209,7 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
        /* Parse the plugin name */
        gs_plugin = bt_common_string_until(at, ".:\\", ".", &end_pos);
        if (!gs_plugin || gs_plugin->len == 0 || at[end_pos] == '\0') {
-               printf_err("Missing plugin or component class name\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Missing plugin or component class name.");
                goto error;
        }
 
@@ -766,7 +218,7 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
        /* Parse the component class name */
        gs_comp_cls = bt_common_string_until(at, ".:\\", ".", &end_pos);
        if (!gs_comp_cls || gs_comp_cls->len == 0) {
-               printf_err("Missing component class name\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Missing component class name.");
                goto error;
        }
 
@@ -886,7 +338,7 @@ struct bt_config_component *bt_config_component_create(
 
        cfg_component = g_new0(struct bt_config_component, 1);
        if (!cfg_component) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -895,19 +347,19 @@ struct bt_config_component *bt_config_component_create(
        cfg_component->type = type;
        cfg_component->plugin_name = g_string_new(plugin_name);
        if (!cfg_component->plugin_name) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg_component->comp_cls_name = g_string_new(comp_cls_name);
        if (!cfg_component->comp_cls_name) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg_component->instance_name = g_string_new(NULL);
        if (!cfg_component->instance_name) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -916,7 +368,7 @@ struct bt_config_component *bt_config_component_create(
        /* Start with empty parameters */
        cfg_component->params = bt_value_map_create();
        if (!cfg_component->params) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1102,7 +554,7 @@ GScanner *create_csv_identifiers_scanner(void)
 
        scanner = g_scanner_new(&scanner_config);
        if (!scanner) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
        }
 
        return scanner;
@@ -1123,7 +575,7 @@ bt_value *names_from_arg(const char *arg)
 
        names = bt_value_array_create();
        if (!names) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1142,42 +594,42 @@ bt_value *names_from_arg(const char *arg)
                {
                        const char *identifier = scanner->value.v_identifier;
 
-                       if (!strcmp(identifier, "payload") ||
-                                       !strcmp(identifier, "args") ||
-                                       !strcmp(identifier, "arg")) {
+                       if (strcmp(identifier, "payload") == 0 ||
+                                       strcmp(identifier, "args") == 0 ||
+                                       strcmp(identifier, "arg") == 0) {
                                found_item = true;
                                if (bt_value_array_append_string_element(names,
                                                "payload")) {
                                        goto error;
                                }
-                       } else if (!strcmp(identifier, "context") ||
-                                       !strcmp(identifier, "ctx")) {
+                       } else if (strcmp(identifier, "context") == 0 ||
+                                       strcmp(identifier, "ctx") == 0) {
                                found_item = true;
                                if (bt_value_array_append_string_element(names,
                                                "context")) {
                                        goto error;
                                }
-                       } else if (!strcmp(identifier, "scope") ||
-                                       !strcmp(identifier, "header")) {
+                       } else if (strcmp(identifier, "scope") == 0 ||
+                                       strcmp(identifier, "header") == 0) {
                                found_item = true;
                                if (bt_value_array_append_string_element(names,
                                                identifier)) {
                                        goto error;
                                }
-                       } else if (!strcmp(identifier, "all")) {
+                       } else if (strcmp(identifier, "all") == 0) {
                                found_all = true;
                                if (bt_value_array_append_string_element(names,
                                                identifier)) {
                                        goto error;
                                }
-                       } else if (!strcmp(identifier, "none")) {
+                       } else if (strcmp(identifier, "none") == 0) {
                                found_none = true;
                                if (bt_value_array_append_string_element(names,
                                                identifier)) {
                                        goto error;
                                }
                        } else {
-                               printf_err("Unknown name: `%s`\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Unknown name: `%s`.",
                                        identifier);
                                goto error;
                        }
@@ -1194,7 +646,7 @@ bt_value *names_from_arg(const char *arg)
 
 end:
        if (found_none && found_all) {
-               printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Only either `all` or `none` can be specified in the list given to the --names option, but not both.");
                goto error;
        }
        /*
@@ -1234,7 +686,7 @@ bt_value *fields_from_arg(const char *arg)
 
        fields = bt_value_array_create();
        if (!fields) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1253,21 +705,21 @@ bt_value *fields_from_arg(const char *arg)
                {
                        const char *identifier = scanner->value.v_identifier;
 
-                       if (!strcmp(identifier, "trace") ||
-                                       !strcmp(identifier, "trace:hostname") ||
-                                       !strcmp(identifier, "trace:domain") ||
-                                       !strcmp(identifier, "trace:procname") ||
-                                       !strcmp(identifier, "trace:vpid") ||
-                                       !strcmp(identifier, "loglevel") ||
-                                       !strcmp(identifier, "emf") ||
-                                       !strcmp(identifier, "callsite") ||
-                                       !strcmp(identifier, "all")) {
+                       if (strcmp(identifier, "trace") == 0 ||
+                                       strcmp(identifier, "trace:hostname") == 0 ||
+                                       strcmp(identifier, "trace:domain") == 0 ||
+                                       strcmp(identifier, "trace:procname") == 0 ||
+                                       strcmp(identifier, "trace:vpid") == 0 ||
+                                       strcmp(identifier, "loglevel") == 0 ||
+                                       strcmp(identifier, "emf") == 0 ||
+                                       strcmp(identifier, "callsite") == 0 ||
+                                       strcmp(identifier, "all") == 0) {
                                if (bt_value_array_append_string_element(fields,
                                                identifier)) {
                                        goto error;
                                }
                        } else {
-                               printf_err("Unknown field: `%s`\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Unknown field: `%s`.",
                                        identifier);
                                goto error;
                        }
@@ -1333,14 +785,14 @@ int insert_flat_params_from_array(GString *params_arg,
 
        tmpstr = g_string_new(NULL);
        if (!tmpstr) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
 
        default_value = g_string_new(NULL);
        if (!default_value) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -1353,7 +805,7 @@ int insert_flat_params_from_array(GString *params_arg,
                bool is_default = false;
 
                if (!str_obj) {
-                       printf_err("Unexpected error\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("Unexpected error.");
                        ret = -1;
                        goto end;
                }
@@ -1364,10 +816,10 @@ int insert_flat_params_from_array(GString *params_arg,
                g_string_append(tmpstr, "-");
 
                /* Special-case for "all" and "none". */
-               if (!strcmp(suffix, "all")) {
+               if (strcmp(suffix, "all") == 0) {
                        is_default = true;
                        g_string_assign(default_value, "show");
-               } else if (!strcmp(suffix, "none")) {
+               } else if (strcmp(suffix, "none") == 0) {
                        is_default = true;
                        g_string_assign(default_value, "hide");
                }
@@ -1491,14 +943,14 @@ int add_run_cfg_comp_check_name(struct bt_config *cfg,
        int ret = 0;
 
        if (cfg_comp->instance_name->len == 0) {
-               printf_err("Found an unnamed component\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Found an unnamed component.");
                ret = -1;
                goto end;
        }
 
        if (bt_value_map_has_entry(instance_names,
                                   cfg_comp->instance_name->str)) {
-               printf_err("Duplicate component instance name:\n    %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("Duplicate component instance name:\n    %s",
                        cfg_comp->instance_name->str);
                ret = -1;
                goto end;
@@ -1506,7 +958,7 @@ int add_run_cfg_comp_check_name(struct bt_config *cfg,
 
        if (bt_value_map_insert_entry(instance_names,
                        cfg_comp->instance_name->str, bt_value_null)) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -1537,7 +989,7 @@ int append_env_var_plugin_paths(bt_value *plugin_paths)
 
 end:
        if (ret) {
-               printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH.");
        }
 
        return ret;
@@ -1562,7 +1014,7 @@ int append_home_and_system_plugin_paths(bt_value *plugin_paths,
                                free(home_plugin_dir);
 
                                if (ret) {
-                                       printf_err("Invalid home plugin path\n");
+                                       BT_CLI_LOGE_APPEND_CAUSE("Invalid home plugin path.");
                                        goto error;
                                }
                        }
@@ -1572,13 +1024,13 @@ int append_home_and_system_plugin_paths(bt_value *plugin_paths,
        if (!omit_system_plugin_path) {
                if (bt_config_append_plugin_paths(plugin_paths,
                                bt_common_get_system_plugin_path())) {
-                       printf_err("Invalid system plugin path\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("Invalid system plugin path.");
                        goto error;
                }
        }
        return 0;
 error:
-       printf_err("Cannot append home and system plugin paths\n");
+       BT_CLI_LOGE_APPEND_CAUSE("Cannot append home and system plugin paths.");
        return -1;
 }
 
@@ -1599,7 +1051,7 @@ struct bt_config *bt_config_base_create(enum bt_config_command command,
        /* Create config */
        cfg = g_new0(struct bt_config, 1);
        if (!cfg) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1616,7 +1068,7 @@ struct bt_config *bt_config_base_create(enum bt_config_command command,
        } else {
                cfg->plugin_paths = bt_value_array_create();
                if (!cfg->plugin_paths) {
-                       print_err_oom();
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
        }
@@ -1646,28 +1098,28 @@ struct bt_config *bt_config_run_create(
        cfg->cmd_data.run.sources = g_ptr_array_new_with_free_func(
                (GDestroyNotify) bt_object_put_ref);
        if (!cfg->cmd_data.run.sources) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg->cmd_data.run.filters = g_ptr_array_new_with_free_func(
                (GDestroyNotify) bt_object_put_ref);
        if (!cfg->cmd_data.run.filters) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg->cmd_data.run.sinks = g_ptr_array_new_with_free_func(
                (GDestroyNotify) bt_object_put_ref);
        if (!cfg->cmd_data.run.sinks) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg->cmd_data.run.connections = g_ptr_array_new_with_free_func(
                (GDestroyNotify) bt_config_connection_destroy);
        if (!cfg->cmd_data.run.connections) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1746,7 +1198,7 @@ struct bt_config *bt_config_query_create(
 
        cfg->cmd_data.query.object = g_string_new(NULL);
        if (!cfg->cmd_data.query.object) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1774,13 +1226,13 @@ struct bt_config *bt_config_print_ctf_metadata_create(
 
        cfg->cmd_data.print_ctf_metadata.path = g_string_new(NULL);
        if (!cfg->cmd_data.print_ctf_metadata.path) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg->cmd_data.print_ctf_metadata.output_path = g_string_new(NULL);
        if (!cfg->cmd_data.print_ctf_metadata.output_path) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1808,14 +1260,14 @@ struct bt_config *bt_config_print_lttng_live_sessions_create(
 
        cfg->cmd_data.print_lttng_live_sessions.url = g_string_new(NULL);
        if (!cfg->cmd_data.print_lttng_live_sessions.url) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cfg->cmd_data.print_lttng_live_sessions.output_path =
                g_string_new(NULL);
        if (!cfg->cmd_data.print_lttng_live_sessions.output_path) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -1840,7 +1292,7 @@ int bt_config_append_plugin_paths_check_setuid_setgid(
        }
 
        if (bt_config_append_plugin_paths(plugin_paths, arg)) {
-               printf_err("Invalid --plugin-path option's argument:\n    %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("Invalid --plugin-path option's argument:\n    %s",
                        arg);
                ret = -1;
                goto end;
@@ -1961,7 +1413,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
        pc = poptGetContext(NULL, argc, (const char **) argv,
                help_long_options, 0);
        if (!pc) {
-               printf_err("Cannot get popt context\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context.");
                goto error;
        }
 
@@ -1989,7 +1441,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
                        BT_OBJECT_PUT_REF_AND_RESET(cfg);
                        goto end;
                default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
+                       BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
                                opt);
                        goto error;
                }
@@ -2000,7 +1452,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
 
        /* Check for option parsing error */
        if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: `%s`.",
                        poptBadOption(pc, 0), poptStrerror(opt));
                goto error;
        }
@@ -2106,6 +1558,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
        struct bt_config *cfg = NULL;
        const char *leftover;
        bt_value *params;
+       GString *error_str = NULL;
 
        params = bt_value_null;
        bt_value_get_ref(bt_value_null);
@@ -2116,6 +1569,12 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                goto error;
        }
 
+       error_str = g_string_new(NULL);
+       if (!error_str) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               goto error;
+       }
+
        cfg->omit_system_plugin_path = force_omit_system_plugin_path;
        cfg->omit_home_plugin_path = force_omit_home_plugin_path;
        ret = append_env_var_plugin_paths(cfg->plugin_paths);
@@ -2127,7 +1586,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
        pc = poptGetContext(NULL, argc, (const char **) argv,
                query_long_options, 0);
        if (!pc) {
-               printf_err("Cannot get popt context\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context.");
                goto error;
        }
 
@@ -2152,10 +1611,10 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                case OPT_PARAMS:
                {
                        bt_value_put_ref(params);
-                       params = bt_value_from_arg(arg);
+                       params = cli_value_from_arg(arg, error_str);
                        if (!params) {
-                               printf_err("Invalid format for --params option's argument:\n    %s\n",
-                                       arg);
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n    %s",
+                                       error_str->str);
                                goto error;
                        }
                        break;
@@ -2166,7 +1625,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                        BT_OBJECT_PUT_REF_AND_RESET(cfg);
                        goto end;
                default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
+                       BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
                                opt);
                        goto error;
                }
@@ -2177,7 +1636,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
 
        /* Check for option parsing error */
        if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: `%s`.",
                        poptBadOption(pc, 0), poptStrerror(opt));
                goto error;
        }
@@ -2192,7 +1651,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                        bt_config_component_from_arg(leftover,
                                default_log_level);
                if (!cfg->cmd_data.query.cfg_component) {
-                       printf_err("Invalid format for component class specification:\n    %s\n",
+                       BT_CLI_LOGE_APPEND_CAUSE("Invalid format for component class specification:\n    %s",
                                leftover);
                        goto error;
                }
@@ -2210,7 +1669,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
        leftover = poptGetArg(pc);
        if (leftover) {
                if (strlen(leftover) == 0) {
-                       printf_err("Invalid empty object\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("Invalid empty object.");
                        goto error;
                }
 
@@ -2224,7 +1683,7 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
 
        leftover = poptGetArg(pc);
        if (leftover) {
-               printf_err("Unexpected argument: %s\n", leftover);
+               BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.", leftover);
                goto error;
        }
 
@@ -2243,6 +1702,10 @@ end:
                poptFreeContext(pc);
        }
 
+       if (error_str) {
+               g_string_free(error_str, TRUE);
+       }
+
        bt_value_put_ref(params);
        free(arg);
        return cfg;
@@ -2316,7 +1779,7 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
        pc = poptGetContext(NULL, argc, (const char **) argv,
                list_plugins_long_options, 0);
        if (!pc) {
-               printf_err("Cannot get popt context\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context.");
                goto error;
        }
 
@@ -2344,7 +1807,7 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
                        BT_OBJECT_PUT_REF_AND_RESET(cfg);
                        goto end;
                default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
+                       BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
                                opt);
                        goto error;
                }
@@ -2355,14 +1818,14 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
 
        /* Check for option parsing error */
        if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: %s",
                        poptBadOption(pc, 0), poptStrerror(opt));
                goto error;
        }
 
        leftover = poptGetArg(pc);
        if (leftover) {
-               printf_err("Unexpected argument: %s\n", leftover);
+               BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.", leftover);
                goto error;
        }
 
@@ -2490,7 +1953,8 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
        bt_value *connection_args = NULL;
        char error_buf[256] = { 0 };
        long retry_duration = -1;
-       bt_value_status status;
+       bt_value_map_extend_status extend_status;
+       GString *error_str = NULL;
        struct poptOption run_long_options[] = {
                { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
                { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL },
@@ -2509,6 +1973,12 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
 
        *retcode = 0;
 
+       error_str = g_string_new(NULL);
+       if (!error_str) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               goto error;
+       }
+
        if (argc <= 1) {
                print_run_usage(stdout);
                *retcode = -1;
@@ -2525,19 +1995,19 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
        cfg->omit_home_plugin_path = force_omit_home_plugin_path;
        cur_base_params = bt_value_map_create();
        if (!cur_base_params) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        instance_names = bt_value_map_create();
        if (!instance_names) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        connection_args = bt_value_array_create();
        if (!connection_args) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -2550,7 +2020,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
        pc = poptGetContext(NULL, argc, (const char **) argv,
                run_long_options, 0);
        if (!pc) {
-               printf_err("Cannot get popt context\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context.");
                goto error;
        }
 
@@ -2589,7 +2059,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        cur_cfg_comp = bt_config_component_from_arg(arg,
                                default_log_level);
                        if (!cur_cfg_comp) {
-                               printf_err("Invalid format for --component option's argument:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --component option's argument:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -2610,10 +2080,9 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
 
                        BT_ASSERT(cur_base_params);
                        bt_value_put_ref(cur_cfg_comp->params);
-                       status = bt_value_copy(cur_base_params,
-                               &cur_cfg_comp->params);
-                       if (status != BT_VALUE_STATUS_OK) {
-                               print_err_oom();
+                       if (bt_value_copy(cur_base_params,
+                                       &cur_cfg_comp->params) < 0) {
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
@@ -2626,23 +2095,23 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        bt_value *params_to_set;
 
                        if (!cur_cfg_comp) {
-                               printf_err("Cannot add parameters to unavailable component:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Cannot add parameters to unavailable component:\n    %s",
                                        arg);
                                goto error;
                        }
 
-                       params = bt_value_from_arg(arg);
+                       params = cli_value_from_arg(arg, error_str);
                        if (!params) {
-                               printf_err("Invalid format for --params option's argument:\n    %s\n",
-                                       arg);
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n    %s",
+                                       error_str->str);
                                goto error;
                        }
 
-                       status = bt_value_map_extend(cur_cfg_comp->params,
-                               params, &params_to_set);
+                       extend_status = bt_value_map_extend(
+                               cur_cfg_comp->params, params, &params_to_set);
                        BT_VALUE_PUT_REF_AND_RESET(params);
-                       if (status != BT_VALUE_STATUS_OK) {
-                               printf_err("Cannot extend current component parameters with --params option's argument:\n    %s\n",
+                       if (extend_status != BT_VALUE_MAP_EXTEND_STATUS_OK) {
+                               BT_CLI_LOGE_APPEND_CAUSE("Cannot extend current component parameters with --params option's argument:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -2652,7 +2121,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                }
                case OPT_NAME:
                        if (!cur_cfg_comp) {
-                               printf_err("Cannot set the name of unavailable component:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Cannot set the name of unavailable component:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -2661,7 +2130,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        break;
                case OPT_LOG_LEVEL:
                        if (!cur_cfg_comp) {
-                               printf_err("Cannot set the log level of unavailable component:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Cannot set the log level of unavailable component:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -2669,19 +2138,18 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        cur_cfg_comp->log_level =
                                bt_log_get_level_from_string(arg);
                        if (cur_cfg_comp->log_level < 0) {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n    %s",
                                        arg);
                                goto error;
                        }
                        break;
                case OPT_BASE_PARAMS:
                {
-                       bt_value *params =
-                               bt_value_from_arg(arg);
+                       bt_value *params = cli_value_from_arg(arg, error_str);
 
                        if (!params) {
-                               printf_err("Invalid format for --base-params option's argument:\n    %s\n",
-                                       arg);
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --base-params option's argument:\n    %s",
+                                       error_str->str);
                                goto error;
                        }
 
@@ -2692,20 +2160,20 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
                        cur_base_params = bt_value_map_create();
                        if (!cur_base_params) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
                case OPT_CONNECT:
                        if (bt_value_array_append_string_element(
                                        connection_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
                case OPT_RETRY_DURATION:
                        if (retry_duration < 0) {
-                               printf_err("--retry-duration option's argument must be positive or 0: %ld\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("--retry-duration option's argument must be positive or 0: %ld",
                                        retry_duration);
                                goto error;
                        }
@@ -2719,7 +2187,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        BT_OBJECT_PUT_REF_AND_RESET(cfg);
                        goto end;
                default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
+                       BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
                                opt);
                        goto error;
                }
@@ -2730,14 +2198,14 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
 
        /* Check for option parsing error */
        if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: %s",
                        poptBadOption(pc, 0), poptStrerror(opt));
                goto error;
        }
 
        /* This command does not accept leftover arguments */
        if (poptPeekArg(pc)) {
-               printf_err("Unexpected argument: %s\n", poptPeekArg(pc));
+               BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: %s", poptPeekArg(pc));
                goto error;
        }
 
@@ -2752,12 +2220,12 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
        }
 
        if (cfg->cmd_data.run.sources->len == 0) {
-               printf_err("Incomplete graph: no source component\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no source component.");
                goto error;
        }
 
        if (cfg->cmd_data.run.sinks->len == 0) {
-               printf_err("Incomplete graph: no sink component\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no sink component.");
                goto error;
        }
 
@@ -2769,7 +2237,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                connection_args,
                error_buf, 256);
        if (ret) {
-               printf_err("Cannot creation connections:\n%s", error_buf);
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot creation connections:\n%s", error_buf);
                goto error;
        }
 
@@ -2784,6 +2252,10 @@ end:
                poptFreeContext(pc);
        }
 
+       if (error_str) {
+               g_string_free(error_str, TRUE);
+       }
+
        free(arg);
        BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
        BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
@@ -2805,7 +2277,7 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args,
 
        argv = calloc(argc, sizeof(*argv));
        if (!argv) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
@@ -2813,7 +2285,7 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args,
 
        len = bt_value_array_get_size(run_args);
        if (len < 0) {
-               printf_err("Invalid executable arguments\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Invalid executable arguments.");
                goto end;
        }
        for (i = 0; i < len; i++) {
@@ -2868,6 +2340,7 @@ void print_convert_usage(FILE *fp)
        fprintf(fp, "  -P, --path=PATH                   Set the `path` string parameter of the\n");
        fprintf(fp, "                                    current component to PATH\n");
        fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
        fprintf(fp, "      --retry-duration=DUR          When babeltrace2(1) needs to retry to run\n");
        fprintf(fp, "                                    the graph later, retry in DUR Âµs\n");
        fprintf(fp, "                                    (default: 100000)\n");
@@ -3026,7 +2499,7 @@ GString *get_component_auto_name(const char *prefix,
        GString *auto_name = g_string_new(NULL);
 
        if (!auto_name) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
@@ -3046,8 +2519,13 @@ end:
 
 struct implicit_component_args {
        bool exists;
+
+       /* The component class name (e.g. src.ctf.fs). */
        GString *comp_arg;
+
+       /* The component instance name. */
        GString *name_arg;
+
        GString *params_arg;
        bt_value *extra_params;
 };
@@ -3076,7 +2554,7 @@ int assign_name_to_implicit_component(struct implicit_component_args *args,
 
        if (bt_value_map_insert_entry(existing_names, name->str,
                        bt_value_null)) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3107,34 +2585,34 @@ int append_run_args_for_implicit_component(
        }
 
        if (bt_value_array_append_string_element(run_args, "--component")) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        if (bt_value_array_append_string_element(run_args, impl_args->comp_arg->str)) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        if (bt_value_array_append_string_element(run_args, "--name")) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        if (bt_value_array_append_string_element(run_args, impl_args->name_arg->str)) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        if (impl_args->params_arg->len > 0) {
                if (bt_value_array_append_string_element(run_args, "--params")) {
-                       print_err_oom();
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
 
                if (bt_value_array_append_string_element(run_args,
                                impl_args->params_arg->str)) {
-                       print_err_oom();
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
        }
@@ -3154,7 +2632,7 @@ int append_run_args_for_implicit_component(
                arg = bt_value_string_get(elem);
                ret = bt_value_array_append_string_element(run_args, arg);
                if (ret) {
-                       print_err_oom();
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
        }
@@ -3168,6 +2646,8 @@ end:
        return ret;
 }
 
+/* Free the fields of a `struct implicit_component_args`. */
+
 static
 void finalize_implicit_component_args(struct implicit_component_args *args)
 {
@@ -3188,6 +2668,17 @@ void finalize_implicit_component_args(struct implicit_component_args *args)
        bt_value_put_ref(args->extra_params);
 }
 
+/* Destroy a dynamically-allocated `struct implicit_component_args`. */
+
+static
+void destroy_implicit_component_args(struct implicit_component_args *args)
+{
+       finalize_implicit_component_args(args);
+       g_free(args);
+}
+
+/* Initialize the fields of an already allocated `struct implicit_component_args`. */
+
 static
 int init_implicit_component_args(struct implicit_component_args *args,
                const char *comp_arg, bool exists)
@@ -3204,7 +2695,7 @@ int init_implicit_component_args(struct implicit_component_args *args,
                        !args->params_arg || !args->extra_params) {
                ret = -1;
                finalize_implicit_component_args(args);
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
@@ -3212,6 +2703,31 @@ end:
        return ret;
 }
 
+/* Dynamically allocate and initialize a `struct implicit_component_args`. */
+
+static
+struct implicit_component_args *create_implicit_component_args(
+               const char *comp_arg)
+{
+       struct implicit_component_args *args;
+       int status;
+
+       args = g_new(struct implicit_component_args, 1);
+       if (!args) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               goto end;
+       }
+
+       status = init_implicit_component_args(args, comp_arg, true);
+       if (status != 0) {
+               g_free(args);
+               args = NULL;
+       }
+
+end:
+       return args;
+}
+
 static
 void append_implicit_component_param(struct implicit_component_args *args,
        const char *key, const char *value)
@@ -3222,6 +2738,33 @@ void append_implicit_component_param(struct implicit_component_args *args,
        append_param_arg(args->params_arg, key, value);
 }
 
+/*
+ * Append the given parameter (`key=value`) to all component specifications
+ * in `implicit_comp_args` (an array of `struct implicit_component_args *`)
+ * which match `comp_arg`.
+ *
+ * Return the number of matching components.
+ */
+
+static
+int append_multiple_implicit_components_param(GPtrArray *implicit_comp_args,
+               const char *comp_arg, const char *key, const char *value)
+{
+       int i;
+       int n = 0;
+
+       for (i = 0; i < implicit_comp_args->len; i++) {
+               struct implicit_component_args *args = implicit_comp_args->pdata[i];
+
+               if (strcmp(args->comp_arg->str, comp_arg) == 0) {
+                       append_implicit_component_param(args, key, value);
+                       n++;
+               }
+       }
+
+       return n;
+}
+
 /* Escape value to make it suitable to use as a string parameter value. */
 static
 gchar *escape_string_value(const char *value)
@@ -3231,7 +2774,7 @@ gchar *escape_string_value(const char *value)
 
        ret = g_string_new(NULL);
        if (!ret) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
@@ -3321,7 +2864,7 @@ gchar *bt_value_to_cli_param_value(bt_value *value)
 
        buf = g_string_new(NULL);
        if (!buf) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -3356,7 +2899,7 @@ int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
        GString *parameter = NULL;
 
        if (bt_value_array_append_string_element(args, "--params")) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3369,7 +2912,7 @@ int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
 
        parameter = g_string_new(NULL);
        if (!parameter) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3377,7 +2920,7 @@ int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
        g_string_printf(parameter, "%s=%s", key, str_value);
 
        if (bt_value_array_append_string_element(args, parameter->str)) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3405,7 +2948,7 @@ int append_string_parameter_to_args(bt_value *args, const char *key, const char
        str_value = bt_value_string_create_init(value);
 
        if (!str_value) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3454,7 +2997,7 @@ int convert_append_name_param(enum bt_config_component_dest dest,
                         */
                        if (bt_value_map_has_entry(all_names,
                                                   cur_name->str)) {
-                               printf_err("Duplicate component instance name:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Duplicate component instance name:\n    %s",
                                        cur_name->str);
                                goto error;
                        }
@@ -3463,7 +3006,7 @@ int convert_append_name_param(enum bt_config_component_dest dest,
                }
 
                if (!name) {
-                       print_err_oom();
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
 
@@ -3472,7 +3015,7 @@ int convert_append_name_param(enum bt_config_component_dest dest,
                 * all component names.
                 */
                if (bt_value_map_insert_entry(all_names, name->str, bt_value_null)) {
-                       print_err_oom();
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
 
@@ -3481,12 +3024,12 @@ int convert_append_name_param(enum bt_config_component_dest dest,
                 */
                if (append_name_opt) {
                        if (bt_value_array_append_string_element(run_args, "--name")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, name->str)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                }
@@ -3531,7 +3074,7 @@ GString *escape_dot_colon(const char *input)
        const char *ch;
 
        if (!output) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
@@ -3562,14 +3105,14 @@ int append_connect_arg(bt_value *run_args,
        GString *arg = g_string_new(NULL);
 
        if (!e_upstream_name || !e_downstream_name || !arg) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
 
        ret = bt_value_array_append_string_element(run_args, "--connect");
        if (ret) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3579,7 +3122,7 @@ int append_connect_arg(bt_value *run_args,
        g_string_append(arg, e_downstream_name->str);
        ret = bt_value_array_append_string_element(run_args, arg->str);
        if (ret) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                ret = -1;
                goto end;
        }
@@ -3727,7 +3270,7 @@ int g_list_prepend_gstring(GList **list, const char *string)
        BT_ASSERT(list);
 
        if (!gs) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
@@ -3737,6 +3280,55 @@ end:
        return ret;
 }
 
+/*
+ * Create `struct implicit_component_args` structures for each of the source
+ * components we identified.  Add them to `component_args`.
+ */
+
+static
+void create_implicit_component_args_from_auto_discovered_sources(
+               const struct auto_source_discovery *auto_disc, GPtrArray *component_args)
+{
+       gchar *cc_name = NULL;
+       struct implicit_component_args *comp = NULL;
+       int status;
+       guint i, len;
+
+       len = auto_disc->results->len;
+
+       for (i = 0; i < len; i++) {
+               struct auto_source_discovery_result *res =
+                       g_ptr_array_index(auto_disc->results, i);
+
+               g_free(cc_name);
+               cc_name = g_strdup_printf("source.%s.%s", res->plugin_name, res->source_cc_name);
+               if (!cc_name) {
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
+                       goto end;
+               }
+
+               comp = create_implicit_component_args(cc_name);
+               if (!comp) {
+                       goto end;
+               }
+
+               status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs);
+               if (status != 0) {
+                       goto end;
+               }
+
+               g_ptr_array_add(component_args, comp);
+               comp = NULL;
+       }
+
+end:
+       g_free(cc_name);
+
+       if (comp) {
+               destroy_implicit_component_args(comp);
+       }
+}
+
 /*
  * Creates a Babeltrace config object from the arguments of a convert
  * command.
@@ -3772,7 +3364,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
        GList *filter_names = NULL;
        GList *sink_names = NULL;
        bt_value *leftovers = NULL;
-       struct implicit_component_args implicit_ctf_input_args = { 0 };
        struct implicit_component_args implicit_ctf_output_args = { 0 };
        struct implicit_component_args implicit_lttng_live_args = { 0 };
        struct implicit_component_args implicit_dummy_args = { 0 };
@@ -3785,6 +3376,24 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
        size_t i;
        struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
        char *output = NULL;
+       struct auto_source_discovery auto_disc = { NULL };
+       GString *auto_disc_comp_name = NULL;
+
+       /*
+        * Array of `struct implicit_component_args *` created for the sources
+        * we have auto-discovered.
+        */
+       GPtrArray *discovered_source_args = NULL;
+
+       /*
+        * If set, restrict automatic source discovery to this component class
+        * of this plugin.
+        */
+       const char *auto_source_discovery_restrict_plugin_name = NULL;
+       const char *auto_source_discovery_restrict_component_class_name = NULL;
+
+       gchar *ctf_fs_source_clock_class_offset_arg = NULL;
+       gchar *ctf_fs_source_clock_class_offset_ns_arg = NULL;
 
        (void) bt_value_copy(initial_plugin_paths, &plugin_paths);
 
@@ -3796,11 +3405,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                goto end;
        }
 
-       if (init_implicit_component_args(&implicit_ctf_input_args,
-                       "source.ctf.fs", false)) {
-               goto error;
-       }
-
        if (init_implicit_component_args(&implicit_ctf_output_args,
                        "sink.ctf.fs", false)) {
                goto error;
@@ -3838,25 +3442,25 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
        all_names = bt_value_map_create();
        if (!all_names) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        run_args = bt_value_array_create();
        if (!run_args) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cur_name = g_string_new(NULL);
        if (!cur_name) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
        cur_name_prefix = g_string_new(NULL);
        if (!cur_name_prefix) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -3867,7 +3471,24 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
        leftovers = bt_value_array_create();
        if (!leftovers) {
-               print_err_oom();
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               goto error;
+       }
+
+       if (auto_source_discovery_init(&auto_disc) != 0) {
+               goto error;
+       }
+
+       discovered_source_args =
+               g_ptr_array_new_with_free_func((GDestroyNotify) destroy_implicit_component_args);
+       if (!discovered_source_args) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               goto error;
+       }
+
+       auto_disc_comp_name = g_string_new(NULL);
+       if (!auto_disc_comp_name) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
@@ -3886,7 +3507,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
        pc = poptGetContext(NULL, argc, (const char **) argv,
                convert_long_options, 0);
        if (!pc) {
-               printf_err("Cannot get popt context\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context.");
                goto error;
        }
 
@@ -3917,7 +3538,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        plugin_comp_cls_names(arg, &name, &plugin_name,
                                &comp_cls_name, &type);
                        if (!plugin_name || !comp_cls_name) {
-                               printf_err("Invalid format for --component option's argument:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE(
+                                       "Invalid format for --component option's argument:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -3947,12 +3569,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
                        if (bt_value_array_append_string_element(run_args,
                                        "--component")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
@@ -3969,25 +3591,25 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                }
                case OPT_PARAMS:
                        if (cur_name_prefix->len == 0) {
-                               printf_err("No current component of which to set parameters:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("No current component of which to set parameters:\n    %s",
                                        arg);
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args,
                                        "--params")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
                case OPT_PATH:
                        if (cur_name_prefix->len == 0) {
-                               printf_err("No current component of which to set `path` parameter:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("No current component of which to set `path` parameter:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -3998,7 +3620,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        break;
                case OPT_URL:
                        if (cur_name_prefix->len == 0) {
-                               printf_err("No current component of which to set `url` parameter:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("No current component of which to set `url` parameter:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -4010,18 +3632,18 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        break;
                case OPT_NAME:
                        if (cur_name_prefix->len == 0) {
-                               printf_err("No current component to name:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("No current component to name:\n    %s",
                                        arg);
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, "--name")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
@@ -4029,18 +3651,18 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        break;
                case OPT_LOG_LEVEL:
                        if (cur_name_prefix->len == 0) {
-                               printf_err("No current component to assign a log level to:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("No current component to assign a log level to:\n    %s",
                                        arg);
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, "--log-level")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
@@ -4050,19 +3672,19 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
                        if (bt_value_array_append_string_element(run_args,
                                        "--omit-home-plugin-path")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
                case OPT_RETRY_DURATION:
                        if (bt_value_array_append_string_element(run_args,
                                        "--retry-duration")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
@@ -4071,7 +3693,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
                        if (bt_value_array_append_string_element(run_args,
                                        "--omit-system-plugin-path")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
@@ -4083,12 +3705,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
                        if (bt_value_array_append_string_element(run_args,
                                        "--plugin-path")) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
 
                        if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
@@ -4126,7 +3748,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        /* Ignore in this pass */
                        break;
                default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
+                       BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
                                opt);
                        goto error;
                }
@@ -4145,7 +3767,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
        /* Check for option parsing error */
        if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option `%s`: %s.",
                        poptBadOption(pc, 0), poptStrerror(opt));
                goto error;
        }
@@ -4162,7 +3784,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
        pc = poptGetContext(NULL, argc, (const char **) argv,
                convert_long_options, 0);
        if (!pc) {
-               printf_err("Cannot get popt context\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context.");
                goto error;
        }
 
@@ -4215,7 +3837,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
                        ret = split_timerange(arg, &begin, &end);
                        if (ret) {
-                               printf_err("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n    %s",
                                        arg);
                                goto error;
                        }
@@ -4255,16 +3877,28 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        implicit_text_args.exists = true;
                        break;
                case OPT_CLOCK_OFFSET:
-                       implicit_ctf_input_args.exists = true;
-                       append_implicit_component_param(
-                                       &implicit_ctf_input_args,
-                                       "clock-class-offset-s", arg);
+                       if (ctf_fs_source_clock_class_offset_arg) {
+                               BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset option\n");
+                               goto error;
+                       }
+
+                       ctf_fs_source_clock_class_offset_arg = g_strdup(arg);
+                       if (!ctf_fs_source_clock_class_offset_arg) {
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+                               goto error;
+                       }
                        break;
                case OPT_CLOCK_OFFSET_NS:
-                       implicit_ctf_input_args.exists = true;
-                       append_implicit_component_param(
-                                       &implicit_ctf_input_args,
-                                       "clock-class-offset-ns", arg);
+                       if (ctf_fs_source_clock_class_offset_ns_arg) {
+                               BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset-ns option\n");
+                               goto error;
+                       }
+
+                       ctf_fs_source_clock_class_offset_ns_arg = g_strdup(arg);
+                       if (!ctf_fs_source_clock_class_offset_ns_arg) {
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+                               goto error;
+                       }
                        break;
                case OPT_CLOCK_SECONDS:
                        append_implicit_component_param(
@@ -4347,25 +3981,28 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        break;
                case OPT_INPUT_FORMAT:
                        if (got_input_format_opt) {
-                               printf_err("Duplicate --input-format option\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Duplicate --input-format option.");
                                goto error;
                        }
 
                        got_input_format_opt = true;
 
                        if (strcmp(arg, "ctf") == 0) {
-                               implicit_ctf_input_args.exists = true;
+                               auto_source_discovery_restrict_plugin_name = "ctf";
+                               auto_source_discovery_restrict_component_class_name = "fs";
                        } else if (strcmp(arg, "lttng-live") == 0) {
+                               auto_source_discovery_restrict_plugin_name = "ctf";
+                               auto_source_discovery_restrict_component_class_name = "lttng-live";
                                implicit_lttng_live_args.exists = true;
                        } else {
-                               printf_err("Unknown legacy input format:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy input format:\n    %s",
                                        arg);
                                goto error;
                        }
                        break;
                case OPT_OUTPUT_FORMAT:
                        if (got_output_format_opt) {
-                               printf_err("Duplicate --output-format option\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output-format option.");
                                goto error;
                        }
 
@@ -4380,26 +4017,26 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        } else if (strcmp(arg, "ctf-metadata") == 0) {
                                print_ctf_metadata = true;
                        } else {
-                               printf_err("Unknown legacy output format:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy output format:\n    %s",
                                        arg);
                                goto error;
                        }
                        break;
                case OPT_OUTPUT:
                        if (output) {
-                               printf_err("Duplicate --output option\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output option");
                                goto error;
                        }
 
                        output = strdup(arg);
                        if (!output) {
-                               print_err_oom();
+                               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
                        break;
                case OPT_RUN_ARGS:
                        if (print_run_args_0) {
-                               printf_err("Cannot specify --run-args and --run-args-0\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
                                goto error;
                        }
 
@@ -4407,7 +4044,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        break;
                case OPT_RUN_ARGS_0:
                        if (print_run_args) {
-                               printf_err("Cannot specify --run-args and --run-args-0\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
                                goto error;
                        }
 
@@ -4439,7 +4076,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
        /* Check for option parsing error */
        if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
+               BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: %s",
                        poptBadOption(pc, 0), poptStrerror(opt));
                goto error;
        }
@@ -4467,9 +4104,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
        /* Consume and keep leftover arguments */
        while ((leftover = poptGetArg(pc))) {
-               bt_value_status status = bt_value_array_append_string_element(leftovers, leftover);
-               if (status != BT_VALUE_STATUS_OK) {
-                       print_err_oom();
+               if (bt_value_array_append_string_element(leftovers, leftover) !=
+                               BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
                        goto error;
                }
        }
@@ -4479,12 +4116,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                const bt_value *bt_val_leftover;
 
                if (bt_value_array_is_empty(leftovers)) {
-                       printf_err("--output-format=ctf-metadata specified without a path\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf-metadata specified without a path.");
                        goto error;
                }
 
                if (bt_value_array_get_size(leftovers) > 1) {
-                       printf_err("Too many paths specified for --output-format=ctf-metadata\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("Too many paths specified for --output-format=ctf-metadata.");
                        goto error;
                }
 
@@ -4514,7 +4151,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
         */
        if (implicit_ctf_output_args.exists) {
                if (!output) {
-                       printf_err("--output-format=ctf specified without --output (trace output path)\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf specified without --output (trace output path).");
                        goto error;
                }
 
@@ -4531,7 +4168,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                 * sink.ctf.fs implicit components.
                 */
                if (implicit_text_args.exists) {
-                       printf_err("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text.");
                        goto error;
                }
        }
@@ -4566,7 +4203,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        const bt_value *bt_val_leftover;
 
                        if (bt_value_array_get_size(leftovers) > 1) {
-                               printf_err("Too many URLs specified for --output-format=lttng-live\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Too many URLs specified for --input-format=lttng-live.");
                                goto error;
                        }
 
@@ -4575,7 +4212,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_leftover),
                                        error_buf, sizeof(error_buf));
                        if (!lttng_live_url_parts.proto) {
-                               printf_err("Invalid LTTng live URL format: %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid LTTng live URL format: %s.",
                                        error_buf);
                                goto error;
                        }
@@ -4614,53 +4251,82 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                goto error;
                        }
                } else {
-                       /*
-                        * Create one source.ctf.fs component, pass it an array
-                        * with the leftovers.
-                        * Note that it still has to be named later.
-                        */
-                       implicit_ctf_input_args.exists = true;
-                       ret = append_parameter_to_args(implicit_ctf_input_args.extra_params,
-                                       "paths", leftovers);
-                       if (ret) {
+                       int status;
+
+                       status = auto_discover_source_components(plugin_paths, leftovers,
+                               auto_source_discovery_restrict_plugin_name,
+                               auto_source_discovery_restrict_component_class_name,
+                               *default_log_level >= 0 ? *default_log_level : cli_default_log_level,
+                               &auto_disc);
+
+                       if (status != 0) {
                                goto error;
                        }
+
+                       create_implicit_component_args_from_auto_discovered_sources(
+                               &auto_disc, discovered_source_args);
                }
        }
 
-       /*
-        * Ensure mutual exclusion between implicit `source.ctf.fs` and
-        * `source.ctf.lttng-live` components.
-        */
-       if (implicit_ctf_input_args.exists && implicit_lttng_live_args.exists) {
-               printf_err("Cannot create both implicit `%s` and `%s` components\n",
-                       implicit_ctf_input_args.comp_arg->str,
-                       implicit_lttng_live_args.comp_arg->str);
-               goto error;
+       /* If --clock-offset was given, apply it to any src.ctf.fs component. */
+       if (ctf_fs_source_clock_class_offset_arg) {
+               int n;
+
+               n = append_multiple_implicit_components_param(
+                       discovered_source_args, "source.ctf.fs", "clock-class-offset-s",
+                       ctf_fs_source_clock_class_offset_arg);
+
+               if (n == 0) {
+                       BT_CLI_LOGE_APPEND_CAUSE("--clock-offset specified, but no source.ctf.fs component instantiated.");
+                       goto error;
+               }
        }
 
-       /*
-        * If the implicit `source.ctf.fs` or `source.ctf.lttng-live`
-        * components exists, make sure there's at least one leftover
-        * (which is the path or URL).
-        */
-       if (implicit_ctf_input_args.exists && bt_value_array_is_empty(leftovers)) {
-               printf_err("Missing path for implicit `%s` component\n",
-                       implicit_ctf_input_args.comp_arg->str);
-               goto error;
+       /* If --clock-offset-ns was given, apply it to any src.ctf.fs component. */
+       if (ctf_fs_source_clock_class_offset_ns_arg) {
+               int n;
+
+               n = append_multiple_implicit_components_param(
+                       discovered_source_args, "source.ctf.fs", "clock-class-offset-ns",
+                       ctf_fs_source_clock_class_offset_ns_arg);
+
+               if (n == 0) {
+                       BT_CLI_LOGE_APPEND_CAUSE("--clock-offset-ns specified, but no source.ctf.fs component instantiated.");
+                       goto error;
+               }
        }
 
+       /*
+        * If the implicit `source.ctf.lttng-live` component exists, make sure
+        * there's at least one leftover (which is the URL).
+        */
        if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) {
-               printf_err("Missing URL for implicit `%s` component\n",
+               BT_CLI_LOGE_APPEND_CAUSE("Missing URL for implicit `%s` component.",
                        implicit_lttng_live_args.comp_arg->str);
                goto error;
        }
 
        /* Assign names to implicit components */
-       ret = assign_name_to_implicit_component(&implicit_ctf_input_args,
-               "source-ctf-fs", all_names, &source_names, true);
-       if (ret) {
-               goto error;
+       for (i = 0; i < discovered_source_args->len; i++) {
+               struct implicit_component_args *args;
+               int j;
+
+               args = discovered_source_args->pdata[i];
+
+               g_string_printf(auto_disc_comp_name, "auto-disc-%s", args->comp_arg->str);
+
+               /* Give it a name like `auto-disc-src-ctf-fs`. */
+               for (j = 0; j < auto_disc_comp_name->len; j++) {
+                       if (auto_disc_comp_name->str[j] == '.') {
+                               auto_disc_comp_name->str[j] = '-';
+                       }
+               }
+
+               ret = assign_name_to_implicit_component(args,
+                       auto_disc_comp_name->str, all_names, &source_names, true);
+               if (ret) {
+                       goto error;
+               }
        }
 
        ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
@@ -4707,12 +4373,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
        /* Make sure there's at least one source and one sink */
        if (!source_names) {
-               printf_err("No source component\n");
+               BT_CLI_LOGE_APPEND_CAUSE("No source component.");
                goto error;
        }
 
        if (!sink_names) {
-               printf_err("No sink component\n");
+               BT_CLI_LOGE_APPEND_CAUSE("No sink component.");
                goto error;
        }
 
@@ -4746,9 +4412,14 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
         * Append the equivalent run arguments for the implicit
         * components.
         */
-       ret = append_run_args_for_implicit_component(&implicit_ctf_input_args, run_args);
-       if (ret) {
-               goto error;
+       for (i = 0; i < discovered_source_args->len; i++) {
+               struct implicit_component_args *args =
+                       discovered_source_args->pdata[i];
+
+               ret = append_run_args_for_implicit_component(args, run_args);
+               if (ret) {
+                       goto error;
+               }
        }
 
        ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
@@ -4797,7 +4468,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
        ret = convert_auto_connect(run_args, source_names, filter_names,
                        sink_names);
        if (ret) {
-               printf_err("Cannot auto-connect components\n");
+               BT_CLI_LOGE_APPEND_CAUSE("Cannot auto-connect components.");
                goto error;
        }
 
@@ -4808,7 +4479,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
         */
        if (print_run_args || print_run_args_0) {
                if (stream_intersection_mode) {
-                       printf_err("Cannot specify --stream-intersection with --run-args or --run-args-0\n");
+                       BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --stream-intersection with --run-args or --run-args-0.");
                        goto error;
                }
 
@@ -4907,7 +4578,6 @@ end:
        destroy_glist_of_gstring(filter_names);
        destroy_glist_of_gstring(sink_names);
        bt_value_put_ref(leftovers);
-       finalize_implicit_component_args(&implicit_ctf_input_args);
        finalize_implicit_component_args(&implicit_ctf_output_args);
        finalize_implicit_component_args(&implicit_lttng_live_args);
        finalize_implicit_component_args(&implicit_dummy_args);
@@ -4917,6 +4587,19 @@ end:
        finalize_implicit_component_args(&implicit_trimmer_args);
        bt_value_put_ref(plugin_paths);
        bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
+       auto_source_discovery_fini(&auto_disc);
+
+       if (discovered_source_args) {
+               g_ptr_array_free(discovered_source_args, TRUE);
+       }
+
+       g_free(ctf_fs_source_clock_class_offset_arg);
+       g_free(ctf_fs_source_clock_class_offset_ns_arg);
+
+       if (auto_disc_comp_name) {
+               g_string_free(auto_disc_comp_name, TRUE);
+       }
+
        return cfg;
 }
 
@@ -5011,7 +4694,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                } else if (strcmp(cur_arg, "--log-level") == 0 ||
                                strcmp(cur_arg, "-l") == 0) {
                        if (!next_arg) {
-                               printf_err("Missing log level value for --log-level option\n");
+                               BT_CLI_LOGE_APPEND_CAUSE("Missing log level value for --log-level option.");
                                *retcode = 1;
                                goto end;
                        }
@@ -5019,7 +4702,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                        default_log_level =
                                bt_log_get_level_from_string(next_arg);
                        if (default_log_level < 0) {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n    %s",
                                        next_arg);
                                *retcode = 1;
                                goto end;
@@ -5031,7 +4714,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
 
                        default_log_level = bt_log_get_level_from_string(arg);
                        if (default_log_level < 0) {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n    %s",
                                        arg);
                                *retcode = 1;
                                goto end;
@@ -5041,7 +4724,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
 
                        default_log_level = bt_log_get_level_from_string(arg);
                        if (default_log_level < 0) {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n    %s",
                                        arg);
                                *retcode = 1;
                                goto end;
This page took 0.061653 seconds and 4 git commands to generate.