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