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