cli: Make append_parameter_to_args accept a bt_value value
[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
242407a9
SM
3210/*
3211 * Convert `value` to its equivalent representation as a command line parameter
3212 * value.
3213 */
3214
3215static
3216gchar *bt_value_to_cli_param_value(bt_value *value)
3217{
3218 GString *buf;
3219 gchar *result = NULL;
3220
3221 buf = g_string_new(NULL);
3222 if (!buf) {
3223 print_err_oom();
3224 goto error;
3225 }
3226
3227 switch (bt_value_get_type(value)) {
3228 case BT_VALUE_TYPE_STRING:
3229 {
3230 const char *str_value = bt_value_string_get(value);
3231 gchar *escaped_str_value;
3232
3233 escaped_str_value = escape_string_value(str_value);
3234 if (!escaped_str_value) {
3235 goto error;
3236 }
3237
3238 g_string_printf(buf, "\"%s\"", escaped_str_value);
3239
3240 g_free(escaped_str_value);
3241 break;
3242 }
3243 default:
3244 abort();
3245 }
3246
3247 result = g_string_free(buf, FALSE);
3248 buf = NULL;
3249
3250 goto end;
3251
3252error:
3253 if (buf) {
3254 g_string_free(buf, TRUE);
3255 }
3256
3257end:
3258 return result;
3259}
3260
b2f834c9 3261static
242407a9 3262int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
b2f834c9 3263{
8b45963b 3264 BT_ASSERT(args);
b2f834c9 3265 BT_ASSERT(bt_value_get_type(args) == BT_VALUE_TYPE_ARRAY);
8b45963b
PP
3266 BT_ASSERT(key);
3267 BT_ASSERT(value);
9009cc24 3268
b2f834c9 3269 int ret = 0;
242407a9 3270 gchar *str_value = NULL;
b2f834c9
SM
3271 GString *parameter = NULL;
3272
3273 if (bt_value_array_append_string_element(args, "--params")) {
9009cc24
PP
3274 print_err_oom();
3275 ret = -1;
3276 goto end;
3277 }
3278
242407a9
SM
3279 str_value = bt_value_to_cli_param_value(value);
3280 if (!str_value) {
9009cc24
PP
3281 ret = -1;
3282 goto end;
3283 }
3284
b2f834c9
SM
3285 parameter = g_string_new(NULL);
3286 if (!parameter) {
9009cc24
PP
3287 print_err_oom();
3288 ret = -1;
3289 goto end;
3290 }
3291
242407a9 3292 g_string_printf(parameter, "%s=%s", key, str_value);
b2f834c9
SM
3293
3294 if (bt_value_array_append_string_element(args, parameter->str)) {
9009cc24
PP
3295 print_err_oom();
3296 ret = -1;
3297 goto end;
3298 }
3299
3300end:
b2f834c9
SM
3301 if (parameter) {
3302 g_string_free(parameter, TRUE);
3303 parameter = NULL;
3304 }
3305
242407a9
SM
3306 if (str_value) {
3307 g_free(str_value);
3308 str_value = NULL;
3309 }
3310
3311 return ret;
3312}
3313
3314static
3315int append_string_parameter_to_args(bt_value *args, const char *key, const char *value)
3316{
3317 bt_value *str_value;
3318 int ret;
3319
3320 str_value = bt_value_string_create_init(value);
3321
3322 if (!str_value) {
3323 print_err_oom();
3324 ret = -1;
3325 goto end;
3326 }
3327
3328 ret = append_parameter_to_args(args, key, str_value);
3329
3330end:
3331 BT_VALUE_PUT_REF_AND_RESET(str_value);
9009cc24
PP
3332 return ret;
3333}
3334
b2f834c9
SM
3335static
3336int append_implicit_component_extra_param(struct implicit_component_args *args,
3337 const char *key, const char *value)
3338{
242407a9 3339 return append_string_parameter_to_args(args->extra_params, key, value);
b2f834c9
SM
3340}
3341
9009cc24
PP
3342static
3343int convert_append_name_param(enum bt_config_component_dest dest,
3344 GString *cur_name, GString *cur_name_prefix,
8eee8ea2
PP
3345 bt_value *run_args,
3346 bt_value *all_names,
9009cc24
PP
3347 GList **source_names, GList **filter_names,
3348 GList **sink_names)
3349{
3350 int ret = 0;
3351
3352 if (cur_name_prefix->len > 0) {
fd5f8053 3353 /* We're after a --component option */
9009cc24
PP
3354 GString *name = NULL;
3355 bool append_name_opt = false;
3356
3357 if (cur_name->len == 0) {
3358 /*
3359 * No explicit name was provided for the user
3360 * component.
3361 */
fd5f8053 3362 name = get_component_auto_name(cur_name_prefix->str,
ce141536 3363 all_names);
9009cc24
PP
3364 append_name_opt = true;
3365 } else {
3366 /*
3367 * An explicit name was provided for the user
3368 * component.
3369 */
ce141536
PP
3370 if (bt_value_map_has_entry(all_names,
3371 cur_name->str)) {
9009cc24
PP
3372 printf_err("Duplicate component instance name:\n %s\n",
3373 cur_name->str);
3374 goto error;
3375 }
3376
3377 name = g_string_new(cur_name->str);
3378 }
3379
3380 if (!name) {
3381 print_err_oom();
3382 goto error;
3383 }
3384
3385 /*
3386 * Remember this name globally, for the uniqueness of
3387 * all component names.
3388 */
ce141536 3389 if (bt_value_map_insert_entry(all_names, name->str, bt_value_null)) {
9009cc24
PP
3390 print_err_oom();
3391 goto error;
3392 }
3393
3394 /*
3395 * Append the --name option if necessary.
3396 */
3397 if (append_name_opt) {
ce141536 3398 if (bt_value_array_append_string_element(run_args, "--name")) {
9009cc24
PP
3399 print_err_oom();
3400 goto error;
3401 }
3402
ce141536 3403 if (bt_value_array_append_string_element(run_args, name->str)) {
9009cc24
PP
3404 print_err_oom();
3405 goto error;
3406 }
3407 }
3408
3409 /*
3410 * Remember this name specifically for the type of the
3411 * component. This is to create connection arguments.
3412 */
3413 switch (dest) {
3414 case BT_CONFIG_COMPONENT_DEST_SOURCE:
3415 *source_names = g_list_append(*source_names, name);
3416 break;
3417 case BT_CONFIG_COMPONENT_DEST_FILTER:
3418 *filter_names = g_list_append(*filter_names, name);
3419 break;
3420 case BT_CONFIG_COMPONENT_DEST_SINK:
3421 *sink_names = g_list_append(*sink_names, name);
3422 break;
3423 default:
0fbb9a9f 3424 abort();
9009cc24
PP
3425 }
3426
3427 g_string_assign(cur_name_prefix, "");
3428 }
3429
3430 goto end;
3431
3432error:
3433 ret = -1;
3434
3435end:
3436 return ret;
3437}
3438
3439/*
3440 * Escapes `.`, `:`, and `\` of `input` with `\`.
3441 */
3442static
3443GString *escape_dot_colon(const char *input)
3444{
3445 GString *output = g_string_new(NULL);
3446 const char *ch;
3447
3448 if (!output) {
3449 print_err_oom();
3450 goto end;
3451 }
3452
3453 for (ch = input; *ch != '\0'; ch++) {
3454 if (*ch == '\\' || *ch == '.' || *ch == ':') {
3455 g_string_append_c(output, '\\');
3456 }
3457
3458 g_string_append_c(output, *ch);
3459 }
3460
3461end:
3462 return output;
3463}
3464
3465/*
3466 * Appends a --connect option to a list of arguments. `upstream_name`
3467 * and `downstream_name` are escaped with escape_dot_colon() in this
3468 * function.
3469 */
3470static
8eee8ea2 3471int append_connect_arg(bt_value *run_args,
9009cc24
PP
3472 const char *upstream_name, const char *downstream_name)
3473{
3474 int ret = 0;
3475 GString *e_upstream_name = escape_dot_colon(upstream_name);
3476 GString *e_downstream_name = escape_dot_colon(downstream_name);
3477 GString *arg = g_string_new(NULL);
3478
3479 if (!e_upstream_name || !e_downstream_name || !arg) {
3480 print_err_oom();
3481 ret = -1;
3482 goto end;
3483 }
3484
ce141536 3485 ret = bt_value_array_append_string_element(run_args, "--connect");
9009cc24
PP
3486 if (ret) {
3487 print_err_oom();
3488 ret = -1;
3489 goto end;
3490 }
3491
3492 g_string_append(arg, e_upstream_name->str);
3493 g_string_append_c(arg, ':');
3494 g_string_append(arg, e_downstream_name->str);
ce141536 3495 ret = bt_value_array_append_string_element(run_args, arg->str);
9009cc24
PP
3496 if (ret) {
3497 print_err_oom();
3498 ret = -1;
3499 goto end;
3500 }
3501
3502end:
3503 if (arg) {
3504 g_string_free(arg, TRUE);
3505 }
3506
3507 if (e_upstream_name) {
3508 g_string_free(e_upstream_name, TRUE);
3509 }
3510
3511 if (e_downstream_name) {
3512 g_string_free(e_downstream_name, TRUE);
3513 }
3514
3515 return ret;
3516}
3517
3518/*
3519 * Appends the run command's --connect options for the convert command.
3520 */
3521static
8eee8ea2 3522int convert_auto_connect(bt_value *run_args,
9009cc24
PP
3523 GList *source_names, GList *filter_names,
3524 GList *sink_names)
3525{
3526 int ret = 0;
3527 GList *source_at = source_names;
3528 GList *filter_at = filter_names;
3529 GList *filter_prev;
3530 GList *sink_at = sink_names;
3531
8b45963b
PP
3532 BT_ASSERT(source_names);
3533 BT_ASSERT(filter_names);
3534 BT_ASSERT(sink_names);
9009cc24
PP
3535
3536 /* Connect all sources to the first filter */
3537 for (source_at = source_names; source_at != NULL; source_at = g_list_next(source_at)) {
3538 GString *source_name = source_at->data;
3539 GString *filter_name = filter_at->data;
3540
3541 ret = append_connect_arg(run_args, source_name->str,
3542 filter_name->str);
3543 if (ret) {
3544 goto error;
3545 }
3546 }
3547
3548 filter_prev = filter_at;
3549 filter_at = g_list_next(filter_at);
3550
3551 /* Connect remaining filters */
3552 for (; filter_at != NULL; filter_prev = filter_at, filter_at = g_list_next(filter_at)) {
3553 GString *filter_name = filter_at->data;
3554 GString *filter_prev_name = filter_prev->data;
3555
3556 ret = append_connect_arg(run_args, filter_prev_name->str,
3557 filter_name->str);
3558 if (ret) {
3559 goto error;
3560 }
3561 }
3562
3563 /* Connect last filter to all sinks */
3564 for (sink_at = sink_names; sink_at != NULL; sink_at = g_list_next(sink_at)) {
3565 GString *filter_name = filter_prev->data;
3566 GString *sink_name = sink_at->data;
3567
3568 ret = append_connect_arg(run_args, filter_name->str,
3569 sink_name->str);
3570 if (ret) {
3571 goto error;
3572 }
3573 }
3574
3575 goto end;
3576
3577error:
3578 ret = -1;
3579
3580end:
3581 return ret;
3582}
3583
3584static
3585int split_timerange(const char *arg, char **begin, char **end)
3586{
3587 int ret = 0;
3588 const char *ch = arg;
3589 size_t end_pos;
3590 GString *g_begin = NULL;
3591 GString *g_end = NULL;
3592
8b45963b 3593 BT_ASSERT(arg);
9009cc24
PP
3594
3595 if (*ch == '[') {
3596 ch++;
3597 }
3598
3599 g_begin = bt_common_string_until(ch, "", ",", &end_pos);
3600 if (!g_begin || ch[end_pos] != ',' || g_begin->len == 0) {
3601 goto error;
3602 }
3603
3604 ch += end_pos + 1;
3605
3606 g_end = bt_common_string_until(ch, "", "]", &end_pos);
3607 if (!g_end || g_end->len == 0) {
3608 goto error;
3609 }
3610
8b45963b
PP
3611 BT_ASSERT(begin);
3612 BT_ASSERT(end);
9009cc24
PP
3613 *begin = g_begin->str;
3614 *end = g_end->str;
3615 g_string_free(g_begin, FALSE);
3616 g_string_free(g_end, FALSE);
3617 g_begin = NULL;
3618 g_end = NULL;
3619 goto end;
3620
3621error:
3622 ret = -1;
3623
3624end:
3625 if (g_begin) {
3626 g_string_free(g_begin, TRUE);
3627 }
3628
3629 if (g_end) {
3630 g_string_free(g_end, TRUE);
3631 }
3632
3633 return ret;
3634}
3635
3636static
3637int g_list_prepend_gstring(GList **list, const char *string)
3638{
3639 int ret = 0;
3640 GString *gs = g_string_new(string);
3641
8b45963b 3642 BT_ASSERT(list);
9009cc24
PP
3643
3644 if (!gs) {
3645 print_err_oom();
3646 goto end;
3647 }
3648
3649 *list = g_list_prepend(*list, gs);
3650
3651end:
3652 return ret;
3653}
3654
94023a1c
PP
3655static
3656struct implicit_component_args *create_implicit_component_args(void)
3657{
3658 struct implicit_component_args *impl_args =
3659 g_new0(struct implicit_component_args, 1);
3660
3661 if (!impl_args) {
3662 goto end;
3663 }
3664
3665 if (init_implicit_component_args(impl_args, NULL, true)) {
3666 destroy_implicit_component_args(impl_args);
3667 impl_args = NULL;
3668 goto end;
3669 }
3670
3671end:
3672 return impl_args;
3673}
3674
3675static
3676int fill_implicit_ctf_inputs_args(GPtrArray *implicit_ctf_inputs_args,
3677 struct implicit_component_args *base_implicit_ctf_input_args,
3678 GList *leftovers)
3679{
3680 int ret = 0;
3681 GList *leftover;
ee78f405 3682 bt_value_status status;
94023a1c
PP
3683
3684 for (leftover = leftovers; leftover != NULL;
3685 leftover = g_list_next(leftover)) {
3686 GString *gs_leftover = leftover->data;
3687 struct implicit_component_args *impl_args =
3688 create_implicit_component_args();
3689
3690 if (!impl_args) {
3691 print_err_oom();
3692 goto error;
3693 }
3694
3695 impl_args->exists = true;
3696 g_string_assign(impl_args->comp_arg,
3697 base_implicit_ctf_input_args->comp_arg->str);
3698 g_string_assign(impl_args->params_arg,
3699 base_implicit_ctf_input_args->params_arg->str);
3700
3701 /*
3702 * We need our own copy of the extra parameters because
3703 * this is where the unique path goes.
3704 */
8c6884d9 3705 BT_VALUE_PUT_REF_AND_RESET(impl_args->extra_params);
6284461f
PP
3706 status = bt_value_copy(base_implicit_ctf_input_args->extra_params,
3707 &impl_args->extra_params);
b5cdc106 3708 if (status != BT_VALUE_STATUS_OK) {
94023a1c
PP
3709 print_err_oom();
3710 destroy_implicit_component_args(impl_args);
3711 goto error;
3712 }
3713
3714 /* Append unique path parameter */
3715 ret = append_implicit_component_extra_param(impl_args,
3716 "path", gs_leftover->str);
3717 if (ret) {
3718 destroy_implicit_component_args(impl_args);
3719 goto error;
3720 }
3721
3722 g_ptr_array_add(implicit_ctf_inputs_args, impl_args);
3723 }
3724
3725 goto end;
3726
3727error:
3728 ret = -1;
3729
3730end:
3731 return ret;
3732}
3733
9009cc24
PP
3734/*
3735 * Creates a Babeltrace config object from the arguments of a convert
3736 * command.
3737 *
3738 * *retcode is set to the appropriate exit code to use.
3739 */
3740static
3741struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
3742 int *retcode, bool force_omit_system_plugin_path,
8e765000 3743 bool force_omit_home_plugin_path,
8eee8ea2 3744 const bt_value *initial_plugin_paths, char *log_level)
9009cc24
PP
3745{
3746 poptContext pc = NULL;
3747 char *arg = NULL;
0a011c88
JG
3748 enum bt_config_component_dest cur_comp_dest =
3749 BT_CONFIG_COMPONENT_DEST_UNKNOWN;
9009cc24
PP
3750 int opt, ret = 0;
3751 struct bt_config *cfg = NULL;
9009cc24
PP
3752 bool got_input_format_opt = false;
3753 bool got_output_format_opt = false;
3754 bool trimmer_has_begin = false;
3755 bool trimmer_has_end = false;
b5fe3e00 3756 bool stream_intersection_mode = false;
9009cc24
PP
3757 GString *cur_name = NULL;
3758 GString *cur_name_prefix = NULL;
3759 const char *leftover = NULL;
3760 bool print_run_args = false;
3761 bool print_run_args_0 = false;
3762 bool print_ctf_metadata = false;
8eee8ea2
PP
3763 bt_value *run_args = NULL;
3764 bt_value *all_names = NULL;
9009cc24
PP
3765 GList *source_names = NULL;
3766 GList *filter_names = NULL;
3767 GList *sink_names = NULL;
94023a1c
PP
3768 GList *leftovers = NULL;
3769 GPtrArray *implicit_ctf_inputs_args = NULL;
3770 struct implicit_component_args base_implicit_ctf_input_args = { 0 };
e7ad156c 3771 struct implicit_component_args implicit_ctf_output_args = { 0 };
9009cc24
PP
3772 struct implicit_component_args implicit_lttng_live_args = { 0 };
3773 struct implicit_component_args implicit_dummy_args = { 0 };
3774 struct implicit_component_args implicit_text_args = { 0 };
3775 struct implicit_component_args implicit_debug_info_args = { 0 };
3776 struct implicit_component_args implicit_muxer_args = { 0 };
3777 struct implicit_component_args implicit_trimmer_args = { 0 };
8eee8ea2 3778 bt_value *plugin_paths;
9009cc24
PP
3779 char error_buf[256] = { 0 };
3780 size_t i;
3781 struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
e7ad156c 3782 char *output = NULL;
9009cc24 3783
6284461f 3784 (void) bt_value_copy(initial_plugin_paths, &plugin_paths);
4b70020d 3785
9009cc24
PP
3786 *retcode = 0;
3787
3788 if (argc <= 1) {
3789 print_convert_usage(stdout);
3790 *retcode = -1;
3791 goto end;
3792 }
3793
94023a1c 3794 if (init_implicit_component_args(&base_implicit_ctf_input_args,
fd5f8053 3795 "source.ctf.fs", false)) {
9009cc24
PP
3796 goto error;
3797 }
3798
e7ad156c
PP
3799 if (init_implicit_component_args(&implicit_ctf_output_args,
3800 "sink.ctf.fs", false)) {
3801 goto error;
3802 }
3803
9009cc24 3804 if (init_implicit_component_args(&implicit_lttng_live_args,
fd5f8053 3805 "source.ctf.lttng-live", false)) {
9009cc24
PP
3806 goto error;
3807 }
3808
fd5f8053
PP
3809 if (init_implicit_component_args(&implicit_text_args,
3810 "sink.text.pretty", false)) {
9009cc24
PP
3811 goto error;
3812 }
3813
fd5f8053
PP
3814 if (init_implicit_component_args(&implicit_dummy_args,
3815 "sink.utils.dummy", false)) {
9009cc24
PP
3816 goto error;
3817 }
3818
3819 if (init_implicit_component_args(&implicit_debug_info_args,
8e765000 3820 "filter.lttng-utils.debug-info", false)) {
9009cc24
PP
3821 goto error;
3822 }
3823
fd5f8053
PP
3824 if (init_implicit_component_args(&implicit_muxer_args,
3825 "filter.utils.muxer", true)) {
9009cc24
PP
3826 goto error;
3827 }
3828
3829 if (init_implicit_component_args(&implicit_trimmer_args,
fd5f8053 3830 "filter.utils.trimmer", false)) {
9009cc24
PP
3831 goto error;
3832 }
3833
94023a1c
PP
3834 implicit_ctf_inputs_args = g_ptr_array_new_with_free_func(
3835 (GDestroyNotify) destroy_implicit_component_args);
3836 if (!implicit_ctf_inputs_args) {
3837 print_err_oom();
3838 goto error;
3839 }
3840
ce141536 3841 all_names = bt_value_map_create();
9009cc24
PP
3842 if (!all_names) {
3843 print_err_oom();
3844 goto error;
3845 }
3846
ce141536 3847 run_args = bt_value_array_create();
9009cc24
PP
3848 if (!run_args) {
3849 print_err_oom();
3850 goto error;
3851 }
3852
3853 cur_name = g_string_new(NULL);
3854 if (!cur_name) {
3855 print_err_oom();
3856 goto error;
3857 }
3858
3859 cur_name_prefix = g_string_new(NULL);
3860 if (!cur_name_prefix) {
3861 print_err_oom();
3862 goto error;
3863 }
3864
3865 ret = append_env_var_plugin_paths(plugin_paths);
3866 if (ret) {
3867 goto error;
3868 }
3869
3870 /*
3871 * First pass: collect all arguments which need to be passed
3872 * as is to the run command. This pass can also add --name
3873 * arguments if needed to automatically name unnamed component
3874 * instances. Also it does the following transformations:
3875 *
b2f834c9
SM
3876 * --path=PATH -> --params=path="PATH"
3877 * --url=URL -> --params=url="URL"
9009cc24
PP
3878 *
3879 * Also it appends the plugin paths of --plugin-path to
3880 * `plugin_paths`.
3881 */
3882 pc = poptGetContext(NULL, argc, (const char **) argv,
3883 convert_long_options, 0);
3884 if (!pc) {
3885 printf_err("Cannot get popt context\n");
3886 goto error;
3887 }
3888
3889 poptReadDefaultConfig(pc, 0);
3890
3891 while ((opt = poptGetNextOpt(pc)) > 0) {
3892 char *name = NULL;
3893 char *plugin_name = NULL;
3894 char *comp_cls_name = NULL;
3895
3896 arg = poptGetOptArg(pc);
3897
3898 switch (opt) {
fd5f8053
PP
3899 case OPT_COMPONENT:
3900 {
ee78f405 3901 bt_component_class_type type;
fd5f8053
PP
3902 const char *type_prefix;
3903
9009cc24
PP
3904 /* Append current component's name if needed */
3905 ret = convert_append_name_param(cur_comp_dest, cur_name,
3906 cur_name_prefix, run_args, all_names,
3907 &source_names, &filter_names, &sink_names);
3908 if (ret) {
3909 goto error;
3910 }
3911
3912 /* Parse the argument */
3913 plugin_comp_cls_names(arg, &name, &plugin_name,
fd5f8053 3914 &comp_cls_name, &type);
9009cc24 3915 if (!plugin_name || !comp_cls_name) {
fd5f8053 3916 printf_err("Invalid format for --component option's argument:\n %s\n",
9009cc24
PP
3917 arg);
3918 goto error;
3919 }
3920
3921 if (name) {
3922 g_string_assign(cur_name, name);
3923 } else {
3924 g_string_assign(cur_name, "");
3925 }
3926
fd5f8053
PP
3927 switch (type) {
3928 case BT_COMPONENT_CLASS_TYPE_SOURCE:
3929 cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
3930 type_prefix = "source";
9009cc24 3931 break;
fd5f8053
PP
3932 case BT_COMPONENT_CLASS_TYPE_FILTER:
3933 cur_comp_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
3934 type_prefix = "filter";
9009cc24 3935 break;
fd5f8053
PP
3936 case BT_COMPONENT_CLASS_TYPE_SINK:
3937 cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
3938 type_prefix = "sink";
9009cc24
PP
3939 break;
3940 default:
0fbb9a9f 3941 abort();
9009cc24
PP
3942 }
3943
ce141536 3944 if (bt_value_array_append_string_element(run_args,
fd5f8053
PP
3945 "--component")) {
3946 print_err_oom();
3947 goto error;
3948 }
3949
ce141536 3950 if (bt_value_array_append_string_element(run_args, arg)) {
9009cc24
PP
3951 print_err_oom();
3952 goto error;
3953 }
3954
3955 g_string_assign(cur_name_prefix, "");
fd5f8053
PP
3956 g_string_append_printf(cur_name_prefix, "%s.%s.%s",
3957 type_prefix, plugin_name, comp_cls_name);
9009cc24
PP
3958 free(name);
3959 free(plugin_name);
3960 free(comp_cls_name);
3961 name = NULL;
3962 plugin_name = NULL;
3963 comp_cls_name = NULL;
3964 break;
fd5f8053 3965 }
9009cc24
PP
3966 case OPT_PARAMS:
3967 if (cur_name_prefix->len == 0) {
3968 printf_err("No current component of which to set parameters:\n %s\n",
3969 arg);
3970 goto error;
3971 }
3972
ce141536 3973 if (bt_value_array_append_string_element(run_args,
9009cc24
PP
3974 "--params")) {
3975 print_err_oom();
3976 goto error;
3977 }
3978
ce141536 3979 if (bt_value_array_append_string_element(run_args, arg)) {
9009cc24
PP
3980 print_err_oom();
3981 goto error;
3982 }
3983 break;
3984 case OPT_PATH:
3985 if (cur_name_prefix->len == 0) {
3986 printf_err("No current component of which to set `path` parameter:\n %s\n",
3987 arg);
3988 goto error;
3989 }
3990
242407a9 3991 if (append_string_parameter_to_args(run_args, "path", arg)) {
9009cc24
PP
3992 goto error;
3993 }
3994 break;
3995 case OPT_URL:
3996 if (cur_name_prefix->len == 0) {
3997 printf_err("No current component of which to set `url` parameter:\n %s\n",
3998 arg);
3999 goto error;
4000 }
4001
9009cc24 4002
242407a9 4003 if (append_string_parameter_to_args(run_args, "url", arg)) {
9009cc24
PP
4004 goto error;
4005 }
4006 break;
4007 case OPT_NAME:
4008 if (cur_name_prefix->len == 0) {
4009 printf_err("No current component to name:\n %s\n",
4010 arg);
4011 goto error;
4012 }
4013
ce141536 4014 if (bt_value_array_append_string_element(run_args, "--name")) {
9009cc24
PP
4015 print_err_oom();
4016 goto error;
4017 }
4018
ce141536 4019 if (bt_value_array_append_string_element(run_args, arg)) {
9009cc24
PP
4020 print_err_oom();
4021 goto error;
4022 }
4023
4024 g_string_assign(cur_name, arg);
4025 break;
4026 case OPT_OMIT_HOME_PLUGIN_PATH:
4027 force_omit_home_plugin_path = true;
4028
ce141536 4029 if (bt_value_array_append_string_element(run_args,
9009cc24
PP
4030 "--omit-home-plugin-path")) {
4031 print_err_oom();
4032 goto error;
4033 }
4034 break;
4035 case OPT_RETRY_DURATION:
ce141536 4036 if (bt_value_array_append_string_element(run_args,
9009cc24
PP
4037 "--retry-duration")) {
4038 print_err_oom();
4039 goto error;
4040 }
4041
ce141536 4042 if (bt_value_array_append_string_element(run_args, arg)) {
9009cc24
PP
4043 print_err_oom();
4044 goto error;
4045 }
4046 break;
4047 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
4048 force_omit_system_plugin_path = true;
4049
ce141536 4050 if (bt_value_array_append_string_element(run_args,
9009cc24
PP
4051 "--omit-system-plugin-path")) {
4052 print_err_oom();
4053 goto error;
4054 }
4055 break;
4056 case OPT_PLUGIN_PATH:
4057 if (bt_config_append_plugin_paths_check_setuid_setgid(
4058 plugin_paths, arg)) {
4059 goto error;
4060 }
4061
ce141536 4062 if (bt_value_array_append_string_element(run_args,
9009cc24
PP
4063 "--plugin-path")) {
4064 print_err_oom();
4065 goto error;
4066 }
4067
ce141536 4068 if (bt_value_array_append_string_element(run_args, arg)) {
9009cc24
PP
4069 print_err_oom();
4070 goto error;
4071 }
4072 break;
4073 case OPT_HELP:
4074 print_convert_usage(stdout);
4075 *retcode = -1;
8138bfe1 4076 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
4077 goto end;
4078 case OPT_BEGIN:
4079 case OPT_CLOCK_CYCLES:
4080 case OPT_CLOCK_DATE:
4081 case OPT_CLOCK_FORCE_CORRELATE:
4082 case OPT_CLOCK_GMT:
4083 case OPT_CLOCK_OFFSET:
4084 case OPT_CLOCK_OFFSET_NS:
4085 case OPT_CLOCK_SECONDS:
4086 case OPT_COLOR:
4087 case OPT_DEBUG:
8e765000 4088 case OPT_DEBUG_INFO:
9009cc24
PP
4089 case OPT_DEBUG_INFO_DIR:
4090 case OPT_DEBUG_INFO_FULL_PATH:
4091 case OPT_DEBUG_INFO_TARGET_PREFIX:
4092 case OPT_END:
4093 case OPT_FIELDS:
4094 case OPT_INPUT_FORMAT:
4095 case OPT_NAMES:
9009cc24
PP
4096 case OPT_NO_DELTA:
4097 case OPT_OUTPUT_FORMAT:
4098 case OPT_OUTPUT:
4099 case OPT_RUN_ARGS:
4100 case OPT_RUN_ARGS_0:
4101 case OPT_STREAM_INTERSECTION:
4102 case OPT_TIMERANGE:
4103 case OPT_VERBOSE:
4104 /* Ignore in this pass */
4105 break;
4106 default:
4107 printf_err("Unknown command-line option specified (option code %d)\n",
4108 opt);
4109 goto error;
4110 }
4111
4112 free(arg);
4113 arg = NULL;
4114 }
4115
4116 /* Append current component's name if needed */
4117 ret = convert_append_name_param(cur_comp_dest, cur_name,
4118 cur_name_prefix, run_args, all_names, &source_names,
4119 &filter_names, &sink_names);
4120 if (ret) {
4121 goto error;
4122 }
4123
4124 /* Check for option parsing error */
4125 if (opt < -1) {
4126 printf_err("While parsing command-line options, at option %s: %s\n",
4127 poptBadOption(pc, 0), poptStrerror(opt));
4128 goto error;
4129 }
4130
4131 poptFreeContext(pc);
4132 free(arg);
4133 arg = NULL;
4134
4135 /*
4136 * Second pass: transform the convert-specific options and
4137 * arguments into implicit component instances for the run
4138 * command.
4139 */
4140 pc = poptGetContext(NULL, argc, (const char **) argv,
4141 convert_long_options, 0);
4142 if (!pc) {
4143 printf_err("Cannot get popt context\n");
4144 goto error;
4145 }
4146
4147 poptReadDefaultConfig(pc, 0);
4148
4149 while ((opt = poptGetNextOpt(pc)) > 0) {
4150 arg = poptGetOptArg(pc);
4151
4152 switch (opt) {
4153 case OPT_BEGIN:
4154 if (trimmer_has_begin) {
4155 printf("At --begin option: --begin or --timerange option already specified\n %s\n",
4156 arg);
4157 goto error;
4158 }
4159
4160 trimmer_has_begin = true;
e7ad156c 4161 ret = append_implicit_component_extra_param(
9009cc24
PP
4162 &implicit_trimmer_args, "begin", arg);
4163 implicit_trimmer_args.exists = true;
4164 if (ret) {
4165 goto error;
4166 }
4167 break;
4168 case OPT_END:
4169 if (trimmer_has_end) {
4170 printf("At --end option: --end or --timerange option already specified\n %s\n",
4171 arg);
4172 goto error;
4173 }
4174
4175 trimmer_has_end = true;
e7ad156c 4176 ret = append_implicit_component_extra_param(
9009cc24
PP
4177 &implicit_trimmer_args, "end", arg);
4178 implicit_trimmer_args.exists = true;
4179 if (ret) {
4180 goto error;
4181 }
4182 break;
4183 case OPT_TIMERANGE:
4184 {
4185 char *begin;
4186 char *end;
4187
4188 if (trimmer_has_begin || trimmer_has_end) {
4189 printf("At --timerange option: --begin, --end, or --timerange option already specified\n %s\n",
4190 arg);
4191 goto error;
4192 }
4193
4194 ret = split_timerange(arg, &begin, &end);
4195 if (ret) {
4196 printf_err("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
4197 arg);
4198 goto error;
4199 }
4200
e7ad156c 4201 ret = append_implicit_component_extra_param(
9009cc24 4202 &implicit_trimmer_args, "begin", begin);
e7ad156c 4203 ret |= append_implicit_component_extra_param(
9009cc24
PP
4204 &implicit_trimmer_args, "end", end);
4205 implicit_trimmer_args.exists = true;
4206 free(begin);
4207 free(end);
4208 if (ret) {
4209 goto error;
4210 }
4211 break;
4212 }
4213 case OPT_CLOCK_CYCLES:
4214 append_implicit_component_param(
4215 &implicit_text_args, "clock-cycles", "yes");
4216 implicit_text_args.exists = true;
4217 break;
4218 case OPT_CLOCK_DATE:
4219 append_implicit_component_param(
4220 &implicit_text_args, "clock-date", "yes");
4221 implicit_text_args.exists = true;
4222 break;
4223 case OPT_CLOCK_FORCE_CORRELATE:
4224 append_implicit_component_param(
53ac3428
PP
4225 &implicit_muxer_args,
4226 "assume-absolute-clock-classes", "yes");
9009cc24
PP
4227 break;
4228 case OPT_CLOCK_GMT:
4229 append_implicit_component_param(
4230 &implicit_text_args, "clock-gmt", "yes");
af47368e 4231 append_implicit_component_param(
480c0b45 4232 &implicit_trimmer_args, "gmt", "yes");
9009cc24
PP
4233 implicit_text_args.exists = true;
4234 break;
4235 case OPT_CLOCK_OFFSET:
94023a1c 4236 base_implicit_ctf_input_args.exists = true;
53ac3428 4237 append_implicit_component_param(
7be7e609 4238 &base_implicit_ctf_input_args,
53ac3428 4239 "clock-class-offset-s", arg);
9009cc24
PP
4240 break;
4241 case OPT_CLOCK_OFFSET_NS:
94023a1c 4242 base_implicit_ctf_input_args.exists = true;
7be7e609
PP
4243 append_implicit_component_param(
4244 &base_implicit_ctf_input_args,
4245 "clock-class-offset-ns", arg);
9009cc24
PP
4246 break;
4247 case OPT_CLOCK_SECONDS:
4248 append_implicit_component_param(
4249 &implicit_text_args, "clock-seconds", "yes");
4250 implicit_text_args.exists = true;
4251 break;
4252 case OPT_COLOR:
9009cc24 4253 implicit_text_args.exists = true;
e7ad156c
PP
4254 ret = append_implicit_component_extra_param(
4255 &implicit_text_args, "color", arg);
9009cc24
PP
4256 if (ret) {
4257 goto error;
4258 }
4259 break;
8e765000
PP
4260 case OPT_DEBUG_INFO:
4261 implicit_debug_info_args.exists = true;
9009cc24
PP
4262 break;
4263 case OPT_DEBUG_INFO_DIR:
e7ad156c
PP
4264 implicit_debug_info_args.exists = true;
4265 ret = append_implicit_component_extra_param(
395a08d0 4266 &implicit_debug_info_args, "debug-info-dir", arg);
9009cc24
PP
4267 if (ret) {
4268 goto error;
4269 }
4270 break;
4271 case OPT_DEBUG_INFO_FULL_PATH:
e7ad156c 4272 implicit_debug_info_args.exists = true;
9009cc24
PP
4273 append_implicit_component_param(
4274 &implicit_debug_info_args, "full-path", "yes");
4275 break;
4276 case OPT_DEBUG_INFO_TARGET_PREFIX:
e7ad156c
PP
4277 implicit_debug_info_args.exists = true;
4278 ret = append_implicit_component_extra_param(
9009cc24
PP
4279 &implicit_debug_info_args,
4280 "target-prefix", arg);
4281 if (ret) {
4282 goto error;
4283 }
4284 break;
4285 case OPT_FIELDS:
4286 {
8eee8ea2 4287 bt_value *fields = fields_from_arg(arg);
9009cc24
PP
4288
4289 if (!fields) {
4290 goto error;
4291 }
4292
e7ad156c 4293 implicit_text_args.exists = true;
9009cc24
PP
4294 ret = insert_flat_params_from_array(
4295 implicit_text_args.params_arg,
ce141536 4296 fields, "field");
8c6884d9 4297 bt_value_put_ref(fields);
9009cc24
PP
4298 if (ret) {
4299 goto error;
4300 }
4301 break;
4302 }
4303 case OPT_NAMES:
4304 {
8eee8ea2 4305 bt_value *names = names_from_arg(arg);
9009cc24
PP
4306
4307 if (!names) {
4308 goto error;
4309 }
4310
e7ad156c 4311 implicit_text_args.exists = true;
9009cc24
PP
4312 ret = insert_flat_params_from_array(
4313 implicit_text_args.params_arg,
ce141536 4314 names, "name");
8c6884d9 4315 bt_value_put_ref(names);
9009cc24
PP
4316 if (ret) {
4317 goto error;
4318 }
4319 break;
4320 }
4321 case OPT_NO_DELTA:
4322 append_implicit_component_param(
4323 &implicit_text_args, "no-delta", "yes");
4324 implicit_text_args.exists = true;
4325 break;
4326 case OPT_INPUT_FORMAT:
4327 if (got_input_format_opt) {
4328 printf_err("Duplicate --input-format option\n");
4329 goto error;
4330 }
4331
4332 got_input_format_opt = true;
4333
4334 if (strcmp(arg, "ctf") == 0) {
94023a1c 4335 base_implicit_ctf_input_args.exists = true;
9009cc24
PP
4336 } else if (strcmp(arg, "lttng-live") == 0) {
4337 implicit_lttng_live_args.exists = true;
4338 } else {
4339 printf_err("Unknown legacy input format:\n %s\n",
4340 arg);
4341 goto error;
4342 }
4343 break;
4344 case OPT_OUTPUT_FORMAT:
4345 if (got_output_format_opt) {
4346 printf_err("Duplicate --output-format option\n");
4347 goto error;
4348 }
4349
4350 got_output_format_opt = true;
4351
4352 if (strcmp(arg, "text") == 0) {
4353 implicit_text_args.exists = true;
e7ad156c
PP
4354 } else if (strcmp(arg, "ctf") == 0) {
4355 implicit_ctf_output_args.exists = true;
9009cc24
PP
4356 } else if (strcmp(arg, "dummy") == 0) {
4357 implicit_dummy_args.exists = true;
4358 } else if (strcmp(arg, "ctf-metadata") == 0) {
4359 print_ctf_metadata = true;
4360 } else {
4361 printf_err("Unknown legacy output format:\n %s\n",
4362 arg);
4363 goto error;
4364 }
4365 break;
4366 case OPT_OUTPUT:
e7ad156c
PP
4367 if (output) {
4368 printf_err("Duplicate --output option\n");
4369 goto error;
4370 }
4371
4372 output = strdup(arg);
4373 if (!output) {
4374 print_err_oom();
9009cc24
PP
4375 goto error;
4376 }
4377 break;
4378 case OPT_RUN_ARGS:
4379 if (print_run_args_0) {
4380 printf_err("Cannot specify --run-args and --run-args-0\n");
4381 goto error;
4382 }
4383
4384 print_run_args = true;
4385 break;
4386 case OPT_RUN_ARGS_0:
4387 if (print_run_args) {
4388 printf_err("Cannot specify --run-args and --run-args-0\n");
4389 goto error;
4390 }
4391
4392 print_run_args_0 = true;
4393 break;
4394 case OPT_STREAM_INTERSECTION:
b5fe3e00
JG
4395 /*
4396 * Applies to all traces implementing the trace-info
4397 * query.
4398 */
4399 stream_intersection_mode = true;
9009cc24
PP
4400 break;
4401 case OPT_VERBOSE:
9e503aa9
PP
4402 if (*log_level != 'V' && *log_level != 'D') {
4403 *log_level = 'I';
9009cc24 4404 }
9009cc24
PP
4405 break;
4406 case OPT_DEBUG:
9e503aa9 4407 *log_level = 'V';
9009cc24
PP
4408 break;
4409 }
4410
4411 free(arg);
4412 arg = NULL;
4413 }
4414
4415 /* Check for option parsing error */
4416 if (opt < -1) {
4417 printf_err("While parsing command-line options, at option %s: %s\n",
4418 poptBadOption(pc, 0), poptStrerror(opt));
4419 goto error;
4420 }
4421
9e503aa9
PP
4422 /*
4423 * Legacy behaviour: --verbose used to make the `text` output
4424 * format print more information. --verbose is now equivalent to
4425 * the INFO log level, which is why we compare to 'I' here.
4426 */
4427 if (*log_level == 'I') {
4428 append_implicit_component_param(&implicit_text_args,
4429 "verbose", "yes");
4430 }
4431
9009cc24
PP
4432 /*
4433 * Append home and system plugin paths now that we possibly got
4434 * --plugin-path.
4435 */
4436 if (append_home_and_system_plugin_paths(plugin_paths,
4437 force_omit_system_plugin_path,
4438 force_omit_home_plugin_path)) {
4439 goto error;
4440 }
4441
94023a1c
PP
4442 /* Consume and keep leftover arguments */
4443 while ((leftover = poptGetArg(pc))) {
4444 GString *gs_leftover = g_string_new(leftover);
9009cc24 4445
94023a1c
PP
4446 if (!gs_leftover) {
4447 print_err_oom();
4448 goto error;
4449 }
4450
4451 leftovers = g_list_append(leftovers, gs_leftover);
4452 if (!leftovers) {
4453 g_string_free(gs_leftover, TRUE);
4454 print_err_oom();
4455 goto error;
4456 }
9009cc24
PP
4457 }
4458
4459 /* Print CTF metadata or print LTTng live sessions */
4460 if (print_ctf_metadata) {
94023a1c
PP
4461 GString *gs_leftover;
4462
4463 if (g_list_length(leftovers) == 0) {
9009cc24
PP
4464 printf_err("--output-format=ctf-metadata specified without a path\n");
4465 goto error;
4466 }
4467
94023a1c
PP
4468 if (g_list_length(leftovers) > 1) {
4469 printf_err("Too many paths specified for --output-format=ctf-metadata\n");
4470 goto error;
4471 }
4472
9009cc24
PP
4473 cfg = bt_config_print_ctf_metadata_create(plugin_paths);
4474 if (!cfg) {
4475 goto error;
4476 }
4477
94023a1c 4478 gs_leftover = leftovers->data;
9009cc24 4479 g_string_assign(cfg->cmd_data.print_ctf_metadata.path,
94023a1c 4480 gs_leftover->str);
a107deea
PP
4481
4482 if (output) {
4483 g_string_assign(
4484 cfg->cmd_data.print_ctf_metadata.output_path,
4485 output);
4486 }
4487
9009cc24
PP
4488 goto end;
4489 }
4490
4491 /*
e7ad156c
PP
4492 * If -o ctf was specified, make sure an output path (--output)
4493 * was also specified. --output does not imply -o ctf because
4494 * it's also used for the default, implicit -o text if -o ctf
4495 * is not specified.
4496 */
4497 if (implicit_ctf_output_args.exists) {
4498 if (!output) {
4499 printf_err("--output-format=ctf specified without --output (trace output path)\n");
4500 goto error;
4501 }
4502
4503 /*
4504 * At this point we know that -o ctf AND --output were
4505 * specified. Make sure that no options were specified
4506 * which would imply -o text because --output would be
4507 * ambiguous in this case. For example, this is wrong:
4508 *
4509 * babeltrace --names=all -o ctf --output=/tmp/path my-trace
4510 *
4511 * because --names=all implies -o text, and --output
4512 * could apply to both the sink.text.pretty and
4513 * sink.ctf.fs implicit components.
4514 */
4515 if (implicit_text_args.exists) {
4516 printf_err("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text\n");
4517 goto error;
4518 }
4519 }
4520
4521 /*
4522 * If -o dummy and -o ctf were not specified, and if there are
4523 * no explicit sink components, then use an implicit
4524 * `sink.text.pretty` component.
9009cc24 4525 */
e7ad156c
PP
4526 if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists &&
4527 !sink_names) {
9009cc24
PP
4528 implicit_text_args.exists = true;
4529 }
4530
e7ad156c
PP
4531 /*
4532 * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's
4533 * `path` parameter if --output was specified.
4534 */
4535 if (output) {
4536 if (implicit_text_args.exists) {
4537 append_implicit_component_extra_param(&implicit_text_args,
4538 "path", output);
4539 } else if (implicit_ctf_output_args.exists) {
4540 append_implicit_component_extra_param(&implicit_ctf_output_args,
4541 "path", output);
4542 }
4543 }
4544
94023a1c
PP
4545 /* Decide where the leftover argument(s) go */
4546 if (g_list_length(leftovers) > 0) {
9009cc24 4547 if (implicit_lttng_live_args.exists) {
94023a1c
PP
4548 GString *gs_leftover;
4549
4550 if (g_list_length(leftovers) > 1) {
4551 printf_err("Too many URLs specified for --output-format=lttng-live\n");
4552 goto error;
4553 }
4554
4555 gs_leftover = leftovers->data;
9009cc24 4556 lttng_live_url_parts =
94023a1c 4557 bt_common_parse_lttng_live_url(gs_leftover->str,
94b828f3 4558 error_buf, sizeof(error_buf));
9009cc24
PP
4559 if (!lttng_live_url_parts.proto) {
4560 printf_err("Invalid LTTng live URL format: %s\n",
4561 error_buf);
4562 goto error;
4563 }
4564
4565 if (!lttng_live_url_parts.session_name) {
4566 /* Print LTTng live sessions */
4567 cfg = bt_config_print_lttng_live_sessions_create(
4568 plugin_paths);
4569 if (!cfg) {
4570 goto error;
4571 }
4572
9009cc24 4573 g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url,
94023a1c 4574 gs_leftover->str);
a107deea
PP
4575
4576 if (output) {
4577 g_string_assign(
4578 cfg->cmd_data.print_lttng_live_sessions.output_path,
4579 output);
4580 }
4581
9009cc24
PP
4582 goto end;
4583 }
4584
e7ad156c 4585 ret = append_implicit_component_extra_param(
94023a1c
PP
4586 &implicit_lttng_live_args, "url",
4587 gs_leftover->str);
9009cc24
PP
4588 if (ret) {
4589 goto error;
4590 }
4591 } else {
94023a1c
PP
4592 /*
4593 * Append one implicit component argument set
4594 * for each leftover (souce.ctf.fs paths). Copy
4595 * the base implicit component arguments.
4596 * Note that they still have to be named later.
4597 */
4598 ret = fill_implicit_ctf_inputs_args(
4599 implicit_ctf_inputs_args,
4600 &base_implicit_ctf_input_args, leftovers);
9009cc24
PP
4601 if (ret) {
4602 goto error;
4603 }
4604 }
4605 }
4606
4607 /*
fd5f8053
PP
4608 * Ensure mutual exclusion between implicit `source.ctf.fs` and
4609 * `source.ctf.lttng-live` components.
9009cc24 4610 */
94023a1c
PP
4611 if (base_implicit_ctf_input_args.exists &&
4612 implicit_lttng_live_args.exists) {
fd5f8053 4613 printf_err("Cannot create both implicit `%s` and `%s` components\n",
94023a1c 4614 base_implicit_ctf_input_args.comp_arg->str,
fd5f8053 4615 implicit_lttng_live_args.comp_arg->str);
9009cc24
PP
4616 goto error;
4617 }
4618
4619 /*
fd5f8053 4620 * If the implicit `source.ctf.fs` or `source.ctf.lttng-live`
94023a1c
PP
4621 * components exists, make sure there's at least one leftover
4622 * (which is the path or URL).
9009cc24 4623 */
94023a1c
PP
4624 if (base_implicit_ctf_input_args.exists &&
4625 g_list_length(leftovers) == 0) {
fd5f8053 4626 printf_err("Missing path for implicit `%s` component\n",
94023a1c 4627 base_implicit_ctf_input_args.comp_arg->str);
9009cc24
PP
4628 goto error;
4629 }
4630
94023a1c 4631 if (implicit_lttng_live_args.exists && g_list_length(leftovers) == 0) {
fd5f8053
PP
4632 printf_err("Missing URL for implicit `%s` component\n",
4633 implicit_lttng_live_args.comp_arg->str);
9009cc24
PP
4634 goto error;
4635 }
4636
4637 /* Assign names to implicit components */
94023a1c
PP
4638 for (i = 0; i < implicit_ctf_inputs_args->len; i++) {
4639 struct implicit_component_args *impl_args =
4640 g_ptr_array_index(implicit_ctf_inputs_args, i);
4641
4642 ret = assign_name_to_implicit_component(impl_args,
4643 "source-ctf-fs", all_names, &source_names, true);
4644 if (ret) {
4645 goto error;
4646 }
9009cc24
PP
4647 }
4648
4649 ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
4650 "lttng-live", all_names, &source_names, true);
4651 if (ret) {
4652 goto error;
4653 }
4654
4655 ret = assign_name_to_implicit_component(&implicit_text_args,
4656 "pretty", all_names, &sink_names, true);
4657 if (ret) {
4658 goto error;
4659 }
4660
e7ad156c
PP
4661 ret = assign_name_to_implicit_component(&implicit_ctf_output_args,
4662 "sink-ctf-fs", all_names, &sink_names, true);
4663 if (ret) {
4664 goto error;
4665 }
4666
9009cc24
PP
4667 ret = assign_name_to_implicit_component(&implicit_dummy_args,
4668 "dummy", all_names, &sink_names, true);
4669 if (ret) {
4670 goto error;
4671 }
4672
4673 ret = assign_name_to_implicit_component(&implicit_muxer_args,
4674 "muxer", all_names, NULL, false);
4675 if (ret) {
4676 goto error;
4677 }
4678
4679 ret = assign_name_to_implicit_component(&implicit_trimmer_args,
4680 "trimmer", all_names, NULL, false);
4681 if (ret) {
4682 goto error;
4683 }
4684
4685 ret = assign_name_to_implicit_component(&implicit_debug_info_args,
4686 "debug-info", all_names, NULL, false);
4687 if (ret) {
4688 goto error;
4689 }
4690
4691 /* Make sure there's at least one source and one sink */
4692 if (!source_names) {
4693 printf_err("No source component\n");
4694 goto error;
4695 }
4696
4697 if (!sink_names) {
4698 printf_err("No sink component\n");
4699 goto error;
4700 }
4701
4702 /*
4703 * Prepend the muxer, the trimmer, and the debug info to the
4704 * filter chain so that we have:
4705 *
4706 * sources -> muxer -> [trimmer] -> [debug info] ->
4707 * [user filters] -> sinks
4708 */
4709 if (implicit_debug_info_args.exists) {
4710 if (g_list_prepend_gstring(&filter_names,
4711 implicit_debug_info_args.name_arg->str)) {
4712 goto error;
4713 }
4714 }
4715
4716 if (implicit_trimmer_args.exists) {
4717 if (g_list_prepend_gstring(&filter_names,
4718 implicit_trimmer_args.name_arg->str)) {
4719 goto error;
4720 }
4721 }
4722
4723 if (g_list_prepend_gstring(&filter_names,
4724 implicit_muxer_args.name_arg->str)) {
4725 goto error;
4726 }
4727
4728 /*
4729 * Append the equivalent run arguments for the implicit
4730 * components.
4731 */
94023a1c
PP
4732 for (i = 0; i < implicit_ctf_inputs_args->len; i++) {
4733 struct implicit_component_args *impl_args =
4734 g_ptr_array_index(implicit_ctf_inputs_args, i);
4735
4736 ret = append_run_args_for_implicit_component(impl_args,
4737 run_args);
4738 if (ret) {
4739 goto error;
4740 }
9009cc24
PP
4741 }
4742
fd5f8053 4743 ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
9009cc24
PP
4744 run_args);
4745 if (ret) {
4746 goto error;
4747 }
4748
fd5f8053
PP
4749 ret = append_run_args_for_implicit_component(&implicit_text_args,
4750 run_args);
9009cc24
PP
4751 if (ret) {
4752 goto error;
4753 }
4754
e7ad156c
PP
4755 ret = append_run_args_for_implicit_component(&implicit_ctf_output_args,
4756 run_args);
4757 if (ret) {
4758 goto error;
4759 }
4760
fd5f8053
PP
4761 ret = append_run_args_for_implicit_component(&implicit_dummy_args,
4762 run_args);
9009cc24
PP
4763 if (ret) {
4764 goto error;
4765 }
4766
fd5f8053
PP
4767 ret = append_run_args_for_implicit_component(&implicit_muxer_args,
4768 run_args);
9009cc24
PP
4769 if (ret) {
4770 goto error;
4771 }
4772
fd5f8053 4773 ret = append_run_args_for_implicit_component(&implicit_trimmer_args,
9009cc24
PP
4774 run_args);
4775 if (ret) {
4776 goto error;
4777 }
4778
fd5f8053 4779 ret = append_run_args_for_implicit_component(&implicit_debug_info_args,
9009cc24
PP
4780 run_args);
4781 if (ret) {
4782 goto error;
4783 }
4784
4785 /* Auto-connect components */
4786 ret = convert_auto_connect(run_args, source_names, filter_names,
4787 sink_names);
4788 if (ret) {
4789 printf_err("Cannot auto-connect components\n");
4790 goto error;
4791 }
4792
4793 /*
4794 * We have all the run command arguments now. Depending on
4795 * --run-args, we pass this to the run command or print them
4796 * here.
4797 */
4798 if (print_run_args || print_run_args_0) {
f9692f14
PP
4799 if (stream_intersection_mode) {
4800 printf_err("Cannot specify --stream-intersection with --run-args or --run-args-0\n");
4801 goto error;
4802 }
4803
ce141536 4804 for (i = 0; i < bt_value_array_get_size(run_args); i++) {
8eee8ea2 4805 const bt_value *arg_value =
ce141536
PP
4806 bt_value_array_borrow_element_by_index(run_args,
4807 i);
9009cc24
PP
4808 const char *arg;
4809 GString *quoted = NULL;
4810 const char *arg_to_print;
4811
8b45963b 4812 BT_ASSERT(arg_value);
b5cdc106 4813 arg = bt_value_string_get(arg_value);
9009cc24
PP
4814
4815 if (print_run_args) {
4816 quoted = bt_common_shell_quote(arg, true);
4817 if (!quoted) {
4818 goto error;
4819 }
4820
4821 arg_to_print = quoted->str;
4822 } else {
4823 arg_to_print = arg;
4824 }
4825
4826 printf("%s", arg_to_print);
4827
4828 if (quoted) {
4829 g_string_free(quoted, TRUE);
4830 }
4831
ce141536 4832 if (i < bt_value_array_get_size(run_args) - 1) {
9009cc24
PP
4833 if (print_run_args) {
4834 putchar(' ');
4835 } else {
4836 putchar('\0');
4837 }
4838 }
4839 }
4840
4841 *retcode = -1;
8138bfe1 4842 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
4843 goto end;
4844 }
4845
ce141536
PP
4846 cfg = bt_config_run_from_args_array(run_args, retcode,
4847 force_omit_system_plugin_path,
4848 force_omit_home_plugin_path,
4849 initial_plugin_paths);
fc11b6a6
PP
4850 if (!cfg) {
4851 goto error;
4852 }
4853
b5fe3e00 4854 cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode;
9009cc24
PP
4855 goto end;
4856
4857error:
4858 *retcode = 1;
8138bfe1 4859 BT_OBJECT_PUT_REF_AND_RESET(cfg);
9009cc24
PP
4860
4861end:
4862 if (pc) {
4863 poptFreeContext(pc);
4864 }
4865
4866 free(arg);
e7ad156c 4867 free(output);
9009cc24
PP
4868
4869 if (cur_name) {
4870 g_string_free(cur_name, TRUE);
4871 }
4872
4873 if (cur_name_prefix) {
4874 g_string_free(cur_name_prefix, TRUE);
4875 }
4876
94023a1c
PP
4877 if (implicit_ctf_inputs_args) {
4878 g_ptr_array_free(implicit_ctf_inputs_args, TRUE);
4879 }
4880
8c6884d9
PP
4881 bt_value_put_ref(run_args);
4882 bt_value_put_ref(all_names);
9009cc24
PP
4883 destroy_glist_of_gstring(source_names);
4884 destroy_glist_of_gstring(filter_names);
4885 destroy_glist_of_gstring(sink_names);
94023a1c
PP
4886 destroy_glist_of_gstring(leftovers);
4887 finalize_implicit_component_args(&base_implicit_ctf_input_args);
4888 finalize_implicit_component_args(&implicit_ctf_output_args);
4889 finalize_implicit_component_args(&implicit_lttng_live_args);
4890 finalize_implicit_component_args(&implicit_dummy_args);
4891 finalize_implicit_component_args(&implicit_text_args);
4892 finalize_implicit_component_args(&implicit_debug_info_args);
4893 finalize_implicit_component_args(&implicit_muxer_args);
4894 finalize_implicit_component_args(&implicit_trimmer_args);
8c6884d9 4895 bt_value_put_ref(plugin_paths);
9009cc24
PP
4896 bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
4897 return cfg;
4898}
4899
4900/*
4901 * Prints the Babeltrace 2.x general usage.
4902 */
4903static
4904void print_gen_usage(FILE *fp)
4905{
4906 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND ARGUMENTS]\n");
4907 fprintf(fp, "\n");
4908 fprintf(fp, "General options:\n");
4909 fprintf(fp, "\n");
9e503aa9
PP
4910 fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=V)\n");
4911 fprintf(fp, " -h, --help Show this help and quit\n");
21b5b16a 4912 fprintf(fp, " -l, --log-level=LVL Set all log levels to LVL (`N`, `V`, `D`,\n");
9e503aa9
PP
4913 fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n");
4914 fprintf(fp, " -v, --verbose Enable verbose mode (same as --log-level=I)\n");
4915 fprintf(fp, " -V, --version Show version and quit\n");
9009cc24
PP
4916 fprintf(fp, "\n");
4917 fprintf(fp, "Available commands:\n");
4918 fprintf(fp, "\n");
4919 fprintf(fp, " convert Convert and trim traces (default)\n");
4920 fprintf(fp, " help Get help for a plugin or a component class\n");
4921 fprintf(fp, " list-plugins List available plugins and their content\n");
4922 fprintf(fp, " query Query objects from a component class\n");
4923 fprintf(fp, " run Build a processing graph and run it\n");
4924 fprintf(fp, "\n");
4925 fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
4926}
4927
9e503aa9
PP
4928static
4929char log_level_from_arg(const char *arg)
4930{
4931 char level = 'U';
4932
4933 if (strcmp(arg, "VERBOSE") == 0 ||
4934 strcmp(arg, "V") == 0) {
4935 level = 'V';
4936 } else if (strcmp(arg, "DEBUG") == 0 ||
4937 strcmp(arg, "D") == 0) {
4938 level = 'D';
4939 } else if (strcmp(arg, "INFO") == 0 ||
4940 strcmp(arg, "I") == 0) {
4941 level = 'I';
4942 } else if (strcmp(arg, "WARN") == 0 ||
4943 strcmp(arg, "WARNING") == 0 ||
4944 strcmp(arg, "W") == 0) {
4945 level = 'W';
4946 } else if (strcmp(arg, "ERROR") == 0 ||
4947 strcmp(arg, "E") == 0) {
4948 level = 'E';
4949 } else if (strcmp(arg, "FATAL") == 0 ||
4950 strcmp(arg, "F") == 0) {
4951 level = 'F';
4952 } else if (strcmp(arg, "NONE") == 0 ||
4953 strcmp(arg, "N") == 0) {
4954 level = 'N';
4955 }
4956
4957 return level;
4958}
4959
9009cc24
PP
4960struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
4961 int *retcode, bool force_omit_system_plugin_path,
8e765000 4962 bool force_omit_home_plugin_path,
8eee8ea2 4963 const bt_value *initial_plugin_paths)
9009cc24
PP
4964{
4965 struct bt_config *config = NULL;
9009cc24
PP
4966 int i;
4967 const char **command_argv = NULL;
4968 int command_argc = -1;
4969 const char *command_name = NULL;
9e503aa9 4970 char log_level = 'U';
9009cc24
PP
4971
4972 enum command_type {
4973 COMMAND_TYPE_NONE = -1,
4974 COMMAND_TYPE_RUN = 0,
4975 COMMAND_TYPE_CONVERT,
4976 COMMAND_TYPE_LIST_PLUGINS,
4977 COMMAND_TYPE_HELP,
4978 COMMAND_TYPE_QUERY,
4979 } command_type = COMMAND_TYPE_NONE;
4980
4981 *retcode = -1;
4982
4983 if (!initial_plugin_paths) {
ce141536 4984 initial_plugin_paths = bt_value_array_create();
9009cc24
PP
4985 if (!initial_plugin_paths) {
4986 *retcode = 1;
4987 goto end;
4988 }
4989 } else {
8c6884d9 4990 bt_value_get_ref(initial_plugin_paths);
9009cc24
PP
4991 }
4992
4993 if (argc <= 1) {
329e245b
PP
4994 print_version();
4995 puts("");
9009cc24
PP
4996 print_gen_usage(stdout);
4997 goto end;
4998 }
4999
5000 for (i = 1; i < argc; i++) {
5001 const char *cur_arg = argv[i];
9e503aa9 5002 const char *next_arg = i == (argc - 1) ? NULL : argv[i + 1];
9009cc24
PP
5003
5004 if (strcmp(cur_arg, "-d") == 0 ||
5005 strcmp(cur_arg, "--debug") == 0) {
9e503aa9 5006 log_level = 'V';
9009cc24
PP
5007 } else if (strcmp(cur_arg, "-v") == 0 ||
5008 strcmp(cur_arg, "--verbose") == 0) {
9e503aa9
PP
5009 if (log_level != 'V' && log_level != 'D') {
5010 /*
5011 * Legacy: do not override a previous
5012 * --debug because --verbose and --debug
5013 * can be specified together (in this
5014 * case we want the lowest log level to
5015 * apply, VERBOSE).
5016 */
5017 log_level = 'I';
5018 }
21b5b16a
PP
5019 } else if (strcmp(cur_arg, "--log-level") == 0 ||
5020 strcmp(cur_arg, "-l") == 0) {
9e503aa9
PP
5021 if (!next_arg) {
5022 printf_err("Missing log level value for --log-level option\n");
5023 *retcode = 1;
5024 goto end;
5025 }
5026
5027 log_level = log_level_from_arg(next_arg);
5028 if (log_level == 'U') {
5029 printf_err("Invalid argument for --log-level option:\n %s\n",
5030 next_arg);
5031 *retcode = 1;
5032 goto end;
5033 }
5034
5035 i++;
5036 } else if (strncmp(cur_arg, "--log-level=", 12) == 0) {
5037 const char *arg = &cur_arg[12];
5038
21b5b16a
PP
5039 log_level = log_level_from_arg(arg);
5040 if (log_level == 'U') {
5041 printf_err("Invalid argument for --log-level option:\n %s\n",
5042 arg);
5043 *retcode = 1;
5044 goto end;
5045 }
5046 } else if (strncmp(cur_arg, "-l", 2) == 0) {
5047 const char *arg = &cur_arg[2];
5048
9e503aa9
PP
5049 log_level = log_level_from_arg(arg);
5050 if (log_level == 'U') {
5051 printf_err("Invalid argument for --log-level option:\n %s\n",
5052 arg);
5053 *retcode = 1;
5054 goto end;
5055 }
9009cc24
PP
5056 } else if (strcmp(cur_arg, "-V") == 0 ||
5057 strcmp(cur_arg, "--version") == 0) {
5058 print_version();
5059 goto end;
5060 } else if (strcmp(cur_arg, "-h") == 0 ||
5061 strcmp(cur_arg, "--help") == 0) {
5062 print_gen_usage(stdout);
5063 goto end;
5064 } else {
9009cc24
PP
5065 /*
5066 * First unknown argument: is it a known command
5067 * name?
5068 */
9e503aa9
PP
5069 command_argv = &argv[i];
5070 command_argc = argc - i;
5071
9009cc24
PP
5072 if (strcmp(cur_arg, "convert") == 0) {
5073 command_type = COMMAND_TYPE_CONVERT;
5074 } else if (strcmp(cur_arg, "list-plugins") == 0) {
5075 command_type = COMMAND_TYPE_LIST_PLUGINS;
5076 } else if (strcmp(cur_arg, "help") == 0) {
5077 command_type = COMMAND_TYPE_HELP;
5078 } else if (strcmp(cur_arg, "query") == 0) {
5079 command_type = COMMAND_TYPE_QUERY;
5080 } else if (strcmp(cur_arg, "run") == 0) {
5081 command_type = COMMAND_TYPE_RUN;
5082 } else {
5083 /*
5084 * Unknown argument, but not a known
9e503aa9
PP
5085 * command name: assume the default
5086 * `convert` command.
9009cc24
PP
5087 */
5088 command_type = COMMAND_TYPE_CONVERT;
9e503aa9
PP
5089 command_name = "convert";
5090 command_argv = &argv[i - 1];
5091 command_argc = argc - i + 1;
9009cc24
PP
5092 }
5093 break;
5094 }
5095 }
5096
5097 if (command_type == COMMAND_TYPE_NONE) {
5098 /*
5099 * We only got non-help, non-version general options
5100 * like --verbose and --debug, without any other
5101 * arguments, so we can't do anything useful: print the
5102 * usage and quit.
5103 */
5104 print_gen_usage(stdout);
5105 goto end;
5106 }
5107
8b45963b
PP
5108 BT_ASSERT(command_argv);
5109 BT_ASSERT(command_argc >= 0);
9009cc24
PP
5110
5111 switch (command_type) {
5112 case COMMAND_TYPE_RUN:
5113 config = bt_config_run_from_args(command_argc, command_argv,
5114 retcode, force_omit_system_plugin_path,
5115 force_omit_home_plugin_path, initial_plugin_paths);
5116 break;
5117 case COMMAND_TYPE_CONVERT:
5118 config = bt_config_convert_from_args(command_argc, command_argv,
5119 retcode, force_omit_system_plugin_path,
8e765000 5120 force_omit_home_plugin_path,
9e503aa9 5121 initial_plugin_paths, &log_level);
9009cc24
PP
5122 break;
5123 case COMMAND_TYPE_LIST_PLUGINS:
5124 config = bt_config_list_plugins_from_args(command_argc,
5125 command_argv, retcode, force_omit_system_plugin_path,
5126 force_omit_home_plugin_path, initial_plugin_paths);
5127 break;
5128 case COMMAND_TYPE_HELP:
5129 config = bt_config_help_from_args(command_argc,
5130 command_argv, retcode, force_omit_system_plugin_path,
5131 force_omit_home_plugin_path, initial_plugin_paths);
5132 break;
5133 case COMMAND_TYPE_QUERY:
5134 config = bt_config_query_from_args(command_argc,
5135 command_argv, retcode, force_omit_system_plugin_path,
5136 force_omit_home_plugin_path, initial_plugin_paths);
5137 break;
5138 default:
0fbb9a9f 5139 abort();
9009cc24
PP
5140 }
5141
5142 if (config) {
9e503aa9
PP
5143 if (log_level == 'U') {
5144 log_level = 'W';
9009cc24
PP
5145 }
5146
9e503aa9 5147 config->log_level = log_level;
9009cc24
PP
5148 config->command_name = command_name;
5149 }
5150
5151end:
8c6884d9 5152 bt_value_put_ref(initial_plugin_paths);
9009cc24
PP
5153 return config;
5154}
This page took 0.276414 seconds and 4 git commands to generate.