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