2 * Babeltrace trace converter - parameter parsing
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
32 #include <babeltrace/babeltrace.h>
33 #include <babeltrace/common-internal.h>
34 #include <babeltrace/values.h>
37 #include <sys/types.h>
39 #include "babeltrace-cfg.h"
40 #include "babeltrace-cfg-connect.h"
42 #define DEFAULT_SOURCE_COMPONENT_NAME "ctf.fs"
43 #define DEFAULT_SINK_COMPONENT_NAME "text.text"
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.
51 #define printf_err(fmt, args...) \
53 if (is_first_error) { \
54 fprintf(stderr, "Error: "); \
55 is_first_error = false; \
57 fprintf(stderr, fmt, ##args); \
60 static bool is_first_error
= true;
62 /* INI-style parsing FSM states */
63 enum ini_parsing_fsm_state
{
64 /* Expect a map key (identifier) */
67 /* Expect an equal character ('=') */
73 /* Expect a negative number value */
74 INI_EXPECT_VALUE_NUMBER_NEG
,
76 /* Expect a comma character (',') */
80 /* INI-style parsing state variables */
81 struct ini_parsing_state
{
82 /* Lexical scanner (owned by this) */
85 /* Output map value object being filled (owned by this) */
86 struct bt_value
*params
;
88 /* Next expected FSM state */
89 enum ini_parsing_fsm_state expecting
;
91 /* Last decoded map key (owned by this) */
94 /* Complete INI-style string to parse (not owned by this) */
97 /* Error buffer (not owned by this) */
101 /* Offset option with "is set" boolean */
107 /* Legacy "ctf"/"lttng-live" format options */
108 struct ctf_legacy_opts
{
109 struct offset_opt offset_s
;
110 struct offset_opt offset_ns
;
111 bool stream_intersection
;
114 /* Legacy "text" format options */
115 struct text_legacy_opts
{
117 * output, dbg_info_dir, dbg_info_target_prefix, names,
118 * and fields are owned by this.
121 GString
*dbg_info_dir
;
122 GString
*dbg_info_target_prefix
;
123 struct bt_value
*names
;
124 struct bt_value
*fields
;
132 bool dbg_info_full_path
;
135 /* Legacy input format format */
136 enum legacy_input_format
{
137 LEGACY_INPUT_FORMAT_NONE
= 0,
138 LEGACY_INPUT_FORMAT_CTF
,
139 LEGACY_INPUT_FORMAT_LTTNG_LIVE
,
142 /* Legacy output format format */
143 enum legacy_output_format
{
144 LEGACY_OUTPUT_FORMAT_NONE
= 0,
145 LEGACY_OUTPUT_FORMAT_TEXT
,
146 LEGACY_OUTPUT_FORMAT_DUMMY
,
150 * Prints the "out of memory" error.
153 void print_err_oom(void)
155 printf_err("Out of memory\n");
159 * Prints duplicate legacy output format error.
162 void print_err_dup_legacy_output(void)
164 printf_err("More than one legacy output format specified\n");
168 * Prints duplicate legacy input format error.
171 void print_err_dup_legacy_input(void)
173 printf_err("More than one legacy input format specified\n");
177 * Checks if any of the "text" legacy options is set.
180 bool text_legacy_opts_is_any_set(struct text_legacy_opts
*opts
)
182 return (opts
->output
&& opts
->output
->len
> 0) ||
183 (opts
->dbg_info_dir
&& opts
->dbg_info_dir
->len
> 0) ||
184 (opts
->dbg_info_target_prefix
&&
185 opts
->dbg_info_target_prefix
->len
> 0) ||
186 bt_value_array_size(opts
->names
) > 0 ||
187 bt_value_array_size(opts
->fields
) > 0 ||
188 opts
->no_delta
|| opts
->clock_cycles
|| opts
->clock_seconds
||
189 opts
->clock_date
|| opts
->clock_gmt
||
190 opts
->dbg_info_full_path
;
194 * Checks if any of the "ctf" legacy options is set.
197 bool ctf_legacy_opts_is_any_set(struct ctf_legacy_opts
*opts
)
199 return opts
->offset_s
.is_set
|| opts
->offset_ns
.is_set
||
200 opts
->stream_intersection
;
204 * Appends an "expecting token" error to the INI-style parsing state's
208 void ini_append_error_expecting(struct ini_parsing_state
*state
,
209 GScanner
*scanner
, const char *expecting
)
214 g_string_append_printf(state
->ini_error
, "Expecting %s:\n", expecting
);
216 /* Only print error if there's one line */
217 if (strchr(state
->arg
, '\n') != NULL
|| strlen(state
->arg
) == 0) {
221 g_string_append_printf(state
->ini_error
, "\n %s\n", state
->arg
);
222 pos
= g_scanner_cur_position(scanner
) + 4;
224 if (!g_scanner_eof(scanner
)) {
228 for (i
= 0; i
< pos
; ++i
) {
229 g_string_append_printf(state
->ini_error
, " ");
232 g_string_append_printf(state
->ini_error
, "^\n\n");
236 int ini_handle_state(struct ini_parsing_state
*state
)
239 GTokenType token_type
;
240 struct bt_value
*value
= NULL
;
242 token_type
= g_scanner_get_next_token(state
->scanner
);
243 if (token_type
== G_TOKEN_EOF
) {
244 if (state
->expecting
!= INI_EXPECT_COMMA
) {
245 switch (state
->expecting
) {
246 case INI_EXPECT_EQUAL
:
247 ini_append_error_expecting(state
,
248 state
->scanner
, "'='");
250 case INI_EXPECT_VALUE
:
251 case INI_EXPECT_VALUE_NUMBER_NEG
:
252 ini_append_error_expecting(state
,
253 state
->scanner
, "value");
255 case INI_EXPECT_MAP_KEY
:
256 ini_append_error_expecting(state
,
257 state
->scanner
, "unquoted map key");
270 switch (state
->expecting
) {
271 case INI_EXPECT_MAP_KEY
:
272 if (token_type
!= G_TOKEN_IDENTIFIER
) {
273 ini_append_error_expecting(state
, state
->scanner
,
278 free(state
->last_map_key
);
279 state
->last_map_key
=
280 strdup(state
->scanner
->value
.v_identifier
);
281 if (!state
->last_map_key
) {
282 g_string_append(state
->ini_error
,
287 if (bt_value_map_has_key(state
->params
, state
->last_map_key
)) {
288 g_string_append_printf(state
->ini_error
,
289 "Duplicate parameter key: `%s`\n",
290 state
->last_map_key
);
294 state
->expecting
= INI_EXPECT_EQUAL
;
296 case INI_EXPECT_EQUAL
:
297 if (token_type
!= G_TOKEN_CHAR
) {
298 ini_append_error_expecting(state
,
299 state
->scanner
, "'='");
303 if (state
->scanner
->value
.v_char
!= '=') {
304 ini_append_error_expecting(state
,
305 state
->scanner
, "'='");
309 state
->expecting
= INI_EXPECT_VALUE
;
311 case INI_EXPECT_VALUE
:
313 switch (token_type
) {
315 if (state
->scanner
->value
.v_char
== '-') {
316 /* Negative number */
318 INI_EXPECT_VALUE_NUMBER_NEG
;
321 ini_append_error_expecting(state
,
322 state
->scanner
, "value");
328 /* Positive integer */
329 uint64_t int_val
= state
->scanner
->value
.v_int64
;
331 if (int_val
> (1ULL << 63) - 1) {
332 g_string_append_printf(state
->ini_error
,
333 "Integer value %" PRIu64
" is outside the range of a 64-bit signed integer\n",
338 value
= bt_value_integer_create_init(
343 /* Positive floating point number */
344 value
= bt_value_float_create_init(
345 state
->scanner
->value
.v_float
);
349 value
= bt_value_string_create_init(
350 state
->scanner
->value
.v_string
);
352 case G_TOKEN_IDENTIFIER
:
355 * Using symbols would be appropriate here,
356 * but said symbols are allowed as map key,
357 * so it's easier to consider everything an
360 * If one of the known symbols is not
361 * recognized here, then fall back to creating
364 const char *id
= state
->scanner
->value
.v_identifier
;
366 if (!strcmp(id
, "null") || !strcmp(id
, "NULL") ||
367 !strcmp(id
, "nul")) {
368 value
= bt_value_null
;
369 } else if (!strcmp(id
, "true") || !strcmp(id
, "TRUE") ||
370 !strcmp(id
, "yes") ||
371 !strcmp(id
, "YES")) {
372 value
= bt_value_bool_create_init(true);
373 } else if (!strcmp(id
, "false") ||
374 !strcmp(id
, "FALSE") ||
377 value
= bt_value_bool_create_init(false);
379 value
= bt_value_string_create_init(id
);
384 /* Unset value variable will trigger the error */
389 ini_append_error_expecting(state
,
390 state
->scanner
, "value");
394 state
->expecting
= INI_EXPECT_COMMA
;
397 case INI_EXPECT_VALUE_NUMBER_NEG
:
399 switch (token_type
) {
402 /* Negative integer */
403 uint64_t int_val
= state
->scanner
->value
.v_int64
;
405 if (int_val
> (1ULL << 63) - 1) {
406 g_string_append_printf(state
->ini_error
,
407 "Integer value -%" PRIu64
" is outside the range of a 64-bit signed integer\n",
412 value
= bt_value_integer_create_init(
413 -((int64_t) int_val
));
417 /* Negative floating point number */
418 value
= bt_value_float_create_init(
419 -state
->scanner
->value
.v_float
);
422 /* Unset value variable will trigger the error */
427 ini_append_error_expecting(state
,
428 state
->scanner
, "value");
432 state
->expecting
= INI_EXPECT_COMMA
;
435 case INI_EXPECT_COMMA
:
436 if (token_type
!= G_TOKEN_CHAR
) {
437 ini_append_error_expecting(state
,
438 state
->scanner
, "','");
442 if (state
->scanner
->value
.v_char
!= ',') {
443 ini_append_error_expecting(state
,
444 state
->scanner
, "','");
448 state
->expecting
= INI_EXPECT_MAP_KEY
;
460 if (bt_value_map_insert(state
->params
,
461 state
->last_map_key
, value
)) {
462 /* Only override return value on error */
473 * Converts an INI-style argument to an equivalent map value object.
475 * Return value is owned by the caller.
478 struct bt_value
*bt_value_from_ini(const char *arg
, GString
*ini_error
)
480 /* Lexical scanner configuration */
481 GScannerConfig scanner_config
= {
482 /* Skip whitespaces */
483 .cset_skip_characters
= " \t\n",
485 /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
486 .cset_identifier_first
=
490 .cset_identifier_nth
=
495 /* "hello" and "Hello" two different keys */
496 .case_sensitive
= TRUE
,
499 .cpair_comment_single
= NULL
,
500 .skip_comment_multi
= TRUE
,
501 .skip_comment_single
= TRUE
,
502 .scan_comment_multi
= FALSE
,
505 * Do scan identifiers, including 1-char identifiers,
506 * but NULL is a normal identifier.
508 .scan_identifier
= TRUE
,
509 .scan_identifier_1char
= TRUE
,
510 .scan_identifier_NULL
= FALSE
,
513 * No specific symbols: null and boolean "symbols" are
514 * scanned as plain identifiers.
516 .scan_symbols
= FALSE
,
517 .symbol_2_token
= FALSE
,
518 .scope_0_fallback
= FALSE
,
521 * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
522 * integers prefixed with "$".
528 .scan_hex_dollar
= FALSE
,
530 /* Convert scanned numbers to integer tokens */
531 .numbers_2_int
= TRUE
,
533 /* Support both integers and floating-point numbers */
534 .int_2_float
= FALSE
,
536 /* Scan integers as 64-bit signed integers */
539 /* Only scan double-quoted strings */
540 .scan_string_sq
= FALSE
,
541 .scan_string_dq
= TRUE
,
543 /* Do not converter identifiers to string tokens */
544 .identifier_2_string
= FALSE
,
546 /* Scan characters as G_TOKEN_CHAR token */
547 .char_2_token
= FALSE
,
549 struct ini_parsing_state state
= {
552 .expecting
= INI_EXPECT_MAP_KEY
,
554 .ini_error
= ini_error
,
557 state
.params
= bt_value_map_create();
562 state
.scanner
= g_scanner_new(&scanner_config
);
563 if (!state
.scanner
) {
567 /* Let the scan begin */
568 g_scanner_input_text(state
.scanner
, arg
, strlen(arg
));
571 int ret
= ini_handle_state(&state
);
576 } else if (ret
> 0) {
585 BT_PUT(state
.params
);
589 g_scanner_destroy(state
.scanner
);
592 free(state
.last_map_key
);
597 * Returns the parameters map value object from a command-line
598 * parameter option's argument.
600 * Return value is owned by the caller.
603 struct bt_value
*bt_value_from_arg(const char *arg
)
605 struct bt_value
*params
= NULL
;
606 GString
*ini_error
= NULL
;
608 ini_error
= g_string_new(NULL
);
614 /* Try INI-style parsing */
615 params
= bt_value_from_ini(arg
, ini_error
);
617 printf_err("%s", ini_error
->str
);
623 g_string_free(ini_error
, TRUE
);
629 * Returns the plugin and component names from a command-line
630 * source/sink option's argument. arg must have the following format:
634 * where PLUGIN is the plugin name, and COMPONENT is the component
637 * On success, both *plugin and *component are not NULL. *plugin
638 * and *component are owned by the caller.
641 void plugin_component_names_from_arg(const char *arg
, char **plugin
,
647 size_t component_len
;
649 /* Initialize both return values to NULL: not found */
653 dot
= strchr(arg
, '.');
659 end
= arg
+ strlen(arg
);
660 plugin_len
= dot
- arg
;
661 component_len
= end
- dot
- 1;
662 if (plugin_len
== 0 || component_len
== 0) {
666 *plugin
= g_malloc0(plugin_len
+ 1);
672 g_strlcpy(*plugin
, arg
, plugin_len
+ 1);
673 *component
= g_malloc0(component_len
+ 1);
679 g_strlcpy(*component
, dot
+ 1, component_len
+ 1);
686 * Prints the Babeltrace version.
689 void print_version(void)
691 puts("Babeltrace " VERSION
);
695 * Destroys a component configuration.
698 void bt_config_component_destroy(struct bt_object
*obj
)
700 struct bt_config_component
*bt_config_component
=
701 container_of(obj
, struct bt_config_component
, base
);
707 if (bt_config_component
->plugin_name
) {
708 g_string_free(bt_config_component
->plugin_name
, TRUE
);
711 if (bt_config_component
->component_name
) {
712 g_string_free(bt_config_component
->component_name
, TRUE
);
715 if (bt_config_component
->instance_name
) {
716 g_string_free(bt_config_component
->instance_name
, TRUE
);
719 BT_PUT(bt_config_component
->params
);
720 g_free(bt_config_component
);
727 * Creates a component configuration using the given plugin name and
728 * component name. plugin_name and component_name are copied (belong to
731 * Return value is owned by the caller.
734 struct bt_config_component
*bt_config_component_create(
735 enum bt_component_class_type type
,
736 const char *plugin_name
, const char *component_name
)
738 struct bt_config_component
*cfg_component
= NULL
;
740 cfg_component
= g_new0(struct bt_config_component
, 1);
741 if (!cfg_component
) {
746 bt_object_init(cfg_component
, bt_config_component_destroy
);
747 cfg_component
->type
= type
;
748 cfg_component
->plugin_name
= g_string_new(plugin_name
);
749 if (!cfg_component
->plugin_name
) {
754 cfg_component
->component_name
= g_string_new(component_name
);
755 if (!cfg_component
->component_name
) {
760 cfg_component
->instance_name
= g_string_new(NULL
);
761 if (!cfg_component
->instance_name
) {
766 /* Start with empty parameters */
767 cfg_component
->params
= bt_value_map_create();
768 if (!cfg_component
->params
) {
776 BT_PUT(cfg_component
);
779 return cfg_component
;
783 * Creates a component configuration from a command-line source/sink
786 struct bt_config_component
*bt_config_component_from_arg(
787 enum bt_component_class_type type
, const char *arg
)
789 struct bt_config_component
*bt_config_component
= NULL
;
791 char *component_name
;
793 plugin_component_names_from_arg(arg
, &plugin_name
, &component_name
);
794 if (!plugin_name
|| !component_name
) {
795 printf_err("Cannot get plugin or component class name\n");
799 bt_config_component
= bt_config_component_create(type
, plugin_name
,
801 if (!bt_config_component
) {
808 BT_PUT(bt_config_component
);
812 g_free(component_name
);
813 return bt_config_component
;
817 * Destroys a configuration.
820 void bt_config_destroy(struct bt_object
*obj
)
822 struct bt_config
*cfg
=
823 container_of(obj
, struct bt_config
, base
);
829 switch (cfg
->command
) {
830 case BT_CONFIG_COMMAND_CONVERT
:
831 if (cfg
->cmd_data
.convert
.sources
) {
832 g_ptr_array_free(cfg
->cmd_data
.convert
.sources
, TRUE
);
835 if (cfg
->cmd_data
.convert
.filters
) {
836 g_ptr_array_free(cfg
->cmd_data
.convert
.filters
, TRUE
);
839 if (cfg
->cmd_data
.convert
.sinks
) {
840 g_ptr_array_free(cfg
->cmd_data
.convert
.sinks
, TRUE
);
843 if (cfg
->cmd_data
.convert
.connections
) {
844 g_ptr_array_free(cfg
->cmd_data
.convert
.connections
,
848 BT_PUT(cfg
->cmd_data
.convert
.plugin_paths
);
850 case BT_CONFIG_COMMAND_LIST_PLUGINS
:
851 BT_PUT(cfg
->cmd_data
.list_plugins
.plugin_paths
);
853 case BT_CONFIG_COMMAND_HELP
:
854 BT_PUT(cfg
->cmd_data
.help
.plugin_paths
);
855 BT_PUT(cfg
->cmd_data
.help
.cfg_component
);
857 case BT_CONFIG_COMMAND_QUERY_INFO
:
858 BT_PUT(cfg
->cmd_data
.query_info
.plugin_paths
);
859 BT_PUT(cfg
->cmd_data
.query_info
.cfg_component
);
861 if (cfg
->cmd_data
.query_info
.action
) {
862 g_string_free(cfg
->cmd_data
.query_info
.action
, TRUE
);
875 static void destroy_gstring(void *data
)
877 g_string_free(data
, TRUE
);
881 * Extracts the various paths from the string arg, delimited by ':',
882 * and appends them to the array value object plugin_paths.
884 enum bt_value_status
bt_config_append_plugin_paths(
885 struct bt_value
*plugin_paths
, const char *arg
)
887 enum bt_value_status status
= BT_VALUE_STATUS_OK
;
888 GPtrArray
*dirs
= g_ptr_array_new_with_free_func(destroy_gstring
);
893 status
= BT_VALUE_STATUS_ERROR
;
897 ret
= bt_common_append_plugin_path_dirs(arg
, dirs
);
899 status
= BT_VALUE_STATUS_ERROR
;
903 for (i
= 0; i
< dirs
->len
; i
++) {
904 GString
*dir
= g_ptr_array_index(dirs
, i
);
906 bt_value_array_append_string(plugin_paths
, dir
->str
);
910 g_ptr_array_free(dirs
, TRUE
);
915 * Creates a simple lexical scanner for parsing comma-delimited names
918 * Return value is owned by the caller.
921 GScanner
*create_csv_identifiers_scanner(void)
923 GScannerConfig scanner_config
= {
924 .cset_skip_characters
= " \t\n",
925 .cset_identifier_first
= G_CSET_a_2_z G_CSET_A_2_Z
"_",
926 .cset_identifier_nth
= G_CSET_a_2_z G_CSET_A_2_Z
":_-",
927 .case_sensitive
= TRUE
,
928 .cpair_comment_single
= NULL
,
929 .skip_comment_multi
= TRUE
,
930 .skip_comment_single
= TRUE
,
931 .scan_comment_multi
= FALSE
,
932 .scan_identifier
= TRUE
,
933 .scan_identifier_1char
= TRUE
,
934 .scan_identifier_NULL
= FALSE
,
935 .scan_symbols
= FALSE
,
936 .symbol_2_token
= FALSE
,
937 .scope_0_fallback
= FALSE
,
938 .scan_binary
= FALSE
,
942 .scan_hex_dollar
= FALSE
,
943 .numbers_2_int
= FALSE
,
944 .int_2_float
= FALSE
,
945 .store_int64
= FALSE
,
946 .scan_string_sq
= FALSE
,
947 .scan_string_dq
= FALSE
,
948 .identifier_2_string
= FALSE
,
949 .char_2_token
= TRUE
,
952 return g_scanner_new(&scanner_config
);
956 * Inserts a string (if exists and not empty) or null to a map value
960 enum bt_value_status
map_insert_string_or_null(struct bt_value
*map
,
961 const char *key
, GString
*string
)
963 enum bt_value_status ret
;
965 if (string
&& string
->len
> 0) {
966 ret
= bt_value_map_insert_string(map
, key
, string
->str
);
968 ret
= bt_value_map_insert(map
, key
, bt_value_null
);
974 * Converts a comma-delimited list of known names (--names option) to
975 * an array value object containing those names as string value objects.
977 * Return value is owned by the caller.
980 struct bt_value
*names_from_arg(const char *arg
)
982 GScanner
*scanner
= NULL
;
983 struct bt_value
*names
= NULL
;
984 bool found_all
= false, found_none
= false, found_item
= false;
986 names
= bt_value_array_create();
992 scanner
= create_csv_identifiers_scanner();
998 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1001 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1003 switch (token_type
) {
1004 case G_TOKEN_IDENTIFIER
:
1006 const char *identifier
= scanner
->value
.v_identifier
;
1008 if (!strcmp(identifier
, "payload") ||
1009 !strcmp(identifier
, "args") ||
1010 !strcmp(identifier
, "arg")) {
1012 if (bt_value_array_append_string(names
,
1016 } else if (!strcmp(identifier
, "context") ||
1017 !strcmp(identifier
, "ctx")) {
1019 if (bt_value_array_append_string(names
,
1023 } else if (!strcmp(identifier
, "scope") ||
1024 !strcmp(identifier
, "header")) {
1026 if (bt_value_array_append_string(names
,
1030 } else if (!strcmp(identifier
, "all")) {
1032 if (bt_value_array_append_string(names
,
1036 } else if (!strcmp(identifier
, "none")) {
1038 if (bt_value_array_append_string(names
,
1043 printf_err("Unknown field name: `%s`\n",
1059 if (found_none
&& found_all
) {
1060 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
1064 * Legacy behavior is to clear the defaults (show none) when at
1065 * least one item is specified.
1067 if (found_item
&& !found_none
&& !found_all
) {
1068 if (bt_value_array_append_string(names
, "none")) {
1073 g_scanner_destroy(scanner
);
1080 g_scanner_destroy(scanner
);
1087 * Converts a comma-delimited list of known fields (--fields option) to
1088 * an array value object containing those fields as string
1091 * Return value is owned by the caller.
1094 struct bt_value
*fields_from_arg(const char *arg
)
1096 GScanner
*scanner
= NULL
;
1097 struct bt_value
*fields
;
1099 fields
= bt_value_array_create();
1105 scanner
= create_csv_identifiers_scanner();
1111 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1114 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1116 switch (token_type
) {
1117 case G_TOKEN_IDENTIFIER
:
1119 const char *identifier
= scanner
->value
.v_identifier
;
1121 if (!strcmp(identifier
, "trace") ||
1122 !strcmp(identifier
, "trace:hostname") ||
1123 !strcmp(identifier
, "trace:domain") ||
1124 !strcmp(identifier
, "trace:procname") ||
1125 !strcmp(identifier
, "trace:vpid") ||
1126 !strcmp(identifier
, "loglevel") ||
1127 !strcmp(identifier
, "emf") ||
1128 !strcmp(identifier
, "callsite") ||
1129 !strcmp(identifier
, "all")) {
1130 if (bt_value_array_append_string(fields
,
1135 printf_err("Unknown field name: `%s`\n",
1157 g_scanner_destroy(scanner
);
1163 * Inserts the equivalent "prefix-name" true boolean value objects into
1164 * map_obj where the names are in array_obj.
1167 int insert_flat_names_fields_from_array(struct bt_value
*map_obj
,
1168 struct bt_value
*array_obj
, const char *prefix
)
1172 GString
*tmpstr
= NULL
, *default_value
= NULL
;
1175 * array_obj may be NULL if no CLI options were specified to
1176 * trigger its creation.
1182 tmpstr
= g_string_new(NULL
);
1189 default_value
= g_string_new(NULL
);
1190 if (!default_value
) {
1196 for (i
= 0; i
< bt_value_array_size(array_obj
); i
++) {
1197 struct bt_value
*str_obj
= bt_value_array_get(array_obj
, i
);
1199 bool is_default
= false;
1202 printf_err("Unexpected error\n");
1207 ret
= bt_value_string_get(str_obj
, &suffix
);
1210 printf_err("Unexpected error\n");
1214 g_string_assign(tmpstr
, prefix
);
1215 g_string_append(tmpstr
, "-");
1217 /* Special-case for "all" and "none". */
1218 if (!strcmp(suffix
, "all")) {
1220 g_string_assign(default_value
, "show");
1221 } else if (!strcmp(suffix
, "none")) {
1223 g_string_assign(default_value
, "hide");
1226 g_string_append(tmpstr
, "default");
1227 ret
= map_insert_string_or_null(map_obj
,
1235 g_string_append(tmpstr
, suffix
);
1236 ret
= bt_value_map_insert_bool(map_obj
, tmpstr
->str
,
1246 if (default_value
) {
1247 g_string_free(default_value
, TRUE
);
1250 g_string_free(tmpstr
, TRUE
);
1257 * Returns the parameters (map value object) corresponding to the
1258 * legacy text format options.
1260 * Return value is owned by the caller.
1263 struct bt_value
*params_from_text_legacy_opts(
1264 struct text_legacy_opts
*text_legacy_opts
)
1266 struct bt_value
*params
;
1268 params
= bt_value_map_create();
1274 if (map_insert_string_or_null(params
, "output-path",
1275 text_legacy_opts
->output
)) {
1280 if (map_insert_string_or_null(params
, "debug-info-dir",
1281 text_legacy_opts
->dbg_info_dir
)) {
1286 if (map_insert_string_or_null(params
, "debug-info-target-prefix",
1287 text_legacy_opts
->dbg_info_target_prefix
)) {
1292 if (bt_value_map_insert_bool(params
, "debug-info-full-path",
1293 text_legacy_opts
->dbg_info_full_path
)) {
1298 if (bt_value_map_insert_bool(params
, "no-delta",
1299 text_legacy_opts
->no_delta
)) {
1304 if (bt_value_map_insert_bool(params
, "clock-cycles",
1305 text_legacy_opts
->clock_cycles
)) {
1310 if (bt_value_map_insert_bool(params
, "clock-seconds",
1311 text_legacy_opts
->clock_seconds
)) {
1316 if (bt_value_map_insert_bool(params
, "clock-date",
1317 text_legacy_opts
->clock_date
)) {
1322 if (bt_value_map_insert_bool(params
, "clock-gmt",
1323 text_legacy_opts
->clock_gmt
)) {
1328 if (insert_flat_names_fields_from_array(params
,
1329 text_legacy_opts
->names
, "name")) {
1333 if (insert_flat_names_fields_from_array(params
,
1334 text_legacy_opts
->fields
, "field")) {
1348 int append_sinks_from_legacy_opts(GPtrArray
*sinks
,
1349 enum legacy_output_format legacy_output_format
,
1350 struct text_legacy_opts
*text_legacy_opts
)
1353 struct bt_value
*params
= NULL
;
1354 const char *plugin_name
;
1355 const char *component_name
;
1356 struct bt_config_component
*bt_config_component
= NULL
;
1358 switch (legacy_output_format
) {
1359 case LEGACY_OUTPUT_FORMAT_TEXT
:
1360 plugin_name
= "text";
1361 component_name
= "text";
1363 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1364 plugin_name
= "utils";
1365 component_name
= "dummy";
1372 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
) {
1373 /* Legacy "text" output format has parameters */
1374 params
= params_from_text_legacy_opts(text_legacy_opts
);
1380 * Legacy "dummy" and "ctf-metadata" output formats do
1381 * not have parameters.
1383 params
= bt_value_map_create();
1390 /* Create a component configuration */
1391 bt_config_component
= bt_config_component_create(
1392 BT_COMPONENT_CLASS_TYPE_SINK
, plugin_name
, component_name
);
1393 if (!bt_config_component
) {
1397 BT_MOVE(bt_config_component
->params
, params
);
1399 /* Move created component configuration to the array */
1400 g_ptr_array_add(sinks
, bt_config_component
);
1414 * Returns the parameters (map value object) corresponding to the
1415 * given legacy CTF format options.
1417 * Return value is owned by the caller.
1420 struct bt_value
*params_from_ctf_legacy_opts(
1421 struct ctf_legacy_opts
*ctf_legacy_opts
)
1423 struct bt_value
*params
;
1425 params
= bt_value_map_create();
1431 if (bt_value_map_insert_integer(params
, "offset-s",
1432 ctf_legacy_opts
->offset_s
.value
)) {
1437 if (bt_value_map_insert_integer(params
, "offset-ns",
1438 ctf_legacy_opts
->offset_ns
.value
)) {
1443 if (bt_value_map_insert_bool(params
, "stream-intersection",
1444 ctf_legacy_opts
->stream_intersection
)) {
1459 int append_sources_from_legacy_opts(GPtrArray
*sources
,
1460 enum legacy_input_format legacy_input_format
,
1461 struct ctf_legacy_opts
*ctf_legacy_opts
,
1462 struct bt_value
*legacy_input_paths
)
1466 struct bt_value
*base_params
;
1467 struct bt_value
*params
= NULL
;
1468 struct bt_value
*input_path
= NULL
;
1469 struct bt_value
*input_path_copy
= NULL
;
1470 const char *input_key
;
1471 const char *component_name
;
1473 switch (legacy_input_format
) {
1474 case LEGACY_INPUT_FORMAT_CTF
:
1476 component_name
= "fs";
1478 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1480 component_name
= "lttng-live";
1487 base_params
= params_from_ctf_legacy_opts(ctf_legacy_opts
);
1492 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1493 struct bt_config_component
*bt_config_component
= NULL
;
1495 /* Copy base parameters as current parameters */
1496 params
= bt_value_copy(base_params
);
1501 /* Get current input path string value object */
1502 input_path
= bt_value_array_get(legacy_input_paths
, i
);
1507 /* Copy current input path value object */
1508 input_path_copy
= bt_value_copy(input_path
);
1509 if (!input_path_copy
) {
1513 /* Insert input path value object into current parameters */
1514 ret
= bt_value_map_insert(params
, input_key
, input_path_copy
);
1519 /* Create a component configuration */
1520 bt_config_component
= bt_config_component_create(
1521 BT_COMPONENT_CLASS_TYPE_SOURCE
, "ctf", component_name
);
1522 if (!bt_config_component
) {
1526 BT_MOVE(bt_config_component
->params
, params
);
1528 /* Move created component configuration to the array */
1529 g_ptr_array_add(sources
, bt_config_component
);
1531 /* Put current stuff */
1533 BT_PUT(input_path_copy
);
1542 BT_PUT(base_params
);
1545 BT_PUT(input_path_copy
);
1550 * Escapes a string for the shell. The string is escaped knowing that
1551 * it's a parameter string value (double-quoted), and that it will be
1552 * entered between single quotes in the shell.
1554 * Return value is owned by the caller.
1557 char *str_shell_escape(const char *input
)
1560 const char *at
= input
;
1561 GString
*str
= g_string_new(NULL
);
1567 while (*at
!= '\0') {
1570 g_string_append(str
, "\\\\");
1573 g_string_append(str
, "\\\"");
1576 g_string_append(str
, "'\"'\"'");
1579 g_string_append(str
, "\\n");
1582 g_string_append(str
, "\\t");
1585 g_string_append_c(str
, *at
);
1595 g_string_free(str
, FALSE
);
1602 int append_prefixed_flag_params(GString
*str
, struct bt_value
*flags
,
1612 for (i
= 0; i
< bt_value_array_size(flags
); i
++) {
1613 struct bt_value
*value
= bt_value_array_get(flags
, i
);
1621 if (bt_value_string_get(value
, &flag
)) {
1627 g_string_append_printf(str
, ",%s-%s=true", prefix
, flag
);
1636 * Appends a boolean parameter string.
1639 void g_string_append_bool_param(GString
*str
, const char *name
, bool value
)
1641 g_string_append_printf(str
, ",%s=%s", name
, value
? "true" : "false");
1645 * Appends a path parameter string, or null if it's empty.
1648 int g_string_append_string_path_param(GString
*str
, const char *name
,
1653 if (path
->len
> 0) {
1654 char *escaped_path
= str_shell_escape(path
->str
);
1656 if (!escaped_path
) {
1661 g_string_append_printf(str
, "%s=\"%s\"", name
, escaped_path
);
1664 g_string_append_printf(str
, "%s=null", name
);
1677 * Prints the non-legacy sink options equivalent to the specified
1678 * legacy output format options.
1681 void print_output_legacy_to_sinks(
1682 enum legacy_output_format legacy_output_format
,
1683 struct text_legacy_opts
*text_legacy_opts
)
1685 const char *output_format
;
1686 GString
*str
= NULL
;
1688 str
= g_string_new(" ");
1694 switch (legacy_output_format
) {
1695 case LEGACY_OUTPUT_FORMAT_TEXT
:
1696 output_format
= "text";
1698 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1699 output_format
= "dummy";
1705 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
1707 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
1709 g_string_append(str
, "-o ");
1711 switch (legacy_output_format
) {
1712 case LEGACY_OUTPUT_FORMAT_TEXT
:
1713 g_string_append(str
, "text.text");
1715 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1716 g_string_append(str
, "utils.dummy");
1722 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
&&
1723 text_legacy_opts_is_any_set(text_legacy_opts
)) {
1726 g_string_append(str
, " -p '");
1728 if (g_string_append_string_path_param(str
, "output-path",
1729 text_legacy_opts
->output
)) {
1733 g_string_append(str
, ",");
1735 if (g_string_append_string_path_param(str
, "debug-info-dir",
1736 text_legacy_opts
->dbg_info_dir
)) {
1740 g_string_append(str
, ",");
1742 if (g_string_append_string_path_param(str
,
1743 "debug-info-target-prefix",
1744 text_legacy_opts
->dbg_info_target_prefix
)) {
1748 g_string_append_bool_param(str
, "no-delta",
1749 text_legacy_opts
->no_delta
);
1750 g_string_append_bool_param(str
, "clock-cycles",
1751 text_legacy_opts
->clock_cycles
);
1752 g_string_append_bool_param(str
, "clock-seconds",
1753 text_legacy_opts
->clock_seconds
);
1754 g_string_append_bool_param(str
, "clock-date",
1755 text_legacy_opts
->clock_date
);
1756 g_string_append_bool_param(str
, "clock-gmt",
1757 text_legacy_opts
->clock_gmt
);
1758 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->names
,
1764 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->fields
,
1770 /* Remove last comma and close single quote */
1771 g_string_append(str
, "'");
1774 printf_err("%s\n\n", str
->str
);
1778 g_string_free(str
, TRUE
);
1784 * Prints the non-legacy source options equivalent to the specified
1785 * legacy input format options.
1788 void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format
,
1789 struct bt_value
*legacy_input_paths
,
1790 struct ctf_legacy_opts
*ctf_legacy_opts
)
1792 const char *input_format
;
1793 GString
*str
= NULL
;
1796 str
= g_string_new(" ");
1802 switch (legacy_input_format
) {
1803 case LEGACY_INPUT_FORMAT_CTF
:
1804 input_format
= "ctf";
1806 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1807 input_format
= "lttng-live";
1813 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
1815 printf_err("Specify the following non-legacy source component instance(s) instead of the\nlegacy `%s` input format options and positional arguments:\n\n",
1818 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1819 struct bt_value
*input_value
=
1820 bt_value_array_get(legacy_input_paths
, i
);
1821 const char *input
= NULL
;
1822 char *escaped_input
;
1825 assert(input_value
);
1826 ret
= bt_value_string_get(input_value
, &input
);
1827 BT_PUT(input_value
);
1828 assert(!ret
&& input
);
1829 escaped_input
= str_shell_escape(input
);
1830 if (!escaped_input
) {
1835 g_string_append(str
, "-i ctf.");
1837 switch (legacy_input_format
) {
1838 case LEGACY_INPUT_FORMAT_CTF
:
1839 g_string_append(str
, "fs -p 'path=\"");
1841 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1842 g_string_append(str
, "lttng-live -p 'url=\"");
1848 g_string_append(str
, escaped_input
);
1849 g_string_append(str
, "\"");
1850 g_string_append_printf(str
, ",offset-s=%" PRId64
,
1851 ctf_legacy_opts
->offset_s
.value
);
1852 g_string_append_printf(str
, ",offset-ns=%" PRId64
,
1853 ctf_legacy_opts
->offset_ns
.value
);
1854 g_string_append_bool_param(str
, "stream-intersection",
1855 ctf_legacy_opts
->stream_intersection
);
1856 g_string_append(str
, "' ");
1857 g_free(escaped_input
);
1860 printf_err("%s\n\n", str
->str
);
1864 g_string_free(str
, TRUE
);
1870 * Validates a given configuration, with optional legacy input and
1871 * output formats options. Prints useful error messages if anything
1874 * Returns true when the configuration is valid.
1877 bool validate_cfg(struct bt_config
*cfg
,
1878 enum legacy_input_format
*legacy_input_format
,
1879 enum legacy_output_format
*legacy_output_format
,
1880 struct bt_value
*legacy_input_paths
,
1881 struct ctf_legacy_opts
*ctf_legacy_opts
,
1882 struct text_legacy_opts
*text_legacy_opts
)
1884 bool legacy_input
= false;
1885 bool legacy_output
= false;
1887 /* Determine if the input and output should be legacy-style */
1888 if (cfg
->cmd_data
.convert
.print_ctf_metadata
||
1889 *legacy_input_format
!= LEGACY_INPUT_FORMAT_NONE
||
1890 !bt_value_array_is_empty(legacy_input_paths
) ||
1891 ctf_legacy_opts_is_any_set(ctf_legacy_opts
)) {
1892 legacy_input
= true;
1895 if (*legacy_output_format
!= LEGACY_OUTPUT_FORMAT_NONE
||
1896 text_legacy_opts_is_any_set(text_legacy_opts
)) {
1897 legacy_output
= true;
1901 /* If no legacy input format was specified, default to CTF */
1902 if (*legacy_input_format
== LEGACY_INPUT_FORMAT_NONE
) {
1903 *legacy_input_format
= LEGACY_INPUT_FORMAT_CTF
;
1906 /* Make sure at least one input path exists */
1907 if (bt_value_array_is_empty(legacy_input_paths
)) {
1908 switch (*legacy_input_format
) {
1909 case LEGACY_INPUT_FORMAT_CTF
:
1910 printf_err("No input path specified for legacy `ctf` input format\n");
1912 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1913 printf_err("No URL specified for legacy `lttng-live` input format\n");
1921 /* Make sure no non-legacy sources are specified */
1922 if (cfg
->cmd_data
.convert
.sources
->len
!= 0) {
1923 if (cfg
->cmd_data
.convert
.print_ctf_metadata
) {
1924 printf_err("You cannot instantiate a source component with the `ctf-metadata` output format\n");
1926 print_input_legacy_to_sources(
1927 *legacy_input_format
,
1928 legacy_input_paths
, ctf_legacy_opts
);
1936 * Strict rule: if we need to print the CTF metadata, the input
1937 * format must be legacy and CTF. Also there should be no
1938 * other sinks, and no legacy output format.
1940 if (cfg
->cmd_data
.convert
.print_ctf_metadata
) {
1941 if (*legacy_input_format
!= LEGACY_INPUT_FORMAT_CTF
) {
1942 printf_err("The `ctf-metadata` output format requires legacy `ctf` input format\n");
1946 if (bt_value_array_size(legacy_input_paths
) != 1) {
1947 printf_err("You need to specify exactly one path with the `ctf-metadata` output format\n");
1951 if (legacy_output
) {
1952 printf_err("You cannot use another legacy output format with the `ctf-metadata` output format\n");
1956 if (cfg
->cmd_data
.convert
.sinks
->len
!= 0) {
1957 printf_err("You cannot instantiate a sink component with the `ctf-metadata` output format\n");
1961 } else if (legacy_output
) {
1963 * If no legacy output format was specified, default to
1966 if (*legacy_output_format
== LEGACY_OUTPUT_FORMAT_NONE
) {
1967 *legacy_output_format
= LEGACY_OUTPUT_FORMAT_TEXT
;
1971 * If any "text" option was specified, the output must be
1974 if (text_legacy_opts_is_any_set(text_legacy_opts
) &&
1975 *legacy_output_format
!=
1976 LEGACY_OUTPUT_FORMAT_TEXT
) {
1977 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
1981 /* Make sure no non-legacy sinks are specified */
1982 if (cfg
->cmd_data
.convert
.sinks
->len
!= 0) {
1983 print_output_legacy_to_sinks(*legacy_output_format
,
1996 * Parses a 64-bit signed integer.
1998 * Returns a negative value if anything goes wrong.
2001 int parse_int64(const char *arg
, int64_t *val
)
2006 *val
= strtoll(arg
, &endptr
, 0);
2007 if (*endptr
!= '\0' || arg
== endptr
|| errno
!= 0) {
2021 OPT_CLOCK_FORCE_CORRELATE
,
2024 OPT_CLOCK_OFFSET_NS
,
2029 OPT_DEBUG_INFO_FULL_PATH
,
2030 OPT_DEBUG_INFO_TARGET_PREFIX
,
2040 OPT_OMIT_HOME_PLUGIN_PATH
,
2041 OPT_OMIT_SYSTEM_PLUGIN_PATH
,
2047 OPT_RESET_BASE_PARAMS
,
2050 OPT_STREAM_INTERSECTION
,
2056 * Sets the value of a given legacy offset option and marks it as set.
2058 static void set_offset_value(struct offset_opt
*offset_opt
, int64_t value
)
2060 offset_opt
->value
= value
;
2061 offset_opt
->is_set
= true;
2064 enum bt_config_component_dest
{
2065 BT_CONFIG_COMPONENT_DEST_SOURCE
,
2066 BT_CONFIG_COMPONENT_DEST_SINK
,
2070 * Adds a configuration component to the appropriate configuration
2071 * array depending on the destination.
2073 static void add_cfg_comp(struct bt_config
*cfg
,
2074 struct bt_config_component
*cfg_comp
,
2075 enum bt_config_component_dest dest
)
2077 if (dest
== BT_CONFIG_COMPONENT_DEST_SOURCE
) {
2078 g_ptr_array_add(cfg
->cmd_data
.convert
.sources
, cfg_comp
);
2080 g_ptr_array_add(cfg
->cmd_data
.convert
.sinks
, cfg_comp
);
2084 static int split_timerange(const char *arg
, const char **begin
, const char **end
)
2088 /* Try to match [begin,end] */
2089 c
= strchr(arg
, '[');
2103 /* Try to match begin,end */
2117 static int append_env_var_plugin_paths(struct bt_value
*plugin_paths
)
2122 if (bt_common_is_setuid_setgid()) {
2123 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2127 envvar
= getenv("BABELTRACE_PLUGIN_PATH");
2132 ret
= bt_config_append_plugin_paths(plugin_paths
, envvar
);
2138 static int append_home_and_system_plugin_paths(struct bt_value
*plugin_paths
,
2139 bool omit_system_plugin_path
, bool omit_home_plugin_path
)
2143 if (!omit_home_plugin_path
) {
2144 if (bt_common_is_setuid_setgid()) {
2145 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2147 char *home_plugin_dir
=
2148 bt_common_get_home_plugin_path();
2150 if (home_plugin_dir
) {
2151 ret
= bt_config_append_plugin_paths(
2154 free(home_plugin_dir
);
2157 printf_err("Invalid home plugin path\n");
2164 if (!omit_system_plugin_path
) {
2165 if (bt_config_append_plugin_paths(plugin_paths
,
2166 bt_common_get_system_plugin_path())) {
2167 printf_err("Invalid system plugin path\n");
2176 static int append_sources_from_implicit_params(GPtrArray
*sources
,
2177 struct bt_config_component
*implicit_source_comp
)
2180 size_t len
= sources
->len
;
2182 for (i
= 0; i
< len
; i
++) {
2183 struct bt_config_component
*comp
;
2184 struct bt_value
*params_to_set
;
2186 comp
= g_ptr_array_index(sources
, i
);
2187 params_to_set
= bt_value_map_extend(comp
->params
,
2188 implicit_source_comp
->params
);
2189 if (!params_to_set
) {
2190 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2193 BT_MOVE(comp
->params
, params_to_set
);
2200 static struct bt_config
*bt_config_base_create(enum bt_config_command command
)
2202 struct bt_config
*cfg
;
2205 cfg
= g_new0(struct bt_config
, 1);
2211 bt_object_init(cfg
, bt_config_destroy
);
2212 cfg
->command
= command
;
2222 static struct bt_config
*bt_config_convert_create(
2223 struct bt_value
*initial_plugin_paths
)
2225 struct bt_config
*cfg
;
2228 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_CONVERT
);
2234 cfg
->cmd_data
.convert
.sources
= g_ptr_array_new_with_free_func(
2235 (GDestroyNotify
) bt_put
);
2236 if (!cfg
->cmd_data
.convert
.sources
) {
2241 cfg
->cmd_data
.convert
.filters
= g_ptr_array_new_with_free_func(
2242 (GDestroyNotify
) bt_put
);
2243 if (!cfg
->cmd_data
.convert
.filters
) {
2248 cfg
->cmd_data
.convert
.sinks
= g_ptr_array_new_with_free_func(
2249 (GDestroyNotify
) bt_put
);
2250 if (!cfg
->cmd_data
.convert
.sinks
) {
2255 cfg
->cmd_data
.convert
.connections
= g_ptr_array_new_with_free_func(
2256 (GDestroyNotify
) bt_config_connection_destroy
);
2257 if (!cfg
->cmd_data
.convert
.connections
) {
2262 if (initial_plugin_paths
) {
2263 cfg
->cmd_data
.convert
.plugin_paths
=
2264 bt_get(initial_plugin_paths
);
2266 cfg
->cmd_data
.convert
.plugin_paths
= bt_value_array_create();
2267 if (!cfg
->cmd_data
.convert
.plugin_paths
) {
2282 static struct bt_config
*bt_config_list_plugins_create(
2283 struct bt_value
*initial_plugin_paths
)
2285 struct bt_config
*cfg
;
2288 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS
);
2294 if (initial_plugin_paths
) {
2295 cfg
->cmd_data
.list_plugins
.plugin_paths
=
2296 bt_get(initial_plugin_paths
);
2298 cfg
->cmd_data
.list_plugins
.plugin_paths
=
2299 bt_value_array_create();
2300 if (!cfg
->cmd_data
.list_plugins
.plugin_paths
) {
2315 static struct bt_config
*bt_config_help_create(
2316 struct bt_value
*initial_plugin_paths
)
2318 struct bt_config
*cfg
;
2321 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_HELP
);
2327 if (initial_plugin_paths
) {
2328 cfg
->cmd_data
.help
.plugin_paths
=
2329 bt_get(initial_plugin_paths
);
2331 cfg
->cmd_data
.help
.plugin_paths
=
2332 bt_value_array_create();
2333 if (!cfg
->cmd_data
.help
.plugin_paths
) {
2339 cfg
->cmd_data
.help
.cfg_component
=
2340 bt_config_component_create(BT_COMPONENT_CLASS_TYPE_UNKNOWN
,
2342 if (!cfg
->cmd_data
.help
.cfg_component
) {
2356 static struct bt_config
*bt_config_query_info_create(
2357 struct bt_value
*initial_plugin_paths
)
2359 struct bt_config
*cfg
;
2362 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_QUERY_INFO
);
2368 if (initial_plugin_paths
) {
2369 cfg
->cmd_data
.query_info
.plugin_paths
=
2370 bt_get(initial_plugin_paths
);
2372 cfg
->cmd_data
.query_info
.plugin_paths
=
2373 bt_value_array_create();
2374 if (!cfg
->cmd_data
.query_info
.plugin_paths
) {
2380 cfg
->cmd_data
.query_info
.action
= g_string_new(NULL
);
2381 if (!cfg
->cmd_data
.query_info
.action
) {
2396 * Prints the expected format for a --params option.
2399 void print_expected_params_format(FILE *fp
)
2401 fprintf(fp
, "Expected format of PARAMS\n");
2402 fprintf(fp
, "-------------------------\n");
2404 fprintf(fp
, " PARAM=VALUE[,PARAM=VALUE]...\n");
2406 fprintf(fp
, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
2407 fprintf(fp
, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
2408 fprintf(fp
, "VALUE can be one of:\n");
2410 fprintf(fp
, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
2411 fprintf(fp
, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
2412 fprintf(fp
, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
2413 fprintf(fp
, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
2414 fprintf(fp
, " (`0x` prefix) signed 64-bit integer.\n");
2415 fprintf(fp
, "* Double precision floating point number (scientific notation is accepted).\n");
2416 fprintf(fp
, "* Unquoted string with no special characters, and not matching any of\n");
2417 fprintf(fp
, " the null and boolean value symbols above.\n");
2418 fprintf(fp
, "* Double-quoted string (accepts escape characters).\n");
2420 fprintf(fp
, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
2422 fprintf(fp
, "Example:\n");
2424 fprintf(fp
, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
2425 fprintf(fp
, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
2426 fprintf(fp
, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
2428 fprintf(fp
, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
2429 fprintf(fp
, "from a shell.\n");
2434 * Prints the help command usage.
2437 void print_help_usage(FILE *fp
)
2439 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
2440 fprintf(fp
, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source=PLUGIN.COMPCLS\n");
2441 fprintf(fp
, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter=PLUGIN.COMPCLS\n");
2442 fprintf(fp
, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink=PLUGIN.COMPCLS\n");
2444 fprintf(fp
, "Options:\n");
2446 fprintf(fp
, " --filter=PLUGIN.COMPCLS Get help for the filter component class\n");
2447 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2448 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2449 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
2450 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2451 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2452 fprintf(fp
, " dynamic plugins can be loaded\n");
2453 fprintf(fp
, " --sink=PLUGIN.COMPCLS Get help for the sink component class\n");
2454 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2455 fprintf(fp
, " --source=PLUGIN.COMPCLS Get help for the source component class\n");
2456 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2457 fprintf(fp
, " -h --help Show this help and quit\n");
2459 fprintf(fp
, "See `babeltrace --help` for the list of general options.\n");
2461 fprintf(fp
, "Use `babeltrace list-plugins` to show the list of available plugins.\n");
2464 static struct poptOption help_long_options
[] = {
2465 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2466 { "filter", '\0', POPT_ARG_STRING
, NULL
, OPT_FILTER
, NULL
, NULL
},
2467 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2468 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2469 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2470 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2471 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
2472 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
2473 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2477 * Creates a Babeltrace config object from the arguments of a help
2480 * *retcode is set to the appropriate exit code to use.
2482 struct bt_config
*bt_config_help_from_args(int argc
, const char *argv
[],
2483 int *retcode
, bool omit_system_plugin_path
,
2484 bool omit_home_plugin_path
,
2485 struct bt_value
*initial_plugin_paths
)
2487 poptContext pc
= NULL
;
2491 struct bt_config
*cfg
= NULL
;
2492 const char *leftover
;
2493 char *plugin_name
= NULL
, *component_name
= NULL
;
2494 char *plugin_comp_cls_names
= NULL
;
2497 cfg
= bt_config_help_create(initial_plugin_paths
);
2503 cfg
->cmd_data
.help
.omit_system_plugin_path
= omit_system_plugin_path
;
2504 cfg
->cmd_data
.help
.omit_home_plugin_path
= omit_home_plugin_path
;
2505 ret
= append_env_var_plugin_paths(cfg
->cmd_data
.help
.plugin_paths
);
2507 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2512 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
2513 help_long_options
, 0);
2515 printf_err("Cannot get popt context\n");
2519 poptReadDefaultConfig(pc
, 0);
2521 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2522 arg
= poptGetOptArg(pc
);
2525 case OPT_PLUGIN_PATH
:
2526 if (bt_common_is_setuid_setgid()) {
2527 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2529 if (bt_config_append_plugin_paths(
2530 cfg
->cmd_data
.help
.plugin_paths
,
2532 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2538 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
2539 cfg
->cmd_data
.help
.omit_system_plugin_path
= true;
2541 case OPT_OMIT_HOME_PLUGIN_PATH
:
2542 cfg
->cmd_data
.help
.omit_home_plugin_path
= true;
2547 if (cfg
->cmd_data
.help
.cfg_component
->type
!=
2548 BT_COMPONENT_CLASS_TYPE_UNKNOWN
) {
2549 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2556 cfg
->cmd_data
.help
.cfg_component
->type
=
2557 BT_COMPONENT_CLASS_TYPE_SOURCE
;
2560 cfg
->cmd_data
.help
.cfg_component
->type
=
2561 BT_COMPONENT_CLASS_TYPE_FILTER
;
2564 cfg
->cmd_data
.help
.cfg_component
->type
=
2565 BT_COMPONENT_CLASS_TYPE_SINK
;
2570 plugin_comp_cls_names
= strdup(arg
);
2571 if (!plugin_comp_cls_names
) {
2577 print_help_usage(stdout
);
2582 printf_err("Unknown command-line option specified (option code %d)\n",
2591 /* Check for option parsing error */
2593 printf_err("While parsing command-line options, at option %s: %s\n",
2594 poptBadOption(pc
, 0), poptStrerror(opt
));
2598 leftover
= poptGetArg(pc
);
2600 if (cfg
->cmd_data
.help
.cfg_component
->type
!=
2601 BT_COMPONENT_CLASS_TYPE_UNKNOWN
) {
2602 printf_err("Cannot specify plugin name and --source/--filter/--sink component class:\n %s\n",
2607 g_string_assign(cfg
->cmd_data
.help
.cfg_component
->plugin_name
,
2610 if (cfg
->cmd_data
.help
.cfg_component
->type
==
2611 BT_COMPONENT_CLASS_TYPE_UNKNOWN
) {
2612 print_help_usage(stdout
);
2618 plugin_component_names_from_arg(plugin_comp_cls_names
,
2619 &plugin_name
, &component_name
);
2620 if (plugin_name
&& component_name
) {
2621 g_string_assign(cfg
->cmd_data
.help
.cfg_component
->plugin_name
,
2623 g_string_assign(cfg
->cmd_data
.help
.cfg_component
->component_name
,
2626 printf_err("Invalid --source/--filter/--sink option's argument:\n %s\n",
2627 plugin_comp_cls_names
);
2632 if (append_home_and_system_plugin_paths(
2633 cfg
->cmd_data
.help
.plugin_paths
,
2634 cfg
->cmd_data
.help
.omit_system_plugin_path
,
2635 cfg
->cmd_data
.help
.omit_home_plugin_path
)) {
2636 printf_err("Cannot append home and system plugin paths\n");
2647 free(plugin_comp_cls_names
);
2648 g_free(plugin_name
);
2649 g_free(component_name
);
2652 poptFreeContext(pc
);
2660 * Prints the help command usage.
2663 void print_query_info_usage(FILE *fp
)
2665 fprintf(fp
, "Usage: babeltrace [GEN OPTS] query-info [OPTS] ACTION --source=PLUGIN.COMPCLS\n");
2666 fprintf(fp
, " babeltrace [GEN OPTS] query-info [OPTS] ACTION --filter=PLUGIN.COMPCLS\n");
2667 fprintf(fp
, " babeltrace [GEN OPTS] query-info [OPTS] ACTION --sink=PLUGIN.COMPCLS\n");
2669 fprintf(fp
, "Options:\n");
2671 fprintf(fp
, " --filter=PLUGIN.COMPCLS Query info from the filter component class\n");
2672 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2673 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2674 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
2675 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2676 fprintf(fp
, " -p, --params=PARAMS Set the query parameters to PARAMS\n");
2677 fprintf(fp
, " (see the expected format of PARAMS below)\n");
2678 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2679 fprintf(fp
, " dynamic plugins can be loaded\n");
2680 fprintf(fp
, " --sink=PLUGIN.COMPCLS Query info from the sink component class\n");
2681 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2682 fprintf(fp
, " --source=PLUGIN.COMPCLS Query info from the source component class\n");
2683 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2684 fprintf(fp
, " -h --help Show this help and quit\n");
2685 fprintf(fp
, "\n\n");
2686 print_expected_params_format(fp
);
2689 static struct poptOption query_info_long_options
[] = {
2690 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2691 { "filter", '\0', POPT_ARG_STRING
, NULL
, OPT_FILTER
, NULL
, NULL
},
2692 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2693 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2694 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2695 { "params", 'p', POPT_ARG_STRING
, NULL
, OPT_PARAMS
, NULL
, NULL
},
2696 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2697 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
2698 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
2699 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2703 * Creates a Babeltrace config object from the arguments of a query-info
2706 * *retcode is set to the appropriate exit code to use.
2708 struct bt_config
*bt_config_query_info_from_args(int argc
, const char *argv
[],
2709 int *retcode
, bool omit_system_plugin_path
,
2710 bool omit_home_plugin_path
,
2711 struct bt_value
*initial_plugin_paths
)
2713 poptContext pc
= NULL
;
2717 struct bt_config
*cfg
= NULL
;
2718 const char *leftover
;
2719 struct bt_value
*params
= bt_value_null
;
2722 cfg
= bt_config_query_info_create(initial_plugin_paths
);
2728 cfg
->cmd_data
.query_info
.omit_system_plugin_path
=
2729 omit_system_plugin_path
;
2730 cfg
->cmd_data
.query_info
.omit_home_plugin_path
= omit_home_plugin_path
;
2731 ret
= append_env_var_plugin_paths(cfg
->cmd_data
.query_info
.plugin_paths
);
2733 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2738 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
2739 query_info_long_options
, 0);
2741 printf_err("Cannot get popt context\n");
2745 poptReadDefaultConfig(pc
, 0);
2747 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2748 arg
= poptGetOptArg(pc
);
2751 case OPT_PLUGIN_PATH
:
2752 if (bt_common_is_setuid_setgid()) {
2753 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2755 if (bt_config_append_plugin_paths(
2756 cfg
->cmd_data
.query_info
.plugin_paths
,
2758 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2764 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
2765 cfg
->cmd_data
.query_info
.omit_system_plugin_path
= true;
2767 case OPT_OMIT_HOME_PLUGIN_PATH
:
2768 cfg
->cmd_data
.query_info
.omit_home_plugin_path
= true;
2774 enum bt_component_class_type type
;
2776 if (cfg
->cmd_data
.query_info
.cfg_component
) {
2777 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2784 type
= BT_COMPONENT_CLASS_TYPE_SOURCE
;
2787 type
= BT_COMPONENT_CLASS_TYPE_FILTER
;
2790 type
= BT_COMPONENT_CLASS_TYPE_SINK
;
2796 cfg
->cmd_data
.query_info
.cfg_component
=
2797 bt_config_component_from_arg(type
, arg
);
2798 if (!cfg
->cmd_data
.query_info
.cfg_component
) {
2799 printf_err("Invalid format for --source/--filter/--sink option's argument:\n %s\n",
2804 /* Default parameters: null */
2805 bt_put(cfg
->cmd_data
.query_info
.cfg_component
->params
);
2806 cfg
->cmd_data
.query_info
.cfg_component
->params
=
2812 params
= bt_value_from_arg(arg
);
2814 printf_err("Invalid format for --params option's argument:\n %s\n",
2821 print_query_info_usage(stdout
);
2826 printf_err("Unknown command-line option specified (option code %d)\n",
2835 if (!cfg
->cmd_data
.query_info
.cfg_component
) {
2836 printf_err("No target component class specified with --source/--filter/--sink option\n");
2841 BT_MOVE(cfg
->cmd_data
.query_info
.cfg_component
->params
, params
);
2843 /* Check for option parsing error */
2845 printf_err("While parsing command-line options, at option %s: %s\n",
2846 poptBadOption(pc
, 0), poptStrerror(opt
));
2851 * We need exactly one leftover argument which is the
2854 leftover
= poptGetArg(pc
);
2856 if (strlen(leftover
) == 0) {
2857 printf_err("Invalid empty action\n");
2861 g_string_assign(cfg
->cmd_data
.query_info
.action
, leftover
);
2863 print_query_info_usage(stdout
);
2869 leftover
= poptGetArg(pc
);
2871 printf_err("Invalid argument: %s\n", leftover
);
2875 if (append_home_and_system_plugin_paths(
2876 cfg
->cmd_data
.query_info
.plugin_paths
,
2877 cfg
->cmd_data
.query_info
.omit_system_plugin_path
,
2878 cfg
->cmd_data
.query_info
.omit_home_plugin_path
)) {
2879 printf_err("Cannot append home and system plugin paths\n");
2891 poptFreeContext(pc
);
2900 * Prints the list-plugins command usage.
2903 void print_list_plugins_usage(FILE *fp
)
2905 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
2907 fprintf(fp
, "Options:\n");
2909 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2910 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
2911 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2912 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2913 fprintf(fp
, " dynamic plugins can be loaded\n");
2914 fprintf(fp
, " -h --help Show this help and quit\n");
2916 fprintf(fp
, "See `babeltrace --help` for the list of general options.\n");
2918 fprintf(fp
, "Use `babeltrace help` to get help for a specific plugin or component class.\n");
2921 static struct poptOption list_plugins_long_options
[] = {
2922 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2923 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2924 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2925 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2926 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2927 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2931 * Creates a Babeltrace config object from the arguments of a
2932 * list-plugins command.
2934 * *retcode is set to the appropriate exit code to use.
2936 struct bt_config
*bt_config_list_plugins_from_args(int argc
, const char *argv
[],
2937 int *retcode
, bool omit_system_plugin_path
,
2938 bool omit_home_plugin_path
,
2939 struct bt_value
*initial_plugin_paths
)
2941 poptContext pc
= NULL
;
2945 struct bt_config
*cfg
= NULL
;
2946 const char *leftover
;
2949 cfg
= bt_config_list_plugins_create(initial_plugin_paths
);
2955 cfg
->cmd_data
.list_plugins
.omit_system_plugin_path
= omit_system_plugin_path
;
2956 cfg
->cmd_data
.list_plugins
.omit_home_plugin_path
= omit_home_plugin_path
;
2957 ret
= append_env_var_plugin_paths(
2958 cfg
->cmd_data
.list_plugins
.plugin_paths
);
2960 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2965 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
2966 list_plugins_long_options
, 0);
2968 printf_err("Cannot get popt context\n");
2972 poptReadDefaultConfig(pc
, 0);
2974 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2975 arg
= poptGetOptArg(pc
);
2978 case OPT_PLUGIN_PATH
:
2979 if (bt_common_is_setuid_setgid()) {
2980 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2982 if (bt_config_append_plugin_paths(
2983 cfg
->cmd_data
.list_plugins
.plugin_paths
,
2985 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2991 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
2992 cfg
->cmd_data
.list_plugins
.omit_system_plugin_path
= true;
2994 case OPT_OMIT_HOME_PLUGIN_PATH
:
2995 cfg
->cmd_data
.list_plugins
.omit_home_plugin_path
= true;
2998 print_list_plugins_usage(stdout
);
3003 printf_err("Unknown command-line option specified (option code %d)\n",
3012 /* Check for option parsing error */
3014 printf_err("While parsing command-line options, at option %s: %s\n",
3015 poptBadOption(pc
, 0), poptStrerror(opt
));
3019 leftover
= poptGetArg(pc
);
3021 printf_err("Invalid argument: %s\n", leftover
);
3025 if (append_home_and_system_plugin_paths(
3026 cfg
->cmd_data
.list_plugins
.plugin_paths
,
3027 cfg
->cmd_data
.list_plugins
.omit_system_plugin_path
,
3028 cfg
->cmd_data
.list_plugins
.omit_home_plugin_path
)) {
3029 printf_err("Cannot append home and system plugin paths\n");
3041 poptFreeContext(pc
);
3049 * Prints the legacy, Babeltrace 1.x command usage. Those options are
3050 * still compatible in Babeltrace 2.x, but it is recommended to use
3051 * the more generic plugin/component parameters instead of those
3052 * hard-coded option names.
3055 void print_legacy_usage(FILE *fp
)
3057 fprintf(fp
, "Usage: babeltrace [OPTIONS] INPUT...\n");
3059 fprintf(fp
, "The following options are compatible with the Babeltrace 1.x options:\n");
3061 fprintf(fp
, " --clock-force-correlate Assume that clocks are inherently correlated\n");
3062 fprintf(fp
, " across traces\n");
3063 fprintf(fp
, " -d, --debug Enable debug mode\n");
3064 fprintf(fp
, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
3065 fprintf(fp
, " -l, --list List available formats\n");
3066 fprintf(fp
, " -o, --output-format=FORMAT Output trace format (default: text)\n");
3067 fprintf(fp
, " -v, --verbose Enable verbose output\n");
3068 fprintf(fp
, " --help-legacy Show this help and quit\n");
3069 fprintf(fp
, " -V, --version Show version and quit\n");
3071 fprintf(fp
, " Available input formats: ctf, lttng-live, ctf-metadata\n");
3072 fprintf(fp
, " Available output formats: text, dummy\n");
3074 fprintf(fp
, "Input formats specific options:\n");
3076 fprintf(fp
, " INPUT... Input trace file(s), directory(ies), or URLs\n");
3077 fprintf(fp
, " --clock-offset=SEC Set clock offset to SEC seconds\n");
3078 fprintf(fp
, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
3079 fprintf(fp
, " --stream-intersection Only process events when all streams are active\n");
3081 fprintf(fp
, "text output format specific options:\n");
3083 fprintf(fp
, " --clock-cycles Print timestamps in clock cycles\n");
3084 fprintf(fp
, " --clock-date Print timestamp dates\n");
3085 fprintf(fp
, " --clock-gmt Print and parse timestamps in GMT time zone\n");
3086 fprintf(fp
, " (default: local time zone)\n");
3087 fprintf(fp
, " --clock-seconds Print the timestamps as [SEC.NS]\n");
3088 fprintf(fp
, " (default format: [HH:MM:SS.NS])\n");
3089 fprintf(fp
, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
3090 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
3091 fprintf(fp
, " --debug-info-full-path Show full debug info source and binary paths\n");
3092 fprintf(fp
, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
3093 fprintf(fp
, " up executables during debug info analysis\n");
3094 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
3095 fprintf(fp
, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
3096 fprintf(fp
, " all, trace, trace:hostname, trace:domain,\n");
3097 fprintf(fp
, " trace:procname, trace:vpid, loglevel, emf\n");
3098 fprintf(fp
, " (default: trace:hostname, trace:procname,\n");
3099 fprintf(fp
, " trace:vpid)\n");
3100 fprintf(fp
, " -n, --names=NAME[,NAME]... Print field names:\n");
3101 fprintf(fp
, " payload (or arg or args)\n");
3102 fprintf(fp
, " none, all, scope, header, context (or ctx)\n");
3103 fprintf(fp
, " (default: payload, context)\n");
3104 fprintf(fp
, " --no-delta Do not print time delta between consecutive\n");
3105 fprintf(fp
, " events\n");
3106 fprintf(fp
, " -w, --output=PATH Write output to PATH (default: standard output)\n");
3110 * Prints the convert command usage.
3113 void print_convert_usage(FILE *fp
)
3115 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
3117 fprintf(fp
, "Options:\n");
3119 fprintf(fp
, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
3120 fprintf(fp
, " for the following component instances\n");
3121 fprintf(fp
, " (see the expected format of PARAMS below)\n");
3122 fprintf(fp
, " --begin=BEGIN Set the `begin` parameter of the latest\n");
3123 fprintf(fp
, " source component instance to BEGIN\n");
3124 fprintf(fp
, " (see the suggested format of BEGIN below)\n");
3125 fprintf(fp
, " -c, --connect=CONNECTION Connect two component instances (see the\n");
3126 fprintf(fp
, " expected format of CONNECTION below)\n");
3127 fprintf(fp
, " -d, --debug Enable debug mode\n");
3128 fprintf(fp
, " --end=END Set the `end` parameter of the latest\n");
3129 fprintf(fp
, " source component instance to END\n");
3130 fprintf(fp
, " (see the suggested format of BEGIN below)\n");
3131 fprintf(fp
, " --name=NAME Set the name of the latest component\n");
3132 fprintf(fp
, " instance to NAME (must be unique amongst\n");
3133 fprintf(fp
, " all the names of the component instances)\n");
3134 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
3135 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
3136 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
3137 fprintf(fp
, " -p, --params=PARAMS Set the parameters of the latest component\n");
3138 fprintf(fp
, " instance (in command-line order) to PARAMS\n");
3139 fprintf(fp
, " (see the expected format of PARAMS below)\n");
3140 fprintf(fp
, " -P, --path=PATH Set the `path` parameter of the latest\n");
3141 fprintf(fp
, " component instance to PATH\n");
3142 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
3143 fprintf(fp
, " dynamic plugins can be loaded\n");
3144 fprintf(fp
, " -r, --reset-base-params Reset the current base parameters of the\n");
3145 fprintf(fp
, " following source and sink component\n");
3146 fprintf(fp
, " instances to an empty map\n");
3147 fprintf(fp
, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
3148 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
3149 fprintf(fp
, " repeated)\n");
3150 fprintf(fp
, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
3151 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
3152 fprintf(fp
, " repeated)\n");
3153 fprintf(fp
, " --timerange=TIMERANGE Set time range to TIMERANGE: BEGIN,END or\n");
3154 fprintf(fp
, " [BEGIN,END] (literally `[` and `]`)\n");
3155 fprintf(fp
, " (suggested format of BEGIN/END below)\n");
3156 fprintf(fp
, " -v, --verbose Enable verbose output\n");
3157 fprintf(fp
, " -h --help Show this help and quit\n");
3159 fprintf(fp
, "See `babeltrace --help` for the list of general options.\n");
3160 fprintf(fp
, "\n\n");
3161 fprintf(fp
, "Suggested format of BEGIN and END\n");
3162 fprintf(fp
, "---------------------------------\n");
3164 fprintf(fp
, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
3165 fprintf(fp
, "\n\n");
3166 fprintf(fp
, "Expected format of CONNECTION\n");
3167 fprintf(fp
, "-----------------------------\n");
3169 fprintf(fp
, " SRC[.SRCPORT]:DST[.DSTPORT]\n");
3171 fprintf(fp
, "SRC and DST are the names of the source and destination component\n");
3172 fprintf(fp
, "instances to connect together. You can set the name of a component\n");
3173 fprintf(fp
, "instance with the --name option.\n");
3175 fprintf(fp
, "SRCPORT and DSTPORT are the optional source and destination ports to use\n");
3176 fprintf(fp
, "for the connection. When the port is not specified, the default port is\n");
3177 fprintf(fp
, "used.\n");
3179 fprintf(fp
, "You can connect a source component to a filter or sink component. You\n");
3180 fprintf(fp
, "can connect a filter component to a sink component.\n");
3182 fprintf(fp
, "Example:\n");
3184 fprintf(fp
, " my-filter.top10:json-out\n");
3185 fprintf(fp
, "\n\n");
3186 print_expected_params_format(fp
);
3189 static struct poptOption convert_long_options
[] = {
3190 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
3191 { "base-params", 'b', POPT_ARG_STRING
, NULL
, OPT_BASE_PARAMS
, NULL
, NULL
},
3192 { "begin", '\0', POPT_ARG_STRING
, NULL
, OPT_BEGIN
, NULL
, NULL
},
3193 { "clock-cycles", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_CYCLES
, NULL
, NULL
},
3194 { "clock-date", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_DATE
, NULL
, NULL
},
3195 { "clock-force-correlate", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_FORCE_CORRELATE
, NULL
, NULL
},
3196 { "clock-gmt", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_GMT
, NULL
, NULL
},
3197 { "clock-offset", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET
, NULL
, NULL
},
3198 { "clock-offset-ns", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET_NS
, NULL
, NULL
},
3199 { "clock-seconds", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_SECONDS
, NULL
, NULL
},
3200 { "connect", 'c', POPT_ARG_STRING
, NULL
, OPT_CONNECT
, NULL
, NULL
},
3201 { "debug", 'd', POPT_ARG_NONE
, NULL
, OPT_DEBUG
, NULL
, NULL
},
3202 { "debug-info-dir", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_DIR
, NULL
, NULL
},
3203 { "debug-info-full-path", 0, POPT_ARG_NONE
, NULL
, OPT_DEBUG_INFO_FULL_PATH
, NULL
, NULL
},
3204 { "debug-info-target-prefix", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_TARGET_PREFIX
, NULL
, NULL
},
3205 { "end", '\0', POPT_ARG_STRING
, NULL
, OPT_END
, NULL
, NULL
},
3206 { "fields", 'f', POPT_ARG_STRING
, NULL
, OPT_FIELDS
, NULL
, NULL
},
3207 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
3208 { "input-format", 'i', POPT_ARG_STRING
, NULL
, OPT_INPUT_FORMAT
, NULL
, NULL
},
3209 { "name", '\0', POPT_ARG_STRING
, NULL
, OPT_NAME
, NULL
, NULL
},
3210 { "names", 'n', POPT_ARG_STRING
, NULL
, OPT_NAMES
, NULL
, NULL
},
3211 { "no-delta", '\0', POPT_ARG_NONE
, NULL
, OPT_NO_DELTA
, NULL
, NULL
},
3212 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
3213 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
3214 { "output", 'w', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_PATH
, NULL
, NULL
},
3215 { "output-format", 'o', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_FORMAT
, NULL
, NULL
},
3216 { "params", 'p', POPT_ARG_STRING
, NULL
, OPT_PARAMS
, NULL
, NULL
},
3217 { "path", 'P', POPT_ARG_STRING
, NULL
, OPT_PATH
, NULL
, NULL
},
3218 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
3219 { "reset-base-params", 'r', POPT_ARG_NONE
, NULL
, OPT_RESET_BASE_PARAMS
, NULL
, NULL
},
3220 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
3221 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
3222 { "stream-intersection", '\0', POPT_ARG_NONE
, NULL
, OPT_STREAM_INTERSECTION
, NULL
, NULL
},
3223 { "timerange", '\0', POPT_ARG_STRING
, NULL
, OPT_TIMERANGE
, NULL
, NULL
},
3224 { "verbose", 'v', POPT_ARG_NONE
, NULL
, OPT_VERBOSE
, NULL
, NULL
},
3225 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
3229 * Creates a Babeltrace config object from the arguments of a convert
3232 * *retcode is set to the appropriate exit code to use.
3234 struct bt_config
*bt_config_convert_from_args(int argc
, const char *argv
[],
3235 int *retcode
, bool omit_system_plugin_path
,
3236 bool omit_home_plugin_path
,
3237 struct bt_value
*initial_plugin_paths
)
3239 poptContext pc
= NULL
;
3241 struct ctf_legacy_opts ctf_legacy_opts
;
3242 struct text_legacy_opts text_legacy_opts
;
3243 enum legacy_input_format legacy_input_format
= LEGACY_INPUT_FORMAT_NONE
;
3244 enum legacy_output_format legacy_output_format
=
3245 LEGACY_OUTPUT_FORMAT_NONE
;
3246 struct bt_value
*legacy_input_paths
= NULL
;
3247 struct bt_config_component
*implicit_source_comp
= NULL
;
3248 struct bt_config_component
*cur_cfg_comp
= NULL
;
3249 bool cur_is_implicit_source
= false;
3250 bool use_implicit_source
= false;
3251 enum bt_config_component_dest cur_cfg_comp_dest
=
3252 BT_CONFIG_COMPONENT_DEST_SOURCE
;
3253 struct bt_value
*cur_base_params
= NULL
;
3255 struct bt_config
*cfg
= NULL
;
3256 struct bt_value
*instance_names
= NULL
;
3257 struct bt_value
*connection_args
= NULL
;
3258 char error_buf
[256] = { 0 };
3261 memset(&ctf_legacy_opts
, 0, sizeof(ctf_legacy_opts
));
3262 memset(&text_legacy_opts
, 0, sizeof(text_legacy_opts
));
3265 print_convert_usage(stdout
);
3270 cfg
= bt_config_convert_create(initial_plugin_paths
);
3276 cfg
->cmd_data
.convert
.omit_system_plugin_path
= omit_system_plugin_path
;
3277 cfg
->cmd_data
.convert
.omit_home_plugin_path
= omit_home_plugin_path
;
3278 text_legacy_opts
.output
= g_string_new(NULL
);
3279 if (!text_legacy_opts
.output
) {
3284 text_legacy_opts
.dbg_info_dir
= g_string_new(NULL
);
3285 if (!text_legacy_opts
.dbg_info_dir
) {
3290 text_legacy_opts
.dbg_info_target_prefix
= g_string_new(NULL
);
3291 if (!text_legacy_opts
.dbg_info_target_prefix
) {
3296 cur_base_params
= bt_value_map_create();
3297 if (!cur_base_params
) {
3302 legacy_input_paths
= bt_value_array_create();
3303 if (!legacy_input_paths
) {
3308 instance_names
= bt_value_map_create();
3309 if (!instance_names
) {
3314 connection_args
= bt_value_array_create();
3315 if (!connection_args
) {
3320 ret
= append_env_var_plugin_paths(cfg
->cmd_data
.convert
.plugin_paths
);
3322 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3326 /* Note: implicit source never gets positional base params. */
3327 implicit_source_comp
= bt_config_component_from_arg(
3328 BT_COMPONENT_CLASS_TYPE_SOURCE
, DEFAULT_SOURCE_COMPONENT_NAME
);
3329 if (!implicit_source_comp
) {
3334 cur_cfg_comp
= implicit_source_comp
;
3335 cur_is_implicit_source
= true;
3336 use_implicit_source
= true;
3339 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
3340 convert_long_options
, 0);
3342 printf_err("Cannot get popt context\n");
3346 poptReadDefaultConfig(pc
, 0);
3348 while ((opt
= poptGetNextOpt(pc
)) > 0) {
3349 arg
= poptGetOptArg(pc
);
3352 case OPT_PLUGIN_PATH
:
3353 if (bt_common_is_setuid_setgid()) {
3354 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3356 if (bt_config_append_plugin_paths(
3357 cfg
->cmd_data
.convert
.plugin_paths
,
3359 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3365 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
3366 cfg
->cmd_data
.convert
.omit_system_plugin_path
= true;
3368 case OPT_OMIT_HOME_PLUGIN_PATH
:
3369 cfg
->cmd_data
.convert
.omit_home_plugin_path
= true;
3371 case OPT_OUTPUT_PATH
:
3372 if (text_legacy_opts
.output
->len
> 0) {
3373 printf_err("Duplicate --output option\n");
3377 g_string_assign(text_legacy_opts
.output
, arg
);
3379 case OPT_DEBUG_INFO_DIR
:
3380 if (text_legacy_opts
.dbg_info_dir
->len
> 0) {
3381 printf_err("Duplicate --debug-info-dir option\n");
3385 g_string_assign(text_legacy_opts
.dbg_info_dir
, arg
);
3387 case OPT_DEBUG_INFO_TARGET_PREFIX
:
3388 if (text_legacy_opts
.dbg_info_target_prefix
->len
> 0) {
3389 printf_err("Duplicate --debug-info-target-prefix option\n");
3393 g_string_assign(text_legacy_opts
.dbg_info_target_prefix
, arg
);
3395 case OPT_INPUT_FORMAT
:
3398 if (opt
== OPT_INPUT_FORMAT
) {
3399 if (!strcmp(arg
, "ctf")) {
3400 /* Legacy CTF input format */
3401 if (legacy_input_format
) {
3402 print_err_dup_legacy_input();
3406 legacy_input_format
=
3407 LEGACY_INPUT_FORMAT_CTF
;
3409 } else if (!strcmp(arg
, "lttng-live")) {
3410 /* Legacy LTTng-live input format */
3411 if (legacy_input_format
) {
3412 print_err_dup_legacy_input();
3416 legacy_input_format
=
3417 LEGACY_INPUT_FORMAT_LTTNG_LIVE
;
3422 use_implicit_source
= false;
3424 /* Non-legacy: try to create a component config */
3425 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3426 add_cfg_comp(cfg
, cur_cfg_comp
,
3430 cur_cfg_comp
= bt_config_component_from_arg(
3431 BT_COMPONENT_CLASS_TYPE_SOURCE
, arg
);
3432 if (!cur_cfg_comp
) {
3433 printf_err("Invalid format for --source option's argument:\n %s\n",
3437 cur_is_implicit_source
= false;
3439 assert(cur_base_params
);
3440 bt_put(cur_cfg_comp
->params
);
3441 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
3442 if (!cur_cfg_comp
->params
) {
3447 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SOURCE
;
3450 case OPT_OUTPUT_FORMAT
:
3453 if (opt
== OPT_OUTPUT_FORMAT
) {
3454 if (!strcmp(arg
, "text")) {
3455 /* Legacy CTF-text output format */
3456 if (legacy_output_format
) {
3457 print_err_dup_legacy_output();
3461 legacy_output_format
=
3462 LEGACY_OUTPUT_FORMAT_TEXT
;
3464 } else if (!strcmp(arg
, "dummy")) {
3465 /* Legacy dummy output format */
3466 if (legacy_output_format
) {
3467 print_err_dup_legacy_output();
3471 legacy_output_format
=
3472 LEGACY_OUTPUT_FORMAT_DUMMY
;
3474 } else if (!strcmp(arg
, "ctf-metadata")) {
3475 cfg
->cmd_data
.convert
.print_ctf_metadata
= true;
3480 /* Non-legacy: try to create a component config */
3481 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3482 add_cfg_comp(cfg
, cur_cfg_comp
,
3486 cur_cfg_comp
= bt_config_component_from_arg(
3487 BT_COMPONENT_CLASS_TYPE_SINK
, arg
);
3488 if (!cur_cfg_comp
) {
3489 printf_err("Invalid format for --sink option's argument:\n %s\n",
3493 cur_is_implicit_source
= false;
3495 assert(cur_base_params
);
3496 bt_put(cur_cfg_comp
->params
);
3497 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
3498 if (!cur_cfg_comp
->params
) {
3503 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SINK
;
3508 struct bt_value
*params
;
3509 struct bt_value
*params_to_set
;
3511 if (!cur_cfg_comp
) {
3512 printf_err("Cannot add parameters to unavailable default source component `%s`:\n %s\n",
3513 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3517 params
= bt_value_from_arg(arg
);
3519 printf_err("Invalid format for --params option's argument:\n %s\n",
3524 params_to_set
= bt_value_map_extend(cur_cfg_comp
->params
,
3527 if (!params_to_set
) {
3528 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
3533 BT_MOVE(cur_cfg_comp
->params
, params_to_set
);
3537 if (!cur_cfg_comp
) {
3538 printf_err("Cannot add `path` parameter to unavailable default source component `%s`:\n %s\n",
3539 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3543 assert(cur_cfg_comp
->params
);
3545 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3552 if (!cur_cfg_comp
) {
3553 printf_err("Cannot set the name of unavailable default source component `%s`:\n %s\n",
3554 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3558 if (bt_value_map_has_key(instance_names
, arg
)) {
3559 printf_err("Duplicate component instance name:\n %s\n",
3564 g_string_assign(cur_cfg_comp
->instance_name
, arg
);
3566 if (bt_value_map_insert(instance_names
,
3567 arg
, bt_value_null
)) {
3572 case OPT_BASE_PARAMS
:
3574 struct bt_value
*params
= bt_value_from_arg(arg
);
3577 printf_err("Invalid format for --base-params option's argument:\n %s\n",
3582 BT_MOVE(cur_base_params
, params
);
3585 case OPT_RESET_BASE_PARAMS
:
3586 BT_PUT(cur_base_params
);
3587 cur_base_params
= bt_value_map_create();
3588 if (!cur_base_params
) {
3594 if (text_legacy_opts
.names
) {
3595 printf_err("Duplicate --names option\n");
3599 text_legacy_opts
.names
= names_from_arg(arg
);
3600 if (!text_legacy_opts
.names
) {
3601 printf_err("Invalid --names option's argument:\n %s\n",
3607 if (text_legacy_opts
.fields
) {
3608 printf_err("Duplicate --fields option\n");
3612 text_legacy_opts
.fields
= fields_from_arg(arg
);
3613 if (!text_legacy_opts
.fields
) {
3614 printf_err("Invalid --fields option's argument:\n %s\n",
3620 text_legacy_opts
.no_delta
= true;
3622 case OPT_CLOCK_CYCLES
:
3623 text_legacy_opts
.clock_cycles
= true;
3625 case OPT_CLOCK_SECONDS
:
3626 text_legacy_opts
.clock_seconds
= true;
3628 case OPT_CLOCK_DATE
:
3629 text_legacy_opts
.clock_date
= true;
3632 text_legacy_opts
.clock_gmt
= true;
3634 case OPT_DEBUG_INFO_FULL_PATH
:
3635 text_legacy_opts
.dbg_info_full_path
= true;
3637 case OPT_CLOCK_OFFSET
:
3641 if (ctf_legacy_opts
.offset_s
.is_set
) {
3642 printf_err("Duplicate --clock-offset option\n");
3646 if (parse_int64(arg
, &val
)) {
3647 printf_err("Invalid --clock-offset option's argument:\n %s\n",
3652 set_offset_value(&ctf_legacy_opts
.offset_s
, val
);
3655 case OPT_CLOCK_OFFSET_NS
:
3659 if (ctf_legacy_opts
.offset_ns
.is_set
) {
3660 printf_err("Duplicate --clock-offset-ns option\n");
3664 if (parse_int64(arg
, &val
)) {
3665 printf_err("Invalid --clock-offset-ns option's argument:\n %s\n",
3670 set_offset_value(&ctf_legacy_opts
.offset_ns
, val
);
3673 case OPT_STREAM_INTERSECTION
:
3674 ctf_legacy_opts
.stream_intersection
= true;
3676 case OPT_CLOCK_FORCE_CORRELATE
:
3677 cfg
->cmd_data
.convert
.force_correlate
= true;
3680 if (!cur_cfg_comp
) {
3681 printf_err("Cannot add `begin` parameter to unavailable default source component `%s`:\n %s\n",
3682 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3685 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
3686 printf_err("--begin option must follow a --source option:\n %s\n",
3690 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3697 if (!cur_cfg_comp
) {
3698 printf_err("Cannot add `end` parameter to unavailable default source component `%s`:\n %s\n",
3699 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3702 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
3703 printf_err("--end option must follow a --source option:\n %s\n",
3707 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3715 const char *begin
, *end
;
3717 if (!cur_cfg_comp
) {
3718 printf_err("Cannot add `begin` and `end` parameters to unavailable default source component `%s`:\n %s\n",
3719 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3722 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
3723 printf_err("--timerange option must follow a --source option:\n %s\n",
3727 if (split_timerange(arg
, &begin
, &end
)) {
3728 printf_err("Invalid --timerange format: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
3732 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3737 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3745 if (bt_value_array_append_string(connection_args
,
3752 print_convert_usage(stdout
);
3757 cfg
->verbose
= true;
3763 printf_err("Unknown command-line option specified (option code %d)\n",
3772 /* Check for option parsing error */
3774 printf_err("While parsing command-line options, at option %s: %s\n",
3775 poptBadOption(pc
, 0), poptStrerror(opt
));
3779 /* Consume leftover arguments as legacy input paths */
3781 const char *input_path
= poptGetArg(pc
);
3787 if (bt_value_array_append_string(legacy_input_paths
,
3794 if (append_home_and_system_plugin_paths(
3795 cfg
->cmd_data
.convert
.plugin_paths
,
3796 cfg
->cmd_data
.convert
.omit_system_plugin_path
,
3797 cfg
->cmd_data
.convert
.omit_home_plugin_path
)) {
3798 printf_err("Cannot append home and system plugin paths\n");
3802 /* Append current component configuration, if any */
3803 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3804 add_cfg_comp(cfg
, cur_cfg_comp
, cur_cfg_comp_dest
);
3806 cur_cfg_comp
= NULL
;
3808 /* Validate legacy/non-legacy options */
3809 if (!validate_cfg(cfg
, &legacy_input_format
, &legacy_output_format
,
3810 legacy_input_paths
, &ctf_legacy_opts
,
3811 &text_legacy_opts
)) {
3812 printf_err("Command-line options form an invalid configuration\n");
3817 * If there's a legacy input format, convert it to source
3818 * component configurations.
3820 if (legacy_input_format
) {
3821 if (append_sources_from_legacy_opts(
3822 cfg
->cmd_data
.convert
.sources
,
3823 legacy_input_format
, &ctf_legacy_opts
,
3824 legacy_input_paths
)) {
3825 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
3828 if (append_sources_from_implicit_params(
3829 cfg
->cmd_data
.convert
.sources
,
3830 implicit_source_comp
)) {
3831 printf_err("Cannot initialize legacy component parameters\n");
3834 use_implicit_source
= false;
3836 if (use_implicit_source
) {
3837 add_cfg_comp(cfg
, implicit_source_comp
,
3838 BT_CONFIG_COMPONENT_DEST_SOURCE
);
3839 implicit_source_comp
= NULL
;
3841 if (implicit_source_comp
3842 && !bt_value_map_is_empty(implicit_source_comp
->params
)) {
3843 printf_err("Arguments specified for implicit input format, but an explicit source component instance has been specified: overriding it\n");
3850 * At this point if we need to print the CTF metadata text, we
3851 * don't care about the legacy/implicit sinks and component
3854 if (cfg
->cmd_data
.convert
.print_ctf_metadata
) {
3859 * If there's a legacy output format, convert it to sink
3860 * component configurations.
3862 if (legacy_output_format
) {
3863 if (append_sinks_from_legacy_opts(cfg
->cmd_data
.convert
.sinks
,
3864 legacy_output_format
, &text_legacy_opts
)) {
3865 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
3870 if (cfg
->cmd_data
.convert
.sinks
->len
== 0) {
3871 /* Use implicit sink as default. */
3872 cur_cfg_comp
= bt_config_component_from_arg(
3873 BT_COMPONENT_CLASS_TYPE_SINK
,
3874 DEFAULT_SINK_COMPONENT_NAME
);
3875 if (!cur_cfg_comp
) {
3876 printf_error("Cannot find implicit sink plugin `%s`\n",
3877 DEFAULT_SINK_COMPONENT_NAME
);
3879 add_cfg_comp(cfg
, cur_cfg_comp
,
3880 BT_CONFIG_COMPONENT_DEST_SINK
);
3881 cur_cfg_comp
= NULL
;
3884 ret
= bt_config_create_connections(cfg
, connection_args
,
3887 printf_err("Cannot creation connections:\n%s", error_buf
);
3899 poptFreeContext(pc
);
3902 if (text_legacy_opts
.output
) {
3903 g_string_free(text_legacy_opts
.output
, TRUE
);
3906 if (text_legacy_opts
.dbg_info_dir
) {
3907 g_string_free(text_legacy_opts
.dbg_info_dir
, TRUE
);
3910 if (text_legacy_opts
.dbg_info_target_prefix
) {
3911 g_string_free(text_legacy_opts
.dbg_info_target_prefix
, TRUE
);
3915 BT_PUT(implicit_source_comp
);
3916 BT_PUT(cur_cfg_comp
);
3917 BT_PUT(cur_base_params
);
3918 BT_PUT(text_legacy_opts
.names
);
3919 BT_PUT(text_legacy_opts
.fields
);
3920 BT_PUT(legacy_input_paths
);
3921 BT_PUT(instance_names
);
3922 BT_PUT(connection_args
);
3927 * Prints the Babeltrace 2.x general usage.
3930 void print_gen_usage(FILE *fp
)
3932 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
3934 fprintf(fp
, "General options:\n");
3936 fprintf(fp
, " -d, --debug Enable debug mode\n");
3937 fprintf(fp
, " -h --help Show this help and quit\n");
3938 fprintf(fp
, " --help-legacy Show Babeltrace 1.x legacy help and quit\n");
3939 fprintf(fp
, " -v, --verbose Enable verbose output\n");
3940 fprintf(fp
, " -V, --version Show version and quit\n");
3942 fprintf(fp
, "Available commands:\n");
3944 fprintf(fp
, " convert Build a trace conversion graph and run it (default)\n");
3945 fprintf(fp
, " help Get help for a plugin or a component class\n");
3946 fprintf(fp
, " list-plugins List available plugins and their content\n");
3947 fprintf(fp
, " query-info Query information from a component class\n");
3949 fprintf(fp
, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
3952 struct bt_config
*bt_config_from_args(int argc
, const char *argv
[],
3953 int *retcode
, bool omit_system_plugin_path
,
3954 bool omit_home_plugin_path
,
3955 struct bt_value
*initial_plugin_paths
)
3957 struct bt_config
*config
= NULL
;
3958 bool verbose
= false;
3961 enum bt_config_command command
= -1;
3962 const char **command_argv
= NULL
;
3963 int command_argc
= -1;
3964 const char *command_name
= NULL
;
3969 print_gen_usage(stdout
);
3973 for (i
= 1; i
< argc
; i
++) {
3974 const char *cur_arg
= argv
[i
];
3976 if (strcmp(cur_arg
, "-d") == 0 ||
3977 strcmp(cur_arg
, "--debug") == 0) {
3979 } else if (strcmp(cur_arg
, "-v") == 0 ||
3980 strcmp(cur_arg
, "--verbose") == 0) {
3982 } else if (strcmp(cur_arg
, "-V") == 0 ||
3983 strcmp(cur_arg
, "--version") == 0) {
3986 } else if (strcmp(cur_arg
, "-h") == 0 ||
3987 strcmp(cur_arg
, "--help") == 0) {
3988 print_gen_usage(stdout
);
3990 } else if (strcmp(cur_arg
, "--help-legacy") == 0) {
3991 print_legacy_usage(stdout
);
3994 bool has_command
= true;
3997 * First unknown argument: is it a known command
4000 if (strcmp(cur_arg
, "convert") == 0) {
4001 command
= BT_CONFIG_COMMAND_CONVERT
;
4002 } else if (strcmp(cur_arg
, "list-plugins") == 0) {
4003 command
= BT_CONFIG_COMMAND_LIST_PLUGINS
;
4004 } else if (strcmp(cur_arg
, "help") == 0) {
4005 command
= BT_CONFIG_COMMAND_HELP
;
4006 } else if (strcmp(cur_arg
, "query-info") == 0) {
4007 command
= BT_CONFIG_COMMAND_QUERY_INFO
;
4010 * Unknown argument, but not a known
4011 * command name: assume the whole
4012 * arguments are for the default convert
4015 command
= BT_CONFIG_COMMAND_CONVERT
;
4016 command_argv
= argv
;
4017 command_argc
= argc
;
4018 has_command
= false;
4022 command_argv
= &argv
[i
];
4023 command_argc
= argc
- i
;
4024 command_name
= cur_arg
;
4030 if ((int) command
< 0) {
4032 * We only got non-help, non-version general options
4033 * like --verbose and --debug, without any other
4034 * arguments, so we can't do anything useful: print the
4037 print_gen_usage(stdout
);
4041 assert(command_argv
);
4042 assert(command_argc
>= 0);
4045 case BT_CONFIG_COMMAND_CONVERT
:
4046 config
= bt_config_convert_from_args(command_argc
, command_argv
,
4047 retcode
, omit_system_plugin_path
,
4048 omit_home_plugin_path
, initial_plugin_paths
);
4050 case BT_CONFIG_COMMAND_LIST_PLUGINS
:
4051 config
= bt_config_list_plugins_from_args(command_argc
,
4052 command_argv
, retcode
, omit_system_plugin_path
,
4053 omit_home_plugin_path
, initial_plugin_paths
);
4055 case BT_CONFIG_COMMAND_HELP
:
4056 config
= bt_config_help_from_args(command_argc
,
4057 command_argv
, retcode
, omit_system_plugin_path
,
4058 omit_home_plugin_path
, initial_plugin_paths
);
4060 case BT_CONFIG_COMMAND_QUERY_INFO
:
4061 config
= bt_config_query_info_from_args(command_argc
,
4062 command_argv
, retcode
, omit_system_plugin_path
,
4063 omit_home_plugin_path
, initial_plugin_paths
);
4071 config
->verbose
= true;
4075 config
->debug
= true;
4078 config
->command_name
= command_name
;