X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=cli%2Fbabeltrace-cfg-cli-args.c;h=ad83e4c3254592e96d180648300192508c912950;hb=0b5139375eb31822909dc178ee5cbd7fe8982471;hp=68d381466e2bafd62afe407e4103cb34e18b4d93;hpb=fd5f8053a3b32993bd52d5799683780570538f3a;p=babeltrace.git diff --git a/cli/babeltrace-cfg-cli-args.c b/cli/babeltrace-cfg-cli-args.c index 68d38146..ad83e4c3 100644 --- a/cli/babeltrace-cfg-cli-args.c +++ b/cli/babeltrace-cfg-cli-args.c @@ -22,6 +22,9 @@ * SOFTWARE. */ +#define BT_LOG_TAG "CLI-CFG-CLI-ARGS" +#include "logging.h" + #include #include #include @@ -35,14 +38,10 @@ #include #include #include -#include #include "babeltrace-cfg.h" #include "babeltrace-cfg-cli-args.h" #include "babeltrace-cfg-cli-args-connect.h" -#define BT_LOG_TAG "CLI-CFG-ARGS" -#include "logging.h" - /* * Error printf() macro which prepends "Error: " the first time it's * called. This gives a nicer feel than having a bunch of error prefixes @@ -657,7 +656,7 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin, /* Parse the plugin name */ gs_plugin = bt_common_string_until(at, ".:\\", ".", &end_pos); if (!gs_plugin || gs_plugin->len == 0 || at[end_pos] == '\0') { - printf_err("Missing plugin name\n"); + printf_err("Missing plugin or component class name\n"); goto error; } @@ -697,6 +696,14 @@ void plugin_comp_cls_names(const char *arg, char **name, char **plugin, goto end; error: + if (name) { + *name = NULL; + } + + *plugin = NULL; + *comp_cls = NULL; + +end: if (gs_name) { g_string_free(gs_name, TRUE); } @@ -709,14 +716,10 @@ error: g_string_free(gs_comp_cls, TRUE); } - if (name) { - *name = NULL; + if (gs_comp_cls_type) { + g_string_free(gs_comp_cls_type, TRUE); } - *plugin = NULL; - *comp_cls = NULL; - -end: return; } @@ -928,12 +931,12 @@ end: static void destroy_glist_of_gstring(GList *list) { + GList *at; + if (!list) { return; } - GList *at; - for (at = list; at != NULL; at = g_list_next(at)) { g_string_free(at->data, TRUE); } @@ -1407,7 +1410,7 @@ int append_env_var_plugin_paths(struct bt_value *plugin_paths) const char *envvar; if (bt_common_is_setuid_setgid()) { - printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n"); + BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary."); goto end; } @@ -1434,7 +1437,7 @@ int append_home_and_system_plugin_paths(struct bt_value *plugin_paths, if (!omit_home_plugin_path) { if (bt_common_is_setuid_setgid()) { - printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n"); + BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary."); } else { char *home_plugin_dir = bt_common_get_home_plugin_path(); @@ -1700,7 +1703,7 @@ int bt_config_append_plugin_paths_check_setuid_setgid( int ret = 0; if (bt_common_is_setuid_setgid()) { - printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n"); + BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary."); goto end; } @@ -1772,7 +1775,7 @@ void print_help_usage(FILE *fp) 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 `babeltrace --help` for the list of general options.\n"); fprintf(fp, "\n"); @@ -1887,7 +1890,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], leftover = poptGetArg(pc); if (leftover) { - if (!plug_comp_cls_names) { + if (plug_comp_cls_names) { printf_err("Cannot specify plugin name and --component component class:\n %s\n", leftover); goto error; @@ -1947,13 +1950,10 @@ end: static void print_query_usage(FILE *fp) { - fprintf(fp, "Usage: babeltrace [GEN OPTS] query [OPTS] OBJECT --component=TYPE.PLUGIN.CLS\n"); + fprintf(fp, "Usage: babeltrace [GEN OPTS] query [OPTS] TYPE.PLUGIN.CLS OBJECT\n"); fprintf(fp, "\n"); fprintf(fp, "Options:\n"); fprintf(fp, "\n"); - fprintf(fp, " -c, --component=TYPE.PLUGIN.CLS Query the component class CLS of type TYPE\n"); - fprintf(fp, " (`source`, `filter`, or `sink`) found in\n"); - fprintf(fp, " the plugin PLUGIN\n"); fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n"); fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n"); fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n"); @@ -1961,7 +1961,7 @@ void print_query_usage(FILE *fp) 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, " -h, --help Show this help and quit\n"); fprintf(fp, "\n\n"); print_expected_params_format(fp); } @@ -1969,7 +1969,6 @@ void print_query_usage(FILE *fp) static struct poptOption query_long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL }, { "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 }, @@ -2037,28 +2036,9 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], case OPT_OMIT_HOME_PLUGIN_PATH: cfg->omit_home_plugin_path = true; break; - case OPT_COMPONENT: - if (cfg->cmd_data.query.cfg_component) { - printf_err("Cannot specify more than one plugin and component class:\n %s\n", - arg); - goto error; - } - - cfg->cmd_data.query.cfg_component = - bt_config_component_from_arg(arg); - if (!cfg->cmd_data.query.cfg_component) { - printf_err("Invalid format for --component option's argument:\n %s\n", - arg); - goto error; - } - - /* Default parameters: null */ - bt_put(cfg->cmd_data.query.cfg_component->params); - cfg->cmd_data.query.cfg_component->params = - bt_value_null; - break; case OPT_PARAMS: { + bt_put(params); params = bt_value_from_arg(arg); if (!params) { printf_err("Invalid format for --params option's argument:\n %s\n", @@ -2082,14 +2062,6 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], arg = NULL; } - if (!cfg->cmd_data.query.cfg_component) { - printf_err("No target component class specified with --component option\n"); - goto error; - } - - assert(params); - BT_MOVE(cfg->cmd_data.query.cfg_component->params, params); - /* Check for option parsing error */ if (opt < -1) { printf_err("While parsing command-line options, at option %s: %s\n", @@ -2098,9 +2070,28 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[], } /* - * We need exactly one leftover argument which is the - * mandatory object. + * 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); + if (!cfg->cmd_data.query.cfg_component) { + printf_err("Invalid format for component class specification:\n %s\n", + leftover); + goto error; + } + + assert(params); + BT_MOVE(cfg->cmd_data.query.cfg_component->params, params); + } else { + print_query_usage(stdout); + *retcode = -1; + BT_PUT(cfg); + goto end; + } + leftover = poptGetArg(pc); if (leftover) { if (strlen(leftover) == 0) { @@ -2137,7 +2128,7 @@ end: poptFreeContext(pc); } - BT_PUT(params); + bt_put(params); free(arg); return cfg; } @@ -2157,7 +2148,7 @@ void print_list_plugins_usage(FILE *fp) 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 `babeltrace --help` for the list of general options.\n"); fprintf(fp, "\n"); @@ -2323,7 +2314,7 @@ void print_run_usage(FILE *fp) fprintf(fp, " the current component with a name given by\n"); fprintf(fp, " the last argument of the --key option and a\n"); fprintf(fp, " value set to VAL\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 `babeltrace --help` for the list of general options.\n"); fprintf(fp, "\n\n"); @@ -2716,7 +2707,7 @@ struct bt_config *bt_config_run_from_args_array(struct bt_value *run_args, { struct bt_config *cfg = NULL; const char **argv; - size_t i; + int64_t i, len; const size_t argc = bt_value_array_size(run_args) + 1; argv = calloc(argc, sizeof(*argv)); @@ -2727,7 +2718,12 @@ struct bt_config *bt_config_run_from_args_array(struct bt_value *run_args, argv[0] = "run"; - for (i = 0; i < bt_value_array_size(run_args); i++) { + len = bt_value_array_size(run_args); + if (len < 0) { + printf_err("Invalid executable arguments\n"); + goto end; + } + for (i = 0; i < len; i++) { int ret; struct bt_value *arg_value = bt_value_array_get(run_args, i); const char *arg; @@ -2790,16 +2786,16 @@ void print_convert_usage(FILE *fp) fprintf(fp, " formatted for `xargs -0`, and quit\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, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); - fprintf(fp, "Implicit `ctf.fs` source component options:\n"); + fprintf(fp, "Implicit `source.ctf.fs` component options:\n"); fprintf(fp, "\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, " --stream-intersection Only process events when all streams\n"); fprintf(fp, " are active\n"); fprintf(fp, "\n"); - fprintf(fp, "Implicit `text.text` sink component options:\n"); + fprintf(fp, "Implicit `sink.text.pretty` component options:\n"); fprintf(fp, "\n"); fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n"); fprintf(fp, " --clock-date Print timestamp dates\n"); @@ -2823,12 +2819,12 @@ 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 `utils.muxer` filter component options:\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 `utils.trimmer` filter component options:\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"); fprintf(fp, " time range to BEGIN (see the format of\n"); @@ -2839,7 +2835,7 @@ void print_convert_usage(FILE *fp) fprintf(fp, " BEGIN,END or [BEGIN,END] (literally `[` and\n"); fprintf(fp, " `]`) (see the format of BEGIN/END below)\n"); fprintf(fp, "\n"); - fprintf(fp, "Implicit `lttng-utils.debug-info` filter component options:\n"); + fprintf(fp, "Implicit `filter.lttng-utils.debug-info` component options:\n"); fprintf(fp, "\n"); fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n"); fprintf(fp, " instead of `/usr/lib/debug`\n"); @@ -2861,10 +2857,13 @@ void print_convert_usage(FILE *fp) fprintf(fp, " `lttng-live`:\n"); fprintf(fp, " Create an implicit `source.ctf.lttng-live`\n"); fprintf(fp, " component\n"); - fprintf(fp, " -o, --output-format=(text | dummy | ctf-metadata)\n"); + fprintf(fp, " -o, --output-format=(text | ctf | dummy | ctf-metadata)\n"); fprintf(fp, " `text`:\n"); fprintf(fp, " Create an implicit `sink.text.pretty`\n"); fprintf(fp, " component\n"); + fprintf(fp, " `ctf`:\n"); + fprintf(fp, " Create an implicit `sink.ctf.fs`\n"); + fprintf(fp, " component\n"); fprintf(fp, " `dummy`:\n"); fprintf(fp, " Create an implicit `sink.utils.dummy`\n"); fprintf(fp, " component\n"); @@ -2955,7 +2954,7 @@ struct implicit_component_args { GString *comp_arg; GString *name_arg; GString *params_arg; - struct bt_value *extra_args; + struct bt_value *extra_params; }; static @@ -3044,11 +3043,11 @@ int append_run_args_for_implicit_component( } } - for (i = 0; i < bt_value_array_size(impl_args->extra_args); i++) { + for (i = 0; i < bt_value_array_size(impl_args->extra_params); i++) { struct bt_value *elem; const char *arg; - elem = bt_value_array_get(impl_args->extra_args, i); + elem = bt_value_array_get(impl_args->extra_params, i); if (!elem) { goto error; } @@ -3076,7 +3075,7 @@ end: } static -void destroy_implicit_component_args(struct implicit_component_args *args) +void finalize_implicit_component_args(struct implicit_component_args *args) { assert(args); @@ -3092,7 +3091,18 @@ void destroy_implicit_component_args(struct implicit_component_args *args) g_string_free(args->params_arg, TRUE); } - bt_put(args->extra_args); + bt_put(args->extra_params); +} + +static +void destroy_implicit_component_args(void *args) +{ + if (!args) { + return; + } + + finalize_implicit_component_args(args); + g_free(args); } static @@ -3105,12 +3115,12 @@ int init_implicit_component_args(struct implicit_component_args *args, args->comp_arg = g_string_new(comp_arg); args->name_arg = g_string_new(NULL); args->params_arg = g_string_new(NULL); - args->extra_args = bt_value_array_create(); + args->extra_params = bt_value_array_create(); if (!args->comp_arg || !args->name_arg || - !args->params_arg || !args->extra_args) { + !args->params_arg || !args->extra_params) { ret = -1; - destroy_implicit_component_args(args); + finalize_implicit_component_args(args); print_err_oom(); goto end; } @@ -3130,7 +3140,7 @@ void append_implicit_component_param(struct implicit_component_args *args, } static -int append_implicit_component_extra_arg(struct implicit_component_args *args, +int append_implicit_component_extra_param(struct implicit_component_args *args, const char *key, const char *value) { int ret = 0; @@ -3139,25 +3149,25 @@ int append_implicit_component_extra_arg(struct implicit_component_args *args, assert(key); assert(value); - if (bt_value_array_append_string(args->extra_args, "--key")) { + if (bt_value_array_append_string(args->extra_params, "--key")) { print_err_oom(); ret = -1; goto end; } - if (bt_value_array_append_string(args->extra_args, key)) { + if (bt_value_array_append_string(args->extra_params, key)) { print_err_oom(); ret = -1; goto end; } - if (bt_value_array_append_string(args->extra_args, "--value")) { + if (bt_value_array_append_string(args->extra_params, "--value")) { print_err_oom(); ret = -1; goto end; } - if (bt_value_array_append_string(args->extra_args, value)) { + if (bt_value_array_append_string(args->extra_params, value)) { print_err_oom(); ret = -1; goto end; @@ -3479,6 +3489,84 @@ end: return ret; } +static +struct implicit_component_args *create_implicit_component_args(void) +{ + struct implicit_component_args *impl_args = + g_new0(struct implicit_component_args, 1); + + if (!impl_args) { + goto end; + } + + if (init_implicit_component_args(impl_args, NULL, true)) { + destroy_implicit_component_args(impl_args); + impl_args = NULL; + goto end; + } + +end: + return impl_args; +} + +static +int fill_implicit_ctf_inputs_args(GPtrArray *implicit_ctf_inputs_args, + struct implicit_component_args *base_implicit_ctf_input_args, + GList *leftovers) +{ + int ret = 0; + GList *leftover; + + for (leftover = leftovers; leftover != NULL; + leftover = g_list_next(leftover)) { + GString *gs_leftover = leftover->data; + struct implicit_component_args *impl_args = + create_implicit_component_args(); + + if (!impl_args) { + print_err_oom(); + goto error; + } + + impl_args->exists = true; + g_string_assign(impl_args->comp_arg, + base_implicit_ctf_input_args->comp_arg->str); + g_string_assign(impl_args->params_arg, + base_implicit_ctf_input_args->params_arg->str); + + /* + * We need our own copy of the extra parameters because + * this is where the unique path goes. + */ + BT_PUT(impl_args->extra_params); + impl_args->extra_params = + bt_value_copy(base_implicit_ctf_input_args->extra_params); + if (!impl_args->extra_params) { + print_err_oom(); + destroy_implicit_component_args(impl_args); + goto error; + } + + /* Append unique path parameter */ + ret = append_implicit_component_extra_param(impl_args, + "path", gs_leftover->str); + if (ret) { + destroy_implicit_component_args(impl_args); + goto error; + } + + g_ptr_array_add(implicit_ctf_inputs_args, impl_args); + } + + goto end; + +error: + ret = -1; + +end: + return ret; +} + /* * Creates a Babeltrace config object from the arguments of a convert * command. @@ -3489,7 +3577,7 @@ static struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, bool force_no_debug_info, - struct bt_value *initial_plugin_paths) + struct bt_value *initial_plugin_paths, char *log_level) { poptContext pc = NULL; char *arg = NULL; @@ -3497,12 +3585,11 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], BT_CONFIG_COMPONENT_DEST_UNKNOWN; int opt, ret = 0; struct bt_config *cfg = NULL; - bool got_verbose_opt = false; - bool got_debug_opt = false; 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; @@ -3514,7 +3601,10 @@ 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; - struct implicit_component_args implicit_ctf_args = { 0 }; + GList *leftovers = NULL; + GPtrArray *implicit_ctf_inputs_args = NULL; + struct implicit_component_args base_implicit_ctf_input_args = { 0 }; + struct implicit_component_args implicit_ctf_output_args = { 0 }; struct implicit_component_args implicit_lttng_live_args = { 0 }; struct implicit_component_args implicit_dummy_args = { 0 }; struct implicit_component_args implicit_text_args = { 0 }; @@ -3525,6 +3615,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], char error_buf[256] = { 0 }; size_t i; struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 }; + char *output = NULL; *retcode = 0; @@ -3534,11 +3625,16 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto end; } - if (init_implicit_component_args(&implicit_ctf_args, + if (init_implicit_component_args(&base_implicit_ctf_input_args, "source.ctf.fs", false)) { goto error; } + if (init_implicit_component_args(&implicit_ctf_output_args, + "sink.ctf.fs", false)) { + goto error; + } + if (init_implicit_component_args(&implicit_lttng_live_args, "source.ctf.lttng-live", false)) { goto error; @@ -3569,6 +3665,13 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + implicit_ctf_inputs_args = g_ptr_array_new_with_free_func( + (GDestroyNotify) destroy_implicit_component_args); + if (!implicit_ctf_inputs_args) { + print_err_oom(); + goto error; + } + all_names = bt_value_map_create(); if (!all_names) { print_err_oom(); @@ -3920,7 +4023,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } trimmer_has_begin = true; - ret = append_implicit_component_extra_arg( + ret = append_implicit_component_extra_param( &implicit_trimmer_args, "begin", arg); implicit_trimmer_args.exists = true; if (ret) { @@ -3935,7 +4038,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } trimmer_has_end = true; - ret = append_implicit_component_extra_arg( + ret = append_implicit_component_extra_param( &implicit_trimmer_args, "end", arg); implicit_trimmer_args.exists = true; if (ret) { @@ -3960,9 +4063,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - ret = append_implicit_component_extra_arg( + ret = append_implicit_component_extra_param( &implicit_trimmer_args, "begin", begin); - ret |= append_implicit_component_extra_arg( + ret |= append_implicit_component_extra_param( &implicit_trimmer_args, "end", end); implicit_trimmer_args.exists = true; free(begin); @@ -3984,28 +4087,27 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], break; case OPT_CLOCK_FORCE_CORRELATE: append_implicit_component_param( - &implicit_muxer_args, "assume-absolute-clock-classes", "yes"); + &implicit_muxer_args, + "assume-absolute-clock-classes", "yes"); break; case OPT_CLOCK_GMT: append_implicit_component_param( &implicit_text_args, "clock-gmt", "yes"); + append_implicit_component_param( + &implicit_trimmer_args, "clock-gmt", "yes"); implicit_text_args.exists = true; break; case OPT_CLOCK_OFFSET: - ret = append_implicit_component_extra_arg( - &implicit_ctf_args, "clock-offset-cycles", arg); - implicit_ctf_args.exists = true; - if (ret) { - goto error; - } + base_implicit_ctf_input_args.exists = true; + append_implicit_component_param( + &base_implicit_ctf_input_args, + "clock-class-offset-s", arg); break; case OPT_CLOCK_OFFSET_NS: - ret = append_implicit_component_extra_arg( - &implicit_ctf_args, "clock-offset-ns", arg); - implicit_ctf_args.exists = true; - if (ret) { - goto error; - } + base_implicit_ctf_input_args.exists = true; + append_implicit_component_param( + &base_implicit_ctf_input_args, + "clock-class-offset-ns", arg); break; case OPT_CLOCK_SECONDS: append_implicit_component_param( @@ -4013,9 +4115,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], implicit_text_args.exists = true; break; case OPT_COLOR: - ret = append_implicit_component_extra_arg( - &implicit_text_args, "color", arg); implicit_text_args.exists = true; + ret = append_implicit_component_extra_param( + &implicit_text_args, "color", arg); if (ret) { goto error; } @@ -4024,18 +4126,21 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], implicit_debug_info_args.exists = false; break; case OPT_DEBUG_INFO_DIR: - ret = append_implicit_component_extra_arg( + implicit_debug_info_args.exists = true; + ret = append_implicit_component_extra_param( &implicit_debug_info_args, "dir", arg); if (ret) { goto error; } break; case OPT_DEBUG_INFO_FULL_PATH: + implicit_debug_info_args.exists = true; append_implicit_component_param( &implicit_debug_info_args, "full-path", "yes"); break; case OPT_DEBUG_INFO_TARGET_PREFIX: - ret = append_implicit_component_extra_arg( + implicit_debug_info_args.exists = true; + ret = append_implicit_component_extra_param( &implicit_debug_info_args, "target-prefix", arg); if (ret) { @@ -4050,6 +4155,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + implicit_text_args.exists = true; ret = insert_flat_params_from_array( implicit_text_args.params_arg, fields, "field"); @@ -4067,6 +4173,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + implicit_text_args.exists = true; ret = insert_flat_params_from_array( implicit_text_args.params_arg, names, "name"); @@ -4090,7 +4197,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], got_input_format_opt = true; if (strcmp(arg, "ctf") == 0) { - implicit_ctf_args.exists = true; + base_implicit_ctf_input_args.exists = true; } else if (strcmp(arg, "lttng-live") == 0) { implicit_lttng_live_args.exists = true; } else { @@ -4109,6 +4216,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], if (strcmp(arg, "text") == 0) { implicit_text_args.exists = true; + } else if (strcmp(arg, "ctf") == 0) { + implicit_ctf_output_args.exists = true; } else if (strcmp(arg, "dummy") == 0) { implicit_dummy_args.exists = true; } else if (strcmp(arg, "ctf-metadata") == 0) { @@ -4120,10 +4229,14 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } break; case OPT_OUTPUT: - ret = append_implicit_component_extra_arg( - &implicit_text_args, "path", arg); - implicit_text_args.exists = true; - if (ret) { + if (output) { + printf_err("Duplicate --output option\n"); + goto error; + } + + output = strdup(arg); + if (!output) { + print_err_oom(); goto error; } break; @@ -4144,23 +4257,19 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], print_run_args_0 = true; break; case OPT_STREAM_INTERSECTION: - append_implicit_component_param(&implicit_ctf_args, - "stream-intersection", "yes"); - implicit_ctf_args.exists = true; + /* + * Applies to all traces implementing the trace-info + * query. + */ + stream_intersection_mode = true; break; case OPT_VERBOSE: - if (got_verbose_opt) { - printf_err("Duplicate -v/--verbose option\n"); - goto error; + if (*log_level != 'V' && *log_level != 'D') { + *log_level = 'I'; } - - append_implicit_component_param(&implicit_text_args, - "verbose", "yes"); - implicit_text_args.exists = true; - got_verbose_opt = true; break; case OPT_DEBUG: - got_debug_opt = true; + *log_level = 'V'; break; } @@ -4175,6 +4284,16 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + /* + * Legacy behaviour: --verbose used to make the `text` output + * format print more information. --verbose is now equivalent to + * the INFO log level, which is why we compare to 'I' here. + */ + if (*log_level == 'I') { + append_implicit_component_param(&implicit_text_args, + "verbose", "yes"); + } + /* * Append home and system plugin paths now that we possibly got * --plugin-path. @@ -4185,47 +4304,115 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - /* Consume leftover argument */ - leftover = poptGetArg(pc); + /* Consume and keep leftover arguments */ + while ((leftover = poptGetArg(pc))) { + GString *gs_leftover = g_string_new(leftover); - if (poptPeekArg(pc)) { - printf_err("Unexpected argument:\n %s\n", - poptPeekArg(pc)); - goto error; + if (!gs_leftover) { + print_err_oom(); + goto error; + } + + leftovers = g_list_append(leftovers, gs_leftover); + if (!leftovers) { + g_string_free(gs_leftover, TRUE); + print_err_oom(); + goto error; + } } /* Print CTF metadata or print LTTng live sessions */ if (print_ctf_metadata) { - if (!leftover) { + GString *gs_leftover; + + if (g_list_length(leftovers) == 0) { printf_err("--output-format=ctf-metadata specified without a path\n"); goto error; } + if (g_list_length(leftovers) > 1) { + printf_err("Too many paths specified for --output-format=ctf-metadata\n"); + goto error; + } + cfg = bt_config_print_ctf_metadata_create(plugin_paths); if (!cfg) { goto error; } - cfg->debug = got_debug_opt; - cfg->verbose = got_verbose_opt; + gs_leftover = leftovers->data; g_string_assign(cfg->cmd_data.print_ctf_metadata.path, - leftover); + gs_leftover->str); goto end; } /* - * If -o dummy was not specified, and if there are no explicit - * sink components, then use an implicit `text.text` sink. + * If -o ctf was specified, make sure an output path (--output) + * was also specified. --output does not imply -o ctf because + * it's also used for the default, implicit -o text if -o ctf + * is not specified. */ - if (!implicit_dummy_args.exists && !sink_names) { + if (implicit_ctf_output_args.exists) { + if (!output) { + printf_err("--output-format=ctf specified without --output (trace output path)\n"); + goto error; + } + + /* + * At this point we know that -o ctf AND --output were + * specified. Make sure that no options were specified + * which would imply -o text because --output would be + * ambiguous in this case. For example, this is wrong: + * + * babeltrace --names=all -o ctf --output=/tmp/path my-trace + * + * because --names=all implies -o text, and --output + * could apply to both the sink.text.pretty and + * sink.ctf.fs implicit components. + */ + if (implicit_text_args.exists) { + printf_err("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text\n"); + goto error; + } + } + + /* + * If -o dummy and -o ctf were not specified, and if there are + * no explicit sink components, then use an implicit + * `sink.text.pretty` component. + */ + if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists && + !sink_names) { implicit_text_args.exists = true; } - /* Decide where the leftover argument goes */ - if (leftover) { + /* + * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's + * `path` parameter if --output was specified. + */ + if (output) { + if (implicit_text_args.exists) { + append_implicit_component_extra_param(&implicit_text_args, + "path", output); + } else if (implicit_ctf_output_args.exists) { + append_implicit_component_extra_param(&implicit_ctf_output_args, + "path", output); + } + } + + /* Decide where the leftover argument(s) go */ + if (g_list_length(leftovers) > 0) { if (implicit_lttng_live_args.exists) { + GString *gs_leftover; + + if (g_list_length(leftovers) > 1) { + printf_err("Too many URLs specified for --output-format=lttng-live\n"); + goto error; + } + + gs_leftover = leftovers->data; lttng_live_url_parts = - bt_common_parse_lttng_live_url(leftover, + bt_common_parse_lttng_live_url(gs_leftover->str, error_buf, sizeof(error_buf)); if (!lttng_live_url_parts.proto) { printf_err("Invalid LTTng live URL format: %s\n", @@ -4241,22 +4428,27 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - cfg->debug = got_debug_opt; - cfg->verbose = got_verbose_opt; g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url, - leftover); + gs_leftover->str); goto end; } - ret = append_implicit_component_extra_arg( - &implicit_lttng_live_args, "url", leftover); + ret = append_implicit_component_extra_param( + &implicit_lttng_live_args, "url", + gs_leftover->str); if (ret) { goto error; } } else { - ret = append_implicit_component_extra_arg( - &implicit_ctf_args, "path", leftover); - implicit_ctf_args.exists = true; + /* + * Append one implicit component argument set + * for each leftover (souce.ctf.fs paths). Copy + * the base implicit component arguments. + * Note that they still have to be named later. + */ + ret = fill_implicit_ctf_inputs_args( + implicit_ctf_inputs_args, + &base_implicit_ctf_input_args, leftovers); if (ret) { goto error; } @@ -4267,35 +4459,42 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * Ensure mutual exclusion between implicit `source.ctf.fs` and * `source.ctf.lttng-live` components. */ - if (implicit_ctf_args.exists && implicit_lttng_live_args.exists) { + if (base_implicit_ctf_input_args.exists && + implicit_lttng_live_args.exists) { printf_err("Cannot create both implicit `%s` and `%s` components\n", - implicit_ctf_args.comp_arg->str, + base_implicit_ctf_input_args.comp_arg->str, implicit_lttng_live_args.comp_arg->str); goto error; } /* * If the implicit `source.ctf.fs` or `source.ctf.lttng-live` - * components exists, make sure there's a leftover (which is the - * path or URL). + * components exists, make sure there's at least one leftover + * (which is the path or URL). */ - if (implicit_ctf_args.exists && !leftover) { + if (base_implicit_ctf_input_args.exists && + g_list_length(leftovers) == 0) { printf_err("Missing path for implicit `%s` component\n", - implicit_ctf_args.comp_arg->str); + base_implicit_ctf_input_args.comp_arg->str); goto error; } - if (implicit_lttng_live_args.exists && !leftover) { + if (implicit_lttng_live_args.exists && g_list_length(leftovers) == 0) { printf_err("Missing URL for implicit `%s` component\n", implicit_lttng_live_args.comp_arg->str); goto error; } /* Assign names to implicit components */ - ret = assign_name_to_implicit_component(&implicit_ctf_args, - "ctf-fs", all_names, &source_names, true); - if (ret) { - goto error; + for (i = 0; i < implicit_ctf_inputs_args->len; i++) { + struct implicit_component_args *impl_args = + g_ptr_array_index(implicit_ctf_inputs_args, i); + + ret = assign_name_to_implicit_component(impl_args, + "source-ctf-fs", all_names, &source_names, true); + if (ret) { + goto error; + } } ret = assign_name_to_implicit_component(&implicit_lttng_live_args, @@ -4310,6 +4509,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + ret = assign_name_to_implicit_component(&implicit_ctf_output_args, + "sink-ctf-fs", all_names, &sink_names, true); + if (ret) { + goto error; + } + ret = assign_name_to_implicit_component(&implicit_dummy_args, "dummy", all_names, &sink_names, true); if (ret) { @@ -4375,19 +4580,30 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * Append the equivalent run arguments for the implicit * components. */ - ret = append_run_args_for_implicit_component(&implicit_ctf_args, + for (i = 0; i < implicit_ctf_inputs_args->len; i++) { + struct implicit_component_args *impl_args = + g_ptr_array_index(implicit_ctf_inputs_args, i); + + ret = append_run_args_for_implicit_component(impl_args, + run_args); + if (ret) { + goto error; + } + } + + ret = append_run_args_for_implicit_component(&implicit_lttng_live_args, run_args); if (ret) { goto error; } - ret = append_run_args_for_implicit_component(&implicit_lttng_live_args, + ret = append_run_args_for_implicit_component(&implicit_text_args, run_args); if (ret) { goto error; } - ret = append_run_args_for_implicit_component(&implicit_text_args, + ret = append_run_args_for_implicit_component(&implicit_ctf_output_args, run_args); if (ret) { goto error; @@ -4431,6 +4647,11 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * here. */ if (print_run_args || print_run_args_0) { + if (stream_intersection_mode) { + printf_err("Cannot specify --stream-intersection with --run-args or --run-args-0\n"); + goto error; + } + for (i = 0; i < bt_value_array_size(run_args); i++) { struct bt_value *arg_value = bt_value_array_get(run_args, i); @@ -4477,6 +4698,11 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], cfg = bt_config_run_from_args_array(run_args, retcode, force_omit_system_plugin_path, force_omit_home_plugin_path, initial_plugin_paths); + if (!cfg) { + goto error; + } + + cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode; goto end; error: @@ -4489,6 +4715,7 @@ end: } free(arg); + free(output); if (cur_name) { g_string_free(cur_name, TRUE); @@ -4498,18 +4725,24 @@ end: g_string_free(cur_name_prefix, TRUE); } + if (implicit_ctf_inputs_args) { + g_ptr_array_free(implicit_ctf_inputs_args, TRUE); + } + bt_put(run_args); bt_put(all_names); destroy_glist_of_gstring(source_names); destroy_glist_of_gstring(filter_names); destroy_glist_of_gstring(sink_names); - destroy_implicit_component_args(&implicit_ctf_args); - destroy_implicit_component_args(&implicit_lttng_live_args); - destroy_implicit_component_args(&implicit_dummy_args); - destroy_implicit_component_args(&implicit_text_args); - destroy_implicit_component_args(&implicit_debug_info_args); - destroy_implicit_component_args(&implicit_muxer_args); - destroy_implicit_component_args(&implicit_trimmer_args); + destroy_glist_of_gstring(leftovers); + finalize_implicit_component_args(&base_implicit_ctf_input_args); + finalize_implicit_component_args(&implicit_ctf_output_args); + finalize_implicit_component_args(&implicit_lttng_live_args); + finalize_implicit_component_args(&implicit_dummy_args); + finalize_implicit_component_args(&implicit_text_args); + finalize_implicit_component_args(&implicit_debug_info_args); + finalize_implicit_component_args(&implicit_muxer_args); + finalize_implicit_component_args(&implicit_trimmer_args); bt_put(plugin_paths); bt_common_destroy_lttng_live_url_parts(<tng_live_url_parts); return cfg; @@ -4525,10 +4758,12 @@ void print_gen_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "General options:\n"); fprintf(fp, "\n"); - fprintf(fp, " -d, --debug Turn on debug mode\n"); - fprintf(fp, " -h --help Show this help and quit\n"); - fprintf(fp, " -v, --verbose Turn on verbose mode\n"); - fprintf(fp, " -V, --version Show version and quit\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, " --log-level=LVL Set all log levels 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, "\n"); fprintf(fp, "Available commands:\n"); fprintf(fp, "\n"); @@ -4541,18 +4776,49 @@ void print_gen_usage(FILE *fp) fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n"); } +static +char log_level_from_arg(const char *arg) +{ + char level = 'U'; + + if (strcmp(arg, "VERBOSE") == 0 || + strcmp(arg, "V") == 0) { + level = 'V'; + } else if (strcmp(arg, "DEBUG") == 0 || + strcmp(arg, "D") == 0) { + level = 'D'; + } else if (strcmp(arg, "INFO") == 0 || + strcmp(arg, "I") == 0) { + level = 'I'; + } else if (strcmp(arg, "WARN") == 0 || + strcmp(arg, "WARNING") == 0 || + strcmp(arg, "W") == 0) { + level = 'W'; + } else if (strcmp(arg, "ERROR") == 0 || + strcmp(arg, "E") == 0) { + level = 'E'; + } else if (strcmp(arg, "FATAL") == 0 || + strcmp(arg, "F") == 0) { + level = 'F'; + } else if (strcmp(arg, "NONE") == 0 || + strcmp(arg, "N") == 0) { + level = 'N'; + } + + return level; +} + struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, bool force_no_debug_info, struct bt_value *initial_plugin_paths) { struct bt_config *config = NULL; - bool verbose = false; - bool debug = false; int i; const char **command_argv = NULL; int command_argc = -1; const char *command_name = NULL; + char log_level = 'U'; enum command_type { COMMAND_TYPE_NONE = -1, @@ -4582,13 +4848,49 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], for (i = 1; i < argc; i++) { const char *cur_arg = argv[i]; + const char *next_arg = i == (argc - 1) ? NULL : argv[i + 1]; if (strcmp(cur_arg, "-d") == 0 || strcmp(cur_arg, "--debug") == 0) { - debug = true; + log_level = 'V'; } else if (strcmp(cur_arg, "-v") == 0 || strcmp(cur_arg, "--verbose") == 0) { - verbose = true; + if (log_level != 'V' && log_level != 'D') { + /* + * Legacy: do not override a previous + * --debug because --verbose and --debug + * can be specified together (in this + * case we want the lowest log level to + * apply, VERBOSE). + */ + log_level = 'I'; + } + } else if (strcmp(cur_arg, "--log-level") == 0) { + if (!next_arg) { + printf_err("Missing log level value for --log-level option\n"); + *retcode = 1; + goto end; + } + + log_level = log_level_from_arg(next_arg); + if (log_level == 'U') { + printf_err("Invalid argument for --log-level option:\n %s\n", + next_arg); + *retcode = 1; + goto end; + } + + i++; + } else if (strncmp(cur_arg, "--log-level=", 12) == 0) { + const char *arg = &cur_arg[12]; + + log_level = log_level_from_arg(arg); + if (log_level == 'U') { + printf_err("Invalid argument for --log-level option:\n %s\n", + arg); + *retcode = 1; + goto end; + } } else if (strcmp(cur_arg, "-V") == 0 || strcmp(cur_arg, "--version") == 0) { print_version(); @@ -4598,12 +4900,13 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], print_gen_usage(stdout); goto end; } else { - bool has_command = true; - /* * First unknown argument: is it a known command * name? */ + command_argv = &argv[i]; + command_argc = argc - i; + if (strcmp(cur_arg, "convert") == 0) { command_type = COMMAND_TYPE_CONVERT; } else if (strcmp(cur_arg, "list-plugins") == 0) { @@ -4617,20 +4920,13 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], } else { /* * Unknown argument, but not a known - * command name: assume the whole - * arguments are for the default convert - * command. + * command name: assume the default + * `convert` command. */ command_type = COMMAND_TYPE_CONVERT; - command_argv = argv; - command_argc = argc; - has_command = false; - } - - if (has_command) { - command_argv = &argv[i]; - command_argc = argc - i; - command_name = cur_arg; + command_name = "convert"; + command_argv = &argv[i - 1]; + command_argc = argc - i + 1; } break; } @@ -4660,7 +4956,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], config = bt_config_convert_from_args(command_argc, command_argv, retcode, force_omit_system_plugin_path, force_omit_home_plugin_path, force_no_debug_info, - initial_plugin_paths); + initial_plugin_paths, &log_level); break; case COMMAND_TYPE_LIST_PLUGINS: config = bt_config_list_plugins_from_args(command_argc, @@ -4682,14 +4978,11 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], } if (config) { - if (verbose) { - config->verbose = true; - } - - if (debug) { - config->debug = true; + if (log_level == 'U') { + log_level = 'W'; } + config->log_level = log_level; config->command_name = command_name; }