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