cli: make config cli args functions return a status enum
[babeltrace.git] / src / cli / babeltrace2-cfg-cli-args.c
CommitLineData
9009cc24 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
9009cc24
PP
3 *
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
5 *
0235b0db 6 * Babeltrace trace converter - parameter parsing
9009cc24
PP
7 */
8
3c729b9a 9#define BT_LOG_TAG "CLI/CFG-CLI-ARGS"
b4565e8b
PP
10#include "logging.h"
11
9009cc24
PP
12#include <errno.h>
13#include <stdlib.h>
14#include <string.h>
578e048b 15#include "common/assert.h"
9009cc24
PP
16#include <stdio.h>
17#include <stdbool.h>
18#include <inttypes.h>
3fadfbc0 19#include <babeltrace2/babeltrace.h>
578e048b 20#include "common/common.h"
9009cc24
PP
21#include <glib.h>
22#include <sys/types.h>
0e497e1c 23#include "argpar/argpar.h"
ec2c5e50
MJ
24#include "babeltrace2-cfg.h"
25#include "babeltrace2-cfg-cli-args.h"
26#include "babeltrace2-cfg-cli-args-connect.h"
5869b179 27#include "param-parse/param-parse.h"
ebddaeb8 28#include "babeltrace2-log-level.h"
73760435 29#include "babeltrace2-plugins.h"
97010665
SM
30#include "babeltrace2-query.h"
31#include "autodisc/autodisc.h"
578e048b 32#include "common/version.h"
9009cc24 33
9f901451 34#define BT_CLI_LOGE_APPEND_CAUSE_OOM() BT_CLI_LOGE_APPEND_CAUSE("Out of memory.")
a93e984c 35#define WHILE_PARSING_ARG_N_FMT "While parsing argument #%d (`%s`): "
9009cc24 36
9009cc24 37/*
fd5f8053
PP
38 * Returns the plugin name, component class name, component class type,
39 * and component name from a command-line --component option's argument.
40 * arg must have the following format:
9009cc24 41 *
fd5f8053 42 * [NAME:]TYPE.PLUGIN.CLS
9009cc24 43 *
fd5f8053
PP
44 * where NAME is the optional component name, TYPE is either `source`,
45 * `filter`, or `sink`, PLUGIN is the plugin name, and CLS is the
46 * component class name.
9009cc24
PP
47 *
48 * On success, both *plugin and *component are not NULL. *plugin
e5c7cd9b
PP
49 * and *comp_cls are owned by the caller. On success, *name can be NULL
50 * if no component class name was found, and *comp_cls_type is set.
9009cc24
PP
51 */
52static
53void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
4cdfc5e8 54 char **comp_cls, bt_component_class_type *comp_cls_type)
9009cc24
PP
55{
56 const char *at = arg;
57 GString *gs_name = NULL;
fd5f8053 58 GString *gs_comp_cls_type = NULL;
9009cc24
PP
59 GString *gs_plugin = NULL;
60 GString *gs_comp_cls = NULL;
61 size_t end_pos;
62
f6ccaed9
PP
63 BT_ASSERT(arg);
64 BT_ASSERT(plugin);
65 BT_ASSERT(comp_cls);
66 BT_ASSERT(comp_cls_type);
9009cc24
PP
67
68 if (!bt_common_string_is_printable(arg)) {
9f901451 69 BT_CLI_LOGE_APPEND_CAUSE("Argument contains a non-printable character.");
9009cc24
PP
70 goto error;
71 }
72
73 /* Parse the component name */
74 gs_name = bt_common_string_until(at, ".:\\", ":", &end_pos);
75 if (!gs_name) {
76 goto error;
77 }
78
79 if (arg[end_pos] == ':') {
80 at += end_pos + 1;
81 } else {
82 /* No name */
83 g_string_assign(gs_name, "");
84 }
85
fd5f8053
PP
86 /* Parse the component class type */
87 gs_comp_cls_type = bt_common_string_until(at, ".:\\", ".", &end_pos);
88 if (!gs_comp_cls_type || at[end_pos] == '\0') {
9f901451 89 BT_CLI_LOGE_APPEND_CAUSE("Missing component class type (`source`, `filter`, or `sink`).");
fd5f8053
PP
90 goto error;
91 }
92
93 if (strcmp(gs_comp_cls_type->str, "source") == 0 ||
94 strcmp(gs_comp_cls_type->str, "src") == 0) {
95 *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SOURCE;
96 } else if (strcmp(gs_comp_cls_type->str, "filter") == 0 ||
97 strcmp(gs_comp_cls_type->str, "flt") == 0) {
98 *comp_cls_type = BT_COMPONENT_CLASS_TYPE_FILTER;
99 } else if (strcmp(gs_comp_cls_type->str, "sink") == 0) {
100 *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SINK;
101 } else {
9f901451 102 BT_CLI_LOGE_APPEND_CAUSE("Unknown component class type: `%s`.",
fd5f8053
PP
103 gs_comp_cls_type->str);
104 goto error;
105 }
106
107 at += end_pos + 1;
108
9009cc24
PP
109 /* Parse the plugin name */
110 gs_plugin = bt_common_string_until(at, ".:\\", ".", &end_pos);
111 if (!gs_plugin || gs_plugin->len == 0 || at[end_pos] == '\0') {
9f901451 112 BT_CLI_LOGE_APPEND_CAUSE("Missing plugin or component class name.");
9009cc24
PP
113 goto error;
114 }
115
116 at += end_pos + 1;
117
118 /* Parse the component class name */
119 gs_comp_cls = bt_common_string_until(at, ".:\\", ".", &end_pos);
120 if (!gs_comp_cls || gs_comp_cls->len == 0) {
9f901451 121 BT_CLI_LOGE_APPEND_CAUSE("Missing component class name.");
9009cc24
PP
122 goto error;
123 }
124
125 if (at[end_pos] != '\0') {
126 /* Found a non-escaped `.` */
127 goto error;
128 }
129
130 if (name) {
131 if (gs_name->len == 0) {
132 *name = NULL;
133 g_string_free(gs_name, TRUE);
134 } else {
135 *name = gs_name->str;
136 g_string_free(gs_name, FALSE);
137 }
138 } else {
139 g_string_free(gs_name, TRUE);
140 }
141
142 *plugin = gs_plugin->str;
143 *comp_cls = gs_comp_cls->str;
144 g_string_free(gs_plugin, FALSE);
145 g_string_free(gs_comp_cls, FALSE);
146 gs_name = NULL;
147 gs_plugin = NULL;
148 gs_comp_cls = NULL;
149 goto end;
150
151error:
282c8cd0
PP
152 if (name) {
153 *name = NULL;
154 }
155
156 *plugin = NULL;
157 *comp_cls = NULL;
158
159end:
9009cc24
PP
160 if (gs_name) {
161 g_string_free(gs_name, TRUE);
162 }
163
164 if (gs_plugin) {
165 g_string_free(gs_plugin, TRUE);
166 }
167
168 if (gs_comp_cls) {
169 g_string_free(gs_comp_cls, TRUE);
170 }
171
282c8cd0
PP
172 if (gs_comp_cls_type) {
173 g_string_free(gs_comp_cls_type, TRUE);
9009cc24
PP
174 }
175
9009cc24
PP
176 return;
177}
178
842193c9
PP
179static
180void print_and_indent(const char *str)
181{
182 const char *ch = &str[0];
183
184 for (; *ch != '\0'; ch++) {
185 if (*ch == '\n') {
186 if (ch[1] != '\0') {
187 printf("\n ");
188 }
189 } else {
190 printf("%c", *ch);
191 }
192 }
193
194 printf("\n");
195}
196
9009cc24
PP
197/*
198 * Prints the Babeltrace version.
199 */
200static
201void print_version(void)
202{
842193c9
PP
203 bool has_extra_name = strlen(BT_VERSION_EXTRA_NAME) > 0;
204 bool has_extra_description = strlen(BT_VERSION_EXTRA_DESCRIPTION) > 0;
205 bool has_extra_patch_names = strlen(BT_VERSION_EXTRA_PATCHES) > 0;
206 bool has_extra = has_extra_name || has_extra_description ||
207 has_extra_patch_names;
208
836e3fd0
PP
209 printf("%sBabeltrace %s%s",
210 bt_common_color_bold(),
211 VERSION,
212 bt_common_color_reset());
842193c9
PP
213
214 if (strlen(BT_VERSION_NAME) > 0) {
836e3fd0
PP
215 printf(" \"%s%s%s%s\"",
216 bt_common_color_fg_bright_blue(),
217 bt_common_color_bold(),
218 BT_VERSION_NAME,
219 bt_common_color_reset());
842193c9
PP
220 }
221
222 if (strlen(BT_VERSION_GIT) > 0) {
836e3fd0
PP
223 printf(" [%s%s%s]",
224 bt_common_color_fg_yellow(),
225 BT_VERSION_GIT,
226 bt_common_color_reset());
842193c9
PP
227 }
228
229 printf("\n");
230
231 if (strlen(BT_VERSION_DESCRIPTION) > 0) {
232 unsigned int columns;
233 GString *descr;
234
235 if (bt_common_get_term_size(&columns, NULL) < 0) {
236 /* Width not found: default to 80 */
237 columns = 80;
238 }
239
240 descr = bt_common_fold(BT_VERSION_DESCRIPTION, columns, 0);
241 BT_ASSERT(descr);
242 printf("\n%s\n", descr->str);
243 g_string_free(descr, TRUE);
244 }
245
246 if (has_extra) {
247 printf("\n");
248
249 if (has_extra_name) {
836e3fd0
PP
250 printf("%sExtra name%s: %s\n",
251 bt_common_color_fg_cyan(),
252 bt_common_color_reset(),
253 BT_VERSION_EXTRA_NAME);
842193c9
PP
254 }
255
256 if (has_extra_description) {
836e3fd0
PP
257 printf("%sExtra description%s:\n ",
258 bt_common_color_fg_cyan(),
259 bt_common_color_reset());
842193c9
PP
260 print_and_indent(BT_VERSION_EXTRA_DESCRIPTION);
261 }
262
263 if (has_extra_patch_names) {
836e3fd0
PP
264 printf("%sExtra patch names%s:\n ",
265 bt_common_color_fg_cyan(),
266 bt_common_color_reset());
842193c9
PP
267 print_and_indent(BT_VERSION_EXTRA_PATCHES);
268 }
7845e95f 269 }
9009cc24
PP
270}
271
272/*
273 * Destroys a component configuration.
274 */
275static
b19ff26f 276void bt_config_component_destroy(bt_object *obj)
9009cc24
PP
277{
278 struct bt_config_component *bt_config_component =
279 container_of(obj, struct bt_config_component, base);
280
281 if (!obj) {
282 goto end;
283 }
284
285 if (bt_config_component->plugin_name) {
286 g_string_free(bt_config_component->plugin_name, TRUE);
287 }
288
289 if (bt_config_component->comp_cls_name) {
290 g_string_free(bt_config_component->comp_cls_name, TRUE);
291 }
292
293 if (bt_config_component->instance_name) {
294 g_string_free(bt_config_component->instance_name, TRUE);
295 }
296
c5b9b441 297 BT_VALUE_PUT_REF_AND_RESET(bt_config_component->params);
9009cc24
PP
298 g_free(bt_config_component);
299
300end:
301 return;
302}
303
304/*
305 * Creates a component configuration using the given plugin name and
306 * component name. `plugin_name` and `comp_cls_name` are copied (belong
307 * to the return value).
308 *
309 * Return value is owned by the caller.
310 */
311static
312struct bt_config_component *bt_config_component_create(
4cdfc5e8 313 bt_component_class_type type,
29da2ffc
PP
314 const char *plugin_name, const char *comp_cls_name,
315 int init_log_level)
9009cc24
PP
316{
317 struct bt_config_component *cfg_component = NULL;
318
319 cfg_component = g_new0(struct bt_config_component, 1);
320 if (!cfg_component) {
9f901451 321 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
322 goto error;
323 }
324
3fea54f6
PP
325 bt_object_init_shared(&cfg_component->base,
326 bt_config_component_destroy);
9009cc24
PP
327 cfg_component->type = type;
328 cfg_component->plugin_name = g_string_new(plugin_name);
329 if (!cfg_component->plugin_name) {
9f901451 330 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
331 goto error;
332 }
333
334 cfg_component->comp_cls_name = g_string_new(comp_cls_name);
335 if (!cfg_component->comp_cls_name) {
9f901451 336 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
337 goto error;
338 }
339
340 cfg_component->instance_name = g_string_new(NULL);
341 if (!cfg_component->instance_name) {
9f901451 342 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
343 goto error;
344 }
345
29da2ffc
PP
346 cfg_component->log_level = init_log_level;
347
9009cc24 348 /* Start with empty parameters */
05e21286 349 cfg_component->params = bt_value_map_create();
9009cc24 350 if (!cfg_component->params) {
9f901451 351 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
352 goto error;
353 }
354
355 goto end;
356
357error:
65300d60 358 BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
9009cc24
PP
359
360end:
361 return cfg_component;
362}
363
364/*
fd5f8053 365 * Creates a component configuration from a command-line --component
9009cc24
PP
366 * option's argument.
367 */
368static
29da2ffc
PP
369struct bt_config_component *bt_config_component_from_arg(const char *arg,
370 int init_log_level)
9009cc24
PP
371{
372 struct bt_config_component *cfg_comp = NULL;
373 char *name = NULL;
374 char *plugin_name = NULL;
375 char *comp_cls_name = NULL;
4cdfc5e8 376 bt_component_class_type type;
9009cc24 377
fd5f8053 378 plugin_comp_cls_names(arg, &name, &plugin_name, &comp_cls_name, &type);
9009cc24 379 if (!plugin_name || !comp_cls_name) {
9009cc24
PP
380 goto error;
381 }
382
29da2ffc
PP
383 cfg_comp = bt_config_component_create(type, plugin_name, comp_cls_name,
384 init_log_level);
9009cc24
PP
385 if (!cfg_comp) {
386 goto error;
387 }
388
389 if (name) {
390 g_string_assign(cfg_comp->instance_name, name);
391 }
392
393 goto end;
394
395error:
65300d60 396 BT_OBJECT_PUT_REF_AND_RESET(cfg_comp);
9009cc24
PP
397
398end:
399 g_free(name);
400 g_free(plugin_name);
401 g_free(comp_cls_name);
402 return cfg_comp;
403}
404
405/*
406 * Destroys a configuration.
407 */
408static
b19ff26f 409void bt_config_destroy(bt_object *obj)
9009cc24
PP
410{
411 struct bt_config *cfg =
412 container_of(obj, struct bt_config, base);
413
414 if (!obj) {
415 goto end;
416 }
417
c5b9b441 418 BT_VALUE_PUT_REF_AND_RESET(cfg->plugin_paths);
9009cc24
PP
419
420 switch (cfg->command) {
421 case BT_CONFIG_COMMAND_RUN:
422 if (cfg->cmd_data.run.sources) {
423 g_ptr_array_free(cfg->cmd_data.run.sources, TRUE);
424 }
425
426 if (cfg->cmd_data.run.filters) {
427 g_ptr_array_free(cfg->cmd_data.run.filters, TRUE);
428 }
429
430 if (cfg->cmd_data.run.sinks) {
431 g_ptr_array_free(cfg->cmd_data.run.sinks, TRUE);
432 }
433
434 if (cfg->cmd_data.run.connections) {
435 g_ptr_array_free(cfg->cmd_data.run.connections,
436 TRUE);
437 }
438 break;
439 case BT_CONFIG_COMMAND_LIST_PLUGINS:
440 break;
441 case BT_CONFIG_COMMAND_HELP:
65300d60 442 BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.help.cfg_component);
9009cc24
PP
443 break;
444 case BT_CONFIG_COMMAND_QUERY:
65300d60 445 BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.query.cfg_component);
9009cc24
PP
446
447 if (cfg->cmd_data.query.object) {
448 g_string_free(cfg->cmd_data.query.object, TRUE);
449 }
450 break;
451 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
452 if (cfg->cmd_data.print_ctf_metadata.path) {
453 g_string_free(cfg->cmd_data.print_ctf_metadata.path,
454 TRUE);
c327e427
PP
455 g_string_free(
456 cfg->cmd_data.print_ctf_metadata.output_path,
457 TRUE);
9009cc24
PP
458 }
459 break;
460 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
461 if (cfg->cmd_data.print_lttng_live_sessions.url) {
462 g_string_free(
463 cfg->cmd_data.print_lttng_live_sessions.url,
464 TRUE);
c327e427
PP
465 g_string_free(
466 cfg->cmd_data.print_lttng_live_sessions.output_path,
467 TRUE);
9009cc24
PP
468 }
469 break;
470 default:
498e7994 471 bt_common_abort();
9009cc24
PP
472 }
473
474 g_free(cfg);
475
476end:
477 return;
478}
479
480static
481void destroy_glist_of_gstring(GList *list)
482{
94023a1c
PP
483 GList *at;
484
9009cc24
PP
485 if (!list) {
486 return;
487 }
488
5084732e 489 for (at = list; at; at = g_list_next(at)) {
9009cc24
PP
490 g_string_free(at->data, TRUE);
491 }
492
493 g_list_free(list);
494}
495
496/*
497 * Creates a simple lexical scanner for parsing comma-delimited names
498 * and fields.
499 *
500 * Return value is owned by the caller.
501 */
502static
503GScanner *create_csv_identifiers_scanner(void)
504{
505 GScanner *scanner;
506 GScannerConfig scanner_config = {
02bb4fcc
SM
507 .cset_skip_characters = (gchar *) " \t\n",
508 .cset_identifier_first = (gchar *) G_CSET_a_2_z G_CSET_A_2_Z "_",
509 .cset_identifier_nth = (gchar *) G_CSET_a_2_z G_CSET_A_2_Z ":_-",
9009cc24
PP
510 .case_sensitive = TRUE,
511 .cpair_comment_single = NULL,
512 .skip_comment_multi = TRUE,
513 .skip_comment_single = TRUE,
514 .scan_comment_multi = FALSE,
515 .scan_identifier = TRUE,
516 .scan_identifier_1char = TRUE,
517 .scan_identifier_NULL = FALSE,
518 .scan_symbols = FALSE,
519 .symbol_2_token = FALSE,
520 .scope_0_fallback = FALSE,
521 .scan_binary = FALSE,
522 .scan_octal = FALSE,
523 .scan_float = FALSE,
524 .scan_hex = FALSE,
525 .scan_hex_dollar = FALSE,
526 .numbers_2_int = FALSE,
527 .int_2_float = FALSE,
528 .store_int64 = FALSE,
529 .scan_string_sq = FALSE,
530 .scan_string_dq = FALSE,
531 .identifier_2_string = FALSE,
532 .char_2_token = TRUE,
533 };
534
535 scanner = g_scanner_new(&scanner_config);
536 if (!scanner) {
9f901451 537 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
538 }
539
540 return scanner;
541}
542
543/*
544 * Converts a comma-delimited list of known names (--names option) to
545 * an array value object containing those names as string value objects.
546 *
547 * Return value is owned by the caller.
548 */
549static
b19ff26f 550bt_value *names_from_arg(const char *arg)
9009cc24
PP
551{
552 GScanner *scanner = NULL;
b19ff26f 553 bt_value *names = NULL;
9009cc24
PP
554 bool found_all = false, found_none = false, found_item = false;
555
05e21286 556 names = bt_value_array_create();
9009cc24 557 if (!names) {
9f901451 558 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
559 goto error;
560 }
561
562 scanner = create_csv_identifiers_scanner();
563 if (!scanner) {
564 goto error;
565 }
566
567 g_scanner_input_text(scanner, arg, strlen(arg));
568
569 while (true) {
570 GTokenType token_type = g_scanner_get_next_token(scanner);
571
572 switch (token_type) {
573 case G_TOKEN_IDENTIFIER:
574 {
575 const char *identifier = scanner->value.v_identifier;
576
2242b43d
PP
577 if (strcmp(identifier, "payload") == 0 ||
578 strcmp(identifier, "args") == 0 ||
579 strcmp(identifier, "arg") == 0) {
9009cc24 580 found_item = true;
05e21286 581 if (bt_value_array_append_string_element(names,
9009cc24
PP
582 "payload")) {
583 goto error;
584 }
2242b43d
PP
585 } else if (strcmp(identifier, "context") == 0 ||
586 strcmp(identifier, "ctx") == 0) {
9009cc24 587 found_item = true;
05e21286 588 if (bt_value_array_append_string_element(names,
9009cc24
PP
589 "context")) {
590 goto error;
591 }
2242b43d
PP
592 } else if (strcmp(identifier, "scope") == 0 ||
593 strcmp(identifier, "header") == 0) {
9009cc24 594 found_item = true;
05e21286 595 if (bt_value_array_append_string_element(names,
9009cc24
PP
596 identifier)) {
597 goto error;
598 }
2242b43d 599 } else if (strcmp(identifier, "all") == 0) {
9009cc24 600 found_all = true;
05e21286 601 if (bt_value_array_append_string_element(names,
9009cc24
PP
602 identifier)) {
603 goto error;
604 }
2242b43d 605 } else if (strcmp(identifier, "none") == 0) {
9009cc24 606 found_none = true;
05e21286 607 if (bt_value_array_append_string_element(names,
9009cc24
PP
608 identifier)) {
609 goto error;
610 }
611 } else {
9f901451 612 BT_CLI_LOGE_APPEND_CAUSE("Unknown name: `%s`.",
9009cc24
PP
613 identifier);
614 goto error;
615 }
616 break;
617 }
618 case G_TOKEN_COMMA:
619 continue;
620 case G_TOKEN_EOF:
621 goto end;
622 default:
623 goto error;
624 }
625 }
626
627end:
628 if (found_none && found_all) {
9f901451 629 BT_CLI_LOGE_APPEND_CAUSE("Only either `all` or `none` can be specified in the list given to the --names option, but not both.");
9009cc24
PP
630 goto error;
631 }
632 /*
633 * Legacy behavior is to clear the defaults (show none) when at
634 * least one item is specified.
635 */
636 if (found_item && !found_none && !found_all) {
05e21286 637 if (bt_value_array_append_string_element(names, "none")) {
9009cc24
PP
638 goto error;
639 }
640 }
641 if (scanner) {
642 g_scanner_destroy(scanner);
643 }
644 return names;
645
646error:
c5b9b441 647 BT_VALUE_PUT_REF_AND_RESET(names);
9009cc24
PP
648 if (scanner) {
649 g_scanner_destroy(scanner);
650 }
651 return names;
652}
653
654/*
655 * Converts a comma-delimited list of known fields (--fields option) to
656 * an array value object containing those fields as string
657 * value objects.
658 *
659 * Return value is owned by the caller.
660 */
661static
b19ff26f 662bt_value *fields_from_arg(const char *arg)
9009cc24
PP
663{
664 GScanner *scanner = NULL;
b19ff26f 665 bt_value *fields;
9009cc24 666
05e21286 667 fields = bt_value_array_create();
9009cc24 668 if (!fields) {
9f901451 669 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
670 goto error;
671 }
672
673 scanner = create_csv_identifiers_scanner();
674 if (!scanner) {
675 goto error;
676 }
677
678 g_scanner_input_text(scanner, arg, strlen(arg));
679
680 while (true) {
681 GTokenType token_type = g_scanner_get_next_token(scanner);
682
683 switch (token_type) {
684 case G_TOKEN_IDENTIFIER:
685 {
686 const char *identifier = scanner->value.v_identifier;
687
2242b43d
PP
688 if (strcmp(identifier, "trace") == 0 ||
689 strcmp(identifier, "trace:hostname") == 0 ||
690 strcmp(identifier, "trace:domain") == 0 ||
691 strcmp(identifier, "trace:procname") == 0 ||
692 strcmp(identifier, "trace:vpid") == 0 ||
693 strcmp(identifier, "loglevel") == 0 ||
694 strcmp(identifier, "emf") == 0 ||
695 strcmp(identifier, "callsite") == 0 ||
696 strcmp(identifier, "all") == 0) {
05e21286 697 if (bt_value_array_append_string_element(fields,
9009cc24
PP
698 identifier)) {
699 goto error;
700 }
701 } else {
9f901451 702 BT_CLI_LOGE_APPEND_CAUSE("Unknown field: `%s`.",
9009cc24
PP
703 identifier);
704 goto error;
705 }
706 break;
707 }
708 case G_TOKEN_COMMA:
709 continue;
710 case G_TOKEN_EOF:
711 goto end;
712 default:
713 goto error;
714 }
715 }
716
717 goto end;
718
719error:
c5b9b441 720 BT_VALUE_PUT_REF_AND_RESET(fields);
9009cc24
PP
721
722end:
723 if (scanner) {
724 g_scanner_destroy(scanner);
725 }
726 return fields;
727}
728
729static
730void append_param_arg(GString *params_arg, const char *key, const char *value)
731{
f6ccaed9
PP
732 BT_ASSERT(params_arg);
733 BT_ASSERT(key);
734 BT_ASSERT(value);
9009cc24
PP
735
736 if (params_arg->len != 0) {
737 g_string_append_c(params_arg, ',');
738 }
739
740 g_string_append(params_arg, key);
741 g_string_append_c(params_arg, '=');
742 g_string_append(params_arg, value);
743}
744
745/*
746 * Inserts the equivalent "prefix-NAME=yes" strings into params_arg
747 * where the names are in names_array.
748 */
749static
750int insert_flat_params_from_array(GString *params_arg,
b19ff26f 751 const bt_value *names_array, const char *prefix)
9009cc24
PP
752{
753 int ret = 0;
f80e9ec1 754 uint64_t i;
9009cc24
PP
755 GString *tmpstr = NULL, *default_value = NULL;
756 bool default_set = false, non_default_set = false;
757
758 /*
759 * names_array may be NULL if no CLI options were specified to
760 * trigger its creation.
761 */
762 if (!names_array) {
763 goto end;
764 }
765
766 tmpstr = g_string_new(NULL);
767 if (!tmpstr) {
9f901451 768 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
769 ret = -1;
770 goto end;
771 }
772
773 default_value = g_string_new(NULL);
774 if (!default_value) {
9f901451 775 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
776 ret = -1;
777 goto end;
778 }
779
393729a6 780 for (i = 0; i < bt_value_array_get_length(names_array); i++) {
b19ff26f 781 const bt_value *str_obj =
05e21286 782 bt_value_array_borrow_element_by_index_const(names_array,
50962110 783 i);
9009cc24
PP
784 const char *suffix;
785 bool is_default = false;
786
601b0d3c 787 suffix = bt_value_string_get(str_obj);
9009cc24
PP
788
789 g_string_assign(tmpstr, prefix);
790 g_string_append(tmpstr, "-");
791
792 /* Special-case for "all" and "none". */
2242b43d 793 if (strcmp(suffix, "all") == 0) {
9009cc24
PP
794 is_default = true;
795 g_string_assign(default_value, "show");
2242b43d 796 } else if (strcmp(suffix, "none") == 0) {
9009cc24
PP
797 is_default = true;
798 g_string_assign(default_value, "hide");
799 }
800 if (is_default) {
801 default_set = true;
802 g_string_append(tmpstr, "default");
803 append_param_arg(params_arg, tmpstr->str,
804 default_value->str);
805 } else {
806 non_default_set = true;
807 g_string_append(tmpstr, suffix);
808 append_param_arg(params_arg, tmpstr->str, "yes");
809 }
810 }
811
812 /* Implicit field-default=hide if any non-default option is set. */
813 if (non_default_set && !default_set) {
814 g_string_assign(tmpstr, prefix);
815 g_string_append(tmpstr, "-default");
816 g_string_assign(default_value, "hide");
817 append_param_arg(params_arg, tmpstr->str, default_value->str);
818 }
819
820end:
821 if (default_value) {
822 g_string_free(default_value, TRUE);
823 }
824
825 if (tmpstr) {
826 g_string_free(tmpstr, TRUE);
827 }
828
829 return ret;
830}
831
916d0d91 832/* argpar options */
9009cc24
PP
833enum {
834 OPT_NONE = 0,
835 OPT_BASE_PARAMS,
836 OPT_BEGIN,
837 OPT_CLOCK_CYCLES,
838 OPT_CLOCK_DATE,
839 OPT_CLOCK_FORCE_CORRELATE,
840 OPT_CLOCK_GMT,
841 OPT_CLOCK_OFFSET,
842 OPT_CLOCK_OFFSET_NS,
843 OPT_CLOCK_SECONDS,
844 OPT_COLOR,
fd5f8053 845 OPT_COMPONENT,
9009cc24
PP
846 OPT_CONNECT,
847 OPT_DEBUG,
9a16feea 848 OPT_DEBUG_INFO,
9009cc24
PP
849 OPT_DEBUG_INFO_DIR,
850 OPT_DEBUG_INFO_FULL_PATH,
851 OPT_DEBUG_INFO_TARGET_PREFIX,
852 OPT_END,
853 OPT_FIELDS,
9009cc24
PP
854 OPT_HELP,
855 OPT_INPUT_FORMAT,
9009cc24 856 OPT_LIST,
29da2ffc 857 OPT_LOG_LEVEL,
9009cc24 858 OPT_NAMES,
9009cc24
PP
859 OPT_NO_DELTA,
860 OPT_OMIT_HOME_PLUGIN_PATH,
861 OPT_OMIT_SYSTEM_PLUGIN_PATH,
9009cc24 862 OPT_OUTPUT,
fd5f8053 863 OPT_OUTPUT_FORMAT,
9009cc24 864 OPT_PARAMS,
9009cc24
PP
865 OPT_PLUGIN_PATH,
866 OPT_RESET_BASE_PARAMS,
867 OPT_RETRY_DURATION,
868 OPT_RUN_ARGS,
869 OPT_RUN_ARGS_0,
9009cc24
PP
870 OPT_STREAM_INTERSECTION,
871 OPT_TIMERANGE,
9009cc24 872 OPT_VERBOSE,
0e497e1c 873 OPT_VERSION,
9009cc24
PP
874};
875
876enum bt_config_component_dest {
0a011c88 877 BT_CONFIG_COMPONENT_DEST_UNKNOWN = -1,
9009cc24
PP
878 BT_CONFIG_COMPONENT_DEST_SOURCE,
879 BT_CONFIG_COMPONENT_DEST_FILTER,
880 BT_CONFIG_COMPONENT_DEST_SINK,
881};
882
883/*
884 * Adds a configuration component to the appropriate configuration
885 * array depending on the destination.
886 */
887static
888void add_run_cfg_comp(struct bt_config *cfg,
889 struct bt_config_component *cfg_comp,
890 enum bt_config_component_dest dest)
891{
65300d60 892 bt_object_get_ref(cfg_comp);
9009cc24
PP
893
894 switch (dest) {
895 case BT_CONFIG_COMPONENT_DEST_SOURCE:
896 g_ptr_array_add(cfg->cmd_data.run.sources, cfg_comp);
897 break;
898 case BT_CONFIG_COMPONENT_DEST_FILTER:
899 g_ptr_array_add(cfg->cmd_data.run.filters, cfg_comp);
900 break;
901 case BT_CONFIG_COMPONENT_DEST_SINK:
902 g_ptr_array_add(cfg->cmd_data.run.sinks, cfg_comp);
903 break;
904 default:
498e7994 905 bt_common_abort();
9009cc24
PP
906 }
907}
908
909static
910int add_run_cfg_comp_check_name(struct bt_config *cfg,
911 struct bt_config_component *cfg_comp,
912 enum bt_config_component_dest dest,
b19ff26f 913 bt_value *instance_names)
9009cc24
PP
914{
915 int ret = 0;
916
917 if (cfg_comp->instance_name->len == 0) {
9f901451 918 BT_CLI_LOGE_APPEND_CAUSE("Found an unnamed component.");
9009cc24
PP
919 ret = -1;
920 goto end;
921 }
922
05e21286
PP
923 if (bt_value_map_has_entry(instance_names,
924 cfg_comp->instance_name->str)) {
9f901451 925 BT_CLI_LOGE_APPEND_CAUSE("Duplicate component instance name:\n %s",
9009cc24
PP
926 cfg_comp->instance_name->str);
927 ret = -1;
928 goto end;
929 }
930
05e21286 931 if (bt_value_map_insert_entry(instance_names,
9009cc24 932 cfg_comp->instance_name->str, bt_value_null)) {
9f901451 933 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
934 ret = -1;
935 goto end;
936 }
937
938 add_run_cfg_comp(cfg, cfg_comp, dest);
939
940end:
941 return ret;
942}
943
944static
b19ff26f 945int append_env_var_plugin_paths(bt_value *plugin_paths)
9009cc24
PP
946{
947 int ret = 0;
948 const char *envvar;
949
950 if (bt_common_is_setuid_setgid()) {
b4565e8b 951 BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
9009cc24
PP
952 goto end;
953 }
954
955 envvar = getenv("BABELTRACE_PLUGIN_PATH");
956 if (!envvar) {
957 goto end;
958 }
959
960 ret = bt_config_append_plugin_paths(plugin_paths, envvar);
961
962end:
963 if (ret) {
9f901451 964 BT_CLI_LOGE_APPEND_CAUSE("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH.");
9009cc24
PP
965 }
966
967 return ret;
968}
969
970static
b19ff26f 971int append_home_and_system_plugin_paths(bt_value *plugin_paths,
9009cc24
PP
972 bool omit_system_plugin_path, bool omit_home_plugin_path)
973{
974 int ret;
975
976 if (!omit_home_plugin_path) {
977 if (bt_common_is_setuid_setgid()) {
b4565e8b 978 BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
9009cc24 979 } else {
86d8b7b8
PP
980 char *home_plugin_dir = bt_common_get_home_plugin_path(
981 BT_LOG_OUTPUT_LEVEL);
9009cc24
PP
982
983 if (home_plugin_dir) {
984 ret = bt_config_append_plugin_paths(
985 plugin_paths, home_plugin_dir);
986 free(home_plugin_dir);
987
988 if (ret) {
9f901451 989 BT_CLI_LOGE_APPEND_CAUSE("Invalid home plugin path.");
9009cc24
PP
990 goto error;
991 }
992 }
993 }
994 }
995
996 if (!omit_system_plugin_path) {
997 if (bt_config_append_plugin_paths(plugin_paths,
998 bt_common_get_system_plugin_path())) {
9f901451 999 BT_CLI_LOGE_APPEND_CAUSE("Invalid system plugin path.");
9009cc24
PP
1000 goto error;
1001 }
1002 }
1003 return 0;
1004error:
9f901451 1005 BT_CLI_LOGE_APPEND_CAUSE("Cannot append home and system plugin paths.");
9009cc24
PP
1006 return -1;
1007}
1008
9009cc24
PP
1009static
1010struct bt_config *bt_config_base_create(enum bt_config_command command,
02510056 1011 const bt_value *plugin_paths, bool needs_plugins)
9009cc24
PP
1012{
1013 struct bt_config *cfg;
1014
1015 /* Create config */
1016 cfg = g_new0(struct bt_config, 1);
1017 if (!cfg) {
9f901451 1018 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1019 goto error;
1020 }
1021
3fea54f6 1022 bt_object_init_shared(&cfg->base, bt_config_destroy);
9009cc24
PP
1023 cfg->command = command;
1024 cfg->command_needs_plugins = needs_plugins;
1025
02510056
PP
1026 if (plugin_paths) {
1027 bt_value *plugin_paths_copy;
05e21286 1028
02510056
PP
1029 (void) bt_value_copy(plugin_paths,
1030 &plugin_paths_copy);
1031 cfg->plugin_paths = plugin_paths_copy;
9009cc24 1032 } else {
05e21286 1033 cfg->plugin_paths = bt_value_array_create();
9009cc24 1034 if (!cfg->plugin_paths) {
9f901451 1035 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1036 goto error;
1037 }
1038 }
1039
1040 goto end;
1041
1042error:
65300d60 1043 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
1044
1045end:
1046 return cfg;
1047}
1048
1049static
02510056 1050struct bt_config *bt_config_run_create(const bt_value *plugin_paths)
9009cc24
PP
1051{
1052 struct bt_config *cfg;
1053
1054 /* Create config */
1055 cfg = bt_config_base_create(BT_CONFIG_COMMAND_RUN,
02510056 1056 plugin_paths, true);
9009cc24
PP
1057 if (!cfg) {
1058 goto error;
1059 }
1060
1061 cfg->cmd_data.run.sources = g_ptr_array_new_with_free_func(
65300d60 1062 (GDestroyNotify) bt_object_put_ref);
9009cc24 1063 if (!cfg->cmd_data.run.sources) {
9f901451 1064 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1065 goto error;
1066 }
1067
1068 cfg->cmd_data.run.filters = g_ptr_array_new_with_free_func(
65300d60 1069 (GDestroyNotify) bt_object_put_ref);
9009cc24 1070 if (!cfg->cmd_data.run.filters) {
9f901451 1071 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1072 goto error;
1073 }
1074
1075 cfg->cmd_data.run.sinks = g_ptr_array_new_with_free_func(
65300d60 1076 (GDestroyNotify) bt_object_put_ref);
9009cc24 1077 if (!cfg->cmd_data.run.sinks) {
9f901451 1078 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1079 goto error;
1080 }
1081
1082 cfg->cmd_data.run.connections = g_ptr_array_new_with_free_func(
1083 (GDestroyNotify) bt_config_connection_destroy);
1084 if (!cfg->cmd_data.run.connections) {
9f901451 1085 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1086 goto error;
1087 }
1088
1089 goto end;
1090
1091error:
65300d60 1092 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
1093
1094end:
1095 return cfg;
1096}
1097
1098static
02510056 1099struct bt_config *bt_config_list_plugins_create(const bt_value *plugin_paths)
9009cc24 1100{
02510056
PP
1101 return bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS,
1102 plugin_paths, true);
9009cc24
PP
1103}
1104
1105static
02510056 1106struct bt_config *bt_config_help_create(const bt_value *plugin_paths,
29da2ffc 1107 int default_log_level)
9009cc24
PP
1108{
1109 struct bt_config *cfg;
1110
1111 /* Create config */
1112 cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP,
02510056 1113 plugin_paths, true);
9009cc24
PP
1114 if (!cfg) {
1115 goto error;
1116 }
1117
1118 cfg->cmd_data.help.cfg_component =
29da2ffc 1119 bt_config_component_create(-1, NULL, NULL, default_log_level);
9009cc24
PP
1120 if (!cfg->cmd_data.help.cfg_component) {
1121 goto error;
1122 }
1123
1124 goto end;
1125
1126error:
65300d60 1127 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
1128
1129end:
1130 return cfg;
1131}
1132
1133static
02510056 1134struct bt_config *bt_config_query_create(const bt_value *plugin_paths)
9009cc24
PP
1135{
1136 struct bt_config *cfg;
1137
1138 /* Create config */
1139 cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY,
02510056 1140 plugin_paths, true);
9009cc24
PP
1141 if (!cfg) {
1142 goto error;
1143 }
1144
1145 cfg->cmd_data.query.object = g_string_new(NULL);
1146 if (!cfg->cmd_data.query.object) {
9f901451 1147 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1148 goto error;
1149 }
1150
1151 goto end;
1152
1153error:
65300d60 1154 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
1155
1156end:
1157 return cfg;
1158}
1159
1160static
353c2524
SM
1161enum bt_config_cli_args_status bt_config_print_ctf_metadata_create(
1162 const bt_value *plugin_paths, struct bt_config **cfg_out)
9009cc24
PP
1163{
1164 struct bt_config *cfg;
353c2524 1165 enum bt_config_cli_args_status status;
9009cc24
PP
1166
1167 /* Create config */
1168 cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_CTF_METADATA,
02510056 1169 plugin_paths, true);
9009cc24
PP
1170 if (!cfg) {
1171 goto error;
1172 }
1173
1174 cfg->cmd_data.print_ctf_metadata.path = g_string_new(NULL);
1175 if (!cfg->cmd_data.print_ctf_metadata.path) {
9f901451 1176 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1177 goto error;
1178 }
1179
c327e427
PP
1180 cfg->cmd_data.print_ctf_metadata.output_path = g_string_new(NULL);
1181 if (!cfg->cmd_data.print_ctf_metadata.output_path) {
9f901451 1182 BT_CLI_LOGE_APPEND_CAUSE_OOM();
c327e427
PP
1183 goto error;
1184 }
1185
353c2524
SM
1186 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
1187 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
9009cc24
PP
1188 goto end;
1189
1190error:
353c2524 1191 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
1192
1193end:
353c2524
SM
1194 bt_object_put_ref(cfg);
1195 return status;
9009cc24
PP
1196}
1197
1198static
353c2524
SM
1199enum bt_config_cli_args_status bt_config_print_lttng_live_sessions_create(
1200 const bt_value *plugin_paths, struct bt_config **cfg_out)
9009cc24
PP
1201{
1202 struct bt_config *cfg;
353c2524 1203 enum bt_config_cli_args_status status;
9009cc24
PP
1204
1205 /* Create config */
1206 cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS,
02510056 1207 plugin_paths, true);
9009cc24
PP
1208 if (!cfg) {
1209 goto error;
1210 }
1211
1212 cfg->cmd_data.print_lttng_live_sessions.url = g_string_new(NULL);
1213 if (!cfg->cmd_data.print_lttng_live_sessions.url) {
9f901451 1214 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1215 goto error;
1216 }
1217
c327e427
PP
1218 cfg->cmd_data.print_lttng_live_sessions.output_path =
1219 g_string_new(NULL);
1220 if (!cfg->cmd_data.print_lttng_live_sessions.output_path) {
9f901451 1221 BT_CLI_LOGE_APPEND_CAUSE_OOM();
c327e427
PP
1222 goto error;
1223 }
1224
353c2524
SM
1225 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
1226 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
9009cc24
PP
1227 goto end;
1228
1229error:
353c2524 1230 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
1231
1232end:
353c2524
SM
1233 bt_object_put_ref(cfg);
1234 return status;
9009cc24
PP
1235}
1236
1237static
1238int bt_config_append_plugin_paths_check_setuid_setgid(
b19ff26f 1239 bt_value *plugin_paths, const char *arg)
9009cc24
PP
1240{
1241 int ret = 0;
1242
1243 if (bt_common_is_setuid_setgid()) {
b4565e8b 1244 BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
9009cc24
PP
1245 goto end;
1246 }
1247
1248 if (bt_config_append_plugin_paths(plugin_paths, arg)) {
9f901451 1249 BT_CLI_LOGE_APPEND_CAUSE("Invalid --plugin-path option's argument:\n %s",
9009cc24
PP
1250 arg);
1251 ret = -1;
1252 goto end;
1253 }
1254
1255end:
1256 return ret;
1257}
1258
1259/*
1260 * Prints the expected format for a --params option.
1261 */
1262static
1263void print_expected_params_format(FILE *fp)
1264{
1265 fprintf(fp, "Expected format of PARAMS\n");
1266 fprintf(fp, "-------------------------\n");
1267 fprintf(fp, "\n");
1268 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
1269 fprintf(fp, "\n");
1270 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
1271 fprintf(fp, "where PARAM is the parameter name (C identifier plus the [:.-] characters),\n");
1272 fprintf(fp, "and VALUE can be one of:\n");
1273 fprintf(fp, "\n");
1274 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
1275 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
1276 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
1277 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
fdd3a2da 1278 fprintf(fp, " (`0x` prefix) unsigned (with `+` prefix) or signed 64-bit integer.\n");
9009cc24
PP
1279 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
1280 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
1281 fprintf(fp, " the null and boolean value symbols above.\n");
1282 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
b25da386
SM
1283 fprintf(fp, "* Array, formatted as an opening `[`, a list of comma-separated values\n");
1284 fprintf(fp, " (as described by the current list) and a closing `]`.\n");
3971c701
SM
1285 fprintf(fp, "* Map, formatted as an opening `{`, a comma-separated list of PARAM=VALUE\n");
1286 fprintf(fp, " assignments and a closing `}`.\n");
9009cc24
PP
1287 fprintf(fp, "\n");
1288 fprintf(fp, "You can put whitespaces allowed around individual `=` and `,` symbols.\n");
1289 fprintf(fp, "\n");
1290 fprintf(fp, "Example:\n");
1291 fprintf(fp, "\n");
1292 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
fdd3a2da 1293 fprintf(fp, " play=+23, observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
b25da386
SM
1294 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\",\n");
1295 fprintf(fp, " things=[1, \"2\", 3]\n");
9009cc24
PP
1296 fprintf(fp, "\n");
1297 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
ec2c5e50 1298 fprintf(fp, "babeltrace2 from a shell.\n");
9009cc24
PP
1299}
1300
a93e984c
SM
1301/*
1302 * Given argpar error status `status` and error `error`, return a formatted
1303 * error message describing the error.
1304 *
1305 * `argv` is the argument vector that was being parsed.
1306 *
1307 * `prefix_fmt` (formatted using the following arguments) is prepended to
1308 * the error message.
1309 *
1310 * The returned string must be freed by the caller.
1311 */
976b24cf 1312static
a80892ba 1313GString *__BT_ATTR_FORMAT_PRINTF(4, 5) format_arg_error(
a93e984c 1314 const struct argpar_error *error,
a80892ba
SM
1315 const char **argv, unsigned int arg_index_offset,
1316 const char *prefix_fmt, ...)
976b24cf 1317{
a93e984c
SM
1318 GString *str = g_string_new(NULL);
1319 va_list args;
976b24cf 1320
a93e984c
SM
1321 va_start(args, prefix_fmt);
1322 g_string_append_vprintf(str, prefix_fmt, args);
1323 va_end(args);
976b24cf 1324
a93e984c
SM
1325 g_string_append(str, ": ");
1326
1327 switch (argpar_error_type(error))
1328 {
1329 case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG:
1330 {
1331 bool is_short;
1332 const struct argpar_opt_descr *descr =
1333 argpar_error_opt_descr(error, &is_short);
1334 int orig_index = argpar_error_orig_index(error);
1335 const char *arg = argv[orig_index];
1336
1337 if (is_short) {
1338 g_string_append_printf(
1339 str,
1340 WHILE_PARSING_ARG_N_FMT "Missing required argument for option `-%c`",
a80892ba 1341 arg_index_offset + orig_index + 1, arg, descr->short_name);
a93e984c
SM
1342 } else {
1343 g_string_append_printf(
1344 str,
1345 WHILE_PARSING_ARG_N_FMT "Missing required argument for option `--%s`",
a80892ba 1346 arg_index_offset + orig_index + 1, arg, descr->long_name);
976b24cf
SM
1347 }
1348
a93e984c
SM
1349 break;
1350 }
1351 case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG:
1352 {
1353 bool is_short;
1354 const struct argpar_opt_descr *descr =
1355 argpar_error_opt_descr(error, &is_short);
1356 int orig_index = argpar_error_orig_index(error);
1357 const char *arg = argv[orig_index];
1358
1359 if (is_short) {
1360 g_string_append_printf(
1361 str,
1362 WHILE_PARSING_ARG_N_FMT "Unexpected argument for option `-%c`",
a80892ba 1363 arg_index_offset + orig_index + 1, arg, descr->short_name);
a93e984c
SM
1364 } else {
1365 g_string_append_printf(
1366 str,
1367 WHILE_PARSING_ARG_N_FMT "Unexpected argument for option `--%s`",
a80892ba 1368 arg_index_offset + orig_index + 1, arg, descr->long_name);
976b24cf 1369 }
a93e984c
SM
1370
1371 break;
1372 }
1373 case ARGPAR_ERROR_TYPE_UNKNOWN_OPT:
1374 {
1375 int orig_index = argpar_error_orig_index(error);
1376 const char *unknown_opt = argpar_error_unknown_opt_name(error);
1377 const char *arg = argv[orig_index];
1378
1379 g_string_append_printf(
1380 str,
1381 WHILE_PARSING_ARG_N_FMT "Unknown option `%s`",
a80892ba 1382 arg_index_offset + orig_index + 1, arg, unknown_opt);
a93e984c
SM
1383
1384 break;
1385 }
1386
1387 default:
1388 BT_ASSERT(0);
1389 }
1390
1391 return str;
1392}
1393
1394enum parse_next_item_status
1395{
1396 PARSE_NEXT_ITEM_STATUS_OK = 0,
1397 PARSE_NEXT_ITEM_STATUS_END = 1,
1398 PARSE_NEXT_ITEM_STATUS_ERROR = -1,
1399};
1400
1401/*
1402 * Parse the next item using `iter`. Log and append an error if necessary.
1403 *
1404 * The item in `*item` on entry is freed, and the new item is also
1405 * returned in `*item`.
1406 */
1407static
1408enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
1409 const struct argpar_item **item, const char **argv,
a80892ba 1410 const char *command, unsigned int consumed_args)
a93e984c
SM
1411{
1412 enum argpar_iter_next_status status;
1413 const struct argpar_error *error = NULL;
1414 enum parse_next_item_status ret;
1415
1416 ARGPAR_ITEM_DESTROY_AND_RESET(*item);
1417 status = argpar_iter_next(iter, item, &error);
1418
1419 switch (status) {
1420 case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
1421 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1422 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
1423 break;
1424 case ARGPAR_ITER_NEXT_STATUS_ERROR:
1425 {
1426 GString *err_str = format_arg_error(error, argv,
a80892ba
SM
1427 consumed_args,
1428 "While parsing `%s` command's command-line arguments",
1429 command);
a93e984c
SM
1430 BT_CLI_LOGE_APPEND_CAUSE("%s", err_str->str);
1431 g_string_free(err_str, TRUE);
1432 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
1433 break;
1434 }
1435 case ARGPAR_ITER_NEXT_STATUS_END:
1436 ret = PARSE_NEXT_ITEM_STATUS_END;
1437 break;
1438 case ARGPAR_ITER_NEXT_STATUS_OK:
1439 ret = PARSE_NEXT_ITEM_STATUS_OK;
1440 break;
1441 default:
1442 bt_common_abort();
976b24cf
SM
1443 }
1444
a93e984c
SM
1445 argpar_error_destroy(error);
1446 return ret;
976b24cf 1447}
9009cc24 1448
a93e984c 1449
9009cc24
PP
1450/*
1451 * Prints the help command usage.
1452 */
1453static
1454void print_help_usage(FILE *fp)
1455{
ec2c5e50
MJ
1456 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
1457 fprintf(fp, " babeltrace2 [GENERAL OPTIONS] help [OPTIONS] TYPE.PLUGIN.CLS\n");
9009cc24
PP
1458 fprintf(fp, "\n");
1459 fprintf(fp, "Options:\n");
1460 fprintf(fp, "\n");
02510056 1461 fprintf(fp, " -h, --help Show this help and quit\n");
9009cc24 1462 fprintf(fp, "\n");
ec2c5e50 1463 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
9009cc24 1464 fprintf(fp, "\n");
ec2c5e50 1465 fprintf(fp, "Use `babeltrace2 list-plugins` to show the list of available plugins.\n");
9009cc24
PP
1466}
1467
1468static
65966041 1469const struct argpar_opt_descr help_options[] = {
13ae36e1
SM
1470 /* id, short_name, long_name, with_arg */
1471 { OPT_HELP, 'h', "help", false },
65966041 1472 ARGPAR_OPT_DESCR_SENTINEL
9009cc24
PP
1473};
1474
1475/*
1476 * Creates a Babeltrace config object from the arguments of a help
1477 * command.
9009cc24
PP
1478 */
1479static
353c2524
SM
1480enum bt_config_cli_args_status bt_config_help_from_args(int argc,
1481 const char *argv[], struct bt_config **cfg_out,
1482 const bt_value *plugin_paths, int default_log_level,
1483 unsigned int consumed_args)
9009cc24 1484{
353c2524
SM
1485 enum bt_config_cli_args_status status;
1486 struct bt_config *cfg;
a93e984c 1487 const char *plugin_comp_cls_arg = NULL;
9009cc24 1488 char *plugin_name = NULL, *comp_cls_name = NULL;
4bf5c85f
SM
1489 GString *substring = NULL;
1490 size_t end_pos;
a93e984c
SM
1491 struct argpar_iter *argpar_iter = NULL;
1492 const struct argpar_item *argpar_item = NULL;
9009cc24 1493
02510056 1494 cfg = bt_config_help_create(plugin_paths, default_log_level);
9009cc24
PP
1495 if (!cfg) {
1496 goto error;
1497 }
1498
a93e984c
SM
1499 argpar_iter = argpar_iter_create(argc, argv, help_options);
1500 if (!argpar_iter) {
1501 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1502 goto error;
1503 }
1504
a93e984c 1505 while (true) {
353c2524 1506 enum parse_next_item_status parse_status =
a80892ba
SM
1507 parse_next_item(argpar_iter, &argpar_item, argv, "help",
1508 consumed_args);
a93e984c 1509
353c2524 1510 if (parse_status == PARSE_NEXT_ITEM_STATUS_ERROR) {
a93e984c 1511 goto error;
353c2524 1512 } else if (parse_status == PARSE_NEXT_ITEM_STATUS_END) {
a93e984c
SM
1513 break;
1514 }
1515
1516 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
1517 const struct argpar_opt_descr *opt_descr =
1518 argpar_item_opt_descr(argpar_item);
1519
1520 switch (opt_descr->id) {
1521 case OPT_HELP:
1522 print_help_usage(stdout);
353c2524 1523 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c
SM
1524 goto end;
1525 default:
1526 bt_common_abort();
1527 }
1528 } else {
1529 const char *arg = argpar_item_non_opt_arg(argpar_item);
1530
1531 if (plugin_comp_cls_arg) {
1532 BT_CLI_LOGE_APPEND_CAUSE(
1533 "Extraneous command-line argument specified to `help` command: `%s`.",
1534 arg);
1535 goto error;
1536 }
1537
1538 plugin_comp_cls_arg = arg;
1539 }
13ae36e1 1540 }
9009cc24 1541
a93e984c 1542 if (!plugin_comp_cls_arg) {
02510056
PP
1543 BT_CLI_LOGE_APPEND_CAUSE(
1544 "Missing plugin name or component class descriptor.");
1545 goto error;
9009cc24
PP
1546 }
1547
4bf5c85f 1548 /* Look for unescaped dots in the argument. */
a93e984c 1549 substring = bt_common_string_until(plugin_comp_cls_arg, ".\\", ".", &end_pos);
4bf5c85f
SM
1550 if (!substring) {
1551 BT_CLI_LOGE_APPEND_CAUSE("Could not consume argument: arg=%s",
a93e984c 1552 plugin_comp_cls_arg);
4bf5c85f
SM
1553 goto error;
1554 }
1555
a93e984c 1556 if (end_pos == strlen(plugin_comp_cls_arg)) {
4bf5c85f
SM
1557 /* Didn't find an unescaped dot, treat it as a plugin name. */
1558 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
a93e984c 1559 plugin_comp_cls_arg);
4bf5c85f
SM
1560 } else {
1561 /*
1562 * Found an unescaped dot, treat it as a component class name.
1563 */
a93e984c 1564 plugin_comp_cls_names(plugin_comp_cls_arg, NULL, &plugin_name, &comp_cls_name,
4bf5c85f
SM
1565 &cfg->cmd_data.help.cfg_component->type);
1566 if (!plugin_name || !comp_cls_name) {
1567 BT_CLI_LOGE_APPEND_CAUSE(
1568 "Could not parse argument as a component class name: arg=%s",
a93e984c 1569 plugin_comp_cls_arg);
4bf5c85f
SM
1570 goto error;
1571 }
1572
02510056
PP
1573 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
1574 plugin_name);
1575 g_string_assign(cfg->cmd_data.help.cfg_component->comp_cls_name,
1576 comp_cls_name);
9009cc24
PP
1577 }
1578
353c2524
SM
1579 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
1580 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
9009cc24
PP
1581 goto end;
1582
1583error:
353c2524 1584 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
1585
1586end:
9009cc24
PP
1587 g_free(plugin_name);
1588 g_free(comp_cls_name);
1589
4bf5c85f
SM
1590 if (substring) {
1591 g_string_free(substring, TRUE);
1592 }
1593
a93e984c
SM
1594 argpar_iter_destroy(argpar_iter);
1595 argpar_item_destroy(argpar_item);
353c2524 1596 bt_object_put_ref(cfg);
9009cc24 1597
353c2524 1598 return status;
9009cc24
PP
1599}
1600
1601/*
1602 * Prints the help command usage.
1603 */
1604static
1605void print_query_usage(FILE *fp)
1606{
ec2c5e50 1607 fprintf(fp, "Usage: babeltrace2 [GEN OPTS] query [OPTS] TYPE.PLUGIN.CLS OBJECT\n");
9009cc24
PP
1608 fprintf(fp, "\n");
1609 fprintf(fp, "Options:\n");
1610 fprintf(fp, "\n");
02510056
PP
1611 fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS (see the expected\n");
1612 fprintf(fp, " format of PARAMS below)\n");
1613 fprintf(fp, " -h, --help Show this help and quit\n");
9009cc24
PP
1614 fprintf(fp, "\n\n");
1615 print_expected_params_format(fp);
1616}
1617
1618static
65966041 1619const struct argpar_opt_descr query_options[] = {
22692f90
SM
1620 /* id, short_name, long_name, with_arg */
1621 { OPT_HELP, 'h', "help", false },
22692f90 1622 { OPT_PARAMS, 'p', "params", true },
65966041 1623 ARGPAR_OPT_DESCR_SENTINEL
9009cc24
PP
1624};
1625
1626/*
1627 * Creates a Babeltrace config object from the arguments of a query
1628 * command.
9009cc24
PP
1629 */
1630static
353c2524
SM
1631enum bt_config_cli_args_status bt_config_query_from_args(int argc,
1632 const char *argv[], struct bt_config **cfg_out,
1633 const bt_value *plugin_paths, int default_log_level,
1634 unsigned int consumed_args)
9009cc24 1635{
353c2524 1636 enum bt_config_cli_args_status status;
9009cc24 1637 struct bt_config *cfg = NULL;
22692f90
SM
1638 const char *component_class_spec = NULL;
1639 const char *query_object = NULL;
8bd04432 1640 GString *error_str = NULL;
a93e984c
SM
1641 struct argpar_iter *argpar_iter = NULL;
1642 const struct argpar_item *argpar_item = NULL;
ac72582c 1643
deb34b1f
FD
1644 bt_value *params = bt_value_map_create();
1645 if (!params) {
1646 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1647 goto error;
1648 }
9009cc24 1649
02510056 1650 cfg = bt_config_query_create(plugin_paths);
9009cc24
PP
1651 if (!cfg) {
1652 goto error;
1653 }
1654
8bd04432
PP
1655 error_str = g_string_new(NULL);
1656 if (!error_str) {
9f901451 1657 BT_CLI_LOGE_APPEND_CAUSE_OOM();
8bd04432
PP
1658 goto error;
1659 }
1660
a93e984c
SM
1661 argpar_iter = argpar_iter_create(argc, argv, query_options);
1662 if (!argpar_iter) {
1663 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1664 goto error;
1665 }
1666
a93e984c 1667 while (true) {
353c2524 1668 enum parse_next_item_status parse_status =
a80892ba
SM
1669 parse_next_item(argpar_iter, &argpar_item, argv, "query",
1670 consumed_args);
9009cc24 1671
353c2524 1672 if (parse_status == PARSE_NEXT_ITEM_STATUS_ERROR) {
a93e984c 1673 goto error;
353c2524 1674 } else if (parse_status == PARSE_NEXT_ITEM_STATUS_END) {
a93e984c
SM
1675 break;
1676 }
9009cc24 1677
a93e984c
SM
1678 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
1679 const struct argpar_opt_descr *opt_descr =
1680 argpar_item_opt_descr(argpar_item);
1681 const char *arg = argpar_item_opt_arg(argpar_item);
22692f90 1682
a93e984c
SM
1683 switch (opt_descr->id) {
1684 case OPT_HELP:
1685 print_query_usage(stdout);
353c2524 1686 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c 1687 goto end;
22692f90
SM
1688 case OPT_PARAMS:
1689 {
deb34b1f
FD
1690 bt_value *parsed_params = bt_param_parse(arg, error_str);
1691 bt_value_map_extend_status extend_status;
1692 if (!parsed_params) {
22692f90
SM
1693 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s",
1694 error_str->str);
1695 goto error;
1696 }
deb34b1f
FD
1697
1698 extend_status = bt_value_map_extend(params, parsed_params);
1699 BT_VALUE_PUT_REF_AND_RESET(parsed_params);
1700 if (extend_status) {
1701 BT_CLI_LOGE_APPEND_CAUSE("Cannot extend current parameters with --params option's argument:\n %s",
1702 arg);
1703 goto error;
1704 }
22692f90
SM
1705 break;
1706 }
1707 default:
a93e984c 1708 bt_common_abort();
9009cc24 1709 }
22692f90 1710 } else {
a93e984c 1711 const char *arg = argpar_item_non_opt_arg(argpar_item);
22692f90
SM
1712
1713 /*
24594611
PP
1714 * We need exactly two non-option arguments
1715 * which are the mandatory component class
1716 * specification and query object.
22692f90
SM
1717 */
1718 if (!component_class_spec) {
a93e984c 1719 component_class_spec = arg;
22692f90 1720 } else if (!query_object) {
a93e984c 1721 query_object = arg;
22692f90
SM
1722 } else {
1723 BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `query` command: `%s`.",
a93e984c 1724 arg);
9009cc24
PP
1725 goto error;
1726 }
9009cc24 1727 }
9009cc24
PP
1728 }
1729
22692f90 1730 if (!component_class_spec || !query_object) {
7b1e06a1 1731 print_query_usage(stdout);
353c2524 1732 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
7b1e06a1
PP
1733 goto end;
1734 }
1735
22692f90
SM
1736 cfg->cmd_data.query.cfg_component =
1737 bt_config_component_from_arg(component_class_spec,
1738 default_log_level);
1739 if (!cfg->cmd_data.query.cfg_component) {
1740 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for component class specification:\n %s",
1741 component_class_spec);
1742 goto error;
9009cc24
PP
1743 }
1744
22692f90
SM
1745 BT_ASSERT(params);
1746 BT_OBJECT_MOVE_REF(cfg->cmd_data.query.cfg_component->params, params);
1747
1748 if (strlen(query_object) == 0) {
1749 BT_CLI_LOGE_APPEND_CAUSE("Invalid empty object.");
9009cc24
PP
1750 goto error;
1751 }
1752
22692f90 1753 g_string_assign(cfg->cmd_data.query.object, query_object);
353c2524
SM
1754 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
1755 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
9009cc24
PP
1756 goto end;
1757
1758error:
353c2524 1759 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
1760
1761end:
a93e984c
SM
1762 argpar_iter_destroy(argpar_iter);
1763 argpar_item_destroy(argpar_item);
9009cc24 1764
8bd04432
PP
1765 if (error_str) {
1766 g_string_free(error_str, TRUE);
1767 }
1768
c5b9b441 1769 bt_value_put_ref(params);
353c2524
SM
1770 bt_object_put_ref(cfg);
1771
1772 return status;
9009cc24
PP
1773}
1774
1775/*
1776 * Prints the list-plugins command usage.
1777 */
1778static
1779void print_list_plugins_usage(FILE *fp)
1780{
ec2c5e50 1781 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
9009cc24
PP
1782 fprintf(fp, "\n");
1783 fprintf(fp, "Options:\n");
1784 fprintf(fp, "\n");
3efa3052 1785 fprintf(fp, " -h, --help Show this help and quit\n");
9009cc24 1786 fprintf(fp, "\n");
ec2c5e50 1787 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
9009cc24 1788 fprintf(fp, "\n");
ec2c5e50 1789 fprintf(fp, "Use `babeltrace2 help` to get help for a specific plugin or component class.\n");
9009cc24
PP
1790}
1791
1792static
65966041 1793const struct argpar_opt_descr list_plugins_options[] = {
96d065ef
SM
1794 /* id, short_name, long_name, with_arg */
1795 { OPT_HELP, 'h', "help", false },
65966041 1796 ARGPAR_OPT_DESCR_SENTINEL
9009cc24
PP
1797};
1798
1799/*
1800 * Creates a Babeltrace config object from the arguments of a
1801 * list-plugins command.
9009cc24
PP
1802 */
1803static
353c2524
SM
1804enum bt_config_cli_args_status bt_config_list_plugins_from_args(int argc,
1805 const char *argv[], struct bt_config **cfg_out,
1806 const bt_value *plugin_paths, unsigned int consumed_args)
9009cc24 1807{
353c2524 1808 enum bt_config_cli_args_status status;
9009cc24 1809 struct bt_config *cfg = NULL;
a93e984c
SM
1810 struct argpar_iter *argpar_iter = NULL;
1811 const struct argpar_item *argpar_item = NULL;
9009cc24 1812
02510056 1813 cfg = bt_config_list_plugins_create(plugin_paths);
9009cc24
PP
1814 if (!cfg) {
1815 goto error;
1816 }
1817
a93e984c
SM
1818 argpar_iter = argpar_iter_create(argc, argv, list_plugins_options);
1819 if (!argpar_iter) {
1820 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1821 goto error;
1822 }
1823
a93e984c 1824 while (true) {
353c2524 1825 enum parse_next_item_status parse_status =
a80892ba
SM
1826 parse_next_item(argpar_iter, &argpar_item, argv, "list-plugins",
1827 consumed_args);
9009cc24 1828
353c2524 1829 if (parse_status == PARSE_NEXT_ITEM_STATUS_ERROR) {
a93e984c 1830 goto error;
353c2524 1831 } else if (parse_status == PARSE_NEXT_ITEM_STATUS_END) {
a93e984c
SM
1832 break;
1833 }
9009cc24 1834
a93e984c
SM
1835 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
1836 const struct argpar_opt_descr *opt_descr =
1837 argpar_item_opt_descr(argpar_item);
1838
1839 switch (opt_descr->id) {
1840 case OPT_HELP:
1841 print_list_plugins_usage(stdout);
353c2524 1842 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c
SM
1843 goto end;
1844 default:
1845 bt_common_abort();
1846 }
1847 } else {
1848 BT_CLI_LOGE_APPEND_CAUSE(
1849 "Extraneous command-line argument specified to `list-plugins` command: `%s`.",
1850 argpar_item_non_opt_arg(argpar_item));
1851 goto error;
1852 }
1853 }
9009cc24 1854
353c2524
SM
1855 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
1856 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
9009cc24
PP
1857 goto end;
1858
1859error:
353c2524 1860 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
1861
1862end:
a93e984c
SM
1863 argpar_iter_destroy(argpar_iter);
1864 argpar_item_destroy(argpar_item);
353c2524 1865 bt_object_put_ref(cfg);
9009cc24 1866
353c2524 1867 return status;
9009cc24
PP
1868}
1869
1870/*
1871 * Prints the run command usage.
1872 */
1873static
1874void print_run_usage(FILE *fp)
1875{
ec2c5e50 1876 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] run [OPTIONS]\n");
9009cc24
PP
1877 fprintf(fp, "\n");
1878 fprintf(fp, "Options:\n");
1879 fprintf(fp, "\n");
1880 fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
1881 fprintf(fp, " for all the following components until\n");
1882 fprintf(fp, " --reset-base-params is encountered\n");
1883 fprintf(fp, " (see the expected format of PARAMS below)\n");
505d9178 1884 fprintf(fp, " -c, --component=NAME:TYPE.PLUGIN.CLS\n");
fd5f8053
PP
1885 fprintf(fp, " Instantiate the component class CLS of type\n");
1886 fprintf(fp, " TYPE (`source`, `filter`, or `sink`) found\n");
1887 fprintf(fp, " in the plugin PLUGIN, add it to the graph,\n");
505d9178 1888 fprintf(fp, " and name it NAME");
b87236ec 1889 fprintf(fp, " -x, --connect=CONNECTION Connect two created components (see the\n");
9009cc24 1890 fprintf(fp, " expected format of CONNECTION below)\n");
29da2ffc 1891 fprintf(fp, " -l, --log-level=LVL Set the log level of the current component to LVL\n");
20931d22 1892 fprintf(fp, " (`N`, `T`, `D`, `I`, `W`, `E`, or `F`)\n");
9009cc24
PP
1893 fprintf(fp, " -p, --params=PARAMS Add initialization parameters PARAMS to the\n");
1894 fprintf(fp, " current component (see the expected format\n");
1895 fprintf(fp, " of PARAMS below)\n");
9009cc24
PP
1896 fprintf(fp, " -r, --reset-base-params Reset the current base parameters to an\n");
1897 fprintf(fp, " empty map\n");
ec2c5e50 1898 fprintf(fp, " --retry-duration=DUR When babeltrace2(1) needs to retry to run\n");
9009cc24
PP
1899 fprintf(fp, " the graph later, retry in DUR µs\n");
1900 fprintf(fp, " (default: 100000)\n");
3efa3052 1901 fprintf(fp, " -h, --help Show this help and quit\n");
9009cc24 1902 fprintf(fp, "\n");
ec2c5e50 1903 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
9009cc24
PP
1904 fprintf(fp, "\n\n");
1905 fprintf(fp, "Expected format of CONNECTION\n");
1906 fprintf(fp, "-----------------------------\n");
1907 fprintf(fp, "\n");
1908 fprintf(fp, " UPSTREAM[.UPSTREAM-PORT]:DOWNSTREAM[.DOWNSTREAM-PORT]\n");
1909 fprintf(fp, "\n");
1910 fprintf(fp, "UPSTREAM and DOWNSTREAM are names of the upstream and downstream\n");
1911 fprintf(fp, "components to connect together. You must escape the following characters\n\n");
505d9178
SM
1912 fprintf(fp, "with `\\`: `\\`, `.`, and `:`. You must set the name of the current\n");
1913 fprintf(fp, "component using the NAME prefix of the --component option.\n");
9009cc24
PP
1914 fprintf(fp, "\n");
1915 fprintf(fp, "UPSTREAM-PORT and DOWNSTREAM-PORT are optional globbing patterns to\n");
1916 fprintf(fp, "identify the upstream and downstream ports to use for the connection.\n");
1917 fprintf(fp, "When the port is not specified, `*` is used.\n");
1918 fprintf(fp, "\n");
1919 fprintf(fp, "When a component named UPSTREAM has an available port which matches the\n");
1920 fprintf(fp, "UPSTREAM-PORT globbing pattern, it is connected to the first port which\n");
1921 fprintf(fp, "matches the DOWNSTREAM-PORT globbing pattern of the component named\n");
1922 fprintf(fp, "DOWNSTREAM.\n");
1923 fprintf(fp, "\n");
1924 fprintf(fp, "The only special character in UPSTREAM-PORT and DOWNSTREAM-PORT is `*`\n");
1925 fprintf(fp, "which matches anything. You must escape the following characters\n");
1926 fprintf(fp, "with `\\`: `\\`, `*`, `?`, `[`, `.`, and `:`.\n");
1927 fprintf(fp, "\n");
1928 fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
1929 fprintf(fp, "can connect a filter component to a sink component.\n");
1930 fprintf(fp, "\n");
1931 fprintf(fp, "Examples:\n");
1932 fprintf(fp, "\n");
1933 fprintf(fp, " my-src:my-sink\n");
1934 fprintf(fp, " ctf-fs.*stream*:utils-muxer:*\n");
1935 fprintf(fp, "\n");
1936 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
ec2c5e50 1937 fprintf(fp, "babeltrace2 from a shell.\n");
9009cc24
PP
1938 fprintf(fp, "\n\n");
1939 print_expected_params_format(fp);
1940}
1941
1942/*
1943 * Creates a Babeltrace config object from the arguments of a run
1944 * command.
9009cc24
PP
1945 */
1946static
353c2524
SM
1947enum bt_config_cli_args_status bt_config_run_from_args(int argc, const char *argv[],
1948 struct bt_config **cfg_out, const bt_value *plugin_paths,
a80892ba 1949 int default_log_level, unsigned int consumed_args)
9009cc24 1950{
353c2524 1951 enum bt_config_cli_args_status status;
9009cc24 1952 struct bt_config_component *cur_cfg_comp = NULL;
b19ff26f 1953 bt_value *cur_base_params = NULL;
976b24cf 1954 int ret = 0;
9009cc24 1955 struct bt_config *cfg = NULL;
b19ff26f
PP
1956 bt_value *instance_names = NULL;
1957 bt_value *connection_args = NULL;
9009cc24 1958 char error_buf[256] = { 0 };
c0521175 1959 long retry_duration = -1;
d24d5663 1960 bt_value_map_extend_status extend_status;
8bd04432 1961 GString *error_str = NULL;
a93e984c
SM
1962 struct argpar_iter *argpar_iter = NULL;
1963 const struct argpar_item *argpar_item = NULL;
976b24cf 1964
65966041 1965 static const struct argpar_opt_descr run_options[] = {
976b24cf
SM
1966 { OPT_BASE_PARAMS, 'b', "base-params", true },
1967 { OPT_COMPONENT, 'c', "component", true },
1968 { OPT_CONNECT, 'x', "connect", true },
1969 { OPT_HELP, 'h', "help", false },
1970 { OPT_LOG_LEVEL, 'l', "log-level", true },
976b24cf 1971 { OPT_PARAMS, 'p', "params", true },
976b24cf
SM
1972 { OPT_RESET_BASE_PARAMS, 'r', "reset-base-params", false },
1973 { OPT_RETRY_DURATION, '\0', "retry-duration", true },
65966041 1974 ARGPAR_OPT_DESCR_SENTINEL
9009cc24
PP
1975 };
1976
8bd04432
PP
1977 error_str = g_string_new(NULL);
1978 if (!error_str) {
9f901451 1979 BT_CLI_LOGE_APPEND_CAUSE_OOM();
8bd04432
PP
1980 goto error;
1981 }
1982
0e497e1c 1983 if (argc < 1) {
9009cc24 1984 print_run_usage(stdout);
353c2524 1985 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
9009cc24
PP
1986 goto end;
1987 }
1988
02510056 1989 cfg = bt_config_run_create(plugin_paths);
9009cc24
PP
1990 if (!cfg) {
1991 goto error;
1992 }
1993
1994 cfg->cmd_data.run.retry_duration_us = 100000;
05e21286 1995 cur_base_params = bt_value_map_create();
9009cc24 1996 if (!cur_base_params) {
9f901451 1997 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
1998 goto error;
1999 }
2000
05e21286 2001 instance_names = bt_value_map_create();
9009cc24 2002 if (!instance_names) {
9f901451 2003 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2004 goto error;
2005 }
2006
05e21286 2007 connection_args = bt_value_array_create();
9009cc24 2008 if (!connection_args) {
9f901451 2009 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2010 goto error;
2011 }
2012
a93e984c
SM
2013 argpar_iter = argpar_iter_create(argc, argv, run_options);
2014 if (!argpar_iter) {
2015 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2016 goto error;
2017 }
2018
a93e984c 2019 while (true) {
353c2524 2020 enum parse_next_item_status parse_status;
a93e984c 2021 const struct argpar_opt_descr *opt_descr;
976b24cf 2022 const char *arg;
9009cc24 2023
353c2524 2024 parse_status = parse_next_item(argpar_iter, &argpar_item, argv, "run",
a80892ba 2025 consumed_args);
353c2524 2026 if (parse_status == PARSE_NEXT_ITEM_STATUS_ERROR) {
a93e984c 2027 goto error;
353c2524 2028 } else if (parse_status == PARSE_NEXT_ITEM_STATUS_END) {
a93e984c
SM
2029 break;
2030 }
976b24cf 2031
a93e984c
SM
2032 /* This command does not accept non-option arguments.*/
2033 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_NON_OPT) {
976b24cf 2034 BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`",
a93e984c 2035 argpar_item_non_opt_arg(argpar_item));
976b24cf
SM
2036 goto error;
2037 }
2038
a93e984c
SM
2039 opt_descr = argpar_item_opt_descr(argpar_item);
2040 arg = argpar_item_opt_arg(argpar_item);
976b24cf 2041
a93e984c
SM
2042 switch (opt_descr->id) {
2043 case OPT_HELP:
2044 print_run_usage(stdout);
353c2524 2045 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c 2046 goto end;
fd5f8053 2047 case OPT_COMPONENT:
9009cc24 2048 {
505d9178 2049 enum bt_config_component_dest dest;
9009cc24 2050
505d9178 2051 BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
29da2ffc
PP
2052 cur_cfg_comp = bt_config_component_from_arg(arg,
2053 default_log_level);
9009cc24 2054 if (!cur_cfg_comp) {
9f901451 2055 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --component option's argument:\n %s",
fd5f8053 2056 arg);
9009cc24
PP
2057 goto error;
2058 }
2059
fd5f8053
PP
2060 switch (cur_cfg_comp->type) {
2061 case BT_COMPONENT_CLASS_TYPE_SOURCE:
505d9178 2062 dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
fd5f8053
PP
2063 break;
2064 case BT_COMPONENT_CLASS_TYPE_FILTER:
505d9178 2065 dest = BT_CONFIG_COMPONENT_DEST_FILTER;
fd5f8053
PP
2066 break;
2067 case BT_COMPONENT_CLASS_TYPE_SINK:
505d9178 2068 dest = BT_CONFIG_COMPONENT_DEST_SINK;
fd5f8053
PP
2069 break;
2070 default:
498e7994 2071 bt_common_abort();
fd5f8053
PP
2072 }
2073
f6ccaed9 2074 BT_ASSERT(cur_base_params);
c5b9b441 2075 bt_value_put_ref(cur_cfg_comp->params);
d24d5663
PP
2076 if (bt_value_copy(cur_base_params,
2077 &cur_cfg_comp->params) < 0) {
9f901451 2078 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2079 goto error;
2080 }
2081
505d9178
SM
2082 ret = add_run_cfg_comp_check_name(cfg,
2083 cur_cfg_comp, dest,
2084 instance_names);
2085 if (ret) {
2086 goto error;
2087 }
2088
9009cc24
PP
2089 break;
2090 }
2091 case OPT_PARAMS:
2092 {
b19ff26f 2093 bt_value *params;
9009cc24
PP
2094
2095 if (!cur_cfg_comp) {
9f901451 2096 BT_CLI_LOGE_APPEND_CAUSE("Cannot add parameters to unavailable component:\n %s",
9009cc24
PP
2097 arg);
2098 goto error;
2099 }
2100
5869b179 2101 params = bt_param_parse(arg, error_str);
9009cc24 2102 if (!params) {
9f901451 2103 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s",
8bd04432 2104 error_str->str);
9009cc24
PP
2105 goto error;
2106 }
2107
ab26240f
FD
2108 extend_status = bt_value_map_extend(cur_cfg_comp->params,
2109 params);
c5b9b441 2110 BT_VALUE_PUT_REF_AND_RESET(params);
d24d5663 2111 if (extend_status != BT_VALUE_MAP_EXTEND_STATUS_OK) {
9f901451 2112 BT_CLI_LOGE_APPEND_CAUSE("Cannot extend current component parameters with --params option's argument:\n %s",
9009cc24
PP
2113 arg);
2114 goto error;
2115 }
2116
9009cc24
PP
2117 break;
2118 }
29da2ffc
PP
2119 case OPT_LOG_LEVEL:
2120 if (!cur_cfg_comp) {
9f901451 2121 BT_CLI_LOGE_APPEND_CAUSE("Cannot set the log level of unavailable component:\n %s",
29da2ffc
PP
2122 arg);
2123 goto error;
2124 }
2125
2126 cur_cfg_comp->log_level =
2127 bt_log_get_level_from_string(arg);
2128 if (cur_cfg_comp->log_level < 0) {
9f901451 2129 BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n %s",
29da2ffc
PP
2130 arg);
2131 goto error;
2132 }
2133 break;
9009cc24
PP
2134 case OPT_BASE_PARAMS:
2135 {
5869b179 2136 bt_value *params = bt_param_parse(arg, error_str);
9009cc24
PP
2137
2138 if (!params) {
9f901451 2139 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --base-params option's argument:\n %s",
8bd04432 2140 error_str->str);
9009cc24
PP
2141 goto error;
2142 }
2143
65300d60 2144 BT_OBJECT_MOVE_REF(cur_base_params, params);
9009cc24
PP
2145 break;
2146 }
2147 case OPT_RESET_BASE_PARAMS:
c5b9b441 2148 BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
05e21286 2149 cur_base_params = bt_value_map_create();
9009cc24 2150 if (!cur_base_params) {
9f901451 2151 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2152 goto error;
2153 }
2154 break;
2155 case OPT_CONNECT:
05e21286 2156 if (bt_value_array_append_string_element(
07208d85 2157 connection_args, arg)) {
9f901451 2158 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2159 goto error;
2160 }
2161 break;
976b24cf
SM
2162 case OPT_RETRY_DURATION: {
2163 gchar *end;
a93e984c 2164 size_t arg_len = strlen(arg);
976b24cf 2165
a93e984c 2166 retry_duration = g_ascii_strtoll(arg, &end, 10);
976b24cf 2167
a93e984c 2168 if (arg_len == 0 || end != (arg + arg_len)) {
976b24cf
SM
2169 BT_CLI_LOGE_APPEND_CAUSE(
2170 "Could not parse --retry-duration option's argument as an unsigned integer: `%s`",
a93e984c 2171 arg);
976b24cf
SM
2172 goto error;
2173 }
2174
9009cc24 2175 if (retry_duration < 0) {
9f901451 2176 BT_CLI_LOGE_APPEND_CAUSE("--retry-duration option's argument must be positive or 0: %ld",
9009cc24
PP
2177 retry_duration);
2178 goto error;
2179 }
2180
2181 cfg->cmd_data.run.retry_duration_us =
2182 (uint64_t) retry_duration;
2183 break;
976b24cf 2184 }
9009cc24 2185 default:
a93e984c 2186 bt_common_abort();
9009cc24 2187 }
9009cc24
PP
2188 }
2189
505d9178 2190 BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
9009cc24
PP
2191
2192 if (cfg->cmd_data.run.sources->len == 0) {
9f901451 2193 BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no source component.");
9009cc24
PP
2194 goto error;
2195 }
2196
2197 if (cfg->cmd_data.run.sinks->len == 0) {
9f901451 2198 BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no sink component.");
9009cc24
PP
2199 goto error;
2200 }
2201
da91b29a 2202 ret = bt_config_cli_args_create_connections(cfg,
05e21286 2203 connection_args,
9009cc24
PP
2204 error_buf, 256);
2205 if (ret) {
9f901451 2206 BT_CLI_LOGE_APPEND_CAUSE("Cannot creation connections:\n%s", error_buf);
9009cc24
PP
2207 goto error;
2208 }
2209
353c2524
SM
2210 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
2211 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
9009cc24
PP
2212 goto end;
2213
2214error:
353c2524 2215 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
2216
2217end:
8bd04432
PP
2218 if (error_str) {
2219 g_string_free(error_str, TRUE);
2220 }
2221
a93e984c
SM
2222 argpar_iter_destroy(argpar_iter);
2223 argpar_item_destroy(argpar_item);
2224
65300d60 2225 BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
c5b9b441
PP
2226 BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
2227 BT_VALUE_PUT_REF_AND_RESET(instance_names);
2228 BT_VALUE_PUT_REF_AND_RESET(connection_args);
353c2524
SM
2229 bt_object_put_ref(cfg);
2230
2231 return status;
9009cc24
PP
2232}
2233
2234static
353c2524
SM
2235enum bt_config_cli_args_status bt_config_run_from_args_array(
2236 const bt_value *run_args, struct bt_config **cfg,
2237 const bt_value *plugin_paths,
02510056 2238 int default_log_level)
9009cc24 2239{
353c2524 2240 enum bt_config_cli_args_status status;
9009cc24 2241 const char **argv;
f80e9ec1 2242 uint64_t i, len = bt_value_array_get_length(run_args);
9009cc24 2243
f80e9ec1
FD
2244 BT_ASSERT(len <= SIZE_MAX);
2245 argv = calloc((size_t) len, sizeof(*argv));
9009cc24 2246 if (!argv) {
9f901451 2247 BT_CLI_LOGE_APPEND_CAUSE_OOM();
353c2524 2248 goto error;
9009cc24
PP
2249 }
2250
0ca8409d 2251 for (i = 0; i < len; i++) {
b19ff26f 2252 const bt_value *arg_value =
05e21286 2253 bt_value_array_borrow_element_by_index_const(run_args,
50962110 2254 i);
9009cc24
PP
2255 const char *arg;
2256
601b0d3c 2257 arg = bt_value_string_get(arg_value);
f6ccaed9 2258 BT_ASSERT(arg);
0e497e1c 2259 argv[i] = arg;
9009cc24
PP
2260 }
2261
353c2524 2262 status = bt_config_run_from_args((int) len, argv, cfg,
a80892ba 2263 plugin_paths, default_log_level, 0);
9009cc24 2264
353c2524
SM
2265 goto end;
2266
2267error:
2268 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
2269
9009cc24
PP
2270end:
2271 free(argv);
353c2524 2272 return status;
9009cc24
PP
2273}
2274
2275/*
2276 * Prints the convert command usage.
2277 */
2278static
2279void print_convert_usage(FILE *fp)
2280{
ec2c5e50 2281 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [convert] [OPTIONS] [PATH/URL]\n");
9009cc24
PP
2282 fprintf(fp, "\n");
2283 fprintf(fp, "Options:\n");
2284 fprintf(fp, "\n");
fd5f8053
PP
2285 fprintf(fp, " -c, --component=[NAME:]TYPE.PLUGIN.CLS\n");
2286 fprintf(fp, " Instantiate the component class CLS of type\n");
2287 fprintf(fp, " TYPE (`source`, `filter`, or `sink`) found\n");
2288 fprintf(fp, " in the plugin PLUGIN, add it to the\n");
2289 fprintf(fp, " conversion graph, and optionally name it\n");
505d9178 2290 fprintf(fp, " NAME\n");
29da2ffc 2291 fprintf(fp, " -l, --log-level=LVL Set the log level of the current component to LVL\n");
20931d22 2292 fprintf(fp, " (`N`, `T`, `D`, `I`, `W`, `E`, or `F`)\n");
9009cc24
PP
2293 fprintf(fp, " -p, --params=PARAMS Add initialization parameters PARAMS to the\n");
2294 fprintf(fp, " current component (see the expected format\n");
2295 fprintf(fp, " of PARAMS below)\n");
ec2c5e50 2296 fprintf(fp, " --retry-duration=DUR When babeltrace2(1) needs to retry to run\n");
9009cc24
PP
2297 fprintf(fp, " the graph later, retry in DUR µs\n");
2298 fprintf(fp, " (default: 100000)\n");
2299 fprintf(fp, " dynamic plugins can be loaded\n");
2300 fprintf(fp, " --run-args Print the equivalent arguments for the\n");
2301 fprintf(fp, " `run` command to the standard output,\n");
2302 fprintf(fp, " formatted for a shell, and quit\n");
2303 fprintf(fp, " --run-args-0 Print the equivalent arguments for the\n");
2304 fprintf(fp, " `run` command to the standard output,\n");
2305 fprintf(fp, " formatted for `xargs -0`, and quit\n");
8ed0bf10
PP
2306 fprintf(fp, " --stream-intersection Only process events when all streams\n");
2307 fprintf(fp, " are active\n");
3efa3052 2308 fprintf(fp, " -h, --help Show this help and quit\n");
9009cc24 2309 fprintf(fp, "\n");
e7ad156c 2310 fprintf(fp, "Implicit `source.ctf.fs` component options:\n");
9009cc24 2311 fprintf(fp, "\n");
9412c556
FD
2312 fprintf(fp, " --clock-force-correlate Force the origin of all clocks\n");
2313 fprintf(fp, " to the Unix epoch\n");
9009cc24
PP
2314 fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n");
2315 fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS ns\n");
9009cc24 2316 fprintf(fp, "\n");
e7ad156c 2317 fprintf(fp, "Implicit `sink.text.pretty` component options:\n");
9009cc24
PP
2318 fprintf(fp, "\n");
2319 fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n");
2320 fprintf(fp, " --clock-date Print timestamp dates\n");
2321 fprintf(fp, " --clock-gmt Print and parse timestamps in the GMT\n");
2322 fprintf(fp, " time zone instead of the local time zone\n");
2323 fprintf(fp, " --clock-seconds Print the timestamps as `SEC.NS` instead\n");
2324 fprintf(fp, " of `hh:mm:ss.nnnnnnnnn`\n");
2325 fprintf(fp, " --color=(never | auto | always)\n");
2326 fprintf(fp, " Never, automatically, or always emit\n");
2327 fprintf(fp, " console color codes\n");
2328 fprintf(fp, " -f, --fields=FIELD[,FIELD]... Print additional fields; FIELD can be:\n");
2329 fprintf(fp, " `all`, `trace`, `trace:hostname`,\n");
2330 fprintf(fp, " `trace:domain`, `trace:procname`,\n");
2331 fprintf(fp, " `trace:vpid`, `loglevel`, `emf`\n");
2332 fprintf(fp, " -n, --names=NAME[,NAME]... Print field names; NAME can be:\n");
2333 fprintf(fp, " `payload` (or `arg` or `args`), `none`,\n");
2334 fprintf(fp, " `all`, `scope`, `header`, `context`\n");
2335 fprintf(fp, " (or `ctx`)\n");
2336 fprintf(fp, " --no-delta Do not print time delta between\n");
2337 fprintf(fp, " consecutive events\n");
2338 fprintf(fp, " -w, --output=PATH Write output text to PATH instead of\n");
2339 fprintf(fp, " the standard output\n");
2340 fprintf(fp, "\n");
e7ad156c 2341 fprintf(fp, "Implicit `filter.utils.trimmer` component options:\n");
9009cc24
PP
2342 fprintf(fp, "\n");
2343 fprintf(fp, " -b, --begin=BEGIN Set the beginning time of the conversion\n");
2344 fprintf(fp, " time range to BEGIN (see the format of\n");
2345 fprintf(fp, " BEGIN below)\n");
2346 fprintf(fp, " -e, --end=END Set the end time of the conversion time\n");
2347 fprintf(fp, " range to END (see the format of END below)\n");
2348 fprintf(fp, " -t, --timerange=TIMERANGE Set conversion time range to TIMERANGE:\n");
2349 fprintf(fp, " BEGIN,END or [BEGIN,END] (literally `[` and\n");
2350 fprintf(fp, " `]`) (see the format of BEGIN/END below)\n");
2351 fprintf(fp, "\n");
e7ad156c 2352 fprintf(fp, "Implicit `filter.lttng-utils.debug-info` component options:\n");
9009cc24 2353 fprintf(fp, "\n");
9a16feea
PP
2354 fprintf(fp, " --debug-info Create an implicit\n");
2355 fprintf(fp, " `filter.lttng-utils.debug-info` component\n");
9009cc24
PP
2356 fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
2357 fprintf(fp, " instead of `/usr/lib/debug`\n");
2358 fprintf(fp, " --debug-info-full-path Show full debug info source and\n");
2359 fprintf(fp, " binary paths instead of just names\n");
2360 fprintf(fp, " --debug-info-target-prefix=DIR\n");
2361 fprintf(fp, " Use directory DIR as a prefix when\n");
2362 fprintf(fp, " looking up executables during debug\n");
2363 fprintf(fp, " info analysis\n");
9009cc24
PP
2364 fprintf(fp, "\n");
2365 fprintf(fp, "Legacy options that still work:\n");
2366 fprintf(fp, "\n");
2367 fprintf(fp, " -i, --input-format=(ctf | lttng-live)\n");
2368 fprintf(fp, " `ctf`:\n");
fd5f8053 2369 fprintf(fp, " Create an implicit `source.ctf.fs`\n");
9009cc24
PP
2370 fprintf(fp, " component\n");
2371 fprintf(fp, " `lttng-live`:\n");
fd5f8053
PP
2372 fprintf(fp, " Create an implicit `source.ctf.lttng-live`\n");
2373 fprintf(fp, " component\n");
e7ad156c 2374 fprintf(fp, " -o, --output-format=(text | ctf | dummy | ctf-metadata)\n");
9009cc24 2375 fprintf(fp, " `text`:\n");
fd5f8053 2376 fprintf(fp, " Create an implicit `sink.text.pretty`\n");
9009cc24 2377 fprintf(fp, " component\n");
dd46f7ea 2378 fprintf(fp, " `ctf`:\n");
e7ad156c
PP
2379 fprintf(fp, " Create an implicit `sink.ctf.fs`\n");
2380 fprintf(fp, " component\n");
9009cc24 2381 fprintf(fp, " `dummy`:\n");
fd5f8053 2382 fprintf(fp, " Create an implicit `sink.utils.dummy`\n");
9009cc24
PP
2383 fprintf(fp, " component\n");
2384 fprintf(fp, " `ctf-metadata`:\n");
fd5f8053
PP
2385 fprintf(fp, " Query the `source.ctf.fs` component class\n");
2386 fprintf(fp, " for metadata text and quit\n");
9009cc24 2387 fprintf(fp, "\n");
ec2c5e50 2388 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
9009cc24
PP
2389 fprintf(fp, "\n\n");
2390 fprintf(fp, "Format of BEGIN and END\n");
2391 fprintf(fp, "-----------------------\n");
2392 fprintf(fp, "\n");
2393 fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
2394 fprintf(fp, "\n\n");
2395 print_expected_params_format(fp);
2396}
2397
2398static
65966041 2399const struct argpar_opt_descr convert_options[] = {
ca60bbc3
SM
2400 /* id, short_name, long_name, with_arg */
2401 { OPT_BEGIN, 'b', "begin", true },
2402 { OPT_CLOCK_CYCLES, '\0', "clock-cycles", false },
2403 { OPT_CLOCK_DATE, '\0', "clock-date", false },
2404 { OPT_CLOCK_FORCE_CORRELATE, '\0', "clock-force-correlate", false },
2405 { OPT_CLOCK_GMT, '\0', "clock-gmt", false },
2406 { OPT_CLOCK_OFFSET, '\0', "clock-offset", true },
2407 { OPT_CLOCK_OFFSET_NS, '\0', "clock-offset-ns", true },
2408 { OPT_CLOCK_SECONDS, '\0', "clock-seconds", false },
2409 { OPT_COLOR, '\0', "color", true },
2410 { OPT_COMPONENT, 'c', "component", true },
2411 { OPT_DEBUG, 'd', "debug", false },
2412 { OPT_DEBUG_INFO_DIR, '\0', "debug-info-dir", true },
2413 { OPT_DEBUG_INFO_FULL_PATH, '\0', "debug-info-full-path", false },
2414 { OPT_DEBUG_INFO_TARGET_PREFIX, '\0', "debug-info-target-prefix", true },
2415 { OPT_END, 'e', "end", true },
2416 { OPT_FIELDS, 'f', "fields", true },
2417 { OPT_HELP, 'h', "help", false },
2418 { OPT_INPUT_FORMAT, 'i', "input-format", true },
2419 { OPT_LOG_LEVEL, 'l', "log-level", true },
ca60bbc3
SM
2420 { OPT_NAMES, 'n', "names", true },
2421 { OPT_DEBUG_INFO, '\0', "debug-info", false },
2422 { OPT_NO_DELTA, '\0', "no-delta", false },
2423 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
2424 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
2425 { OPT_OUTPUT, 'w', "output", true },
2426 { OPT_OUTPUT_FORMAT, 'o', "output-format", true },
2427 { OPT_PARAMS, 'p', "params", true },
ca60bbc3
SM
2428 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
2429 { OPT_RETRY_DURATION, '\0', "retry-duration", true },
2430 { OPT_RUN_ARGS, '\0', "run-args", false },
2431 { OPT_RUN_ARGS_0, '\0', "run-args-0", false },
2432 { OPT_STREAM_INTERSECTION, '\0', "stream-intersection", false },
2433 { OPT_TIMERANGE, '\0', "timerange", true },
ca60bbc3 2434 { OPT_VERBOSE, 'v', "verbose", false },
65966041 2435 ARGPAR_OPT_DESCR_SENTINEL
9009cc24
PP
2436};
2437
2438static
2439GString *get_component_auto_name(const char *prefix,
b19ff26f 2440 const bt_value *existing_names)
9009cc24
PP
2441{
2442 unsigned int i = 0;
2443 GString *auto_name = g_string_new(NULL);
2444
2445 if (!auto_name) {
9f901451 2446 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2447 goto end;
2448 }
2449
07208d85 2450 if (!bt_value_map_has_entry(existing_names, prefix)) {
9009cc24
PP
2451 g_string_assign(auto_name, prefix);
2452 goto end;
2453 }
2454
2455 do {
2456 g_string_printf(auto_name, "%s-%d", prefix, i);
2457 i++;
07208d85 2458 } while (bt_value_map_has_entry(existing_names, auto_name->str));
9009cc24
PP
2459
2460end:
2461 return auto_name;
2462}
2463
2464struct implicit_component_args {
2465 bool exists;
73760435
SM
2466
2467 /* The component class name (e.g. src.ctf.fs). */
fd5f8053 2468 GString *comp_arg;
73760435
SM
2469
2470 /* The component instance name. */
9009cc24 2471 GString *name_arg;
73760435 2472
9009cc24 2473 GString *params_arg;
b19ff26f 2474 bt_value *extra_params;
9009cc24
PP
2475};
2476
2477static
2478int assign_name_to_implicit_component(struct implicit_component_args *args,
b19ff26f 2479 const char *prefix, bt_value *existing_names,
9009cc24
PP
2480 GList **comp_names, bool append_to_comp_names)
2481{
2482 int ret = 0;
2483 GString *name = NULL;
2484
2485 if (!args->exists) {
2486 goto end;
2487 }
2488
da91b29a 2489 name = get_component_auto_name(prefix,
05e21286 2490 existing_names);
9009cc24
PP
2491
2492 if (!name) {
2493 ret = -1;
2494 goto end;
2495 }
2496
2497 g_string_assign(args->name_arg, name->str);
2498
05e21286 2499 if (bt_value_map_insert_entry(existing_names, name->str,
9009cc24 2500 bt_value_null)) {
9f901451 2501 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2502 ret = -1;
2503 goto end;
2504 }
2505
2506 if (append_to_comp_names) {
2507 *comp_names = g_list_append(*comp_names, name);
2508 name = NULL;
2509 }
2510
2511end:
2512 if (name) {
2513 g_string_free(name, TRUE);
2514 }
2515
2516 return ret;
2517}
2518
2519static
2520int append_run_args_for_implicit_component(
9009cc24 2521 struct implicit_component_args *impl_args,
b19ff26f 2522 bt_value *run_args)
9009cc24
PP
2523{
2524 int ret = 0;
f80e9ec1 2525 uint64_t i;
505d9178 2526 GString *component_arg_for_run = NULL;
9009cc24
PP
2527
2528 if (!impl_args->exists) {
2529 goto end;
2530 }
2531
505d9178
SM
2532 component_arg_for_run = g_string_new(NULL);
2533 if (!component_arg_for_run) {
9f901451 2534 BT_CLI_LOGE_APPEND_CAUSE_OOM();
fd5f8053 2535 goto error;
9009cc24
PP
2536 }
2537
505d9178
SM
2538 /* Build the full `name:type.plugin.cls`. */
2539 BT_ASSERT(!strchr(impl_args->name_arg->str, '\\'));
2540 BT_ASSERT(!strchr(impl_args->name_arg->str, ':'));
2541 g_string_printf(component_arg_for_run, "%s:%s",
2542 impl_args->name_arg->str, impl_args->comp_arg->str);
9009cc24 2543
505d9178 2544 if (bt_value_array_append_string_element(run_args, "--component")) {
9f901451 2545 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2546 goto error;
2547 }
2548
505d9178
SM
2549 if (bt_value_array_append_string_element(run_args,
2550 component_arg_for_run->str)) {
9f901451 2551 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2552 goto error;
2553 }
2554
2555 if (impl_args->params_arg->len > 0) {
05e21286 2556 if (bt_value_array_append_string_element(run_args, "--params")) {
9f901451 2557 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2558 goto error;
2559 }
2560
05e21286 2561 if (bt_value_array_append_string_element(run_args,
9009cc24 2562 impl_args->params_arg->str)) {
9f901451 2563 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2564 goto error;
2565 }
2566 }
2567
f80e9ec1 2568 for (i = 0; i < bt_value_array_get_length(impl_args->extra_params); i++) {
b19ff26f 2569 const bt_value *elem;
9009cc24
PP
2570 const char *arg;
2571
33f4e1fd
FD
2572 elem = bt_value_array_borrow_element_by_index(
2573 impl_args->extra_params, i);
9009cc24 2574
f6ccaed9 2575 BT_ASSERT(bt_value_is_string(elem));
601b0d3c 2576 arg = bt_value_string_get(elem);
05e21286 2577 ret = bt_value_array_append_string_element(run_args, arg);
9009cc24 2578 if (ret) {
9f901451 2579 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2580 goto error;
2581 }
2582 }
2583
2584 goto end;
2585
2586error:
2587 ret = -1;
2588
2589end:
505d9178
SM
2590 if (component_arg_for_run) {
2591 g_string_free(component_arg_for_run, TRUE);
2592 }
2593
9009cc24
PP
2594 return ret;
2595}
2596
73760435
SM
2597/* Free the fields of a `struct implicit_component_args`. */
2598
9009cc24 2599static
94023a1c 2600void finalize_implicit_component_args(struct implicit_component_args *args)
9009cc24 2601{
f6ccaed9 2602 BT_ASSERT(args);
9009cc24 2603
fd5f8053
PP
2604 if (args->comp_arg) {
2605 g_string_free(args->comp_arg, TRUE);
9009cc24
PP
2606 }
2607
2608 if (args->name_arg) {
2609 g_string_free(args->name_arg, TRUE);
2610 }
2611
2612 if (args->params_arg) {
2613 g_string_free(args->params_arg, TRUE);
2614 }
2615
c5b9b441 2616 bt_value_put_ref(args->extra_params);
9009cc24
PP
2617}
2618
73760435
SM
2619/* Destroy a dynamically-allocated `struct implicit_component_args`. */
2620
2621static
2622void destroy_implicit_component_args(struct implicit_component_args *args)
2623{
2624 finalize_implicit_component_args(args);
2625 g_free(args);
2626}
2627
2628/* Initialize the fields of an already allocated `struct implicit_component_args`. */
2629
9009cc24
PP
2630static
2631int init_implicit_component_args(struct implicit_component_args *args,
fd5f8053 2632 const char *comp_arg, bool exists)
9009cc24
PP
2633{
2634 int ret = 0;
2635
2636 args->exists = exists;
fd5f8053 2637 args->comp_arg = g_string_new(comp_arg);
9009cc24
PP
2638 args->name_arg = g_string_new(NULL);
2639 args->params_arg = g_string_new(NULL);
05e21286 2640 args->extra_params = bt_value_array_create();
9009cc24 2641
fd5f8053 2642 if (!args->comp_arg || !args->name_arg ||
e7ad156c 2643 !args->params_arg || !args->extra_params) {
9009cc24 2644 ret = -1;
94023a1c 2645 finalize_implicit_component_args(args);
9f901451 2646 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2647 goto end;
2648 }
2649
2650end:
2651 return ret;
2652}
2653
73760435
SM
2654/* Dynamically allocate and initialize a `struct implicit_component_args`. */
2655
2656static
2657struct implicit_component_args *create_implicit_component_args(
2658 const char *comp_arg)
2659{
2660 struct implicit_component_args *args;
2661 int status;
2662
2663 args = g_new(struct implicit_component_args, 1);
2664 if (!args) {
2665 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2666 goto end;
2667 }
2668
2669 status = init_implicit_component_args(args, comp_arg, true);
2670 if (status != 0) {
2671 g_free(args);
2672 args = NULL;
2673 }
2674
2675end:
2676 return args;
2677}
2678
9009cc24
PP
2679static
2680void append_implicit_component_param(struct implicit_component_args *args,
2681 const char *key, const char *value)
2682{
f6ccaed9
PP
2683 BT_ASSERT(args);
2684 BT_ASSERT(key);
2685 BT_ASSERT(value);
9009cc24
PP
2686 append_param_arg(args->params_arg, key, value);
2687}
2688
73760435
SM
2689/*
2690 * Append the given parameter (`key=value`) to all component specifications
2691 * in `implicit_comp_args` (an array of `struct implicit_component_args *`)
2692 * which match `comp_arg`.
2693 *
2694 * Return the number of matching components.
2695 */
2696
2697static
2698int append_multiple_implicit_components_param(GPtrArray *implicit_comp_args,
2699 const char *comp_arg, const char *key, const char *value)
2700{
2701 int i;
2702 int n = 0;
2703
2704 for (i = 0; i < implicit_comp_args->len; i++) {
2705 struct implicit_component_args *args = implicit_comp_args->pdata[i];
2706
2707 if (strcmp(args->comp_arg->str, comp_arg) == 0) {
2708 append_implicit_component_param(args, key, value);
2709 n++;
2710 }
2711 }
2712
2713 return n;
2714}
2715
c7b0cd78 2716/* Escape value to make it suitable to use as a string parameter value. */
9009cc24 2717static
c7b0cd78 2718gchar *escape_string_value(const char *value)
9009cc24 2719{
c7b0cd78
SM
2720 GString *ret;
2721 const char *in;
2722
2723 ret = g_string_new(NULL);
2724 if (!ret) {
9f901451 2725 BT_CLI_LOGE_APPEND_CAUSE_OOM();
c7b0cd78
SM
2726 goto end;
2727 }
2728
2729 in = value;
2730 while (*in) {
2731 switch (*in) {
2732 case '"':
2733 case '\\':
2734 g_string_append_c(ret, '\\');
2735 break;
2736 }
2737
2738 g_string_append_c(ret, *in);
2739
2740 in++;
2741 }
2742
2743end:
2744 return g_string_free(ret, FALSE);
2745}
9009cc24 2746
77957ab5 2747static
f280892e 2748int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf)
77957ab5 2749{
f280892e 2750 BT_ASSERT(buf);
77957ab5 2751
f280892e 2752 int ret = -1;
77957ab5
SM
2753
2754 switch (bt_value_get_type(value)) {
2755 case BT_VALUE_TYPE_STRING:
2756 {
2757 const char *str_value = bt_value_string_get(value);
2758 gchar *escaped_str_value;
2759
2760 escaped_str_value = escape_string_value(str_value);
2761 if (!escaped_str_value) {
f280892e 2762 goto end;
77957ab5
SM
2763 }
2764
f280892e 2765 g_string_append_printf(buf, "\"%s\"", escaped_str_value);
77957ab5
SM
2766
2767 g_free(escaped_str_value);
2768 break;
2769 }
f280892e
SM
2770 case BT_VALUE_TYPE_ARRAY: {
2771 g_string_append_c(buf, '[');
393729a6 2772 uint64_t sz = bt_value_array_get_length(value);
f280892e 2773 for (uint64_t i = 0; i < sz; i++) {
bea5b968 2774 const bt_value *item;
bea5b968 2775
f280892e 2776 if (i > 0) {
bea5b968 2777 g_string_append(buf, ", ");
f280892e 2778 }
bea5b968
PP
2779
2780 item = bt_value_array_borrow_element_by_index_const(
2781 value, i);
2782 ret = bt_value_to_cli_param_value_append(item, buf);
2783
f280892e
SM
2784 if (ret) {
2785 goto end;
2786 }
2787 }
2788 g_string_append_c(buf, ']');
2789 break;
2790 }
77957ab5 2791 default:
498e7994 2792 bt_common_abort();
77957ab5
SM
2793 }
2794
f280892e
SM
2795 ret = 0;
2796
2797end:
2798 return ret;
2799}
2800
2801/*
2802 * Convert `value` to its equivalent representation as a command line parameter
2803 * value.
2804 */
2805
2806static
2807gchar *bt_value_to_cli_param_value(bt_value *value)
2808{
2809 GString *buf;
2810 gchar *result = NULL;
2811
2812 buf = g_string_new(NULL);
2813 if (!buf) {
9f901451 2814 BT_CLI_LOGE_APPEND_CAUSE_OOM();
f280892e
SM
2815 goto error;
2816 }
2817
2818 if (bt_value_to_cli_param_value_append(value, buf)) {
2819 goto error;
2820 }
2821
77957ab5
SM
2822 result = g_string_free(buf, FALSE);
2823 buf = NULL;
2824
2825 goto end;
2826
2827error:
2828 if (buf) {
2829 g_string_free(buf, TRUE);
2830 }
2831
2832end:
2833 return result;
2834}
2835
c7b0cd78 2836static
77957ab5 2837int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
c7b0cd78 2838{
f6ccaed9 2839 BT_ASSERT(args);
c7b0cd78 2840 BT_ASSERT(bt_value_get_type(args) == BT_VALUE_TYPE_ARRAY);
f6ccaed9
PP
2841 BT_ASSERT(key);
2842 BT_ASSERT(value);
9009cc24 2843
c7b0cd78 2844 int ret = 0;
77957ab5 2845 gchar *str_value = NULL;
c7b0cd78
SM
2846 GString *parameter = NULL;
2847
2848 if (bt_value_array_append_string_element(args, "--params")) {
9f901451 2849 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2850 ret = -1;
2851 goto end;
2852 }
2853
77957ab5
SM
2854 str_value = bt_value_to_cli_param_value(value);
2855 if (!str_value) {
9009cc24
PP
2856 ret = -1;
2857 goto end;
2858 }
2859
c7b0cd78
SM
2860 parameter = g_string_new(NULL);
2861 if (!parameter) {
9f901451 2862 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2863 ret = -1;
2864 goto end;
2865 }
2866
77957ab5 2867 g_string_printf(parameter, "%s=%s", key, str_value);
c7b0cd78
SM
2868
2869 if (bt_value_array_append_string_element(args, parameter->str)) {
9f901451 2870 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2871 ret = -1;
2872 goto end;
2873 }
2874
2875end:
c7b0cd78
SM
2876 if (parameter) {
2877 g_string_free(parameter, TRUE);
2878 parameter = NULL;
2879 }
2880
77957ab5
SM
2881 if (str_value) {
2882 g_free(str_value);
2883 str_value = NULL;
2884 }
2885
2886 return ret;
2887}
2888
2889static
2890int append_string_parameter_to_args(bt_value *args, const char *key, const char *value)
2891{
2892 bt_value *str_value;
2893 int ret;
2894
2895 str_value = bt_value_string_create_init(value);
2896
2897 if (!str_value) {
9f901451 2898 BT_CLI_LOGE_APPEND_CAUSE_OOM();
77957ab5
SM
2899 ret = -1;
2900 goto end;
2901 }
2902
2903 ret = append_parameter_to_args(args, key, str_value);
2904
2905end:
2906 BT_VALUE_PUT_REF_AND_RESET(str_value);
9009cc24
PP
2907 return ret;
2908}
2909
c7b0cd78
SM
2910static
2911int append_implicit_component_extra_param(struct implicit_component_args *args,
2912 const char *key, const char *value)
2913{
77957ab5 2914 return append_string_parameter_to_args(args->extra_params, key, value);
c7b0cd78
SM
2915}
2916
9009cc24
PP
2917/*
2918 * Escapes `.`, `:`, and `\` of `input` with `\`.
2919 */
2920static
2921GString *escape_dot_colon(const char *input)
2922{
2923 GString *output = g_string_new(NULL);
2924 const char *ch;
2925
2926 if (!output) {
9f901451 2927 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2928 goto end;
2929 }
2930
2931 for (ch = input; *ch != '\0'; ch++) {
2932 if (*ch == '\\' || *ch == '.' || *ch == ':') {
2933 g_string_append_c(output, '\\');
2934 }
2935
2936 g_string_append_c(output, *ch);
2937 }
2938
2939end:
2940 return output;
2941}
2942
2943/*
2944 * Appends a --connect option to a list of arguments. `upstream_name`
2945 * and `downstream_name` are escaped with escape_dot_colon() in this
2946 * function.
2947 */
2948static
b19ff26f 2949int append_connect_arg(bt_value *run_args,
9009cc24
PP
2950 const char *upstream_name, const char *downstream_name)
2951{
2952 int ret = 0;
2953 GString *e_upstream_name = escape_dot_colon(upstream_name);
2954 GString *e_downstream_name = escape_dot_colon(downstream_name);
2955 GString *arg = g_string_new(NULL);
2956
2957 if (!e_upstream_name || !e_downstream_name || !arg) {
9f901451 2958 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2959 ret = -1;
2960 goto end;
2961 }
2962
05e21286 2963 ret = bt_value_array_append_string_element(run_args, "--connect");
9009cc24 2964 if (ret) {
9f901451 2965 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2966 ret = -1;
2967 goto end;
2968 }
2969
2970 g_string_append(arg, e_upstream_name->str);
2971 g_string_append_c(arg, ':');
2972 g_string_append(arg, e_downstream_name->str);
05e21286 2973 ret = bt_value_array_append_string_element(run_args, arg->str);
9009cc24 2974 if (ret) {
9f901451 2975 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
2976 ret = -1;
2977 goto end;
2978 }
2979
2980end:
2981 if (arg) {
2982 g_string_free(arg, TRUE);
2983 }
2984
2985 if (e_upstream_name) {
2986 g_string_free(e_upstream_name, TRUE);
2987 }
2988
2989 if (e_downstream_name) {
2990 g_string_free(e_downstream_name, TRUE);
2991 }
2992
2993 return ret;
2994}
2995
2996/*
2997 * Appends the run command's --connect options for the convert command.
2998 */
2999static
b19ff26f 3000int convert_auto_connect(bt_value *run_args,
9009cc24
PP
3001 GList *source_names, GList *filter_names,
3002 GList *sink_names)
3003{
3004 int ret = 0;
3005 GList *source_at = source_names;
3006 GList *filter_at = filter_names;
3007 GList *filter_prev;
3008 GList *sink_at = sink_names;
3009
f6ccaed9
PP
3010 BT_ASSERT(source_names);
3011 BT_ASSERT(filter_names);
3012 BT_ASSERT(sink_names);
9009cc24
PP
3013
3014 /* Connect all sources to the first filter */
5084732e 3015 for (source_at = source_names; source_at; source_at = g_list_next(source_at)) {
9009cc24
PP
3016 GString *source_name = source_at->data;
3017 GString *filter_name = filter_at->data;
3018
3019 ret = append_connect_arg(run_args, source_name->str,
3020 filter_name->str);
3021 if (ret) {
3022 goto error;
3023 }
3024 }
3025
3026 filter_prev = filter_at;
3027 filter_at = g_list_next(filter_at);
3028
3029 /* Connect remaining filters */
5084732e 3030 for (; filter_at; filter_prev = filter_at, filter_at = g_list_next(filter_at)) {
9009cc24
PP
3031 GString *filter_name = filter_at->data;
3032 GString *filter_prev_name = filter_prev->data;
3033
3034 ret = append_connect_arg(run_args, filter_prev_name->str,
3035 filter_name->str);
3036 if (ret) {
3037 goto error;
3038 }
3039 }
3040
3041 /* Connect last filter to all sinks */
5084732e 3042 for (sink_at = sink_names; sink_at; sink_at = g_list_next(sink_at)) {
9009cc24
PP
3043 GString *filter_name = filter_prev->data;
3044 GString *sink_name = sink_at->data;
3045
3046 ret = append_connect_arg(run_args, filter_name->str,
3047 sink_name->str);
3048 if (ret) {
3049 goto error;
3050 }
3051 }
3052
3053 goto end;
3054
3055error:
3056 ret = -1;
3057
3058end:
3059 return ret;
3060}
3061
3062static
3063int split_timerange(const char *arg, char **begin, char **end)
3064{
3065 int ret = 0;
3066 const char *ch = arg;
3067 size_t end_pos;
3068 GString *g_begin = NULL;
3069 GString *g_end = NULL;
3070
f6ccaed9 3071 BT_ASSERT(arg);
9009cc24
PP
3072
3073 if (*ch == '[') {
3074 ch++;
3075 }
3076
3077 g_begin = bt_common_string_until(ch, "", ",", &end_pos);
3078 if (!g_begin || ch[end_pos] != ',' || g_begin->len == 0) {
3079 goto error;
3080 }
3081
3082 ch += end_pos + 1;
3083
3084 g_end = bt_common_string_until(ch, "", "]", &end_pos);
3085 if (!g_end || g_end->len == 0) {
3086 goto error;
3087 }
3088
f6ccaed9
PP
3089 BT_ASSERT(begin);
3090 BT_ASSERT(end);
9009cc24
PP
3091 *begin = g_begin->str;
3092 *end = g_end->str;
3093 g_string_free(g_begin, FALSE);
3094 g_string_free(g_end, FALSE);
3095 g_begin = NULL;
3096 g_end = NULL;
3097 goto end;
3098
3099error:
3100 ret = -1;
3101
3102end:
3103 if (g_begin) {
3104 g_string_free(g_begin, TRUE);
3105 }
3106
3107 if (g_end) {
3108 g_string_free(g_end, TRUE);
3109 }
3110
3111 return ret;
3112}
3113
3114static
3115int g_list_prepend_gstring(GList **list, const char *string)
3116{
3117 int ret = 0;
3118 GString *gs = g_string_new(string);
3119
f6ccaed9 3120 BT_ASSERT(list);
9009cc24
PP
3121
3122 if (!gs) {
9f901451 3123 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3124 goto end;
3125 }
3126
3127 *list = g_list_prepend(*list, gs);
3128
3129end:
3130 return ret;
3131}
3132
73760435 3133/*
24594611
PP
3134 * Create `struct implicit_component_args` structures for each of the
3135 * source components we identified. Add them to `component_args`.
1ead9076 3136 *
005d49d6
SM
3137 * `non_opts` is an array of the non-option arguments passed on the command
3138 * line.
3139 *
24594611
PP
3140 * `non_opt_params` is an array where each element is an array of
3141 * strings containing all the arguments to `--params` that apply to the
3142 * non-option argument at the same index. For example, if, for a
3143 * non-option argument, the following `--params` options applied:
1ead9076
SM
3144 *
3145 * --params=a=2 --params=b=3,c=4
3146 *
24594611 3147 * its entry in `non_opt_params` would contain
1ead9076
SM
3148 *
3149 * ["a=2", "b=3,c=4"]
73760435
SM
3150 */
3151
3152static
1ead9076
SM
3153int create_implicit_component_args_from_auto_discovered_sources(
3154 const struct auto_source_discovery *auto_disc,
005d49d6 3155 const bt_value *non_opts,
24594611
PP
3156 const bt_value *non_opt_params,
3157 const bt_value *non_opt_loglevels,
1ead9076 3158 GPtrArray *component_args)
73760435
SM
3159{
3160 gchar *cc_name = NULL;
3161 struct implicit_component_args *comp = NULL;
3162 int status;
3163 guint i, len;
3164
3165 len = auto_disc->results->len;
3166
3167 for (i = 0; i < len; i++) {
3168 struct auto_source_discovery_result *res =
3169 g_ptr_array_index(auto_disc->results, i);
1ead9076 3170 uint64_t orig_indices_i, orig_indices_count;
73760435
SM
3171
3172 g_free(cc_name);
3173 cc_name = g_strdup_printf("source.%s.%s", res->plugin_name, res->source_cc_name);
3174 if (!cc_name) {
3175 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1ead9076 3176 goto error;
73760435
SM
3177 }
3178
3179 comp = create_implicit_component_args(cc_name);
3180 if (!comp) {
1ead9076
SM
3181 goto error;
3182 }
3183
3184 /*
24594611
PP
3185 * Append parameters and log levels of all the
3186 * non-option arguments that contributed to this
3187 * component instance coming into existence.
1ead9076 3188 */
393729a6 3189 orig_indices_count = bt_value_array_get_length(res->original_input_indices);
1ead9076
SM
3190 for (orig_indices_i = 0; orig_indices_i < orig_indices_count; orig_indices_i++) {
3191 const bt_value *orig_idx_value =
3192 bt_value_array_borrow_element_by_index(
3193 res->original_input_indices, orig_indices_i);
3194 uint64_t orig_idx = bt_value_integer_unsigned_get(orig_idx_value);
3195 const bt_value *params_array =
3196 bt_value_array_borrow_element_by_index_const(
24594611 3197 non_opt_params, orig_idx);
1ead9076 3198 uint64_t params_i, params_count;
1b2b6649 3199 const bt_value *loglevel_value;
1ead9076 3200
393729a6 3201 params_count = bt_value_array_get_length(params_array);
1ead9076
SM
3202 for (params_i = 0; params_i < params_count; params_i++) {
3203 const bt_value *params_value =
3204 bt_value_array_borrow_element_by_index_const(
3205 params_array, params_i);
3206 const char *params = bt_value_string_get(params_value);
3207 bt_value_array_append_element_status append_status;
3208
3209 append_status = bt_value_array_append_string_element(
3210 comp->extra_params, "--params");
3211 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3212 BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
3213 goto error;
3214 }
3215
3216 append_status = bt_value_array_append_string_element(
3217 comp->extra_params, params);
3218 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3219 BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
3220 goto error;
3221 }
3222 }
1b2b6649
SM
3223
3224 loglevel_value = bt_value_array_borrow_element_by_index_const(
24594611 3225 non_opt_loglevels, orig_idx);
1b2b6649
SM
3226 if (bt_value_get_type(loglevel_value) == BT_VALUE_TYPE_STRING) {
3227 const char *loglevel = bt_value_string_get(loglevel_value);
3228 bt_value_array_append_element_status append_status;
3229
3230 append_status = bt_value_array_append_string_element(
3231 comp->extra_params, "--log-level");
3232 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3233 BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
3234 goto error;
3235 }
3236
3237 append_status = bt_value_array_append_string_element(
3238 comp->extra_params, loglevel);
3239 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3240 BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
3241 goto error;
3242 }
3243 }
73760435
SM
3244 }
3245
005d49d6
SM
3246 /*
3247 * If single input and a src.ctf.fs component, provide the
3248 * relative path from the path passed on the command line to the
3249 * found trace.
3250 */
3251 if (bt_value_array_get_length(res->inputs) == 1 &&
3252 strcmp(res->plugin_name, "ctf") == 0 &&
3253 strcmp(res->source_cc_name, "fs") == 0) {
3254 const bt_value *orig_idx_value =
3255 bt_value_array_borrow_element_by_index(
3256 res->original_input_indices, 0);
3257 uint64_t orig_idx = bt_value_integer_unsigned_get(orig_idx_value);
3258 const bt_value *non_opt_value =
3259 bt_value_array_borrow_element_by_index_const(
3260 non_opts, orig_idx);
3261 const char *non_opt = bt_value_string_get(non_opt_value);
3262 const bt_value *input_value =
3263 bt_value_array_borrow_element_by_index_const(
3264 res->inputs, 0);
3265 const char *input = bt_value_string_get(input_value);
3266
3267 BT_ASSERT(orig_indices_count == 1);
3268 BT_ASSERT(g_str_has_prefix(input, non_opt));
3269
3270 input += strlen(non_opt);
3271
3272 while (G_IS_DIR_SEPARATOR(*input)) {
3273 input++;
3274 }
3275
3276 if (strlen(input) > 0) {
3277 append_string_parameter_to_args(comp->extra_params,
3278 "trace-name", input);
3279 }
3280 }
3281
73760435
SM
3282 status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs);
3283 if (status != 0) {
1ead9076 3284 goto error;
73760435
SM
3285 }
3286
3287 g_ptr_array_add(component_args, comp);
3288 comp = NULL;
3289 }
3290
1ead9076
SM
3291 status = 0;
3292 goto end;
3293
3294error:
3295 status = -1;
3296
73760435
SM
3297end:
3298 g_free(cc_name);
3299
3300 if (comp) {
3301 destroy_implicit_component_args(comp);
3302 }
1ead9076
SM
3303
3304 return status;
73760435
SM
3305}
3306
505d9178
SM
3307/*
3308 * As we iterate the arguments to the convert command, this tracks what is the
3309 * type of the current item, to which some contextual options (e.g. --params)
3310 * apply to.
3311 */
3312enum convert_current_item_type {
3313 /* There is no current item. */
3314 CONVERT_CURRENT_ITEM_TYPE_NONE,
3315
3316 /* Current item is a component. */
3317 CONVERT_CURRENT_ITEM_TYPE_COMPONENT,
8b4cd08a 3318
24594611
PP
3319 /* Current item is a non-option argument. */
3320 CONVERT_CURRENT_ITEM_TYPE_NON_OPT,
505d9178
SM
3321};
3322
9009cc24
PP
3323/*
3324 * Creates a Babeltrace config object from the arguments of a convert
3325 * command.
9009cc24
PP
3326 */
3327static
353c2524
SM
3328enum bt_config_cli_args_status bt_config_convert_from_args(int argc,
3329 const char *argv[], struct bt_config **cfg_out,
3330 const bt_value *plugin_paths,
a80892ba
SM
3331 int *default_log_level, const bt_interrupter *interrupter,
3332 unsigned int consumed_args)
9009cc24 3333{
353c2524 3334 enum bt_config_cli_args_status status;
505d9178
SM
3335 enum convert_current_item_type current_item_type =
3336 CONVERT_CURRENT_ITEM_TYPE_NONE;
353c2524 3337 int ret;
9009cc24 3338 struct bt_config *cfg = NULL;
9009cc24
PP
3339 bool got_input_format_opt = false;
3340 bool got_output_format_opt = false;
3341 bool trimmer_has_begin = false;
3342 bool trimmer_has_end = false;
75a2cb9b 3343 bool stream_intersection_mode = false;
9009cc24
PP
3344 bool print_run_args = false;
3345 bool print_run_args_0 = false;
3346 bool print_ctf_metadata = false;
b19ff26f
PP
3347 bt_value *run_args = NULL;
3348 bt_value *all_names = NULL;
9009cc24
PP
3349 GList *source_names = NULL;
3350 GList *filter_names = NULL;
3351 GList *sink_names = NULL;
24594611
PP
3352 bt_value *non_opts = NULL;
3353 bt_value *non_opt_params = NULL;
3354 bt_value *non_opt_loglevels = NULL;
e7ad156c 3355 struct implicit_component_args implicit_ctf_output_args = { 0 };
9009cc24
PP
3356 struct implicit_component_args implicit_lttng_live_args = { 0 };
3357 struct implicit_component_args implicit_dummy_args = { 0 };
3358 struct implicit_component_args implicit_text_args = { 0 };
3359 struct implicit_component_args implicit_debug_info_args = { 0 };
3360 struct implicit_component_args implicit_muxer_args = { 0 };
3361 struct implicit_component_args implicit_trimmer_args = { 0 };
9009cc24
PP
3362 char error_buf[256] = { 0 };
3363 size_t i;
3364 struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
e7ad156c 3365 char *output = NULL;
73760435
SM
3366 struct auto_source_discovery auto_disc = { NULL };
3367 GString *auto_disc_comp_name = NULL;
a93e984c
SM
3368 struct argpar_iter *argpar_iter = NULL;
3369 const struct argpar_item *argpar_item = NULL;
505d9178
SM
3370 GString *name_gstr = NULL;
3371 GString *component_arg_for_run = NULL;
c57d9a63 3372 bt_value *live_inputs_array_val = NULL;
73760435
SM
3373
3374 /*
3375 * Array of `struct implicit_component_args *` created for the sources
3376 * we have auto-discovered.
3377 */
3378 GPtrArray *discovered_source_args = NULL;
3379
3380 /*
3381 * If set, restrict automatic source discovery to this component class
3382 * of this plugin.
3383 */
3384 const char *auto_source_discovery_restrict_plugin_name = NULL;
3385 const char *auto_source_discovery_restrict_component_class_name = NULL;
3386
9412c556 3387 bool ctf_fs_source_force_clock_class_unix_epoch_origin = false;
73760435
SM
3388 gchar *ctf_fs_source_clock_class_offset_arg = NULL;
3389 gchar *ctf_fs_source_clock_class_offset_ns_arg = NULL;
9009cc24 3390
0e497e1c 3391 if (argc < 1) {
9009cc24 3392 print_convert_usage(stdout);
353c2524 3393 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
9009cc24
PP
3394 goto end;
3395 }
3396
e7ad156c
PP
3397 if (init_implicit_component_args(&implicit_ctf_output_args,
3398 "sink.ctf.fs", false)) {
3399 goto error;
3400 }
3401
9009cc24 3402 if (init_implicit_component_args(&implicit_lttng_live_args,
fd5f8053 3403 "source.ctf.lttng-live", false)) {
9009cc24
PP
3404 goto error;
3405 }
3406
fd5f8053
PP
3407 if (init_implicit_component_args(&implicit_text_args,
3408 "sink.text.pretty", false)) {
9009cc24
PP
3409 goto error;
3410 }
3411
fd5f8053
PP
3412 if (init_implicit_component_args(&implicit_dummy_args,
3413 "sink.utils.dummy", false)) {
9009cc24
PP
3414 goto error;
3415 }
3416
3417 if (init_implicit_component_args(&implicit_debug_info_args,
9a16feea 3418 "filter.lttng-utils.debug-info", false)) {
9009cc24
PP
3419 goto error;
3420 }
3421
fd5f8053
PP
3422 if (init_implicit_component_args(&implicit_muxer_args,
3423 "filter.utils.muxer", true)) {
9009cc24
PP
3424 goto error;
3425 }
3426
3427 if (init_implicit_component_args(&implicit_trimmer_args,
fd5f8053 3428 "filter.utils.trimmer", false)) {
9009cc24
PP
3429 goto error;
3430 }
3431
05e21286 3432 all_names = bt_value_map_create();
9009cc24 3433 if (!all_names) {
9f901451 3434 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3435 goto error;
3436 }
3437
05e21286 3438 run_args = bt_value_array_create();
9009cc24 3439 if (!run_args) {
9f901451 3440 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3441 goto error;
3442 }
3443
505d9178
SM
3444 component_arg_for_run = g_string_new(NULL);
3445 if (!component_arg_for_run) {
9f901451 3446 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3447 goto error;
3448 }
3449
24594611
PP
3450 non_opts = bt_value_array_create();
3451 if (!non_opts) {
9f901451 3452 BT_CLI_LOGE_APPEND_CAUSE_OOM();
f280892e
SM
3453 goto error;
3454 }
3455
24594611
PP
3456 non_opt_params = bt_value_array_create();
3457 if (!non_opt_params) {
1ead9076
SM
3458 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3459 goto error;
3460 }
3461
24594611
PP
3462 non_opt_loglevels = bt_value_array_create();
3463 if (!non_opt_loglevels) {
1b2b6649
SM
3464 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3465 goto error;
3466 }
3467
73760435
SM
3468 if (auto_source_discovery_init(&auto_disc) != 0) {
3469 goto error;
3470 }
3471
3472 discovered_source_args =
3473 g_ptr_array_new_with_free_func((GDestroyNotify) destroy_implicit_component_args);
3474 if (!discovered_source_args) {
3475 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3476 goto error;
3477 }
3478
3479 auto_disc_comp_name = g_string_new(NULL);
3480 if (!auto_disc_comp_name) {
3481 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3482 goto error;
3483 }
3484
9009cc24
PP
3485 /*
3486 * First pass: collect all arguments which need to be passed
3487 * as is to the run command. This pass can also add --name
3488 * arguments if needed to automatically name unnamed component
453b777b 3489 * instances.
9009cc24 3490 */
a93e984c
SM
3491 argpar_iter = argpar_iter_create(argc, argv, convert_options);
3492 if (!argpar_iter) {
3493 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3494 goto error;
3495 }
3496
a93e984c 3497 while (true) {
353c2524 3498 enum parse_next_item_status parse_status;
9009cc24
PP
3499 char *name = NULL;
3500 char *plugin_name = NULL;
3501 char *comp_cls_name = NULL;
3502
353c2524 3503 parse_status = parse_next_item(argpar_iter, &argpar_item, argv, "convert",
a80892ba 3504 consumed_args);
353c2524 3505 if (parse_status == PARSE_NEXT_ITEM_STATUS_ERROR) {
a93e984c 3506 goto error;
353c2524 3507 } else if (parse_status == PARSE_NEXT_ITEM_STATUS_END) {
a93e984c
SM
3508 break;
3509 }
3510
3511 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
3512 const struct argpar_opt_descr *opt_descr =
3513 argpar_item_opt_descr(argpar_item);
3514 const char *arg = argpar_item_opt_arg(argpar_item);
fd5f8053 3515
a93e984c
SM
3516 switch (opt_descr->id) {
3517 case OPT_HELP:
3518 print_convert_usage(stdout);
353c2524 3519 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c 3520 goto end;
8b4cd08a
SM
3521 case OPT_COMPONENT:
3522 {
3523 bt_component_class_type type;
9009cc24 3524
8b4cd08a 3525 current_item_type = CONVERT_CURRENT_ITEM_TYPE_COMPONENT;
9009cc24 3526
8b4cd08a
SM
3527 /* Parse the argument */
3528 plugin_comp_cls_names(arg, &name, &plugin_name,
3529 &comp_cls_name, &type);
3530 if (!plugin_name || !comp_cls_name) {
505d9178 3531 BT_CLI_LOGE_APPEND_CAUSE(
8b4cd08a
SM
3532 "Invalid format for --component option's argument:\n %s",
3533 arg);
505d9178
SM
3534 goto error;
3535 }
3536
8b4cd08a
SM
3537 if (name) {
3538 /*
3539 * Name was given by the user, verify it isn't
3540 * taken.
3541 */
3542 if (bt_value_map_has_entry(all_names, name)) {
3543 BT_CLI_LOGE_APPEND_CAUSE(
3544 "Duplicate component instance name:\n %s",
3545 name);
3546 goto error;
3547 }
3548
3549 name_gstr = g_string_new(name);
3550 if (!name_gstr) {
3551 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3552 goto error;
3553 }
3554
3555 g_string_assign(component_arg_for_run, arg);
3556 } else {
3557 /* Name not given by user, generate one. */
3558 name_gstr = get_component_auto_name(arg, all_names);
3559 if (!name_gstr) {
3560 goto error;
3561 }
3562
3563 g_string_printf(component_arg_for_run, "%s:%s",
3564 name_gstr->str, arg);
3565 }
3566
3567 if (bt_value_array_append_string_element(run_args,
3568 "--component")) {
505d9178
SM
3569 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3570 goto error;
3571 }
3572
8b4cd08a
SM
3573 if (bt_value_array_append_string_element(run_args,
3574 component_arg_for_run->str)) {
3575 BT_CLI_LOGE_APPEND_CAUSE_OOM();
505d9178
SM
3576 goto error;
3577 }
9009cc24 3578
8b4cd08a
SM
3579 /*
3580 * Remember this name globally, for the uniqueness of
3581 * all component names.
3582 */
3583 if (bt_value_map_insert_entry(all_names,
3584 name_gstr->str, bt_value_null)) {
3585 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3586 goto error;
3587 }
fd5f8053 3588
8b4cd08a
SM
3589 /*
3590 * Remember this name specifically for the type of the
3591 * component. This is to create connection arguments.
3592 *
3593 * The list takes ownership of `name_gstr`.
3594 */
3595 switch (type) {
3596 case BT_COMPONENT_CLASS_TYPE_SOURCE:
3597 source_names = g_list_append(source_names, name_gstr);
3598 break;
3599 case BT_COMPONENT_CLASS_TYPE_FILTER:
3600 filter_names = g_list_append(filter_names, name_gstr);
3601 break;
3602 case BT_COMPONENT_CLASS_TYPE_SINK:
3603 sink_names = g_list_append(sink_names, name_gstr);
3604 break;
3605 default:
498e7994 3606 bt_common_abort();
8b4cd08a
SM
3607 }
3608 name_gstr = NULL;
3609
3610 free(name);
3611 free(plugin_name);
3612 free(comp_cls_name);
3613 name = NULL;
3614 plugin_name = NULL;
3615 comp_cls_name = NULL;
3616 break;
505d9178 3617 }
8b4cd08a 3618 case OPT_PARAMS:
1ead9076
SM
3619 if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
3620 /*
3621 * The current item is a component (--component option),
3622 * pass it directly to the run args.
3623 */
3624 if (bt_value_array_append_string_element(run_args,
3625 "--params")) {
3626 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3627 goto error;
3628 }
505d9178 3629
1ead9076
SM
3630 if (bt_value_array_append_string_element(run_args, arg)) {
3631 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3632 goto error;
3633 }
24594611
PP
3634 } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_NON_OPT) {
3635 /*
3636 * The current item is a
3637 * non-option argument, record
3638 * it in `non_opt_params`.
3639 */
1ead9076 3640 bt_value *array;
1db12e0d 3641 bt_value_array_append_element_status append_element_status;
393729a6 3642 uint64_t idx = bt_value_array_get_length(non_opt_params) - 1;
9009cc24 3643
24594611 3644 array = bt_value_array_borrow_element_by_index(non_opt_params, idx);
1db12e0d
SM
3645
3646 append_element_status = bt_value_array_append_string_element(array, arg);
3647 if (append_element_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3648 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3649 goto error;
3650 }
1ead9076
SM
3651 } else {
3652 BT_CLI_LOGE_APPEND_CAUSE(
3653 "No current component (--component option) or non-option argument of which to set parameters:\n %s",
3654 arg);
8b4cd08a
SM
3655 goto error;
3656 }
505d9178 3657 break;
8b4cd08a 3658 case OPT_LOG_LEVEL:
1b2b6649
SM
3659 if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
3660 if (bt_value_array_append_string_element(run_args, "--log-level")) {
3661 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3662 goto error;
3663 }
9009cc24 3664
1b2b6649
SM
3665 if (bt_value_array_append_string_element(run_args, arg)) {
3666 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3667 goto error;
3668 }
24594611 3669 } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_NON_OPT) {
393729a6 3670 uint64_t idx = bt_value_array_get_length(non_opt_loglevels) - 1;
618e62e0 3671 enum bt_value_array_set_element_by_index_status set_element_status;
1b2b6649 3672 bt_value *log_level_str_value;
9009cc24 3673
1b2b6649
SM
3674 log_level_str_value = bt_value_string_create_init(arg);
3675 if (!log_level_str_value) {
3676 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3677 goto error;
3678 }
3679
618e62e0
SM
3680 set_element_status =
3681 bt_value_array_set_element_by_index(non_opt_loglevels,
3682 idx, log_level_str_value);
3683 bt_value_put_ref(log_level_str_value);
3684 if (set_element_status != BT_VALUE_ARRAY_SET_ELEMENT_BY_INDEX_STATUS_OK) {
1b2b6649
SM
3685 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3686 goto error;
3687 }
3688 } else {
3689 BT_CLI_LOGE_APPEND_CAUSE(
3690 "No current component (--component option) or non-option argument to assign a log level to:\n %s",
3691 arg);
8b4cd08a
SM
3692 goto error;
3693 }
29da2ffc 3694
8b4cd08a
SM
3695 break;
3696 case OPT_RETRY_DURATION:
3697 if (bt_value_array_append_string_element(run_args,
3698 "--retry-duration")) {
3699 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3700 goto error;
3701 }
29da2ffc 3702
8b4cd08a
SM
3703 if (bt_value_array_append_string_element(run_args, arg)) {
3704 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3705 goto error;
3706 }
3707 break;
3708 case OPT_BEGIN:
3709 case OPT_CLOCK_CYCLES:
3710 case OPT_CLOCK_DATE:
3711 case OPT_CLOCK_FORCE_CORRELATE:
3712 case OPT_CLOCK_GMT:
3713 case OPT_CLOCK_OFFSET:
3714 case OPT_CLOCK_OFFSET_NS:
3715 case OPT_CLOCK_SECONDS:
3716 case OPT_COLOR:
3717 case OPT_DEBUG:
3718 case OPT_DEBUG_INFO:
3719 case OPT_DEBUG_INFO_DIR:
3720 case OPT_DEBUG_INFO_FULL_PATH:
3721 case OPT_DEBUG_INFO_TARGET_PREFIX:
3722 case OPT_END:
3723 case OPT_FIELDS:
3724 case OPT_INPUT_FORMAT:
3725 case OPT_NAMES:
3726 case OPT_NO_DELTA:
3727 case OPT_OUTPUT_FORMAT:
3728 case OPT_OUTPUT:
3729 case OPT_RUN_ARGS:
3730 case OPT_RUN_ARGS_0:
3731 case OPT_STREAM_INTERSECTION:
3732 case OPT_TIMERANGE:
3733 case OPT_VERBOSE:
3734 /* Ignore in this pass */
3735 break;
3736 default:
a93e984c 3737 bt_common_abort();
9009cc24 3738 }
a93e984c
SM
3739 } else {
3740 const char *arg = argpar_item_non_opt_arg(argpar_item);
8b4cd08a 3741 bt_value_array_append_element_status append_status;
9009cc24 3742
24594611 3743 current_item_type = CONVERT_CURRENT_ITEM_TYPE_NON_OPT;
9009cc24 3744
a93e984c 3745 append_status = bt_value_array_append_string_element(non_opts, arg);
8b4cd08a 3746 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
9f901451 3747 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3748 goto error;
3749 }
1ead9076 3750
847ab606
PP
3751 append_status = bt_value_array_append_empty_array_element(
3752 non_opt_params, NULL);
1ead9076
SM
3753 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3754 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3755 goto error;
3756 }
1b2b6649 3757
24594611 3758 append_status = bt_value_array_append_element(non_opt_loglevels, bt_value_null);
1b2b6649
SM
3759 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3760 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3761 goto error;
3762 }
9009cc24 3763 }
9009cc24
PP
3764 }
3765
9009cc24
PP
3766 /*
3767 * Second pass: transform the convert-specific options and
3768 * arguments into implicit component instances for the run
3769 * command.
3770 */
a93e984c
SM
3771 argpar_iter_destroy(argpar_iter);
3772 argpar_iter = argpar_iter_create(argc, argv, convert_options);
3773 if (!argpar_iter) {
3774 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3775 goto error;
3776 }
3777
3778 while (true) {
353c2524 3779 enum parse_next_item_status parse_status;
a93e984c 3780 const struct argpar_opt_descr *opt_descr;
ca60bbc3 3781 const char *arg;
9009cc24 3782
353c2524 3783 parse_status = parse_next_item(argpar_iter, &argpar_item, argv, "convert",
a80892ba 3784 consumed_args);
353c2524 3785 if (parse_status == PARSE_NEXT_ITEM_STATUS_ERROR) {
a93e984c 3786 goto error;
353c2524 3787 } else if (parse_status == PARSE_NEXT_ITEM_STATUS_END) {
a93e984c
SM
3788 break;
3789 }
3790
3791 if (argpar_item_type(argpar_item) != ARGPAR_ITEM_TYPE_OPT) {
ca60bbc3
SM
3792 continue;
3793 }
9009cc24 3794
a93e984c
SM
3795 opt_descr = argpar_item_opt_descr(argpar_item);
3796 arg = argpar_item_opt_arg(argpar_item);
9009cc24 3797
a93e984c 3798 switch (opt_descr->id) {
9009cc24
PP
3799 case OPT_BEGIN:
3800 if (trimmer_has_begin) {
5d4818b1 3801 BT_CLI_LOGE_APPEND_CAUSE("At --begin option: --begin or --timerange option already specified\n %s\n",
9009cc24
PP
3802 arg);
3803 goto error;
3804 }
3805
3806 trimmer_has_begin = true;
e7ad156c 3807 ret = append_implicit_component_extra_param(
9009cc24
PP
3808 &implicit_trimmer_args, "begin", arg);
3809 implicit_trimmer_args.exists = true;
3810 if (ret) {
3811 goto error;
3812 }
3813 break;
3814 case OPT_END:
3815 if (trimmer_has_end) {
5d4818b1 3816 BT_CLI_LOGE_APPEND_CAUSE("At --end option: --end or --timerange option already specified\n %s\n",
9009cc24
PP
3817 arg);
3818 goto error;
3819 }
3820
3821 trimmer_has_end = true;
e7ad156c 3822 ret = append_implicit_component_extra_param(
9009cc24
PP
3823 &implicit_trimmer_args, "end", arg);
3824 implicit_trimmer_args.exists = true;
3825 if (ret) {
3826 goto error;
3827 }
3828 break;
3829 case OPT_TIMERANGE:
3830 {
3831 char *begin;
3832 char *end;
3833
3834 if (trimmer_has_begin || trimmer_has_end) {
5d4818b1 3835 BT_CLI_LOGE_APPEND_CAUSE("At --timerange option: --begin, --end, or --timerange option already specified\n %s\n",
9009cc24
PP
3836 arg);
3837 goto error;
3838 }
3839
3840 ret = split_timerange(arg, &begin, &end);
3841 if (ret) {
9f901451 3842 BT_CLI_LOGE_APPEND_CAUSE("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n %s",
9009cc24
PP
3843 arg);
3844 goto error;
3845 }
3846
e7ad156c 3847 ret = append_implicit_component_extra_param(
9009cc24 3848 &implicit_trimmer_args, "begin", begin);
e7ad156c 3849 ret |= append_implicit_component_extra_param(
9009cc24
PP
3850 &implicit_trimmer_args, "end", end);
3851 implicit_trimmer_args.exists = true;
3852 free(begin);
3853 free(end);
3854 if (ret) {
3855 goto error;
3856 }
3857 break;
3858 }
3859 case OPT_CLOCK_CYCLES:
3860 append_implicit_component_param(
3861 &implicit_text_args, "clock-cycles", "yes");
3862 implicit_text_args.exists = true;
3863 break;
3864 case OPT_CLOCK_DATE:
3865 append_implicit_component_param(
3866 &implicit_text_args, "clock-date", "yes");
3867 implicit_text_args.exists = true;
3868 break;
3869 case OPT_CLOCK_FORCE_CORRELATE:
9412c556 3870 ctf_fs_source_force_clock_class_unix_epoch_origin = true;
9009cc24
PP
3871 break;
3872 case OPT_CLOCK_GMT:
3873 append_implicit_component_param(
3874 &implicit_text_args, "clock-gmt", "yes");
eb01fbce 3875 append_implicit_component_param(
f855116d 3876 &implicit_trimmer_args, "gmt", "yes");
9009cc24
PP
3877 implicit_text_args.exists = true;
3878 break;
3879 case OPT_CLOCK_OFFSET:
73760435
SM
3880 if (ctf_fs_source_clock_class_offset_arg) {
3881 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset option\n");
3882 goto error;
3883 }
3884
3885 ctf_fs_source_clock_class_offset_arg = g_strdup(arg);
3886 if (!ctf_fs_source_clock_class_offset_arg) {
3887 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3888 goto error;
3889 }
9009cc24
PP
3890 break;
3891 case OPT_CLOCK_OFFSET_NS:
73760435
SM
3892 if (ctf_fs_source_clock_class_offset_ns_arg) {
3893 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset-ns option\n");
3894 goto error;
3895 }
3896
3897 ctf_fs_source_clock_class_offset_ns_arg = g_strdup(arg);
3898 if (!ctf_fs_source_clock_class_offset_ns_arg) {
3899 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3900 goto error;
3901 }
9009cc24
PP
3902 break;
3903 case OPT_CLOCK_SECONDS:
3904 append_implicit_component_param(
3905 &implicit_text_args, "clock-seconds", "yes");
3906 implicit_text_args.exists = true;
3907 break;
3908 case OPT_COLOR:
9009cc24 3909 implicit_text_args.exists = true;
e7ad156c
PP
3910 ret = append_implicit_component_extra_param(
3911 &implicit_text_args, "color", arg);
9009cc24
PP
3912 if (ret) {
3913 goto error;
3914 }
3915 break;
9a16feea
PP
3916 case OPT_DEBUG_INFO:
3917 implicit_debug_info_args.exists = true;
9009cc24
PP
3918 break;
3919 case OPT_DEBUG_INFO_DIR:
e7ad156c
PP
3920 implicit_debug_info_args.exists = true;
3921 ret = append_implicit_component_extra_param(
4cd687b9 3922 &implicit_debug_info_args, "debug-info-dir", arg);
9009cc24
PP
3923 if (ret) {
3924 goto error;
3925 }
3926 break;
3927 case OPT_DEBUG_INFO_FULL_PATH:
e7ad156c 3928 implicit_debug_info_args.exists = true;
9009cc24
PP
3929 append_implicit_component_param(
3930 &implicit_debug_info_args, "full-path", "yes");
3931 break;
3932 case OPT_DEBUG_INFO_TARGET_PREFIX:
e7ad156c
PP
3933 implicit_debug_info_args.exists = true;
3934 ret = append_implicit_component_extra_param(
9009cc24
PP
3935 &implicit_debug_info_args,
3936 "target-prefix", arg);
3937 if (ret) {
3938 goto error;
3939 }
3940 break;
3941 case OPT_FIELDS:
3942 {
b19ff26f 3943 bt_value *fields = fields_from_arg(arg);
9009cc24
PP
3944
3945 if (!fields) {
3946 goto error;
3947 }
3948
e7ad156c 3949 implicit_text_args.exists = true;
9009cc24
PP
3950 ret = insert_flat_params_from_array(
3951 implicit_text_args.params_arg,
05e21286 3952 fields, "field");
c5b9b441 3953 bt_value_put_ref(fields);
9009cc24
PP
3954 if (ret) {
3955 goto error;
3956 }
3957 break;
3958 }
3959 case OPT_NAMES:
3960 {
b19ff26f 3961 bt_value *names = names_from_arg(arg);
9009cc24
PP
3962
3963 if (!names) {
3964 goto error;
3965 }
3966
e7ad156c 3967 implicit_text_args.exists = true;
9009cc24
PP
3968 ret = insert_flat_params_from_array(
3969 implicit_text_args.params_arg,
05e21286 3970 names, "name");
c5b9b441 3971 bt_value_put_ref(names);
9009cc24
PP
3972 if (ret) {
3973 goto error;
3974 }
3975 break;
3976 }
3977 case OPT_NO_DELTA:
3978 append_implicit_component_param(
3979 &implicit_text_args, "no-delta", "yes");
3980 implicit_text_args.exists = true;
3981 break;
3982 case OPT_INPUT_FORMAT:
3983 if (got_input_format_opt) {
9f901451 3984 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --input-format option.");
9009cc24
PP
3985 goto error;
3986 }
3987
3988 got_input_format_opt = true;
3989
3990 if (strcmp(arg, "ctf") == 0) {
73760435
SM
3991 auto_source_discovery_restrict_plugin_name = "ctf";
3992 auto_source_discovery_restrict_component_class_name = "fs";
9009cc24 3993 } else if (strcmp(arg, "lttng-live") == 0) {
73760435
SM
3994 auto_source_discovery_restrict_plugin_name = "ctf";
3995 auto_source_discovery_restrict_component_class_name = "lttng-live";
9009cc24
PP
3996 implicit_lttng_live_args.exists = true;
3997 } else {
9f901451 3998 BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy input format:\n %s",
9009cc24
PP
3999 arg);
4000 goto error;
4001 }
4002 break;
4003 case OPT_OUTPUT_FORMAT:
4004 if (got_output_format_opt) {
9f901451 4005 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output-format option.");
9009cc24
PP
4006 goto error;
4007 }
4008
4009 got_output_format_opt = true;
4010
4011 if (strcmp(arg, "text") == 0) {
4012 implicit_text_args.exists = true;
e7ad156c
PP
4013 } else if (strcmp(arg, "ctf") == 0) {
4014 implicit_ctf_output_args.exists = true;
9009cc24
PP
4015 } else if (strcmp(arg, "dummy") == 0) {
4016 implicit_dummy_args.exists = true;
4017 } else if (strcmp(arg, "ctf-metadata") == 0) {
4018 print_ctf_metadata = true;
4019 } else {
9f901451 4020 BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy output format:\n %s",
9009cc24
PP
4021 arg);
4022 goto error;
4023 }
4024 break;
4025 case OPT_OUTPUT:
e7ad156c 4026 if (output) {
9f901451 4027 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output option");
e7ad156c
PP
4028 goto error;
4029 }
4030
4031 output = strdup(arg);
4032 if (!output) {
9f901451 4033 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
4034 goto error;
4035 }
4036 break;
4037 case OPT_RUN_ARGS:
4038 if (print_run_args_0) {
9f901451 4039 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
9009cc24
PP
4040 goto error;
4041 }
4042
4043 print_run_args = true;
4044 break;
4045 case OPT_RUN_ARGS_0:
4046 if (print_run_args) {
9f901451 4047 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
9009cc24
PP
4048 goto error;
4049 }
4050
4051 print_run_args_0 = true;
4052 break;
4053 case OPT_STREAM_INTERSECTION:
75a2cb9b 4054 /*
1a29b831 4055 * Applies to all traces implementing the
5f2a1585 4056 * babeltrace.trace-infos query.
75a2cb9b
JG
4057 */
4058 stream_intersection_mode = true;
9009cc24
PP
4059 break;
4060 case OPT_VERBOSE:
ebddaeb8
SM
4061 *default_log_level =
4062 logging_level_min(*default_log_level, BT_LOG_INFO);
9009cc24
PP
4063 break;
4064 case OPT_DEBUG:
ebddaeb8
SM
4065 *default_log_level =
4066 logging_level_min(*default_log_level, BT_LOG_TRACE);
29da2ffc 4067 break;
a93e984c
SM
4068 case OPT_COMPONENT:
4069 case OPT_HELP:
4070 case OPT_LOG_LEVEL:
4071 case OPT_OMIT_HOME_PLUGIN_PATH:
4072 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
4073 case OPT_PARAMS:
4074 case OPT_PLUGIN_PATH:
4075 case OPT_RETRY_DURATION:
4076 /* Ignore in this pass */
9009cc24 4077 break;
a93e984c
SM
4078 default:
4079 bt_common_abort();
9009cc24 4080 }
9009cc24
PP
4081 }
4082
ebddaeb8
SM
4083 set_auto_log_levels(default_log_level);
4084
3efa3052
PP
4085 /*
4086 * Legacy behaviour: --verbose used to make the `text` output
4087 * format print more information. --verbose is now equivalent to
83094759
PP
4088 * the INFO log level, which is why we compare to `BT_LOG_INFO`
4089 * here.
3efa3052 4090 */
29da2ffc 4091 if (*default_log_level == BT_LOG_INFO) {
3efa3052
PP
4092 append_implicit_component_param(&implicit_text_args,
4093 "verbose", "yes");
4094 }
4095
9009cc24
PP
4096 /* Print CTF metadata or print LTTng live sessions */
4097 if (print_ctf_metadata) {
24594611 4098 const bt_value *bt_val_non_opt;
94023a1c 4099
24594611 4100 if (bt_value_array_is_empty(non_opts)) {
9f901451 4101 BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf-metadata specified without a path.");
9009cc24
PP
4102 goto error;
4103 }
4104
393729a6 4105 if (bt_value_array_get_length(non_opts) > 1) {
9f901451 4106 BT_CLI_LOGE_APPEND_CAUSE("Too many paths specified for --output-format=ctf-metadata.");
94023a1c
PP
4107 goto error;
4108 }
4109
353c2524
SM
4110 status = bt_config_print_ctf_metadata_create(plugin_paths, &cfg);
4111 if (status != BT_CONFIG_CLI_ARGS_STATUS_OK) {
4112 goto end;
9009cc24
PP
4113 }
4114
24594611 4115 bt_val_non_opt = bt_value_array_borrow_element_by_index_const(non_opts, 0);
9009cc24 4116 g_string_assign(cfg->cmd_data.print_ctf_metadata.path,
24594611 4117 bt_value_string_get(bt_val_non_opt));
c327e427
PP
4118
4119 if (output) {
4120 g_string_assign(
4121 cfg->cmd_data.print_ctf_metadata.output_path,
4122 output);
4123 }
4124
353c2524 4125 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
9009cc24
PP
4126 goto end;
4127 }
4128
4129 /*
e7ad156c
PP
4130 * If -o ctf was specified, make sure an output path (--output)
4131 * was also specified. --output does not imply -o ctf because
4132 * it's also used for the default, implicit -o text if -o ctf
4133 * is not specified.
4134 */
4135 if (implicit_ctf_output_args.exists) {
4136 if (!output) {
9f901451 4137 BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf specified without --output (trace output path).");
e7ad156c
PP
4138 goto error;
4139 }
4140
4141 /*
4142 * At this point we know that -o ctf AND --output were
4143 * specified. Make sure that no options were specified
4144 * which would imply -o text because --output would be
4145 * ambiguous in this case. For example, this is wrong:
4146 *
ec2c5e50 4147 * babeltrace2 --names=all -o ctf --output=/tmp/path my-trace
e7ad156c
PP
4148 *
4149 * because --names=all implies -o text, and --output
4150 * could apply to both the sink.text.pretty and
4151 * sink.ctf.fs implicit components.
4152 */
4153 if (implicit_text_args.exists) {
9f901451 4154 BT_CLI_LOGE_APPEND_CAUSE("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text.");
e7ad156c
PP
4155 goto error;
4156 }
4157 }
4158
4159 /*
4160 * If -o dummy and -o ctf were not specified, and if there are
4161 * no explicit sink components, then use an implicit
4162 * `sink.text.pretty` component.
9009cc24 4163 */
e7ad156c
PP
4164 if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists &&
4165 !sink_names) {
9009cc24
PP
4166 implicit_text_args.exists = true;
4167 }
4168
e7ad156c
PP
4169 /*
4170 * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's
4171 * `path` parameter if --output was specified.
4172 */
4173 if (output) {
4174 if (implicit_text_args.exists) {
4175 append_implicit_component_extra_param(&implicit_text_args,
4176 "path", output);
4177 } else if (implicit_ctf_output_args.exists) {
4178 append_implicit_component_extra_param(&implicit_ctf_output_args,
4179 "path", output);
4180 }
4181 }
4182
24594611 4183 /* Decide where the non-option argument(s) go */
393729a6 4184 if (bt_value_array_get_length(non_opts) > 0) {
9009cc24 4185 if (implicit_lttng_live_args.exists) {
24594611 4186 const bt_value *bt_val_non_opt;
94023a1c 4187
393729a6 4188 if (bt_value_array_get_length(non_opts) > 1) {
9f901451 4189 BT_CLI_LOGE_APPEND_CAUSE("Too many URLs specified for --input-format=lttng-live.");
94023a1c
PP
4190 goto error;
4191 }
4192
24594611 4193 bt_val_non_opt = bt_value_array_borrow_element_by_index_const(non_opts, 0);
9009cc24 4194 lttng_live_url_parts =
24594611 4195 bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_non_opt),
94b828f3 4196 error_buf, sizeof(error_buf));
9009cc24 4197 if (!lttng_live_url_parts.proto) {
9f901451 4198 BT_CLI_LOGE_APPEND_CAUSE("Invalid LTTng live URL format: %s.",
9009cc24
PP
4199 error_buf);
4200 goto error;
4201 }
4202
4203 if (!lttng_live_url_parts.session_name) {
4204 /* Print LTTng live sessions */
353c2524
SM
4205 status = bt_config_print_lttng_live_sessions_create(
4206 plugin_paths, &cfg);
4207 if (status != BT_CONFIG_CLI_ARGS_STATUS_OK) {
4208 goto end;
9009cc24
PP
4209 }
4210
9009cc24 4211 g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url,
24594611 4212 bt_value_string_get(bt_val_non_opt));
c327e427
PP
4213
4214 if (output) {
4215 g_string_assign(
4216 cfg->cmd_data.print_lttng_live_sessions.output_path,
4217 output);
4218 }
4219
353c2524 4220 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
9009cc24
PP
4221 goto end;
4222 }
4223
c57d9a63
PP
4224 live_inputs_array_val = bt_value_array_create();
4225 if (!live_inputs_array_val) {
4226 BT_CLI_LOGE_APPEND_CAUSE_OOM();
4227 goto error;
4228 }
4229
4230 if (bt_value_array_append_string_element(
4231 live_inputs_array_val,
4232 bt_value_string_get(bt_val_non_opt))) {
4233 BT_CLI_LOGE_APPEND_CAUSE_OOM();
4234 goto error;
4235 }
4236
4237 ret = append_parameter_to_args(
4238 implicit_lttng_live_args.extra_params,
4239 "inputs", live_inputs_array_val);
9009cc24
PP
4240 if (ret) {
4241 goto error;
4242 }
dccb8b6f
FD
4243
4244 ret = append_implicit_component_extra_param(
4245 &implicit_lttng_live_args,
4246 "session-not-found-action", "end");
4247 if (ret) {
4248 goto error;
4249 }
9009cc24 4250 } else {
97010665
SM
4251 size_t plugin_count;
4252 const bt_plugin **plugins;
4253 const bt_plugin *plugin;
353c2524 4254 auto_source_discovery_status auto_disc_status;
73760435 4255
353c2524
SM
4256 ret = require_loaded_plugins(plugin_paths);
4257 if (ret != 0) {
97010665
SM
4258 goto error;
4259 }
4260
4261 if (auto_source_discovery_restrict_plugin_name) {
4262 plugin_count = 1;
97512754 4263 plugin = borrow_loaded_plugin_by_name(auto_source_discovery_restrict_plugin_name);
97010665
SM
4264 plugins = &plugin;
4265 } else {
4266 plugin_count = get_loaded_plugins_count();
4267 plugins = borrow_loaded_plugins();
4268 }
4269
353c2524
SM
4270 auto_disc_status = auto_discover_source_components(
4271 non_opts, plugins, plugin_count,
73760435 4272 auto_source_discovery_restrict_component_class_name,
3dae1685 4273 *default_log_level, &auto_disc, interrupter);
73760435 4274
353c2524
SM
4275 if (auto_disc_status != AUTO_SOURCE_DISCOVERY_STATUS_OK) {
4276 if (auto_disc_status == AUTO_SOURCE_DISCOVERY_STATUS_INTERRUPTED) {
3dae1685
SM
4277 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
4278 "Babeltrace CLI", "Automatic source discovery interrupted by the user");
4279 }
9009cc24
PP
4280 goto error;
4281 }
73760435 4282
353c2524 4283 ret = create_implicit_component_args_from_auto_discovered_sources(
005d49d6 4284 &auto_disc, non_opts, non_opt_params, non_opt_loglevels,
1b2b6649 4285 discovered_source_args);
353c2524 4286 if (ret != 0) {
1ead9076
SM
4287 goto error;
4288 }
9009cc24
PP
4289 }
4290 }
4291
9412c556
FD
4292
4293 /*
4294 * If --clock-force-correlated was given, apply it to any src.ctf.fs
4295 * component.
4296 */
4297 if (ctf_fs_source_force_clock_class_unix_epoch_origin) {
4298 int n;
4299
4300 n = append_multiple_implicit_components_param(
4301 discovered_source_args, "source.ctf.fs", "force-clock-class-origin-unix-epoch",
4302 "yes");
4303 if (n == 0) {
4304 BT_CLI_LOGE_APPEND_CAUSE("--clock-force-correlate specified, but no source.ctf.fs component instantiated.");
4305 goto error;
4306 }
4307 }
4308
73760435
SM
4309 /* If --clock-offset was given, apply it to any src.ctf.fs component. */
4310 if (ctf_fs_source_clock_class_offset_arg) {
4311 int n;
4312
4313 n = append_multiple_implicit_components_param(
4314 discovered_source_args, "source.ctf.fs", "clock-class-offset-s",
4315 ctf_fs_source_clock_class_offset_arg);
4316
4317 if (n == 0) {
4318 BT_CLI_LOGE_APPEND_CAUSE("--clock-offset specified, but no source.ctf.fs component instantiated.");
4319 goto error;
4320 }
9009cc24
PP
4321 }
4322
73760435
SM
4323 /* If --clock-offset-ns was given, apply it to any src.ctf.fs component. */
4324 if (ctf_fs_source_clock_class_offset_ns_arg) {
4325 int n;
4326
4327 n = append_multiple_implicit_components_param(
4328 discovered_source_args, "source.ctf.fs", "clock-class-offset-ns",
4329 ctf_fs_source_clock_class_offset_ns_arg);
4330
4331 if (n == 0) {
4332 BT_CLI_LOGE_APPEND_CAUSE("--clock-offset-ns specified, but no source.ctf.fs component instantiated.");
4333 goto error;
4334 }
9009cc24
PP
4335 }
4336
73760435 4337 /*
24594611
PP
4338 * If the implicit `source.ctf.lttng-live` component exists,
4339 * make sure there's at least one non-option argument (which is
4340 * the URL).
73760435 4341 */
24594611 4342 if (implicit_lttng_live_args.exists && bt_value_array_is_empty(non_opts)) {
9f901451 4343 BT_CLI_LOGE_APPEND_CAUSE("Missing URL for implicit `%s` component.",
fd5f8053 4344 implicit_lttng_live_args.comp_arg->str);
9009cc24
PP
4345 goto error;
4346 }
4347
4348 /* Assign names to implicit components */
73760435
SM
4349 for (i = 0; i < discovered_source_args->len; i++) {
4350 struct implicit_component_args *args;
4351 int j;
4352
4353 args = discovered_source_args->pdata[i];
4354
4355 g_string_printf(auto_disc_comp_name, "auto-disc-%s", args->comp_arg->str);
4356
4357 /* Give it a name like `auto-disc-src-ctf-fs`. */
4358 for (j = 0; j < auto_disc_comp_name->len; j++) {
4359 if (auto_disc_comp_name->str[j] == '.') {
4360 auto_disc_comp_name->str[j] = '-';
4361 }
4362 }
4363
4364 ret = assign_name_to_implicit_component(args,
4365 auto_disc_comp_name->str, all_names, &source_names, true);
4366 if (ret) {
4367 goto error;
4368 }
9009cc24
PP
4369 }
4370
4371 ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
4372 "lttng-live", all_names, &source_names, true);
4373 if (ret) {
4374 goto error;
4375 }
4376
4377 ret = assign_name_to_implicit_component(&implicit_text_args,
4378 "pretty", all_names, &sink_names, true);
4379 if (ret) {
4380 goto error;
4381 }
4382
e7ad156c
PP
4383 ret = assign_name_to_implicit_component(&implicit_ctf_output_args,
4384 "sink-ctf-fs", all_names, &sink_names, true);
4385 if (ret) {
4386 goto error;
4387 }
4388
9009cc24
PP
4389 ret = assign_name_to_implicit_component(&implicit_dummy_args,
4390 "dummy", all_names, &sink_names, true);
4391 if (ret) {
4392 goto error;
4393 }
4394
4395 ret = assign_name_to_implicit_component(&implicit_muxer_args,
4396 "muxer", all_names, NULL, false);
4397 if (ret) {
4398 goto error;
4399 }
4400
4401 ret = assign_name_to_implicit_component(&implicit_trimmer_args,
4402 "trimmer", all_names, NULL, false);
4403 if (ret) {
4404 goto error;
4405 }
4406
4407 ret = assign_name_to_implicit_component(&implicit_debug_info_args,
4408 "debug-info", all_names, NULL, false);
4409 if (ret) {
4410 goto error;
4411 }
4412
4413 /* Make sure there's at least one source and one sink */
4414 if (!source_names) {
9f901451 4415 BT_CLI_LOGE_APPEND_CAUSE("No source component.");
9009cc24
PP
4416 goto error;
4417 }
4418
4419 if (!sink_names) {
9f901451 4420 BT_CLI_LOGE_APPEND_CAUSE("No sink component.");
9009cc24
PP
4421 goto error;
4422 }
4423
46f55736
PP
4424 /* Make sure there's a single sink component */
4425 if (g_list_length(sink_names) != 1) {
4426 BT_CLI_LOGE_APPEND_CAUSE(
4427 "More than one sink component specified.");
4428 goto error;
4429 }
4430
9009cc24
PP
4431 /*
4432 * Prepend the muxer, the trimmer, and the debug info to the
4433 * filter chain so that we have:
4434 *
4435 * sources -> muxer -> [trimmer] -> [debug info] ->
4436 * [user filters] -> sinks
4437 */
4438 if (implicit_debug_info_args.exists) {
4439 if (g_list_prepend_gstring(&filter_names,
4440 implicit_debug_info_args.name_arg->str)) {
4441 goto error;
4442 }
4443 }
4444
4445 if (implicit_trimmer_args.exists) {
4446 if (g_list_prepend_gstring(&filter_names,
4447 implicit_trimmer_args.name_arg->str)) {
4448 goto error;
4449 }
4450 }
4451
4452 if (g_list_prepend_gstring(&filter_names,
4453 implicit_muxer_args.name_arg->str)) {
4454 goto error;
4455 }
4456
4457 /*
4458 * Append the equivalent run arguments for the implicit
4459 * components.
4460 */
73760435
SM
4461 for (i = 0; i < discovered_source_args->len; i++) {
4462 struct implicit_component_args *args =
4463 discovered_source_args->pdata[i];
4464
4465 ret = append_run_args_for_implicit_component(args, run_args);
4466 if (ret) {
4467 goto error;
4468 }
9009cc24
PP
4469 }
4470
fd5f8053 4471 ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
9009cc24
PP
4472 run_args);
4473 if (ret) {
4474 goto error;
4475 }
4476
fd5f8053
PP
4477 ret = append_run_args_for_implicit_component(&implicit_text_args,
4478 run_args);
9009cc24
PP
4479 if (ret) {
4480 goto error;
4481 }
4482
e7ad156c
PP
4483 ret = append_run_args_for_implicit_component(&implicit_ctf_output_args,
4484 run_args);
4485 if (ret) {
4486 goto error;
4487 }
4488
fd5f8053
PP
4489 ret = append_run_args_for_implicit_component(&implicit_dummy_args,
4490 run_args);
9009cc24
PP
4491 if (ret) {
4492 goto error;
4493 }
4494
fd5f8053
PP
4495 ret = append_run_args_for_implicit_component(&implicit_muxer_args,
4496 run_args);
9009cc24
PP
4497 if (ret) {
4498 goto error;
4499 }
4500
fd5f8053 4501 ret = append_run_args_for_implicit_component(&implicit_trimmer_args,
9009cc24
PP
4502 run_args);
4503 if (ret) {
4504 goto error;
4505 }
4506
fd5f8053 4507 ret = append_run_args_for_implicit_component(&implicit_debug_info_args,
9009cc24
PP
4508 run_args);
4509 if (ret) {
4510 goto error;
4511 }
4512
4513 /* Auto-connect components */
4514 ret = convert_auto_connect(run_args, source_names, filter_names,
4515 sink_names);
4516 if (ret) {
9f901451 4517 BT_CLI_LOGE_APPEND_CAUSE("Cannot auto-connect components.");
9009cc24
PP
4518 goto error;
4519 }
4520
4521 /*
4522 * We have all the run command arguments now. Depending on
4523 * --run-args, we pass this to the run command or print them
4524 * here.
4525 */
4526 if (print_run_args || print_run_args_0) {
f80e9ec1 4527 uint64_t args_idx, args_len;
c60cf081 4528 if (stream_intersection_mode) {
9f901451 4529 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --stream-intersection with --run-args or --run-args-0.");
c60cf081
PP
4530 goto error;
4531 }
4532
f80e9ec1
FD
4533 args_len = bt_value_array_get_length(run_args);
4534 for (args_idx = 0; args_idx < args_len; args_idx++) {
b19ff26f 4535 const bt_value *arg_value =
05e21286 4536 bt_value_array_borrow_element_by_index(run_args,
f80e9ec1 4537 args_idx);
9009cc24
PP
4538 const char *arg;
4539 GString *quoted = NULL;
4540 const char *arg_to_print;
4541
601b0d3c 4542 arg = bt_value_string_get(arg_value);
9009cc24
PP
4543
4544 if (print_run_args) {
4545 quoted = bt_common_shell_quote(arg, true);
4546 if (!quoted) {
4547 goto error;
4548 }
4549
4550 arg_to_print = quoted->str;
4551 } else {
4552 arg_to_print = arg;
4553 }
4554
4555 printf("%s", arg_to_print);
4556
4557 if (quoted) {
4558 g_string_free(quoted, TRUE);
4559 }
4560
f80e9ec1 4561 if (args_idx < args_len - 1) {
9009cc24
PP
4562 if (print_run_args) {
4563 putchar(' ');
4564 } else {
4565 putchar('\0');
4566 }
4567 }
4568 }
4569
353c2524 4570 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
9009cc24
PP
4571 goto end;
4572 }
4573
353c2524 4574 status = bt_config_run_from_args_array(run_args, &cfg,
02510056 4575 plugin_paths, *default_log_level);
353c2524
SM
4576 if (status != BT_CONFIG_CLI_ARGS_STATUS_OK) {
4577 goto end;
fc11b6a6
PP
4578 }
4579
75a2cb9b 4580 cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode;
353c2524 4581 BT_OBJECT_MOVE_REF(*cfg_out, cfg);
9009cc24
PP
4582 goto end;
4583
4584error:
353c2524 4585 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
9009cc24
PP
4586
4587end:
a93e984c
SM
4588 argpar_iter_destroy(argpar_iter);
4589 argpar_item_destroy(argpar_item);
9009cc24 4590
e7ad156c 4591 free(output);
9009cc24 4592
505d9178
SM
4593 if (component_arg_for_run) {
4594 g_string_free(component_arg_for_run, TRUE);
9009cc24
PP
4595 }
4596
505d9178
SM
4597 if (name_gstr) {
4598 g_string_free(name_gstr, TRUE);
9009cc24
PP
4599 }
4600
c57d9a63 4601 bt_value_put_ref(live_inputs_array_val);
c5b9b441
PP
4602 bt_value_put_ref(run_args);
4603 bt_value_put_ref(all_names);
9009cc24
PP
4604 destroy_glist_of_gstring(source_names);
4605 destroy_glist_of_gstring(filter_names);
4606 destroy_glist_of_gstring(sink_names);
24594611
PP
4607 bt_value_put_ref(non_opt_params);
4608 bt_value_put_ref(non_opt_loglevels);
4609 bt_value_put_ref(non_opts);
94023a1c
PP
4610 finalize_implicit_component_args(&implicit_ctf_output_args);
4611 finalize_implicit_component_args(&implicit_lttng_live_args);
4612 finalize_implicit_component_args(&implicit_dummy_args);
4613 finalize_implicit_component_args(&implicit_text_args);
4614 finalize_implicit_component_args(&implicit_debug_info_args);
4615 finalize_implicit_component_args(&implicit_muxer_args);
4616 finalize_implicit_component_args(&implicit_trimmer_args);
9009cc24 4617 bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
73760435
SM
4618 auto_source_discovery_fini(&auto_disc);
4619
4620 if (discovered_source_args) {
4621 g_ptr_array_free(discovered_source_args, TRUE);
4622 }
4623
4624 g_free(ctf_fs_source_clock_class_offset_arg);
4625 g_free(ctf_fs_source_clock_class_offset_ns_arg);
4626
4627 if (auto_disc_comp_name) {
4628 g_string_free(auto_disc_comp_name, TRUE);
4629 }
4630
353c2524
SM
4631 bt_object_put_ref(cfg);
4632
4633 return status;
9009cc24
PP
4634}
4635
4636/*
4637 * Prints the Babeltrace 2.x general usage.
4638 */
4639static
4640void print_gen_usage(FILE *fp)
4641{
ec2c5e50 4642 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [COMMAND] [COMMAND ARGUMENTS]\n");
9009cc24
PP
4643 fprintf(fp, "\n");
4644 fprintf(fp, "General options:\n");
4645 fprintf(fp, "\n");
20931d22 4646 fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=T)\n");
02510056 4647 fprintf(fp, " -h, --help Show this help and quit\n");
20931d22 4648 fprintf(fp, " -l, --log-level=LVL Set the default log level to LVL (`N`, `T`, `D`,\n");
02510056
PP
4649 fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n");
4650 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
4651 fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n");
4652 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
4653 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
4654 fprintf(fp, " dynamic plugins can be loaded\n");
4655 fprintf(fp, " -v, --verbose Enable verbose mode (same as --log-level=I)\n");
4656 fprintf(fp, " -V, --version Show version and quit\n");
9009cc24
PP
4657 fprintf(fp, "\n");
4658 fprintf(fp, "Available commands:\n");
4659 fprintf(fp, "\n");
4660 fprintf(fp, " convert Convert and trim traces (default)\n");
4661 fprintf(fp, " help Get help for a plugin or a component class\n");
4662 fprintf(fp, " list-plugins List available plugins and their content\n");
4663 fprintf(fp, " query Query objects from a component class\n");
4664 fprintf(fp, " run Build a processing graph and run it\n");
4665 fprintf(fp, "\n");
ec2c5e50 4666 fprintf(fp, "Use `babeltrace2 COMMAND --help` to show the help of COMMAND.\n");
9009cc24
PP
4667}
4668
353c2524
SM
4669enum bt_config_cli_args_status bt_config_cli_args_create(int argc,
4670 const char *argv[], struct bt_config **cfg,
4671 bool omit_system_plugin_path,
02510056 4672 bool omit_home_plugin_path,
3dae1685
SM
4673 const bt_value *initial_plugin_paths,
4674 const bt_interrupter *interrupter)
9009cc24 4675{
353c2524 4676 enum bt_config_cli_args_status status;
0e497e1c
SM
4677 int top_level_argc;
4678 const char **top_level_argv;
9009cc24 4679 int command_argc = -1;
0e497e1c 4680 const char **command_argv = NULL;
9009cc24 4681 const char *command_name = NULL;
29da2ffc 4682 int default_log_level = -1;
a93e984c
SM
4683 struct argpar_iter *argpar_iter = NULL;
4684 const struct argpar_item *argpar_item = NULL;
4685 const struct argpar_error *argpar_error = NULL;
02510056 4686 bt_value *plugin_paths = NULL;
a80892ba 4687 unsigned int consumed_args;
0e497e1c
SM
4688
4689 /* Top-level option descriptions. */
65966041 4690 static const struct argpar_opt_descr descrs[] = {
0e497e1c
SM
4691 { OPT_DEBUG, 'd', "debug", false },
4692 { OPT_HELP, 'h', "help", false },
4693 { OPT_LOG_LEVEL, 'l', "log-level", true },
4694 { OPT_VERBOSE, 'v', "verbose", false },
4695 { OPT_VERSION, 'V', "version", false},
02510056
PP
4696 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
4697 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
4698 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
65966041 4699 ARGPAR_OPT_DESCR_SENTINEL
0e497e1c 4700 };
9009cc24
PP
4701
4702 enum command_type {
4703 COMMAND_TYPE_NONE = -1,
4704 COMMAND_TYPE_RUN = 0,
4705 COMMAND_TYPE_CONVERT,
4706 COMMAND_TYPE_LIST_PLUGINS,
4707 COMMAND_TYPE_HELP,
4708 COMMAND_TYPE_QUERY,
4709 } command_type = COMMAND_TYPE_NONE;
4710
9009cc24 4711 if (!initial_plugin_paths) {
02510056
PP
4712 plugin_paths = bt_value_array_create();
4713 if (!plugin_paths) {
4714 goto error;
9009cc24
PP
4715 }
4716 } else {
02510056
PP
4717 bt_value_copy_status copy_status = bt_value_copy(
4718 initial_plugin_paths, &plugin_paths);
4719 if (copy_status) {
4720 goto error;
4721 }
4722 }
4723
4724 BT_ASSERT(plugin_paths);
4725
4726 /*
4727 * The `BABELTRACE_PLUGIN_PATH` paths take precedence over the
4728 * `--plugin-path` option's paths, so append it now before
4729 * parsing the general options.
4730 */
4731 if (append_env_var_plugin_paths(plugin_paths)) {
4732 goto error;
9009cc24
PP
4733 }
4734
4735 if (argc <= 1) {
d878cbfd
PP
4736 print_version();
4737 puts("");
9009cc24 4738 print_gen_usage(stdout);
353c2524 4739 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
9009cc24
PP
4740 goto end;
4741 }
4742
0e497e1c
SM
4743 /* Skip first argument, the name of the program. */
4744 top_level_argc = argc - 1;
4745 top_level_argv = argv + 1;
3efa3052 4746
a93e984c
SM
4747 argpar_iter = argpar_iter_create(top_level_argc, top_level_argv, descrs);
4748 if (!argpar_iter) {
4749 BT_CLI_LOGE_APPEND_CAUSE_OOM();
0e497e1c
SM
4750 goto error;
4751 }
5bd4da00 4752
a93e984c 4753 while (true) {
353c2524 4754 enum argpar_iter_next_status argpar_status;
0e497e1c 4755
a93e984c 4756 ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
353c2524 4757 argpar_status = argpar_iter_next(argpar_iter, &argpar_item, &argpar_error);
0e497e1c 4758
353c2524 4759 switch (argpar_status) {
a93e984c
SM
4760 case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
4761 BT_CLI_LOGE_APPEND_CAUSE_OOM();
4762 goto error;
4763 case ARGPAR_ITER_NEXT_STATUS_ERROR:
4764 {
4765 if (argpar_error_type(argpar_error)
4766 != ARGPAR_ERROR_TYPE_UNKNOWN_OPT) {
4767 GString *err_str = format_arg_error(argpar_error, top_level_argv,
a80892ba 4768 0, "While parsing command-line arguments");
a93e984c
SM
4769 BT_CLI_LOGE_APPEND_CAUSE("%s", err_str->str);
4770 g_string_free(err_str, TRUE);
4771 goto error;
4772 }
0e497e1c 4773
a93e984c
SM
4774 break;
4775 }
4776 default:
4777 break;
4778 }
ebddaeb8 4779
353c2524 4780 if (argpar_status == ARGPAR_ITER_NEXT_STATUS_END) {
a93e984c
SM
4781 break;
4782 }
ebddaeb8 4783
353c2524 4784 if (argpar_status == ARGPAR_ITER_NEXT_STATUS_ERROR) {
a93e984c
SM
4785 BT_ASSERT(argpar_error_type(argpar_error) ==
4786 ARGPAR_ERROR_TYPE_UNKNOWN_OPT);
4787 /*
4788 * Unknown option, assume this is implicitly the
4789 * convert command, stop processing arguments.
4790 */
4791 break;
4792 }
4793
4794 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
4795 const struct argpar_opt_descr *opt_descr =
4796 argpar_item_opt_descr(argpar_item);
4797 const char *arg = argpar_item_opt_arg(argpar_item);
4798
4799 switch (opt_descr->id) {
4800 case OPT_DEBUG:
4801 default_log_level =
4802 logging_level_min(default_log_level, BT_LOG_TRACE);
4803 break;
4804 case OPT_VERBOSE:
4805 default_log_level =
4806 logging_level_min(default_log_level, BT_LOG_INFO);
4807 break;
4808 case OPT_LOG_LEVEL:
4809 {
4810 int level = bt_log_get_level_from_string(arg);
4811
4812 if (level < 0) {
4813 BT_CLI_LOGE_APPEND_CAUSE(
4814 "Invalid argument for --log-level option:\n %s",
4815 arg);
4816 goto error;
ebddaeb8 4817 }
a93e984c
SM
4818
4819 default_log_level =
4820 logging_level_min(default_log_level, level);
4821 break;
3efa3052 4822 }
a93e984c
SM
4823 case OPT_PLUGIN_PATH:
4824 if (bt_config_append_plugin_paths_check_setuid_setgid(
4825 plugin_paths, arg)) {
4826 goto error;
4827 }
4828 break;
4829 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
4830 omit_system_plugin_path = true;
4831 break;
4832 case OPT_OMIT_HOME_PLUGIN_PATH:
4833 omit_home_plugin_path = true;
4834 break;
4835 case OPT_VERSION:
4836 print_version();
353c2524 4837 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c
SM
4838 goto end;
4839 case OPT_HELP:
4840 print_gen_usage(stdout);
353c2524 4841 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
a93e984c
SM
4842 goto end;
4843 default:
4844 bt_common_abort();
4845 }
4846 } else {
4847 const char *arg = argpar_item_non_opt_arg(argpar_item);
4848 unsigned int orig_index = argpar_item_non_opt_orig_index(argpar_item);
4849
9009cc24
PP
4850 /*
4851 * First unknown argument: is it a known command
4852 * name?
4853 */
a93e984c
SM
4854 command_argc = top_level_argc - orig_index - 1;
4855 command_argv = &top_level_argv[orig_index + 1];
3efa3052 4856
a93e984c 4857 if (strcmp(arg, "convert") == 0) {
9009cc24 4858 command_type = COMMAND_TYPE_CONVERT;
04439d65 4859 command_name = "convert";
a93e984c 4860 } else if (strcmp(arg, "list-plugins") == 0) {
9009cc24 4861 command_type = COMMAND_TYPE_LIST_PLUGINS;
04439d65 4862 command_name = "list-plugins";
a93e984c 4863 } else if (strcmp(arg, "help") == 0) {
9009cc24 4864 command_type = COMMAND_TYPE_HELP;
04439d65 4865 command_name = "help";
a93e984c 4866 } else if (strcmp(arg, "query") == 0) {
9009cc24 4867 command_type = COMMAND_TYPE_QUERY;
04439d65 4868 command_name = "query";
a93e984c 4869 } else if (strcmp(arg, "run") == 0) {
9009cc24 4870 command_type = COMMAND_TYPE_RUN;
04439d65 4871 command_name = "run";
9009cc24
PP
4872 } else {
4873 /*
0e497e1c 4874 * Non-option argument, but not a known
3efa3052
PP
4875 * command name: assume the default
4876 * `convert` command.
9009cc24
PP
4877 */
4878 command_type = COMMAND_TYPE_CONVERT;
3efa3052 4879 command_name = "convert";
0e497e1c
SM
4880 command_argc++;
4881 command_argv--;
9009cc24 4882 }
a93e984c
SM
4883
4884 /* Stop processing arguments. */
9009cc24
PP
4885 break;
4886 }
4887 }
4888
4889 if (command_type == COMMAND_TYPE_NONE) {
a93e984c
SM
4890 unsigned int ingested_orig_args = argpar_iter_ingested_orig_args(argpar_iter);
4891
4892 if (ingested_orig_args == top_level_argc) {
0e497e1c
SM
4893 /*
4894 * We only got non-help, non-version general options
4895 * like --verbose and --debug, without any other
4896 * arguments, so we can't do anything useful: print the
4897 * usage and quit.
4898 */
4899 print_gen_usage(stdout);
353c2524 4900 status = BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY;
0e497e1c
SM
4901 goto end;
4902 }
4903
9009cc24 4904 /*
0e497e1c
SM
4905 * We stopped on an unknown option argument (and therefore
4906 * didn't see a command name). Assume `convert` command.
9009cc24 4907 */
0e497e1c
SM
4908 command_type = COMMAND_TYPE_CONVERT;
4909 command_name = "convert";
a93e984c
SM
4910 command_argc = top_level_argc - ingested_orig_args;
4911 command_argv = &top_level_argv[ingested_orig_args];
9009cc24
PP
4912 }
4913
f6ccaed9
PP
4914 BT_ASSERT(command_argv);
4915 BT_ASSERT(command_argc >= 0);
9009cc24 4916
29da2ffc 4917 /*
ebddaeb8
SM
4918 * For all commands other than `convert`, we now know the log level to
4919 * use, so we can apply it with `set_auto_log_levels`.
4920 *
4921 * The convert command has `--debug` and `--verbose` arguments that are
4922 * equivalent to the top-level arguments of the same name. So after it
4923 * has parsed its arguments, `bt_config_convert_from_args` calls
4924 * `set_auto_log_levels` itself.
29da2ffc 4925 */
ebddaeb8
SM
4926 if (command_type != COMMAND_TYPE_CONVERT) {
4927 set_auto_log_levels(&default_log_level);
29da2ffc
PP
4928 }
4929
02510056
PP
4930 /*
4931 * At this point, `plugin_paths` contains the initial plugin
4932 * paths, the paths from the `BABELTRACE_PLUGIN_PATH` paths, and
4933 * the paths from the `--plugin-path` option.
4934 *
4935 * Now append the user and system plugin paths.
4936 */
4937 if (append_home_and_system_plugin_paths(plugin_paths,
4938 omit_system_plugin_path, omit_home_plugin_path)) {
4939 goto error;
4940 }
4941
a80892ba
SM
4942 consumed_args = argpar_iter_ingested_orig_args(argpar_iter);
4943
9009cc24
PP
4944 switch (command_type) {
4945 case COMMAND_TYPE_RUN:
353c2524
SM
4946 status = bt_config_run_from_args(command_argc, command_argv,
4947 cfg, plugin_paths,
a80892ba 4948 default_log_level, consumed_args);
9009cc24
PP
4949 break;
4950 case COMMAND_TYPE_CONVERT:
353c2524
SM
4951 status = bt_config_convert_from_args(command_argc, command_argv,
4952 cfg, plugin_paths, &default_log_level, interrupter,
a80892ba 4953 consumed_args);
9009cc24
PP
4954 break;
4955 case COMMAND_TYPE_LIST_PLUGINS:
353c2524
SM
4956 status = bt_config_list_plugins_from_args(command_argc,
4957 command_argv, cfg, plugin_paths, consumed_args);
9009cc24
PP
4958 break;
4959 case COMMAND_TYPE_HELP:
353c2524
SM
4960 status = bt_config_help_from_args(command_argc,
4961 command_argv, cfg, plugin_paths,
a80892ba 4962 default_log_level, consumed_args);
9009cc24
PP
4963 break;
4964 case COMMAND_TYPE_QUERY:
353c2524
SM
4965 status = bt_config_query_from_args(command_argc,
4966 command_argv, cfg, plugin_paths,
a80892ba 4967 default_log_level, consumed_args);
9009cc24
PP
4968 break;
4969 default:
498e7994 4970 bt_common_abort();
9009cc24
PP
4971 }
4972
353c2524
SM
4973 if (status == BT_CONFIG_CLI_ARGS_STATUS_ERROR) {
4974 goto error;
4975 } else if (status == BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY) {
4976 goto end;
9009cc24
PP
4977 }
4978
353c2524
SM
4979 BT_ASSERT(status == BT_CONFIG_CLI_ARGS_STATUS_OK);
4980 BT_ASSERT(*cfg);
4981 BT_ASSERT(default_log_level >= BT_LOG_TRACE);
4982 (*cfg)->log_level = default_log_level;
4983 (*cfg)->command_name = command_name;
4984
4985 status = BT_CONFIG_CLI_ARGS_STATUS_OK;
0e497e1c
SM
4986 goto end;
4987
4988error:
353c2524 4989 status = BT_CONFIG_CLI_ARGS_STATUS_ERROR;
0e497e1c 4990
9009cc24 4991end:
a93e984c
SM
4992 argpar_error_destroy(argpar_error);
4993 argpar_item_destroy(argpar_item);
4994 argpar_iter_destroy(argpar_iter);
02510056 4995 bt_value_put_ref(plugin_paths);
353c2524 4996 return status;
9009cc24 4997}
This page took 0.445264 seconds and 4 git commands to generate.