X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fcli%2Fbabeltrace2-cfg-cli-args.c;h=81dd05bbb1ae856db79e8e2243a77524833c904f;hb=9701066527431ae10c70a05d7c92196f6dfd6e27;hp=7fc0488455b565b143ca9b8e9521d25d34d3130c;hpb=73760435c5a44d48313a85d94af093c293bc17ef;p=babeltrace.git diff --git a/src/cli/babeltrace2-cfg-cli-args.c b/src/cli/babeltrace2-cfg-cli-args.c index 7fc04884..81dd05bb 100644 --- a/src/cli/babeltrace2-cfg-cli-args.c +++ b/src/cli/babeltrace2-cfg-cli-args.c @@ -22,7 +22,7 @@ * SOFTWARE. */ -#define BT_LOG_TAG "CLI-CFG-CLI-ARGS" +#define BT_LOG_TAG "CLI/CFG-CLI-ARGS" #include "logging.h" #include @@ -34,15 +34,16 @@ #include #include #include "common/common.h" -#include #include #include +#include "argpar/argpar.h" #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 "babeltrace2-query.h" +#include "autodisc/autodisc.h" #include "common/version.h" static const int cli_default_log_level = BT_LOG_WARNING; @@ -506,7 +507,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); } @@ -855,7 +856,7 @@ end: return ret; } -/* popt options */ +/* argpar options */ enum { OPT_NONE = 0, OPT_BASE_PARAMS, @@ -881,7 +882,6 @@ enum { OPT_INPUT_FORMAT, OPT_LIST, OPT_LOG_LEVEL, - OPT_NAME, OPT_NAMES, OPT_NO_DELTA, OPT_OMIT_HOME_PLUGIN_PATH, @@ -889,7 +889,6 @@ enum { OPT_OUTPUT, OPT_OUTPUT_FORMAT, OPT_PARAMS, - OPT_PATH, OPT_PLUGIN_PATH, OPT_RESET_BASE_PARAMS, OPT_RETRY_DURATION, @@ -897,8 +896,8 @@ enum { OPT_RUN_ARGS_0, OPT_STREAM_INTERSECTION, OPT_TIMERANGE, - OPT_URL, OPT_VERBOSE, + OPT_VERSION, }; enum bt_config_component_dest { @@ -1342,6 +1341,31 @@ void print_expected_params_format(FILE *fp) fprintf(fp, "babeltrace2 from a shell.\n"); } +static +bool help_option_is_specified( + const struct bt_argpar_parse_ret *argpar_parse_ret) +{ + int i; + bool specified = false; + + 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; + + if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) { + continue; + } + + argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; + if (argpar_item_opt->descr->id == OPT_HELP) { + specified = true; + break; + } + } + + return specified; +} /* * Prints the help command usage. @@ -1367,13 +1391,13 @@ void print_help_usage(FILE *fp) } static -struct poptOption help_long_options[] = { - /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, 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 }, - { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, - { NULL, 0, '\0', NULL, 0, NULL, NULL }, +const struct bt_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 }; /* @@ -1388,13 +1412,11 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], bool force_omit_home_plugin_path, const bt_value *initial_plugin_paths, int default_log_level) { - poptContext pc = NULL; - char *arg = NULL; - int opt; - int ret; + int ret, i; struct bt_config *cfg = NULL; - const char *leftover; + const char *non_opt = NULL; char *plugin_name = NULL, *comp_cls_name = NULL; + struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; *retcode = 0; cfg = bt_config_help_create(initial_plugin_paths, default_log_level); @@ -1410,56 +1432,65 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], } /* Parse options */ - pc = poptGetContext(NULL, argc, (const char **) argv, - help_long_options, 0); - if (!pc) { - BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context."); + 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); goto error; } - poptReadDefaultConfig(pc, 0); + if (help_option_is_specified(&argpar_parse_ret)) { + print_help_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); - while ((opt = poptGetNextOpt(pc)) > 0) { - arg = poptGetOptArg(pc); + 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; - switch (opt) { - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - cfg->plugin_paths, arg)) { + 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; + default: + BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", + argpar_item_opt->descr->id); 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; - 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).", - opt); - goto error; - } + } else { + struct bt_argpar_item_non_opt *argpar_item_non_opt + = (struct bt_argpar_item_non_opt *) argpar_item; - free(arg); - arg = NULL; - } + if (non_opt) { + BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `help` command: `%s`.", + argpar_item_non_opt->arg); + goto error; + } - /* Check for option parsing error */ - if (opt < -1) { - BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: `%s`.", - poptBadOption(pc, 0), poptStrerror(opt)); - goto error; + non_opt = argpar_item_non_opt->arg; + } } - leftover = poptGetArg(pc); - if (leftover) { - plugin_comp_cls_names(leftover, NULL, + if (non_opt) { + plugin_comp_cls_names(non_opt, NULL, &plugin_name, &comp_cls_name, &cfg->cmd_data.help.cfg_component->type); if (plugin_name && comp_cls_name) { @@ -1474,7 +1505,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], /* Fall back to plugin help */ g_string_assign( cfg->cmd_data.help.cfg_component->plugin_name, - leftover); + non_opt); } } else { print_help_usage(stdout); @@ -1497,11 +1528,8 @@ end: g_free(plugin_name); g_free(comp_cls_name); - if (pc) { - poptFreeContext(pc); - } + bt_argpar_parse_ret_fini(&argpar_parse_ret); - free(arg); return cfg; } @@ -1528,14 +1556,14 @@ void print_query_usage(FILE *fp) } static -struct poptOption query_long_options[] = { - /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, 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 }, - { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL }, - { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, - { NULL, 0, '\0', NULL, 0, NULL, NULL }, +const struct bt_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 }; /* @@ -1551,14 +1579,13 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], const bt_value *initial_plugin_paths, int default_log_level) { - poptContext pc = NULL; - char *arg = NULL; - int opt; - int ret; + int ret, i; struct bt_config *cfg = NULL; - const char *leftover; + 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 = { 0 }; params = bt_value_null; bt_value_get_ref(bt_value_null); @@ -1583,110 +1610,106 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], } /* Parse options */ - pc = poptGetContext(NULL, argc, (const char **) argv, - query_long_options, 0); - if (!pc) { - BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context."); + 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); goto error; } - poptReadDefaultConfig(pc, 0); + if (help_option_is_specified(&argpar_parse_ret)) { + print_query_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; + } - while ((opt = poptGetNextOpt(pc)) > 0) { - arg = poptGetOptArg(pc); + 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); - switch (opt) { - case OPT_PLUGIN_PATH: - if (bt_config_append_plugin_paths_check_setuid_setgid( - cfg->plugin_paths, arg)) { + 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; + + 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; + case OPT_PARAMS: + { + bt_value_put_ref(params); + params = cli_value_from_arg(arg, error_str); + if (!params) { + BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s", + error_str->str); + goto error; + } + break; + } + default: + BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", + argpar_item_opt->descr->id); 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; - case OPT_PARAMS: - { - bt_value_put_ref(params); - params = cli_value_from_arg(arg, error_str); - if (!params) { - BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s", - error_str->str); + } else { + struct bt_argpar_item_non_opt *argpar_item_non_opt + = (struct bt_argpar_item_non_opt *) argpar_item; + + /* + * 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; + } else if (!query_object) { + query_object = argpar_item_non_opt->arg; + } else { + BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `query` command: `%s`.", + argpar_item_non_opt->arg); goto error; } - break; } - case OPT_HELP: - print_query_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).", - opt); - goto error; - } - - free(arg); - arg = NULL; - } - - /* Check for option parsing error */ - if (opt < -1) { - BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: `%s`.", - poptBadOption(pc, 0), poptStrerror(opt)); - goto error; } - /* - * We need exactly two leftover arguments which are the - * mandatory component class specification and query object. - */ - leftover = poptGetArg(pc); - if (leftover) { - cfg->cmd_data.query.cfg_component = - bt_config_component_from_arg(leftover, - default_log_level); - if (!cfg->cmd_data.query.cfg_component) { - BT_CLI_LOGE_APPEND_CAUSE("Invalid format for component class specification:\n %s", - leftover); - goto error; - } - - BT_ASSERT(params); - BT_OBJECT_MOVE_REF(cfg->cmd_data.query.cfg_component->params, - params); - } else { + if (!component_class_spec || !query_object) { print_query_usage(stdout); *retcode = -1; BT_OBJECT_PUT_REF_AND_RESET(cfg); goto end; } - leftover = poptGetArg(pc); - if (leftover) { - if (strlen(leftover) == 0) { - BT_CLI_LOGE_APPEND_CAUSE("Invalid empty object."); - goto error; - } - - g_string_assign(cfg->cmd_data.query.object, leftover); - } else { - print_query_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; + cfg->cmd_data.query.cfg_component = + bt_config_component_from_arg(component_class_spec, + default_log_level); + if (!cfg->cmd_data.query.cfg_component) { + BT_CLI_LOGE_APPEND_CAUSE("Invalid format for component class specification:\n %s", + component_class_spec); + goto error; } - leftover = poptGetArg(pc); - if (leftover) { - BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.", leftover); + BT_ASSERT(params); + BT_OBJECT_MOVE_REF(cfg->cmd_data.query.cfg_component->params, params); + + if (strlen(query_object) == 0) { + BT_CLI_LOGE_APPEND_CAUSE("Invalid empty object."); goto error; } + g_string_assign(cfg->cmd_data.query.object, query_object); + if (append_home_and_system_plugin_paths_cfg(cfg)) { goto error; } @@ -1698,16 +1721,13 @@ error: BT_OBJECT_PUT_REF_AND_RESET(cfg); end: - if (pc) { - poptFreeContext(pc); - } + bt_argpar_parse_ret_fini(&argpar_parse_ret); if (error_str) { g_string_free(error_str, TRUE); } bt_value_put_ref(params); - free(arg); return cfg; } @@ -1734,13 +1754,13 @@ void print_list_plugins_usage(FILE *fp) } static -struct poptOption list_plugins_long_options[] = { - /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, 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 }, - { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, - { NULL, 0, '\0', NULL, 0, NULL, NULL }, +const struct bt_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 }; /* @@ -1755,12 +1775,9 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[], bool force_omit_home_plugin_path, const bt_value *initial_plugin_paths) { - poptContext pc = NULL; - char *arg = NULL; - int opt; - int ret; + int ret, i; struct bt_config *cfg = NULL; - const char *leftover; + struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; *retcode = 0; cfg = bt_config_list_plugins_create(initial_plugin_paths); @@ -1776,19 +1793,40 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[], } /* Parse options */ - pc = poptGetContext(NULL, argc, (const char **) argv, - list_plugins_long_options, 0); - if (!pc) { - BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context."); + 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; } - poptReadDefaultConfig(pc, 0); + 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; + + BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.", + argpar_item_non_opt->arg); + goto error; + } - while ((opt = poptGetNextOpt(pc)) > 0) { - arg = poptGetOptArg(pc); + argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; + arg = argpar_item_opt->arg; - switch (opt) { + switch (argpar_item_opt->descr->id) { case OPT_PLUGIN_PATH: if (bt_config_append_plugin_paths_check_setuid_setgid( cfg->plugin_paths, arg)) { @@ -1801,32 +1839,11 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[], case OPT_OMIT_HOME_PLUGIN_PATH: cfg->omit_home_plugin_path = true; break; - case OPT_HELP: - print_list_plugins_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).", - opt); + argpar_item_opt->descr->id); goto error; } - - free(arg); - arg = NULL; - } - - /* Check for option parsing error */ - if (opt < -1) { - 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) { - BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.", leftover); - goto error; } if (append_home_and_system_plugin_paths_cfg(cfg)) { @@ -1840,11 +1857,8 @@ error: BT_OBJECT_PUT_REF_AND_RESET(cfg); end: - if (pc) { - poptFreeContext(pc); - } + bt_argpar_parse_ret_fini(&argpar_parse_ret); - free(arg); return cfg; } @@ -1862,19 +1876,15 @@ void print_run_usage(FILE *fp) fprintf(fp, " for all the following components until\n"); fprintf(fp, " --reset-base-params is encountered\n"); fprintf(fp, " (see the expected format of PARAMS below)\n"); - fprintf(fp, " -c, --component=[NAME:]TYPE.PLUGIN.CLS\n"); + fprintf(fp, " -c, --component=NAME:TYPE.PLUGIN.CLS\n"); fprintf(fp, " Instantiate the component class CLS of type\n"); fprintf(fp, " TYPE (`source`, `filter`, or `sink`) found\n"); fprintf(fp, " in the plugin PLUGIN, add it to the graph,\n"); - fprintf(fp, " and optionally name it NAME (you can also\n"); - fprintf(fp, " specify the name with --name)\n"); + fprintf(fp, " and name it NAME"); 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"); 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"); @@ -1899,8 +1909,8 @@ void print_run_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "UPSTREAM and DOWNSTREAM are names of the upstream and downstream\n"); fprintf(fp, "components to connect together. You must escape the following characters\n\n"); - fprintf(fp, "with `\\`: `\\`, `.`, and `:`. You can set the name of the current\n"); - fprintf(fp, "component with the --name option.\n"); + fprintf(fp, "with `\\`: `\\`, `.`, and `:`. You must set the name of the current\n"); + fprintf(fp, "component using the NAME prefix of the --component option.\n"); fprintf(fp, "\n"); fprintf(fp, "UPSTREAM-PORT and DOWNSTREAM-PORT are optional globbing patterns to\n"); fprintf(fp, "identify the upstream and downstream ports to use for the connection.\n"); @@ -1941,13 +1951,9 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], bool force_omit_home_plugin_path, const bt_value *initial_plugin_paths, int default_log_level) { - poptContext pc = NULL; - char *arg = NULL; struct bt_config_component *cur_cfg_comp = NULL; - enum bt_config_component_dest cur_cfg_comp_dest = - BT_CONFIG_COMPONENT_DEST_UNKNOWN; bt_value *cur_base_params = NULL; - int opt, ret = 0; + int ret = 0; struct bt_config *cfg = NULL; bt_value *instance_names = NULL; bt_value *connection_args = NULL; @@ -1955,20 +1961,22 @@ 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 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 }, - { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL }, - { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, - { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL }, - { "retry-duration", '\0', POPT_ARG_LONG, &retry_duration, OPT_RETRY_DURATION, NULL, NULL }, - { NULL, 0, '\0', NULL, 0, NULL, NULL }, + struct bt_argpar_parse_ret argpar_parse_ret = { 0 }; + int i; + + static const struct bt_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 }; *retcode = 0; @@ -1979,7 +1987,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } - if (argc <= 1) { + if (argc < 1) { print_run_usage(stdout); *retcode = -1; goto end; @@ -2017,19 +2025,41 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], } /* Parse options */ - pc = poptGetContext(NULL, argc, (const char **) argv, - run_long_options, 0); - if (!pc) { - BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context."); + 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); goto error; } - poptReadDefaultConfig(pc, 0); + 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; + const char *arg; + + /* This command does not accept non-option 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; + + BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`", + argpar_nonopt_item->arg); + goto error; + } - while ((opt = poptGetNextOpt(pc)) > 0) { - arg = poptGetOptArg(pc); + argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; + arg = argpar_item_opt->arg; - switch (opt) { + switch (argpar_item_opt->descr->id) { case OPT_PLUGIN_PATH: if (bt_config_append_plugin_paths_check_setuid_setgid( cfg->plugin_paths, arg)) { @@ -2044,18 +2074,9 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], break; case OPT_COMPONENT: { - enum bt_config_component_dest new_dest; - - if (cur_cfg_comp) { - ret = add_run_cfg_comp_check_name(cfg, - cur_cfg_comp, cur_cfg_comp_dest, - instance_names); - BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp); - if (ret) { - goto error; - } - } + enum bt_config_component_dest dest; + BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp); cur_cfg_comp = bt_config_component_from_arg(arg, default_log_level); if (!cur_cfg_comp) { @@ -2066,13 +2087,13 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], switch (cur_cfg_comp->type) { case BT_COMPONENT_CLASS_TYPE_SOURCE: - new_dest = BT_CONFIG_COMPONENT_DEST_SOURCE; + dest = BT_CONFIG_COMPONENT_DEST_SOURCE; break; case BT_COMPONENT_CLASS_TYPE_FILTER: - new_dest = BT_CONFIG_COMPONENT_DEST_FILTER; + dest = BT_CONFIG_COMPONENT_DEST_FILTER; break; case BT_COMPONENT_CLASS_TYPE_SINK: - new_dest = BT_CONFIG_COMPONENT_DEST_SINK; + dest = BT_CONFIG_COMPONENT_DEST_SINK; break; default: abort(); @@ -2086,7 +2107,13 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } - cur_cfg_comp_dest = new_dest; + ret = add_run_cfg_comp_check_name(cfg, + cur_cfg_comp, dest, + instance_names); + if (ret) { + goto error; + } + break; } case OPT_PARAMS: @@ -2119,15 +2146,6 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], BT_OBJECT_MOVE_REF(cur_cfg_comp->params, params_to_set); break; } - case OPT_NAME: - if (!cur_cfg_comp) { - 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", @@ -2171,7 +2189,19 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], goto error; } break; - case OPT_RETRY_DURATION: + case OPT_RETRY_DURATION: { + gchar *end; + size_t arg_len = strlen(argpar_item_opt->arg); + + retry_duration = g_ascii_strtoll(argpar_item_opt->arg, &end, 10); + + if (arg_len == 0 || end != (argpar_item_opt->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); + goto error; + } + if (retry_duration < 0) { BT_CLI_LOGE_APPEND_CAUSE("--retry-duration option's argument must be positive or 0: %ld", retry_duration); @@ -2181,43 +2211,15 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[], cfg->cmd_data.run.retry_duration_us = (uint64_t) retry_duration; break; - case OPT_HELP: - print_run_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).", - opt); + argpar_item_opt->descr->id); goto error; } - - free(arg); - arg = NULL; - } - - /* Check for option parsing error */ - if (opt < -1) { - 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)) { - BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: %s", poptPeekArg(pc)); - goto error; - } - - /* Add current component */ - if (cur_cfg_comp) { - ret = add_run_cfg_comp_check_name(cfg, cur_cfg_comp, - cur_cfg_comp_dest, instance_names); - BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp); - if (ret) { - goto error; - } - } + BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp); if (cfg->cmd_data.run.sources->len == 0) { BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no source component."); @@ -2248,15 +2250,11 @@ error: BT_OBJECT_PUT_REF_AND_RESET(cfg); end: - if (pc) { - poptFreeContext(pc); - } - if (error_str) { g_string_free(error_str, TRUE); } - free(arg); + bt_argpar_parse_ret_fini(&argpar_parse_ret); 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); @@ -2273,7 +2271,7 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args, struct bt_config *cfg = NULL; const char **argv; int64_t i, len; - const size_t argc = bt_value_array_get_size(run_args) + 1; + const size_t argc = bt_value_array_get_size(run_args); argv = calloc(argc, sizeof(*argv)); if (!argv) { @@ -2281,8 +2279,6 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args, goto end; } - argv[0] = "run"; - len = bt_value_array_get_size(run_args); if (len < 0) { BT_CLI_LOGE_APPEND_CAUSE("Invalid executable arguments."); @@ -2297,7 +2293,7 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args, BT_ASSERT(arg_value); arg = bt_value_string_get(arg_value); BT_ASSERT(arg); - argv[i + 1] = arg; + argv[i] = arg; } cfg = bt_config_run_from_args(argc, argv, retcode, @@ -2324,21 +2320,15 @@ void print_convert_usage(FILE *fp) fprintf(fp, " TYPE (`source`, `filter`, or `sink`) found\n"); fprintf(fp, " in the plugin PLUGIN, add it to the\n"); 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, " 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"); 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 Add initialization parameters PARAMS to the\n"); fprintf(fp, " current component (see the expected format\n"); fprintf(fp, " of PARAMS below)\n"); - 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"); @@ -2353,8 +2343,6 @@ void print_convert_usage(FILE *fp) fprintf(fp, " formatted for `xargs -0`, and quit\n"); fprintf(fp, " --stream-intersection Only process events when all streams\n"); fprintf(fp, " are active\n"); - fprintf(fp, " -u, --url=URL Set the `url` string parameter of the\n"); - fprintf(fp, " current component to URL\n"); fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "Implicit `source.ctf.fs` component options:\n"); @@ -2449,46 +2437,43 @@ void print_convert_usage(FILE *fp) } static -struct poptOption convert_long_options[] = { - /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - { "begin", 'b', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL }, - { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL }, - { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL }, - { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL }, - { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL }, - { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL }, - { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL }, - { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL }, - { "color", '\0', POPT_ARG_STRING, NULL, OPT_COLOR, NULL, NULL }, - { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL }, - { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL }, - { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL }, - { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL }, - { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL }, - { "end", 'e', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL }, - { "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 }, - { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, 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 }, - { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT, NULL, NULL }, - { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL }, - { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL }, - { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL }, - { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, - { "retry-duration", '\0', POPT_ARG_STRING, NULL, OPT_RETRY_DURATION, NULL, NULL }, - { "run-args", '\0', POPT_ARG_NONE, NULL, OPT_RUN_ARGS, NULL, NULL }, - { "run-args-0", '\0', POPT_ARG_NONE, NULL, OPT_RUN_ARGS_0, NULL, NULL }, - { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL }, - { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL }, - { "url", 'u', POPT_ARG_STRING, NULL, OPT_URL, NULL, NULL }, - { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL }, - { NULL, 0, '\0', NULL, 0, NULL, NULL }, +const struct bt_argpar_opt_descr convert_options[] = { + /* id, short_name, long_name, with_arg */ + { OPT_BEGIN, 'b', "begin", true }, + { OPT_CLOCK_CYCLES, '\0', "clock-cycles", false }, + { OPT_CLOCK_DATE, '\0', "clock-date", false }, + { OPT_CLOCK_FORCE_CORRELATE, '\0', "clock-force-correlate", false }, + { OPT_CLOCK_GMT, '\0', "clock-gmt", false }, + { OPT_CLOCK_OFFSET, '\0', "clock-offset", true }, + { OPT_CLOCK_OFFSET_NS, '\0', "clock-offset-ns", true }, + { OPT_CLOCK_SECONDS, '\0', "clock-seconds", false }, + { OPT_COLOR, '\0', "color", true }, + { OPT_COMPONENT, 'c', "component", true }, + { OPT_DEBUG, 'd', "debug", false }, + { OPT_DEBUG_INFO_DIR, '\0', "debug-info-dir", true }, + { OPT_DEBUG_INFO_FULL_PATH, '\0', "debug-info-full-path", false }, + { OPT_DEBUG_INFO_TARGET_PREFIX, '\0', "debug-info-target-prefix", true }, + { OPT_END, 'e', "end", true }, + { OPT_FIELDS, 'f', "fields", true }, + { OPT_HELP, 'h', "help", false }, + { OPT_INPUT_FORMAT, 'i', "input-format", true }, + { OPT_LOG_LEVEL, 'l', "log-level", true }, + { OPT_NAMES, 'n', "names", true }, + { OPT_DEBUG_INFO, '\0', "debug-info", false }, + { OPT_NO_DELTA, '\0', "no-delta", false }, + { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false }, + { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false }, + { OPT_OUTPUT, 'w', "output", true }, + { OPT_OUTPUT_FORMAT, 'o', "output-format", true }, + { OPT_PARAMS, 'p', "params", true }, + { OPT_PLUGIN_PATH, '\0', "plugin-path", true }, + { OPT_RETRY_DURATION, '\0', "retry-duration", true }, + { OPT_RUN_ARGS, '\0', "run-args", false }, + { OPT_RUN_ARGS_0, '\0', "run-args-0", false }, + { OPT_STREAM_INTERSECTION, '\0', "stream-intersection", false }, + { OPT_TIMERANGE, '\0', "timerange", true }, + { OPT_VERBOSE, 'v', "verbose", false }, + BT_ARGPAR_OPT_DESCR_SENTINEL }; static @@ -2579,27 +2564,31 @@ int append_run_args_for_implicit_component( { int ret = 0; size_t i; + GString *component_arg_for_run = NULL; if (!impl_args->exists) { goto end; } - if (bt_value_array_append_string_element(run_args, "--component")) { + component_arg_for_run = g_string_new(NULL); + if (!component_arg_for_run) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (bt_value_array_append_string_element(run_args, impl_args->comp_arg->str)) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } + /* Build the full `name:type.plugin.cls`. */ + BT_ASSERT(!strchr(impl_args->name_arg->str, '\\')); + BT_ASSERT(!strchr(impl_args->name_arg->str, ':')); + g_string_printf(component_arg_for_run, "%s:%s", + impl_args->name_arg->str, impl_args->comp_arg->str); - if (bt_value_array_append_string_element(run_args, "--name")) { + if (bt_value_array_append_string_element(run_args, "--component")) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (bt_value_array_append_string_element(run_args, impl_args->name_arg->str)) { + if (bt_value_array_append_string_element(run_args, + component_arg_for_run->str)) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } @@ -2643,6 +2632,10 @@ error: ret = -1; end: + if (component_arg_for_run) { + g_string_free(component_arg_for_run, TRUE); + } + return ret; } @@ -2967,103 +2960,6 @@ int append_implicit_component_extra_param(struct implicit_component_args *args, return append_string_parameter_to_args(args->extra_params, key, value); } -static -int convert_append_name_param(enum bt_config_component_dest dest, - GString *cur_name, GString *cur_name_prefix, - bt_value *run_args, - bt_value *all_names, - GList **source_names, GList **filter_names, - GList **sink_names) -{ - int ret = 0; - - if (cur_name_prefix->len > 0) { - /* We're after a --component option */ - GString *name = NULL; - bool append_name_opt = false; - - if (cur_name->len == 0) { - /* - * No explicit name was provided for the user - * component. - */ - name = get_component_auto_name(cur_name_prefix->str, - all_names); - append_name_opt = true; - } else { - /* - * An explicit name was provided for the user - * component. - */ - if (bt_value_map_has_entry(all_names, - cur_name->str)) { - BT_CLI_LOGE_APPEND_CAUSE("Duplicate component instance name:\n %s", - cur_name->str); - goto error; - } - - name = g_string_new(cur_name->str); - } - - if (!name) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - - /* - * Remember this name globally, for the uniqueness of - * all component names. - */ - if (bt_value_map_insert_entry(all_names, name->str, bt_value_null)) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - - /* - * Append the --name option if necessary. - */ - if (append_name_opt) { - if (bt_value_array_append_string_element(run_args, "--name")) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - - if (bt_value_array_append_string_element(run_args, name->str)) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - } - - /* - * Remember this name specifically for the type of the - * component. This is to create connection arguments. - */ - switch (dest) { - case BT_CONFIG_COMPONENT_DEST_SOURCE: - *source_names = g_list_append(*source_names, name); - break; - case BT_CONFIG_COMPONENT_DEST_FILTER: - *filter_names = g_list_append(*filter_names, name); - break; - case BT_CONFIG_COMPONENT_DEST_SINK: - *sink_names = g_list_append(*sink_names, name); - break; - default: - abort(); - } - - g_string_assign(cur_name_prefix, ""); - } - - goto end; - -error: - ret = -1; - -end: - return ret; -} - /* * Escapes `.`, `:`, and `\` of `input` with `\`. */ @@ -3162,7 +3058,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; @@ -3177,7 +3073,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; @@ -3189,7 +3085,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; @@ -3281,13 +3177,27 @@ 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_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_opt_params, + const bt_value *non_opt_loglevels, + GPtrArray *component_args) { gchar *cc_name = NULL; struct implicit_component_args *comp = NULL; @@ -3299,36 +3209,123 @@ 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_size(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_size(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; + } + } } 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; } +/* + * As we iterate the arguments to the convert command, this tracks what is the + * type of the current item, to which some contextual options (e.g. --params) + * apply to. + */ +enum convert_current_item_type { + /* There is no current item. */ + CONVERT_CURRENT_ITEM_TYPE_NONE, + + /* Current item is a component. */ + CONVERT_CURRENT_ITEM_TYPE_COMPONENT, + + /* Current item is a non-option argument. */ + CONVERT_CURRENT_ITEM_TYPE_NON_OPT, +}; + /* * Creates a Babeltrace config object from the arguments of a convert * command. @@ -3341,20 +3338,15 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], bool force_omit_home_plugin_path, const bt_value *initial_plugin_paths, int *default_log_level) { - poptContext pc = NULL; - char *arg = NULL; - enum bt_config_component_dest cur_comp_dest = - BT_CONFIG_COMPONENT_DEST_UNKNOWN; - int opt, ret = 0; + enum convert_current_item_type current_item_type = + CONVERT_CURRENT_ITEM_TYPE_NONE; + int ret = 0; struct bt_config *cfg = NULL; bool got_input_format_opt = false; bool got_output_format_opt = false; bool trimmer_has_begin = false; bool trimmer_has_end = false; bool stream_intersection_mode = false; - GString *cur_name = NULL; - GString *cur_name_prefix = NULL; - const char *leftover = NULL; bool print_run_args = false; bool print_run_args_0 = false; bool print_ctf_metadata = false; @@ -3363,7 +3355,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 }; @@ -3378,6 +3372,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], 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 }; + GString *name_gstr = NULL; + GString *component_arg_for_run = NULL; /* * Array of `struct implicit_component_args *` created for the sources @@ -3399,7 +3396,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], *retcode = 0; - if (argc <= 1) { + if (argc < 1) { print_convert_usage(stdout); *retcode = -1; goto end; @@ -3452,25 +3449,31 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - cur_name = g_string_new(NULL); - if (!cur_name) { + component_arg_for_run = g_string_new(NULL); + if (!component_arg_for_run) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - cur_name_prefix = g_string_new(NULL); - if (!cur_name_prefix) { + ret = append_env_var_plugin_paths(plugin_paths); + if (ret) { + goto error; + } + + non_opts = bt_value_array_create(); + if (!non_opts) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - ret = append_env_var_plugin_paths(plugin_paths); - if (ret) { + non_opt_params = bt_value_array_create(); + if (!non_opt_params) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - leftovers = bt_value_array_create(); - if (!leftovers) { + non_opt_loglevels = bt_value_array_create(); + if (!non_opt_loglevels) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } @@ -3496,304 +3499,336 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * First pass: collect all arguments which need to be passed * as is to the run command. This pass can also add --name * arguments if needed to automatically name unnamed component - * instances. Also it does the following transformations: - * - * --path=PATH -> --params=path="PATH" - * --url=URL -> --params=url="URL" + * instances. * * Also it appends the plugin paths of --plugin-path to * `plugin_paths`. */ - pc = poptGetContext(NULL, argc, (const char **) argv, - convert_long_options, 0); - if (!pc) { - BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context."); + 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); goto error; } - poptReadDefaultConfig(pc, 0); + if (help_option_is_specified(&argpar_parse_ret)) { + print_convert_usage(stdout); + *retcode = -1; + BT_OBJECT_PUT_REF_AND_RESET(cfg); + goto end; + } - while ((opt = poptGetNextOpt(pc)) > 0) { + 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; char *name = NULL; char *plugin_name = NULL; char *comp_cls_name = NULL; + const char *arg; - arg = poptGetOptArg(pc); + if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) { + argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; + arg = argpar_item_opt->arg; - switch (opt) { - case OPT_COMPONENT: - { - bt_component_class_type type; - const char *type_prefix; + switch (argpar_item_opt->descr->id) { + case OPT_COMPONENT: + { + bt_component_class_type type; - /* Append current component's name if needed */ - ret = convert_append_name_param(cur_comp_dest, cur_name, - cur_name_prefix, run_args, all_names, - &source_names, &filter_names, &sink_names); - if (ret) { - goto error; - } + current_item_type = CONVERT_CURRENT_ITEM_TYPE_COMPONENT; - /* Parse the argument */ - plugin_comp_cls_names(arg, &name, &plugin_name, - &comp_cls_name, &type); - if (!plugin_name || !comp_cls_name) { - BT_CLI_LOGE_APPEND_CAUSE( - "Invalid format for --component option's argument:\n %s", - arg); - goto error; - } - - if (name) { - g_string_assign(cur_name, name); - } else { - g_string_assign(cur_name, ""); - } - - switch (type) { - case BT_COMPONENT_CLASS_TYPE_SOURCE: - cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE; - type_prefix = "source"; - break; - case BT_COMPONENT_CLASS_TYPE_FILTER: - cur_comp_dest = BT_CONFIG_COMPONENT_DEST_FILTER; - type_prefix = "filter"; - break; - case BT_COMPONENT_CLASS_TYPE_SINK: - cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK; - type_prefix = "sink"; - break; - default: - abort(); - } - - if (bt_value_array_append_string_element(run_args, - "--component")) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } + /* Parse the argument */ + plugin_comp_cls_names(arg, &name, &plugin_name, + &comp_cls_name, &type); + if (!plugin_name || !comp_cls_name) { + BT_CLI_LOGE_APPEND_CAUSE( + "Invalid format for --component option's argument:\n %s", + arg); + goto error; + } - if (bt_value_array_append_string_element(run_args, arg)) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } + if (name) { + /* + * Name was given by the user, verify it isn't + * taken. + */ + if (bt_value_map_has_entry(all_names, name)) { + BT_CLI_LOGE_APPEND_CAUSE( + "Duplicate component instance name:\n %s", + name); + goto error; + } + + name_gstr = g_string_new(name); + if (!name_gstr) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + + g_string_assign(component_arg_for_run, arg); + } else { + /* Name not given by user, generate one. */ + name_gstr = get_component_auto_name(arg, all_names); + if (!name_gstr) { + goto error; + } + + g_string_printf(component_arg_for_run, "%s:%s", + name_gstr->str, arg); + } - g_string_assign(cur_name_prefix, ""); - g_string_append_printf(cur_name_prefix, "%s.%s.%s", - type_prefix, plugin_name, comp_cls_name); - free(name); - free(plugin_name); - free(comp_cls_name); - name = NULL; - plugin_name = NULL; - comp_cls_name = NULL; - break; - } - case OPT_PARAMS: - if (cur_name_prefix->len == 0) { - 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, + "--component")) { + 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, + component_arg_for_run->str)) { + 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_PATH: - if (cur_name_prefix->len == 0) { - BT_CLI_LOGE_APPEND_CAUSE("No current component of which to set `path` parameter:\n %s", - arg); - goto error; - } + /* + * Remember this name globally, for the uniqueness of + * all component names. + */ + if (bt_value_map_insert_entry(all_names, + name_gstr->str, bt_value_null)) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } - if (append_string_parameter_to_args(run_args, "path", arg)) { - goto error; - } - break; - case OPT_URL: - if (cur_name_prefix->len == 0) { - BT_CLI_LOGE_APPEND_CAUSE("No current component of which to set `url` parameter:\n %s", - arg); - goto error; + /* + * Remember this name specifically for the type of the + * component. This is to create connection arguments. + * + * The list takes ownership of `name_gstr`. + */ + switch (type) { + case BT_COMPONENT_CLASS_TYPE_SOURCE: + source_names = g_list_append(source_names, name_gstr); + break; + case BT_COMPONENT_CLASS_TYPE_FILTER: + filter_names = g_list_append(filter_names, name_gstr); + break; + case BT_COMPONENT_CLASS_TYPE_SINK: + sink_names = g_list_append(sink_names, name_gstr); + break; + default: + abort(); + } + name_gstr = NULL; + + free(name); + free(plugin_name); + free(comp_cls_name); + name = NULL; + plugin_name = NULL; + comp_cls_name = NULL; + break; } + case OPT_PARAMS: + 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, 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; + uint64_t idx = bt_value_array_get_size(non_opt_params) - 1; + + array = bt_value_array_borrow_element_by_index(non_opt_params, idx); + bt_value_array_append_string_element(array, arg); + } else { + BT_CLI_LOGE_APPEND_CAUSE( + "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, 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_size(non_opt_loglevels) - 1; + bt_value *log_level_str_value; + + 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_set_element_by_index(non_opt_loglevels, idx, + log_level_str_value)) { + bt_value_put_ref(log_level_str_value); + 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_OMIT_HOME_PLUGIN_PATH: + force_omit_home_plugin_path = true; - if (append_string_parameter_to_args(run_args, "url", arg)) { - goto error; - } - break; - case OPT_NAME: - if (cur_name_prefix->len == 0) { - 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")) { - 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(); + goto error; + } + break; + case OPT_RETRY_DURATION: + if (bt_value_array_append_string_element(run_args, + "--retry-duration")) { + 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; + } + break; + case OPT_OMIT_SYSTEM_PLUGIN_PATH: + force_omit_system_plugin_path = true; - 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, + "--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, "--log-level")) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - 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(); + if (bt_value_array_append_string_element(run_args, arg)) { + BT_CLI_LOGE_APPEND_CAUSE_OOM(); + goto error; + } + break; + case OPT_BEGIN: + case OPT_CLOCK_CYCLES: + case OPT_CLOCK_DATE: + case OPT_CLOCK_FORCE_CORRELATE: + case OPT_CLOCK_GMT: + case OPT_CLOCK_OFFSET: + case OPT_CLOCK_OFFSET_NS: + case OPT_CLOCK_SECONDS: + case OPT_COLOR: + case OPT_DEBUG: + case OPT_DEBUG_INFO: + case OPT_DEBUG_INFO_DIR: + case OPT_DEBUG_INFO_FULL_PATH: + case OPT_DEBUG_INFO_TARGET_PREFIX: + case OPT_END: + case OPT_FIELDS: + case OPT_INPUT_FORMAT: + case OPT_NAMES: + case OPT_NO_DELTA: + case OPT_OUTPUT_FORMAT: + case OPT_OUTPUT: + case OPT_RUN_ARGS: + case OPT_RUN_ARGS_0: + case OPT_STREAM_INTERSECTION: + case OPT_TIMERANGE: + case OPT_VERBOSE: + /* 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; } + } else if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) { + struct bt_argpar_item_non_opt *argpar_item_non_opt; + bt_value_array_append_element_status append_status; - break; - case OPT_OMIT_HOME_PLUGIN_PATH: - force_omit_home_plugin_path = true; + current_item_type = CONVERT_CURRENT_ITEM_TYPE_NON_OPT; - if (bt_value_array_append_string_element(run_args, - "--omit-home-plugin-path")) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - goto error; - } - break; - case OPT_RETRY_DURATION: - if (bt_value_array_append_string_element(run_args, - "--retry-duration")) { - 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_SYSTEM_PLUGIN_PATH: - force_omit_system_plugin_path = true; + argpar_item_non_opt = (struct bt_argpar_item_non_opt *) argpar_item; - if (bt_value_array_append_string_element(run_args, - "--omit-system-plugin-path")) { + append_status = bt_value_array_append_string_element(non_opts, + argpar_item_non_opt->arg); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { 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")) { + append_status = bt_value_array_append_empty_array_element(non_opt_params); + if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { BT_CLI_LOGE_APPEND_CAUSE_OOM(); goto error; } - if (bt_value_array_append_string_element(run_args, arg)) { + 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; } - break; - case OPT_HELP: - print_convert_usage(stdout); - *retcode = -1; - BT_OBJECT_PUT_REF_AND_RESET(cfg); - goto end; - case OPT_BEGIN: - case OPT_CLOCK_CYCLES: - case OPT_CLOCK_DATE: - case OPT_CLOCK_FORCE_CORRELATE: - case OPT_CLOCK_GMT: - case OPT_CLOCK_OFFSET: - case OPT_CLOCK_OFFSET_NS: - case OPT_CLOCK_SECONDS: - case OPT_COLOR: - case OPT_DEBUG: - case OPT_DEBUG_INFO: - case OPT_DEBUG_INFO_DIR: - case OPT_DEBUG_INFO_FULL_PATH: - case OPT_DEBUG_INFO_TARGET_PREFIX: - case OPT_END: - case OPT_FIELDS: - case OPT_INPUT_FORMAT: - case OPT_NAMES: - case OPT_NO_DELTA: - case OPT_OUTPUT_FORMAT: - case OPT_OUTPUT: - case OPT_RUN_ARGS: - case OPT_RUN_ARGS_0: - case OPT_STREAM_INTERSECTION: - case OPT_TIMERANGE: - case OPT_VERBOSE: - /* Ignore in this pass */ - break; - default: - BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).", - opt); - goto error; + } else { + abort(); } - - free(arg); - arg = NULL; - } - - /* Append current component's name if needed */ - ret = convert_append_name_param(cur_comp_dest, cur_name, - cur_name_prefix, run_args, all_names, &source_names, - &filter_names, &sink_names); - if (ret) { - goto error; } - /* Check for option parsing error */ - if (opt < -1) { - BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option `%s`: %s.", - poptBadOption(pc, 0), poptStrerror(opt)); - goto error; - } - - poptFreeContext(pc); - free(arg); - arg = NULL; - /* * Second pass: transform the convert-specific options and * arguments into implicit component instances for the run * command. */ - pc = poptGetContext(NULL, argc, (const char **) argv, - convert_long_options, 0); - if (!pc) { - BT_CLI_LOGE_APPEND_CAUSE("Cannot get popt context."); - goto error; - } + 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; - poptReadDefaultConfig(pc, 0); + if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) { + continue; + } - while ((opt = poptGetNextOpt(pc)) > 0) { - arg = poptGetOptArg(pc); + argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item; + arg = argpar_item_opt->arg; - switch (opt) { + switch (argpar_item_opt->descr->id) { case OPT_BEGIN: if (trimmer_has_begin) { printf("At --begin option: --begin or --timerange option already specified\n %s\n", @@ -4052,8 +4087,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], break; case OPT_STREAM_INTERSECTION: /* - * Applies to all traces implementing the trace-info - * query. + * Applies to all traces implementing the + * babeltrace.trace-info query. */ stream_intersection_mode = true; break; @@ -4069,16 +4104,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], default: break; } - - free(arg); - arg = NULL; - } - - /* Check for option parsing error */ - if (opt < -1) { - BT_CLI_LOGE_APPEND_CAUSE("While parsing command-line options, at option %s: %s", - poptBadOption(pc, 0), poptStrerror(opt)); - goto error; } /* @@ -4102,25 +4127,16 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - /* Consume and keep leftover arguments */ - while ((leftover = poptGetArg(pc))) { - if (bt_value_array_append_string_element(leftovers, leftover) != - BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { - BT_CLI_LOGE_APPEND_CAUSE_OOM(); - 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_size(non_opts) > 1) { BT_CLI_LOGE_APPEND_CAUSE("Too many paths specified for --output-format=ctf-metadata."); goto error; } @@ -4130,9 +4146,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( @@ -4197,19 +4213,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_size(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_size(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.", @@ -4226,7 +4242,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( @@ -4239,7 +4255,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], ret = append_implicit_component_extra_param( &implicit_lttng_live_args, "url", - bt_value_string_get(bt_val_leftover)); + bt_value_string_get(bt_val_non_opt)); if (ret) { goto error; } @@ -4252,9 +4268,25 @@ 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 = find_loaded_plugin(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); @@ -4263,8 +4295,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], 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_opt_params, non_opt_loglevels, + discovered_source_args); + if (status != 0) { + goto error; + } } } @@ -4297,10 +4333,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; @@ -4557,19 +4594,16 @@ end: *default_log_level = cli_default_log_level; } - if (pc) { - poptFreeContext(pc); - } + bt_argpar_parse_ret_fini(&argpar_parse_ret); - free(arg); free(output); - if (cur_name) { - g_string_free(cur_name, TRUE); + if (component_arg_for_run) { + g_string_free(component_arg_for_run, TRUE); } - if (cur_name_prefix) { - g_string_free(cur_name_prefix, TRUE); + if (name_gstr) { + g_string_free(name_gstr, TRUE); } bt_value_put_ref(run_args); @@ -4577,7 +4611,9 @@ end: 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); @@ -4638,10 +4674,23 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], { struct bt_config *config = NULL; int i; - const char **command_argv = NULL; + 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 }; + + /* Top-level option descriptions. */ + static const struct bt_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 + }; enum command_type { COMMAND_TYPE_NONE = -1, @@ -4671,114 +4720,118 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], goto end; } - for (i = 1; i < argc; i++) { - const char *cur_arg = argv[i]; - const char *next_arg = i == (argc - 1) ? NULL : argv[i + 1]; + /* 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 (strcmp(cur_arg, "-d") == 0 || - strcmp(cur_arg, "--debug") == 0) { - default_log_level = BT_LOG_TRACE; - } else if (strcmp(cur_arg, "-v") == 0 || - strcmp(cur_arg, "--verbose") == 0) { - 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, TRACE). - */ - default_log_level = BT_LOG_INFO; - } - } else if (strcmp(cur_arg, "--log-level") == 0 || - strcmp(cur_arg, "-l") == 0) { - if (!next_arg) { - BT_CLI_LOGE_APPEND_CAUSE("Missing log level value for --log-level option."); - *retcode = 1; - goto end; - } - - 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; - } - - i++; - } else if (strncmp(cur_arg, "--log-level=", 12) == 0) { - const char *arg = &cur_arg[12]; + if (argpar_parse_ret.error) { + BT_CLI_LOGE_APPEND_CAUSE( + "While parsing command-line arguments: %s", + argpar_parse_ret.error->str); + goto error; + } - 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; + for (i = 0; i < argpar_parse_ret.items->len; i++) { + struct bt_argpar_item *item; + + item = g_ptr_array_index(argpar_parse_ret.items, i); + + if (item->type == BT_ARGPAR_ITEM_TYPE_OPT) { + struct bt_argpar_item_opt *item_opt = + (struct bt_argpar_item_opt *) item; + + 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; } - } else if (strncmp(cur_arg, "-l", 2) == 0) { - const char *arg = &cur_arg[2]; - - 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; - } - } else if (strcmp(cur_arg, "-V") == 0 || - strcmp(cur_arg, "--version") == 0) { - print_version(); - goto end; - } else if (strcmp(cur_arg, "-h") == 0 || - strcmp(cur_arg, "--help") == 0) { - print_gen_usage(stdout); - goto end; - } else { + } 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; /* * First unknown argument: is it a known command * name? */ - command_argv = &argv[i]; - command_argc = argc - i; + command_argc = + top_level_argc - item_non_opt->orig_index - 1; + command_argv = + &top_level_argv[item_non_opt->orig_index + 1]; - if (strcmp(cur_arg, "convert") == 0) { + if (strcmp(item_non_opt->arg, "convert") == 0) { command_type = COMMAND_TYPE_CONVERT; - } else if (strcmp(cur_arg, "list-plugins") == 0) { + } else if (strcmp(item_non_opt->arg, "list-plugins") == 0) { command_type = COMMAND_TYPE_LIST_PLUGINS; - } else if (strcmp(cur_arg, "help") == 0) { + } else if (strcmp(item_non_opt->arg, "help") == 0) { command_type = COMMAND_TYPE_HELP; - } else if (strcmp(cur_arg, "query") == 0) { + } else if (strcmp(item_non_opt->arg, "query") == 0) { command_type = COMMAND_TYPE_QUERY; - } else if (strcmp(cur_arg, "run") == 0) { + } else if (strcmp(item_non_opt->arg, "run") == 0) { command_type = COMMAND_TYPE_RUN; } else { /* - * Unknown argument, but not a known + * Non-option argument, but not a known * command name: assume the default * `convert` command. */ command_type = COMMAND_TYPE_CONVERT; command_name = "convert"; - command_argv = &argv[i - 1]; - command_argc = argc - i + 1; + command_argc++; + command_argv--; } break; } } if (command_type == COMMAND_TYPE_NONE) { + if (argpar_parse_ret.ingested_orig_args == top_level_argc) { + /* + * We only got non-help, non-version general options + * like --verbose and --debug, without any other + * arguments, so we can't do anything useful: print the + * usage and quit. + */ + print_gen_usage(stdout); + goto end; + } + /* - * We only got non-help, non-version general options - * like --verbose and --debug, without any other - * arguments, so we can't do anything useful: print the - * usage and quit. + * We stopped on an unknown option argument (and therefore + * didn't see a command name). Assume `convert` command. */ - print_gen_usage(stdout); - goto end; + 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]; } BT_ASSERT(command_argv); @@ -4834,7 +4887,13 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], config->command_name = command_name; } + goto end; + +error: + *retcode = 1; + end: + bt_argpar_parse_ret_fini(&argpar_parse_ret); bt_value_put_ref(initial_plugin_paths); return config; }