X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fcli%2Fbabeltrace2-cfg-cli-args.c;h=a16fbfceaa4b6d2cff737bddd1eee9ba374c7b4d;hb=5084732e40a7925d22f741e4ed08f19d36078fbe;hp=e1470d7203cec0e00a001539b41fc42699215a01;hpb=578e048b5debf169e286e5b5cc747b5d6c16886d;p=babeltrace.git diff --git a/src/cli/babeltrace2-cfg-cli-args.c b/src/cli/babeltrace2-cfg-cli-args.c index e1470d72..a16fbfce 100644 --- a/src/cli/babeltrace2-cfg-cli-args.c +++ b/src/cli/babeltrace2-cfg-cli-args.c @@ -40,24 +40,12 @@ #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_WARNING; /* INI-style parsing FSM states */ enum ini_parsing_fsm_state { @@ -144,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, @@ -713,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; } @@ -733,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; } @@ -746,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; } @@ -756,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; } @@ -765,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; } @@ -878,13 +331,14 @@ end: static struct bt_config_component *bt_config_component_create( bt_component_class_type type, - const char *plugin_name, const char *comp_cls_name) + const char *plugin_name, const char *comp_cls_name, + int init_log_level) { struct bt_config_component *cfg_component = NULL; cfg_component = g_new0(struct bt_config_component, 1); if (!cfg_component) { - print_err_oom(); + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } @@ -893,26 +347,28 @@ 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; } + cfg_component->log_level = init_log_level; + /* 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; } @@ -930,7 +386,8 @@ end: * option's argument. */ static -struct bt_config_component *bt_config_component_from_arg(const char *arg) +struct bt_config_component *bt_config_component_from_arg(const char *arg, + int init_log_level) { struct bt_config_component *cfg_comp = NULL; char *name = NULL; @@ -943,7 +400,8 @@ struct bt_config_component *bt_config_component_from_arg(const char *arg) goto error; } - cfg_comp = bt_config_component_create(type, plugin_name, comp_cls_name); + cfg_comp = bt_config_component_create(type, plugin_name, comp_cls_name, + init_log_level); if (!cfg_comp) { goto error; } @@ -1048,7 +506,7 @@ void destroy_glist_of_gstring(GList *list) return; } - for (at = list; at != NULL; at = g_list_next(at)) { + for (at = list; at; at = g_list_next(at)) { g_string_free(at->data, TRUE); } @@ -1096,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; @@ -1117,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; } @@ -1136,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; } @@ -1188,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; } /* @@ -1228,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; } @@ -1247,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; } @@ -1327,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; } @@ -1347,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; } @@ -1358,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"); } @@ -1422,6 +880,7 @@ enum { OPT_HELP, OPT_INPUT_FORMAT, OPT_LIST, + OPT_LOG_LEVEL, OPT_NAME, OPT_NAMES, OPT_NO_DELTA, @@ -1484,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; @@ -1499,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; } @@ -1530,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; @@ -1546,8 +1005,8 @@ int append_home_and_system_plugin_paths(bt_value *plugin_paths, if (bt_common_is_setuid_setgid()) { BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary."); } else { - char *home_plugin_dir = - bt_common_get_home_plugin_path(); + char *home_plugin_dir = bt_common_get_home_plugin_path( + BT_LOG_OUTPUT_LEVEL); if (home_plugin_dir) { ret = bt_config_append_plugin_paths( @@ -1555,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; } } @@ -1565,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; } @@ -1592,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; } @@ -1609,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; } } @@ -1639,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; } @@ -1697,7 +1156,8 @@ end: static struct bt_config *bt_config_help_create( - const bt_value *initial_plugin_paths) + const bt_value *initial_plugin_paths, + int default_log_level) { struct bt_config *cfg; @@ -1709,7 +1169,7 @@ struct bt_config *bt_config_help_create( } cfg->cmd_data.help.cfg_component = - bt_config_component_create(-1, NULL, NULL); + bt_config_component_create(-1, NULL, NULL, default_log_level); if (!cfg->cmd_data.help.cfg_component) { goto error; } @@ -1738,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; } @@ -1766,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; } @@ -1800,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; } @@ -1832,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; @@ -1926,7 +1386,7 @@ static struct bt_config *bt_config_help_from_args(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, - const bt_value *initial_plugin_paths) + const bt_value *initial_plugin_paths, int default_log_level) { poptContext pc = NULL; char *arg = NULL; @@ -1937,7 +1397,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], char *plugin_name = NULL, *comp_cls_name = NULL; *retcode = 0; - cfg = bt_config_help_create(initial_plugin_paths); + cfg = bt_config_help_create(initial_plugin_paths, default_log_level); if (!cfg) { goto error; } @@ -1953,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; } @@ -1981,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; } @@ -1992,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; } @@ -2088,7 +1548,8 @@ static struct bt_config *bt_config_query_from_args(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, - const bt_value *initial_plugin_paths) + const bt_value *initial_plugin_paths, + int default_log_level) { poptContext pc = NULL; char *arg = NULL; @@ -2097,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); @@ -2107,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); @@ -2118,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; } @@ -2143,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; @@ -2157,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; } @@ -2168,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; } @@ -2180,9 +1648,10 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], leftover = poptGetArg(pc); if (leftover) { cfg->cmd_data.query.cfg_component = - bt_config_component_from_arg(leftover); + 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; } @@ -2200,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; } @@ -2214,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; } @@ -2233,6 +1702,10 @@ end: poptFreeContext(pc); } + if (error_str) { + g_string_free(error_str, TRUE); + } + bt_value_put_ref(params); free(arg); return cfg; @@ -2306,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; } @@ -2334,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; } @@ -2345,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; } @@ -2397,6 +1870,8 @@ void print_run_usage(FILE *fp) fprintf(fp, " specify the name with --name)\n"); fprintf(fp, " -x, --connect=CONNECTION Connect two created components (see the\n"); fprintf(fp, " expected format of CONNECTION below)\n"); + fprintf(fp, " -l, --log-level=LVL Set the log level of the current component to LVL\n"); + fprintf(fp, " (`N`, `V`, `D`, `I`, `W`, `E`, or `F`)\n"); fprintf(fp, " -n, --name=NAME Set the name of the current component\n"); fprintf(fp, " to NAME (must be unique amongst all the\n"); fprintf(fp, " names of the created components)\n"); @@ -2464,7 +1939,7 @@ static struct bt_config *bt_config_run_from_args(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, - const bt_value *initial_plugin_paths) + const bt_value *initial_plugin_paths, int default_log_level) { poptContext pc = NULL; char *arg = NULL; @@ -2478,12 +1953,14 @@ 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 }, { "connect", 'x', POPT_ARG_STRING, NULL, OPT_CONNECT, NULL, NULL }, { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL }, + { "log-level", 'l', POPT_ARG_STRING, NULL, OPT_LOG_LEVEL, NULL, NULL }, { "name", 'n', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL }, { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL }, { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL }, @@ -2496,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; @@ -2512,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; } @@ -2537,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; } @@ -2573,9 +2056,10 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], } } - cur_cfg_comp = bt_config_component_from_arg(arg); + 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; } @@ -2596,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; } @@ -2612,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, ¶ms_to_set); + extend_status = bt_value_map_extend( + cur_cfg_comp->params, params, ¶ms_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; } @@ -2638,21 +2121,35 @@ 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; } g_string_assign(cur_cfg_comp->instance_name, arg); break; + case OPT_LOG_LEVEL: + if (!cur_cfg_comp) { + BT_CLI_LOGE_APPEND_CAUSE("Cannot set the log level of unavailable component:\n %s", + arg); + goto error; + } + + cur_cfg_comp->log_level = + bt_log_get_level_from_string(arg); + if (cur_cfg_comp->log_level < 0) { + 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; } @@ -2663,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; } @@ -2690,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; } @@ -2701,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; } @@ -2723,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; } @@ -2740,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; } @@ -2755,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); @@ -2767,7 +2268,7 @@ static struct bt_config *bt_config_run_from_args_array(const bt_value *run_args, int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, - const bt_value *initial_plugin_paths) + const bt_value *initial_plugin_paths, int default_log_level) { struct bt_config *cfg = NULL; const char **argv; @@ -2776,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; } @@ -2784,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++) { @@ -2801,7 +2302,7 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args, cfg = bt_config_run_from_args(argc, argv, retcode, force_omit_system_plugin_path, force_omit_home_plugin_path, - initial_plugin_paths); + initial_plugin_paths, default_log_level); end: free(argv); @@ -2825,6 +2326,8 @@ void print_convert_usage(FILE *fp) fprintf(fp, " conversion graph, and optionally name it\n"); fprintf(fp, " NAME (you can also specify the name with\n"); fprintf(fp, " --name)\n"); + fprintf(fp, " -l, --log-level=LVL Set the log level of the current component to LVL\n"); + fprintf(fp, " (`N`, `V`, `D`, `I`, `W`, `E`, or `F`)\n"); fprintf(fp, " --name=NAME Set the name of the current component\n"); fprintf(fp, " to NAME (must be unique amongst all the\n"); fprintf(fp, " names of the created components)\n"); @@ -2837,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"); @@ -2965,6 +2469,7 @@ struct poptOption convert_long_options[] = { { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL }, { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL }, { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL }, + { "log-level", 'l', POPT_ARG_STRING, NULL, OPT_LOG_LEVEL, NULL, NULL }, { "name", '\0', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL }, { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL }, { "debug-info", '\0', POPT_ARG_NONE, NULL, OPT_DEBUG_INFO, NULL, NULL }, @@ -2994,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; } @@ -3014,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; }; @@ -3044,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; } @@ -3075,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; } } @@ -3122,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; } } @@ -3136,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) { @@ -3156,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) @@ -3172,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; } @@ -3180,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) @@ -3190,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) @@ -3199,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; } @@ -3289,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; } @@ -3324,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; } @@ -3337,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; } @@ -3345,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; } @@ -3373,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; } @@ -3422,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; } @@ -3431,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; } @@ -3440,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; } @@ -3449,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; } } @@ -3499,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; } @@ -3530,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; } @@ -3547,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; } @@ -3587,7 +3162,7 @@ int convert_auto_connect(bt_value *run_args, BT_ASSERT(sink_names); /* Connect all sources to the first filter */ - for (source_at = source_names; source_at != NULL; source_at = g_list_next(source_at)) { + for (source_at = source_names; source_at; source_at = g_list_next(source_at)) { GString *source_name = source_at->data; GString *filter_name = filter_at->data; @@ -3602,7 +3177,7 @@ int convert_auto_connect(bt_value *run_args, filter_at = g_list_next(filter_at); /* Connect remaining filters */ - for (; filter_at != NULL; filter_prev = filter_at, filter_at = g_list_next(filter_at)) { + for (; filter_at; filter_prev = filter_at, filter_at = g_list_next(filter_at)) { GString *filter_name = filter_at->data; GString *filter_prev_name = filter_prev->data; @@ -3614,7 +3189,7 @@ int convert_auto_connect(bt_value *run_args, } /* Connect last filter to all sinks */ - for (sink_at = sink_names; sink_at != NULL; sink_at = g_list_next(sink_at)) { + for (sink_at = sink_names; sink_at; sink_at = g_list_next(sink_at)) { GString *filter_name = filter_prev->data; GString *sink_name = sink_at->data; @@ -3695,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; } @@ -3705,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. @@ -3715,7 +3339,7 @@ static struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, - const bt_value *initial_plugin_paths, char *log_level) + const bt_value *initial_plugin_paths, int *default_log_level) { poptContext pc = NULL; char *arg = NULL; @@ -3740,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 }; @@ -3753,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); @@ -3764,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; @@ -3806,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; } @@ -3835,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; } @@ -3854,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; } @@ -3885,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; } @@ -3915,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; } @@ -3937,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; } @@ -3966,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; } @@ -3978,41 +3632,59 @@ 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; } g_string_assign(cur_name, arg); + break; + case OPT_LOG_LEVEL: + if (cur_name_prefix->len == 0) { + 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")) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + if (bt_value_array_append_string_element(run_args, arg)) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + break; case OPT_OMIT_HOME_PLUGIN_PATH: force_omit_home_plugin_path = true; 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; @@ -4021,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; @@ -4033,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; @@ -4076,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; } @@ -4095,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; } @@ -4112,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; } @@ -4165,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; } @@ -4205,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( @@ -4297,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; } @@ -4330,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; } @@ -4357,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; } @@ -4371,12 +4058,15 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], stream_intersection_mode = true; break; case OPT_VERBOSE: - if (*log_level != 'V' && *log_level != 'D') { - *log_level = 'I'; + if (*default_log_level != BT_LOG_TRACE && + *default_log_level != BT_LOG_DEBUG) { + *default_log_level = BT_LOG_INFO; } break; case OPT_DEBUG: - *log_level = 'V'; + *default_log_level = BT_LOG_TRACE; + break; + default: break; } @@ -4386,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; } @@ -4394,9 +4084,10 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], /* * Legacy behaviour: --verbose used to make the `text` output * format print more information. --verbose is now equivalent to - * the INFO log level, which is why we compare to 'I' here. + * the INFO log level, which is why we compare to `BT_LOG_INFO` + * here. */ - if (*log_level == 'I') { + if (*default_log_level == BT_LOG_INFO) { append_implicit_component_param(&implicit_text_args, "verbose", "yes"); } @@ -4413,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; } } @@ -4425,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; } @@ -4460,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; } @@ -4477,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; } } @@ -4512,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; } @@ -4521,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; } @@ -4560,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, @@ -4653,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; } @@ -4692,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, @@ -4743,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; } @@ -4754,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; } @@ -4800,10 +4525,18 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto end; } + /* + * If the log level is still unset at this point, set it to + * the program's default. + */ + if (*default_log_level < 0) { + *default_log_level = cli_default_log_level; + } + cfg = bt_config_run_from_args_array(run_args, retcode, - force_omit_system_plugin_path, - force_omit_home_plugin_path, - initial_plugin_paths); + force_omit_system_plugin_path, + force_omit_home_plugin_path, + initial_plugin_paths, *default_log_level); if (!cfg) { goto error; } @@ -4816,6 +4549,14 @@ error: BT_OBJECT_PUT_REF_AND_RESET(cfg); end: + /* + * If the log level is still unset at this point, set it to + * the program's default. + */ + if (*default_log_level < 0) { + *default_log_level = cli_default_log_level; + } + if (pc) { poptFreeContext(pc); } @@ -4837,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); @@ -4847,6 +4587,19 @@ end: finalize_implicit_component_args(&implicit_trimmer_args); bt_value_put_ref(plugin_paths); bt_common_destroy_lttng_live_url_parts(<tng_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; } @@ -4862,7 +4615,7 @@ void print_gen_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=V)\n"); fprintf(fp, " -h, --help Show this help and quit\n"); - fprintf(fp, " -l, --log-level=LVL Set all log levels to LVL (`N`, `V`, `D`,\n"); + fprintf(fp, " -l, --log-level=LVL Set the default log level to LVL (`N`, `V`, `D`,\n"); fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n"); fprintf(fp, " -v, --verbose Enable verbose mode (same as --log-level=I)\n"); fprintf(fp, " -V, --version Show version and quit\n"); @@ -4878,38 +4631,6 @@ void print_gen_usage(FILE *fp) fprintf(fp, "Use `babeltrace2 COMMAND --help` to show the help of COMMAND.\n"); } -static -char log_level_from_arg(const char *arg) -{ - char level = 'U'; - - if (strcmp(arg, "VERBOSE") == 0 || - strcmp(arg, "V") == 0) { - level = 'V'; - } else if (strcmp(arg, "DEBUG") == 0 || - strcmp(arg, "D") == 0) { - level = 'D'; - } else if (strcmp(arg, "INFO") == 0 || - strcmp(arg, "I") == 0) { - level = 'I'; - } else if (strcmp(arg, "WARN") == 0 || - strcmp(arg, "WARNING") == 0 || - strcmp(arg, "W") == 0) { - level = 'W'; - } else if (strcmp(arg, "ERROR") == 0 || - strcmp(arg, "E") == 0) { - level = 'E'; - } else if (strcmp(arg, "FATAL") == 0 || - strcmp(arg, "F") == 0) { - level = 'F'; - } else if (strcmp(arg, "NONE") == 0 || - strcmp(arg, "N") == 0) { - level = 'N'; - } - - return level; -} - struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, @@ -4920,7 +4641,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], const char **command_argv = NULL; int command_argc = -1; const char *command_name = NULL; - char log_level = 'U'; + int default_log_level = -1; enum command_type { COMMAND_TYPE_NONE = -1, @@ -4956,30 +4677,32 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], if (strcmp(cur_arg, "-d") == 0 || strcmp(cur_arg, "--debug") == 0) { - log_level = 'V'; + default_log_level = BT_LOG_TRACE; } else if (strcmp(cur_arg, "-v") == 0 || strcmp(cur_arg, "--verbose") == 0) { - if (log_level != 'V' && log_level != 'D') { + if (default_log_level != BT_LOG_TRACE && + default_log_level != BT_LOG_DEBUG) { /* * Legacy: do not override a previous * --debug because --verbose and --debug * can be specified together (in this * case we want the lowest log level to - * apply, VERBOSE). + * apply, TRACE). */ - log_level = 'I'; + default_log_level = BT_LOG_INFO; } } 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; } - log_level = log_level_from_arg(next_arg); - if (log_level == 'U') { - printf_err("Invalid argument for --log-level option:\n %s\n", + default_log_level = + bt_log_get_level_from_string(next_arg); + if (default_log_level < 0) { + BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n %s", next_arg); *retcode = 1; goto end; @@ -4989,9 +4712,9 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], } else if (strncmp(cur_arg, "--log-level=", 12) == 0) { const char *arg = &cur_arg[12]; - log_level = log_level_from_arg(arg); - if (log_level == 'U') { - printf_err("Invalid argument for --log-level option:\n %s\n", + default_log_level = bt_log_get_level_from_string(arg); + if (default_log_level < 0) { + BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n %s", arg); *retcode = 1; goto end; @@ -4999,9 +4722,9 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], } else if (strncmp(cur_arg, "-l", 2) == 0) { const char *arg = &cur_arg[2]; - log_level = log_level_from_arg(arg); - if (log_level == 'U') { - printf_err("Invalid argument for --log-level option:\n %s\n", + default_log_level = bt_log_get_level_from_string(arg); + if (default_log_level < 0) { + BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n %s", arg); *retcode = 1; goto end; @@ -5061,17 +4784,28 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], BT_ASSERT(command_argv); BT_ASSERT(command_argc >= 0); + /* + * The convert command can set its own default log level for + * backward compatibility reasons. It only does so if there's no + * log level yet, so do not force one for this command. + */ + if (command_type != COMMAND_TYPE_CONVERT && default_log_level < 0) { + /* Default log level */ + default_log_level = cli_default_log_level; + } + switch (command_type) { case COMMAND_TYPE_RUN: config = bt_config_run_from_args(command_argc, command_argv, retcode, force_omit_system_plugin_path, - force_omit_home_plugin_path, initial_plugin_paths); + force_omit_home_plugin_path, initial_plugin_paths, + default_log_level); break; case COMMAND_TYPE_CONVERT: config = bt_config_convert_from_args(command_argc, command_argv, retcode, force_omit_system_plugin_path, force_omit_home_plugin_path, - initial_plugin_paths, &log_level); + initial_plugin_paths, &default_log_level); break; case COMMAND_TYPE_LIST_PLUGINS: config = bt_config_list_plugins_from_args(command_argc, @@ -5081,23 +4815,22 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], case COMMAND_TYPE_HELP: config = bt_config_help_from_args(command_argc, command_argv, retcode, force_omit_system_plugin_path, - force_omit_home_plugin_path, initial_plugin_paths); + force_omit_home_plugin_path, initial_plugin_paths, + default_log_level); break; case COMMAND_TYPE_QUERY: config = bt_config_query_from_args(command_argc, command_argv, retcode, force_omit_system_plugin_path, - force_omit_home_plugin_path, initial_plugin_paths); + force_omit_home_plugin_path, initial_plugin_paths, + default_log_level); break; default: abort(); } if (config) { - if (log_level == 'U') { - log_level = 'W'; - } - - config->log_level = log_level; + BT_ASSERT(default_log_level >= BT_LOG_TRACE); + config->log_level = default_log_level; config->command_name = command_name; }