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