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