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