X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=converter%2Fbabeltrace-cfg.c;h=e005df2c528c28b9b1b84a887bf3d27a06f92464;hb=a67681c1f02f54bc1f708d449bceb35476024083;hp=6d8ff8d9846e23853853cf8af577369139dbde70;hpb=3b6cfcc54e7adaf6725738cb4dd97325cef14ee5;p=babeltrace.git diff --git a/converter/babeltrace-cfg.c b/converter/babeltrace-cfg.c index 6d8ff8d9..e005df2c 100644 --- a/converter/babeltrace-cfg.c +++ b/converter/babeltrace-cfg.c @@ -37,6 +37,7 @@ #include #include #include "babeltrace-cfg.h" +#include "babeltrace-cfg-connect.h" #define DEFAULT_SOURCE_COMPONENT_NAME "ctf.fs" #define DEFAULT_SINK_COMPONENT_NAME "text.text" @@ -129,6 +130,7 @@ struct text_legacy_opts { bool clock_date; bool clock_gmt; bool dbg_info_full_path; + bool verbose; }; /* Legacy input format format */ @@ -142,7 +144,6 @@ enum legacy_input_format { enum legacy_output_format { LEGACY_OUTPUT_FORMAT_NONE = 0, LEGACY_OUTPUT_FORMAT_TEXT, - LEGACY_OUTPUT_FORMAT_CTF_METADATA, LEGACY_OUTPUT_FORMAT_DUMMY, }; @@ -186,7 +187,7 @@ bool text_legacy_opts_is_any_set(struct text_legacy_opts *opts) bt_value_array_size(opts->names) > 0 || bt_value_array_size(opts->fields) > 0 || opts->no_delta || opts->clock_cycles || opts->clock_seconds || - opts->clock_date || opts->clock_gmt || + opts->clock_date || opts->clock_gmt || opts->verbose || opts->dbg_info_full_path; } @@ -731,8 +732,9 @@ end: * Return value is owned by the caller. */ static -struct bt_config_component *bt_config_component_create(const char *plugin_name, - const char *component_name) +struct bt_config_component *bt_config_component_create( + enum bt_component_class_type type, + const char *plugin_name, const char *component_name) { struct bt_config_component *cfg_component = NULL; @@ -743,6 +745,7 @@ struct bt_config_component *bt_config_component_create(const char *plugin_name, } bt_object_init(cfg_component, bt_config_component_destroy); + cfg_component->type = type; cfg_component->plugin_name = g_string_new(plugin_name); if (!cfg_component->plugin_name) { print_err_oom(); @@ -781,8 +784,8 @@ end: * Creates a component configuration from a command-line source/sink * option's argument. */ -static -struct bt_config_component *bt_config_component_from_arg(const char *arg) +struct bt_config_component *bt_config_component_from_arg( + enum bt_component_class_type type, const char *arg) { struct bt_config_component *bt_config_component = NULL; char *plugin_name; @@ -794,7 +797,7 @@ struct bt_config_component *bt_config_component_from_arg(const char *arg) goto error; } - bt_config_component = bt_config_component_create(plugin_name, + bt_config_component = bt_config_component_create(type, plugin_name, component_name); if (!bt_config_component) { goto error; @@ -830,10 +833,19 @@ void bt_config_destroy(struct bt_object *obj) g_ptr_array_free(cfg->cmd_data.convert.sources, TRUE); } + if (cfg->cmd_data.convert.filters) { + g_ptr_array_free(cfg->cmd_data.convert.filters, TRUE); + } + if (cfg->cmd_data.convert.sinks) { g_ptr_array_free(cfg->cmd_data.convert.sinks, TRUE); } + if (cfg->cmd_data.convert.connections) { + g_ptr_array_free(cfg->cmd_data.convert.connections, + TRUE); + } + BT_PUT(cfg->cmd_data.convert.plugin_paths); break; case BT_CONFIG_COMMAND_LIST_PLUGINS: @@ -841,13 +853,14 @@ void bt_config_destroy(struct bt_object *obj) break; case BT_CONFIG_COMMAND_HELP: BT_PUT(cfg->cmd_data.help.plugin_paths); + BT_PUT(cfg->cmd_data.help.cfg_component); + break; + case BT_CONFIG_COMMAND_QUERY: + BT_PUT(cfg->cmd_data.query.plugin_paths); + BT_PUT(cfg->cmd_data.query.cfg_component); - if (cfg->cmd_data.help.plugin_name) { - g_string_free(cfg->cmd_data.help.plugin_name, TRUE); - } - - if (cfg->cmd_data.help.component_name) { - g_string_free(cfg->cmd_data.help.component_name, TRUE); + if (cfg->cmd_data.query.object) { + g_string_free(cfg->cmd_data.query.object, TRUE); } break; default: @@ -1313,6 +1326,12 @@ struct bt_value *params_from_text_legacy_opts( goto error; } + if (bt_value_map_insert_bool(params, "verbose", + text_legacy_opts->verbose)) { + print_err_oom(); + goto error; + } + if (insert_flat_names_fields_from_array(params, text_legacy_opts->names, "name")) { goto error; @@ -1348,12 +1367,8 @@ int append_sinks_from_legacy_opts(GPtrArray *sinks, plugin_name = "text"; component_name = "text"; break; - case LEGACY_OUTPUT_FORMAT_CTF_METADATA: - plugin_name = "ctf"; - component_name = "metadata-text"; - break; case LEGACY_OUTPUT_FORMAT_DUMMY: - plugin_name = "dummy"; + plugin_name = "utils"; component_name = "dummy"; break; default: @@ -1380,8 +1395,8 @@ int append_sinks_from_legacy_opts(GPtrArray *sinks, } /* Create a component configuration */ - bt_config_component = bt_config_component_create(plugin_name, - component_name); + bt_config_component = bt_config_component_create( + BT_COMPONENT_CLASS_TYPE_SINK, plugin_name, component_name); if (!bt_config_component) { goto error; } @@ -1509,8 +1524,8 @@ int append_sources_from_legacy_opts(GPtrArray *sources, } /* Create a component configuration */ - bt_config_component = bt_config_component_create("ctf", - component_name); + bt_config_component = bt_config_component_create( + BT_COMPONENT_CLASS_TYPE_SOURCE, "ctf", component_name); if (!bt_config_component) { goto error; } @@ -1674,7 +1689,7 @@ void print_output_legacy_to_sinks( enum legacy_output_format legacy_output_format, struct text_legacy_opts *text_legacy_opts) { - const char *input_format; + const char *output_format; GString *str = NULL; str = g_string_new(" "); @@ -1685,33 +1700,27 @@ void print_output_legacy_to_sinks( switch (legacy_output_format) { case LEGACY_OUTPUT_FORMAT_TEXT: - input_format = "text"; - break; - case LEGACY_OUTPUT_FORMAT_CTF_METADATA: - input_format = "ctf-metadata"; + output_format = "text"; break; case LEGACY_OUTPUT_FORMAT_DUMMY: - input_format = "dummy"; + output_format = "dummy"; break; default: assert(false); } printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n", - input_format); + output_format); printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n", - input_format); + output_format); g_string_append(str, "-o "); switch (legacy_output_format) { case LEGACY_OUTPUT_FORMAT_TEXT: g_string_append(str, "text.text"); break; - case LEGACY_OUTPUT_FORMAT_CTF_METADATA: - g_string_append(str, "ctf.metadata-text"); - break; case LEGACY_OUTPUT_FORMAT_DUMMY: - g_string_append(str, "dummy.dummy"); + g_string_append(str, "utils.dummy"); break; default: assert(false); @@ -1753,6 +1762,8 @@ void print_output_legacy_to_sinks( text_legacy_opts->clock_date); g_string_append_bool_param(str, "clock-gmt", text_legacy_opts->clock_gmt); + g_string_append_bool_param(str, "verbose", + text_legacy_opts->verbose); ret = append_prefixed_flag_params(str, text_legacy_opts->names, "name"); if (ret) { @@ -1883,7 +1894,8 @@ bool validate_cfg(struct bt_config *cfg, bool legacy_output = false; /* Determine if the input and output should be legacy-style */ - if (*legacy_input_format != LEGACY_INPUT_FORMAT_NONE || + if (cfg->cmd_data.convert.print_ctf_metadata || + *legacy_input_format != LEGACY_INPUT_FORMAT_NONE || !bt_value_array_is_empty(legacy_input_paths) || ctf_legacy_opts_is_any_set(ctf_legacy_opts)) { legacy_input = true; @@ -1917,13 +1929,45 @@ bool validate_cfg(struct bt_config *cfg, /* Make sure no non-legacy sources are specified */ if (cfg->cmd_data.convert.sources->len != 0) { - print_input_legacy_to_sources(*legacy_input_format, - legacy_input_paths, ctf_legacy_opts); + if (cfg->cmd_data.convert.print_ctf_metadata) { + printf_err("You cannot instantiate a source component with the `ctf-metadata` output format\n"); + } else { + print_input_legacy_to_sources( + *legacy_input_format, + legacy_input_paths, ctf_legacy_opts); + } + goto error; } } - if (legacy_output) { + /* + * Strict rule: if we need to print the CTF metadata, the input + * format must be legacy and CTF. Also there should be no + * other sinks, and no legacy output format. + */ + if (cfg->cmd_data.convert.print_ctf_metadata) { + if (*legacy_input_format != LEGACY_INPUT_FORMAT_CTF) { + printf_err("The `ctf-metadata` output format requires legacy `ctf` input format\n"); + goto error; + } + + if (bt_value_array_size(legacy_input_paths) != 1) { + printf_err("You need to specify exactly one path with the `ctf-metadata` output format\n"); + goto error; + } + + if (legacy_output) { + printf_err("You cannot use another legacy output format with the `ctf-metadata` output format\n"); + goto error; + } + + if (cfg->cmd_data.convert.sinks->len != 0) { + printf_err("You cannot instantiate a sink component with the `ctf-metadata` output format\n"); + goto error; + goto error; + } + } else if (legacy_output) { /* * If no legacy output format was specified, default to * "text". @@ -1951,16 +1995,6 @@ bool validate_cfg(struct bt_config *cfg, } } - /* - * If the output is the legacy "ctf-metadata" format, then the - * input should be the legacy "ctf" input format. - */ - if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_CTF_METADATA && - *legacy_input_format != LEGACY_INPUT_FORMAT_CTF) { - printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n"); - goto error; - } - return true; error: @@ -1998,6 +2032,7 @@ enum { OPT_CLOCK_OFFSET, OPT_CLOCK_OFFSET_NS, OPT_CLOCK_SECONDS, + OPT_CONNECT, OPT_DEBUG, OPT_DEBUG_INFO_DIR, OPT_DEBUG_INFO_FULL_PATH, @@ -2212,6 +2247,13 @@ static struct bt_config *bt_config_convert_create( goto error; } + cfg->cmd_data.convert.filters = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_put); + if (!cfg->cmd_data.convert.filters) { + print_err_oom(); + goto error; + } + cfg->cmd_data.convert.sinks = g_ptr_array_new_with_free_func( (GDestroyNotify) bt_put); if (!cfg->cmd_data.convert.sinks) { @@ -2219,6 +2261,13 @@ static struct bt_config *bt_config_convert_create( goto error; } + cfg->cmd_data.convert.connections = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_config_connection_destroy); + if (!cfg->cmd_data.convert.connections) { + print_err_oom(); + goto error; + } + if (initial_plugin_paths) { cfg->cmd_data.convert.plugin_paths = bt_get(initial_plugin_paths); @@ -2296,14 +2345,49 @@ static struct bt_config *bt_config_help_create( } } - cfg->cmd_data.help.plugin_name = g_string_new(NULL); - if (!cfg->cmd_data.help.plugin_name) { + cfg->cmd_data.help.cfg_component = + bt_config_component_create(BT_COMPONENT_CLASS_TYPE_UNKNOWN, + NULL, NULL); + if (!cfg->cmd_data.help.cfg_component) { + print_err_oom(); + goto error; + } + + goto end; + +error: + BT_PUT(cfg); + +end: + return cfg; +} + +static struct bt_config *bt_config_query_create( + struct bt_value *initial_plugin_paths) +{ + struct bt_config *cfg; + + /* Create config */ + cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY); + if (!cfg) { print_err_oom(); goto error; } - cfg->cmd_data.help.component_name = g_string_new(NULL); - if (!cfg->cmd_data.help.component_name) { + if (initial_plugin_paths) { + cfg->cmd_data.query.plugin_paths = + bt_get(initial_plugin_paths); + } else { + cfg->cmd_data.query.plugin_paths = + bt_value_array_create(); + if (!cfg->cmd_data.query.plugin_paths) { + print_err_oom(); + goto error; + } + } + + cfg->cmd_data.query.object = g_string_new(NULL); + if (!cfg->cmd_data.query.object) { print_err_oom(); goto error; } @@ -2317,6 +2401,44 @@ end: return cfg; } +/* + * Prints the expected format for a --params option. + */ +static +void print_expected_params_format(FILE *fp) +{ + fprintf(fp, "Expected format of PARAMS\n"); + fprintf(fp, "-------------------------\n"); + fprintf(fp, "\n"); + fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n"); + fprintf(fp, "\n"); + fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n"); + fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n"); + fprintf(fp, "VALUE can be one of:\n"); + fprintf(fp, "\n"); + fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n"); + fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n"); + fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n"); + fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n"); + fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n"); + fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n"); + fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n"); + fprintf(fp, " the null and boolean value symbols above.\n"); + fprintf(fp, "* Double-quoted string (accepts escape characters).\n"); + fprintf(fp, "\n"); + fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n"); + fprintf(fp, "\n"); + fprintf(fp, "Example:\n"); + fprintf(fp, "\n"); + fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n"); + fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n"); + fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n"); + fprintf(fp, "\n"); + fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n"); + fprintf(fp, "from a shell.\n"); +} + + /* * Prints the help command usage. */ @@ -2324,9 +2446,9 @@ static void print_help_usage(FILE *fp) { fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n"); - fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source PLUGIN.COMPCLS\n"); - fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter PLUGIN.COMPCLS\n"); - fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink PLUGIN.COMPCLS\n"); + fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source=PLUGIN.COMPCLS\n"); + fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter=PLUGIN.COMPCLS\n"); + fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink=PLUGIN.COMPCLS\n"); fprintf(fp, "\n"); fprintf(fp, "Options:\n"); fprintf(fp, "\n"); @@ -2387,7 +2509,6 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], goto error; } - cfg->cmd_data.help.comp_cls_type = BT_COMPONENT_CLASS_TYPE_UNKNOWN; cfg->cmd_data.help.omit_system_plugin_path = omit_system_plugin_path; cfg->cmd_data.help.omit_home_plugin_path = omit_home_plugin_path; ret = append_env_var_plugin_paths(cfg->cmd_data.help.plugin_paths); @@ -2432,7 +2553,7 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], case OPT_SOURCE: case OPT_FILTER: case OPT_SINK: - if (cfg->cmd_data.help.comp_cls_type != + if (cfg->cmd_data.help.cfg_component->type != BT_COMPONENT_CLASS_TYPE_UNKNOWN) { printf_err("Cannot specify more than one plugin and component class:\n %s\n", arg); @@ -2441,15 +2562,15 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], switch (opt) { case OPT_SOURCE: - cfg->cmd_data.help.comp_cls_type = + cfg->cmd_data.help.cfg_component->type = BT_COMPONENT_CLASS_TYPE_SOURCE; break; case OPT_FILTER: - cfg->cmd_data.help.comp_cls_type = + cfg->cmd_data.help.cfg_component->type = BT_COMPONENT_CLASS_TYPE_FILTER; break; case OPT_SINK: - cfg->cmd_data.help.comp_cls_type = + cfg->cmd_data.help.cfg_component->type = BT_COMPONENT_CLASS_TYPE_SINK; break; default: @@ -2485,16 +2606,17 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], leftover = poptGetArg(pc); if (leftover) { - if (cfg->cmd_data.help.comp_cls_type != + if (cfg->cmd_data.help.cfg_component->type != BT_COMPONENT_CLASS_TYPE_UNKNOWN) { printf_err("Cannot specify plugin name and --source/--filter/--sink component class:\n %s\n", leftover); goto error; } - g_string_assign(cfg->cmd_data.help.plugin_name, leftover); + g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name, + leftover); } else { - if (cfg->cmd_data.help.comp_cls_type == + if (cfg->cmd_data.help.cfg_component->type == BT_COMPONENT_CLASS_TYPE_UNKNOWN) { print_help_usage(stdout); *retcode = -1; @@ -2505,8 +2627,9 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[], plugin_component_names_from_arg(plugin_comp_cls_names, &plugin_name, &component_name); if (plugin_name && component_name) { - g_string_assign(cfg->cmd_data.help.plugin_name, plugin_name); - g_string_assign(cfg->cmd_data.help.component_name, + g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name, + plugin_name); + g_string_assign(cfg->cmd_data.help.cfg_component->component_name, component_name); } else { printf_err("Invalid --source/--filter/--sink option's argument:\n %s\n", @@ -2542,6 +2665,246 @@ end: return cfg; } +/* + * Prints the help command usage. + */ +static +void print_query_usage(FILE *fp) +{ + fprintf(fp, "Usage: babeltrace [GEN OPTS] query [OPTS] OBJECT --source=PLUGIN.COMPCLS\n"); + fprintf(fp, " babeltrace [GEN OPTS] query [OPTS] OBJECT --filter=PLUGIN.COMPCLS\n"); + fprintf(fp, " babeltrace [GEN OPTS] query [OPTS] OBJECT --sink=PLUGIN.COMPCLS\n"); + fprintf(fp, "\n"); + fprintf(fp, "Options:\n"); + fprintf(fp, "\n"); + fprintf(fp, " --filter=PLUGIN.COMPCLS Query object from the filter component\n"); + fprintf(fp, " class COMPCLS found in 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"); + fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS\n"); + fprintf(fp, " (see the expected format of PARAMS below)\n"); + fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n"); + fprintf(fp, " dynamic plugins can be loaded\n"); + fprintf(fp, " --sink=PLUGIN.COMPCLS Query object from the sink component class\n"); + fprintf(fp, " COMPCLS found in the plugin PLUGIN\n"); + fprintf(fp, " --source=PLUGIN.COMPCLS Query object from the source component\n"); + fprintf(fp, " class COMPCLS found in the plugin PLUGIN\n"); + fprintf(fp, " -h --help Show this help and quit\n"); + fprintf(fp, "\n\n"); + print_expected_params_format(fp); +} + +static struct poptOption query_long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, 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 }, + { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL }, + { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, + { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL }, + { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL }, + { NULL, 0, 0, NULL, 0, NULL, NULL }, +}; + +/* + * Creates a Babeltrace config object from the arguments of a query + * command. + * + * *retcode is set to the appropriate exit code to use. + */ +struct bt_config *bt_config_query_from_args(int argc, const char *argv[], + int *retcode, bool omit_system_plugin_path, + bool omit_home_plugin_path, + struct bt_value *initial_plugin_paths) +{ + poptContext pc = NULL; + char *arg = NULL; + int opt; + int ret; + struct bt_config *cfg = NULL; + const char *leftover; + struct bt_value *params = bt_value_null; + + *retcode = 0; + cfg = bt_config_query_create(initial_plugin_paths); + if (!cfg) { + print_err_oom(); + goto error; + } + + cfg->cmd_data.query.omit_system_plugin_path = + omit_system_plugin_path; + cfg->cmd_data.query.omit_home_plugin_path = omit_home_plugin_path; + ret = append_env_var_plugin_paths(cfg->cmd_data.query.plugin_paths); + if (ret) { + printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n"); + goto error; + } + + /* Parse options */ + pc = poptGetContext(NULL, argc, (const char **) argv, + query_long_options, 0); + if (!pc) { + printf_err("Cannot get popt context\n"); + goto error; + } + + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) > 0) { + arg = poptGetOptArg(pc); + + switch (opt) { + case OPT_PLUGIN_PATH: + if (bt_common_is_setuid_setgid()) { + printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n"); + } else { + if (bt_config_append_plugin_paths( + cfg->cmd_data.query.plugin_paths, + arg)) { + printf_err("Invalid --plugin-path option's argument:\n %s\n", + arg); + goto error; + } + } + break; + case OPT_OMIT_SYSTEM_PLUGIN_PATH: + cfg->cmd_data.query.omit_system_plugin_path = true; + break; + case OPT_OMIT_HOME_PLUGIN_PATH: + cfg->cmd_data.query.omit_home_plugin_path = true; + break; + case OPT_SOURCE: + case OPT_FILTER: + case OPT_SINK: + { + enum bt_component_class_type type; + + if (cfg->cmd_data.query.cfg_component) { + printf_err("Cannot specify more than one plugin and component class:\n %s\n", + arg); + goto error; + } + + switch (opt) { + case OPT_SOURCE: + type = BT_COMPONENT_CLASS_TYPE_SOURCE; + break; + case OPT_FILTER: + type = BT_COMPONENT_CLASS_TYPE_FILTER; + break; + case OPT_SINK: + type = BT_COMPONENT_CLASS_TYPE_SINK; + break; + default: + assert(false); + } + + cfg->cmd_data.query.cfg_component = + bt_config_component_from_arg(type, arg); + if (!cfg->cmd_data.query.cfg_component) { + printf_err("Invalid format for --source/--filter/--sink 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: + { + params = bt_value_from_arg(arg); + if (!params) { + printf_err("Invalid format for --params option's argument:\n %s\n", + arg); + goto error; + } + break; + } + case OPT_HELP: + print_query_usage(stdout); + *retcode = -1; + BT_PUT(cfg); + goto end; + default: + printf_err("Unknown command-line option specified (option code %d)\n", + opt); + goto error; + } + + free(arg); + arg = NULL; + } + + if (!cfg->cmd_data.query.cfg_component) { + printf_err("No target component class specified with --source/--filter/--sink 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", + poptBadOption(pc, 0), poptStrerror(opt)); + goto error; + } + + /* + * We need exactly one leftover argument which is the + * mandatory object. + */ + leftover = poptGetArg(pc); + if (leftover) { + if (strlen(leftover) == 0) { + printf_err("Invalid empty object\n"); + goto error; + } + + g_string_assign(cfg->cmd_data.query.object, leftover); + } else { + print_query_usage(stdout); + *retcode = -1; + BT_PUT(cfg); + goto end; + } + + leftover = poptGetArg(pc); + if (leftover) { + printf_err("Invalid argument: %s\n", leftover); + goto error; + } + + if (append_home_and_system_plugin_paths( + cfg->cmd_data.query.plugin_paths, + cfg->cmd_data.query.omit_system_plugin_path, + cfg->cmd_data.query.omit_home_plugin_path)) { + printf_err("Cannot append home and system plugin paths\n"); + goto error; + } + + goto end; + +error: + *retcode = 1; + BT_PUT(cfg); + +end: + if (pc) { + poptFreeContext(pc); + } + + BT_PUT(params); + free(arg); + return cfg; +} + /* * Prints the list-plugins command usage. */ @@ -2768,6 +3131,8 @@ void print_convert_usage(FILE *fp) fprintf(fp, " --begin=BEGIN Set the `begin` parameter of the latest\n"); fprintf(fp, " source component instance to BEGIN\n"); fprintf(fp, " (see the suggested format of BEGIN below)\n"); + fprintf(fp, " -c, --connect=CONNECTION Connect two component instances (see the\n"); + fprintf(fp, " expected format of CONNECTION below)\n"); fprintf(fp, " -d, --debug Enable debug mode\n"); fprintf(fp, " --end=END Set the `end` parameter of the latest\n"); fprintf(fp, " source component instance to END\n"); @@ -2807,35 +3172,27 @@ void print_convert_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n"); fprintf(fp, "\n\n"); - fprintf(fp, "Expected format of PARAMS\n"); - fprintf(fp, "-------------------------\n"); + fprintf(fp, "Expected format of CONNECTION\n"); + fprintf(fp, "-----------------------------\n"); fprintf(fp, "\n"); - fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n"); + fprintf(fp, " SRC[.SRCPORT]:DST[.DSTPORT]\n"); fprintf(fp, "\n"); - fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n"); - fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n"); - fprintf(fp, "VALUE can be one of:\n"); + fprintf(fp, "SRC and DST are the names of the source and destination component\n"); + fprintf(fp, "instances to connect together. You can set the name of a component\n"); + fprintf(fp, "instance with the --name option.\n"); fprintf(fp, "\n"); - fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n"); - fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n"); - fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n"); - fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n"); - fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n"); - fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n"); - fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n"); - fprintf(fp, " the null and boolean value symbols above.\n"); - fprintf(fp, "* Double-quoted string (accepts escape characters).\n"); + fprintf(fp, "SRCPORT and DSTPORT are the optional source and destination ports to use\n"); + fprintf(fp, "for the connection. When the port is not specified, the default port is\n"); + fprintf(fp, "used.\n"); fprintf(fp, "\n"); - fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n"); + fprintf(fp, "You can connect a source component to a filter or sink component. You\n"); + fprintf(fp, "can connect a filter component to a sink component.\n"); fprintf(fp, "\n"); fprintf(fp, "Example:\n"); fprintf(fp, "\n"); - fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n"); - fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n"); - fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n"); - fprintf(fp, "\n"); - fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n"); - fprintf(fp, "from a shell.\n"); + fprintf(fp, " my-filter.top10:json-out\n"); + fprintf(fp, "\n\n"); + print_expected_params_format(fp); } static struct poptOption convert_long_options[] = { @@ -2849,6 +3206,7 @@ static struct poptOption convert_long_options[] = { { "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 }, + { "connect", 'c', POPT_ARG_STRING, NULL, OPT_CONNECT, 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 }, @@ -2905,6 +3263,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], int opt, ret = 0; struct bt_config *cfg = NULL; struct bt_value *instance_names = NULL; + struct bt_value *connection_args = NULL; + char error_buf[256] = { 0 }; *retcode = 0; memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts)); @@ -2960,6 +3320,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + connection_args = bt_value_array_create(); + if (!connection_args) { + print_err_oom(); + goto error; + } + ret = append_env_var_plugin_paths(cfg->cmd_data.convert.plugin_paths); if (ret) { printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n"); @@ -2967,7 +3333,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } /* Note: implicit source never gets positional base params. */ - implicit_source_comp = bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME); + implicit_source_comp = bt_config_component_from_arg( + BT_COMPONENT_CLASS_TYPE_SOURCE, DEFAULT_SOURCE_COMPONENT_NAME); if (!implicit_source_comp) { print_err_oom(); goto error; @@ -3069,7 +3436,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], cur_cfg_comp_dest); } - cur_cfg_comp = bt_config_component_from_arg(arg); + cur_cfg_comp = bt_config_component_from_arg( + BT_COMPONENT_CLASS_TYPE_SOURCE, arg); if (!cur_cfg_comp) { printf_err("Invalid format for --source option's argument:\n %s\n", arg); @@ -3113,14 +3481,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], LEGACY_OUTPUT_FORMAT_DUMMY; break; } else if (!strcmp(arg, "ctf-metadata")) { - /* Legacy CTF-metadata output format */ - if (legacy_output_format) { - print_err_dup_legacy_output(); - goto error; - } - - legacy_output_format = - LEGACY_OUTPUT_FORMAT_CTF_METADATA; + cfg->cmd_data.convert.print_ctf_metadata = true; break; } } @@ -3131,7 +3492,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], cur_cfg_comp_dest); } - cur_cfg_comp = bt_config_component_from_arg(arg); + cur_cfg_comp = bt_config_component_from_arg( + BT_COMPONENT_CLASS_TYPE_SINK, arg); if (!cur_cfg_comp) { printf_err("Invalid format for --sink option's argument:\n %s\n", arg); @@ -3388,12 +3750,20 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } break; } + case OPT_CONNECT: + if (bt_value_array_append_string(connection_args, + arg)) { + print_err_oom(); + goto error; + } + break; case OPT_HELP: print_convert_usage(stdout); *retcode = -1; BT_PUT(cfg); goto end; case OPT_VERBOSE: + text_legacy_opts.verbose = true; cfg->verbose = true; break; case OPT_DEBUG: @@ -3480,12 +3850,21 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } else { if (implicit_source_comp && !bt_value_map_is_empty(implicit_source_comp->params)) { - printf_err("Arguments specified for implicit source, but an explicit source has been specified, overriding it\n"); + printf_err("Arguments specified for implicit input format, but an explicit source component instance has been specified: overriding it\n"); goto error; } } } + /* + * At this point if we need to print the CTF metadata text, we + * don't care about the legacy/implicit sinks and component + * connections. + */ + if (cfg->cmd_data.convert.print_ctf_metadata) { + goto end; + } + /* * If there's a legacy output format, convert it to sink * component configurations. @@ -3500,7 +3879,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], if (cfg->cmd_data.convert.sinks->len == 0) { /* Use implicit sink as default. */ - cur_cfg_comp = bt_config_component_from_arg(DEFAULT_SINK_COMPONENT_NAME); + cur_cfg_comp = bt_config_component_from_arg( + BT_COMPONENT_CLASS_TYPE_SINK, + DEFAULT_SINK_COMPONENT_NAME); if (!cur_cfg_comp) { printf_error("Cannot find implicit sink plugin `%s`\n", DEFAULT_SINK_COMPONENT_NAME); @@ -3510,6 +3891,13 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], cur_cfg_comp = NULL; } + ret = bt_config_create_connections(cfg, connection_args, + error_buf, 256); + if (ret) { + printf_err("Cannot creation connections:\n%s", error_buf); + goto error; + } + goto end; error: @@ -3541,6 +3929,7 @@ end: BT_PUT(text_legacy_opts.fields); BT_PUT(legacy_input_paths); BT_PUT(instance_names); + BT_PUT(connection_args); return cfg; } @@ -3565,6 +3954,7 @@ void print_gen_usage(FILE *fp) fprintf(fp, " convert Build a trace conversion graph and run it (default)\n"); fprintf(fp, " help Get help for a plugin or a component class\n"); fprintf(fp, " list-plugins List available plugins and their content\n"); + fprintf(fp, " query Query objects from a component class\n"); fprintf(fp, "\n"); fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n"); } @@ -3623,6 +4013,8 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], command = BT_CONFIG_COMMAND_LIST_PLUGINS; } else if (strcmp(cur_arg, "help") == 0) { command = BT_CONFIG_COMMAND_HELP; + } else if (strcmp(cur_arg, "query") == 0) { + command = BT_CONFIG_COMMAND_QUERY; } else { /* * Unknown argument, but not a known @@ -3675,6 +4067,11 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], command_argv, retcode, omit_system_plugin_path, omit_home_plugin_path, initial_plugin_paths); break; + case BT_CONFIG_COMMAND_QUERY: + config = bt_config_query_from_args(command_argc, + command_argv, retcode, omit_system_plugin_path, + omit_home_plugin_path, initial_plugin_paths); + break; default: assert(false); }