+/*
+ * Sets the value of a given legacy offset option and marks it as set.
+ */
+static void set_offset_value(struct offset_opt *offset_opt, int64_t value)
+{
+ offset_opt->value = value;
+ offset_opt->is_set = true;
+}
+
+enum bt_config_component_dest {
+ BT_CONFIG_COMPONENT_DEST_SOURCE,
+ BT_CONFIG_COMPONENT_DEST_SINK,
+};
+
+/*
+ * Adds a configuration component to the appropriate configuration
+ * array depending on the destination.
+ */
+static void add_cfg_comp(struct bt_config *cfg,
+ struct bt_config_component *cfg_comp,
+ enum bt_config_component_dest dest)
+{
+ if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
+ g_ptr_array_add(cfg->cmd_data.convert.sources, cfg_comp);
+ } else {
+ g_ptr_array_add(cfg->cmd_data.convert.sinks, cfg_comp);
+ }
+}
+
+static int split_timerange(const char *arg, const char **begin, const char **end)
+{
+ const char *c;
+
+ /* Try to match [begin,end] */
+ c = strchr(arg, '[');
+ if (!c)
+ goto skip;
+ *begin = ++c;
+ c = strchr(c, ',');
+ if (!c)
+ goto skip;
+ *end = ++c;
+ c = strchr(c, ']');
+ if (!c)
+ goto skip;
+ goto found;
+
+skip:
+ /* Try to match begin,end */
+ c = arg;
+ *begin = c;
+ c = strchr(c, ',');
+ if (!c)
+ goto not_found;
+ *end = ++c;
+ /* fall-through */
+found:
+ return 0;
+not_found:
+ return -1;
+}
+
+static int append_env_var_plugin_paths(struct bt_value *plugin_paths)
+{
+ int ret = 0;
+ const char *envvar;
+
+ if (bt_common_is_setuid_setgid()) {
+ printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
+ goto end;
+ }
+
+ envvar = getenv("BABELTRACE_PLUGIN_PATH");
+ if (!envvar) {
+ goto end;
+ }
+
+ ret = bt_config_append_plugin_paths(plugin_paths, envvar);
+
+end:
+ return ret;
+}
+
+static int append_home_and_system_plugin_paths(struct bt_value *plugin_paths,
+ bool omit_system_plugin_path, bool omit_home_plugin_path)
+{
+ int ret;
+
+ if (!omit_home_plugin_path) {
+ if (bt_common_is_setuid_setgid()) {
+ printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
+ } else {
+ char *home_plugin_dir =
+ bt_common_get_home_plugin_path();
+
+ if (home_plugin_dir) {
+ ret = bt_config_append_plugin_paths(
+ plugin_paths,
+ home_plugin_dir);
+ free(home_plugin_dir);
+
+ if (ret) {
+ printf_err("Invalid home plugin path\n");
+ goto error;
+ }
+ }
+ }
+ }
+
+ if (!omit_system_plugin_path) {
+ if (bt_config_append_plugin_paths(plugin_paths,
+ bt_common_get_system_plugin_path())) {
+ printf_err("Invalid system plugin path\n");
+ goto error;
+ }
+ }
+ return 0;
+error:
+ return -1;
+}
+
+static int append_sources_from_implicit_params(GPtrArray *sources,
+ struct bt_config_component *implicit_source_comp)
+{
+ size_t i;
+ size_t len = sources->len;
+
+ for (i = 0; i < len; i++) {
+ struct bt_config_component *comp;
+ struct bt_value *params_to_set;
+
+ comp = g_ptr_array_index(sources, i);
+ params_to_set = bt_value_map_extend(comp->params,
+ implicit_source_comp->params);
+ if (!params_to_set) {
+ printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
+ goto error;
+ }
+ BT_MOVE(comp->params, params_to_set);
+ }
+ return 0;
+error:
+ return -1;
+}
+
+static struct bt_config *bt_config_base_create(enum bt_config_command command)
+{
+ struct bt_config *cfg;
+
+ /* Create config */
+ cfg = g_new0(struct bt_config, 1);
+ if (!cfg) {
+ print_err_oom();
+ goto error;
+ }
+
+ bt_object_init(cfg, bt_config_destroy);
+ cfg->command = command;
+ goto end;
+
+error:
+ BT_PUT(cfg);
+
+end:
+ return cfg;
+}
+
+static struct bt_config *bt_config_convert_create(
+ struct bt_value *initial_plugin_paths)
+{
+ struct bt_config *cfg;
+
+ /* Create config */
+ cfg = bt_config_base_create(BT_CONFIG_COMMAND_CONVERT);
+ if (!cfg) {
+ print_err_oom();
+ goto error;
+ }
+
+ cfg->cmd_data.convert.sources = g_ptr_array_new_with_free_func(
+ (GDestroyNotify) bt_put);
+ if (!cfg->cmd_data.convert.sources) {
+ print_err_oom();
+ 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) {
+ print_err_oom();
+ 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);
+ } else {
+ cfg->cmd_data.convert.plugin_paths = bt_value_array_create();
+ if (!cfg->cmd_data.convert.plugin_paths) {
+ print_err_oom();
+ goto error;
+ }
+ }
+
+ goto end;
+
+error:
+ BT_PUT(cfg);
+
+end:
+ return cfg;
+}
+
+static struct bt_config *bt_config_list_plugins_create(
+ struct bt_value *initial_plugin_paths)
+{
+ struct bt_config *cfg;
+
+ /* Create config */
+ cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS);
+ if (!cfg) {
+ print_err_oom();
+ goto error;
+ }
+
+ if (initial_plugin_paths) {
+ cfg->cmd_data.list_plugins.plugin_paths =
+ bt_get(initial_plugin_paths);
+ } else {
+ cfg->cmd_data.list_plugins.plugin_paths =
+ bt_value_array_create();
+ if (!cfg->cmd_data.list_plugins.plugin_paths) {
+ print_err_oom();
+ goto error;
+ }
+ }
+
+ goto end;
+
+error:
+ BT_PUT(cfg);
+
+end:
+ return cfg;
+}
+
+static struct bt_config *bt_config_help_create(
+ struct bt_value *initial_plugin_paths)
+{
+ struct bt_config *cfg;
+
+ /* Create config */
+ cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP);
+ if (!cfg) {
+ print_err_oom();
+ goto error;
+ }
+
+ if (initial_plugin_paths) {
+ cfg->cmd_data.help.plugin_paths =
+ bt_get(initial_plugin_paths);
+ } else {
+ cfg->cmd_data.help.plugin_paths =
+ bt_value_array_create();
+ if (!cfg->cmd_data.help.plugin_paths) {
+ print_err_oom();
+ goto error;
+ }
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ goto end;
+
+error:
+ BT_PUT(cfg);
+
+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.
+ */
+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, "\n");
+ fprintf(fp, "Options:\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " --filter=PLUGIN.COMPCLS Get help for the filter component class\n");
+ fprintf(fp, " 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, " --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 Get help for the sink component class\n");
+ fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
+ fprintf(fp, " --source=PLUGIN.COMPCLS Get help for the source component class\n");
+ fprintf(fp, " COMPCLS found in the plugin PLUGIN\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");
+ fprintf(fp, "Use `babeltrace list-plugins` to show the list of available plugins.\n");
+}
+
+static struct poptOption help_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 },
+ { "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 help
+ * command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+struct bt_config *bt_config_help_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;
+ char *plugin_name = NULL, *component_name = NULL;
+ char *plugin_comp_cls_names = NULL;
+
+ *retcode = 0;
+ cfg = bt_config_help_create(initial_plugin_paths);
+ if (!cfg) {
+ print_err_oom();
+ goto error;
+ }
+
+ 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);
+ if (ret) {
+ printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
+ goto error;
+ }
+
+ /* Parse options */
+ pc = poptGetContext(NULL, argc, (const char **) argv,
+ help_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.help.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.help.omit_system_plugin_path = true;
+ break;
+ case OPT_OMIT_HOME_PLUGIN_PATH:
+ cfg->cmd_data.help.omit_home_plugin_path = true;
+ break;
+ case OPT_SOURCE:
+ case OPT_FILTER:
+ case OPT_SINK:
+ 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);
+ goto error;
+ }
+
+ switch (opt) {
+ case OPT_SOURCE:
+ cfg->cmd_data.help.cfg_component->type =
+ BT_COMPONENT_CLASS_TYPE_SOURCE;
+ break;
+ case OPT_FILTER:
+ cfg->cmd_data.help.cfg_component->type =
+ BT_COMPONENT_CLASS_TYPE_FILTER;
+ break;
+ case OPT_SINK:
+ cfg->cmd_data.help.cfg_component->type =
+ BT_COMPONENT_CLASS_TYPE_SINK;
+ break;
+ default:
+ assert(false);
+ }
+ plugin_comp_cls_names = strdup(arg);
+ if (!plugin_comp_cls_names) {
+ print_err_oom();
+ goto error;
+ }
+ break;
+ case OPT_HELP:
+ print_help_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;
+ }
+
+ /* 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;
+ }
+
+ leftover = poptGetArg(pc);
+ if (leftover) {
+ 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.cfg_component->plugin_name,
+ leftover);
+ } else {
+ if (cfg->cmd_data.help.cfg_component->type ==
+ BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
+ print_help_usage(stdout);
+ *retcode = -1;
+ BT_PUT(cfg);
+ goto end;
+ }
+
+ 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.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",
+ plugin_comp_cls_names);
+ goto error;
+ }
+ }
+
+ if (append_home_and_system_plugin_paths(
+ cfg->cmd_data.help.plugin_paths,
+ cfg->cmd_data.help.omit_system_plugin_path,
+ cfg->cmd_data.help.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:
+ free(plugin_comp_cls_names);
+ g_free(plugin_name);
+ g_free(component_name);
+
+ if (pc) {
+ poptFreeContext(pc);
+ }
+
+ free(arg);
+ 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.
+ */
+static
+void print_list_plugins_usage(FILE *fp)
+{
+ fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "Options:\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
+ fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
+ fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
+ fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
+ fprintf(fp, " dynamic plugins can be loaded\n");
+ fprintf(fp, " -h --help Show this help and quit\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "Use `babeltrace help` to get help for a specific plugin or component class.\n");
+}
+
+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 },
+};
+
+/*
+ * Creates a Babeltrace config object from the arguments of a
+ * list-plugins command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+struct bt_config *bt_config_list_plugins_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;
+
+ *retcode = 0;
+ cfg = bt_config_list_plugins_create(initial_plugin_paths);
+ if (!cfg) {
+ print_err_oom();
+ goto error;
+ }
+
+ cfg->cmd_data.list_plugins.omit_system_plugin_path = omit_system_plugin_path;
+ cfg->cmd_data.list_plugins.omit_home_plugin_path = omit_home_plugin_path;
+ ret = append_env_var_plugin_paths(
+ cfg->cmd_data.list_plugins.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,
+ list_plugins_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.list_plugins.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.list_plugins.omit_system_plugin_path = true;
+ break;
+ case OPT_OMIT_HOME_PLUGIN_PATH:
+ cfg->cmd_data.list_plugins.omit_home_plugin_path = true;
+ break;
+ case OPT_HELP:
+ print_list_plugins_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;
+ }
+
+ /* 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;
+ }
+
+ leftover = poptGetArg(pc);
+ if (leftover) {
+ printf_err("Invalid argument: %s\n", leftover);
+ goto error;
+ }
+
+ if (append_home_and_system_plugin_paths(
+ cfg->cmd_data.list_plugins.plugin_paths,
+ cfg->cmd_data.list_plugins.omit_system_plugin_path,
+ cfg->cmd_data.list_plugins.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);
+ }
+
+ free(arg);
+ return cfg;
+}
+
+/*
+ * Prints the legacy, Babeltrace 1.x command usage. Those options are
+ * still compatible in Babeltrace 2.x, but it is recommended to use
+ * the more generic plugin/component parameters instead of those
+ * hard-coded option names.
+ */
+static
+void print_legacy_usage(FILE *fp)
+{
+ fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " --clock-force-correlate Assume that clocks are inherently correlated\n");
+ fprintf(fp, " across traces\n");
+ fprintf(fp, " -d, --debug Enable debug mode\n");
+ fprintf(fp, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
+ fprintf(fp, " -l, --list List available formats\n");
+ fprintf(fp, " -o, --output-format=FORMAT Output trace format (default: text)\n");
+ fprintf(fp, " -v, --verbose Enable verbose output\n");
+ fprintf(fp, " --help-legacy Show this help and quit\n");
+ fprintf(fp, " -V, --version Show version and quit\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " Available input formats: ctf, lttng-live, ctf-metadata\n");
+ fprintf(fp, " Available output formats: text, dummy\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "Input formats specific options:\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " INPUT... Input trace file(s), directory(ies), or URLs\n");
+ fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n");
+ fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
+ fprintf(fp, " --stream-intersection Only process events when all streams are active\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "text output format specific options:\n");
+ fprintf(fp, " \n");
+ fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n");
+ fprintf(fp, " --clock-date Print timestamp dates\n");
+ fprintf(fp, " --clock-gmt Print and parse timestamps in GMT time zone\n");
+ fprintf(fp, " (default: local time zone)\n");
+ fprintf(fp, " --clock-seconds Print the timestamps as [SEC.NS]\n");
+ fprintf(fp, " (default format: [HH:MM:SS.NS])\n");
+ fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
+ fprintf(fp, " (default: `/usr/lib/debug`)\n");
+ fprintf(fp, " --debug-info-full-path Show full debug info source and binary paths\n");
+ fprintf(fp, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
+ fprintf(fp, " up executables during debug info analysis\n");
+ fprintf(fp, " (default: `/usr/lib/debug`)\n");
+ fprintf(fp, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
+ fprintf(fp, " all, trace, trace:hostname, trace:domain,\n");
+ fprintf(fp, " trace:procname, trace:vpid, loglevel, emf\n");
+ fprintf(fp, " (default: trace:hostname, trace:procname,\n");
+ fprintf(fp, " trace:vpid)\n");
+ fprintf(fp, " -n, --names=NAME[,NAME]... Print field names:\n");
+ fprintf(fp, " payload (or arg or args)\n");
+ fprintf(fp, " none, all, scope, header, context (or ctx)\n");
+ fprintf(fp, " (default: payload, context)\n");
+ fprintf(fp, " --no-delta Do not print time delta between consecutive\n");
+ fprintf(fp, " events\n");
+ fprintf(fp, " -w, --output=PATH Write output to PATH (default: standard output)\n");
+}
+
+/*
+ * Prints the convert command usage.
+ */
+static
+void print_convert_usage(FILE *fp)
+{
+ fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "Options:\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
+ fprintf(fp, " for the following component instances\n");
+ fprintf(fp, " (see the expected format of PARAMS below)\n");
+ 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");
+ fprintf(fp, " (see the suggested format of BEGIN below)\n");
+ fprintf(fp, " --name=NAME Set the name of the latest component\n");
+ fprintf(fp, " instance to NAME (must be unique amongst\n");
+ fprintf(fp, " all the names of the component instances)\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 parameters of the latest component\n");
+ fprintf(fp, " instance (in command-line order) to PARAMS\n");
+ fprintf(fp, " (see the expected format of PARAMS below)\n");
+ fprintf(fp, " -P, --path=PATH Set the `path` parameter of the latest\n");
+ fprintf(fp, " component instance 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, " -r, --reset-base-params Reset the current base parameters of the\n");
+ fprintf(fp, " following source and sink component\n");
+ fprintf(fp, " instances to an empty map\n");
+ fprintf(fp, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
+ fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
+ fprintf(fp, " repeated)\n");
+ fprintf(fp, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
+ fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
+ fprintf(fp, " repeated)\n");
+ fprintf(fp, " --timerange=TIMERANGE Set time range to TIMERANGE: BEGIN,END or\n");
+ fprintf(fp, " [BEGIN,END] (literally `[` and `]`)\n");
+ fprintf(fp, " (suggested format of BEGIN/END below)\n");
+ fprintf(fp, " -v, --verbose Enable verbose output\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");
+ fprintf(fp, "Suggested format of BEGIN and END\n");
+ fprintf(fp, "---------------------------------\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
+ fprintf(fp, "\n\n");
+ fprintf(fp, "Expected format of CONNECTION\n");
+ fprintf(fp, "-----------------------------\n");
+ fprintf(fp, "\n");
+ fprintf(fp, " SRC[.SRCPORT]:DST[.DSTPORT]\n");
+ fprintf(fp, "\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, "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, "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, " my-filter.top10:json-out\n");
+ fprintf(fp, "\n\n");
+ print_expected_params_format(fp);
+}
+
+static struct poptOption convert_long_options[] = {