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