X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fcli%2Fbabeltrace2-cfg-cli-args.c;h=86bf918e7a1e5218020c1cef158720f651327fea;hb=a93e984c07724c096b4a0af678703d796e26bf0c;hp=36b781d3564cb18b830ab61aab2a3563a526683d;hpb=8b4cd08a4cc2e13235c20689d74790ed3ccc6a51;p=babeltrace.git diff --git a/src/cli/babeltrace2-cfg-cli-args.c b/src/cli/babeltrace2-cfg-cli-args.c index 36b781d3..86bf918e 100644 --- a/src/cli/babeltrace2-cfg-cli-args.c +++ b/src/cli/babeltrace2-cfg-cli-args.c @@ -1,25 +1,9 @@ /* - * Babeltrace trace converter - parameter parsing + * SPDX-License-Identifier: MIT * * Copyright 2016 Philippe Proulx * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Babeltrace trace converter - parameter parsing */ #define BT_LOG_TAG "CLI/CFG-CLI-ARGS" @@ -40,99 +24,15 @@ #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 "param-parse/param-parse.h" +#include "babeltrace2-log-level.h" #include "babeltrace2-plugins.h" -#include "babeltrace2-cfg-src-auto-disc.h" +#include "babeltrace2-query.h" +#include "autodisc/autodisc.h" #include "common/version.h" -static const int cli_default_log_level = BT_LOG_WARNING; - -/* INI-style parsing FSM states */ -enum ini_parsing_fsm_state { - /* Expect a map key (identifier) */ - INI_EXPECT_MAP_KEY, - - /* Expect an equal character ('=') */ - INI_EXPECT_EQUAL, - - /* Expect a value */ - INI_EXPECT_VALUE, - - /* Expect a comma character (',') */ - INI_EXPECT_COMMA, -}; - -/* INI-style parsing state variables */ -struct ini_parsing_state { - /* Lexical scanner (owned by this) */ - GScanner *scanner; - - /* Output map value object being filled (owned by this) */ - bt_value *params; - - /* Next expected FSM state */ - enum ini_parsing_fsm_state expecting; - - /* Last decoded map key (owned by this) */ - char *last_map_key; - - /* Complete INI-style string to parse (not owned by this) */ - const char *arg; - - /* Error buffer (not owned by this) */ - GString *ini_error; -}; - -/* Offset option with "is set" boolean */ -struct offset_opt { - int64_t value; - bool is_set; -}; - -/* Legacy "ctf"/"lttng-live" format options */ -struct ctf_legacy_opts { - struct offset_opt offset_s; - struct offset_opt offset_ns; - bool stream_intersection; -}; - -/* Legacy "text" format options */ -struct text_legacy_opts { - /* - * output, dbg_info_dir, dbg_info_target_prefix, names, - * and fields are owned by this. - */ - GString *output; - GString *dbg_info_dir; - GString *dbg_info_target_prefix; - const bt_value *names; - const bt_value *fields; - - /* Flags */ - bool no_delta; - bool clock_cycles; - bool clock_seconds; - bool clock_date; - bool clock_gmt; - bool dbg_info_full_path; - bool verbose; -}; - -/* Legacy input format format */ -enum legacy_input_format { - LEGACY_INPUT_FORMAT_NONE = 0, - LEGACY_INPUT_FORMAT_CTF, - LEGACY_INPUT_FORMAT_LTTNG_LIVE, -}; - -/* Legacy output format format */ -enum legacy_output_format { - LEGACY_OUTPUT_FORMAT_NONE = 0, - LEGACY_OUTPUT_FORMAT_TEXT, - LEGACY_OUTPUT_FORMAT_DUMMY, -}; - #define BT_CLI_LOGE_APPEND_CAUSE_OOM() BT_CLI_LOGE_APPEND_CAUSE("Out of memory.") +#define WHILE_PARSING_ARG_N_FMT "While parsing argument #%d (`%s`): " /* * Returns the plugin name, component class name, component class type, @@ -276,16 +176,96 @@ end: return; } +static +void print_and_indent(const char *str) +{ + const char *ch = &str[0]; + + for (; *ch != '\0'; ch++) { + if (*ch == '\n') { + if (ch[1] != '\0') { + printf("\n "); + } + } else { + printf("%c", *ch); + } + } + + printf("\n"); +} + /* * Prints the Babeltrace version. */ static void print_version(void) { - if (GIT_VERSION[0] == '\0') { - puts("Babeltrace " VERSION); - } else { - puts("Babeltrace " VERSION " - " GIT_VERSION); + bool has_extra_name = strlen(BT_VERSION_EXTRA_NAME) > 0; + bool has_extra_description = strlen(BT_VERSION_EXTRA_DESCRIPTION) > 0; + bool has_extra_patch_names = strlen(BT_VERSION_EXTRA_PATCHES) > 0; + bool has_extra = has_extra_name || has_extra_description || + has_extra_patch_names; + + printf("%sBabeltrace %s%s", + bt_common_color_bold(), + VERSION, + bt_common_color_reset()); + + if (strlen(BT_VERSION_NAME) > 0) { + printf(" \"%s%s%s%s\"", + bt_common_color_fg_bright_blue(), + bt_common_color_bold(), + BT_VERSION_NAME, + bt_common_color_reset()); + } + + if (strlen(BT_VERSION_GIT) > 0) { + printf(" [%s%s%s]", + bt_common_color_fg_yellow(), + BT_VERSION_GIT, + bt_common_color_reset()); + } + + printf("\n"); + + if (strlen(BT_VERSION_DESCRIPTION) > 0) { + unsigned int columns; + GString *descr; + + if (bt_common_get_term_size(&columns, NULL) < 0) { + /* Width not found: default to 80 */ + columns = 80; + } + + descr = bt_common_fold(BT_VERSION_DESCRIPTION, columns, 0); + BT_ASSERT(descr); + printf("\n%s\n", descr->str); + g_string_free(descr, TRUE); + } + + if (has_extra) { + printf("\n"); + + if (has_extra_name) { + printf("%sExtra name%s: %s\n", + bt_common_color_fg_cyan(), + bt_common_color_reset(), + BT_VERSION_EXTRA_NAME); + } + + if (has_extra_description) { + printf("%sExtra description%s:\n ", + bt_common_color_fg_cyan(), + bt_common_color_reset()); + print_and_indent(BT_VERSION_EXTRA_DESCRIPTION); + } + + if (has_extra_patch_names) { + printf("%sExtra patch names%s:\n ", + bt_common_color_fg_cyan(), + bt_common_color_reset()); + print_and_indent(BT_VERSION_EXTRA_PATCHES); + } } } @@ -488,7 +468,7 @@ void bt_config_destroy(bt_object *obj) } break; default: - abort(); + bt_common_abort(); } g_free(cfg); @@ -524,9 +504,9 @@ GScanner *create_csv_identifiers_scanner(void) { GScanner *scanner; GScannerConfig scanner_config = { - .cset_skip_characters = " \t\n", - .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_", - .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-", + .cset_skip_characters = (gchar *) " \t\n", + .cset_identifier_first = (gchar *) G_CSET_a_2_z G_CSET_A_2_Z "_", + .cset_identifier_nth = (gchar *) G_CSET_a_2_z G_CSET_A_2_Z ":_-", .case_sensitive = TRUE, .cpair_comment_single = NULL, .skip_comment_multi = TRUE, @@ -771,7 +751,7 @@ int insert_flat_params_from_array(GString *params_arg, const bt_value *names_array, const char *prefix) { int ret = 0; - int i; + uint64_t i; GString *tmpstr = NULL, *default_value = NULL; bool default_set = false, non_default_set = false; @@ -797,19 +777,13 @@ int insert_flat_params_from_array(GString *params_arg, goto end; } - for (i = 0; i < bt_value_array_get_size(names_array); i++) { + for (i = 0; i < bt_value_array_get_length(names_array); i++) { const bt_value *str_obj = bt_value_array_borrow_element_by_index_const(names_array, - i); + i); const char *suffix; bool is_default = false; - if (!str_obj) { - BT_CLI_LOGE_APPEND_CAUSE("Unexpected error."); - ret = -1; - goto end; - } - suffix = bt_value_string_get(str_obj); g_string_assign(tmpstr, prefix); @@ -928,7 +902,7 @@ void add_run_cfg_comp(struct bt_config *cfg, g_ptr_array_add(cfg->cmd_data.run.sinks, cfg_comp); break; default: - abort(); + bt_common_abort(); } } @@ -1032,17 +1006,9 @@ error: return -1; } -static -int append_home_and_system_plugin_paths_cfg(struct bt_config *cfg) -{ - return append_home_and_system_plugin_paths(cfg->plugin_paths, - cfg->omit_system_plugin_path, cfg->omit_home_plugin_path); -} - static struct bt_config *bt_config_base_create(enum bt_config_command command, - const bt_value *initial_plugin_paths, - bool needs_plugins) + const bt_value *plugin_paths, bool needs_plugins) { struct bt_config *cfg; @@ -1057,12 +1023,12 @@ struct bt_config *bt_config_base_create(enum bt_config_command command, cfg->command = command; cfg->command_needs_plugins = needs_plugins; - if (initial_plugin_paths) { - bt_value *initial_plugin_paths_copy; + if (plugin_paths) { + bt_value *plugin_paths_copy; - (void) bt_value_copy(initial_plugin_paths, - &initial_plugin_paths_copy); - cfg->plugin_paths = initial_plugin_paths_copy; + (void) bt_value_copy(plugin_paths, + &plugin_paths_copy); + cfg->plugin_paths = plugin_paths_copy; } else { cfg->plugin_paths = bt_value_array_create(); if (!cfg->plugin_paths) { @@ -1081,14 +1047,13 @@ end: } static -struct bt_config *bt_config_run_create( - const bt_value *initial_plugin_paths) +struct bt_config *bt_config_run_create(const bt_value *plugin_paths) { struct bt_config *cfg; /* Create config */ cfg = bt_config_base_create(BT_CONFIG_COMMAND_RUN, - initial_plugin_paths, true); + plugin_paths, true); if (!cfg) { goto error; } @@ -1131,37 +1096,21 @@ end: } static -struct bt_config *bt_config_list_plugins_create( - const bt_value *initial_plugin_paths) +struct bt_config *bt_config_list_plugins_create(const bt_value *plugin_paths) { - struct bt_config *cfg; - - /* Create config */ - cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS, - initial_plugin_paths, true); - if (!cfg) { - goto error; - } - - goto end; - -error: - BT_OBJECT_PUT_REF_AND_RESET(cfg); - -end: - return cfg; + return bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS, + plugin_paths, true); } static -struct bt_config *bt_config_help_create( - const bt_value *initial_plugin_paths, +struct bt_config *bt_config_help_create(const bt_value *plugin_paths, int default_log_level) { struct bt_config *cfg; /* Create config */ cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP, - initial_plugin_paths, true); + plugin_paths, true); if (!cfg) { goto error; } @@ -1182,14 +1131,13 @@ end: } static -struct bt_config *bt_config_query_create( - const bt_value *initial_plugin_paths) +struct bt_config *bt_config_query_create(const bt_value *plugin_paths) { struct bt_config *cfg; /* Create config */ cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY, - initial_plugin_paths, true); + plugin_paths, true); if (!cfg) { goto error; } @@ -1211,13 +1159,13 @@ end: static struct bt_config *bt_config_print_ctf_metadata_create( - const bt_value *initial_plugin_paths) + const bt_value *plugin_paths) { struct bt_config *cfg; /* Create config */ cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_CTF_METADATA, - initial_plugin_paths, true); + plugin_paths, true); if (!cfg) { goto error; } @@ -1245,13 +1193,13 @@ end: static struct bt_config *bt_config_print_lttng_live_sessions_create( - const bt_value *initial_plugin_paths) + const bt_value *plugin_paths) { struct bt_config *cfg; /* Create config */ cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS, - initial_plugin_paths, true); + plugin_paths, true); if (!cfg) { goto error; } @@ -1326,6 +1274,8 @@ void print_expected_params_format(FILE *fp) fprintf(fp, "* Double-quoted string (accepts escape characters).\n"); fprintf(fp, "* Array, formatted as an opening `[`, a list of comma-separated values\n"); fprintf(fp, " (as described by the current list) and a closing `]`.\n"); + fprintf(fp, "* Map, formatted as an opening `{`, a comma-separated list of PARAM=VALUE\n"); + fprintf(fp, " assignments and a closing `}`.\n"); fprintf(fp, "\n"); fprintf(fp, "You can put whitespaces allowed around individual `=` and `,` symbols.\n"); fprintf(fp, "\n"); @@ -1340,32 +1290,153 @@ void print_expected_params_format(FILE *fp) fprintf(fp, "babeltrace2 from a shell.\n"); } +/* + * Given argpar error status `status` and error `error`, return a formatted + * error message describing the error. + * + * `argv` is the argument vector that was being parsed. + * + * `prefix_fmt` (formatted using the following arguments) is prepended to + * the error message. + * + * The returned string must be freed by the caller. + */ static -bool help_option_is_specified( - const struct bt_argpar_parse_ret *argpar_parse_ret) +GString *__BT_ATTR_FORMAT_PRINTF(3, 4) format_arg_error( + const struct argpar_error *error, + const char **argv, const char *prefix_fmt, ...) + { - int i; - bool specified = false; + GString *str = g_string_new(NULL); + va_list args; - for (i = 0; i < argpar_parse_ret->items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret->items, i); - struct bt_argpar_item_opt *argpar_item_opt; + va_start(args, prefix_fmt); + g_string_append_vprintf(str, prefix_fmt, args); + va_end(args); - if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) { - continue; + g_string_append(str, ": "); + + switch (argpar_error_type(error)) + { + case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG: + { + bool is_short; + const struct argpar_opt_descr *descr = + argpar_error_opt_descr(error, &is_short); + int orig_index = argpar_error_orig_index(error); + const char *arg = argv[orig_index]; + + if (is_short) { + g_string_append_printf( + str, + WHILE_PARSING_ARG_N_FMT "Missing required argument for option `-%c`", + orig_index + 1, arg, descr->short_name); + } else { + g_string_append_printf( + str, + WHILE_PARSING_ARG_N_FMT "Missing required argument for option `--%s`", + orig_index + 1, arg, descr->long_name); } - argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; - if (argpar_item_opt->descr->id == OPT_HELP) { - specified = true; - break; + break; + } + case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG: + { + bool is_short; + const struct argpar_opt_descr *descr = + argpar_error_opt_descr(error, &is_short); + int orig_index = argpar_error_orig_index(error); + const char *arg = argv[orig_index]; + + if (is_short) { + g_string_append_printf( + str, + WHILE_PARSING_ARG_N_FMT "Unexpected argument for option `-%c`", + orig_index + 1, arg, descr->short_name); + } else { + g_string_append_printf( + str, + WHILE_PARSING_ARG_N_FMT "Unexpected argument for option `--%s`", + orig_index + 1, arg, descr->long_name); } + + break; + } + case ARGPAR_ERROR_TYPE_UNKNOWN_OPT: + { + int orig_index = argpar_error_orig_index(error); + const char *unknown_opt = argpar_error_unknown_opt_name(error); + const char *arg = argv[orig_index]; + + g_string_append_printf( + str, + WHILE_PARSING_ARG_N_FMT "Unknown option `%s`", + orig_index + 1, arg, unknown_opt); + + break; + } + + default: + BT_ASSERT(0); + } + + return str; +} + +enum parse_next_item_status +{ + PARSE_NEXT_ITEM_STATUS_OK = 0, + PARSE_NEXT_ITEM_STATUS_END = 1, + PARSE_NEXT_ITEM_STATUS_ERROR = -1, +}; + +/* + * Parse the next item using `iter`. Log and append an error if necessary. + * + * The item in `*item` on entry is freed, and the new item is also + * returned in `*item`. + */ +static +enum parse_next_item_status parse_next_item(struct argpar_iter *iter, + const struct argpar_item **item, const char **argv, + const char *command) +{ + enum argpar_iter_next_status status; + const struct argpar_error *error = NULL; + enum parse_next_item_status ret; + + ARGPAR_ITEM_DESTROY_AND_RESET(*item); + status = argpar_iter_next(iter, item, &error); + + switch (status) { + case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY: + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + ret = PARSE_NEXT_ITEM_STATUS_ERROR; + break; + case ARGPAR_ITER_NEXT_STATUS_ERROR: + { + GString *err_str = format_arg_error(error, argv, + "While parsing `%s` command's command-line arguments", command); + BT_CLI_LOGE_APPEND_CAUSE("%s", err_str->str); + g_string_free(err_str, TRUE); + ret = PARSE_NEXT_ITEM_STATUS_ERROR; + break; + } + case ARGPAR_ITER_NEXT_STATUS_END: + ret = PARSE_NEXT_ITEM_STATUS_END; + break; + case ARGPAR_ITER_NEXT_STATUS_OK: + ret = PARSE_NEXT_ITEM_STATUS_OK; + break; + default: + bt_common_abort(); } - return specified; + argpar_error_destroy(error); + return ret; } + /* * Prints the help command usage. */ @@ -1377,12 +1448,7 @@ void print_help_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "Options:\n"); fprintf(fp, "\n"); - fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); - fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n"); - fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search 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, " -h, --help Show this help and quit\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n"); fprintf(fp, "\n"); @@ -1390,13 +1456,10 @@ void print_help_usage(FILE *fp) } static -const struct bt_argpar_opt_descr help_options[] = { +const struct argpar_opt_descr help_options[] = { /* id, short_name, long_name, with_arg */ { OPT_HELP, 'h', "help", false }, - { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false }, - { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false }, - { OPT_PLUGIN_PATH, '\0', "plugin-path", true }, - BT_ARGPAR_OPT_DESCR_SENTINEL + ARGPAR_OPT_DESCR_SENTINEL }; /* @@ -1407,116 +1470,103 @@ const struct bt_argpar_opt_descr help_options[] = { */ 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, int default_log_level) + int *retcode, const bt_value *plugin_paths, + int default_log_level) { - int ret, i; struct bt_config *cfg = NULL; - const char *leftover = NULL; + const char *plugin_comp_cls_arg = NULL; char *plugin_name = NULL, *comp_cls_name = NULL; - struct bt_argpar_parse_ret argpar_parse_ret; + GString *substring = NULL; + size_t end_pos; + struct argpar_iter *argpar_iter = NULL; + const struct argpar_item *argpar_item = NULL; *retcode = 0; - cfg = bt_config_help_create(initial_plugin_paths, default_log_level); + cfg = bt_config_help_create(plugin_paths, default_log_level); if (!cfg) { 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); - if (ret) { - goto error; - } - - /* Parse options */ - argpar_parse_ret = bt_argpar_parse(argc, argv, help_options, true); - if (argpar_parse_ret.error) { - BT_CLI_LOGE_APPEND_CAUSE( - "While parsing `help` command's command-line arguments: %s", - argpar_parse_ret.error->str); + argpar_iter = argpar_iter_create(argc, argv, help_options); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (help_option_is_specified(&argpar_parse_ret)) { - print_help_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; - } + while (true) { + enum parse_next_item_status status = + parse_next_item(argpar_iter, &argpar_item, argv, "help"); - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret.items, i); + if (status == PARSE_NEXT_ITEM_STATUS_ERROR) { + goto error; + } else if (status == PARSE_NEXT_ITEM_STATUS_END) { + break; + } - if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) { - struct bt_argpar_item_opt *argpar_item_opt; - const char *arg; - argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; - arg = argpar_item_opt->arg; + if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { + const struct argpar_opt_descr *opt_descr = + argpar_item_opt_descr(argpar_item); - switch (argpar_item_opt->descr->id) { - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - cfg->plugin_paths, arg)) { - goto error; - } - break; - case OPT_OMIT_SYSTEM_PLUGIN_PATH: - cfg->omit_system_plugin_path = true; - break; - case OPT_OMIT_HOME_PLUGIN_PATH: - cfg->omit_home_plugin_path = true; - break; + switch (opt_descr->id) { + case OPT_HELP: + print_help_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; default: - BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", - argpar_item_opt->descr->id); - goto error; + bt_common_abort(); } } else { - struct bt_argpar_item_non_opt *argpar_item_non_opt - = (struct bt_argpar_item_non_opt *) argpar_item; + const char *arg = argpar_item_non_opt_arg(argpar_item); - if (leftover) { - BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `help` command: `%s`.", - argpar_item_non_opt->arg); + if (plugin_comp_cls_arg) { + BT_CLI_LOGE_APPEND_CAUSE( + "Extraneous command-line argument specified to `help` command: `%s`.", + arg); goto error; } - leftover = argpar_item_non_opt->arg; + plugin_comp_cls_arg = arg; } } - if (leftover) { - plugin_comp_cls_names(leftover, NULL, - &plugin_name, &comp_cls_name, - &cfg->cmd_data.help.cfg_component->type); - if (plugin_name && comp_cls_name) { - /* Component class help */ - g_string_assign( - cfg->cmd_data.help.cfg_component->plugin_name, - plugin_name); - g_string_assign( - cfg->cmd_data.help.cfg_component->comp_cls_name, - comp_cls_name); - } else { - /* Fall back to plugin help */ - g_string_assign( - cfg->cmd_data.help.cfg_component->plugin_name, - leftover); - } - } else { - print_help_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; + if (!plugin_comp_cls_arg) { + BT_CLI_LOGE_APPEND_CAUSE( + "Missing plugin name or component class descriptor."); + goto error; } - if (append_home_and_system_plugin_paths_cfg(cfg)) { + /* Look for unescaped dots in the argument. */ + substring = bt_common_string_until(plugin_comp_cls_arg, ".\\", ".", &end_pos); + if (!substring) { + BT_CLI_LOGE_APPEND_CAUSE("Could not consume argument: arg=%s", + plugin_comp_cls_arg); goto error; } + if (end_pos == strlen(plugin_comp_cls_arg)) { + /* Didn't find an unescaped dot, treat it as a plugin name. */ + g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name, + plugin_comp_cls_arg); + } else { + /* + * Found an unescaped dot, treat it as a component class name. + */ + plugin_comp_cls_names(plugin_comp_cls_arg, NULL, &plugin_name, &comp_cls_name, + &cfg->cmd_data.help.cfg_component->type); + if (!plugin_name || !comp_cls_name) { + BT_CLI_LOGE_APPEND_CAUSE( + "Could not parse argument as a component class name: arg=%s", + plugin_comp_cls_arg); + goto error; + } + + g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name, + plugin_name); + g_string_assign(cfg->cmd_data.help.cfg_component->comp_cls_name, + comp_cls_name); + } + goto end; error: @@ -1527,7 +1577,12 @@ end: g_free(plugin_name); g_free(comp_cls_name); - bt_argpar_parse_ret_fini(&argpar_parse_ret); + if (substring) { + g_string_free(substring, TRUE); + } + + argpar_iter_destroy(argpar_iter); + argpar_item_destroy(argpar_item); return cfg; } @@ -1542,27 +1597,19 @@ void print_query_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "Options:\n"); fprintf(fp, "\n"); - fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); - fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n"); - fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n"); - fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS\n"); - fprintf(fp, " (see the expected format of PARAMS below)\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, " -h, --help Show this help and quit\n"); + fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS (see the expected\n"); + fprintf(fp, " format of PARAMS below)\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n\n"); print_expected_params_format(fp); } static -const struct bt_argpar_opt_descr query_options[] = { +const struct argpar_opt_descr query_options[] = { /* id, short_name, long_name, with_arg */ { OPT_HELP, 'h', "help", false }, - { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false }, - { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false }, { OPT_PARAMS, 'p', "params", true }, - { OPT_PLUGIN_PATH, '\0', "plugin-path", true }, - BT_ARGPAR_OPT_DESCR_SENTINEL + ARGPAR_OPT_DESCR_SENTINEL }; /* @@ -1573,24 +1620,24 @@ const struct bt_argpar_opt_descr query_options[] = { */ 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, + int *retcode, const bt_value *plugin_paths, int default_log_level) { - int ret, i; struct bt_config *cfg = NULL; const char *component_class_spec = NULL; const char *query_object = NULL; - bt_value *params; GString *error_str = NULL; - struct bt_argpar_parse_ret argpar_parse_ret; + struct argpar_iter *argpar_iter = NULL; + const struct argpar_item *argpar_item = NULL; - params = bt_value_null; - bt_value_get_ref(bt_value_null); + bt_value *params = bt_value_map_create(); + if (!params) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } *retcode = 0; - cfg = bt_config_query_create(initial_plugin_paths); + cfg = bt_config_query_create(plugin_paths); if (!cfg) { goto error; } @@ -1601,82 +1648,70 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], 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); - if (ret) { - goto error; - } - - /* Parse options */ - argpar_parse_ret = bt_argpar_parse(argc, argv, query_options, true); - if (argpar_parse_ret.error) { - BT_CLI_LOGE_APPEND_CAUSE( - "While parsing `query` command's command-line arguments: %s", - argpar_parse_ret.error->str); + argpar_iter = argpar_iter_create(argc, argv, query_options); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (help_option_is_specified(&argpar_parse_ret)) { - print_query_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; - } + while (true) { + enum parse_next_item_status status = + parse_next_item(argpar_iter, &argpar_item, argv, "query"); - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret.items, i); + if (status == PARSE_NEXT_ITEM_STATUS_ERROR) { + goto error; + } else if (status == PARSE_NEXT_ITEM_STATUS_END) { + break; + } - if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) { - struct bt_argpar_item_opt *argpar_item_opt = - (struct bt_argpar_item_opt *) argpar_item; - const char *arg = argpar_item_opt->arg; + if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { + const struct argpar_opt_descr *opt_descr = + argpar_item_opt_descr(argpar_item); + const char *arg = argpar_item_opt_arg(argpar_item); - switch (argpar_item_opt->descr->id) { - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - cfg->plugin_paths, arg)) { - goto error; - } - break; - case OPT_OMIT_SYSTEM_PLUGIN_PATH: - cfg->omit_system_plugin_path = true; - break; - case OPT_OMIT_HOME_PLUGIN_PATH: - cfg->omit_home_plugin_path = true; - break; + switch (opt_descr->id) { + case OPT_HELP: + print_query_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; case OPT_PARAMS: { - bt_value_put_ref(params); - params = cli_value_from_arg(arg, error_str); - if (!params) { + bt_value *parsed_params = bt_param_parse(arg, error_str); + bt_value_map_extend_status extend_status; + if (!parsed_params) { BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s", error_str->str); goto error; } + + extend_status = bt_value_map_extend(params, parsed_params); + BT_VALUE_PUT_REF_AND_RESET(parsed_params); + if (extend_status) { + BT_CLI_LOGE_APPEND_CAUSE("Cannot extend current parameters with --params option's argument:\n %s", + arg); + goto error; + } break; } default: - BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", - argpar_item_opt->descr->id); - goto error; + bt_common_abort(); } } else { - struct bt_argpar_item_non_opt *argpar_item_non_opt - = (struct bt_argpar_item_non_opt *) argpar_item; + const char *arg = argpar_item_non_opt_arg(argpar_item); /* - * We need exactly two leftover arguments which are the - * mandatory component class specification and query object. + * We need exactly two non-option arguments + * which are the mandatory component class + * specification and query object. */ if (!component_class_spec) { - component_class_spec = argpar_item_non_opt->arg; + component_class_spec = arg; } else if (!query_object) { - query_object = argpar_item_non_opt->arg; + query_object = arg; } else { BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `query` command: `%s`.", - argpar_item_non_opt->arg); + arg); goto error; } } @@ -1707,11 +1742,6 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], } g_string_assign(cfg->cmd_data.query.object, query_object); - - if (append_home_and_system_plugin_paths_cfg(cfg)) { - goto error; - } - goto end; error: @@ -1719,7 +1749,8 @@ error: BT_OBJECT_PUT_REF_AND_RESET(cfg); end: - bt_argpar_parse_ret_fini(&argpar_parse_ret); + argpar_iter_destroy(argpar_iter); + argpar_item_destroy(argpar_item); if (error_str) { g_string_free(error_str, TRUE); @@ -1739,11 +1770,6 @@ void print_list_plugins_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "Options:\n"); fprintf(fp, "\n"); - fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); - fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n"); - fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search 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, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n"); @@ -1752,13 +1778,10 @@ void print_list_plugins_usage(FILE *fp) } static -const struct bt_argpar_opt_descr list_plugins_options[] = { +const struct argpar_opt_descr list_plugins_options[] = { /* id, short_name, long_name, with_arg */ { OPT_HELP, 'h', "help", false }, - { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false }, - { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false }, - { OPT_PLUGIN_PATH, '\0', "plugin-path", true }, - BT_ARGPAR_OPT_DESCR_SENTINEL + ARGPAR_OPT_DESCR_SENTINEL }; /* @@ -1769,84 +1792,54 @@ const struct bt_argpar_opt_descr list_plugins_options[] = { */ static struct bt_config *bt_config_list_plugins_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) + int *retcode, const bt_value *plugin_paths) { - int ret, i; struct bt_config *cfg = NULL; - struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; + struct argpar_iter *argpar_iter = NULL; + const struct argpar_item *argpar_item = NULL; *retcode = 0; - cfg = bt_config_list_plugins_create(initial_plugin_paths); + cfg = bt_config_list_plugins_create(plugin_paths); if (!cfg) { 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); - if (ret) { + argpar_iter = argpar_iter_create(argc, argv, list_plugins_options); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - /* Parse options */ - argpar_parse_ret = bt_argpar_parse(argc, argv, list_plugins_options, true); - if (argpar_parse_ret.error) { - BT_CLI_LOGE_APPEND_CAUSE( - "While parsing `list-plugins` command's command-line arguments: %s", - argpar_parse_ret.error->str); - goto error; - } - - if (help_option_is_specified(&argpar_parse_ret)) { - print_list_plugins_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; - } - - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret.items, i); - struct bt_argpar_item_opt *argpar_item_opt; - const char *arg; - - if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) { - struct bt_argpar_item_non_opt *argpar_item_non_opt - = (struct bt_argpar_item_non_opt *) argpar_item; + while (true) { + enum parse_next_item_status status = + parse_next_item(argpar_iter, &argpar_item, argv, "list-plugins"); - BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.", - argpar_item_non_opt->arg); + if (status == PARSE_NEXT_ITEM_STATUS_ERROR) { goto error; + } else if (status == PARSE_NEXT_ITEM_STATUS_END) { + break; } - argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; - arg = argpar_item_opt->arg; + if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { + const struct argpar_opt_descr *opt_descr = + argpar_item_opt_descr(argpar_item); - switch (argpar_item_opt->descr->id) { - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - cfg->plugin_paths, arg)) { - goto error; + switch (opt_descr->id) { + case OPT_HELP: + print_list_plugins_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; + default: + bt_common_abort(); } - break; - case OPT_OMIT_SYSTEM_PLUGIN_PATH: - cfg->omit_system_plugin_path = true; - break; - case OPT_OMIT_HOME_PLUGIN_PATH: - cfg->omit_home_plugin_path = true; - break; - default: - BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", - argpar_item_opt->descr->id); + } else { + BT_CLI_LOGE_APPEND_CAUSE( + "Extraneous command-line argument specified to `list-plugins` command: `%s`.", + argpar_item_non_opt_arg(argpar_item)); goto error; } - } - - if (append_home_and_system_plugin_paths_cfg(cfg)) { - goto error; - } + } goto end; @@ -1855,7 +1848,8 @@ error: BT_OBJECT_PUT_REF_AND_RESET(cfg); end: - bt_argpar_parse_ret_fini(&argpar_parse_ret); + argpar_iter_destroy(argpar_iter); + argpar_item_destroy(argpar_item); return cfg; } @@ -1882,15 +1876,10 @@ void print_run_usage(FILE *fp) 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, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); - fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n"); - fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n"); + fprintf(fp, " (`N`, `T`, `D`, `I`, `W`, `E`, or `F`)\n"); fprintf(fp, " -p, --params=PARAMS Add initialization parameters PARAMS to the\n"); fprintf(fp, " current component (see the expected format\n"); fprintf(fp, " of PARAMS below)\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, " -r, --reset-base-params Reset the current base parameters to an\n"); fprintf(fp, " empty map\n"); fprintf(fp, " --retry-duration=DUR When babeltrace2(1) needs to retry to run\n"); @@ -1945,9 +1934,8 @@ void print_run_usage(FILE *fp) */ 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, int default_log_level) + int *retcode, const bt_value *plugin_paths, + int default_log_level) { struct bt_config_component *cur_cfg_comp = NULL; bt_value *cur_base_params = NULL; @@ -1959,22 +1947,19 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], long retry_duration = -1; bt_value_map_extend_status extend_status; GString *error_str = NULL; - struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; - int i; + struct argpar_iter *argpar_iter = NULL; + const struct argpar_item *argpar_item = NULL; - static const struct bt_argpar_opt_descr run_options[] = { + static const struct argpar_opt_descr run_options[] = { { OPT_BASE_PARAMS, 'b', "base-params", true }, { OPT_COMPONENT, 'c', "component", true }, { OPT_CONNECT, 'x', "connect", true }, { OPT_HELP, 'h', "help", false }, { OPT_LOG_LEVEL, 'l', "log-level", true }, - { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false }, - { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false }, { OPT_PARAMS, 'p', "params", true }, - { OPT_PLUGIN_PATH, '\0', "plugin-path", true }, { OPT_RESET_BASE_PARAMS, 'r', "reset-base-params", false }, { OPT_RETRY_DURATION, '\0', "retry-duration", true }, - BT_ARGPAR_OPT_DESCR_SENTINEL + ARGPAR_OPT_DESCR_SENTINEL }; *retcode = 0; @@ -1991,14 +1976,12 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto end; } - cfg = bt_config_run_create(initial_plugin_paths); + cfg = bt_config_run_create(plugin_paths); if (!cfg) { goto error; } cfg->cmd_data.run.retry_duration_us = 100000; - cfg->omit_system_plugin_path = force_omit_system_plugin_path; - cfg->omit_home_plugin_path = force_omit_home_plugin_path; cur_base_params = bt_value_map_create(); if (!cur_base_params) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); @@ -2017,59 +2000,40 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } - ret = append_env_var_plugin_paths(cfg->plugin_paths); - if (ret) { - goto error; - } - - /* Parse options */ - argpar_parse_ret = bt_argpar_parse(argc, argv, run_options, true); - if (argpar_parse_ret.error) { - BT_CLI_LOGE_APPEND_CAUSE( - "While parsing `run` command's command-line arguments: %s", - argpar_parse_ret.error->str); + argpar_iter = argpar_iter_create(argc, argv, run_options); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (help_option_is_specified(&argpar_parse_ret)) { - print_run_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; - } - - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret.items, i); - struct bt_argpar_item_opt *argpar_item_opt; + while (true) { + enum parse_next_item_status status; + const struct argpar_opt_descr *opt_descr; const char *arg; - /* This command does not accept leftover arguments. */ - if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) { - struct bt_argpar_item_non_opt *argpar_nonopt_item = - (struct bt_argpar_item_non_opt *) argpar_item; + status = parse_next_item(argpar_iter, &argpar_item, argv, "run"); + if (status == PARSE_NEXT_ITEM_STATUS_ERROR) { + goto error; + } else if (status == PARSE_NEXT_ITEM_STATUS_END) { + break; + } + /* This command does not accept non-option arguments.*/ + if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_NON_OPT) { BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`", - argpar_nonopt_item->arg); + argpar_item_non_opt_arg(argpar_item)); goto error; } - argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; - arg = argpar_item_opt->arg; + opt_descr = argpar_item_opt_descr(argpar_item); + arg = argpar_item_opt_arg(argpar_item); - switch (argpar_item_opt->descr->id) { - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - cfg->plugin_paths, arg)) { - goto error; - } - break; - case OPT_OMIT_SYSTEM_PLUGIN_PATH: - cfg->omit_system_plugin_path = true; - break; - case OPT_OMIT_HOME_PLUGIN_PATH: - cfg->omit_home_plugin_path = true; - break; + switch (opt_descr->id) { + case OPT_HELP: + print_run_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; case OPT_COMPONENT: { enum bt_config_component_dest dest; @@ -2094,7 +2058,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], dest = BT_CONFIG_COMPONENT_DEST_SINK; break; default: - abort(); + bt_common_abort(); } BT_ASSERT(cur_base_params); @@ -2117,7 +2081,6 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], case OPT_PARAMS: { bt_value *params; - bt_value *params_to_set; if (!cur_cfg_comp) { BT_CLI_LOGE_APPEND_CAUSE("Cannot add parameters to unavailable component:\n %s", @@ -2125,15 +2088,15 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } - params = cli_value_from_arg(arg, error_str); + params = bt_param_parse(arg, error_str); if (!params) { BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s", error_str->str); goto error; } - extend_status = bt_value_map_extend( - cur_cfg_comp->params, params, ¶ms_to_set); + extend_status = bt_value_map_extend(cur_cfg_comp->params, + params); BT_VALUE_PUT_REF_AND_RESET(params); 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", @@ -2141,7 +2104,6 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } - BT_OBJECT_MOVE_REF(cur_cfg_comp->params, params_to_set); break; } case OPT_LOG_LEVEL: @@ -2161,7 +2123,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], break; case OPT_BASE_PARAMS: { - bt_value *params = cli_value_from_arg(arg, error_str); + bt_value *params = bt_param_parse(arg, error_str); if (!params) { BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --base-params option's argument:\n %s", @@ -2189,14 +2151,14 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], break; case OPT_RETRY_DURATION: { gchar *end; - size_t arg_len = strlen(argpar_item_opt->arg); + size_t arg_len = strlen(arg); - retry_duration = g_ascii_strtoll(argpar_item_opt->arg, &end, 10); + retry_duration = g_ascii_strtoll(arg, &end, 10); - if (arg_len == 0 || end != (argpar_item_opt->arg + arg_len)) { + if (arg_len == 0 || end != (arg + arg_len)) { BT_CLI_LOGE_APPEND_CAUSE( "Could not parse --retry-duration option's argument as an unsigned integer: `%s`", - argpar_item_opt->arg); + arg); goto error; } @@ -2211,9 +2173,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], break; } default: - BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", - argpar_item_opt->descr->id); - goto error; + bt_common_abort(); } } @@ -2229,10 +2189,6 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } - if (append_home_and_system_plugin_paths_cfg(cfg)) { - goto error; - } - ret = bt_config_cli_args_create_connections(cfg, connection_args, error_buf, 256); @@ -2252,7 +2208,9 @@ end: g_string_free(error_str, TRUE); } - bt_argpar_parse_ret_fini(&argpar_parse_ret); + argpar_iter_destroy(argpar_iter); + argpar_item_destroy(argpar_item); + BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp); BT_VALUE_PUT_REF_AND_RESET(cur_base_params); BT_VALUE_PUT_REF_AND_RESET(instance_names); @@ -2262,41 +2220,33 @@ end: 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, int default_log_level) + int *retcode, const bt_value *plugin_paths, + int default_log_level) { struct bt_config *cfg = NULL; const char **argv; - int64_t i, len; - const size_t argc = bt_value_array_get_size(run_args); + uint64_t i, len = bt_value_array_get_length(run_args); - argv = calloc(argc, sizeof(*argv)); + BT_ASSERT(len <= SIZE_MAX); + argv = calloc((size_t) len, sizeof(*argv)); if (!argv) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto end; } - len = bt_value_array_get_size(run_args); - if (len < 0) { - BT_CLI_LOGE_APPEND_CAUSE("Invalid executable arguments."); - goto end; - } for (i = 0; i < len; i++) { const bt_value *arg_value = bt_value_array_borrow_element_by_index_const(run_args, - i); + i); const char *arg; - BT_ASSERT(arg_value); arg = bt_value_string_get(arg_value); BT_ASSERT(arg); argv[i] = arg; } - cfg = bt_config_run_from_args(argc, argv, retcode, - force_omit_system_plugin_path, force_omit_home_plugin_path, - initial_plugin_paths, default_log_level); + cfg = bt_config_run_from_args((int) len, argv, retcode, + plugin_paths, default_log_level); end: free(argv); @@ -2320,15 +2270,10 @@ void print_convert_usage(FILE *fp) fprintf(fp, " conversion graph, and optionally name it\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, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); - fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n"); - fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n"); + fprintf(fp, " (`N`, `T`, `D`, `I`, `W`, `E`, or `F`)\n"); fprintf(fp, " -p, --params=PARAMS Add initialization parameters PARAMS to the\n"); fprintf(fp, " current component (see the expected format\n"); fprintf(fp, " of PARAMS below)\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"); @@ -2345,6 +2290,8 @@ void print_convert_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "Implicit `source.ctf.fs` component options:\n"); fprintf(fp, "\n"); + fprintf(fp, " --clock-force-correlate Force the origin of all clocks\n"); + fprintf(fp, " to the Unix epoch\n"); fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n"); fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS ns\n"); fprintf(fp, "\n"); @@ -2372,11 +2319,6 @@ void print_convert_usage(FILE *fp) fprintf(fp, " -w, --output=PATH Write output text to PATH instead of\n"); fprintf(fp, " the standard output\n"); fprintf(fp, "\n"); - fprintf(fp, "Implicit `filter.utils.muxer` component options:\n"); - fprintf(fp, "\n"); - fprintf(fp, " --clock-force-correlate Assume that clocks are inherently\n"); - fprintf(fp, " correlated across traces\n"); - fprintf(fp, "\n"); fprintf(fp, "Implicit `filter.utils.trimmer` component options:\n"); fprintf(fp, "\n"); fprintf(fp, " -b, --begin=BEGIN Set the beginning time of the conversion\n"); @@ -2435,7 +2377,7 @@ void print_convert_usage(FILE *fp) } static -const struct bt_argpar_opt_descr convert_options[] = { +const struct argpar_opt_descr convert_options[] = { /* id, short_name, long_name, with_arg */ { OPT_BEGIN, 'b', "begin", true }, { OPT_CLOCK_CYCLES, '\0', "clock-cycles", false }, @@ -2471,7 +2413,7 @@ const struct bt_argpar_opt_descr convert_options[] = { { OPT_STREAM_INTERSECTION, '\0', "stream-intersection", false }, { OPT_TIMERANGE, '\0', "timerange", true }, { OPT_VERBOSE, 'v', "verbose", false }, - BT_ARGPAR_OPT_DESCR_SENTINEL + ARGPAR_OPT_DESCR_SENTINEL }; static @@ -2561,7 +2503,7 @@ int append_run_args_for_implicit_component( bt_value *run_args) { int ret = 0; - size_t i; + uint64_t i; GString *component_arg_for_run = NULL; if (!impl_args->exists) { @@ -2604,16 +2546,12 @@ int append_run_args_for_implicit_component( } } - for (i = 0; i < bt_value_array_get_size(impl_args->extra_params); - i++) { + for (i = 0; i < bt_value_array_get_length(impl_args->extra_params); i++) { const bt_value *elem; const char *arg; - elem = bt_value_array_borrow_element_by_index(impl_args->extra_params, - i); - if (!elem) { - goto error; - } + elem = bt_value_array_borrow_element_by_index( + impl_args->extra_params, i); BT_ASSERT(bt_value_is_string(elem)); arg = bt_value_string_get(elem); @@ -2812,10 +2750,9 @@ int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf) } case BT_VALUE_TYPE_ARRAY: { g_string_append_c(buf, '['); - uint64_t sz = bt_value_array_get_size(value); + uint64_t sz = bt_value_array_get_length(value); for (uint64_t i = 0; i < sz; i++) { const bt_value *item; - int ret; if (i > 0) { g_string_append(buf, ", "); @@ -2833,7 +2770,7 @@ int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf) break; } default: - abort(); + bt_common_abort(); } ret = 0; @@ -3175,13 +3112,31 @@ end: } /* - * Create `struct implicit_component_args` structures for each of the source - * components we identified. Add them to `component_args`. + * Create `struct implicit_component_args` structures for each of the + * source components we identified. Add them to `component_args`. + * + * `non_opts` is an array of the non-option arguments passed on the command + * line. + * + * `non_opt_params` is an array where each element is an array of + * strings containing all the arguments to `--params` that apply to the + * non-option argument at the same index. For example, if, for a + * non-option argument, the following `--params` options applied: + * + * --params=a=2 --params=b=3,c=4 + * + * its entry in `non_opt_params` would contain + * + * ["a=2", "b=3,c=4"] */ static -void create_implicit_component_args_from_auto_discovered_sources( - const struct auto_source_discovery *auto_disc, GPtrArray *component_args) +int create_implicit_component_args_from_auto_discovered_sources( + const struct auto_source_discovery *auto_disc, + const bt_value *non_opts, + const bt_value *non_opt_params, + const bt_value *non_opt_loglevels, + GPtrArray *component_args) { gchar *cc_name = NULL; struct implicit_component_args *comp = NULL; @@ -3193,34 +3148,141 @@ void create_implicit_component_args_from_auto_discovered_sources( for (i = 0; i < len; i++) { struct auto_source_discovery_result *res = g_ptr_array_index(auto_disc->results, i); + uint64_t orig_indices_i, orig_indices_count; 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; + goto error; } comp = create_implicit_component_args(cc_name); if (!comp) { - goto end; + goto error; + } + + /* + * Append parameters and log levels of all the + * non-option arguments that contributed to this + * component instance coming into existence. + */ + orig_indices_count = bt_value_array_get_length(res->original_input_indices); + for (orig_indices_i = 0; orig_indices_i < orig_indices_count; orig_indices_i++) { + const bt_value *orig_idx_value = + bt_value_array_borrow_element_by_index( + res->original_input_indices, orig_indices_i); + uint64_t orig_idx = bt_value_integer_unsigned_get(orig_idx_value); + const bt_value *params_array = + bt_value_array_borrow_element_by_index_const( + non_opt_params, orig_idx); + uint64_t params_i, params_count; + const bt_value *loglevel_value; + + params_count = bt_value_array_get_length(params_array); + for (params_i = 0; params_i < params_count; params_i++) { + const bt_value *params_value = + bt_value_array_borrow_element_by_index_const( + params_array, params_i); + const char *params = bt_value_string_get(params_value); + bt_value_array_append_element_status append_status; + + append_status = bt_value_array_append_string_element( + comp->extra_params, "--params"); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element."); + goto error; + } + + append_status = bt_value_array_append_string_element( + comp->extra_params, params); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element."); + goto error; + } + } + + loglevel_value = bt_value_array_borrow_element_by_index_const( + non_opt_loglevels, orig_idx); + if (bt_value_get_type(loglevel_value) == BT_VALUE_TYPE_STRING) { + const char *loglevel = bt_value_string_get(loglevel_value); + bt_value_array_append_element_status append_status; + + append_status = bt_value_array_append_string_element( + comp->extra_params, "--log-level"); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element."); + goto error; + } + + append_status = bt_value_array_append_string_element( + comp->extra_params, loglevel); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element."); + goto error; + } + } + } + + /* + * If single input and a src.ctf.fs component, provide the + * relative path from the path passed on the command line to the + * found trace. + */ + if (bt_value_array_get_length(res->inputs) == 1 && + strcmp(res->plugin_name, "ctf") == 0 && + strcmp(res->source_cc_name, "fs") == 0) { + const bt_value *orig_idx_value = + bt_value_array_borrow_element_by_index( + res->original_input_indices, 0); + uint64_t orig_idx = bt_value_integer_unsigned_get(orig_idx_value); + const bt_value *non_opt_value = + bt_value_array_borrow_element_by_index_const( + non_opts, orig_idx); + const char *non_opt = bt_value_string_get(non_opt_value); + const bt_value *input_value = + bt_value_array_borrow_element_by_index_const( + res->inputs, 0); + const char *input = bt_value_string_get(input_value); + + BT_ASSERT(orig_indices_count == 1); + BT_ASSERT(g_str_has_prefix(input, non_opt)); + + input += strlen(non_opt); + + while (G_IS_DIR_SEPARATOR(*input)) { + input++; + } + + if (strlen(input) > 0) { + append_string_parameter_to_args(comp->extra_params, + "trace-name", input); + } } status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs); if (status != 0) { - goto end; + goto error; } g_ptr_array_add(component_args, comp); comp = NULL; } + status = 0; + goto end; + +error: + status = -1; + end: g_free(cc_name); if (comp) { destroy_implicit_component_args(comp); } + + return status; } /* @@ -3235,8 +3297,8 @@ enum convert_current_item_type { /* Current item is a component. */ CONVERT_CURRENT_ITEM_TYPE_COMPONENT, - /* Current item is a leftover. */ - CONVERT_CURRENT_ITEM_TYPE_LEFTOVER, + /* Current item is a non-option argument. */ + CONVERT_CURRENT_ITEM_TYPE_NON_OPT, }; /* @@ -3247,9 +3309,8 @@ enum convert_current_item_type { */ 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, int *default_log_level) + int *retcode, const bt_value *plugin_paths, + int *default_log_level, const bt_interrupter *interrupter) { enum convert_current_item_type current_item_type = CONVERT_CURRENT_ITEM_TYPE_NONE; @@ -3268,7 +3329,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], GList *source_names = NULL; GList *filter_names = NULL; GList *sink_names = NULL; - bt_value *leftovers = NULL; + bt_value *non_opts = NULL; + bt_value *non_opt_params = NULL; + bt_value *non_opt_loglevels = NULL; 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 }; @@ -3276,16 +3339,17 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], struct implicit_component_args implicit_debug_info_args = { 0 }; struct implicit_component_args implicit_muxer_args = { 0 }; struct implicit_component_args implicit_trimmer_args = { 0 }; - bt_value *plugin_paths; char error_buf[256] = { 0 }; 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; - struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; + struct argpar_iter *argpar_iter = NULL; + const struct argpar_item *argpar_item = NULL; GString *name_gstr = NULL; GString *component_arg_for_run = NULL; + bt_value *live_inputs_array_val = NULL; /* * Array of `struct implicit_component_args *` created for the sources @@ -3300,11 +3364,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], const char *auto_source_discovery_restrict_plugin_name = NULL; const char *auto_source_discovery_restrict_component_class_name = NULL; + bool ctf_fs_source_force_clock_class_unix_epoch_origin = false; 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); - *retcode = 0; if (argc < 1) { @@ -3366,13 +3428,20 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - ret = append_env_var_plugin_paths(plugin_paths); - if (ret) { + non_opts = bt_value_array_create(); + if (!non_opts) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - leftovers = bt_value_array_create(); - if (!leftovers) { + non_opt_params = bt_value_array_create(); + if (!non_opt_params) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + non_opt_loglevels = bt_value_array_create(); + if (!non_opt_loglevels) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } @@ -3399,39 +3468,37 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * as is to the run command. This pass can also add --name * arguments if needed to automatically name unnamed component * instances. - * - * Also it appends the plugin paths of --plugin-path to - * `plugin_paths`. */ - argpar_parse_ret = bt_argpar_parse(argc, argv, convert_options, true); - if (argpar_parse_ret.error) { - BT_CLI_LOGE_APPEND_CAUSE( - "While parsing `convert` command's command-line arguments: %s", - argpar_parse_ret.error->str); + argpar_iter = argpar_iter_create(argc, argv, convert_options); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (help_option_is_specified(&argpar_parse_ret)) { - print_convert_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; - } - - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret.items, i); - struct bt_argpar_item_opt *argpar_item_opt; + while (true) { + enum parse_next_item_status status; char *name = NULL; char *plugin_name = NULL; char *comp_cls_name = NULL; - const char *arg; - if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) { - argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; - arg = argpar_item_opt->arg; + status = parse_next_item(argpar_iter, &argpar_item, argv, "convert"); + if (status == PARSE_NEXT_ITEM_STATUS_ERROR) { + goto error; + } else if (status == PARSE_NEXT_ITEM_STATUS_END) { + break; + } + + if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { + const struct argpar_opt_descr *opt_descr = + argpar_item_opt_descr(argpar_item); + const char *arg = argpar_item_opt_arg(argpar_item); - switch (argpar_item_opt->descr->id) { + switch (opt_descr->id) { + case OPT_HELP: + print_convert_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; case OPT_COMPONENT: { bt_component_class_type type; @@ -3517,7 +3584,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], sink_names = g_list_append(sink_names, name_gstr); break; default: - abort(); + bt_common_abort(); } name_gstr = NULL; @@ -3530,51 +3597,82 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], break; } case OPT_PARAMS: - if (current_item_type != CONVERT_CURRENT_ITEM_TYPE_COMPONENT) { - BT_CLI_LOGE_APPEND_CAUSE( - "No current component (--component option) of which to set parameters:\n %s", - arg); - goto error; - } + if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_COMPONENT) { + /* + * The current item is a component (--component option), + * pass it directly to the run args. + */ + if (bt_value_array_append_string_element(run_args, + "--params")) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } - if (bt_value_array_append_string_element(run_args, - "--params")) { - 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; + } + } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_NON_OPT) { + /* + * The current item is a + * non-option argument, record + * it in `non_opt_params`. + */ + bt_value *array; + bt_value_array_append_element_status append_element_status; + uint64_t idx = bt_value_array_get_length(non_opt_params) - 1; - if (bt_value_array_append_string_element(run_args, arg)) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - break; - case OPT_LOG_LEVEL: - if (current_item_type != CONVERT_CURRENT_ITEM_TYPE_COMPONENT) { + array = bt_value_array_borrow_element_by_index(non_opt_params, idx); + + append_element_status = bt_value_array_append_string_element(array, arg); + if (append_element_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + } else { BT_CLI_LOGE_APPEND_CAUSE( - "No current component (--component option) to assign a log level to:\n %s", + "No current component (--component option) or non-option argument of which to set parameters:\n %s", arg); goto error; } + break; + case OPT_LOG_LEVEL: + if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_COMPONENT) { + 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, "--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; - } + if (bt_value_array_append_string_element(run_args, arg)) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_NON_OPT) { + uint64_t idx = bt_value_array_get_length(non_opt_loglevels) - 1; + enum bt_value_array_set_element_by_index_status set_element_status; + bt_value *log_level_str_value; - break; - case OPT_OMIT_HOME_PLUGIN_PATH: - force_omit_home_plugin_path = true; + log_level_str_value = bt_value_string_create_init(arg); + if (!log_level_str_value) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } - if (bt_value_array_append_string_element(run_args, - "--omit-home-plugin-path")) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); + set_element_status = + bt_value_array_set_element_by_index(non_opt_loglevels, + idx, log_level_str_value); + bt_value_put_ref(log_level_str_value); + if (set_element_status != BT_VALUE_ARRAY_SET_ELEMENT_BY_INDEX_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + } else { + BT_CLI_LOGE_APPEND_CAUSE( + "No current component (--component option) or non-option argument to assign a log level to:\n %s", + arg); goto error; } + break; case OPT_RETRY_DURATION: if (bt_value_array_append_string_element(run_args, @@ -3583,32 +3681,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - if (bt_value_array_append_string_element(run_args, arg)) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - break; - case OPT_OMIT_SYSTEM_PLUGIN_PATH: - force_omit_system_plugin_path = true; - - if (bt_value_array_append_string_element(run_args, - "--omit-system-plugin-path")) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - break; - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - plugin_paths, arg)) { - goto error; - } - - if (bt_value_array_append_string_element(run_args, - "--plugin-path")) { - 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; @@ -3643,26 +3715,32 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], /* Ignore in this pass */ break; default: - BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", - argpar_item_opt->descr->id); - goto error; + bt_common_abort(); } - } else if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) { - struct bt_argpar_item_non_opt *argpar_item_non_opt; + } else { + const char *arg = argpar_item_non_opt_arg(argpar_item); bt_value_array_append_element_status append_status; - current_item_type = CONVERT_CURRENT_ITEM_TYPE_LEFTOVER; + current_item_type = CONVERT_CURRENT_ITEM_TYPE_NON_OPT; - argpar_item_non_opt = (struct bt_argpar_item_non_opt *) argpar_item; + append_status = bt_value_array_append_string_element(non_opts, arg); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } - append_status = bt_value_array_append_string_element(leftovers, - argpar_item_non_opt->arg); + append_status = bt_value_array_append_empty_array_element( + non_opt_params, NULL); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + append_status = bt_value_array_append_element(non_opt_loglevels, bt_value_null); if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - } else { - abort(); } } @@ -3671,23 +3749,36 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * arguments into implicit component instances for the run * command. */ - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *argpar_item = - g_ptr_array_index(argpar_parse_ret.items, i); - struct bt_argpar_item_opt *argpar_item_opt; + argpar_iter_destroy(argpar_iter); + argpar_iter = argpar_iter_create(argc, argv, convert_options); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + while (true) { + enum parse_next_item_status status; + const struct argpar_opt_descr *opt_descr; const char *arg; - if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) { + status = parse_next_item(argpar_iter, &argpar_item, argv, "convert"); + if (status == PARSE_NEXT_ITEM_STATUS_ERROR) { + goto error; + } else if (status == PARSE_NEXT_ITEM_STATUS_END) { + break; + } + + if (argpar_item_type(argpar_item) != ARGPAR_ITEM_TYPE_OPT) { continue; } - argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; - arg = argpar_item_opt->arg; + opt_descr = argpar_item_opt_descr(argpar_item); + arg = argpar_item_opt_arg(argpar_item); - switch (argpar_item_opt->descr->id) { + switch (opt_descr->id) { case OPT_BEGIN: if (trimmer_has_begin) { - printf("At --begin option: --begin or --timerange option already specified\n %s\n", + BT_CLI_LOGE_APPEND_CAUSE("At --begin option: --begin or --timerange option already specified\n %s\n", arg); goto error; } @@ -3702,7 +3793,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], break; case OPT_END: if (trimmer_has_end) { - printf("At --end option: --end or --timerange option already specified\n %s\n", + BT_CLI_LOGE_APPEND_CAUSE("At --end option: --end or --timerange option already specified\n %s\n", arg); goto error; } @@ -3721,7 +3812,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], char *end; if (trimmer_has_begin || trimmer_has_end) { - printf("At --timerange option: --begin, --end, or --timerange option already specified\n %s\n", + BT_CLI_LOGE_APPEND_CAUSE("At --timerange option: --begin, --end, or --timerange option already specified\n %s\n", arg); goto error; } @@ -3756,9 +3847,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], implicit_text_args.exists = true; break; case OPT_CLOCK_FORCE_CORRELATE: - append_implicit_component_param( - &implicit_muxer_args, - "assume-absolute-clock-classes", "yes"); + ctf_fs_source_force_clock_class_unix_epoch_origin = true; break; case OPT_CLOCK_GMT: append_implicit_component_param( @@ -3944,24 +4033,35 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], case OPT_STREAM_INTERSECTION: /* * Applies to all traces implementing the - * babeltrace.trace-info query. + * babeltrace.trace-infos query. */ stream_intersection_mode = true; break; case OPT_VERBOSE: - if (*default_log_level != BT_LOG_TRACE && - *default_log_level != BT_LOG_DEBUG) { - *default_log_level = BT_LOG_INFO; - } + *default_log_level = + logging_level_min(*default_log_level, BT_LOG_INFO); break; case OPT_DEBUG: - *default_log_level = BT_LOG_TRACE; + *default_log_level = + logging_level_min(*default_log_level, BT_LOG_TRACE); break; - default: + case OPT_COMPONENT: + case OPT_HELP: + case OPT_LOG_LEVEL: + case OPT_OMIT_HOME_PLUGIN_PATH: + case OPT_OMIT_SYSTEM_PLUGIN_PATH: + case OPT_PARAMS: + case OPT_PLUGIN_PATH: + case OPT_RETRY_DURATION: + /* Ignore in this pass */ break; + default: + bt_common_abort(); } } + set_auto_log_levels(default_log_level); + /* * Legacy behaviour: --verbose used to make the `text` output * format print more information. --verbose is now equivalent to @@ -3973,26 +4073,16 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], "verbose", "yes"); } - /* - * Append home and system plugin paths now that we possibly got - * --plugin-path. - */ - if (append_home_and_system_plugin_paths(plugin_paths, - force_omit_system_plugin_path, - force_omit_home_plugin_path)) { - goto error; - } - /* Print CTF metadata or print LTTng live sessions */ if (print_ctf_metadata) { - const bt_value *bt_val_leftover; + const bt_value *bt_val_non_opt; - if (bt_value_array_is_empty(leftovers)) { + if (bt_value_array_is_empty(non_opts)) { BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf-metadata specified without a path."); goto error; } - if (bt_value_array_get_size(leftovers) > 1) { + if (bt_value_array_get_length(non_opts) > 1) { BT_CLI_LOGE_APPEND_CAUSE("Too many paths specified for --output-format=ctf-metadata."); goto error; } @@ -4002,9 +4092,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0); + bt_val_non_opt = bt_value_array_borrow_element_by_index_const(non_opts, 0); g_string_assign(cfg->cmd_data.print_ctf_metadata.path, - bt_value_string_get(bt_val_leftover)); + bt_value_string_get(bt_val_non_opt)); if (output) { g_string_assign( @@ -4069,19 +4159,19 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } } - /* Decide where the leftover argument(s) go */ - if (bt_value_array_get_size(leftovers) > 0) { + /* Decide where the non-option argument(s) go */ + if (bt_value_array_get_length(non_opts) > 0) { if (implicit_lttng_live_args.exists) { - const bt_value *bt_val_leftover; + const bt_value *bt_val_non_opt; - if (bt_value_array_get_size(leftovers) > 1) { + if (bt_value_array_get_length(non_opts) > 1) { BT_CLI_LOGE_APPEND_CAUSE("Too many URLs specified for --input-format=lttng-live."); goto error; } - bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0); + bt_val_non_opt = bt_value_array_borrow_element_by_index_const(non_opts, 0); lttng_live_url_parts = - bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_leftover), + bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_non_opt), error_buf, sizeof(error_buf)); if (!lttng_live_url_parts.proto) { BT_CLI_LOGE_APPEND_CAUSE("Invalid LTTng live URL format: %s.", @@ -4098,7 +4188,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url, - bt_value_string_get(bt_val_leftover)); + bt_value_string_get(bt_val_non_opt)); if (output) { g_string_assign( @@ -4109,9 +4199,22 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto end; } - ret = append_implicit_component_extra_param( - &implicit_lttng_live_args, "url", - bt_value_string_get(bt_val_leftover)); + live_inputs_array_val = bt_value_array_create(); + if (!live_inputs_array_val) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + if (bt_value_array_append_string_element( + live_inputs_array_val, + bt_value_string_get(bt_val_non_opt))) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + ret = append_parameter_to_args( + implicit_lttng_live_args.extra_params, + "inputs", live_inputs_array_val); if (ret) { goto error; } @@ -4124,19 +4227,59 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } } else { int status; + size_t plugin_count; + const bt_plugin **plugins; + const bt_plugin *plugin; - status = auto_discover_source_components(plugin_paths, leftovers, - auto_source_discovery_restrict_plugin_name, + status = require_loaded_plugins(plugin_paths); + if (status != 0) { + goto error; + } + + if (auto_source_discovery_restrict_plugin_name) { + plugin_count = 1; + plugin = borrow_loaded_plugin_by_name(auto_source_discovery_restrict_plugin_name); + plugins = &plugin; + } else { + plugin_count = get_loaded_plugins_count(); + plugins = borrow_loaded_plugins(); + } + + status = auto_discover_source_components(non_opts, plugins, plugin_count, auto_source_discovery_restrict_component_class_name, - *default_log_level >= 0 ? *default_log_level : cli_default_log_level, - &auto_disc); + *default_log_level, &auto_disc, interrupter); if (status != 0) { + if (status == AUTO_SOURCE_DISCOVERY_STATUS_INTERRUPTED) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( + "Babeltrace CLI", "Automatic source discovery interrupted by the user"); + } goto error; } - create_implicit_component_args_from_auto_discovered_sources( - &auto_disc, discovered_source_args); + status = create_implicit_component_args_from_auto_discovered_sources( + &auto_disc, non_opts, non_opt_params, non_opt_loglevels, + discovered_source_args); + if (status != 0) { + goto error; + } + } + } + + + /* + * If --clock-force-correlated was given, apply it to any src.ctf.fs + * component. + */ + if (ctf_fs_source_force_clock_class_unix_epoch_origin) { + int n; + + n = append_multiple_implicit_components_param( + discovered_source_args, "source.ctf.fs", "force-clock-class-origin-unix-epoch", + "yes"); + if (n == 0) { + BT_CLI_LOGE_APPEND_CAUSE("--clock-force-correlate specified, but no source.ctf.fs component instantiated."); + goto error; } } @@ -4169,10 +4312,11 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } /* - * If the implicit `source.ctf.lttng-live` component exists, make sure - * there's at least one leftover (which is the URL). + * If the implicit `source.ctf.lttng-live` component exists, + * make sure there's at least one non-option argument (which is + * the URL). */ - if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) { + if (implicit_lttng_live_args.exists && bt_value_array_is_empty(non_opts)) { BT_CLI_LOGE_APPEND_CAUSE("Missing URL for implicit `%s` component.", implicit_lttng_live_args.comp_arg->str); goto error; @@ -4254,6 +4398,13 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + /* Make sure there's a single sink component */ + if (g_list_length(sink_names) != 1) { + BT_CLI_LOGE_APPEND_CAUSE( + "More than one sink component specified."); + goto error; + } + /* * Prepend the muxer, the trimmer, and the debug info to the * filter chain so that we have: @@ -4350,20 +4501,21 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * here. */ if (print_run_args || print_run_args_0) { + uint64_t args_idx, args_len; if (stream_intersection_mode) { BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --stream-intersection with --run-args or --run-args-0."); goto error; } - for (i = 0; i < bt_value_array_get_size(run_args); i++) { + args_len = bt_value_array_get_length(run_args); + for (args_idx = 0; args_idx < args_len; args_idx++) { const bt_value *arg_value = bt_value_array_borrow_element_by_index(run_args, - i); + args_idx); const char *arg; GString *quoted = NULL; const char *arg_to_print; - BT_ASSERT(arg_value); arg = bt_value_string_get(arg_value); if (print_run_args) { @@ -4383,7 +4535,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], g_string_free(quoted, TRUE); } - if (i < bt_value_array_get_size(run_args) - 1) { + if (args_idx < args_len - 1) { if (print_run_args) { putchar(' '); } else { @@ -4397,18 +4549,8 @@ 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, *default_log_level); + plugin_paths, *default_log_level); if (!cfg) { goto error; } @@ -4421,15 +4563,8 @@ 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; - } - - bt_argpar_parse_ret_fini(&argpar_parse_ret); + argpar_iter_destroy(argpar_iter); + argpar_item_destroy(argpar_item); free(output); @@ -4441,12 +4576,15 @@ end: g_string_free(name_gstr, TRUE); } + bt_value_put_ref(live_inputs_array_val); bt_value_put_ref(run_args); bt_value_put_ref(all_names); destroy_glist_of_gstring(source_names); destroy_glist_of_gstring(filter_names); destroy_glist_of_gstring(sink_names); - bt_value_put_ref(leftovers); + bt_value_put_ref(non_opt_params); + bt_value_put_ref(non_opt_loglevels); + bt_value_put_ref(non_opts); finalize_implicit_component_args(&implicit_ctf_output_args); finalize_implicit_component_args(&implicit_lttng_live_args); finalize_implicit_component_args(&implicit_dummy_args); @@ -4454,7 +4592,6 @@ end: finalize_implicit_component_args(&implicit_debug_info_args); finalize_implicit_component_args(&implicit_muxer_args); 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); @@ -4482,12 +4619,17 @@ void print_gen_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "General options:\n"); 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 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"); + fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=T)\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); + fprintf(fp, " -l, --log-level=LVL Set the default log level to LVL (`N`, `T`, `D`,\n"); + fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n"); + fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); + fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n"); + fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search 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, " -v, --verbose Enable verbose mode (same as --log-level=I)\n"); + fprintf(fp, " -V, --version Show version and quit\n"); fprintf(fp, "\n"); fprintf(fp, "Available commands:\n"); fprintf(fp, "\n"); @@ -4501,28 +4643,34 @@ void print_gen_usage(FILE *fp) } 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, - const bt_value *initial_plugin_paths) + int *retcode, bool omit_system_plugin_path, + bool omit_home_plugin_path, + const bt_value *initial_plugin_paths, + const bt_interrupter *interrupter) { struct bt_config *config = NULL; - int i; int top_level_argc; const char **top_level_argv; int command_argc = -1; const char **command_argv = NULL; const char *command_name = NULL; int default_log_level = -1; - struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; + struct argpar_iter *argpar_iter = NULL; + const struct argpar_item *argpar_item = NULL; + const struct argpar_error *argpar_error = NULL; + bt_value *plugin_paths = NULL; /* Top-level option descriptions. */ - static const struct bt_argpar_opt_descr descrs[] = { + static const struct argpar_opt_descr descrs[] = { { OPT_DEBUG, 'd', "debug", false }, { OPT_HELP, 'h', "help", false }, { OPT_LOG_LEVEL, 'l', "log-level", true }, { OPT_VERBOSE, 'v', "verbose", false }, { OPT_VERSION, 'V', "version", false}, - BT_ARGPAR_OPT_DESCR_SENTINEL + { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false }, + { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false }, + { OPT_PLUGIN_PATH, '\0', "plugin-path", true }, + ARGPAR_OPT_DESCR_SENTINEL }; enum command_type { @@ -4537,13 +4685,27 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], *retcode = -1; if (!initial_plugin_paths) { - initial_plugin_paths = bt_value_array_create(); - if (!initial_plugin_paths) { - *retcode = 1; - goto end; + plugin_paths = bt_value_array_create(); + if (!plugin_paths) { + goto error; } } else { - bt_value_get_ref(initial_plugin_paths); + bt_value_copy_status copy_status = bt_value_copy( + initial_plugin_paths, &plugin_paths); + if (copy_status) { + goto error; + } + } + + BT_ASSERT(plugin_paths); + + /* + * The `BABELTRACE_PLUGIN_PATH` paths take precedence over the + * `--plugin-path` option's paths, so append it now before + * parsing the general options. + */ + if (append_env_var_plugin_paths(plugin_paths)) { + goto error; } if (argc <= 1) { @@ -4556,78 +4718,130 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], /* Skip first argument, the name of the program. */ top_level_argc = argc - 1; top_level_argv = argv + 1; - argpar_parse_ret = bt_argpar_parse(top_level_argc, top_level_argv, - descrs, false); - if (argpar_parse_ret.error) { - BT_CLI_LOGE_APPEND_CAUSE( - "While parsing command-line arguments: %s", - argpar_parse_ret.error->str); + argpar_iter = argpar_iter_create(top_level_argc, top_level_argv, descrs); + if (!argpar_iter) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - for (i = 0; i < argpar_parse_ret.items->len; i++) { - struct bt_argpar_item *item; + while (true) { + enum argpar_iter_next_status status; - item = g_ptr_array_index(argpar_parse_ret.items, i); + ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item); + status = argpar_iter_next(argpar_iter, &argpar_item, &argpar_error); - if (item->type == BT_ARGPAR_ITEM_TYPE_OPT) { - struct bt_argpar_item_opt *item_opt = - (struct bt_argpar_item_opt *) item; + switch (status) { + case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY: + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + case ARGPAR_ITER_NEXT_STATUS_ERROR: + { + if (argpar_error_type(argpar_error) + != ARGPAR_ERROR_TYPE_UNKNOWN_OPT) { + GString *err_str = format_arg_error(argpar_error, top_level_argv, + "While parsing command-line arguments"); + BT_CLI_LOGE_APPEND_CAUSE("%s", err_str->str); + g_string_free(err_str, TRUE); + goto error; + } - switch (item_opt->descr->id) { - case OPT_DEBUG: - default_log_level = BT_LOG_TRACE; - break; - case OPT_VERBOSE: - /* - * 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, TRACE). - */ - default_log_level = BT_LOG_INFO; - break; - case OPT_LOG_LEVEL: - default_log_level = - bt_log_get_level_from_string(item_opt->arg); - if (default_log_level < 0) { - BT_CLI_LOGE_APPEND_CAUSE( - "Invalid argument for --log-level option:\n %s", - item_opt->arg); - goto error; - } - break; - case OPT_VERSION: - print_version(); - goto end; - case OPT_HELP: - print_gen_usage(stdout); - goto end; + break; + } + default: + break; + } + + if (status == ARGPAR_ITER_NEXT_STATUS_END) { + break; + } + + if (status == ARGPAR_ITER_NEXT_STATUS_ERROR) { + BT_ASSERT(argpar_error_type(argpar_error) == + ARGPAR_ERROR_TYPE_UNKNOWN_OPT); + /* + * Unknown option, assume this is implicitly the + * convert command, stop processing arguments. + */ + break; + } + + if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { + const struct argpar_opt_descr *opt_descr = + argpar_item_opt_descr(argpar_item); + const char *arg = argpar_item_opt_arg(argpar_item); + + switch (opt_descr->id) { + case OPT_DEBUG: + default_log_level = + logging_level_min(default_log_level, BT_LOG_TRACE); + break; + case OPT_VERBOSE: + default_log_level = + logging_level_min(default_log_level, BT_LOG_INFO); + break; + case OPT_LOG_LEVEL: + { + int level = bt_log_get_level_from_string(arg); + + if (level < 0) { + BT_CLI_LOGE_APPEND_CAUSE( + "Invalid argument for --log-level option:\n %s", + arg); + goto error; + } + + default_log_level = + logging_level_min(default_log_level, level); + break; + } + case OPT_PLUGIN_PATH: + if (bt_config_append_plugin_paths_check_setuid_setgid( + plugin_paths, arg)) { + goto error; + } + break; + case OPT_OMIT_SYSTEM_PLUGIN_PATH: + omit_system_plugin_path = true; + break; + case OPT_OMIT_HOME_PLUGIN_PATH: + omit_home_plugin_path = true; + break; + case OPT_VERSION: + print_version(); + goto end; + case OPT_HELP: + print_gen_usage(stdout); + goto end; + default: + bt_common_abort(); } - } else if (item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) { - struct bt_argpar_item_non_opt *item_non_opt = - (struct bt_argpar_item_non_opt *) item; + } else { + const char *arg = argpar_item_non_opt_arg(argpar_item); + unsigned int orig_index = argpar_item_non_opt_orig_index(argpar_item); + /* * First unknown argument: is it a known command * name? */ - command_argc = - top_level_argc - item_non_opt->orig_index - 1; - command_argv = - &top_level_argv[item_non_opt->orig_index + 1]; + command_argc = top_level_argc - orig_index - 1; + command_argv = &top_level_argv[orig_index + 1]; - if (strcmp(item_non_opt->arg, "convert") == 0) { + if (strcmp(arg, "convert") == 0) { command_type = COMMAND_TYPE_CONVERT; - } else if (strcmp(item_non_opt->arg, "list-plugins") == 0) { + command_name = "convert"; + } else if (strcmp(arg, "list-plugins") == 0) { command_type = COMMAND_TYPE_LIST_PLUGINS; - } else if (strcmp(item_non_opt->arg, "help") == 0) { + command_name = "list-plugins"; + } else if (strcmp(arg, "help") == 0) { command_type = COMMAND_TYPE_HELP; - } else if (strcmp(item_non_opt->arg, "query") == 0) { + command_name = "help"; + } else if (strcmp(arg, "query") == 0) { command_type = COMMAND_TYPE_QUERY; - } else if (strcmp(item_non_opt->arg, "run") == 0) { + command_name = "query"; + } else if (strcmp(arg, "run") == 0) { command_type = COMMAND_TYPE_RUN; + command_name = "run"; } else { /* * Non-option argument, but not a known @@ -4639,12 +4853,16 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], command_argc++; command_argv--; } + + /* Stop processing arguments. */ break; } } if (command_type == COMMAND_TYPE_NONE) { - if (argpar_parse_ret.ingested_orig_args == top_level_argc) { + unsigned int ingested_orig_args = argpar_iter_ingested_orig_args(argpar_iter); + + if (ingested_orig_args == top_level_argc) { /* * We only got non-help, non-version general options * like --verbose and --debug, without any other @@ -4661,57 +4879,64 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], */ command_type = COMMAND_TYPE_CONVERT; command_name = "convert"; - command_argc = - top_level_argc - argpar_parse_ret.ingested_orig_args; - command_argv = - &top_level_argv[argpar_parse_ret.ingested_orig_args]; + command_argc = top_level_argc - ingested_orig_args; + command_argv = &top_level_argv[ingested_orig_args]; } 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. + * For all commands other than `convert`, we now know the log level to + * use, so we can apply it with `set_auto_log_levels`. + * + * The convert command has `--debug` and `--verbose` arguments that are + * equivalent to the top-level arguments of the same name. So after it + * has parsed its arguments, `bt_config_convert_from_args` calls + * `set_auto_log_levels` itself. + */ + if (command_type != COMMAND_TYPE_CONVERT) { + set_auto_log_levels(&default_log_level); + } + + /* + * At this point, `plugin_paths` contains the initial plugin + * paths, the paths from the `BABELTRACE_PLUGIN_PATH` paths, and + * the paths from the `--plugin-path` option. + * + * Now append the user and system plugin paths. */ - if (command_type != COMMAND_TYPE_CONVERT && default_log_level < 0) { - /* Default log level */ - default_log_level = cli_default_log_level; + if (append_home_and_system_plugin_paths(plugin_paths, + omit_system_plugin_path, omit_home_plugin_path)) { + goto error; } 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, + retcode, 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, &default_log_level); + retcode, plugin_paths, &default_log_level, interrupter); break; case COMMAND_TYPE_LIST_PLUGINS: config = bt_config_list_plugins_from_args(command_argc, - command_argv, retcode, force_omit_system_plugin_path, - force_omit_home_plugin_path, initial_plugin_paths); + command_argv, retcode, plugin_paths); break; 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, + command_argv, retcode, 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, + command_argv, retcode, plugin_paths, default_log_level); break; default: - abort(); + bt_common_abort(); } if (config) { @@ -4726,7 +4951,9 @@ error: *retcode = 1; end: - bt_argpar_parse_ret_fini(&argpar_parse_ret); - bt_value_put_ref(initial_plugin_paths); + argpar_error_destroy(argpar_error); + argpar_item_destroy(argpar_item); + argpar_iter_destroy(argpar_iter); + bt_value_put_ref(plugin_paths); return config; }