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