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/values.h>
36 #include "babeltrace-cfg.h"
39 * Error printf() macro which prepends "Error: " the first time it's
40 * called. This gives a nicer feel than having a bunch of error prefixes
41 * (since the following lines usually describe the error and possible
42 * solutions), or the error prefix just at the end.
44 #define printf_err(fmt, args...) \
46 if (is_first_error) { \
47 fprintf(stderr, "Error: "); \
48 is_first_error = false; \
50 fprintf(stderr, fmt, ##args); \
53 static bool is_first_error
= true;
55 /* INI-style parsing FSM states */
56 enum ini_parsing_fsm_state
{
57 /* Expect a map key (identifier) */
60 /* Expect an equal character ('=') */
66 /* Expect a negative number value */
67 INI_EXPECT_VALUE_NUMBER_NEG
,
69 /* Expect a comma character (',') */
73 /* INI-style parsing state variables */
74 struct ini_parsing_state
{
75 /* Lexical scanner (owned by this) */
78 /* Output map value object being filled (owned by this) */
79 struct bt_value
*params
;
81 /* Next expected FSM state */
82 enum ini_parsing_fsm_state expecting
;
84 /* Last decoded map key (owned by this) */
87 /* Complete INI-style string to parse (not owned by this) */
90 /* Error buffer (not owned by this) */
94 /* Offset option with "is set" boolean */
100 /* Legacy "ctf"/"lttng-live" format options */
101 struct ctf_legacy_opts
{
102 struct offset_opt offset_s
;
103 struct offset_opt offset_ns
;
104 bool stream_intersection
;
107 /* Legacy "text" format options */
108 struct text_legacy_opts
{
110 * output, dbg_info_dir, dbg_info_target_prefix, names,
111 * and fields are owned by this.
114 GString
*dbg_info_dir
;
115 GString
*dbg_info_target_prefix
;
116 struct bt_value
*names
;
117 struct bt_value
*fields
;
125 bool dbg_info_full_path
;
128 /* Legacy input format format */
129 enum legacy_input_format
{
130 LEGACY_INPUT_FORMAT_NONE
= 0,
131 LEGACY_INPUT_FORMAT_CTF
,
132 LEGACY_INPUT_FORMAT_LTTNG_LIVE
,
135 /* Legacy output format format */
136 enum legacy_output_format
{
137 LEGACY_OUTPUT_FORMAT_NONE
= 0,
138 LEGACY_OUTPUT_FORMAT_TEXT
,
139 LEGACY_OUTPUT_FORMAT_CTF_METADATA
,
140 LEGACY_OUTPUT_FORMAT_DUMMY
,
144 * Prints the "out of memory" error.
147 void print_err_oom(void)
149 printf_err("Out of memory\n");
153 * Prints duplicate legacy output format error.
156 void print_err_dup_legacy_output(void)
158 printf_err("More than one legacy output format specified\n");
162 * Prints duplicate legacy input format error.
165 void print_err_dup_legacy_input(void)
167 printf_err("More than one legacy input format specified\n");
171 * Checks if any of the "text" legacy options is set.
174 bool text_legacy_opts_is_any_set(struct text_legacy_opts
*opts
)
176 return (opts
->output
&& opts
->output
->len
> 0) ||
177 (opts
->dbg_info_dir
&& opts
->dbg_info_dir
->len
> 0) ||
178 (opts
->dbg_info_target_prefix
&&
179 opts
->dbg_info_target_prefix
->len
> 0) ||
180 bt_value_array_size(opts
->names
) > 0 ||
181 bt_value_array_size(opts
->fields
) > 0 ||
182 opts
->no_delta
|| opts
->clock_cycles
|| opts
->clock_seconds
||
183 opts
->clock_date
|| opts
->clock_gmt
||
184 opts
->dbg_info_full_path
;
188 * Checks if any of the "ctf" legacy options is set.
191 bool ctf_legacy_opts_is_any_set(struct ctf_legacy_opts
*opts
)
193 return opts
->offset_s
.is_set
|| opts
->offset_ns
.is_set
||
194 opts
->stream_intersection
;
198 * Appends an "expecting token" error to the INI-style parsing state's
202 void ini_append_error_expecting(struct ini_parsing_state
*state
,
203 GScanner
*scanner
, const char *expecting
)
208 g_string_append_printf(state
->ini_error
, "Expecting %s:\n", expecting
);
210 /* Only print error if there's one line */
211 if (strchr(state
->arg
, '\n') != NULL
|| strlen(state
->arg
) == 0) {
215 g_string_append_printf(state
->ini_error
, "\n %s\n", state
->arg
);
216 pos
= g_scanner_cur_position(scanner
) + 4;
218 if (!g_scanner_eof(scanner
)) {
222 for (i
= 0; i
< pos
; ++i
) {
223 g_string_append_printf(state
->ini_error
, " ");
226 g_string_append_printf(state
->ini_error
, "^\n\n");
230 int ini_handle_state(struct ini_parsing_state
*state
)
233 GTokenType token_type
;
234 struct bt_value
*value
= NULL
;
236 token_type
= g_scanner_get_next_token(state
->scanner
);
237 if (token_type
== G_TOKEN_EOF
) {
238 if (state
->expecting
!= INI_EXPECT_COMMA
) {
239 switch (state
->expecting
) {
240 case INI_EXPECT_EQUAL
:
241 ini_append_error_expecting(state
,
242 state
->scanner
, "'='");
244 case INI_EXPECT_VALUE
:
245 case INI_EXPECT_VALUE_NUMBER_NEG
:
246 ini_append_error_expecting(state
,
247 state
->scanner
, "value");
249 case INI_EXPECT_MAP_KEY
:
250 ini_append_error_expecting(state
,
251 state
->scanner
, "unquoted map key");
264 switch (state
->expecting
) {
265 case INI_EXPECT_MAP_KEY
:
266 if (token_type
!= G_TOKEN_IDENTIFIER
) {
267 ini_append_error_expecting(state
, state
->scanner
,
272 free(state
->last_map_key
);
273 state
->last_map_key
=
274 strdup(state
->scanner
->value
.v_identifier
);
275 if (!state
->last_map_key
) {
276 g_string_append(state
->ini_error
,
281 if (bt_value_map_has_key(state
->params
, state
->last_map_key
)) {
282 g_string_append_printf(state
->ini_error
,
283 "Duplicate parameter key: `%s`\n",
284 state
->last_map_key
);
288 state
->expecting
= INI_EXPECT_EQUAL
;
290 case INI_EXPECT_EQUAL
:
291 if (token_type
!= G_TOKEN_CHAR
) {
292 ini_append_error_expecting(state
,
293 state
->scanner
, "'='");
297 if (state
->scanner
->value
.v_char
!= '=') {
298 ini_append_error_expecting(state
,
299 state
->scanner
, "'='");
303 state
->expecting
= INI_EXPECT_VALUE
;
305 case INI_EXPECT_VALUE
:
307 switch (token_type
) {
309 if (state
->scanner
->value
.v_char
== '-') {
310 /* Negative number */
312 INI_EXPECT_VALUE_NUMBER_NEG
;
315 ini_append_error_expecting(state
,
316 state
->scanner
, "value");
322 /* Positive integer */
323 uint64_t int_val
= state
->scanner
->value
.v_int64
;
325 if (int_val
> (1ULL << 63) - 1) {
326 g_string_append_printf(state
->ini_error
,
327 "Integer value %" PRIu64
" is outside the range of a 64-bit signed integer\n",
332 value
= bt_value_integer_create_init(
337 /* Positive floating point number */
338 value
= bt_value_float_create_init(
339 state
->scanner
->value
.v_float
);
343 value
= bt_value_string_create_init(
344 state
->scanner
->value
.v_string
);
346 case G_TOKEN_IDENTIFIER
:
349 * Using symbols would be appropriate here,
350 * but said symbols are allowed as map key,
351 * so it's easier to consider everything an
354 * If one of the known symbols is not
355 * recognized here, then fall back to creating
358 const char *id
= state
->scanner
->value
.v_identifier
;
360 if (!strcmp(id
, "null") || !strcmp(id
, "NULL") ||
361 !strcmp(id
, "nul")) {
362 value
= bt_value_null
;
363 } else if (!strcmp(id
, "true") || !strcmp(id
, "TRUE") ||
364 !strcmp(id
, "yes") ||
365 !strcmp(id
, "YES")) {
366 value
= bt_value_bool_create_init(true);
367 } else if (!strcmp(id
, "false") ||
368 !strcmp(id
, "FALSE") ||
371 value
= bt_value_bool_create_init(false);
373 value
= bt_value_string_create_init(id
);
378 /* Unset value variable will trigger the error */
383 ini_append_error_expecting(state
,
384 state
->scanner
, "value");
388 state
->expecting
= INI_EXPECT_COMMA
;
391 case INI_EXPECT_VALUE_NUMBER_NEG
:
393 switch (token_type
) {
396 /* Negative integer */
397 uint64_t int_val
= state
->scanner
->value
.v_int64
;
399 if (int_val
> (1ULL << 63) - 1) {
400 g_string_append_printf(state
->ini_error
,
401 "Integer value -%" PRIu64
" is outside the range of a 64-bit signed integer\n",
406 value
= bt_value_integer_create_init(
407 -((int64_t) int_val
));
411 /* Negative floating point number */
412 value
= bt_value_float_create_init(
413 -state
->scanner
->value
.v_float
);
416 /* Unset value variable will trigger the error */
421 ini_append_error_expecting(state
,
422 state
->scanner
, "value");
426 state
->expecting
= INI_EXPECT_COMMA
;
429 case INI_EXPECT_COMMA
:
430 if (token_type
!= G_TOKEN_CHAR
) {
431 ini_append_error_expecting(state
,
432 state
->scanner
, "','");
436 if (state
->scanner
->value
.v_char
!= ',') {
437 ini_append_error_expecting(state
,
438 state
->scanner
, "','");
442 state
->expecting
= INI_EXPECT_MAP_KEY
;
454 if (bt_value_map_insert(state
->params
,
455 state
->last_map_key
, value
)) {
456 /* Only override return value on error */
467 * Converts an INI-style argument to an equivalent map value object.
469 * Return value is owned by the caller.
472 struct bt_value
*bt_value_from_ini(const char *arg
, GString
*ini_error
)
474 /* Lexical scanner configuration */
475 GScannerConfig scanner_config
= {
476 /* Skip whitespaces */
477 .cset_skip_characters
= " \t\n",
479 /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
480 .cset_identifier_first
=
484 .cset_identifier_nth
=
489 /* "hello" and "Hello" two different keys */
490 .case_sensitive
= TRUE
,
493 .cpair_comment_single
= NULL
,
494 .skip_comment_multi
= TRUE
,
495 .skip_comment_single
= TRUE
,
496 .scan_comment_multi
= FALSE
,
499 * Do scan identifiers, including 1-char identifiers,
500 * but NULL is a normal identifier.
502 .scan_identifier
= TRUE
,
503 .scan_identifier_1char
= TRUE
,
504 .scan_identifier_NULL
= FALSE
,
507 * No specific symbols: null and boolean "symbols" are
508 * scanned as plain identifiers.
510 .scan_symbols
= FALSE
,
511 .symbol_2_token
= FALSE
,
512 .scope_0_fallback
= FALSE
,
515 * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
516 * integers prefixed with "$".
522 .scan_hex_dollar
= FALSE
,
524 /* Convert scanned numbers to integer tokens */
525 .numbers_2_int
= TRUE
,
527 /* Support both integers and floating-point numbers */
528 .int_2_float
= FALSE
,
530 /* Scan integers as 64-bit signed integers */
533 /* Only scan double-quoted strings */
534 .scan_string_sq
= FALSE
,
535 .scan_string_dq
= TRUE
,
537 /* Do not converter identifiers to string tokens */
538 .identifier_2_string
= FALSE
,
540 /* Scan characters as G_TOKEN_CHAR token */
541 .char_2_token
= FALSE
,
543 struct ini_parsing_state state
= {
546 .expecting
= INI_EXPECT_MAP_KEY
,
548 .ini_error
= ini_error
,
551 state
.params
= bt_value_map_create();
556 state
.scanner
= g_scanner_new(&scanner_config
);
557 if (!state
.scanner
) {
561 /* Let the scan begin */
562 g_scanner_input_text(state
.scanner
, arg
, strlen(arg
));
565 int ret
= ini_handle_state(&state
);
570 } else if (ret
> 0) {
579 BT_PUT(state
.params
);
583 g_scanner_destroy(state
.scanner
);
586 free(state
.last_map_key
);
591 * Returns the parameters map value object from a command-line
592 * parameter option's argument.
594 * Return value is owned by the caller.
597 struct bt_value
*bt_value_from_arg(const char *arg
)
599 struct bt_value
*params
= NULL
;
600 GString
*ini_error
= NULL
;
602 ini_error
= g_string_new(NULL
);
608 /* Try INI-style parsing */
609 params
= bt_value_from_ini(arg
, ini_error
);
611 printf_err("%s", ini_error
->str
);
617 g_string_free(ini_error
, TRUE
);
623 * Returns the plugin and component names from a command-line
624 * source/sink option's argument. arg must have the following format:
628 * where PLUGIN is the plugin name, and COMPONENT is the component
631 * On success, both *plugin and *component are not NULL. *plugin
632 * and *component are owned by the caller.
635 void plugin_component_names_from_arg(const char *arg
, char **plugin
,
641 size_t component_len
;
643 /* Initialize both return values to NULL: not found */
647 dot
= strchr(arg
, '.');
653 end
= arg
+ strlen(arg
);
654 plugin_len
= dot
- arg
;
655 component_len
= end
- dot
- 1;
656 if (plugin_len
== 0 || component_len
== 0) {
660 *plugin
= g_malloc0(plugin_len
+ 1);
666 g_strlcpy(*plugin
, arg
, plugin_len
+ 1);
667 *component
= g_malloc0(component_len
+ 1);
673 g_strlcpy(*component
, dot
+ 1, component_len
+ 1);
680 * Prints the Babeltrace version.
683 void print_version(void)
685 puts("Babeltrace " VERSION
);
689 * Prints the legacy, Babeltrace 1.x command usage. Those options are
690 * still compatible in Babeltrace 2.x, but it is recommended to use
691 * the more generic plugin/component parameters instead of those
692 * hard-coded option names.
695 void print_legacy_usage(FILE *fp
)
697 fprintf(fp
, "Usage: babeltrace [OPTIONS] INPUT...\n");
699 fprintf(fp
, "The following options are compatible with the Babeltrace 1.x options:\n");
701 fprintf(fp
, " --help-legacy Show this help\n");
702 fprintf(fp
, " -V, --version Show version\n");
703 fprintf(fp
, " --clock-force-correlate Assume that clocks are inherently correlated\n");
704 fprintf(fp
, " across traces\n");
705 fprintf(fp
, " -d, --debug Enable debug mode\n");
706 fprintf(fp
, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
707 fprintf(fp
, " -l, --list List available formats\n");
708 fprintf(fp
, " -o, --output-format=FORMAT Output trace format (default: text)\n");
709 fprintf(fp
, " -v, --verbose Enable verbose output\n");
711 fprintf(fp
, " Available input formats: ctf, lttng-live, ctf-metadata\n");
712 fprintf(fp
, " Available output formats: text, dummy\n");
714 fprintf(fp
, "Input formats specific options:\n");
716 fprintf(fp
, " INPUT... Input trace file(s), directory(ies), or URLs\n");
717 fprintf(fp
, " --clock-offset=SEC Set clock offset to SEC seconds\n");
718 fprintf(fp
, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
719 fprintf(fp
, " --stream-intersection Only process events when all streams are active\n");
721 fprintf(fp
, "text output format specific options:\n");
723 fprintf(fp
, " --clock-cycles Print timestamps in clock cycles\n");
724 fprintf(fp
, " --clock-date Print timestamp dates\n");
725 fprintf(fp
, " --clock-gmt Print timestamps in GMT time zone\n");
726 fprintf(fp
, " (default: local time zone)\n");
727 fprintf(fp
, " --clock-seconds Print the timestamps as [SEC.NS]\n");
728 fprintf(fp
, " (default format: [HH:MM:SS.NS])\n");
729 fprintf(fp
, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
730 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
731 fprintf(fp
, " --debug-info-full-path Show full debug info source and binary paths\n");
732 fprintf(fp
, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
733 fprintf(fp
, " up executables during debug info analysis\n");
734 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
735 fprintf(fp
, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
736 fprintf(fp
, " all, trace, trace:hostname, trace:domain,\n");
737 fprintf(fp
, " trace:procname, trace:vpid, loglevel, emf,\n");
738 fprintf(fp
, " callsite\n");
739 fprintf(fp
, " (default: trace:hostname, trace:procname,\n");
740 fprintf(fp
, " trace:vpid)\n");
741 fprintf(fp
, " -n, --names=NAME[,NAME]... Print field names:\n");
742 fprintf(fp
, " payload (or arg or args)\n");
743 fprintf(fp
, " none, all, scope, header, context (or ctx)\n");
744 fprintf(fp
, " (default: payload, context)\n");
745 fprintf(fp
, " --no-delta Do not print time delta between consecutive\n");
746 fprintf(fp
, " events\n");
747 fprintf(fp
, " -w, --output=PATH Write output to PATH (default: standard output)\n");
751 * Prints the Babeltrace 2.x usage.
754 void print_usage(FILE *fp
)
756 fprintf(fp
, "Usage: babeltrace [OPTIONS]\n");
758 fprintf(fp
, " -B, --base-begin-ns=NS Set NS as the current base beginning\n");
759 fprintf(fp
, " timestamp of the following source component\n");
760 fprintf(fp
, " instances\n");
761 fprintf(fp
, " -E, --base-end-ns=NS Set NS as the current base end timestamp\n");
762 fprintf(fp
, " of the following source component instances\n");
763 fprintf(fp
, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
764 fprintf(fp
, " of the following source and sink component\n");
765 fprintf(fp
, " instances (see the exact format of PARAMS\n");
766 fprintf(fp
, " below)\n");
767 fprintf(fp
, " --begin-ns=NS Set the beginning timestamp of the latest\n");
768 fprintf(fp
, " source component instance to NS\n");
769 fprintf(fp
, " -d, --debug Enable debug mode\n");
770 fprintf(fp
, " --end-ns=NS Set the end timestamp of the latest source\n");
771 fprintf(fp
, " component instance to NS\n");
772 fprintf(fp
, " -l, --list List available plugins and their components\n");
773 fprintf(fp
, " -P, --path=PATH Set the `path` parameter of the latest source\n");
774 fprintf(fp
, " or sink component to PATH\n");
775 fprintf(fp
, " -p, --params=PARAMS Set the parameters of the latest source or\n");
776 fprintf(fp
, " sink component instance (in command-line \n");
777 fprintf(fp
, " order) to PARAMS (see the exact format of\n");
778 fprintf(fp
, " PARAMS below)\n");
779 fprintf(fp
, " --plugin-path=PATH[:PATH]... Set paths from which dynamic plugins can be\n");
780 fprintf(fp
, " loaded to PATH\n");
781 fprintf(fp
, " --reset-base-begin-ns Reset the current base beginning timestamp\n");
782 fprintf(fp
, " of the following source component instances\n");
783 fprintf(fp
, " --reset-base-end-ns Reset the current base end timestamp of the\n");
784 fprintf(fp
, " following source component instances\n");
785 fprintf(fp
, " -r, --reset-base-params Reset the current base parameters of the\n");
786 fprintf(fp
, " following source and sink component\n");
787 fprintf(fp
, " instances to an empty map\n");
788 fprintf(fp
, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
789 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
790 fprintf(fp
, " repeated)\n");
791 fprintf(fp
, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
792 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
793 fprintf(fp
, " repeated)\n");
794 fprintf(fp
, " -h --help Show this help\n");
795 fprintf(fp
, " --help-legacy Show Babeltrace 1.x legacy options\n");
796 fprintf(fp
, " -v, --verbose Enable verbose output\n");
797 fprintf(fp
, " -V, --version Show version\n");
799 fprintf(fp
, "Format of PARAMS\n");
800 fprintf(fp
, "----------------\n");
802 fprintf(fp
, " PARAM=VALUE[,PARAM=VALUE]...\n");
804 fprintf(fp
, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
805 fprintf(fp
, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
806 fprintf(fp
, "VALUE can be one of:\n");
808 fprintf(fp
, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
809 fprintf(fp
, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
810 fprintf(fp
, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
811 fprintf(fp
, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
812 fprintf(fp
, " (`0x` prefix) signed 64-bit integer.\n");
813 fprintf(fp
, "* Double precision floating point number (scientific notation is accepted).\n");
814 fprintf(fp
, "* Unquoted string with no special characters, and not matching any of\n");
815 fprintf(fp
, " the null and boolean value symbols above.\n");
816 fprintf(fp
, "* Double-quoted string (accepts escape characters).\n");
818 fprintf(fp
, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
820 fprintf(fp
, "Example:\n");
822 fprintf(fp
, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
823 fprintf(fp
, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
824 fprintf(fp
, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
826 fprintf(fp
, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
827 fprintf(fp
, "from a shell.\n");
831 * Destroys a component configuration.
834 void bt_config_component_destroy(struct bt_object
*obj
)
836 struct bt_config_component
*bt_config_component
=
837 container_of(obj
, struct bt_config_component
, base
);
843 if (bt_config_component
->plugin_name
) {
844 g_string_free(bt_config_component
->plugin_name
, TRUE
);
847 if (bt_config_component
->component_name
) {
848 g_string_free(bt_config_component
->component_name
, TRUE
);
851 BT_PUT(bt_config_component
->params
);
852 g_free(bt_config_component
);
859 * Creates a component configuration using the given plugin name and
860 * component name. plugin_name and component_name are copied (belong to
863 * Return value is owned by the caller.
866 struct bt_config_component
*bt_config_component_create(const char *plugin_name
,
867 const char *component_name
)
869 struct bt_config_component
*cfg_component
= NULL
;
871 cfg_component
= g_new0(struct bt_config_component
, 1);
872 if (!cfg_component
) {
877 bt_object_init(cfg_component
, bt_config_component_destroy
);
878 cfg_component
->plugin_name
= g_string_new(plugin_name
);
879 if (!cfg_component
->plugin_name
) {
884 cfg_component
->component_name
= g_string_new(component_name
);
885 if (!cfg_component
->component_name
) {
890 /* Start with empty parameters */
891 cfg_component
->params
= bt_value_map_create();
892 if (!cfg_component
->params
) {
897 /* Begin/end timestamp: not set */
898 cfg_component
->begin_ns
= -1ULL;
899 cfg_component
->end_ns
= -1ULL;
904 BT_PUT(cfg_component
);
907 return cfg_component
;
911 * Creates a component configuration from a command-line source/sink
915 struct bt_config_component
*bt_config_component_from_arg(const char *arg
)
917 struct bt_config_component
*bt_config_component
= NULL
;
919 char *component_name
;
921 plugin_component_names_from_arg(arg
, &plugin_name
, &component_name
);
922 if (!plugin_name
|| !component_name
) {
923 printf_err("Cannot get plugin or component class name\n");
927 bt_config_component
= bt_config_component_create(plugin_name
,
929 if (!bt_config_component
) {
936 BT_PUT(bt_config_component
);
940 g_free(component_name
);
941 return bt_config_component
;
945 * Destroys a configuration.
948 void bt_config_destroy(struct bt_object
*obj
)
950 struct bt_config
*bt_config
=
951 container_of(obj
, struct bt_config
, base
);
957 if (bt_config
->sources
) {
958 g_ptr_array_free(bt_config
->sources
, TRUE
);
961 if (bt_config
->sinks
) {
962 g_ptr_array_free(bt_config
->sinks
, TRUE
);
965 BT_PUT(bt_config
->plugin_paths
);
973 * Extracts the various paths from the string arg, delimited by ':',
974 * and converts them to an array value object.
976 * Returned array value object is empty if arg is empty.
978 * Return value is owned by the caller.
981 struct bt_value
*plugin_paths_from_arg(const char *arg
)
983 struct bt_value
*plugin_paths
;
984 const char *at
= arg
;
985 const char *end
= arg
+ strlen(arg
);
987 plugin_paths
= bt_value_array_create();
996 const char *next_colon
;
998 next_colon
= strchr(at
, ':');
999 if (next_colon
== at
) {
1001 * Empty path: try next character (supported
1002 * to conform to the typical parsing of $PATH).
1006 } else if (!next_colon
) {
1007 /* No more colon: use the remaining */
1008 next_colon
= arg
+ strlen(arg
);
1011 path
= g_string_new(NULL
);
1017 g_string_append_len(path
, at
, next_colon
- at
);
1018 at
= next_colon
+ 1;
1019 ret
= bt_value_array_append_string(plugin_paths
, path
->str
);
1020 g_string_free(path
, TRUE
);
1030 BT_PUT(plugin_paths
);
1033 return plugin_paths
;
1037 * Creates a simple lexical scanner for parsing comma-delimited names
1040 * Return value is owned by the caller.
1043 GScanner
*create_csv_identifiers_scanner(void)
1045 GScannerConfig scanner_config
= {
1046 .cset_skip_characters
= " \t\n",
1047 .cset_identifier_first
= G_CSET_a_2_z G_CSET_A_2_Z
"_",
1048 .cset_identifier_nth
= G_CSET_a_2_z G_CSET_A_2_Z
":_-",
1049 .case_sensitive
= TRUE
,
1050 .cpair_comment_single
= NULL
,
1051 .skip_comment_multi
= TRUE
,
1052 .skip_comment_single
= TRUE
,
1053 .scan_comment_multi
= FALSE
,
1054 .scan_identifier
= TRUE
,
1055 .scan_identifier_1char
= TRUE
,
1056 .scan_identifier_NULL
= FALSE
,
1057 .scan_symbols
= FALSE
,
1058 .symbol_2_token
= FALSE
,
1059 .scope_0_fallback
= FALSE
,
1060 .scan_binary
= FALSE
,
1061 .scan_octal
= FALSE
,
1062 .scan_float
= FALSE
,
1064 .scan_hex_dollar
= FALSE
,
1065 .numbers_2_int
= FALSE
,
1066 .int_2_float
= FALSE
,
1067 .store_int64
= FALSE
,
1068 .scan_string_sq
= FALSE
,
1069 .scan_string_dq
= FALSE
,
1070 .identifier_2_string
= FALSE
,
1071 .char_2_token
= TRUE
,
1074 return g_scanner_new(&scanner_config
);
1078 * Inserts a string (if exists and not empty) or null to a map value
1082 enum bt_value_status
map_insert_string_or_null(struct bt_value
*map
,
1083 const char *key
, GString
*string
)
1085 enum bt_value_status ret
;
1087 if (string
&& string
->len
> 0) {
1088 ret
= bt_value_map_insert_string(map
, key
, string
->str
);
1090 ret
= bt_value_map_insert(map
, key
, bt_value_null
);
1096 * Converts a comma-delimited list of known names (--names option) to
1097 * an array value object containing those names as string value objects.
1099 * Return value is owned by the caller.
1102 struct bt_value
*names_from_arg(const char *arg
)
1104 GScanner
*scanner
= NULL
;
1105 struct bt_value
*names
= NULL
;
1106 bool found_all
= false, found_none
= false, found_item
= false;
1108 names
= bt_value_array_create();
1114 scanner
= create_csv_identifiers_scanner();
1120 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1123 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1125 switch (token_type
) {
1126 case G_TOKEN_IDENTIFIER
:
1128 const char *identifier
= scanner
->value
.v_identifier
;
1130 if (!strcmp(identifier
, "payload") ||
1131 !strcmp(identifier
, "args") ||
1132 !strcmp(identifier
, "arg")) {
1134 if (bt_value_array_append_string(names
,
1138 } else if (!strcmp(identifier
, "context") ||
1139 !strcmp(identifier
, "ctx")) {
1141 if (bt_value_array_append_string(names
,
1145 } else if (!strcmp(identifier
, "scope") ||
1146 !strcmp(identifier
, "header")) {
1148 if (bt_value_array_append_string(names
,
1152 } else if (!strcmp(identifier
, "all")) {
1154 if (bt_value_array_append_string(names
,
1158 } else if (!strcmp(identifier
, "none")) {
1160 if (bt_value_array_append_string(names
,
1165 printf_err("Unknown field name: `%s`\n",
1181 if (found_none
&& found_all
) {
1182 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
1186 * Legacy behavior is to clear the defaults (show none) when at
1187 * least one item is specified.
1189 if (found_item
&& !found_none
&& !found_all
) {
1190 if (bt_value_array_append_string(names
, "none")) {
1195 g_scanner_destroy(scanner
);
1202 g_scanner_destroy(scanner
);
1209 * Converts a comma-delimited list of known fields (--fields option) to
1210 * an array value object containing those fields as string
1213 * Return value is owned by the caller.
1216 struct bt_value
*fields_from_arg(const char *arg
)
1218 GScanner
*scanner
= NULL
;
1219 struct bt_value
*fields
;
1221 fields
= bt_value_array_create();
1227 scanner
= create_csv_identifiers_scanner();
1233 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1236 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1238 switch (token_type
) {
1239 case G_TOKEN_IDENTIFIER
:
1241 const char *identifier
= scanner
->value
.v_identifier
;
1243 if (!strcmp(identifier
, "trace") ||
1244 !strcmp(identifier
, "trace:hostname") ||
1245 !strcmp(identifier
, "trace:domain") ||
1246 !strcmp(identifier
, "trace:procname") ||
1247 !strcmp(identifier
, "trace:vpid") ||
1248 !strcmp(identifier
, "loglevel") ||
1249 !strcmp(identifier
, "emf") ||
1250 !strcmp(identifier
, "callsite") ||
1251 !strcmp(identifier
, "all")) {
1252 if (bt_value_array_append_string(fields
,
1257 printf_err("Unknown field name: `%s`\n",
1279 g_scanner_destroy(scanner
);
1285 * Inserts the equivalent "prefix-name" true boolean value objects into
1286 * map_obj where the names are in array_obj.
1289 int insert_flat_names_fields_from_array(struct bt_value
*map_obj
,
1290 struct bt_value
*array_obj
, const char *prefix
)
1294 GString
*tmpstr
= NULL
, *default_value
= NULL
;
1297 * array_obj may be NULL if no CLI options were specified to
1298 * trigger its creation.
1304 tmpstr
= g_string_new(NULL
);
1311 default_value
= g_string_new(NULL
);
1312 if (!default_value
) {
1318 for (i
= 0; i
< bt_value_array_size(array_obj
); i
++) {
1319 struct bt_value
*str_obj
= bt_value_array_get(array_obj
, i
);
1321 bool is_default
= false;
1324 printf_err("Unexpected error\n");
1329 ret
= bt_value_string_get(str_obj
, &suffix
);
1332 printf_err("Unexpected error\n");
1336 g_string_assign(tmpstr
, prefix
);
1337 g_string_append(tmpstr
, "-");
1339 /* Special-case for "all" and "none". */
1340 if (!strcmp(suffix
, "all")) {
1342 g_string_assign(default_value
, "show");
1343 } else if (!strcmp(suffix
, "none")) {
1345 g_string_assign(default_value
, "hide");
1348 g_string_append(tmpstr
, "default");
1349 ret
= map_insert_string_or_null(map_obj
,
1357 g_string_append(tmpstr
, suffix
);
1358 ret
= bt_value_map_insert_bool(map_obj
, tmpstr
->str
,
1368 if (default_value
) {
1369 g_string_free(default_value
, TRUE
);
1372 g_string_free(tmpstr
, TRUE
);
1379 * Returns the parameters (map value object) corresponding to the
1380 * legacy text format options.
1382 * Return value is owned by the caller.
1385 struct bt_value
*params_from_text_legacy_opts(
1386 struct text_legacy_opts
*text_legacy_opts
)
1388 struct bt_value
*params
;
1390 params
= bt_value_map_create();
1396 if (map_insert_string_or_null(params
, "output-path",
1397 text_legacy_opts
->output
)) {
1402 if (map_insert_string_or_null(params
, "debug-info-dir",
1403 text_legacy_opts
->dbg_info_dir
)) {
1408 if (map_insert_string_or_null(params
, "debug-info-target-prefix",
1409 text_legacy_opts
->dbg_info_target_prefix
)) {
1414 if (bt_value_map_insert_bool(params
, "debug-info-full-path",
1415 text_legacy_opts
->dbg_info_full_path
)) {
1420 if (bt_value_map_insert_bool(params
, "no-delta",
1421 text_legacy_opts
->no_delta
)) {
1426 if (bt_value_map_insert_bool(params
, "clock-cycles",
1427 text_legacy_opts
->clock_cycles
)) {
1432 if (bt_value_map_insert_bool(params
, "clock-seconds",
1433 text_legacy_opts
->clock_seconds
)) {
1438 if (bt_value_map_insert_bool(params
, "clock-date",
1439 text_legacy_opts
->clock_date
)) {
1444 if (bt_value_map_insert_bool(params
, "clock-gmt",
1445 text_legacy_opts
->clock_gmt
)) {
1450 if (insert_flat_names_fields_from_array(params
,
1451 text_legacy_opts
->names
, "name")) {
1455 if (insert_flat_names_fields_from_array(params
,
1456 text_legacy_opts
->fields
, "field")) {
1470 int append_sinks_from_legacy_opts(GPtrArray
*sinks
,
1471 enum legacy_output_format legacy_output_format
,
1472 struct text_legacy_opts
*text_legacy_opts
)
1475 struct bt_value
*params
= NULL
;
1476 const char *plugin_name
;
1477 const char *component_name
;
1478 struct bt_config_component
*bt_config_component
= NULL
;
1480 switch (legacy_output_format
) {
1481 case LEGACY_OUTPUT_FORMAT_TEXT
:
1482 plugin_name
= "text";
1483 component_name
= "text";
1485 case LEGACY_OUTPUT_FORMAT_CTF_METADATA
:
1486 plugin_name
= "ctf";
1487 component_name
= "metadata-text";
1489 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1490 plugin_name
= "dummy";
1491 component_name
= "dummy";
1498 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
) {
1499 /* Legacy "text" output format has parameters */
1500 params
= params_from_text_legacy_opts(text_legacy_opts
);
1506 * Legacy "dummy" and "ctf-metadata" output formats do
1507 * not have parameters.
1509 params
= bt_value_map_create();
1516 /* Create a component configuration */
1517 bt_config_component
= bt_config_component_create(plugin_name
,
1519 if (!bt_config_component
) {
1523 BT_MOVE(bt_config_component
->params
, params
);
1525 /* Move created component configuration to the array */
1526 g_ptr_array_add(sinks
, bt_config_component
);
1540 * Returns the parameters (map value object) corresponding to the
1541 * given legacy CTF format options.
1543 * Return value is owned by the caller.
1546 struct bt_value
*params_from_ctf_legacy_opts(
1547 struct ctf_legacy_opts
*ctf_legacy_opts
)
1549 struct bt_value
*params
;
1551 params
= bt_value_map_create();
1557 if (bt_value_map_insert_integer(params
, "offset-s",
1558 ctf_legacy_opts
->offset_s
.value
)) {
1563 if (bt_value_map_insert_integer(params
, "offset-ns",
1564 ctf_legacy_opts
->offset_ns
.value
)) {
1569 if (bt_value_map_insert_bool(params
, "stream-intersection",
1570 ctf_legacy_opts
->stream_intersection
)) {
1585 int append_sources_from_legacy_opts(GPtrArray
*sources
,
1586 enum legacy_input_format legacy_input_format
,
1587 struct ctf_legacy_opts
*ctf_legacy_opts
,
1588 struct bt_value
*legacy_input_paths
,
1589 uint64_t begin_ns
, uint64_t end_ns
)
1593 struct bt_value
*base_params
;
1594 struct bt_value
*params
= NULL
;
1595 struct bt_value
*input_path
= NULL
;
1596 struct bt_value
*input_path_copy
= NULL
;
1597 const char *input_key
;
1598 const char *component_name
;
1600 switch (legacy_input_format
) {
1601 case LEGACY_INPUT_FORMAT_CTF
:
1603 component_name
= "fs";
1605 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1607 component_name
= "lttng-live";
1614 base_params
= params_from_ctf_legacy_opts(ctf_legacy_opts
);
1619 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1620 struct bt_config_component
*bt_config_component
= NULL
;
1622 /* Copy base parameters as current parameters */
1623 params
= bt_value_copy(base_params
);
1628 /* Get current input path string value object */
1629 input_path
= bt_value_array_get(legacy_input_paths
, i
);
1634 /* Copy current input path value object */
1635 input_path_copy
= bt_value_copy(input_path
);
1636 if (!input_path_copy
) {
1640 /* Insert input path value object into current parameters */
1641 ret
= bt_value_map_insert(params
, input_key
, input_path_copy
);
1646 /* Create a component configuration */
1647 bt_config_component
= bt_config_component_create("ctf",
1649 if (!bt_config_component
) {
1653 BT_MOVE(bt_config_component
->params
, params
);
1654 bt_config_component
->begin_ns
= begin_ns
;
1655 bt_config_component
->end_ns
= end_ns
;
1657 /* Move created component configuration to the array */
1658 g_ptr_array_add(sources
, bt_config_component
);
1660 /* Put current stuff */
1662 BT_PUT(input_path_copy
);
1671 BT_PUT(base_params
);
1674 BT_PUT(input_path_copy
);
1679 * Escapes a string for the shell. The string is escaped knowing that
1680 * it's a parameter string value (double-quoted), and that it will be
1681 * entered between single quotes in the shell.
1683 * Return value is owned by the caller.
1686 char *str_shell_escape(const char *input
)
1689 const char *at
= input
;
1690 GString
*str
= g_string_new(NULL
);
1696 while (*at
!= '\0') {
1699 g_string_append(str
, "\\\\");
1702 g_string_append(str
, "\\\"");
1705 g_string_append(str
, "'\"'\"'");
1708 g_string_append(str
, "\\n");
1711 g_string_append(str
, "\\t");
1714 g_string_append_c(str
, *at
);
1724 g_string_free(str
, FALSE
);
1731 int append_prefixed_flag_params(GString
*str
, struct bt_value
*flags
,
1741 for (i
= 0; i
< bt_value_array_size(flags
); i
++) {
1742 struct bt_value
*value
= bt_value_array_get(flags
, i
);
1750 if (bt_value_string_get(value
, &flag
)) {
1756 g_string_append_printf(str
, ",%s-%s=true", prefix
, flag
);
1765 * Appends a boolean parameter string.
1768 void g_string_append_bool_param(GString
*str
, const char *name
, bool value
)
1770 g_string_append_printf(str
, ",%s=%s", name
, value
? "true" : "false");
1774 * Appends a path parameter string, or null if it's empty.
1777 int g_string_append_string_path_param(GString
*str
, const char *name
,
1782 if (path
->len
> 0) {
1783 char *escaped_path
= str_shell_escape(path
->str
);
1785 if (!escaped_path
) {
1790 g_string_append_printf(str
, "%s=\"%s\"", name
, escaped_path
);
1793 g_string_append_printf(str
, "%s=null", name
);
1806 * Prints the non-legacy sink options equivalent to the specified
1807 * legacy output format options.
1810 void print_output_legacy_to_sinks(
1811 enum legacy_output_format legacy_output_format
,
1812 struct text_legacy_opts
*text_legacy_opts
)
1814 const char *input_format
;
1815 GString
*str
= NULL
;
1817 str
= g_string_new(" ");
1823 switch (legacy_output_format
) {
1824 case LEGACY_OUTPUT_FORMAT_TEXT
:
1825 input_format
= "text";
1827 case LEGACY_OUTPUT_FORMAT_CTF_METADATA
:
1828 input_format
= "ctf-metadata";
1830 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1831 input_format
= "dummy";
1837 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
1839 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
1841 g_string_append(str
, "-o ");
1843 switch (legacy_output_format
) {
1844 case LEGACY_OUTPUT_FORMAT_TEXT
:
1845 g_string_append(str
, "text.text");
1847 case LEGACY_OUTPUT_FORMAT_CTF_METADATA
:
1848 g_string_append(str
, "ctf.metadata-text");
1850 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1851 g_string_append(str
, "dummy.dummy");
1857 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
&&
1858 text_legacy_opts_is_any_set(text_legacy_opts
)) {
1861 g_string_append(str
, " -p '");
1863 if (g_string_append_string_path_param(str
, "output-path",
1864 text_legacy_opts
->output
)) {
1868 g_string_append(str
, ",");
1870 if (g_string_append_string_path_param(str
, "debug-info-dir",
1871 text_legacy_opts
->dbg_info_dir
)) {
1875 g_string_append(str
, ",");
1877 if (g_string_append_string_path_param(str
,
1878 "debug-info-target-prefix",
1879 text_legacy_opts
->dbg_info_target_prefix
)) {
1883 g_string_append_bool_param(str
, "no-delta",
1884 text_legacy_opts
->no_delta
);
1885 g_string_append_bool_param(str
, "clock-cycles",
1886 text_legacy_opts
->clock_cycles
);
1887 g_string_append_bool_param(str
, "clock-seconds",
1888 text_legacy_opts
->clock_seconds
);
1889 g_string_append_bool_param(str
, "clock-date",
1890 text_legacy_opts
->clock_date
);
1891 g_string_append_bool_param(str
, "clock-gmt",
1892 text_legacy_opts
->clock_gmt
);
1893 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->names
,
1899 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->fields
,
1905 /* Remove last comma and close single quote */
1906 g_string_append(str
, "'");
1909 printf_err("%s\n\n", str
->str
);
1913 g_string_free(str
, TRUE
);
1919 * Prints the non-legacy source options equivalent to the specified
1920 * legacy input format options.
1923 void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format
,
1924 struct bt_value
*legacy_input_paths
,
1925 struct ctf_legacy_opts
*ctf_legacy_opts
)
1927 const char *input_format
;
1928 GString
*str
= NULL
;
1931 str
= g_string_new(" ");
1937 switch (legacy_input_format
) {
1938 case LEGACY_INPUT_FORMAT_CTF
:
1939 input_format
= "ctf";
1941 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1942 input_format
= "lttng-live";
1948 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
1950 printf_err("Specify the following non-legacy source component instance(s) instead of the\nlegacy `%s` input format options and positional arguments:\n\n",
1953 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1954 struct bt_value
*input_value
=
1955 bt_value_array_get(legacy_input_paths
, i
);
1956 const char *input
= NULL
;
1957 char *escaped_input
;
1960 assert(input_value
);
1961 ret
= bt_value_string_get(input_value
, &input
);
1962 BT_PUT(input_value
);
1963 assert(!ret
&& input
);
1964 escaped_input
= str_shell_escape(input
);
1965 if (!escaped_input
) {
1970 g_string_append(str
, "-i ctf.");
1972 switch (legacy_input_format
) {
1973 case LEGACY_INPUT_FORMAT_CTF
:
1974 g_string_append(str
, "fs -p 'path=\"");
1976 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1977 g_string_append(str
, "lttng-live -p 'url=\"");
1983 g_string_append(str
, escaped_input
);
1984 g_string_append(str
, "\"");
1985 g_string_append_printf(str
, ",offset-s=%" PRId64
,
1986 ctf_legacy_opts
->offset_s
.value
);
1987 g_string_append_printf(str
, ",offset-ns=%" PRId64
,
1988 ctf_legacy_opts
->offset_ns
.value
);
1989 g_string_append_bool_param(str
, "stream-intersection",
1990 ctf_legacy_opts
->stream_intersection
);
1991 g_string_append(str
, "' ");
1992 g_free(escaped_input
);
1995 printf_err("%s\n\n", str
->str
);
1999 g_string_free(str
, TRUE
);
2005 * Validates a given source component configuration.
2008 bool validate_source_config_component(struct bt_config_component
*cfg_comp
)
2012 if (cfg_comp
->begin_ns
!= -1ULL && cfg_comp
->end_ns
!= -1ULL) {
2013 if (cfg_comp
->begin_ns
> cfg_comp
->end_ns
) {
2014 printf_err("Beginning timestamp (%" PRIu64
") is greater than end timestamp (%" PRIu64
")\n",
2015 cfg_comp
->begin_ns
, cfg_comp
->end_ns
);
2027 * Validates a given configuration, with optional legacy input and
2028 * output formats options. Prints useful error messages if anything
2031 * Returns true when the configuration is valid.
2034 bool validate_cfg(struct bt_config
*cfg
,
2035 enum legacy_input_format
*legacy_input_format
,
2036 enum legacy_output_format
*legacy_output_format
,
2037 struct bt_value
*legacy_input_paths
,
2038 struct ctf_legacy_opts
*ctf_legacy_opts
,
2039 struct text_legacy_opts
*text_legacy_opts
)
2041 bool legacy_input
= false;
2042 bool legacy_output
= false;
2044 /* Determine if the input and output should be legacy-style */
2045 if (*legacy_input_format
!= LEGACY_INPUT_FORMAT_NONE
||
2046 cfg
->sources
->len
== 0 ||
2047 !bt_value_array_is_empty(legacy_input_paths
) ||
2048 ctf_legacy_opts_is_any_set(ctf_legacy_opts
)) {
2049 legacy_input
= true;
2052 if (*legacy_output_format
!= LEGACY_OUTPUT_FORMAT_NONE
||
2053 cfg
->sinks
->len
== 0 ||
2054 text_legacy_opts_is_any_set(text_legacy_opts
)) {
2055 legacy_output
= true;
2059 /* If no legacy input format was specified, default to CTF */
2060 if (*legacy_input_format
== LEGACY_INPUT_FORMAT_NONE
) {
2061 *legacy_input_format
= LEGACY_INPUT_FORMAT_CTF
;
2064 /* Make sure at least one input path exists */
2065 if (bt_value_array_is_empty(legacy_input_paths
)) {
2066 switch (*legacy_input_format
) {
2067 case LEGACY_INPUT_FORMAT_CTF
:
2068 printf_err("No input path specified for legacy `ctf` input format\n");
2070 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
2071 printf_err("No URL specified for legacy `lttng-live` input format\n");
2079 /* Make sure no non-legacy sources are specified */
2080 if (cfg
->sources
->len
!= 0) {
2081 print_input_legacy_to_sources(*legacy_input_format
,
2082 legacy_input_paths
, ctf_legacy_opts
);
2087 if (legacy_output
) {
2089 * If no legacy output format was specified, default to
2092 if (*legacy_output_format
== LEGACY_OUTPUT_FORMAT_NONE
) {
2093 *legacy_output_format
= LEGACY_OUTPUT_FORMAT_TEXT
;
2097 * If any "text" option was specified, the output must be
2100 if (text_legacy_opts_is_any_set(text_legacy_opts
) &&
2101 *legacy_output_format
!=
2102 LEGACY_OUTPUT_FORMAT_TEXT
) {
2103 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
2107 /* Make sure no non-legacy sinks are specified */
2108 if (cfg
->sinks
->len
!= 0) {
2109 print_output_legacy_to_sinks(*legacy_output_format
,
2116 * If the output is the legacy "ctf-metadata" format, then the
2117 * input should be the legacy "ctf" input format.
2119 if (*legacy_output_format
== LEGACY_OUTPUT_FORMAT_CTF_METADATA
&&
2120 *legacy_input_format
!= LEGACY_INPUT_FORMAT_CTF
) {
2121 printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n");
2132 * Parses a 64-bit signed integer.
2134 * Returns a negative value if anything goes wrong.
2137 int parse_int64(const char *arg
, int64_t *val
)
2142 *val
= strtoll(arg
, &endptr
, 0);
2143 if (*endptr
!= '\0' || arg
== endptr
|| errno
!= 0) {
2151 * Parses a time in nanoseconds.
2153 * Returns a negative value if anything goes wrong.
2156 int ns_from_arg(const char *arg
, uint64_t *ns
)
2161 if (parse_int64(arg
, &value
)) {
2171 *ns
= (uint64_t) value
;
2186 OPT_CLOCK_FORCE_CORRELATE
,
2189 OPT_CLOCK_OFFSET_NS
,
2193 OPT_DEBUG_INFO_FULL_PATH
,
2194 OPT_DEBUG_INFO_TARGET_PREFIX
,
2208 OPT_RESET_BASE_BEGIN_NS
,
2209 OPT_RESET_BASE_END_NS
,
2210 OPT_RESET_BASE_PARAMS
,
2213 OPT_STREAM_INTERSECTION
,
2218 /* popt long option descriptions */
2219 static struct poptOption long_options
[] = {
2220 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2221 { "base-begin-ns", 'B', POPT_ARG_STRING
, NULL
, OPT_BASE_BEGIN_NS
, NULL
, NULL
},
2222 { "base-end-ns", 'E', POPT_ARG_STRING
, NULL
, OPT_BASE_END_NS
, NULL
, NULL
},
2223 { "base-params", 'b', POPT_ARG_STRING
, NULL
, OPT_BASE_PARAMS
, NULL
, NULL
},
2224 { "begin-ns", '\0', POPT_ARG_STRING
, NULL
, OPT_BEGIN_NS
, NULL
, NULL
},
2225 { "clock-cycles", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_CYCLES
, NULL
, NULL
},
2226 { "clock-date", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_DATE
, NULL
, NULL
},
2227 { "clock-force-correlate", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_FORCE_CORRELATE
, NULL
, NULL
},
2228 { "clock-gmt", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_GMT
, NULL
, NULL
},
2229 { "clock-offset", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET
, NULL
, NULL
},
2230 { "clock-offset-ns", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET_NS
, NULL
, NULL
},
2231 { "clock-seconds", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_SECONDS
, NULL
, NULL
},
2232 { "debug", 'd', POPT_ARG_NONE
, NULL
, OPT_DEBUG
, NULL
, NULL
},
2233 { "debug-info-dir", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_DIR
, NULL
, NULL
},
2234 { "debug-info-full-path", 0, POPT_ARG_NONE
, NULL
, OPT_DEBUG_INFO_FULL_PATH
, NULL
, NULL
},
2235 { "debug-info-target-prefix", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_TARGET_PREFIX
, NULL
, NULL
},
2236 { "end-ns", '\0', POPT_ARG_STRING
, NULL
, OPT_END_NS
, NULL
, NULL
},
2237 { "fields", 'f', POPT_ARG_STRING
, NULL
, OPT_FIELDS
, NULL
, NULL
},
2238 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2239 { "help-legacy", '\0', POPT_ARG_NONE
, NULL
, OPT_HELP_LEGACY
, NULL
, NULL
},
2240 { "input-format", 'i', POPT_ARG_STRING
, NULL
, OPT_INPUT_FORMAT
, NULL
, NULL
},
2241 { "list", 'l', POPT_ARG_NONE
, NULL
, OPT_LIST
, NULL
, NULL
},
2242 { "names", 'n', POPT_ARG_STRING
, NULL
, OPT_NAMES
, NULL
, NULL
},
2243 { "no-delta", '\0', POPT_ARG_NONE
, NULL
, OPT_NO_DELTA
, NULL
, NULL
},
2244 { "output", 'w', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_PATH
, NULL
, NULL
},
2245 { "output-format", 'o', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_FORMAT
, NULL
, NULL
},
2246 { "path", 'P', POPT_ARG_STRING
, NULL
, OPT_PATH
, NULL
, NULL
},
2247 { "params", 'p', POPT_ARG_STRING
, NULL
, OPT_PARAMS
, NULL
, NULL
},
2248 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2249 { "reset-base-begin-ns", '\0', POPT_ARG_NONE
, NULL
, OPT_RESET_BASE_BEGIN_NS
, NULL
, NULL
},
2250 { "reset-base-end-ns", '\0', POPT_ARG_NONE
, NULL
, OPT_RESET_BASE_END_NS
, NULL
, NULL
},
2251 { "reset-base-params", 'r', POPT_ARG_NONE
, NULL
, OPT_RESET_BASE_PARAMS
, NULL
, NULL
},
2252 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
2253 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
2254 { "stream-intersection", '\0', POPT_ARG_NONE
, NULL
, OPT_STREAM_INTERSECTION
, NULL
, NULL
},
2255 { "verbose", 'v', POPT_ARG_NONE
, NULL
, OPT_VERBOSE
, NULL
, NULL
},
2256 { "version", 'V', POPT_ARG_NONE
, NULL
, OPT_VERSION
, NULL
, NULL
},
2257 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2261 * Sets the value of a given legacy offset option and marks it as set.
2263 static void set_offset_value(struct offset_opt
*offset_opt
, int64_t value
)
2265 offset_opt
->value
= value
;
2266 offset_opt
->is_set
= true;
2269 enum bt_config_component_dest
{
2270 BT_CONFIG_COMPONENT_DEST_SOURCE
,
2271 BT_CONFIG_COMPONENT_DEST_SINK
,
2275 * Adds a configuration component to the appropriate configuration
2276 * array depending on the destination.
2278 static void add_cfg_comp(struct bt_config
*cfg
,
2279 struct bt_config_component
*cfg_comp
,
2280 enum bt_config_component_dest dest
)
2282 if (dest
== BT_CONFIG_COMPONENT_DEST_SOURCE
) {
2283 g_ptr_array_add(cfg
->sources
, cfg_comp
);
2285 g_ptr_array_add(cfg
->sinks
, cfg_comp
);
2290 * Returns a Babeltrace configuration, out of command-line arguments,
2291 * containing everything that is needed to instanciate specific
2292 * components with given parameters.
2294 * *exit_code is set to the appropriate exit code to use as far as this
2297 * Return value is NULL on error, otherwise it's owned by the caller.
2299 struct bt_config
*bt_config_from_args(int argc
, char *argv
[], int *exit_code
)
2301 struct bt_config
*cfg
= NULL
;
2302 poptContext pc
= NULL
;
2304 struct ctf_legacy_opts ctf_legacy_opts
= { 0 };
2305 struct text_legacy_opts text_legacy_opts
= { 0 };
2306 enum legacy_input_format legacy_input_format
= LEGACY_INPUT_FORMAT_NONE
;
2307 enum legacy_output_format legacy_output_format
=
2308 LEGACY_OUTPUT_FORMAT_NONE
;
2309 struct bt_value
*legacy_input_paths
= NULL
;
2310 struct bt_config_component
*cur_cfg_comp
= NULL
;
2311 enum bt_config_component_dest cur_cfg_comp_dest
=
2312 BT_CONFIG_COMPONENT_DEST_SOURCE
;
2313 struct bt_value
*cur_base_params
= NULL
;
2314 uint64_t cur_base_begin_ns
= -1ULL;
2315 uint64_t cur_base_end_ns
= -1ULL;
2317 bool cur_cfg_comp_params_set
= false;
2323 print_usage(stdout
);
2327 text_legacy_opts
.output
= g_string_new(NULL
);
2328 if (!text_legacy_opts
.output
) {
2333 text_legacy_opts
.dbg_info_dir
= g_string_new(NULL
);
2334 if (!text_legacy_opts
.dbg_info_dir
) {
2339 text_legacy_opts
.dbg_info_target_prefix
= g_string_new(NULL
);
2340 if (!text_legacy_opts
.dbg_info_target_prefix
) {
2345 cur_base_params
= bt_value_map_create();
2346 if (!cur_base_params
) {
2352 cfg
= g_new0(struct bt_config
, 1);
2358 bt_object_init(cfg
, bt_config_destroy
);
2359 cfg
->sources
= g_ptr_array_new_with_free_func((GDestroyNotify
) bt_put
);
2360 if (!cfg
->sources
) {
2365 cfg
->sinks
= g_ptr_array_new_with_free_func((GDestroyNotify
) bt_put
);
2371 legacy_input_paths
= bt_value_array_create();
2372 if (!legacy_input_paths
) {
2378 pc
= poptGetContext(NULL
, argc
, (const char **) argv
, long_options
, 0);
2380 printf_err("Cannot get popt context\n");
2384 poptReadDefaultConfig(pc
, 0);
2386 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2387 arg
= poptGetOptArg(pc
);
2390 case OPT_PLUGIN_PATH
:
2391 if (cfg
->plugin_paths
) {
2392 printf_err("Duplicate --plugin-path option\n");
2396 cfg
->plugin_paths
= plugin_paths_from_arg(arg
);
2397 if (!cfg
->plugin_paths
) {
2398 printf_err("Invalid --plugin-path option's argument\n");
2402 case OPT_OUTPUT_PATH
:
2403 if (text_legacy_opts
.output
->len
> 0) {
2404 printf_err("Duplicate --output option\n");
2408 g_string_assign(text_legacy_opts
.output
, arg
);
2410 case OPT_DEBUG_INFO_DIR
:
2411 if (text_legacy_opts
.dbg_info_dir
->len
> 0) {
2412 printf_err("Duplicate --debug-info-dir option\n");
2416 g_string_assign(text_legacy_opts
.dbg_info_dir
, arg
);
2418 case OPT_DEBUG_INFO_TARGET_PREFIX
:
2419 if (text_legacy_opts
.dbg_info_target_prefix
->len
> 0) {
2420 printf_err("Duplicate --debug-info-target-prefix option\n");
2424 g_string_assign(text_legacy_opts
.dbg_info_target_prefix
, arg
);
2426 case OPT_INPUT_FORMAT
:
2429 if (opt
== OPT_INPUT_FORMAT
) {
2430 if (!strcmp(arg
, "ctf")) {
2431 /* Legacy CTF input format */
2432 if (legacy_input_format
) {
2433 print_err_dup_legacy_input();
2437 legacy_input_format
=
2438 LEGACY_INPUT_FORMAT_CTF
;
2440 } else if (!strcmp(arg
, "lttng-live")) {
2441 /* Legacy LTTng-live input format */
2442 if (legacy_input_format
) {
2443 print_err_dup_legacy_input();
2447 legacy_input_format
=
2448 LEGACY_INPUT_FORMAT_LTTNG_LIVE
;
2453 /* Non-legacy: try to create a component config */
2455 add_cfg_comp(cfg
, cur_cfg_comp
,
2459 cur_cfg_comp
= bt_config_component_from_arg(arg
);
2460 if (!cur_cfg_comp
) {
2461 printf_err("Invalid format for --source option's argument:\n %s\n",
2466 assert(cur_base_params
);
2467 bt_put(cur_cfg_comp
->params
);
2468 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
2469 if (!cur_cfg_comp
) {
2474 cur_cfg_comp
->begin_ns
= cur_base_begin_ns
;
2475 cur_cfg_comp
->end_ns
= cur_base_end_ns
;
2476 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SOURCE
;
2477 cur_cfg_comp_params_set
= false;
2480 case OPT_OUTPUT_FORMAT
:
2483 if (opt
== OPT_OUTPUT_FORMAT
) {
2484 if (!strcmp(arg
, "text")) {
2485 /* Legacy CTF-text output format */
2486 if (legacy_output_format
) {
2487 print_err_dup_legacy_output();
2491 legacy_output_format
=
2492 LEGACY_OUTPUT_FORMAT_TEXT
;
2494 } else if (!strcmp(arg
, "dummy")) {
2495 /* Legacy dummy output format */
2496 if (legacy_output_format
) {
2497 print_err_dup_legacy_output();
2501 legacy_output_format
=
2502 LEGACY_OUTPUT_FORMAT_DUMMY
;
2504 } else if (!strcmp(arg
, "ctf-metadata")) {
2505 /* Legacy CTF-metadata output format */
2506 if (legacy_output_format
) {
2507 print_err_dup_legacy_output();
2511 legacy_output_format
=
2512 LEGACY_OUTPUT_FORMAT_CTF_METADATA
;
2517 /* Non-legacy: try to create a component config */
2519 add_cfg_comp(cfg
, cur_cfg_comp
,
2523 cur_cfg_comp
= bt_config_component_from_arg(arg
);
2524 if (!cur_cfg_comp
) {
2525 printf_err("Invalid format for --sink option's argument:\n %s\n",
2530 assert(cur_base_params
);
2531 bt_put(cur_cfg_comp
->params
);
2532 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
2533 if (!cur_cfg_comp
) {
2538 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SINK
;
2539 cur_cfg_comp_params_set
= false;
2544 struct bt_value
*params
;
2545 struct bt_value
*params_to_set
;
2547 if (!cur_cfg_comp
) {
2548 printf_err("--params option must follow a --source or --sink option\n");
2552 if (cur_cfg_comp_params_set
) {
2553 printf_err("Duplicate --params option for the same current component\ninstance (class %s.%s)\n",
2554 cur_cfg_comp
->plugin_name
->str
,
2555 cur_cfg_comp
->component_name
->str
);
2559 params
= bt_value_from_arg(arg
);
2561 printf_err("Invalid format for --params option's argument:\n %s\n",
2566 params_to_set
= bt_value_map_extend(cur_base_params
,
2569 if (!params_to_set
) {
2570 printf_err("Cannot extend current base parameters with --params option's argument:\n %s\n",
2575 BT_MOVE(cur_cfg_comp
->params
, params_to_set
);
2576 cur_cfg_comp_params_set
= true;
2580 if (!cur_cfg_comp
) {
2581 printf_err("--path option must follow a --source or --sink option\n");
2585 assert(cur_cfg_comp
->params
);
2587 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
2593 case OPT_BASE_PARAMS
:
2595 struct bt_value
*params
= bt_value_from_arg(arg
);
2598 printf_err("Invalid format for --base-params option's argument:\n %s\n",
2603 BT_MOVE(cur_base_params
, params
);
2606 case OPT_RESET_BASE_PARAMS
:
2607 BT_PUT(cur_base_params
);
2608 cur_base_params
= bt_value_map_create();
2609 if (!cur_base_params
) {
2614 case OPT_BASE_BEGIN_NS
:
2615 if (ns_from_arg(arg
, &cur_base_begin_ns
)) {
2616 printf_err("Invalid --base-begin-ns option's argument:\n %s\n",
2621 case OPT_BASE_END_NS
:
2622 if (ns_from_arg(arg
, &cur_base_end_ns
)) {
2623 printf_err("Invalid --base-end-ns option's argument:\n %s\n",
2628 case OPT_RESET_BASE_BEGIN_NS
:
2629 cur_base_begin_ns
= -1ULL;
2631 case OPT_RESET_BASE_END_NS
:
2632 cur_base_end_ns
= -1ULL;
2635 if (!cur_cfg_comp
|| cur_cfg_comp_dest
==
2636 BT_CONFIG_COMPONENT_DEST_SINK
) {
2637 printf_err("--begin-ns option must follow a --source option\n");
2641 if (ns_from_arg(arg
, &cur_cfg_comp
->begin_ns
)) {
2642 printf_err("Invalid --begin-ns option's argument:\n %s\n",
2648 if (!cur_cfg_comp
|| cur_cfg_comp_dest
==
2649 BT_CONFIG_COMPONENT_DEST_SINK
) {
2650 printf_err("--end-ns option must follow a --source option\n");
2654 if (ns_from_arg(arg
, &cur_cfg_comp
->end_ns
)) {
2655 printf_err("Invalid --end-ns option's argument:\n %s\n",
2661 if (text_legacy_opts
.names
) {
2662 printf_err("Duplicate --names option\n");
2666 text_legacy_opts
.names
= names_from_arg(arg
);
2667 if (!text_legacy_opts
.names
) {
2668 printf_err("Invalid --names option's argument\n");
2673 if (text_legacy_opts
.fields
) {
2674 printf_err("Duplicate --fields option\n");
2678 text_legacy_opts
.fields
= fields_from_arg(arg
);
2679 if (!text_legacy_opts
.fields
) {
2680 printf_err("Invalid --fields option's argument\n");
2685 text_legacy_opts
.no_delta
= true;
2687 case OPT_CLOCK_CYCLES
:
2688 text_legacy_opts
.clock_cycles
= true;
2690 case OPT_CLOCK_SECONDS
:
2691 text_legacy_opts
.clock_seconds
= true;
2693 case OPT_CLOCK_DATE
:
2694 text_legacy_opts
.clock_date
= true;
2697 text_legacy_opts
.clock_gmt
= true;
2699 case OPT_DEBUG_INFO_FULL_PATH
:
2700 text_legacy_opts
.dbg_info_full_path
= true;
2702 case OPT_CLOCK_OFFSET
:
2706 if (ctf_legacy_opts
.offset_s
.is_set
) {
2707 printf_err("Duplicate --clock-offset option\n");
2711 if (parse_int64(arg
, &val
)) {
2712 printf_err("Invalid --clock-offset option's argument\n");
2716 set_offset_value(&ctf_legacy_opts
.offset_s
, val
);
2719 case OPT_CLOCK_OFFSET_NS
:
2723 if (ctf_legacy_opts
.offset_ns
.is_set
) {
2724 printf_err("Duplicate --clock-offset-ns option\n");
2728 if (parse_int64(arg
, &val
)) {
2729 printf_err("Invalid --clock-offset-ns option's argument\n");
2733 set_offset_value(&ctf_legacy_opts
.offset_ns
, val
);
2736 case OPT_STREAM_INTERSECTION
:
2737 ctf_legacy_opts
.stream_intersection
= true;
2739 case OPT_CLOCK_FORCE_CORRELATE
:
2740 cfg
->force_correlate
= true;
2744 print_usage(stdout
);
2746 case OPT_HELP_LEGACY
:
2748 print_legacy_usage(stdout
);
2755 cfg
->do_list
= true;
2758 cfg
->verbose
= true;
2764 printf_err("Unknown command-line option specified (option code %d)\n",
2773 /* Append current component configuration, if any */
2775 add_cfg_comp(cfg
, cur_cfg_comp
, cur_cfg_comp_dest
);
2776 cur_cfg_comp
= NULL
;
2779 /* Check for option parsing error */
2781 printf_err("While parsing command-line options, at option %s: %s\n",
2782 poptBadOption(pc
, 0), poptStrerror(opt
));
2786 /* Consume leftover arguments as legacy input paths */
2788 const char *input_path
= poptGetArg(pc
);
2794 if (bt_value_array_append_string(legacy_input_paths
,
2801 /* Validate legacy/non-legacy options */
2802 if (!validate_cfg(cfg
, &legacy_input_format
, &legacy_output_format
,
2803 legacy_input_paths
, &ctf_legacy_opts
,
2804 &text_legacy_opts
)) {
2805 printf_err("Command-line options form an invalid configuration\n");
2810 * If there's a legacy input format, convert it to source
2811 * component configurations.
2813 if (legacy_input_format
) {
2814 if (append_sources_from_legacy_opts(cfg
->sources
,
2815 legacy_input_format
, &ctf_legacy_opts
,
2816 legacy_input_paths
, cur_base_begin_ns
,
2818 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
2824 * If there's a legacy output format, convert it to sink
2825 * component configurations.
2827 if (legacy_output_format
) {
2828 if (append_sinks_from_legacy_opts(cfg
->sinks
,
2829 legacy_output_format
, &text_legacy_opts
)) {
2830 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
2835 for (i
= 0; i
< cfg
->sources
->len
; i
++) {
2836 struct bt_config_component
*cfg_component
=
2837 bt_config_get_component(cfg
->sources
, i
);
2840 bt_put(cfg_component
);
2842 if (!validate_source_config_component(cfg_component
)) {
2843 printf_err("Invalid source component instance (class %s.%s)\n",
2844 cfg_component
->plugin_name
->str
,
2845 cfg_component
->component_name
->str
);
2859 poptFreeContext(pc
);
2862 if (text_legacy_opts
.output
) {
2863 g_string_free(text_legacy_opts
.output
, TRUE
);
2866 if (text_legacy_opts
.dbg_info_dir
) {
2867 g_string_free(text_legacy_opts
.dbg_info_dir
, TRUE
);
2870 if (text_legacy_opts
.dbg_info_target_prefix
) {
2871 g_string_free(text_legacy_opts
.dbg_info_target_prefix
, TRUE
);
2875 BT_PUT(cur_cfg_comp
);
2876 BT_PUT(cur_base_params
);
2877 BT_PUT(text_legacy_opts
.names
);
2878 BT_PUT(text_legacy_opts
.fields
);
2879 BT_PUT(legacy_input_paths
);