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