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