bt2: move common internal functions to their own files
[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`.
3180 */
3181
3182static
3183void create_implicit_component_args_from_auto_discovered_sources(
3184 const struct auto_source_discovery *auto_disc, GPtrArray *component_args)
3185{
3186 gchar *cc_name = NULL;
3187 struct implicit_component_args *comp = NULL;
3188 int status;
3189 guint i, len;
3190
3191 len = auto_disc->results->len;
3192
3193 for (i = 0; i < len; i++) {
3194 struct auto_source_discovery_result *res =
3195 g_ptr_array_index(auto_disc->results, i);
3196
3197 g_free(cc_name);
3198 cc_name = g_strdup_printf("source.%s.%s", res->plugin_name, res->source_cc_name);
3199 if (!cc_name) {
3200 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3201 goto end;
3202 }
3203
3204 comp = create_implicit_component_args(cc_name);
3205 if (!comp) {
3206 goto end;
3207 }
3208
3209 status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs);
3210 if (status != 0) {
3211 goto end;
3212 }
3213
3214 g_ptr_array_add(component_args, comp);
3215 comp = NULL;
3216 }
3217
3218end:
3219 g_free(cc_name);
3220
3221 if (comp) {
3222 destroy_implicit_component_args(comp);
3223 }
3224}
3225
505d9178
SM
3226/*
3227 * As we iterate the arguments to the convert command, this tracks what is the
3228 * type of the current item, to which some contextual options (e.g. --params)
3229 * apply to.
3230 */
3231enum convert_current_item_type {
3232 /* There is no current item. */
3233 CONVERT_CURRENT_ITEM_TYPE_NONE,
3234
3235 /* Current item is a component. */
3236 CONVERT_CURRENT_ITEM_TYPE_COMPONENT,
8b4cd08a
SM
3237
3238 /* Current item is a leftover. */
3239 CONVERT_CURRENT_ITEM_TYPE_LEFTOVER,
505d9178
SM
3240};
3241
9009cc24
PP
3242/*
3243 * Creates a Babeltrace config object from the arguments of a convert
3244 * command.
3245 *
3246 * *retcode is set to the appropriate exit code to use.
3247 */
3248static
3249struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
3250 int *retcode, bool force_omit_system_plugin_path,
9a16feea 3251 bool force_omit_home_plugin_path,
29da2ffc 3252 const bt_value *initial_plugin_paths, int *default_log_level)
9009cc24 3253{
505d9178
SM
3254 enum convert_current_item_type current_item_type =
3255 CONVERT_CURRENT_ITEM_TYPE_NONE;
ca60bbc3 3256 int ret = 0;
9009cc24 3257 struct bt_config *cfg = NULL;
9009cc24
PP
3258 bool got_input_format_opt = false;
3259 bool got_output_format_opt = false;
3260 bool trimmer_has_begin = false;
3261 bool trimmer_has_end = false;
75a2cb9b 3262 bool stream_intersection_mode = false;
9009cc24
PP
3263 bool print_run_args = false;
3264 bool print_run_args_0 = false;
3265 bool print_ctf_metadata = false;
b19ff26f
PP
3266 bt_value *run_args = NULL;
3267 bt_value *all_names = NULL;
9009cc24
PP
3268 GList *source_names = NULL;
3269 GList *filter_names = NULL;
3270 GList *sink_names = NULL;
f280892e 3271 bt_value *leftovers = NULL;
e7ad156c 3272 struct implicit_component_args implicit_ctf_output_args = { 0 };
9009cc24
PP
3273 struct implicit_component_args implicit_lttng_live_args = { 0 };
3274 struct implicit_component_args implicit_dummy_args = { 0 };
3275 struct implicit_component_args implicit_text_args = { 0 };
3276 struct implicit_component_args implicit_debug_info_args = { 0 };
3277 struct implicit_component_args implicit_muxer_args = { 0 };
3278 struct implicit_component_args implicit_trimmer_args = { 0 };
b19ff26f 3279 bt_value *plugin_paths;
9009cc24
PP
3280 char error_buf[256] = { 0 };
3281 size_t i;
3282 struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
e7ad156c 3283 char *output = NULL;
73760435
SM
3284 struct auto_source_discovery auto_disc = { NULL };
3285 GString *auto_disc_comp_name = NULL;
ca60bbc3 3286 struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
505d9178
SM
3287 GString *name_gstr = NULL;
3288 GString *component_arg_for_run = NULL;
73760435
SM
3289
3290 /*
3291 * Array of `struct implicit_component_args *` created for the sources
3292 * we have auto-discovered.
3293 */
3294 GPtrArray *discovered_source_args = NULL;
3295
3296 /*
3297 * If set, restrict automatic source discovery to this component class
3298 * of this plugin.
3299 */
3300 const char *auto_source_discovery_restrict_plugin_name = NULL;
3301 const char *auto_source_discovery_restrict_component_class_name = NULL;
3302
3303 gchar *ctf_fs_source_clock_class_offset_arg = NULL;
3304 gchar *ctf_fs_source_clock_class_offset_ns_arg = NULL;
9009cc24 3305
6be5a99e 3306 (void) bt_value_copy(initial_plugin_paths, &plugin_paths);
398454ed 3307
9009cc24
PP
3308 *retcode = 0;
3309
0e497e1c 3310 if (argc < 1) {
9009cc24
PP
3311 print_convert_usage(stdout);
3312 *retcode = -1;
3313 goto end;
3314 }
3315
e7ad156c
PP
3316 if (init_implicit_component_args(&implicit_ctf_output_args,
3317 "sink.ctf.fs", false)) {
3318 goto error;
3319 }
3320
9009cc24 3321 if (init_implicit_component_args(&implicit_lttng_live_args,
fd5f8053 3322 "source.ctf.lttng-live", false)) {
9009cc24
PP
3323 goto error;
3324 }
3325
fd5f8053
PP
3326 if (init_implicit_component_args(&implicit_text_args,
3327 "sink.text.pretty", false)) {
9009cc24
PP
3328 goto error;
3329 }
3330
fd5f8053
PP
3331 if (init_implicit_component_args(&implicit_dummy_args,
3332 "sink.utils.dummy", false)) {
9009cc24
PP
3333 goto error;
3334 }
3335
3336 if (init_implicit_component_args(&implicit_debug_info_args,
9a16feea 3337 "filter.lttng-utils.debug-info", false)) {
9009cc24
PP
3338 goto error;
3339 }
3340
fd5f8053
PP
3341 if (init_implicit_component_args(&implicit_muxer_args,
3342 "filter.utils.muxer", true)) {
9009cc24
PP
3343 goto error;
3344 }
3345
3346 if (init_implicit_component_args(&implicit_trimmer_args,
fd5f8053 3347 "filter.utils.trimmer", false)) {
9009cc24
PP
3348 goto error;
3349 }
3350
05e21286 3351 all_names = bt_value_map_create();
9009cc24 3352 if (!all_names) {
9f901451 3353 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3354 goto error;
3355 }
3356
05e21286 3357 run_args = bt_value_array_create();
9009cc24 3358 if (!run_args) {
9f901451 3359 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3360 goto error;
3361 }
3362
505d9178
SM
3363 component_arg_for_run = g_string_new(NULL);
3364 if (!component_arg_for_run) {
9f901451 3365 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3366 goto error;
3367 }
3368
3369 ret = append_env_var_plugin_paths(plugin_paths);
3370 if (ret) {
3371 goto error;
3372 }
3373
f280892e
SM
3374 leftovers = bt_value_array_create();
3375 if (!leftovers) {
9f901451 3376 BT_CLI_LOGE_APPEND_CAUSE_OOM();
f280892e
SM
3377 goto error;
3378 }
3379
73760435
SM
3380 if (auto_source_discovery_init(&auto_disc) != 0) {
3381 goto error;
3382 }
3383
3384 discovered_source_args =
3385 g_ptr_array_new_with_free_func((GDestroyNotify) destroy_implicit_component_args);
3386 if (!discovered_source_args) {
3387 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3388 goto error;
3389 }
3390
3391 auto_disc_comp_name = g_string_new(NULL);
3392 if (!auto_disc_comp_name) {
3393 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3394 goto error;
3395 }
3396
9009cc24
PP
3397 /*
3398 * First pass: collect all arguments which need to be passed
3399 * as is to the run command. This pass can also add --name
3400 * arguments if needed to automatically name unnamed component
453b777b 3401 * instances.
9009cc24
PP
3402 *
3403 * Also it appends the plugin paths of --plugin-path to
3404 * `plugin_paths`.
3405 */
ca60bbc3
SM
3406 argpar_parse_ret = bt_argpar_parse(argc, argv, convert_options, true);
3407 if (argpar_parse_ret.error) {
3408 BT_CLI_LOGE_APPEND_CAUSE(
3409 "While parsing `convert` command's command-line arguments: %s",
3410 argpar_parse_ret.error->str);
9009cc24
PP
3411 goto error;
3412 }
3413
ca60bbc3
SM
3414 if (help_option_is_specified(&argpar_parse_ret)) {
3415 print_convert_usage(stdout);
3416 *retcode = -1;
3417 BT_OBJECT_PUT_REF_AND_RESET(cfg);
3418 goto end;
3419 }
9009cc24 3420
ca60bbc3
SM
3421 for (i = 0; i < argpar_parse_ret.items->len; i++) {
3422 struct bt_argpar_item *argpar_item =
3423 g_ptr_array_index(argpar_parse_ret.items, i);
3424 struct bt_argpar_item_opt *argpar_item_opt;
9009cc24
PP
3425 char *name = NULL;
3426 char *plugin_name = NULL;
3427 char *comp_cls_name = NULL;
ca60bbc3 3428 const char *arg;
9009cc24 3429
8b4cd08a
SM
3430 if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
3431 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
3432 arg = argpar_item_opt->arg;
fd5f8053 3433
8b4cd08a
SM
3434 switch (argpar_item_opt->descr->id) {
3435 case OPT_COMPONENT:
3436 {
3437 bt_component_class_type type;
9009cc24 3438
8b4cd08a 3439 current_item_type = CONVERT_CURRENT_ITEM_TYPE_COMPONENT;
9009cc24 3440
8b4cd08a
SM
3441 /* Parse the argument */
3442 plugin_comp_cls_names(arg, &name, &plugin_name,
3443 &comp_cls_name, &type);
3444 if (!plugin_name || !comp_cls_name) {
505d9178 3445 BT_CLI_LOGE_APPEND_CAUSE(
8b4cd08a
SM
3446 "Invalid format for --component option's argument:\n %s",
3447 arg);
505d9178
SM
3448 goto error;
3449 }
3450
8b4cd08a
SM
3451 if (name) {
3452 /*
3453 * Name was given by the user, verify it isn't
3454 * taken.
3455 */
3456 if (bt_value_map_has_entry(all_names, name)) {
3457 BT_CLI_LOGE_APPEND_CAUSE(
3458 "Duplicate component instance name:\n %s",
3459 name);
3460 goto error;
3461 }
3462
3463 name_gstr = g_string_new(name);
3464 if (!name_gstr) {
3465 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3466 goto error;
3467 }
3468
3469 g_string_assign(component_arg_for_run, arg);
3470 } else {
3471 /* Name not given by user, generate one. */
3472 name_gstr = get_component_auto_name(arg, all_names);
3473 if (!name_gstr) {
3474 goto error;
3475 }
3476
3477 g_string_printf(component_arg_for_run, "%s:%s",
3478 name_gstr->str, arg);
3479 }
3480
3481 if (bt_value_array_append_string_element(run_args,
3482 "--component")) {
505d9178
SM
3483 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3484 goto error;
3485 }
3486
8b4cd08a
SM
3487 if (bt_value_array_append_string_element(run_args,
3488 component_arg_for_run->str)) {
3489 BT_CLI_LOGE_APPEND_CAUSE_OOM();
505d9178
SM
3490 goto error;
3491 }
9009cc24 3492
8b4cd08a
SM
3493 /*
3494 * Remember this name globally, for the uniqueness of
3495 * all component names.
3496 */
3497 if (bt_value_map_insert_entry(all_names,
3498 name_gstr->str, bt_value_null)) {
3499 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3500 goto error;
3501 }
fd5f8053 3502
8b4cd08a
SM
3503 /*
3504 * Remember this name specifically for the type of the
3505 * component. This is to create connection arguments.
3506 *
3507 * The list takes ownership of `name_gstr`.
3508 */
3509 switch (type) {
3510 case BT_COMPONENT_CLASS_TYPE_SOURCE:
3511 source_names = g_list_append(source_names, name_gstr);
3512 break;
3513 case BT_COMPONENT_CLASS_TYPE_FILTER:
3514 filter_names = g_list_append(filter_names, name_gstr);
3515 break;
3516 case BT_COMPONENT_CLASS_TYPE_SINK:
3517 sink_names = g_list_append(sink_names, name_gstr);
3518 break;
3519 default:
3520 abort();
3521 }
3522 name_gstr = NULL;
3523
3524 free(name);
3525 free(plugin_name);
3526 free(comp_cls_name);
3527 name = NULL;
3528 plugin_name = NULL;
3529 comp_cls_name = NULL;
3530 break;
505d9178 3531 }
8b4cd08a
SM
3532 case OPT_PARAMS:
3533 if (current_item_type != CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
3534 BT_CLI_LOGE_APPEND_CAUSE(
3535 "No current component (--component option) of which to set parameters:\n %s",
3536 arg);
3537 goto error;
3538 }
505d9178 3539
8b4cd08a
SM
3540 if (bt_value_array_append_string_element(run_args,
3541 "--params")) {
3542 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3543 goto error;
3544 }
9009cc24 3545
8b4cd08a
SM
3546 if (bt_value_array_append_string_element(run_args, arg)) {
3547 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3548 goto error;
3549 }
505d9178 3550 break;
8b4cd08a
SM
3551 case OPT_LOG_LEVEL:
3552 if (current_item_type != CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
3553 BT_CLI_LOGE_APPEND_CAUSE(
3554 "No current component (--component option) to assign a log level to:\n %s",
3555 arg);
3556 goto error;
3557 }
9009cc24 3558
8b4cd08a
SM
3559 if (bt_value_array_append_string_element(run_args, "--log-level")) {
3560 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3561 goto error;
3562 }
9009cc24 3563
8b4cd08a
SM
3564 if (bt_value_array_append_string_element(run_args, arg)) {
3565 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3566 goto error;
3567 }
29da2ffc 3568
8b4cd08a
SM
3569 break;
3570 case OPT_OMIT_HOME_PLUGIN_PATH:
3571 force_omit_home_plugin_path = true;
29da2ffc 3572
8b4cd08a
SM
3573 if (bt_value_array_append_string_element(run_args,
3574 "--omit-home-plugin-path")) {
3575 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3576 goto error;
3577 }
3578 break;
3579 case OPT_RETRY_DURATION:
3580 if (bt_value_array_append_string_element(run_args,
3581 "--retry-duration")) {
3582 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3583 goto error;
3584 }
29da2ffc 3585
8b4cd08a
SM
3586 if (bt_value_array_append_string_element(run_args, arg)) {
3587 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3588 goto error;
3589 }
3590 break;
3591 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
3592 force_omit_system_plugin_path = true;
9009cc24 3593
8b4cd08a
SM
3594 if (bt_value_array_append_string_element(run_args,
3595 "--omit-system-plugin-path")) {
3596 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3597 goto error;
3598 }
3599 break;
3600 case OPT_PLUGIN_PATH:
3601 if (bt_config_append_plugin_paths_check_setuid_setgid(
3602 plugin_paths, arg)) {
3603 goto error;
3604 }
9009cc24 3605
8b4cd08a
SM
3606 if (bt_value_array_append_string_element(run_args,
3607 "--plugin-path")) {
3608 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3609 goto error;
3610 }
9009cc24 3611
8b4cd08a
SM
3612 if (bt_value_array_append_string_element(run_args, arg)) {
3613 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3614 goto error;
3615 }
3616 break;
3617 case OPT_BEGIN:
3618 case OPT_CLOCK_CYCLES:
3619 case OPT_CLOCK_DATE:
3620 case OPT_CLOCK_FORCE_CORRELATE:
3621 case OPT_CLOCK_GMT:
3622 case OPT_CLOCK_OFFSET:
3623 case OPT_CLOCK_OFFSET_NS:
3624 case OPT_CLOCK_SECONDS:
3625 case OPT_COLOR:
3626 case OPT_DEBUG:
3627 case OPT_DEBUG_INFO:
3628 case OPT_DEBUG_INFO_DIR:
3629 case OPT_DEBUG_INFO_FULL_PATH:
3630 case OPT_DEBUG_INFO_TARGET_PREFIX:
3631 case OPT_END:
3632 case OPT_FIELDS:
3633 case OPT_INPUT_FORMAT:
3634 case OPT_NAMES:
3635 case OPT_NO_DELTA:
3636 case OPT_OUTPUT_FORMAT:
3637 case OPT_OUTPUT:
3638 case OPT_RUN_ARGS:
3639 case OPT_RUN_ARGS_0:
3640 case OPT_STREAM_INTERSECTION:
3641 case OPT_TIMERANGE:
3642 case OPT_VERBOSE:
3643 /* Ignore in this pass */
3644 break;
3645 default:
3646 BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
3647 argpar_item_opt->descr->id);
9009cc24
PP
3648 goto error;
3649 }
8b4cd08a
SM
3650 } else if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
3651 struct bt_argpar_item_non_opt *argpar_item_non_opt;
3652 bt_value_array_append_element_status append_status;
9009cc24 3653
8b4cd08a 3654 current_item_type = CONVERT_CURRENT_ITEM_TYPE_LEFTOVER;
9009cc24 3655
8b4cd08a
SM
3656 argpar_item_non_opt = (struct bt_argpar_item_non_opt *) argpar_item;
3657
3658 append_status = bt_value_array_append_string_element(leftovers,
3659 argpar_item_non_opt->arg);
3660 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
9f901451 3661 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3662 goto error;
3663 }
8b4cd08a
SM
3664 } else {
3665 abort();
9009cc24 3666 }
9009cc24
PP
3667 }
3668
9009cc24
PP
3669 /*
3670 * Second pass: transform the convert-specific options and
3671 * arguments into implicit component instances for the run
3672 * command.
3673 */
ca60bbc3
SM
3674 for (i = 0; i < argpar_parse_ret.items->len; i++) {
3675 struct bt_argpar_item *argpar_item =
3676 g_ptr_array_index(argpar_parse_ret.items, i);
3677 struct bt_argpar_item_opt *argpar_item_opt;
3678 const char *arg;
9009cc24 3679
ca60bbc3
SM
3680 if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) {
3681 continue;
3682 }
9009cc24 3683
ca60bbc3
SM
3684 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
3685 arg = argpar_item_opt->arg;
9009cc24 3686
ca60bbc3 3687 switch (argpar_item_opt->descr->id) {
9009cc24
PP
3688 case OPT_BEGIN:
3689 if (trimmer_has_begin) {
3690 printf("At --begin option: --begin or --timerange option already specified\n %s\n",
3691 arg);
3692 goto error;
3693 }
3694
3695 trimmer_has_begin = true;
e7ad156c 3696 ret = append_implicit_component_extra_param(
9009cc24
PP
3697 &implicit_trimmer_args, "begin", arg);
3698 implicit_trimmer_args.exists = true;
3699 if (ret) {
3700 goto error;
3701 }
3702 break;
3703 case OPT_END:
3704 if (trimmer_has_end) {
3705 printf("At --end option: --end or --timerange option already specified\n %s\n",
3706 arg);
3707 goto error;
3708 }
3709
3710 trimmer_has_end = true;
e7ad156c 3711 ret = append_implicit_component_extra_param(
9009cc24
PP
3712 &implicit_trimmer_args, "end", arg);
3713 implicit_trimmer_args.exists = true;
3714 if (ret) {
3715 goto error;
3716 }
3717 break;
3718 case OPT_TIMERANGE:
3719 {
3720 char *begin;
3721 char *end;
3722
3723 if (trimmer_has_begin || trimmer_has_end) {
3724 printf("At --timerange option: --begin, --end, or --timerange option already specified\n %s\n",
3725 arg);
3726 goto error;
3727 }
3728
3729 ret = split_timerange(arg, &begin, &end);
3730 if (ret) {
9f901451 3731 BT_CLI_LOGE_APPEND_CAUSE("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n %s",
9009cc24
PP
3732 arg);
3733 goto error;
3734 }
3735
e7ad156c 3736 ret = append_implicit_component_extra_param(
9009cc24 3737 &implicit_trimmer_args, "begin", begin);
e7ad156c 3738 ret |= append_implicit_component_extra_param(
9009cc24
PP
3739 &implicit_trimmer_args, "end", end);
3740 implicit_trimmer_args.exists = true;
3741 free(begin);
3742 free(end);
3743 if (ret) {
3744 goto error;
3745 }
3746 break;
3747 }
3748 case OPT_CLOCK_CYCLES:
3749 append_implicit_component_param(
3750 &implicit_text_args, "clock-cycles", "yes");
3751 implicit_text_args.exists = true;
3752 break;
3753 case OPT_CLOCK_DATE:
3754 append_implicit_component_param(
3755 &implicit_text_args, "clock-date", "yes");
3756 implicit_text_args.exists = true;
3757 break;
3758 case OPT_CLOCK_FORCE_CORRELATE:
3759 append_implicit_component_param(
a2a54545
PP
3760 &implicit_muxer_args,
3761 "assume-absolute-clock-classes", "yes");
9009cc24
PP
3762 break;
3763 case OPT_CLOCK_GMT:
3764 append_implicit_component_param(
3765 &implicit_text_args, "clock-gmt", "yes");
eb01fbce 3766 append_implicit_component_param(
f855116d 3767 &implicit_trimmer_args, "gmt", "yes");
9009cc24
PP
3768 implicit_text_args.exists = true;
3769 break;
3770 case OPT_CLOCK_OFFSET:
73760435
SM
3771 if (ctf_fs_source_clock_class_offset_arg) {
3772 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset option\n");
3773 goto error;
3774 }
3775
3776 ctf_fs_source_clock_class_offset_arg = g_strdup(arg);
3777 if (!ctf_fs_source_clock_class_offset_arg) {
3778 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3779 goto error;
3780 }
9009cc24
PP
3781 break;
3782 case OPT_CLOCK_OFFSET_NS:
73760435
SM
3783 if (ctf_fs_source_clock_class_offset_ns_arg) {
3784 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset-ns option\n");
3785 goto error;
3786 }
3787
3788 ctf_fs_source_clock_class_offset_ns_arg = g_strdup(arg);
3789 if (!ctf_fs_source_clock_class_offset_ns_arg) {
3790 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3791 goto error;
3792 }
9009cc24
PP
3793 break;
3794 case OPT_CLOCK_SECONDS:
3795 append_implicit_component_param(
3796 &implicit_text_args, "clock-seconds", "yes");
3797 implicit_text_args.exists = true;
3798 break;
3799 case OPT_COLOR:
9009cc24 3800 implicit_text_args.exists = true;
e7ad156c
PP
3801 ret = append_implicit_component_extra_param(
3802 &implicit_text_args, "color", arg);
9009cc24
PP
3803 if (ret) {
3804 goto error;
3805 }
3806 break;
9a16feea
PP
3807 case OPT_DEBUG_INFO:
3808 implicit_debug_info_args.exists = true;
9009cc24
PP
3809 break;
3810 case OPT_DEBUG_INFO_DIR:
e7ad156c
PP
3811 implicit_debug_info_args.exists = true;
3812 ret = append_implicit_component_extra_param(
4cd687b9 3813 &implicit_debug_info_args, "debug-info-dir", arg);
9009cc24
PP
3814 if (ret) {
3815 goto error;
3816 }
3817 break;
3818 case OPT_DEBUG_INFO_FULL_PATH:
e7ad156c 3819 implicit_debug_info_args.exists = true;
9009cc24
PP
3820 append_implicit_component_param(
3821 &implicit_debug_info_args, "full-path", "yes");
3822 break;
3823 case OPT_DEBUG_INFO_TARGET_PREFIX:
e7ad156c
PP
3824 implicit_debug_info_args.exists = true;
3825 ret = append_implicit_component_extra_param(
9009cc24
PP
3826 &implicit_debug_info_args,
3827 "target-prefix", arg);
3828 if (ret) {
3829 goto error;
3830 }
3831 break;
3832 case OPT_FIELDS:
3833 {
b19ff26f 3834 bt_value *fields = fields_from_arg(arg);
9009cc24
PP
3835
3836 if (!fields) {
3837 goto error;
3838 }
3839
e7ad156c 3840 implicit_text_args.exists = true;
9009cc24
PP
3841 ret = insert_flat_params_from_array(
3842 implicit_text_args.params_arg,
05e21286 3843 fields, "field");
c5b9b441 3844 bt_value_put_ref(fields);
9009cc24
PP
3845 if (ret) {
3846 goto error;
3847 }
3848 break;
3849 }
3850 case OPT_NAMES:
3851 {
b19ff26f 3852 bt_value *names = names_from_arg(arg);
9009cc24
PP
3853
3854 if (!names) {
3855 goto error;
3856 }
3857
e7ad156c 3858 implicit_text_args.exists = true;
9009cc24
PP
3859 ret = insert_flat_params_from_array(
3860 implicit_text_args.params_arg,
05e21286 3861 names, "name");
c5b9b441 3862 bt_value_put_ref(names);
9009cc24
PP
3863 if (ret) {
3864 goto error;
3865 }
3866 break;
3867 }
3868 case OPT_NO_DELTA:
3869 append_implicit_component_param(
3870 &implicit_text_args, "no-delta", "yes");
3871 implicit_text_args.exists = true;
3872 break;
3873 case OPT_INPUT_FORMAT:
3874 if (got_input_format_opt) {
9f901451 3875 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --input-format option.");
9009cc24
PP
3876 goto error;
3877 }
3878
3879 got_input_format_opt = true;
3880
3881 if (strcmp(arg, "ctf") == 0) {
73760435
SM
3882 auto_source_discovery_restrict_plugin_name = "ctf";
3883 auto_source_discovery_restrict_component_class_name = "fs";
9009cc24 3884 } else if (strcmp(arg, "lttng-live") == 0) {
73760435
SM
3885 auto_source_discovery_restrict_plugin_name = "ctf";
3886 auto_source_discovery_restrict_component_class_name = "lttng-live";
9009cc24
PP
3887 implicit_lttng_live_args.exists = true;
3888 } else {
9f901451 3889 BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy input format:\n %s",
9009cc24
PP
3890 arg);
3891 goto error;
3892 }
3893 break;
3894 case OPT_OUTPUT_FORMAT:
3895 if (got_output_format_opt) {
9f901451 3896 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output-format option.");
9009cc24
PP
3897 goto error;
3898 }
3899
3900 got_output_format_opt = true;
3901
3902 if (strcmp(arg, "text") == 0) {
3903 implicit_text_args.exists = true;
e7ad156c
PP
3904 } else if (strcmp(arg, "ctf") == 0) {
3905 implicit_ctf_output_args.exists = true;
9009cc24
PP
3906 } else if (strcmp(arg, "dummy") == 0) {
3907 implicit_dummy_args.exists = true;
3908 } else if (strcmp(arg, "ctf-metadata") == 0) {
3909 print_ctf_metadata = true;
3910 } else {
9f901451 3911 BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy output format:\n %s",
9009cc24
PP
3912 arg);
3913 goto error;
3914 }
3915 break;
3916 case OPT_OUTPUT:
e7ad156c 3917 if (output) {
9f901451 3918 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output option");
e7ad156c
PP
3919 goto error;
3920 }
3921
3922 output = strdup(arg);
3923 if (!output) {
9f901451 3924 BT_CLI_LOGE_APPEND_CAUSE_OOM();
9009cc24
PP
3925 goto error;
3926 }
3927 break;
3928 case OPT_RUN_ARGS:
3929 if (print_run_args_0) {
9f901451 3930 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
9009cc24
PP
3931 goto error;
3932 }
3933
3934 print_run_args = true;
3935 break;
3936 case OPT_RUN_ARGS_0:
3937 if (print_run_args) {
9f901451 3938 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
9009cc24
PP
3939 goto error;
3940 }
3941
3942 print_run_args_0 = true;
3943 break;
3944 case OPT_STREAM_INTERSECTION:
75a2cb9b 3945 /*
1a29b831
PP
3946 * Applies to all traces implementing the
3947 * babeltrace.trace-info query.
75a2cb9b
JG
3948 */
3949 stream_intersection_mode = true;
9009cc24
PP
3950 break;
3951 case OPT_VERBOSE:
ef267d12 3952 if (*default_log_level != BT_LOG_TRACE &&
29da2ffc
PP
3953 *default_log_level != BT_LOG_DEBUG) {
3954 *default_log_level = BT_LOG_INFO;
9009cc24 3955 }
9009cc24
PP
3956 break;
3957 case OPT_DEBUG:
ef267d12 3958 *default_log_level = BT_LOG_TRACE;
29da2ffc
PP
3959 break;
3960 default:
9009cc24
PP
3961 break;
3962 }
9009cc24
PP
3963 }
3964
3efa3052
PP
3965 /*
3966 * Legacy behaviour: --verbose used to make the `text` output
3967 * format print more information. --verbose is now equivalent to
83094759
PP
3968 * the INFO log level, which is why we compare to `BT_LOG_INFO`
3969 * here.
3efa3052 3970 */
29da2ffc 3971 if (*default_log_level == BT_LOG_INFO) {
3efa3052
PP
3972 append_implicit_component_param(&implicit_text_args,
3973 "verbose", "yes");
3974 }
3975
9009cc24
PP
3976 /*
3977 * Append home and system plugin paths now that we possibly got
3978 * --plugin-path.
3979 */
3980 if (append_home_and_system_plugin_paths(plugin_paths,
3981 force_omit_system_plugin_path,
3982 force_omit_home_plugin_path)) {
3983 goto error;
3984 }
3985
9009cc24
PP
3986 /* Print CTF metadata or print LTTng live sessions */
3987 if (print_ctf_metadata) {
f280892e 3988 const bt_value *bt_val_leftover;
94023a1c 3989
f280892e 3990 if (bt_value_array_is_empty(leftovers)) {
9f901451 3991 BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf-metadata specified without a path.");
9009cc24
PP
3992 goto error;
3993 }
3994
f280892e 3995 if (bt_value_array_get_size(leftovers) > 1) {
9f901451 3996 BT_CLI_LOGE_APPEND_CAUSE("Too many paths specified for --output-format=ctf-metadata.");
94023a1c
PP
3997 goto error;
3998 }
3999
9009cc24
PP
4000 cfg = bt_config_print_ctf_metadata_create(plugin_paths);
4001 if (!cfg) {
4002 goto error;
4003 }
4004
f280892e 4005 bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
9009cc24 4006 g_string_assign(cfg->cmd_data.print_ctf_metadata.path,
f280892e 4007 bt_value_string_get(bt_val_leftover));
c327e427
PP
4008
4009 if (output) {
4010 g_string_assign(
4011 cfg->cmd_data.print_ctf_metadata.output_path,
4012 output);
4013 }
4014
9009cc24
PP
4015 goto end;
4016 }
4017
4018 /*
e7ad156c
PP
4019 * If -o ctf was specified, make sure an output path (--output)
4020 * was also specified. --output does not imply -o ctf because
4021 * it's also used for the default, implicit -o text if -o ctf
4022 * is not specified.
4023 */
4024 if (implicit_ctf_output_args.exists) {
4025 if (!output) {
9f901451 4026 BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf specified without --output (trace output path).");
e7ad156c
PP
4027 goto error;
4028 }
4029
4030 /*
4031 * At this point we know that -o ctf AND --output were
4032 * specified. Make sure that no options were specified
4033 * which would imply -o text because --output would be
4034 * ambiguous in this case. For example, this is wrong:
4035 *
ec2c5e50 4036 * babeltrace2 --names=all -o ctf --output=/tmp/path my-trace
e7ad156c
PP
4037 *
4038 * because --names=all implies -o text, and --output
4039 * could apply to both the sink.text.pretty and
4040 * sink.ctf.fs implicit components.
4041 */
4042 if (implicit_text_args.exists) {
9f901451 4043 BT_CLI_LOGE_APPEND_CAUSE("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text.");
e7ad156c
PP
4044 goto error;
4045 }
4046 }
4047
4048 /*
4049 * If -o dummy and -o ctf were not specified, and if there are
4050 * no explicit sink components, then use an implicit
4051 * `sink.text.pretty` component.
9009cc24 4052 */
e7ad156c
PP
4053 if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists &&
4054 !sink_names) {
9009cc24
PP
4055 implicit_text_args.exists = true;
4056 }
4057
e7ad156c
PP
4058 /*
4059 * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's
4060 * `path` parameter if --output was specified.
4061 */
4062 if (output) {
4063 if (implicit_text_args.exists) {
4064 append_implicit_component_extra_param(&implicit_text_args,
4065 "path", output);
4066 } else if (implicit_ctf_output_args.exists) {
4067 append_implicit_component_extra_param(&implicit_ctf_output_args,
4068 "path", output);
4069 }
4070 }
4071
94023a1c 4072 /* Decide where the leftover argument(s) go */
f280892e 4073 if (bt_value_array_get_size(leftovers) > 0) {
9009cc24 4074 if (implicit_lttng_live_args.exists) {
f280892e 4075 const bt_value *bt_val_leftover;
94023a1c 4076
f280892e 4077 if (bt_value_array_get_size(leftovers) > 1) {
9f901451 4078 BT_CLI_LOGE_APPEND_CAUSE("Too many URLs specified for --input-format=lttng-live.");
94023a1c
PP
4079 goto error;
4080 }
4081
f280892e 4082 bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
9009cc24 4083 lttng_live_url_parts =
f280892e 4084 bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_leftover),
94b828f3 4085 error_buf, sizeof(error_buf));
9009cc24 4086 if (!lttng_live_url_parts.proto) {
9f901451 4087 BT_CLI_LOGE_APPEND_CAUSE("Invalid LTTng live URL format: %s.",
9009cc24
PP
4088 error_buf);
4089 goto error;
4090 }
4091
4092 if (!lttng_live_url_parts.session_name) {
4093 /* Print LTTng live sessions */
4094 cfg = bt_config_print_lttng_live_sessions_create(
4095 plugin_paths);
4096 if (!cfg) {
4097 goto error;
4098 }
4099
9009cc24 4100 g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url,
f280892e 4101 bt_value_string_get(bt_val_leftover));
c327e427
PP
4102
4103 if (output) {
4104 g_string_assign(
4105 cfg->cmd_data.print_lttng_live_sessions.output_path,
4106 output);
4107 }
4108
9009cc24
PP
4109 goto end;
4110 }
4111
e7ad156c 4112 ret = append_implicit_component_extra_param(
94023a1c 4113 &implicit_lttng_live_args, "url",
f280892e 4114 bt_value_string_get(bt_val_leftover));
9009cc24
PP
4115 if (ret) {
4116 goto error;
4117 }
dccb8b6f
FD
4118
4119 ret = append_implicit_component_extra_param(
4120 &implicit_lttng_live_args,
4121 "session-not-found-action", "end");
4122 if (ret) {
4123 goto error;
4124 }
9009cc24 4125 } else {
73760435
SM
4126 int status;
4127
4128 status = auto_discover_source_components(plugin_paths, leftovers,
4129 auto_source_discovery_restrict_plugin_name,
4130 auto_source_discovery_restrict_component_class_name,
4131 *default_log_level >= 0 ? *default_log_level : cli_default_log_level,
4132 &auto_disc);
4133
4134 if (status != 0) {
9009cc24
PP
4135 goto error;
4136 }
73760435
SM
4137
4138 create_implicit_component_args_from_auto_discovered_sources(
4139 &auto_disc, discovered_source_args);
9009cc24
PP
4140 }
4141 }
4142
73760435
SM
4143 /* If --clock-offset was given, apply it to any src.ctf.fs component. */
4144 if (ctf_fs_source_clock_class_offset_arg) {
4145 int n;
4146
4147 n = append_multiple_implicit_components_param(
4148 discovered_source_args, "source.ctf.fs", "clock-class-offset-s",
4149 ctf_fs_source_clock_class_offset_arg);
4150
4151 if (n == 0) {
4152 BT_CLI_LOGE_APPEND_CAUSE("--clock-offset specified, but no source.ctf.fs component instantiated.");
4153 goto error;
4154 }
9009cc24
PP
4155 }
4156
73760435
SM
4157 /* If --clock-offset-ns was given, apply it to any src.ctf.fs component. */
4158 if (ctf_fs_source_clock_class_offset_ns_arg) {
4159 int n;
4160
4161 n = append_multiple_implicit_components_param(
4162 discovered_source_args, "source.ctf.fs", "clock-class-offset-ns",
4163 ctf_fs_source_clock_class_offset_ns_arg);
4164
4165 if (n == 0) {
4166 BT_CLI_LOGE_APPEND_CAUSE("--clock-offset-ns specified, but no source.ctf.fs component instantiated.");
4167 goto error;
4168 }
9009cc24
PP
4169 }
4170
73760435
SM
4171 /*
4172 * If the implicit `source.ctf.lttng-live` component exists, make sure
4173 * there's at least one leftover (which is the URL).
4174 */
f280892e 4175 if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) {
9f901451 4176 BT_CLI_LOGE_APPEND_CAUSE("Missing URL for implicit `%s` component.",
fd5f8053 4177 implicit_lttng_live_args.comp_arg->str);
9009cc24
PP
4178 goto error;
4179 }
4180
4181 /* Assign names to implicit components */
73760435
SM
4182 for (i = 0; i < discovered_source_args->len; i++) {
4183 struct implicit_component_args *args;
4184 int j;
4185
4186 args = discovered_source_args->pdata[i];
4187
4188 g_string_printf(auto_disc_comp_name, "auto-disc-%s", args->comp_arg->str);
4189
4190 /* Give it a name like `auto-disc-src-ctf-fs`. */
4191 for (j = 0; j < auto_disc_comp_name->len; j++) {
4192 if (auto_disc_comp_name->str[j] == '.') {
4193 auto_disc_comp_name->str[j] = '-';
4194 }
4195 }
4196
4197 ret = assign_name_to_implicit_component(args,
4198 auto_disc_comp_name->str, all_names, &source_names, true);
4199 if (ret) {
4200 goto error;
4201 }
9009cc24
PP
4202 }
4203
4204 ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
4205 "lttng-live", all_names, &source_names, true);
4206 if (ret) {
4207 goto error;
4208 }
4209
4210 ret = assign_name_to_implicit_component(&implicit_text_args,
4211 "pretty", all_names, &sink_names, true);
4212 if (ret) {
4213 goto error;
4214 }
4215
e7ad156c
PP
4216 ret = assign_name_to_implicit_component(&implicit_ctf_output_args,
4217 "sink-ctf-fs", all_names, &sink_names, true);
4218 if (ret) {
4219 goto error;
4220 }
4221
9009cc24
PP
4222 ret = assign_name_to_implicit_component(&implicit_dummy_args,
4223 "dummy", all_names, &sink_names, true);
4224 if (ret) {
4225 goto error;
4226 }
4227
4228 ret = assign_name_to_implicit_component(&implicit_muxer_args,
4229 "muxer", all_names, NULL, false);
4230 if (ret) {
4231 goto error;
4232 }
4233
4234 ret = assign_name_to_implicit_component(&implicit_trimmer_args,
4235 "trimmer", all_names, NULL, false);
4236 if (ret) {
4237 goto error;
4238 }
4239
4240 ret = assign_name_to_implicit_component(&implicit_debug_info_args,
4241 "debug-info", all_names, NULL, false);
4242 if (ret) {
4243 goto error;
4244 }
4245
4246 /* Make sure there's at least one source and one sink */
4247 if (!source_names) {
9f901451 4248 BT_CLI_LOGE_APPEND_CAUSE("No source component.");
9009cc24
PP
4249 goto error;
4250 }
4251
4252 if (!sink_names) {
9f901451 4253 BT_CLI_LOGE_APPEND_CAUSE("No sink component.");
9009cc24
PP
4254 goto error;
4255 }
4256
4257 /*
4258 * Prepend the muxer, the trimmer, and the debug info to the
4259 * filter chain so that we have:
4260 *
4261 * sources -> muxer -> [trimmer] -> [debug info] ->
4262 * [user filters] -> sinks
4263 */
4264 if (implicit_debug_info_args.exists) {
4265 if (g_list_prepend_gstring(&filter_names,
4266 implicit_debug_info_args.name_arg->str)) {
4267 goto error;
4268 }
4269 }
4270
4271 if (implicit_trimmer_args.exists) {
4272 if (g_list_prepend_gstring(&filter_names,
4273 implicit_trimmer_args.name_arg->str)) {
4274 goto error;
4275 }
4276 }
4277
4278 if (g_list_prepend_gstring(&filter_names,
4279 implicit_muxer_args.name_arg->str)) {
4280 goto error;
4281 }
4282
4283 /*
4284 * Append the equivalent run arguments for the implicit
4285 * components.
4286 */
73760435
SM
4287 for (i = 0; i < discovered_source_args->len; i++) {
4288 struct implicit_component_args *args =
4289 discovered_source_args->pdata[i];
4290
4291 ret = append_run_args_for_implicit_component(args, run_args);
4292 if (ret) {
4293 goto error;
4294 }
9009cc24
PP
4295 }
4296
fd5f8053 4297 ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
9009cc24
PP
4298 run_args);
4299 if (ret) {
4300 goto error;
4301 }
4302
fd5f8053
PP
4303 ret = append_run_args_for_implicit_component(&implicit_text_args,
4304 run_args);
9009cc24
PP
4305 if (ret) {
4306 goto error;
4307 }
4308
e7ad156c
PP
4309 ret = append_run_args_for_implicit_component(&implicit_ctf_output_args,
4310 run_args);
4311 if (ret) {
4312 goto error;
4313 }
4314
fd5f8053
PP
4315 ret = append_run_args_for_implicit_component(&implicit_dummy_args,
4316 run_args);
9009cc24
PP
4317 if (ret) {
4318 goto error;
4319 }
4320
fd5f8053
PP
4321 ret = append_run_args_for_implicit_component(&implicit_muxer_args,
4322 run_args);
9009cc24
PP
4323 if (ret) {
4324 goto error;
4325 }
4326
fd5f8053 4327 ret = append_run_args_for_implicit_component(&implicit_trimmer_args,
9009cc24
PP
4328 run_args);
4329 if (ret) {
4330 goto error;
4331 }
4332
fd5f8053 4333 ret = append_run_args_for_implicit_component(&implicit_debug_info_args,
9009cc24
PP
4334 run_args);
4335 if (ret) {
4336 goto error;
4337 }
4338
4339 /* Auto-connect components */
4340 ret = convert_auto_connect(run_args, source_names, filter_names,
4341 sink_names);
4342 if (ret) {
9f901451 4343 BT_CLI_LOGE_APPEND_CAUSE("Cannot auto-connect components.");
9009cc24
PP
4344 goto error;
4345 }
4346
4347 /*
4348 * We have all the run command arguments now. Depending on
4349 * --run-args, we pass this to the run command or print them
4350 * here.
4351 */
4352 if (print_run_args || print_run_args_0) {
c60cf081 4353 if (stream_intersection_mode) {
9f901451 4354 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --stream-intersection with --run-args or --run-args-0.");
c60cf081
PP
4355 goto error;
4356 }
4357
05e21286 4358 for (i = 0; i < bt_value_array_get_size(run_args); i++) {
b19ff26f 4359 const bt_value *arg_value =
05e21286
PP
4360 bt_value_array_borrow_element_by_index(run_args,
4361 i);
9009cc24
PP
4362 const char *arg;
4363 GString *quoted = NULL;
4364 const char *arg_to_print;
4365
f6ccaed9 4366 BT_ASSERT(arg_value);
601b0d3c 4367 arg = bt_value_string_get(arg_value);
9009cc24
PP
4368
4369 if (print_run_args) {
4370 quoted = bt_common_shell_quote(arg, true);
4371 if (!quoted) {
4372 goto error;
4373 }
4374
4375 arg_to_print = quoted->str;
4376 } else {
4377 arg_to_print = arg;
4378 }
4379
4380 printf("%s", arg_to_print);
4381
4382 if (quoted) {
4383 g_string_free(quoted, TRUE);
4384 }
4385
05e21286 4386 if (i < bt_value_array_get_size(run_args) - 1) {
9009cc24
PP
4387 if (print_run_args) {
4388 putchar(' ');
4389 } else {
4390 putchar('\0');
4391 }
4392 }
4393 }
4394
4395 *retcode = -1;
65300d60 4396 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
4397 goto end;
4398 }
4399
29da2ffc
PP
4400 /*
4401 * If the log level is still unset at this point, set it to
4402 * the program's default.
4403 */
4404 if (*default_log_level < 0) {
4405 *default_log_level = cli_default_log_level;
4406 }
4407
05e21286 4408 cfg = bt_config_run_from_args_array(run_args, retcode,
29da2ffc
PP
4409 force_omit_system_plugin_path,
4410 force_omit_home_plugin_path,
4411 initial_plugin_paths, *default_log_level);
fc11b6a6
PP
4412 if (!cfg) {
4413 goto error;
4414 }
4415
75a2cb9b 4416 cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode;
9009cc24
PP
4417 goto end;
4418
4419error:
4420 *retcode = 1;
65300d60 4421 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
4422
4423end:
034c8d01
PP
4424 /*
4425 * If the log level is still unset at this point, set it to
4426 * the program's default.
4427 */
4428 if (*default_log_level < 0) {
4429 *default_log_level = cli_default_log_level;
4430 }
4431
ca60bbc3 4432 bt_argpar_parse_ret_fini(&argpar_parse_ret);
9009cc24 4433
e7ad156c 4434 free(output);
9009cc24 4435
505d9178
SM
4436 if (component_arg_for_run) {
4437 g_string_free(component_arg_for_run, TRUE);
9009cc24
PP
4438 }
4439
505d9178
SM
4440 if (name_gstr) {
4441 g_string_free(name_gstr, TRUE);
9009cc24
PP
4442 }
4443
c5b9b441
PP
4444 bt_value_put_ref(run_args);
4445 bt_value_put_ref(all_names);
9009cc24
PP
4446 destroy_glist_of_gstring(source_names);
4447 destroy_glist_of_gstring(filter_names);
4448 destroy_glist_of_gstring(sink_names);
f280892e 4449 bt_value_put_ref(leftovers);
94023a1c
PP
4450 finalize_implicit_component_args(&implicit_ctf_output_args);
4451 finalize_implicit_component_args(&implicit_lttng_live_args);
4452 finalize_implicit_component_args(&implicit_dummy_args);
4453 finalize_implicit_component_args(&implicit_text_args);
4454 finalize_implicit_component_args(&implicit_debug_info_args);
4455 finalize_implicit_component_args(&implicit_muxer_args);
4456 finalize_implicit_component_args(&implicit_trimmer_args);
c5b9b441 4457 bt_value_put_ref(plugin_paths);
9009cc24 4458 bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
73760435
SM
4459 auto_source_discovery_fini(&auto_disc);
4460
4461 if (discovered_source_args) {
4462 g_ptr_array_free(discovered_source_args, TRUE);
4463 }
4464
4465 g_free(ctf_fs_source_clock_class_offset_arg);
4466 g_free(ctf_fs_source_clock_class_offset_ns_arg);
4467
4468 if (auto_disc_comp_name) {
4469 g_string_free(auto_disc_comp_name, TRUE);
4470 }
4471
9009cc24
PP
4472 return cfg;
4473}
4474
4475/*
4476 * Prints the Babeltrace 2.x general usage.
4477 */
4478static
4479void print_gen_usage(FILE *fp)
4480{
ec2c5e50 4481 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [COMMAND] [COMMAND ARGUMENTS]\n");
9009cc24
PP
4482 fprintf(fp, "\n");
4483 fprintf(fp, "General options:\n");
4484 fprintf(fp, "\n");
3efa3052
PP
4485 fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=V)\n");
4486 fprintf(fp, " -h, --help Show this help and quit\n");
29da2ffc 4487 fprintf(fp, " -l, --log-level=LVL Set the default log level to LVL (`N`, `V`, `D`,\n");
3efa3052
PP
4488 fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n");
4489 fprintf(fp, " -v, --verbose Enable verbose mode (same as --log-level=I)\n");
4490 fprintf(fp, " -V, --version Show version and quit\n");
9009cc24
PP
4491 fprintf(fp, "\n");
4492 fprintf(fp, "Available commands:\n");
4493 fprintf(fp, "\n");
4494 fprintf(fp, " convert Convert and trim traces (default)\n");
4495 fprintf(fp, " help Get help for a plugin or a component class\n");
4496 fprintf(fp, " list-plugins List available plugins and their content\n");
4497 fprintf(fp, " query Query objects from a component class\n");
4498 fprintf(fp, " run Build a processing graph and run it\n");
4499 fprintf(fp, "\n");
ec2c5e50 4500 fprintf(fp, "Use `babeltrace2 COMMAND --help` to show the help of COMMAND.\n");
9009cc24
PP
4501}
4502
4503struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
4504 int *retcode, bool force_omit_system_plugin_path,
9a16feea 4505 bool force_omit_home_plugin_path,
b19ff26f 4506 const bt_value *initial_plugin_paths)
9009cc24
PP
4507{
4508 struct bt_config *config = NULL;
9009cc24 4509 int i;
0e497e1c
SM
4510 int top_level_argc;
4511 const char **top_level_argv;
9009cc24 4512 int command_argc = -1;
0e497e1c 4513 const char **command_argv = NULL;
9009cc24 4514 const char *command_name = NULL;
29da2ffc 4515 int default_log_level = -1;
0e497e1c
SM
4516 struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
4517
4518 /* Top-level option descriptions. */
4519 static const struct bt_argpar_opt_descr descrs[] = {
4520 { OPT_DEBUG, 'd', "debug", false },
4521 { OPT_HELP, 'h', "help", false },
4522 { OPT_LOG_LEVEL, 'l', "log-level", true },
4523 { OPT_VERBOSE, 'v', "verbose", false },
4524 { OPT_VERSION, 'V', "version", false},
4525 BT_ARGPAR_OPT_DESCR_SENTINEL
4526 };
9009cc24
PP
4527
4528 enum command_type {
4529 COMMAND_TYPE_NONE = -1,
4530 COMMAND_TYPE_RUN = 0,
4531 COMMAND_TYPE_CONVERT,
4532 COMMAND_TYPE_LIST_PLUGINS,
4533 COMMAND_TYPE_HELP,
4534 COMMAND_TYPE_QUERY,
4535 } command_type = COMMAND_TYPE_NONE;
4536
4537 *retcode = -1;
4538
4539 if (!initial_plugin_paths) {
05e21286 4540 initial_plugin_paths = bt_value_array_create();
9009cc24
PP
4541 if (!initial_plugin_paths) {
4542 *retcode = 1;
4543 goto end;
4544 }
4545 } else {
c5b9b441 4546 bt_value_get_ref(initial_plugin_paths);
9009cc24
PP
4547 }
4548
4549 if (argc <= 1) {
d878cbfd
PP
4550 print_version();
4551 puts("");
9009cc24
PP
4552 print_gen_usage(stdout);
4553 goto end;
4554 }
4555
0e497e1c
SM
4556 /* Skip first argument, the name of the program. */
4557 top_level_argc = argc - 1;
4558 top_level_argv = argv + 1;
4559 argpar_parse_ret = bt_argpar_parse(top_level_argc, top_level_argv,
4560 descrs, false);
3efa3052 4561
0e497e1c
SM
4562 if (argpar_parse_ret.error) {
4563 BT_CLI_LOGE_APPEND_CAUSE(
4564 "While parsing command-line arguments: %s",
4565 argpar_parse_ret.error->str);
4566 goto error;
4567 }
5bd4da00 4568
0e497e1c
SM
4569 for (i = 0; i < argpar_parse_ret.items->len; i++) {
4570 struct bt_argpar_item *item;
4571
4572 item = g_ptr_array_index(argpar_parse_ret.items, i);
4573
4574 if (item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
4575 struct bt_argpar_item_opt *item_opt =
4576 (struct bt_argpar_item_opt *) item;
4577
4578 switch (item_opt->descr->id) {
4579 case OPT_DEBUG:
4580 default_log_level = BT_LOG_TRACE;
4581 break;
4582 case OPT_VERBOSE:
4583 /*
4584 * Legacy: do not override a previous
4585 * --debug because --verbose and --debug
4586 * can be specified together (in this
4587 * case we want the lowest log level to
4588 * apply, TRACE).
4589 */
4590 default_log_level = BT_LOG_INFO;
4591 break;
4592 case OPT_LOG_LEVEL:
4593 default_log_level =
4594 bt_log_get_level_from_string(item_opt->arg);
4595 if (default_log_level < 0) {
4596 BT_CLI_LOGE_APPEND_CAUSE(
4597 "Invalid argument for --log-level option:\n %s",
4598 item_opt->arg);
4599 goto error;
4600 }
4601 break;
4602 case OPT_VERSION:
4603 print_version();
4604 goto end;
4605 case OPT_HELP:
4606 print_gen_usage(stdout);
4607 goto end;
3efa3052 4608 }
0e497e1c
SM
4609 } else if (item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
4610 struct bt_argpar_item_non_opt *item_non_opt =
4611 (struct bt_argpar_item_non_opt *) item;
9009cc24
PP
4612 /*
4613 * First unknown argument: is it a known command
4614 * name?
4615 */
0e497e1c
SM
4616 command_argc =
4617 top_level_argc - item_non_opt->orig_index - 1;
4618 command_argv =
4619 &top_level_argv[item_non_opt->orig_index + 1];
3efa3052 4620
0e497e1c 4621 if (strcmp(item_non_opt->arg, "convert") == 0) {
9009cc24 4622 command_type = COMMAND_TYPE_CONVERT;
0e497e1c 4623 } else if (strcmp(item_non_opt->arg, "list-plugins") == 0) {
9009cc24 4624 command_type = COMMAND_TYPE_LIST_PLUGINS;
0e497e1c 4625 } else if (strcmp(item_non_opt->arg, "help") == 0) {
9009cc24 4626 command_type = COMMAND_TYPE_HELP;
0e497e1c 4627 } else if (strcmp(item_non_opt->arg, "query") == 0) {
9009cc24 4628 command_type = COMMAND_TYPE_QUERY;
0e497e1c 4629 } else if (strcmp(item_non_opt->arg, "run") == 0) {
9009cc24
PP
4630 command_type = COMMAND_TYPE_RUN;
4631 } else {
4632 /*
0e497e1c 4633 * Non-option argument, but not a known
3efa3052
PP
4634 * command name: assume the default
4635 * `convert` command.
9009cc24
PP
4636 */
4637 command_type = COMMAND_TYPE_CONVERT;
3efa3052 4638 command_name = "convert";
0e497e1c
SM
4639 command_argc++;
4640 command_argv--;
9009cc24
PP
4641 }
4642 break;
4643 }
4644 }
4645
4646 if (command_type == COMMAND_TYPE_NONE) {
0e497e1c
SM
4647 if (argpar_parse_ret.ingested_orig_args == top_level_argc) {
4648 /*
4649 * We only got non-help, non-version general options
4650 * like --verbose and --debug, without any other
4651 * arguments, so we can't do anything useful: print the
4652 * usage and quit.
4653 */
4654 print_gen_usage(stdout);
4655 goto end;
4656 }
4657
9009cc24 4658 /*
0e497e1c
SM
4659 * We stopped on an unknown option argument (and therefore
4660 * didn't see a command name). Assume `convert` command.
9009cc24 4661 */
0e497e1c
SM
4662 command_type = COMMAND_TYPE_CONVERT;
4663 command_name = "convert";
4664 command_argc =
4665 top_level_argc - argpar_parse_ret.ingested_orig_args;
4666 command_argv =
4667 &top_level_argv[argpar_parse_ret.ingested_orig_args];
9009cc24
PP
4668 }
4669
f6ccaed9
PP
4670 BT_ASSERT(command_argv);
4671 BT_ASSERT(command_argc >= 0);
9009cc24 4672
29da2ffc
PP
4673 /*
4674 * The convert command can set its own default log level for
4675 * backward compatibility reasons. It only does so if there's no
4676 * log level yet, so do not force one for this command.
4677 */
4678 if (command_type != COMMAND_TYPE_CONVERT && default_log_level < 0) {
4679 /* Default log level */
4680 default_log_level = cli_default_log_level;
4681 }
4682
9009cc24
PP
4683 switch (command_type) {
4684 case COMMAND_TYPE_RUN:
4685 config = bt_config_run_from_args(command_argc, command_argv,
4686 retcode, force_omit_system_plugin_path,
29da2ffc
PP
4687 force_omit_home_plugin_path, initial_plugin_paths,
4688 default_log_level);
9009cc24
PP
4689 break;
4690 case COMMAND_TYPE_CONVERT:
4691 config = bt_config_convert_from_args(command_argc, command_argv,
4692 retcode, force_omit_system_plugin_path,
9a16feea 4693 force_omit_home_plugin_path,
29da2ffc 4694 initial_plugin_paths, &default_log_level);
9009cc24
PP
4695 break;
4696 case COMMAND_TYPE_LIST_PLUGINS:
4697 config = bt_config_list_plugins_from_args(command_argc,
4698 command_argv, retcode, force_omit_system_plugin_path,
4699 force_omit_home_plugin_path, initial_plugin_paths);
4700 break;
4701 case COMMAND_TYPE_HELP:
4702 config = bt_config_help_from_args(command_argc,
4703 command_argv, retcode, force_omit_system_plugin_path,
29da2ffc
PP
4704 force_omit_home_plugin_path, initial_plugin_paths,
4705 default_log_level);
9009cc24
PP
4706 break;
4707 case COMMAND_TYPE_QUERY:
4708 config = bt_config_query_from_args(command_argc,
4709 command_argv, retcode, force_omit_system_plugin_path,
29da2ffc
PP
4710 force_omit_home_plugin_path, initial_plugin_paths,
4711 default_log_level);
9009cc24
PP
4712 break;
4713 default:
0fbb9a9f 4714 abort();
9009cc24
PP
4715 }
4716
4717 if (config) {
ef267d12 4718 BT_ASSERT(default_log_level >= BT_LOG_TRACE);
29da2ffc 4719 config->log_level = default_log_level;
9009cc24
PP
4720 config->command_name = command_name;
4721 }
4722
0e497e1c
SM
4723 goto end;
4724
4725error:
4726 *retcode = 1;
4727
9009cc24 4728end:
0e497e1c 4729 bt_argpar_parse_ret_fini(&argpar_parse_ret);
c5b9b441 4730 bt_value_put_ref(initial_plugin_paths);
9009cc24
PP
4731 return config;
4732}
This page took 0.324641 seconds and 4 git commands to generate.