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