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, "Command line 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
;
136 /* Legacy input format format */
137 enum legacy_input_format
{
138 LEGACY_INPUT_FORMAT_NONE
= 0,
139 LEGACY_INPUT_FORMAT_CTF
,
140 LEGACY_INPUT_FORMAT_LTTNG_LIVE
,
143 /* Legacy output format format */
144 enum legacy_output_format
{
145 LEGACY_OUTPUT_FORMAT_NONE
= 0,
146 LEGACY_OUTPUT_FORMAT_TEXT
,
147 LEGACY_OUTPUT_FORMAT_DUMMY
,
151 * Prints the "out of memory" error.
154 void print_err_oom(void)
156 printf_err("Out of memory\n");
160 * Prints duplicate legacy output format error.
163 void print_err_dup_legacy_output(void)
165 printf_err("More than one legacy output format specified\n");
169 * Prints duplicate legacy input format error.
172 void print_err_dup_legacy_input(void)
174 printf_err("More than one legacy input format specified\n");
178 * Checks if any of the "text" legacy options is set.
181 bool text_legacy_opts_is_any_set(struct text_legacy_opts
*opts
)
183 return (opts
->output
&& opts
->output
->len
> 0) ||
184 (opts
->dbg_info_dir
&& opts
->dbg_info_dir
->len
> 0) ||
185 (opts
->dbg_info_target_prefix
&&
186 opts
->dbg_info_target_prefix
->len
> 0) ||
187 bt_value_array_size(opts
->names
) > 0 ||
188 bt_value_array_size(opts
->fields
) > 0 ||
189 opts
->no_delta
|| opts
->clock_cycles
|| opts
->clock_seconds
||
190 opts
->clock_date
|| opts
->clock_gmt
||
191 opts
->dbg_info_full_path
;
195 * Checks if any of the "ctf" legacy options is set.
198 bool ctf_legacy_opts_is_any_set(struct ctf_legacy_opts
*opts
)
200 return opts
->offset_s
.is_set
|| opts
->offset_ns
.is_set
||
201 opts
->stream_intersection
;
205 * Appends an "expecting token" error to the INI-style parsing state's
209 void ini_append_error_expecting(struct ini_parsing_state
*state
,
210 GScanner
*scanner
, const char *expecting
)
215 g_string_append_printf(state
->ini_error
, "Expecting %s:\n", expecting
);
217 /* Only print error if there's one line */
218 if (strchr(state
->arg
, '\n') != NULL
|| strlen(state
->arg
) == 0) {
222 g_string_append_printf(state
->ini_error
, "\n %s\n", state
->arg
);
223 pos
= g_scanner_cur_position(scanner
) + 4;
225 if (!g_scanner_eof(scanner
)) {
229 for (i
= 0; i
< pos
; ++i
) {
230 g_string_append_printf(state
->ini_error
, " ");
233 g_string_append_printf(state
->ini_error
, "^\n\n");
237 int ini_handle_state(struct ini_parsing_state
*state
)
240 GTokenType token_type
;
241 struct bt_value
*value
= NULL
;
243 token_type
= g_scanner_get_next_token(state
->scanner
);
244 if (token_type
== G_TOKEN_EOF
) {
245 if (state
->expecting
!= INI_EXPECT_COMMA
) {
246 switch (state
->expecting
) {
247 case INI_EXPECT_EQUAL
:
248 ini_append_error_expecting(state
,
249 state
->scanner
, "'='");
251 case INI_EXPECT_VALUE
:
252 case INI_EXPECT_VALUE_NUMBER_NEG
:
253 ini_append_error_expecting(state
,
254 state
->scanner
, "value");
256 case INI_EXPECT_MAP_KEY
:
257 ini_append_error_expecting(state
,
258 state
->scanner
, "unquoted map key");
271 switch (state
->expecting
) {
272 case INI_EXPECT_MAP_KEY
:
273 if (token_type
!= G_TOKEN_IDENTIFIER
) {
274 ini_append_error_expecting(state
, state
->scanner
,
279 free(state
->last_map_key
);
280 state
->last_map_key
=
281 strdup(state
->scanner
->value
.v_identifier
);
282 if (!state
->last_map_key
) {
283 g_string_append(state
->ini_error
,
288 if (bt_value_map_has_key(state
->params
, state
->last_map_key
)) {
289 g_string_append_printf(state
->ini_error
,
290 "Duplicate parameter key: `%s`\n",
291 state
->last_map_key
);
295 state
->expecting
= INI_EXPECT_EQUAL
;
297 case INI_EXPECT_EQUAL
:
298 if (token_type
!= G_TOKEN_CHAR
) {
299 ini_append_error_expecting(state
,
300 state
->scanner
, "'='");
304 if (state
->scanner
->value
.v_char
!= '=') {
305 ini_append_error_expecting(state
,
306 state
->scanner
, "'='");
310 state
->expecting
= INI_EXPECT_VALUE
;
312 case INI_EXPECT_VALUE
:
314 switch (token_type
) {
316 if (state
->scanner
->value
.v_char
== '-') {
317 /* Negative number */
319 INI_EXPECT_VALUE_NUMBER_NEG
;
322 ini_append_error_expecting(state
,
323 state
->scanner
, "value");
329 /* Positive integer */
330 uint64_t int_val
= state
->scanner
->value
.v_int64
;
332 if (int_val
> (1ULL << 63) - 1) {
333 g_string_append_printf(state
->ini_error
,
334 "Integer value %" PRIu64
" is outside the range of a 64-bit signed integer\n",
339 value
= bt_value_integer_create_init(
344 /* Positive floating point number */
345 value
= bt_value_float_create_init(
346 state
->scanner
->value
.v_float
);
350 value
= bt_value_string_create_init(
351 state
->scanner
->value
.v_string
);
353 case G_TOKEN_IDENTIFIER
:
356 * Using symbols would be appropriate here,
357 * but said symbols are allowed as map key,
358 * so it's easier to consider everything an
361 * If one of the known symbols is not
362 * recognized here, then fall back to creating
365 const char *id
= state
->scanner
->value
.v_identifier
;
367 if (!strcmp(id
, "null") || !strcmp(id
, "NULL") ||
368 !strcmp(id
, "nul")) {
369 value
= bt_value_null
;
370 } else if (!strcmp(id
, "true") || !strcmp(id
, "TRUE") ||
371 !strcmp(id
, "yes") ||
372 !strcmp(id
, "YES")) {
373 value
= bt_value_bool_create_init(true);
374 } else if (!strcmp(id
, "false") ||
375 !strcmp(id
, "FALSE") ||
378 value
= bt_value_bool_create_init(false);
380 value
= bt_value_string_create_init(id
);
385 /* Unset value variable will trigger the error */
390 ini_append_error_expecting(state
,
391 state
->scanner
, "value");
395 state
->expecting
= INI_EXPECT_COMMA
;
398 case INI_EXPECT_VALUE_NUMBER_NEG
:
400 switch (token_type
) {
403 /* Negative integer */
404 uint64_t int_val
= state
->scanner
->value
.v_int64
;
406 if (int_val
> (1ULL << 63) - 1) {
407 g_string_append_printf(state
->ini_error
,
408 "Integer value -%" PRIu64
" is outside the range of a 64-bit signed integer\n",
413 value
= bt_value_integer_create_init(
414 -((int64_t) int_val
));
418 /* Negative floating point number */
419 value
= bt_value_float_create_init(
420 -state
->scanner
->value
.v_float
);
423 /* Unset value variable will trigger the error */
428 ini_append_error_expecting(state
,
429 state
->scanner
, "value");
433 state
->expecting
= INI_EXPECT_COMMA
;
436 case INI_EXPECT_COMMA
:
437 if (token_type
!= G_TOKEN_CHAR
) {
438 ini_append_error_expecting(state
,
439 state
->scanner
, "','");
443 if (state
->scanner
->value
.v_char
!= ',') {
444 ini_append_error_expecting(state
,
445 state
->scanner
, "','");
449 state
->expecting
= INI_EXPECT_MAP_KEY
;
461 if (bt_value_map_insert(state
->params
,
462 state
->last_map_key
, value
)) {
463 /* Only override return value on error */
474 * Converts an INI-style argument to an equivalent map value object.
476 * Return value is owned by the caller.
479 struct bt_value
*bt_value_from_ini(const char *arg
, GString
*ini_error
)
481 /* Lexical scanner configuration */
482 GScannerConfig scanner_config
= {
483 /* Skip whitespaces */
484 .cset_skip_characters
= " \t\n",
486 /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
487 .cset_identifier_first
=
491 .cset_identifier_nth
=
496 /* "hello" and "Hello" two different keys */
497 .case_sensitive
= TRUE
,
500 .cpair_comment_single
= NULL
,
501 .skip_comment_multi
= TRUE
,
502 .skip_comment_single
= TRUE
,
503 .scan_comment_multi
= FALSE
,
506 * Do scan identifiers, including 1-char identifiers,
507 * but NULL is a normal identifier.
509 .scan_identifier
= TRUE
,
510 .scan_identifier_1char
= TRUE
,
511 .scan_identifier_NULL
= FALSE
,
514 * No specific symbols: null and boolean "symbols" are
515 * scanned as plain identifiers.
517 .scan_symbols
= FALSE
,
518 .symbol_2_token
= FALSE
,
519 .scope_0_fallback
= FALSE
,
522 * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
523 * integers prefixed with "$".
529 .scan_hex_dollar
= FALSE
,
531 /* Convert scanned numbers to integer tokens */
532 .numbers_2_int
= TRUE
,
534 /* Support both integers and floating-point numbers */
535 .int_2_float
= FALSE
,
537 /* Scan integers as 64-bit signed integers */
540 /* Only scan double-quoted strings */
541 .scan_string_sq
= FALSE
,
542 .scan_string_dq
= TRUE
,
544 /* Do not converter identifiers to string tokens */
545 .identifier_2_string
= FALSE
,
547 /* Scan characters as G_TOKEN_CHAR token */
548 .char_2_token
= FALSE
,
550 struct ini_parsing_state state
= {
553 .expecting
= INI_EXPECT_MAP_KEY
,
555 .ini_error
= ini_error
,
558 state
.params
= bt_value_map_create();
563 state
.scanner
= g_scanner_new(&scanner_config
);
564 if (!state
.scanner
) {
568 /* Let the scan begin */
569 g_scanner_input_text(state
.scanner
, arg
, strlen(arg
));
572 int ret
= ini_handle_state(&state
);
577 } else if (ret
> 0) {
586 BT_PUT(state
.params
);
590 g_scanner_destroy(state
.scanner
);
593 free(state
.last_map_key
);
598 * Returns the parameters map value object from a command-line
599 * parameter option's argument.
601 * Return value is owned by the caller.
604 struct bt_value
*bt_value_from_arg(const char *arg
)
606 struct bt_value
*params
= NULL
;
607 GString
*ini_error
= NULL
;
609 ini_error
= g_string_new(NULL
);
615 /* Try INI-style parsing */
616 params
= bt_value_from_ini(arg
, ini_error
);
618 printf_err("%s", ini_error
->str
);
624 g_string_free(ini_error
, TRUE
);
630 * Returns the plugin and component names from a command-line
631 * source/sink option's argument. arg must have the following format:
635 * where PLUGIN is the plugin name, and COMPONENT is the component
638 * On success, both *plugin and *component are not NULL. *plugin
639 * and *component are owned by the caller.
642 void plugin_component_names_from_arg(const char *arg
, char **plugin
,
645 const char *arg_ch
= arg
;
647 bool in_component
= false;
649 /* Initialize both return values */
650 *plugin
= g_malloc0(strlen(arg
) + 1);
657 *component
= g_malloc0(strlen(arg
) + 1);
663 while (*arg_ch
!= '\0') {
666 if (arg_ch
[1] == '\0') {
667 /* `\` at the end of the string */
671 } else if (arg_ch
[1] == '\\' || arg_ch
[1] == '.') {
672 /* Escaped `\` or `.` */
677 /* Unknown escaped character (write `\` too) */
702 if (strlen(*plugin
) == 0 || strlen(*component
) == 0) {
719 * Prints the Babeltrace version.
722 void print_version(void)
724 puts("Babeltrace " VERSION
);
728 * Destroys a component configuration.
731 void bt_config_component_destroy(struct bt_object
*obj
)
733 struct bt_config_component
*bt_config_component
=
734 container_of(obj
, struct bt_config_component
, base
);
740 if (bt_config_component
->plugin_name
) {
741 g_string_free(bt_config_component
->plugin_name
, TRUE
);
744 if (bt_config_component
->component_name
) {
745 g_string_free(bt_config_component
->component_name
, TRUE
);
748 if (bt_config_component
->instance_name
) {
749 g_string_free(bt_config_component
->instance_name
, TRUE
);
752 BT_PUT(bt_config_component
->params
);
753 g_free(bt_config_component
);
760 * Creates a component configuration using the given plugin name and
761 * component name. plugin_name and component_name are copied (belong to
764 * Return value is owned by the caller.
767 struct bt_config_component
*bt_config_component_create(
768 enum bt_component_class_type type
,
769 const char *plugin_name
, const char *component_name
)
771 struct bt_config_component
*cfg_component
= NULL
;
773 cfg_component
= g_new0(struct bt_config_component
, 1);
774 if (!cfg_component
) {
779 bt_object_init(cfg_component
, bt_config_component_destroy
);
780 cfg_component
->type
= type
;
781 cfg_component
->plugin_name
= g_string_new(plugin_name
);
782 if (!cfg_component
->plugin_name
) {
787 cfg_component
->component_name
= g_string_new(component_name
);
788 if (!cfg_component
->component_name
) {
793 cfg_component
->instance_name
= g_string_new(NULL
);
794 if (!cfg_component
->instance_name
) {
799 /* Start with empty parameters */
800 cfg_component
->params
= bt_value_map_create();
801 if (!cfg_component
->params
) {
809 BT_PUT(cfg_component
);
812 return cfg_component
;
816 * Creates a component configuration from a command-line source/sink
819 struct bt_config_component
*bt_config_component_from_arg(
820 enum bt_component_class_type type
, const char *arg
)
822 struct bt_config_component
*bt_config_component
= NULL
;
824 char *component_name
;
826 plugin_component_names_from_arg(arg
, &plugin_name
, &component_name
);
827 if (!plugin_name
|| !component_name
) {
828 printf_err("Cannot get plugin or component class name\n");
832 bt_config_component
= bt_config_component_create(type
, plugin_name
,
834 if (!bt_config_component
) {
841 BT_PUT(bt_config_component
);
845 g_free(component_name
);
846 return bt_config_component
;
850 * Destroys a configuration.
853 void bt_config_destroy(struct bt_object
*obj
)
855 struct bt_config
*cfg
=
856 container_of(obj
, struct bt_config
, base
);
862 switch (cfg
->command
) {
863 case BT_CONFIG_COMMAND_CONVERT
:
864 if (cfg
->cmd_data
.convert
.sources
) {
865 g_ptr_array_free(cfg
->cmd_data
.convert
.sources
, TRUE
);
868 if (cfg
->cmd_data
.convert
.filters
) {
869 g_ptr_array_free(cfg
->cmd_data
.convert
.filters
, TRUE
);
872 if (cfg
->cmd_data
.convert
.sinks
) {
873 g_ptr_array_free(cfg
->cmd_data
.convert
.sinks
, TRUE
);
876 if (cfg
->cmd_data
.convert
.connections
) {
877 g_ptr_array_free(cfg
->cmd_data
.convert
.connections
,
881 BT_PUT(cfg
->cmd_data
.convert
.plugin_paths
);
883 case BT_CONFIG_COMMAND_LIST_PLUGINS
:
884 BT_PUT(cfg
->cmd_data
.list_plugins
.plugin_paths
);
886 case BT_CONFIG_COMMAND_HELP
:
887 BT_PUT(cfg
->cmd_data
.help
.plugin_paths
);
888 BT_PUT(cfg
->cmd_data
.help
.cfg_component
);
890 case BT_CONFIG_COMMAND_QUERY
:
891 BT_PUT(cfg
->cmd_data
.query
.plugin_paths
);
892 BT_PUT(cfg
->cmd_data
.query
.cfg_component
);
894 if (cfg
->cmd_data
.query
.object
) {
895 g_string_free(cfg
->cmd_data
.query
.object
, TRUE
);
908 static void destroy_gstring(void *data
)
910 g_string_free(data
, TRUE
);
914 * Extracts the various paths from the string arg, delimited by ':',
915 * and appends them to the array value object plugin_paths.
917 enum bt_value_status
bt_config_append_plugin_paths(
918 struct bt_value
*plugin_paths
, const char *arg
)
920 enum bt_value_status status
= BT_VALUE_STATUS_OK
;
921 GPtrArray
*dirs
= g_ptr_array_new_with_free_func(destroy_gstring
);
926 status
= BT_VALUE_STATUS_ERROR
;
930 ret
= bt_common_append_plugin_path_dirs(arg
, dirs
);
932 status
= BT_VALUE_STATUS_ERROR
;
936 for (i
= 0; i
< dirs
->len
; i
++) {
937 GString
*dir
= g_ptr_array_index(dirs
, i
);
939 bt_value_array_append_string(plugin_paths
, dir
->str
);
943 g_ptr_array_free(dirs
, TRUE
);
948 * Creates a simple lexical scanner for parsing comma-delimited names
951 * Return value is owned by the caller.
954 GScanner
*create_csv_identifiers_scanner(void)
956 GScannerConfig scanner_config
= {
957 .cset_skip_characters
= " \t\n",
958 .cset_identifier_first
= G_CSET_a_2_z G_CSET_A_2_Z
"_",
959 .cset_identifier_nth
= G_CSET_a_2_z G_CSET_A_2_Z
":_-",
960 .case_sensitive
= TRUE
,
961 .cpair_comment_single
= NULL
,
962 .skip_comment_multi
= TRUE
,
963 .skip_comment_single
= TRUE
,
964 .scan_comment_multi
= FALSE
,
965 .scan_identifier
= TRUE
,
966 .scan_identifier_1char
= TRUE
,
967 .scan_identifier_NULL
= FALSE
,
968 .scan_symbols
= FALSE
,
969 .symbol_2_token
= FALSE
,
970 .scope_0_fallback
= FALSE
,
971 .scan_binary
= FALSE
,
975 .scan_hex_dollar
= FALSE
,
976 .numbers_2_int
= FALSE
,
977 .int_2_float
= FALSE
,
978 .store_int64
= FALSE
,
979 .scan_string_sq
= FALSE
,
980 .scan_string_dq
= FALSE
,
981 .identifier_2_string
= FALSE
,
982 .char_2_token
= TRUE
,
985 return g_scanner_new(&scanner_config
);
989 * Inserts a string (if exists and not empty) or null to a map value
993 enum bt_value_status
map_insert_string_or_null(struct bt_value
*map
,
994 const char *key
, GString
*string
)
996 enum bt_value_status ret
;
998 if (string
&& string
->len
> 0) {
999 ret
= bt_value_map_insert_string(map
, key
, string
->str
);
1001 ret
= bt_value_map_insert(map
, key
, bt_value_null
);
1007 * Converts a comma-delimited list of known names (--names option) to
1008 * an array value object containing those names as string value objects.
1010 * Return value is owned by the caller.
1013 struct bt_value
*names_from_arg(const char *arg
)
1015 GScanner
*scanner
= NULL
;
1016 struct bt_value
*names
= NULL
;
1017 bool found_all
= false, found_none
= false, found_item
= false;
1019 names
= bt_value_array_create();
1025 scanner
= create_csv_identifiers_scanner();
1031 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1034 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1036 switch (token_type
) {
1037 case G_TOKEN_IDENTIFIER
:
1039 const char *identifier
= scanner
->value
.v_identifier
;
1041 if (!strcmp(identifier
, "payload") ||
1042 !strcmp(identifier
, "args") ||
1043 !strcmp(identifier
, "arg")) {
1045 if (bt_value_array_append_string(names
,
1049 } else if (!strcmp(identifier
, "context") ||
1050 !strcmp(identifier
, "ctx")) {
1052 if (bt_value_array_append_string(names
,
1056 } else if (!strcmp(identifier
, "scope") ||
1057 !strcmp(identifier
, "header")) {
1059 if (bt_value_array_append_string(names
,
1063 } else if (!strcmp(identifier
, "all")) {
1065 if (bt_value_array_append_string(names
,
1069 } else if (!strcmp(identifier
, "none")) {
1071 if (bt_value_array_append_string(names
,
1076 printf_err("Unknown field name: `%s`\n",
1092 if (found_none
&& found_all
) {
1093 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
1097 * Legacy behavior is to clear the defaults (show none) when at
1098 * least one item is specified.
1100 if (found_item
&& !found_none
&& !found_all
) {
1101 if (bt_value_array_append_string(names
, "none")) {
1106 g_scanner_destroy(scanner
);
1113 g_scanner_destroy(scanner
);
1120 * Converts a comma-delimited list of known fields (--fields option) to
1121 * an array value object containing those fields as string
1124 * Return value is owned by the caller.
1127 struct bt_value
*fields_from_arg(const char *arg
)
1129 GScanner
*scanner
= NULL
;
1130 struct bt_value
*fields
;
1132 fields
= bt_value_array_create();
1138 scanner
= create_csv_identifiers_scanner();
1144 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1147 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1149 switch (token_type
) {
1150 case G_TOKEN_IDENTIFIER
:
1152 const char *identifier
= scanner
->value
.v_identifier
;
1154 if (!strcmp(identifier
, "trace") ||
1155 !strcmp(identifier
, "trace:hostname") ||
1156 !strcmp(identifier
, "trace:domain") ||
1157 !strcmp(identifier
, "trace:procname") ||
1158 !strcmp(identifier
, "trace:vpid") ||
1159 !strcmp(identifier
, "loglevel") ||
1160 !strcmp(identifier
, "emf") ||
1161 !strcmp(identifier
, "callsite") ||
1162 !strcmp(identifier
, "all")) {
1163 if (bt_value_array_append_string(fields
,
1168 printf_err("Unknown field name: `%s`\n",
1190 g_scanner_destroy(scanner
);
1196 * Inserts the equivalent "prefix-name" true boolean value objects into
1197 * map_obj where the names are in array_obj.
1200 int insert_flat_names_fields_from_array(struct bt_value
*map_obj
,
1201 struct bt_value
*array_obj
, const char *prefix
)
1205 GString
*tmpstr
= NULL
, *default_value
= NULL
;
1208 * array_obj may be NULL if no CLI options were specified to
1209 * trigger its creation.
1215 tmpstr
= g_string_new(NULL
);
1222 default_value
= g_string_new(NULL
);
1223 if (!default_value
) {
1229 for (i
= 0; i
< bt_value_array_size(array_obj
); i
++) {
1230 struct bt_value
*str_obj
= bt_value_array_get(array_obj
, i
);
1232 bool is_default
= false;
1235 printf_err("Unexpected error\n");
1240 ret
= bt_value_string_get(str_obj
, &suffix
);
1243 printf_err("Unexpected error\n");
1247 g_string_assign(tmpstr
, prefix
);
1248 g_string_append(tmpstr
, "-");
1250 /* Special-case for "all" and "none". */
1251 if (!strcmp(suffix
, "all")) {
1253 g_string_assign(default_value
, "show");
1254 } else if (!strcmp(suffix
, "none")) {
1256 g_string_assign(default_value
, "hide");
1259 g_string_append(tmpstr
, "default");
1260 ret
= map_insert_string_or_null(map_obj
,
1268 g_string_append(tmpstr
, suffix
);
1269 ret
= bt_value_map_insert_bool(map_obj
, tmpstr
->str
,
1279 if (default_value
) {
1280 g_string_free(default_value
, TRUE
);
1283 g_string_free(tmpstr
, TRUE
);
1290 * Returns the parameters (map value object) corresponding to the
1291 * legacy text format options.
1293 * Return value is owned by the caller.
1296 struct bt_value
*params_from_text_legacy_opts(
1297 struct text_legacy_opts
*text_legacy_opts
)
1299 struct bt_value
*params
;
1301 params
= bt_value_map_create();
1307 if (map_insert_string_or_null(params
, "output-path",
1308 text_legacy_opts
->output
)) {
1313 if (map_insert_string_or_null(params
, "debug-info-dir",
1314 text_legacy_opts
->dbg_info_dir
)) {
1319 if (map_insert_string_or_null(params
, "debug-info-target-prefix",
1320 text_legacy_opts
->dbg_info_target_prefix
)) {
1325 if (bt_value_map_insert_bool(params
, "debug-info-full-path",
1326 text_legacy_opts
->dbg_info_full_path
)) {
1331 if (bt_value_map_insert_bool(params
, "no-delta",
1332 text_legacy_opts
->no_delta
)) {
1337 if (bt_value_map_insert_bool(params
, "clock-cycles",
1338 text_legacy_opts
->clock_cycles
)) {
1343 if (bt_value_map_insert_bool(params
, "clock-seconds",
1344 text_legacy_opts
->clock_seconds
)) {
1349 if (bt_value_map_insert_bool(params
, "clock-date",
1350 text_legacy_opts
->clock_date
)) {
1355 if (bt_value_map_insert_bool(params
, "clock-gmt",
1356 text_legacy_opts
->clock_gmt
)) {
1361 if (bt_value_map_insert_bool(params
, "verbose",
1362 text_legacy_opts
->verbose
)) {
1367 if (insert_flat_names_fields_from_array(params
,
1368 text_legacy_opts
->names
, "name")) {
1372 if (insert_flat_names_fields_from_array(params
,
1373 text_legacy_opts
->fields
, "field")) {
1387 int append_sinks_from_legacy_opts(GPtrArray
*sinks
,
1388 enum legacy_output_format legacy_output_format
,
1389 struct text_legacy_opts
*text_legacy_opts
)
1392 struct bt_value
*params
= NULL
;
1393 const char *plugin_name
;
1394 const char *component_name
;
1395 struct bt_config_component
*bt_config_component
= NULL
;
1397 switch (legacy_output_format
) {
1398 case LEGACY_OUTPUT_FORMAT_TEXT
:
1399 plugin_name
= "text";
1400 component_name
= "text";
1402 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1403 plugin_name
= "utils";
1404 component_name
= "dummy";
1411 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
) {
1412 /* Legacy "text" output format has parameters */
1413 params
= params_from_text_legacy_opts(text_legacy_opts
);
1419 * Legacy "dummy" and "ctf-metadata" output formats do
1420 * not have parameters.
1422 params
= bt_value_map_create();
1429 /* Create a component configuration */
1430 bt_config_component
= bt_config_component_create(
1431 BT_COMPONENT_CLASS_TYPE_SINK
, plugin_name
, component_name
);
1432 if (!bt_config_component
) {
1436 BT_MOVE(bt_config_component
->params
, params
);
1438 /* Move created component configuration to the array */
1439 g_ptr_array_add(sinks
, bt_config_component
);
1453 * Returns the parameters (map value object) corresponding to the
1454 * given legacy CTF format options.
1456 * Return value is owned by the caller.
1459 struct bt_value
*params_from_ctf_legacy_opts(
1460 struct ctf_legacy_opts
*ctf_legacy_opts
)
1462 struct bt_value
*params
;
1464 params
= bt_value_map_create();
1470 if (bt_value_map_insert_integer(params
, "offset-s",
1471 ctf_legacy_opts
->offset_s
.value
)) {
1476 if (bt_value_map_insert_integer(params
, "offset-ns",
1477 ctf_legacy_opts
->offset_ns
.value
)) {
1482 if (bt_value_map_insert_bool(params
, "stream-intersection",
1483 ctf_legacy_opts
->stream_intersection
)) {
1498 int append_sources_from_legacy_opts(GPtrArray
*sources
,
1499 enum legacy_input_format legacy_input_format
,
1500 struct ctf_legacy_opts
*ctf_legacy_opts
,
1501 struct bt_value
*legacy_input_paths
)
1505 struct bt_value
*base_params
;
1506 struct bt_value
*params
= NULL
;
1507 struct bt_value
*input_path
= NULL
;
1508 struct bt_value
*input_path_copy
= NULL
;
1509 const char *input_key
;
1510 const char *component_name
;
1512 switch (legacy_input_format
) {
1513 case LEGACY_INPUT_FORMAT_CTF
:
1515 component_name
= "fs";
1517 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1519 component_name
= "lttng-live";
1526 base_params
= params_from_ctf_legacy_opts(ctf_legacy_opts
);
1531 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1532 struct bt_config_component
*bt_config_component
= NULL
;
1534 /* Copy base parameters as current parameters */
1535 params
= bt_value_copy(base_params
);
1540 /* Get current input path string value object */
1541 input_path
= bt_value_array_get(legacy_input_paths
, i
);
1546 /* Copy current input path value object */
1547 input_path_copy
= bt_value_copy(input_path
);
1548 if (!input_path_copy
) {
1552 /* Insert input path value object into current parameters */
1553 ret
= bt_value_map_insert(params
, input_key
, input_path_copy
);
1558 /* Create a component configuration */
1559 bt_config_component
= bt_config_component_create(
1560 BT_COMPONENT_CLASS_TYPE_SOURCE
, "ctf", component_name
);
1561 if (!bt_config_component
) {
1565 BT_MOVE(bt_config_component
->params
, params
);
1567 /* Move created component configuration to the array */
1568 g_ptr_array_add(sources
, bt_config_component
);
1570 /* Put current stuff */
1572 BT_PUT(input_path_copy
);
1581 BT_PUT(base_params
);
1584 BT_PUT(input_path_copy
);
1589 * Escapes a string for the shell. The string is escaped knowing that
1590 * it's a parameter string value (double-quoted), and that it will be
1591 * entered between single quotes in the shell.
1593 * Return value is owned by the caller.
1596 char *str_shell_escape(const char *input
)
1599 const char *at
= input
;
1600 GString
*str
= g_string_new(NULL
);
1606 while (*at
!= '\0') {
1609 g_string_append(str
, "\\\\");
1612 g_string_append(str
, "\\\"");
1615 g_string_append(str
, "'\"'\"'");
1618 g_string_append(str
, "\\n");
1621 g_string_append(str
, "\\t");
1624 g_string_append_c(str
, *at
);
1634 g_string_free(str
, FALSE
);
1641 int append_prefixed_flag_params(GString
*str
, struct bt_value
*flags
,
1651 for (i
= 0; i
< bt_value_array_size(flags
); i
++) {
1652 struct bt_value
*value
= bt_value_array_get(flags
, i
);
1660 if (bt_value_string_get(value
, &flag
)) {
1666 g_string_append_printf(str
, ",%s-%s=true", prefix
, flag
);
1675 * Appends a boolean parameter string.
1678 void g_string_append_bool_param(GString
*str
, const char *name
, bool value
)
1680 g_string_append_printf(str
, ",%s=%s", name
, value
? "true" : "false");
1684 * Appends a path parameter string, or null if it's empty.
1687 int g_string_append_string_path_param(GString
*str
, const char *name
,
1692 if (path
->len
> 0) {
1693 char *escaped_path
= str_shell_escape(path
->str
);
1695 if (!escaped_path
) {
1700 g_string_append_printf(str
, "%s=\"%s\"", name
, escaped_path
);
1703 g_string_append_printf(str
, "%s=null", name
);
1716 * Prints the non-legacy sink options equivalent to the specified
1717 * legacy output format options.
1720 void print_output_legacy_to_sinks(
1721 enum legacy_output_format legacy_output_format
,
1722 struct text_legacy_opts
*text_legacy_opts
)
1724 const char *output_format
;
1725 GString
*str
= NULL
;
1727 str
= g_string_new(" ");
1733 switch (legacy_output_format
) {
1734 case LEGACY_OUTPUT_FORMAT_TEXT
:
1735 output_format
= "text";
1737 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1738 output_format
= "dummy";
1744 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
1746 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
1748 g_string_append(str
, "-o ");
1750 switch (legacy_output_format
) {
1751 case LEGACY_OUTPUT_FORMAT_TEXT
:
1752 g_string_append(str
, "text.text");
1754 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1755 g_string_append(str
, "utils.dummy");
1761 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
&&
1762 text_legacy_opts_is_any_set(text_legacy_opts
)) {
1765 g_string_append(str
, " -p '");
1767 if (g_string_append_string_path_param(str
, "output-path",
1768 text_legacy_opts
->output
)) {
1772 g_string_append(str
, ",");
1774 if (g_string_append_string_path_param(str
, "debug-info-dir",
1775 text_legacy_opts
->dbg_info_dir
)) {
1779 g_string_append(str
, ",");
1781 if (g_string_append_string_path_param(str
,
1782 "debug-info-target-prefix",
1783 text_legacy_opts
->dbg_info_target_prefix
)) {
1787 g_string_append_bool_param(str
, "no-delta",
1788 text_legacy_opts
->no_delta
);
1789 g_string_append_bool_param(str
, "clock-cycles",
1790 text_legacy_opts
->clock_cycles
);
1791 g_string_append_bool_param(str
, "clock-seconds",
1792 text_legacy_opts
->clock_seconds
);
1793 g_string_append_bool_param(str
, "clock-date",
1794 text_legacy_opts
->clock_date
);
1795 g_string_append_bool_param(str
, "clock-gmt",
1796 text_legacy_opts
->clock_gmt
);
1797 g_string_append_bool_param(str
, "verbose",
1798 text_legacy_opts
->verbose
);
1799 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->names
,
1805 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->fields
,
1811 /* Remove last comma and close single quote */
1812 g_string_append(str
, "'");
1815 printf_err("%s\n\n", str
->str
);
1819 g_string_free(str
, TRUE
);
1825 * Prints the non-legacy source options equivalent to the specified
1826 * legacy input format options.
1829 void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format
,
1830 struct bt_value
*legacy_input_paths
,
1831 struct ctf_legacy_opts
*ctf_legacy_opts
)
1833 const char *input_format
;
1834 GString
*str
= NULL
;
1837 str
= g_string_new(" ");
1843 switch (legacy_input_format
) {
1844 case LEGACY_INPUT_FORMAT_CTF
:
1845 input_format
= "ctf";
1847 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1848 input_format
= "lttng-live";
1854 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
1856 printf_err("Specify the following non-legacy source component instance(s) instead of the\nlegacy `%s` input format options and positional arguments:\n\n",
1859 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1860 struct bt_value
*input_value
=
1861 bt_value_array_get(legacy_input_paths
, i
);
1862 const char *input
= NULL
;
1863 char *escaped_input
;
1866 assert(input_value
);
1867 ret
= bt_value_string_get(input_value
, &input
);
1868 BT_PUT(input_value
);
1869 assert(!ret
&& input
);
1870 escaped_input
= str_shell_escape(input
);
1871 if (!escaped_input
) {
1876 g_string_append(str
, "-i ctf.");
1878 switch (legacy_input_format
) {
1879 case LEGACY_INPUT_FORMAT_CTF
:
1880 g_string_append(str
, "fs -p 'path=\"");
1882 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1883 g_string_append(str
, "lttng-live -p 'url=\"");
1889 g_string_append(str
, escaped_input
);
1890 g_string_append(str
, "\"");
1891 g_string_append_printf(str
, ",offset-s=%" PRId64
,
1892 ctf_legacy_opts
->offset_s
.value
);
1893 g_string_append_printf(str
, ",offset-ns=%" PRId64
,
1894 ctf_legacy_opts
->offset_ns
.value
);
1895 g_string_append_bool_param(str
, "stream-intersection",
1896 ctf_legacy_opts
->stream_intersection
);
1897 g_string_append(str
, "' ");
1898 g_free(escaped_input
);
1901 printf_err("%s\n\n", str
->str
);
1905 g_string_free(str
, TRUE
);
1911 * Validates a given configuration, with optional legacy input and
1912 * output formats options. Prints useful error messages if anything
1915 * Returns true when the configuration is valid.
1918 bool validate_cfg(struct bt_config
*cfg
,
1919 enum legacy_input_format
*legacy_input_format
,
1920 enum legacy_output_format
*legacy_output_format
,
1921 struct bt_value
*legacy_input_paths
,
1922 struct ctf_legacy_opts
*ctf_legacy_opts
,
1923 struct text_legacy_opts
*text_legacy_opts
)
1925 bool legacy_input
= false;
1926 bool legacy_output
= false;
1928 /* Determine if the input and output should be legacy-style */
1929 if (cfg
->cmd_data
.convert
.print_ctf_metadata
||
1930 *legacy_input_format
!= LEGACY_INPUT_FORMAT_NONE
||
1931 !bt_value_array_is_empty(legacy_input_paths
) ||
1932 ctf_legacy_opts_is_any_set(ctf_legacy_opts
)) {
1933 legacy_input
= true;
1936 if (*legacy_output_format
!= LEGACY_OUTPUT_FORMAT_NONE
||
1937 text_legacy_opts_is_any_set(text_legacy_opts
)) {
1938 legacy_output
= true;
1942 /* If no legacy input format was specified, default to CTF */
1943 if (*legacy_input_format
== LEGACY_INPUT_FORMAT_NONE
) {
1944 *legacy_input_format
= LEGACY_INPUT_FORMAT_CTF
;
1947 /* Make sure at least one input path exists */
1948 if (bt_value_array_is_empty(legacy_input_paths
)) {
1949 switch (*legacy_input_format
) {
1950 case LEGACY_INPUT_FORMAT_CTF
:
1951 printf_err("No input path specified for legacy `ctf` input format\n");
1953 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1954 printf_err("No URL specified for legacy `lttng-live` input format\n");
1962 /* Make sure no non-legacy sources are specified */
1963 if (cfg
->cmd_data
.convert
.sources
->len
!= 0) {
1964 if (cfg
->cmd_data
.convert
.print_ctf_metadata
) {
1965 printf_err("You cannot instantiate a source component with the `ctf-metadata` output format\n");
1967 print_input_legacy_to_sources(
1968 *legacy_input_format
,
1969 legacy_input_paths
, ctf_legacy_opts
);
1977 * Strict rule: if we need to print the CTF metadata, the input
1978 * format must be legacy and CTF. Also there should be no
1979 * other sinks, and no legacy output format.
1981 if (cfg
->cmd_data
.convert
.print_ctf_metadata
) {
1982 if (*legacy_input_format
!= LEGACY_INPUT_FORMAT_CTF
) {
1983 printf_err("The `ctf-metadata` output format requires legacy `ctf` input format\n");
1987 if (bt_value_array_size(legacy_input_paths
) != 1) {
1988 printf_err("You need to specify exactly one path with the `ctf-metadata` output format\n");
1992 if (legacy_output
) {
1993 printf_err("You cannot use another legacy output format with the `ctf-metadata` output format\n");
1997 if (cfg
->cmd_data
.convert
.sinks
->len
!= 0) {
1998 printf_err("You cannot instantiate a sink component with the `ctf-metadata` output format\n");
2002 } else if (legacy_output
) {
2004 * If no legacy output format was specified, default to
2007 if (*legacy_output_format
== LEGACY_OUTPUT_FORMAT_NONE
) {
2008 *legacy_output_format
= LEGACY_OUTPUT_FORMAT_TEXT
;
2012 * If any "text" option was specified, the output must be
2015 if (text_legacy_opts_is_any_set(text_legacy_opts
) &&
2016 *legacy_output_format
!=
2017 LEGACY_OUTPUT_FORMAT_TEXT
) {
2018 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
2022 /* Make sure no non-legacy sinks are specified */
2023 if (cfg
->cmd_data
.convert
.sinks
->len
!= 0) {
2024 print_output_legacy_to_sinks(*legacy_output_format
,
2037 * Parses a 64-bit signed integer.
2039 * Returns a negative value if anything goes wrong.
2042 int parse_int64(const char *arg
, int64_t *val
)
2047 *val
= strtoll(arg
, &endptr
, 0);
2048 if (*endptr
!= '\0' || arg
== endptr
|| errno
!= 0) {
2062 OPT_CLOCK_FORCE_CORRELATE
,
2065 OPT_CLOCK_OFFSET_NS
,
2070 OPT_DEBUG_INFO_FULL_PATH
,
2071 OPT_DEBUG_INFO_TARGET_PREFIX
,
2081 OPT_OMIT_HOME_PLUGIN_PATH
,
2082 OPT_OMIT_SYSTEM_PLUGIN_PATH
,
2088 OPT_RESET_BASE_PARAMS
,
2091 OPT_STREAM_INTERSECTION
,
2097 * Sets the value of a given legacy offset option and marks it as set.
2099 static void set_offset_value(struct offset_opt
*offset_opt
, int64_t value
)
2101 offset_opt
->value
= value
;
2102 offset_opt
->is_set
= true;
2105 enum bt_config_component_dest
{
2106 BT_CONFIG_COMPONENT_DEST_SOURCE
,
2107 BT_CONFIG_COMPONENT_DEST_FILTER
,
2108 BT_CONFIG_COMPONENT_DEST_SINK
,
2112 * Adds a configuration component to the appropriate configuration
2113 * array depending on the destination.
2115 static void add_cfg_comp(struct bt_config
*cfg
,
2116 struct bt_config_component
*cfg_comp
,
2117 enum bt_config_component_dest dest
)
2120 case BT_CONFIG_COMPONENT_DEST_SOURCE
:
2121 g_ptr_array_add(cfg
->cmd_data
.convert
.sources
, cfg_comp
);
2123 case BT_CONFIG_COMPONENT_DEST_FILTER
:
2124 g_ptr_array_add(cfg
->cmd_data
.convert
.filters
, cfg_comp
);
2126 case BT_CONFIG_COMPONENT_DEST_SINK
:
2127 g_ptr_array_add(cfg
->cmd_data
.convert
.sinks
, cfg_comp
);
2134 static int split_timerange(const char *arg
, const char **begin
, const char **end
)
2138 /* Try to match [begin,end] */
2139 c
= strchr(arg
, '[');
2153 /* Try to match begin,end */
2167 static int append_env_var_plugin_paths(struct bt_value
*plugin_paths
)
2172 if (bt_common_is_setuid_setgid()) {
2173 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2177 envvar
= getenv("BABELTRACE_PLUGIN_PATH");
2182 ret
= bt_config_append_plugin_paths(plugin_paths
, envvar
);
2188 static int append_home_and_system_plugin_paths(struct bt_value
*plugin_paths
,
2189 bool omit_system_plugin_path
, bool omit_home_plugin_path
)
2193 if (!omit_home_plugin_path
) {
2194 if (bt_common_is_setuid_setgid()) {
2195 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2197 char *home_plugin_dir
=
2198 bt_common_get_home_plugin_path();
2200 if (home_plugin_dir
) {
2201 ret
= bt_config_append_plugin_paths(
2204 free(home_plugin_dir
);
2207 printf_err("Invalid home plugin path\n");
2214 if (!omit_system_plugin_path
) {
2215 if (bt_config_append_plugin_paths(plugin_paths
,
2216 bt_common_get_system_plugin_path())) {
2217 printf_err("Invalid system plugin path\n");
2226 static int append_sources_from_implicit_params(GPtrArray
*sources
,
2227 struct bt_config_component
*implicit_source_comp
)
2230 size_t len
= sources
->len
;
2232 for (i
= 0; i
< len
; i
++) {
2233 struct bt_config_component
*comp
;
2234 struct bt_value
*params_to_set
;
2236 comp
= g_ptr_array_index(sources
, i
);
2237 params_to_set
= bt_value_map_extend(comp
->params
,
2238 implicit_source_comp
->params
);
2239 if (!params_to_set
) {
2240 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2243 BT_MOVE(comp
->params
, params_to_set
);
2250 static struct bt_config
*bt_config_base_create(enum bt_config_command command
)
2252 struct bt_config
*cfg
;
2255 cfg
= g_new0(struct bt_config
, 1);
2261 bt_object_init(cfg
, bt_config_destroy
);
2262 cfg
->command
= command
;
2272 static struct bt_config
*bt_config_convert_create(
2273 struct bt_value
*initial_plugin_paths
)
2275 struct bt_config
*cfg
;
2278 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_CONVERT
);
2284 cfg
->cmd_data
.convert
.sources
= g_ptr_array_new_with_free_func(
2285 (GDestroyNotify
) bt_put
);
2286 if (!cfg
->cmd_data
.convert
.sources
) {
2291 cfg
->cmd_data
.convert
.filters
= g_ptr_array_new_with_free_func(
2292 (GDestroyNotify
) bt_put
);
2293 if (!cfg
->cmd_data
.convert
.filters
) {
2298 cfg
->cmd_data
.convert
.sinks
= g_ptr_array_new_with_free_func(
2299 (GDestroyNotify
) bt_put
);
2300 if (!cfg
->cmd_data
.convert
.sinks
) {
2305 cfg
->cmd_data
.convert
.connections
= g_ptr_array_new_with_free_func(
2306 (GDestroyNotify
) bt_config_connection_destroy
);
2307 if (!cfg
->cmd_data
.convert
.connections
) {
2312 if (initial_plugin_paths
) {
2313 cfg
->cmd_data
.convert
.plugin_paths
=
2314 bt_get(initial_plugin_paths
);
2316 cfg
->cmd_data
.convert
.plugin_paths
= bt_value_array_create();
2317 if (!cfg
->cmd_data
.convert
.plugin_paths
) {
2332 static struct bt_config
*bt_config_list_plugins_create(
2333 struct bt_value
*initial_plugin_paths
)
2335 struct bt_config
*cfg
;
2338 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS
);
2344 if (initial_plugin_paths
) {
2345 cfg
->cmd_data
.list_plugins
.plugin_paths
=
2346 bt_get(initial_plugin_paths
);
2348 cfg
->cmd_data
.list_plugins
.plugin_paths
=
2349 bt_value_array_create();
2350 if (!cfg
->cmd_data
.list_plugins
.plugin_paths
) {
2365 static struct bt_config
*bt_config_help_create(
2366 struct bt_value
*initial_plugin_paths
)
2368 struct bt_config
*cfg
;
2371 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_HELP
);
2377 if (initial_plugin_paths
) {
2378 cfg
->cmd_data
.help
.plugin_paths
=
2379 bt_get(initial_plugin_paths
);
2381 cfg
->cmd_data
.help
.plugin_paths
=
2382 bt_value_array_create();
2383 if (!cfg
->cmd_data
.help
.plugin_paths
) {
2389 cfg
->cmd_data
.help
.cfg_component
=
2390 bt_config_component_create(BT_COMPONENT_CLASS_TYPE_UNKNOWN
,
2392 if (!cfg
->cmd_data
.help
.cfg_component
) {
2406 static struct bt_config
*bt_config_query_create(
2407 struct bt_value
*initial_plugin_paths
)
2409 struct bt_config
*cfg
;
2412 cfg
= bt_config_base_create(BT_CONFIG_COMMAND_QUERY
);
2418 if (initial_plugin_paths
) {
2419 cfg
->cmd_data
.query
.plugin_paths
=
2420 bt_get(initial_plugin_paths
);
2422 cfg
->cmd_data
.query
.plugin_paths
=
2423 bt_value_array_create();
2424 if (!cfg
->cmd_data
.query
.plugin_paths
) {
2430 cfg
->cmd_data
.query
.object
= g_string_new(NULL
);
2431 if (!cfg
->cmd_data
.query
.object
) {
2446 * Prints the expected format for a --params option.
2449 void print_expected_params_format(FILE *fp
)
2451 fprintf(fp
, "Expected format of PARAMS\n");
2452 fprintf(fp
, "-------------------------\n");
2454 fprintf(fp
, " PARAM=VALUE[,PARAM=VALUE]...\n");
2456 fprintf(fp
, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
2457 fprintf(fp
, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
2458 fprintf(fp
, "VALUE can be one of:\n");
2460 fprintf(fp
, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
2461 fprintf(fp
, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
2462 fprintf(fp
, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
2463 fprintf(fp
, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
2464 fprintf(fp
, " (`0x` prefix) signed 64-bit integer.\n");
2465 fprintf(fp
, "* Double precision floating point number (scientific notation is accepted).\n");
2466 fprintf(fp
, "* Unquoted string with no special characters, and not matching any of\n");
2467 fprintf(fp
, " the null and boolean value symbols above.\n");
2468 fprintf(fp
, "* Double-quoted string (accepts escape characters).\n");
2470 fprintf(fp
, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
2472 fprintf(fp
, "Example:\n");
2474 fprintf(fp
, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
2475 fprintf(fp
, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
2476 fprintf(fp
, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
2478 fprintf(fp
, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
2479 fprintf(fp
, "from a shell.\n");
2484 * Prints the help command usage.
2487 void print_help_usage(FILE *fp
)
2489 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
2490 fprintf(fp
, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source=PLUGIN.COMPCLS\n");
2491 fprintf(fp
, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter=PLUGIN.COMPCLS\n");
2492 fprintf(fp
, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink=PLUGIN.COMPCLS\n");
2494 fprintf(fp
, "Options:\n");
2496 fprintf(fp
, " --filter=PLUGIN.COMPCLS Get help for the filter component class\n");
2497 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2498 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2499 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
2500 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2501 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2502 fprintf(fp
, " dynamic plugins can be loaded\n");
2503 fprintf(fp
, " --sink=PLUGIN.COMPCLS Get help for the sink component class\n");
2504 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2505 fprintf(fp
, " --source=PLUGIN.COMPCLS Get help for the source component class\n");
2506 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2507 fprintf(fp
, " -h --help Show this help and quit\n");
2509 fprintf(fp
, "See `babeltrace --help` for the list of general options.\n");
2511 fprintf(fp
, "Use `babeltrace list-plugins` to show the list of available plugins.\n");
2514 static struct poptOption help_long_options
[] = {
2515 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2516 { "filter", '\0', POPT_ARG_STRING
, NULL
, OPT_FILTER
, NULL
, NULL
},
2517 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2518 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2519 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2520 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2521 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
2522 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
2523 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2527 * Creates a Babeltrace config object from the arguments of a help
2530 * *retcode is set to the appropriate exit code to use.
2532 struct bt_config
*bt_config_help_from_args(int argc
, const char *argv
[],
2533 int *retcode
, bool omit_system_plugin_path
,
2534 bool omit_home_plugin_path
,
2535 struct bt_value
*initial_plugin_paths
)
2537 poptContext pc
= NULL
;
2541 struct bt_config
*cfg
= NULL
;
2542 const char *leftover
;
2543 char *plugin_name
= NULL
, *component_name
= NULL
;
2544 char *plugin_comp_cls_names
= NULL
;
2547 cfg
= bt_config_help_create(initial_plugin_paths
);
2553 cfg
->cmd_data
.help
.omit_system_plugin_path
= omit_system_plugin_path
;
2554 cfg
->cmd_data
.help
.omit_home_plugin_path
= omit_home_plugin_path
;
2555 ret
= append_env_var_plugin_paths(cfg
->cmd_data
.help
.plugin_paths
);
2557 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2562 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
2563 help_long_options
, 0);
2565 printf_err("Cannot get popt context\n");
2569 poptReadDefaultConfig(pc
, 0);
2571 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2572 arg
= poptGetOptArg(pc
);
2575 case OPT_PLUGIN_PATH
:
2576 if (bt_common_is_setuid_setgid()) {
2577 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2579 if (bt_config_append_plugin_paths(
2580 cfg
->cmd_data
.help
.plugin_paths
,
2582 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2588 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
2589 cfg
->cmd_data
.help
.omit_system_plugin_path
= true;
2591 case OPT_OMIT_HOME_PLUGIN_PATH
:
2592 cfg
->cmd_data
.help
.omit_home_plugin_path
= true;
2597 if (cfg
->cmd_data
.help
.cfg_component
->type
!=
2598 BT_COMPONENT_CLASS_TYPE_UNKNOWN
) {
2599 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2606 cfg
->cmd_data
.help
.cfg_component
->type
=
2607 BT_COMPONENT_CLASS_TYPE_SOURCE
;
2610 cfg
->cmd_data
.help
.cfg_component
->type
=
2611 BT_COMPONENT_CLASS_TYPE_FILTER
;
2614 cfg
->cmd_data
.help
.cfg_component
->type
=
2615 BT_COMPONENT_CLASS_TYPE_SINK
;
2620 plugin_comp_cls_names
= strdup(arg
);
2621 if (!plugin_comp_cls_names
) {
2627 print_help_usage(stdout
);
2632 printf_err("Unknown command-line option specified (option code %d)\n",
2641 /* Check for option parsing error */
2643 printf_err("While parsing command-line options, at option %s: %s\n",
2644 poptBadOption(pc
, 0), poptStrerror(opt
));
2648 leftover
= poptGetArg(pc
);
2650 if (cfg
->cmd_data
.help
.cfg_component
->type
!=
2651 BT_COMPONENT_CLASS_TYPE_UNKNOWN
) {
2652 printf_err("Cannot specify plugin name and --source/--filter/--sink component class:\n %s\n",
2657 g_string_assign(cfg
->cmd_data
.help
.cfg_component
->plugin_name
,
2660 if (cfg
->cmd_data
.help
.cfg_component
->type
==
2661 BT_COMPONENT_CLASS_TYPE_UNKNOWN
) {
2662 print_help_usage(stdout
);
2668 plugin_component_names_from_arg(plugin_comp_cls_names
,
2669 &plugin_name
, &component_name
);
2670 if (plugin_name
&& component_name
) {
2671 g_string_assign(cfg
->cmd_data
.help
.cfg_component
->plugin_name
,
2673 g_string_assign(cfg
->cmd_data
.help
.cfg_component
->component_name
,
2676 printf_err("Invalid --source/--filter/--sink option's argument:\n %s\n",
2677 plugin_comp_cls_names
);
2682 if (append_home_and_system_plugin_paths(
2683 cfg
->cmd_data
.help
.plugin_paths
,
2684 cfg
->cmd_data
.help
.omit_system_plugin_path
,
2685 cfg
->cmd_data
.help
.omit_home_plugin_path
)) {
2686 printf_err("Cannot append home and system plugin paths\n");
2697 free(plugin_comp_cls_names
);
2698 g_free(plugin_name
);
2699 g_free(component_name
);
2702 poptFreeContext(pc
);
2710 * Prints the help command usage.
2713 void print_query_usage(FILE *fp
)
2715 fprintf(fp
, "Usage: babeltrace [GEN OPTS] query [OPTS] OBJECT --source=PLUGIN.COMPCLS\n");
2716 fprintf(fp
, " babeltrace [GEN OPTS] query [OPTS] OBJECT --filter=PLUGIN.COMPCLS\n");
2717 fprintf(fp
, " babeltrace [GEN OPTS] query [OPTS] OBJECT --sink=PLUGIN.COMPCLS\n");
2719 fprintf(fp
, "Options:\n");
2721 fprintf(fp
, " --filter=PLUGIN.COMPCLS Query object from the filter component\n");
2722 fprintf(fp
, " class COMPCLS found in the plugin PLUGIN\n");
2723 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2724 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
2725 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2726 fprintf(fp
, " -p, --params=PARAMS Set the query parameters to PARAMS\n");
2727 fprintf(fp
, " (see the expected format of PARAMS below)\n");
2728 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2729 fprintf(fp
, " dynamic plugins can be loaded\n");
2730 fprintf(fp
, " --sink=PLUGIN.COMPCLS Query object from the sink component class\n");
2731 fprintf(fp
, " COMPCLS found in the plugin PLUGIN\n");
2732 fprintf(fp
, " --source=PLUGIN.COMPCLS Query object from the source component\n");
2733 fprintf(fp
, " class COMPCLS found in the plugin PLUGIN\n");
2734 fprintf(fp
, " -h --help Show this help and quit\n");
2735 fprintf(fp
, "\n\n");
2736 print_expected_params_format(fp
);
2739 static struct poptOption query_long_options
[] = {
2740 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2741 { "filter", '\0', POPT_ARG_STRING
, NULL
, OPT_FILTER
, NULL
, NULL
},
2742 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2743 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2744 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2745 { "params", 'p', POPT_ARG_STRING
, NULL
, OPT_PARAMS
, NULL
, NULL
},
2746 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2747 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
2748 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
2749 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2753 * Creates a Babeltrace config object from the arguments of a query
2756 * *retcode is set to the appropriate exit code to use.
2758 struct bt_config
*bt_config_query_from_args(int argc
, const char *argv
[],
2759 int *retcode
, bool omit_system_plugin_path
,
2760 bool omit_home_plugin_path
,
2761 struct bt_value
*initial_plugin_paths
)
2763 poptContext pc
= NULL
;
2767 struct bt_config
*cfg
= NULL
;
2768 const char *leftover
;
2769 struct bt_value
*params
= bt_value_null
;
2772 cfg
= bt_config_query_create(initial_plugin_paths
);
2778 cfg
->cmd_data
.query
.omit_system_plugin_path
=
2779 omit_system_plugin_path
;
2780 cfg
->cmd_data
.query
.omit_home_plugin_path
= omit_home_plugin_path
;
2781 ret
= append_env_var_plugin_paths(cfg
->cmd_data
.query
.plugin_paths
);
2783 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2788 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
2789 query_long_options
, 0);
2791 printf_err("Cannot get popt context\n");
2795 poptReadDefaultConfig(pc
, 0);
2797 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2798 arg
= poptGetOptArg(pc
);
2801 case OPT_PLUGIN_PATH
:
2802 if (bt_common_is_setuid_setgid()) {
2803 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2805 if (bt_config_append_plugin_paths(
2806 cfg
->cmd_data
.query
.plugin_paths
,
2808 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2814 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
2815 cfg
->cmd_data
.query
.omit_system_plugin_path
= true;
2817 case OPT_OMIT_HOME_PLUGIN_PATH
:
2818 cfg
->cmd_data
.query
.omit_home_plugin_path
= true;
2824 enum bt_component_class_type type
;
2826 if (cfg
->cmd_data
.query
.cfg_component
) {
2827 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2834 type
= BT_COMPONENT_CLASS_TYPE_SOURCE
;
2837 type
= BT_COMPONENT_CLASS_TYPE_FILTER
;
2840 type
= BT_COMPONENT_CLASS_TYPE_SINK
;
2846 cfg
->cmd_data
.query
.cfg_component
=
2847 bt_config_component_from_arg(type
, arg
);
2848 if (!cfg
->cmd_data
.query
.cfg_component
) {
2849 printf_err("Invalid format for --source/--filter/--sink option's argument:\n %s\n",
2854 /* Default parameters: null */
2855 bt_put(cfg
->cmd_data
.query
.cfg_component
->params
);
2856 cfg
->cmd_data
.query
.cfg_component
->params
=
2862 params
= bt_value_from_arg(arg
);
2864 printf_err("Invalid format for --params option's argument:\n %s\n",
2871 print_query_usage(stdout
);
2876 printf_err("Unknown command-line option specified (option code %d)\n",
2885 if (!cfg
->cmd_data
.query
.cfg_component
) {
2886 printf_err("No target component class specified with --source/--filter/--sink option\n");
2891 BT_MOVE(cfg
->cmd_data
.query
.cfg_component
->params
, params
);
2893 /* Check for option parsing error */
2895 printf_err("While parsing command-line options, at option %s: %s\n",
2896 poptBadOption(pc
, 0), poptStrerror(opt
));
2901 * We need exactly one leftover argument which is the
2904 leftover
= poptGetArg(pc
);
2906 if (strlen(leftover
) == 0) {
2907 printf_err("Invalid empty object\n");
2911 g_string_assign(cfg
->cmd_data
.query
.object
, leftover
);
2913 print_query_usage(stdout
);
2919 leftover
= poptGetArg(pc
);
2921 printf_err("Invalid argument: %s\n", leftover
);
2925 if (append_home_and_system_plugin_paths(
2926 cfg
->cmd_data
.query
.plugin_paths
,
2927 cfg
->cmd_data
.query
.omit_system_plugin_path
,
2928 cfg
->cmd_data
.query
.omit_home_plugin_path
)) {
2929 printf_err("Cannot append home and system plugin paths\n");
2941 poptFreeContext(pc
);
2950 * Prints the list-plugins command usage.
2953 void print_list_plugins_usage(FILE *fp
)
2955 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
2957 fprintf(fp
, "Options:\n");
2959 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2960 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
2961 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2962 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2963 fprintf(fp
, " dynamic plugins can be loaded\n");
2964 fprintf(fp
, " -h --help Show this help and quit\n");
2966 fprintf(fp
, "See `babeltrace --help` for the list of general options.\n");
2968 fprintf(fp
, "Use `babeltrace help` to get help for a specific plugin or component class.\n");
2971 static struct poptOption list_plugins_long_options
[] = {
2972 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2973 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2974 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2975 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2976 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2977 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2981 * Creates a Babeltrace config object from the arguments of a
2982 * list-plugins command.
2984 * *retcode is set to the appropriate exit code to use.
2986 struct bt_config
*bt_config_list_plugins_from_args(int argc
, const char *argv
[],
2987 int *retcode
, bool omit_system_plugin_path
,
2988 bool omit_home_plugin_path
,
2989 struct bt_value
*initial_plugin_paths
)
2991 poptContext pc
= NULL
;
2995 struct bt_config
*cfg
= NULL
;
2996 const char *leftover
;
2999 cfg
= bt_config_list_plugins_create(initial_plugin_paths
);
3005 cfg
->cmd_data
.list_plugins
.omit_system_plugin_path
= omit_system_plugin_path
;
3006 cfg
->cmd_data
.list_plugins
.omit_home_plugin_path
= omit_home_plugin_path
;
3007 ret
= append_env_var_plugin_paths(
3008 cfg
->cmd_data
.list_plugins
.plugin_paths
);
3010 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3015 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
3016 list_plugins_long_options
, 0);
3018 printf_err("Cannot get popt context\n");
3022 poptReadDefaultConfig(pc
, 0);
3024 while ((opt
= poptGetNextOpt(pc
)) > 0) {
3025 arg
= poptGetOptArg(pc
);
3028 case OPT_PLUGIN_PATH
:
3029 if (bt_common_is_setuid_setgid()) {
3030 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3032 if (bt_config_append_plugin_paths(
3033 cfg
->cmd_data
.list_plugins
.plugin_paths
,
3035 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3041 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
3042 cfg
->cmd_data
.list_plugins
.omit_system_plugin_path
= true;
3044 case OPT_OMIT_HOME_PLUGIN_PATH
:
3045 cfg
->cmd_data
.list_plugins
.omit_home_plugin_path
= true;
3048 print_list_plugins_usage(stdout
);
3053 printf_err("Unknown command-line option specified (option code %d)\n",
3062 /* Check for option parsing error */
3064 printf_err("While parsing command-line options, at option %s: %s\n",
3065 poptBadOption(pc
, 0), poptStrerror(opt
));
3069 leftover
= poptGetArg(pc
);
3071 printf_err("Invalid argument: %s\n", leftover
);
3075 if (append_home_and_system_plugin_paths(
3076 cfg
->cmd_data
.list_plugins
.plugin_paths
,
3077 cfg
->cmd_data
.list_plugins
.omit_system_plugin_path
,
3078 cfg
->cmd_data
.list_plugins
.omit_home_plugin_path
)) {
3079 printf_err("Cannot append home and system plugin paths\n");
3091 poptFreeContext(pc
);
3099 * Prints the legacy, Babeltrace 1.x command usage. Those options are
3100 * still compatible in Babeltrace 2.x, but it is recommended to use
3101 * the more generic plugin/component parameters instead of those
3102 * hard-coded option names.
3105 void print_legacy_usage(FILE *fp
)
3107 fprintf(fp
, "Usage: babeltrace [OPTIONS] INPUT...\n");
3109 fprintf(fp
, "The following options are compatible with the Babeltrace 1.x options:\n");
3111 fprintf(fp
, " --clock-force-correlate Assume that clocks are inherently correlated\n");
3112 fprintf(fp
, " across traces\n");
3113 fprintf(fp
, " -d, --debug Enable debug mode\n");
3114 fprintf(fp
, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
3115 fprintf(fp
, " -l, --list List available formats\n");
3116 fprintf(fp
, " -o, --output-format=FORMAT Output trace format (default: text)\n");
3117 fprintf(fp
, " -v, --verbose Enable verbose output\n");
3118 fprintf(fp
, " --help-legacy Show this help and quit\n");
3119 fprintf(fp
, " -V, --version Show version and quit\n");
3121 fprintf(fp
, " Available input formats: ctf, lttng-live, ctf-metadata\n");
3122 fprintf(fp
, " Available output formats: text, dummy\n");
3124 fprintf(fp
, "Input formats specific options:\n");
3126 fprintf(fp
, " INPUT... Input trace file(s), directory(ies), or URLs\n");
3127 fprintf(fp
, " --clock-offset=SEC Set clock offset to SEC seconds\n");
3128 fprintf(fp
, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
3129 fprintf(fp
, " --stream-intersection Only process events when all streams are active\n");
3131 fprintf(fp
, "text output format specific options:\n");
3133 fprintf(fp
, " --clock-cycles Print timestamps in clock cycles\n");
3134 fprintf(fp
, " --clock-date Print timestamp dates\n");
3135 fprintf(fp
, " --clock-gmt Print and parse timestamps in GMT time zone\n");
3136 fprintf(fp
, " (default: local time zone)\n");
3137 fprintf(fp
, " --clock-seconds Print the timestamps as [SEC.NS]\n");
3138 fprintf(fp
, " (default format: [HH:MM:SS.NS])\n");
3139 fprintf(fp
, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
3140 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
3141 fprintf(fp
, " --debug-info-full-path Show full debug info source and binary paths\n");
3142 fprintf(fp
, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
3143 fprintf(fp
, " up executables during debug info analysis\n");
3144 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
3145 fprintf(fp
, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
3146 fprintf(fp
, " all, trace, trace:hostname, trace:domain,\n");
3147 fprintf(fp
, " trace:procname, trace:vpid, loglevel, emf\n");
3148 fprintf(fp
, " (default: trace:hostname, trace:procname,\n");
3149 fprintf(fp
, " trace:vpid)\n");
3150 fprintf(fp
, " -n, --names=NAME[,NAME]... Print field names:\n");
3151 fprintf(fp
, " payload (or arg or args)\n");
3152 fprintf(fp
, " none, all, scope, header, context (or ctx)\n");
3153 fprintf(fp
, " (default: payload, context)\n");
3154 fprintf(fp
, " --no-delta Do not print time delta between consecutive\n");
3155 fprintf(fp
, " events\n");
3156 fprintf(fp
, " -w, --output=PATH Write output to PATH (default: standard output)\n");
3160 * Prints the convert command usage.
3163 void print_convert_usage(FILE *fp
)
3165 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
3167 fprintf(fp
, "Options:\n");
3169 fprintf(fp
, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
3170 fprintf(fp
, " for the following component instances\n");
3171 fprintf(fp
, " (see the expected format of PARAMS below)\n");
3172 fprintf(fp
, " --begin=BEGIN Set the `begin` parameter of the latest\n");
3173 fprintf(fp
, " source component instance to BEGIN\n");
3174 fprintf(fp
, " (see the suggested format of BEGIN below)\n");
3175 fprintf(fp
, " -c, --connect=CONNECTION Connect two component instances (see the\n");
3176 fprintf(fp
, " expected format of CONNECTION below)\n");
3177 fprintf(fp
, " -d, --debug Enable debug mode\n");
3178 fprintf(fp
, " --end=END Set the `end` parameter of the latest\n");
3179 fprintf(fp
, " source component instance to END\n");
3180 fprintf(fp
, " (see the suggested format of BEGIN below)\n");
3181 fprintf(fp
, " --filter=PLUGIN.COMPCLS Instantiate a filter component from plugin\n");
3182 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
3183 fprintf(fp
, " repeated)\n");
3184 fprintf(fp
, " --name=NAME Set the name of the latest component\n");
3185 fprintf(fp
, " instance to NAME (must be unique amongst\n");
3186 fprintf(fp
, " all the names of the component instances)\n");
3187 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
3188 fprintf(fp
, " (~/.local/lib/babeltrace/plugins)\n");
3189 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
3190 fprintf(fp
, " -p, --params=PARAMS Set the parameters of the latest component\n");
3191 fprintf(fp
, " instance (in command-line order) to PARAMS\n");
3192 fprintf(fp
, " (see the expected format of PARAMS below)\n");
3193 fprintf(fp
, " -P, --path=PATH Set the `path` parameter of the latest\n");
3194 fprintf(fp
, " component instance to PATH\n");
3195 fprintf(fp
, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
3196 fprintf(fp
, " dynamic plugins can be loaded\n");
3197 fprintf(fp
, " -r, --reset-base-params Reset the current base parameters of the\n");
3198 fprintf(fp
, " following source and sink component\n");
3199 fprintf(fp
, " instances to an empty map\n");
3200 fprintf(fp
, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
3201 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
3202 fprintf(fp
, " repeated)\n");
3203 fprintf(fp
, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
3204 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
3205 fprintf(fp
, " repeated)\n");
3206 fprintf(fp
, " --timerange=TIMERANGE Set time range to TIMERANGE: BEGIN,END or\n");
3207 fprintf(fp
, " [BEGIN,END] (literally `[` and `]`)\n");
3208 fprintf(fp
, " (suggested format of BEGIN/END below)\n");
3209 fprintf(fp
, " -v, --verbose Enable verbose output\n");
3210 fprintf(fp
, " -h --help Show this help and quit\n");
3212 fprintf(fp
, "See `babeltrace --help` for the list of general options.\n");
3213 fprintf(fp
, "\n\n");
3214 fprintf(fp
, "Suggested format of BEGIN and END\n");
3215 fprintf(fp
, "---------------------------------\n");
3217 fprintf(fp
, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
3218 fprintf(fp
, "\n\n");
3219 fprintf(fp
, "Expected format of CONNECTION\n");
3220 fprintf(fp
, "-----------------------------\n");
3222 fprintf(fp
, " SRC[.SRCPORT]:DST[.DSTPORT]\n");
3224 fprintf(fp
, "SRC and DST are the names of the source and destination component\n");
3225 fprintf(fp
, "instances to connect together. You can set the name of a component\n");
3226 fprintf(fp
, "instance with the --name option.\n");
3228 fprintf(fp
, "SRCPORT and DSTPORT are the optional source and destination ports to use\n");
3229 fprintf(fp
, "for the connection. When the port is not specified, the default port is\n");
3230 fprintf(fp
, "used.\n");
3232 fprintf(fp
, "You can connect a source component to a filter or sink component. You\n");
3233 fprintf(fp
, "can connect a filter component to a sink component.\n");
3235 fprintf(fp
, "Example:\n");
3237 fprintf(fp
, " my-filter.top10:json-out\n");
3238 fprintf(fp
, "\n\n");
3239 print_expected_params_format(fp
);
3242 static struct poptOption convert_long_options
[] = {
3243 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
3244 { "base-params", 'b', POPT_ARG_STRING
, NULL
, OPT_BASE_PARAMS
, NULL
, NULL
},
3245 { "begin", '\0', POPT_ARG_STRING
, NULL
, OPT_BEGIN
, NULL
, NULL
},
3246 { "clock-cycles", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_CYCLES
, NULL
, NULL
},
3247 { "clock-date", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_DATE
, NULL
, NULL
},
3248 { "clock-force-correlate", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_FORCE_CORRELATE
, NULL
, NULL
},
3249 { "clock-gmt", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_GMT
, NULL
, NULL
},
3250 { "clock-offset", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET
, NULL
, NULL
},
3251 { "clock-offset-ns", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET_NS
, NULL
, NULL
},
3252 { "clock-seconds", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_SECONDS
, NULL
, NULL
},
3253 { "connect", 'c', POPT_ARG_STRING
, NULL
, OPT_CONNECT
, NULL
, NULL
},
3254 { "debug", 'd', POPT_ARG_NONE
, NULL
, OPT_DEBUG
, NULL
, NULL
},
3255 { "debug-info-dir", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_DIR
, NULL
, NULL
},
3256 { "debug-info-full-path", 0, POPT_ARG_NONE
, NULL
, OPT_DEBUG_INFO_FULL_PATH
, NULL
, NULL
},
3257 { "debug-info-target-prefix", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_TARGET_PREFIX
, NULL
, NULL
},
3258 { "end", '\0', POPT_ARG_STRING
, NULL
, OPT_END
, NULL
, NULL
},
3259 { "fields", 'f', POPT_ARG_STRING
, NULL
, OPT_FIELDS
, NULL
, NULL
},
3260 { "filter", '\0', POPT_ARG_STRING
, NULL
, OPT_FILTER
, NULL
, NULL
},
3261 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
3262 { "input-format", 'i', POPT_ARG_STRING
, NULL
, OPT_INPUT_FORMAT
, NULL
, NULL
},
3263 { "name", '\0', POPT_ARG_STRING
, NULL
, OPT_NAME
, NULL
, NULL
},
3264 { "names", 'n', POPT_ARG_STRING
, NULL
, OPT_NAMES
, NULL
, NULL
},
3265 { "no-delta", '\0', POPT_ARG_NONE
, NULL
, OPT_NO_DELTA
, NULL
, NULL
},
3266 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
3267 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
3268 { "output", 'w', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_PATH
, NULL
, NULL
},
3269 { "output-format", 'o', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_FORMAT
, NULL
, NULL
},
3270 { "params", 'p', POPT_ARG_STRING
, NULL
, OPT_PARAMS
, NULL
, NULL
},
3271 { "path", 'P', POPT_ARG_STRING
, NULL
, OPT_PATH
, NULL
, NULL
},
3272 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
3273 { "reset-base-params", 'r', POPT_ARG_NONE
, NULL
, OPT_RESET_BASE_PARAMS
, NULL
, NULL
},
3274 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
3275 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
3276 { "stream-intersection", '\0', POPT_ARG_NONE
, NULL
, OPT_STREAM_INTERSECTION
, NULL
, NULL
},
3277 { "timerange", '\0', POPT_ARG_STRING
, NULL
, OPT_TIMERANGE
, NULL
, NULL
},
3278 { "verbose", 'v', POPT_ARG_NONE
, NULL
, OPT_VERBOSE
, NULL
, NULL
},
3279 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
3283 * Creates a Babeltrace config object from the arguments of a convert
3286 * *retcode is set to the appropriate exit code to use.
3288 struct bt_config
*bt_config_convert_from_args(int argc
, const char *argv
[],
3289 int *retcode
, bool omit_system_plugin_path
,
3290 bool omit_home_plugin_path
,
3291 struct bt_value
*initial_plugin_paths
)
3293 poptContext pc
= NULL
;
3295 struct ctf_legacy_opts ctf_legacy_opts
;
3296 struct text_legacy_opts text_legacy_opts
;
3297 enum legacy_input_format legacy_input_format
= LEGACY_INPUT_FORMAT_NONE
;
3298 enum legacy_output_format legacy_output_format
=
3299 LEGACY_OUTPUT_FORMAT_NONE
;
3300 struct bt_value
*legacy_input_paths
= NULL
;
3301 struct bt_config_component
*implicit_source_comp
= NULL
;
3302 struct bt_config_component
*cur_cfg_comp
= NULL
;
3303 bool cur_is_implicit_source
= false;
3304 bool use_implicit_source
= false;
3305 enum bt_config_component_dest cur_cfg_comp_dest
=
3306 BT_CONFIG_COMPONENT_DEST_SOURCE
;
3307 struct bt_value
*cur_base_params
= NULL
;
3309 struct bt_config
*cfg
= NULL
;
3310 struct bt_value
*instance_names
= NULL
;
3311 struct bt_value
*connection_args
= NULL
;
3312 char error_buf
[256] = { 0 };
3315 memset(&ctf_legacy_opts
, 0, sizeof(ctf_legacy_opts
));
3316 memset(&text_legacy_opts
, 0, sizeof(text_legacy_opts
));
3319 print_convert_usage(stdout
);
3324 cfg
= bt_config_convert_create(initial_plugin_paths
);
3330 cfg
->cmd_data
.convert
.omit_system_plugin_path
= omit_system_plugin_path
;
3331 cfg
->cmd_data
.convert
.omit_home_plugin_path
= omit_home_plugin_path
;
3332 text_legacy_opts
.output
= g_string_new(NULL
);
3333 if (!text_legacy_opts
.output
) {
3338 text_legacy_opts
.dbg_info_dir
= g_string_new(NULL
);
3339 if (!text_legacy_opts
.dbg_info_dir
) {
3344 text_legacy_opts
.dbg_info_target_prefix
= g_string_new(NULL
);
3345 if (!text_legacy_opts
.dbg_info_target_prefix
) {
3350 cur_base_params
= bt_value_map_create();
3351 if (!cur_base_params
) {
3356 legacy_input_paths
= bt_value_array_create();
3357 if (!legacy_input_paths
) {
3362 instance_names
= bt_value_map_create();
3363 if (!instance_names
) {
3368 connection_args
= bt_value_array_create();
3369 if (!connection_args
) {
3374 ret
= append_env_var_plugin_paths(cfg
->cmd_data
.convert
.plugin_paths
);
3376 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3380 /* Note: implicit source never gets positional base params. */
3381 implicit_source_comp
= bt_config_component_from_arg(
3382 BT_COMPONENT_CLASS_TYPE_SOURCE
, DEFAULT_SOURCE_COMPONENT_NAME
);
3383 if (!implicit_source_comp
) {
3388 cur_cfg_comp
= implicit_source_comp
;
3389 cur_is_implicit_source
= true;
3390 use_implicit_source
= true;
3393 pc
= poptGetContext(NULL
, argc
, (const char **) argv
,
3394 convert_long_options
, 0);
3396 printf_err("Cannot get popt context\n");
3400 poptReadDefaultConfig(pc
, 0);
3402 while ((opt
= poptGetNextOpt(pc
)) > 0) {
3403 arg
= poptGetOptArg(pc
);
3406 case OPT_PLUGIN_PATH
:
3407 if (bt_common_is_setuid_setgid()) {
3408 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3410 if (bt_config_append_plugin_paths(
3411 cfg
->cmd_data
.convert
.plugin_paths
,
3413 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3419 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
3420 cfg
->cmd_data
.convert
.omit_system_plugin_path
= true;
3422 case OPT_OMIT_HOME_PLUGIN_PATH
:
3423 cfg
->cmd_data
.convert
.omit_home_plugin_path
= true;
3425 case OPT_OUTPUT_PATH
:
3426 if (text_legacy_opts
.output
->len
> 0) {
3427 printf_err("Duplicate --output option\n");
3431 g_string_assign(text_legacy_opts
.output
, arg
);
3433 case OPT_DEBUG_INFO_DIR
:
3434 if (text_legacy_opts
.dbg_info_dir
->len
> 0) {
3435 printf_err("Duplicate --debug-info-dir option\n");
3439 g_string_assign(text_legacy_opts
.dbg_info_dir
, arg
);
3441 case OPT_DEBUG_INFO_TARGET_PREFIX
:
3442 if (text_legacy_opts
.dbg_info_target_prefix
->len
> 0) {
3443 printf_err("Duplicate --debug-info-target-prefix option\n");
3447 g_string_assign(text_legacy_opts
.dbg_info_target_prefix
, arg
);
3449 case OPT_INPUT_FORMAT
:
3452 if (opt
== OPT_INPUT_FORMAT
) {
3453 if (!strcmp(arg
, "ctf")) {
3454 /* Legacy CTF input format */
3455 if (legacy_input_format
) {
3456 print_err_dup_legacy_input();
3460 legacy_input_format
=
3461 LEGACY_INPUT_FORMAT_CTF
;
3463 } else if (!strcmp(arg
, "lttng-live")) {
3464 /* Legacy LTTng-live input format */
3465 if (legacy_input_format
) {
3466 print_err_dup_legacy_input();
3470 legacy_input_format
=
3471 LEGACY_INPUT_FORMAT_LTTNG_LIVE
;
3476 use_implicit_source
= false;
3478 /* Non-legacy: try to create a component config */
3479 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3480 add_cfg_comp(cfg
, cur_cfg_comp
,
3484 cur_cfg_comp
= bt_config_component_from_arg(
3485 BT_COMPONENT_CLASS_TYPE_SOURCE
, arg
);
3486 if (!cur_cfg_comp
) {
3487 printf_err("Invalid format for --source option's argument:\n %s\n",
3491 cur_is_implicit_source
= false;
3493 assert(cur_base_params
);
3494 bt_put(cur_cfg_comp
->params
);
3495 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
3496 if (!cur_cfg_comp
->params
) {
3501 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SOURCE
;
3506 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3507 add_cfg_comp(cfg
, cur_cfg_comp
,
3511 cur_cfg_comp
= bt_config_component_from_arg(
3512 BT_COMPONENT_CLASS_TYPE_FILTER
, arg
);
3513 if (!cur_cfg_comp
) {
3514 printf_err("Invalid format for --filter option's argument:\n %s\n",
3518 cur_is_implicit_source
= false;
3520 assert(cur_base_params
);
3521 bt_put(cur_cfg_comp
->params
);
3522 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
3523 if (!cur_cfg_comp
->params
) {
3528 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_FILTER
;
3531 case OPT_OUTPUT_FORMAT
:
3534 if (opt
== OPT_OUTPUT_FORMAT
) {
3535 if (!strcmp(arg
, "text")) {
3536 /* Legacy CTF-text output format */
3537 if (legacy_output_format
) {
3538 print_err_dup_legacy_output();
3542 legacy_output_format
=
3543 LEGACY_OUTPUT_FORMAT_TEXT
;
3545 } else if (!strcmp(arg
, "dummy")) {
3546 /* Legacy dummy output format */
3547 if (legacy_output_format
) {
3548 print_err_dup_legacy_output();
3552 legacy_output_format
=
3553 LEGACY_OUTPUT_FORMAT_DUMMY
;
3555 } else if (!strcmp(arg
, "ctf-metadata")) {
3556 cfg
->cmd_data
.convert
.print_ctf_metadata
= true;
3561 /* Non-legacy: try to create a component config */
3562 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3563 add_cfg_comp(cfg
, cur_cfg_comp
,
3567 cur_cfg_comp
= bt_config_component_from_arg(
3568 BT_COMPONENT_CLASS_TYPE_SINK
, arg
);
3569 if (!cur_cfg_comp
) {
3570 printf_err("Invalid format for --sink option's argument:\n %s\n",
3574 cur_is_implicit_source
= false;
3576 assert(cur_base_params
);
3577 bt_put(cur_cfg_comp
->params
);
3578 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
3579 if (!cur_cfg_comp
->params
) {
3584 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SINK
;
3589 struct bt_value
*params
;
3590 struct bt_value
*params_to_set
;
3592 if (!cur_cfg_comp
) {
3593 printf_err("Cannot add parameters to unavailable default source component `%s`:\n %s\n",
3594 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3598 params
= bt_value_from_arg(arg
);
3600 printf_err("Invalid format for --params option's argument:\n %s\n",
3605 params_to_set
= bt_value_map_extend(cur_cfg_comp
->params
,
3608 if (!params_to_set
) {
3609 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
3614 BT_MOVE(cur_cfg_comp
->params
, params_to_set
);
3618 if (!cur_cfg_comp
) {
3619 printf_err("Cannot add `path` parameter to unavailable default source component `%s`:\n %s\n",
3620 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3624 assert(cur_cfg_comp
->params
);
3626 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3633 if (!cur_cfg_comp
) {
3634 printf_err("Cannot set the name of unavailable default source component `%s`:\n %s\n",
3635 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3639 if (bt_value_map_has_key(instance_names
, arg
)) {
3640 printf_err("Duplicate component instance name:\n %s\n",
3645 g_string_assign(cur_cfg_comp
->instance_name
, arg
);
3647 if (bt_value_map_insert(instance_names
,
3648 arg
, bt_value_null
)) {
3653 case OPT_BASE_PARAMS
:
3655 struct bt_value
*params
= bt_value_from_arg(arg
);
3658 printf_err("Invalid format for --base-params option's argument:\n %s\n",
3663 BT_MOVE(cur_base_params
, params
);
3666 case OPT_RESET_BASE_PARAMS
:
3667 BT_PUT(cur_base_params
);
3668 cur_base_params
= bt_value_map_create();
3669 if (!cur_base_params
) {
3675 if (text_legacy_opts
.names
) {
3676 printf_err("Duplicate --names option\n");
3680 text_legacy_opts
.names
= names_from_arg(arg
);
3681 if (!text_legacy_opts
.names
) {
3682 printf_err("Invalid --names option's argument:\n %s\n",
3688 if (text_legacy_opts
.fields
) {
3689 printf_err("Duplicate --fields option\n");
3693 text_legacy_opts
.fields
= fields_from_arg(arg
);
3694 if (!text_legacy_opts
.fields
) {
3695 printf_err("Invalid --fields option's argument:\n %s\n",
3701 text_legacy_opts
.no_delta
= true;
3703 case OPT_CLOCK_CYCLES
:
3704 text_legacy_opts
.clock_cycles
= true;
3706 case OPT_CLOCK_SECONDS
:
3707 text_legacy_opts
.clock_seconds
= true;
3709 case OPT_CLOCK_DATE
:
3710 text_legacy_opts
.clock_date
= true;
3713 text_legacy_opts
.clock_gmt
= true;
3715 case OPT_DEBUG_INFO_FULL_PATH
:
3716 text_legacy_opts
.dbg_info_full_path
= true;
3718 case OPT_CLOCK_OFFSET
:
3722 if (ctf_legacy_opts
.offset_s
.is_set
) {
3723 printf_err("Duplicate --clock-offset option\n");
3727 if (parse_int64(arg
, &val
)) {
3728 printf_err("Invalid --clock-offset option's argument:\n %s\n",
3733 set_offset_value(&ctf_legacy_opts
.offset_s
, val
);
3736 case OPT_CLOCK_OFFSET_NS
:
3740 if (ctf_legacy_opts
.offset_ns
.is_set
) {
3741 printf_err("Duplicate --clock-offset-ns option\n");
3745 if (parse_int64(arg
, &val
)) {
3746 printf_err("Invalid --clock-offset-ns option's argument:\n %s\n",
3751 set_offset_value(&ctf_legacy_opts
.offset_ns
, val
);
3754 case OPT_STREAM_INTERSECTION
:
3755 ctf_legacy_opts
.stream_intersection
= true;
3757 case OPT_CLOCK_FORCE_CORRELATE
:
3758 cfg
->cmd_data
.convert
.force_correlate
= true;
3761 if (!cur_cfg_comp
) {
3762 printf_err("Cannot add `begin` parameter to unavailable default source component `%s`:\n %s\n",
3763 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3766 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
3767 printf_err("--begin option must follow a --source option:\n %s\n",
3771 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3778 if (!cur_cfg_comp
) {
3779 printf_err("Cannot add `end` parameter to unavailable default source component `%s`:\n %s\n",
3780 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3783 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
3784 printf_err("--end option must follow a --source option:\n %s\n",
3788 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3796 const char *begin
, *end
;
3798 if (!cur_cfg_comp
) {
3799 printf_err("Cannot add `begin` and `end` parameters to unavailable default source component `%s`:\n %s\n",
3800 DEFAULT_SOURCE_COMPONENT_NAME
, arg
);
3803 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
3804 printf_err("--timerange option must follow a --source option:\n %s\n",
3808 if (split_timerange(arg
, &begin
, &end
)) {
3809 printf_err("Invalid --timerange format: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
3813 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3818 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
3826 if (bt_value_array_append_string(connection_args
,
3833 print_convert_usage(stdout
);
3838 text_legacy_opts
.verbose
= true;
3839 cfg
->verbose
= true;
3845 printf_err("Unknown command-line option specified (option code %d)\n",
3854 /* Check for option parsing error */
3856 printf_err("While parsing command-line options, at option %s: %s\n",
3857 poptBadOption(pc
, 0), poptStrerror(opt
));
3861 /* Consume leftover arguments as legacy input paths */
3863 const char *input_path
= poptGetArg(pc
);
3869 if (bt_value_array_append_string(legacy_input_paths
,
3876 if (append_home_and_system_plugin_paths(
3877 cfg
->cmd_data
.convert
.plugin_paths
,
3878 cfg
->cmd_data
.convert
.omit_system_plugin_path
,
3879 cfg
->cmd_data
.convert
.omit_home_plugin_path
)) {
3880 printf_err("Cannot append home and system plugin paths\n");
3884 /* Append current component configuration, if any */
3885 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
3886 add_cfg_comp(cfg
, cur_cfg_comp
, cur_cfg_comp_dest
);
3888 cur_cfg_comp
= NULL
;
3890 /* Validate legacy/non-legacy options */
3891 if (!validate_cfg(cfg
, &legacy_input_format
, &legacy_output_format
,
3892 legacy_input_paths
, &ctf_legacy_opts
,
3893 &text_legacy_opts
)) {
3894 printf_err("Command-line options form an invalid configuration\n");
3899 * If there's a legacy input format, convert it to source
3900 * component configurations.
3902 if (legacy_input_format
) {
3903 if (append_sources_from_legacy_opts(
3904 cfg
->cmd_data
.convert
.sources
,
3905 legacy_input_format
, &ctf_legacy_opts
,
3906 legacy_input_paths
)) {
3907 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
3910 if (append_sources_from_implicit_params(
3911 cfg
->cmd_data
.convert
.sources
,
3912 implicit_source_comp
)) {
3913 printf_err("Cannot initialize legacy component parameters\n");
3916 use_implicit_source
= false;
3918 if (use_implicit_source
) {
3919 add_cfg_comp(cfg
, implicit_source_comp
,
3920 BT_CONFIG_COMPONENT_DEST_SOURCE
);
3921 implicit_source_comp
= NULL
;
3923 if (implicit_source_comp
3924 && !bt_value_map_is_empty(implicit_source_comp
->params
)) {
3925 printf_err("Arguments specified for implicit input format, but an explicit source component instance has been specified: overriding it\n");
3932 * At this point if we need to print the CTF metadata text, we
3933 * don't care about the legacy/implicit sinks and component
3936 if (cfg
->cmd_data
.convert
.print_ctf_metadata
) {
3941 * If there's a legacy output format, convert it to sink
3942 * component configurations.
3944 if (legacy_output_format
) {
3945 if (append_sinks_from_legacy_opts(cfg
->cmd_data
.convert
.sinks
,
3946 legacy_output_format
, &text_legacy_opts
)) {
3947 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
3952 if (cfg
->cmd_data
.convert
.sinks
->len
== 0) {
3953 /* Use implicit sink as default. */
3954 cur_cfg_comp
= bt_config_component_from_arg(
3955 BT_COMPONENT_CLASS_TYPE_SINK
,
3956 DEFAULT_SINK_COMPONENT_NAME
);
3957 if (!cur_cfg_comp
) {
3958 printf_error("Cannot find implicit sink plugin `%s`\n",
3959 DEFAULT_SINK_COMPONENT_NAME
);
3961 add_cfg_comp(cfg
, cur_cfg_comp
,
3962 BT_CONFIG_COMPONENT_DEST_SINK
);
3963 cur_cfg_comp
= NULL
;
3966 ret
= bt_config_create_connections(cfg
, connection_args
,
3969 printf_err("Cannot creation connections:\n%s", error_buf
);
3981 poptFreeContext(pc
);
3984 if (text_legacy_opts
.output
) {
3985 g_string_free(text_legacy_opts
.output
, TRUE
);
3988 if (text_legacy_opts
.dbg_info_dir
) {
3989 g_string_free(text_legacy_opts
.dbg_info_dir
, TRUE
);
3992 if (text_legacy_opts
.dbg_info_target_prefix
) {
3993 g_string_free(text_legacy_opts
.dbg_info_target_prefix
, TRUE
);
3997 BT_PUT(implicit_source_comp
);
3998 BT_PUT(cur_cfg_comp
);
3999 BT_PUT(cur_base_params
);
4000 BT_PUT(text_legacy_opts
.names
);
4001 BT_PUT(text_legacy_opts
.fields
);
4002 BT_PUT(legacy_input_paths
);
4003 BT_PUT(instance_names
);
4004 BT_PUT(connection_args
);
4009 * Prints the Babeltrace 2.x general usage.
4012 void print_gen_usage(FILE *fp
)
4014 fprintf(fp
, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
4016 fprintf(fp
, "General options:\n");
4018 fprintf(fp
, " -d, --debug Enable debug mode\n");
4019 fprintf(fp
, " -h --help Show this help and quit\n");
4020 fprintf(fp
, " --help-legacy Show Babeltrace 1.x legacy help and quit\n");
4021 fprintf(fp
, " -v, --verbose Enable verbose output\n");
4022 fprintf(fp
, " -V, --version Show version and quit\n");
4024 fprintf(fp
, "Available commands:\n");
4026 fprintf(fp
, " convert Build a trace conversion graph and run it (default)\n");
4027 fprintf(fp
, " help Get help for a plugin or a component class\n");
4028 fprintf(fp
, " list-plugins List available plugins and their content\n");
4029 fprintf(fp
, " query Query objects from a component class\n");
4031 fprintf(fp
, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
4034 struct bt_config
*bt_config_from_args(int argc
, const char *argv
[],
4035 int *retcode
, bool omit_system_plugin_path
,
4036 bool omit_home_plugin_path
,
4037 struct bt_value
*initial_plugin_paths
)
4039 struct bt_config
*config
= NULL
;
4040 bool verbose
= false;
4043 enum bt_config_command command
= -1;
4044 const char **command_argv
= NULL
;
4045 int command_argc
= -1;
4046 const char *command_name
= NULL
;
4051 print_gen_usage(stdout
);
4055 for (i
= 1; i
< argc
; i
++) {
4056 const char *cur_arg
= argv
[i
];
4058 if (strcmp(cur_arg
, "-d") == 0 ||
4059 strcmp(cur_arg
, "--debug") == 0) {
4061 } else if (strcmp(cur_arg
, "-v") == 0 ||
4062 strcmp(cur_arg
, "--verbose") == 0) {
4064 } else if (strcmp(cur_arg
, "-V") == 0 ||
4065 strcmp(cur_arg
, "--version") == 0) {
4068 } else if (strcmp(cur_arg
, "-h") == 0 ||
4069 strcmp(cur_arg
, "--help") == 0) {
4070 print_gen_usage(stdout
);
4072 } else if (strcmp(cur_arg
, "--help-legacy") == 0) {
4073 print_legacy_usage(stdout
);
4076 bool has_command
= true;
4079 * First unknown argument: is it a known command
4082 if (strcmp(cur_arg
, "convert") == 0) {
4083 command
= BT_CONFIG_COMMAND_CONVERT
;
4084 } else if (strcmp(cur_arg
, "list-plugins") == 0) {
4085 command
= BT_CONFIG_COMMAND_LIST_PLUGINS
;
4086 } else if (strcmp(cur_arg
, "help") == 0) {
4087 command
= BT_CONFIG_COMMAND_HELP
;
4088 } else if (strcmp(cur_arg
, "query") == 0) {
4089 command
= BT_CONFIG_COMMAND_QUERY
;
4092 * Unknown argument, but not a known
4093 * command name: assume the whole
4094 * arguments are for the default convert
4097 command
= BT_CONFIG_COMMAND_CONVERT
;
4098 command_argv
= argv
;
4099 command_argc
= argc
;
4100 has_command
= false;
4104 command_argv
= &argv
[i
];
4105 command_argc
= argc
- i
;
4106 command_name
= cur_arg
;
4112 if ((int) command
< 0) {
4114 * We only got non-help, non-version general options
4115 * like --verbose and --debug, without any other
4116 * arguments, so we can't do anything useful: print the
4119 print_gen_usage(stdout
);
4123 assert(command_argv
);
4124 assert(command_argc
>= 0);
4127 case BT_CONFIG_COMMAND_CONVERT
:
4128 config
= bt_config_convert_from_args(command_argc
, command_argv
,
4129 retcode
, omit_system_plugin_path
,
4130 omit_home_plugin_path
, initial_plugin_paths
);
4132 case BT_CONFIG_COMMAND_LIST_PLUGINS
:
4133 config
= bt_config_list_plugins_from_args(command_argc
,
4134 command_argv
, retcode
, omit_system_plugin_path
,
4135 omit_home_plugin_path
, initial_plugin_paths
);
4137 case BT_CONFIG_COMMAND_HELP
:
4138 config
= bt_config_help_from_args(command_argc
,
4139 command_argv
, retcode
, omit_system_plugin_path
,
4140 omit_home_plugin_path
, initial_plugin_paths
);
4142 case BT_CONFIG_COMMAND_QUERY
:
4143 config
= bt_config_query_from_args(command_argc
,
4144 command_argv
, retcode
, omit_system_plugin_path
,
4145 omit_home_plugin_path
, initial_plugin_paths
);
4153 config
->verbose
= true;
4157 config
->debug
= true;
4160 config
->command_name
= command_name
;