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 <sys/types.h>
38 #include "babeltrace-cfg.h"
40 #define SYSTEM_PLUGIN_PATH INSTALL_LIBDIR "/babeltrace/plugins"
41 #define DEFAULT_SOURCE_COMPONENT_NAME "ctf.fs"
42 #define DEFAULT_SINK_COMPONENT_NAME "text.text"
43 #define HOME_ENV_VAR "HOME"
44 #define HOME_SUBPATH "/.babeltrace/plugins"
47 * Error printf() macro which prepends "Error: " the first time it's
48 * called. This gives a nicer feel than having a bunch of error prefixes
49 * (since the following lines usually describe the error and possible
50 * solutions), or the error prefix just at the end.
52 #define printf_err(fmt, args...) \
54 if (is_first_error) { \
55 fprintf(stderr, "Error: "); \
56 is_first_error = false; \
58 fprintf(stderr, fmt, ##args); \
61 static bool is_first_error
= true;
63 /* INI-style parsing FSM states */
64 enum ini_parsing_fsm_state
{
65 /* Expect a map key (identifier) */
68 /* Expect an equal character ('=') */
74 /* Expect a negative number value */
75 INI_EXPECT_VALUE_NUMBER_NEG
,
77 /* Expect a comma character (',') */
81 /* INI-style parsing state variables */
82 struct ini_parsing_state
{
83 /* Lexical scanner (owned by this) */
86 /* Output map value object being filled (owned by this) */
87 struct bt_value
*params
;
89 /* Next expected FSM state */
90 enum ini_parsing_fsm_state expecting
;
92 /* Last decoded map key (owned by this) */
95 /* Complete INI-style string to parse (not owned by this) */
98 /* Error buffer (not owned by this) */
102 /* Offset option with "is set" boolean */
108 /* Legacy "ctf"/"lttng-live" format options */
109 struct ctf_legacy_opts
{
110 struct offset_opt offset_s
;
111 struct offset_opt offset_ns
;
112 bool stream_intersection
;
115 /* Legacy "text" format options */
116 struct text_legacy_opts
{
118 * output, dbg_info_dir, dbg_info_target_prefix, names,
119 * and fields are owned by this.
122 GString
*dbg_info_dir
;
123 GString
*dbg_info_target_prefix
;
124 struct bt_value
*names
;
125 struct bt_value
*fields
;
133 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_CTF_METADATA
,
148 LEGACY_OUTPUT_FORMAT_DUMMY
,
151 static bool omit_system_plugin_path
;
152 static bool omit_home_plugin_path
;
155 * Prints the "out of memory" error.
158 void print_err_oom(void)
160 printf_err("Out of memory\n");
164 * Prints duplicate legacy output format error.
167 void print_err_dup_legacy_output(void)
169 printf_err("More than one legacy output format specified\n");
173 * Prints duplicate legacy input format error.
176 void print_err_dup_legacy_input(void)
178 printf_err("More than one legacy input format specified\n");
182 * Checks if any of the "text" legacy options is set.
185 bool text_legacy_opts_is_any_set(struct text_legacy_opts
*opts
)
187 return (opts
->output
&& opts
->output
->len
> 0) ||
188 (opts
->dbg_info_dir
&& opts
->dbg_info_dir
->len
> 0) ||
189 (opts
->dbg_info_target_prefix
&&
190 opts
->dbg_info_target_prefix
->len
> 0) ||
191 bt_value_array_size(opts
->names
) > 0 ||
192 bt_value_array_size(opts
->fields
) > 0 ||
193 opts
->no_delta
|| opts
->clock_cycles
|| opts
->clock_seconds
||
194 opts
->clock_date
|| opts
->clock_gmt
||
195 opts
->dbg_info_full_path
;
199 * Checks if any of the "ctf" legacy options is set.
202 bool ctf_legacy_opts_is_any_set(struct ctf_legacy_opts
*opts
)
204 return opts
->offset_s
.is_set
|| opts
->offset_ns
.is_set
||
205 opts
->stream_intersection
;
209 * Appends an "expecting token" error to the INI-style parsing state's
213 void ini_append_error_expecting(struct ini_parsing_state
*state
,
214 GScanner
*scanner
, const char *expecting
)
219 g_string_append_printf(state
->ini_error
, "Expecting %s:\n", expecting
);
221 /* Only print error if there's one line */
222 if (strchr(state
->arg
, '\n') != NULL
|| strlen(state
->arg
) == 0) {
226 g_string_append_printf(state
->ini_error
, "\n %s\n", state
->arg
);
227 pos
= g_scanner_cur_position(scanner
) + 4;
229 if (!g_scanner_eof(scanner
)) {
233 for (i
= 0; i
< pos
; ++i
) {
234 g_string_append_printf(state
->ini_error
, " ");
237 g_string_append_printf(state
->ini_error
, "^\n\n");
241 int ini_handle_state(struct ini_parsing_state
*state
)
244 GTokenType token_type
;
245 struct bt_value
*value
= NULL
;
247 token_type
= g_scanner_get_next_token(state
->scanner
);
248 if (token_type
== G_TOKEN_EOF
) {
249 if (state
->expecting
!= INI_EXPECT_COMMA
) {
250 switch (state
->expecting
) {
251 case INI_EXPECT_EQUAL
:
252 ini_append_error_expecting(state
,
253 state
->scanner
, "'='");
255 case INI_EXPECT_VALUE
:
256 case INI_EXPECT_VALUE_NUMBER_NEG
:
257 ini_append_error_expecting(state
,
258 state
->scanner
, "value");
260 case INI_EXPECT_MAP_KEY
:
261 ini_append_error_expecting(state
,
262 state
->scanner
, "unquoted map key");
275 switch (state
->expecting
) {
276 case INI_EXPECT_MAP_KEY
:
277 if (token_type
!= G_TOKEN_IDENTIFIER
) {
278 ini_append_error_expecting(state
, state
->scanner
,
283 free(state
->last_map_key
);
284 state
->last_map_key
=
285 strdup(state
->scanner
->value
.v_identifier
);
286 if (!state
->last_map_key
) {
287 g_string_append(state
->ini_error
,
292 if (bt_value_map_has_key(state
->params
, state
->last_map_key
)) {
293 g_string_append_printf(state
->ini_error
,
294 "Duplicate parameter key: `%s`\n",
295 state
->last_map_key
);
299 state
->expecting
= INI_EXPECT_EQUAL
;
301 case INI_EXPECT_EQUAL
:
302 if (token_type
!= G_TOKEN_CHAR
) {
303 ini_append_error_expecting(state
,
304 state
->scanner
, "'='");
308 if (state
->scanner
->value
.v_char
!= '=') {
309 ini_append_error_expecting(state
,
310 state
->scanner
, "'='");
314 state
->expecting
= INI_EXPECT_VALUE
;
316 case INI_EXPECT_VALUE
:
318 switch (token_type
) {
320 if (state
->scanner
->value
.v_char
== '-') {
321 /* Negative number */
323 INI_EXPECT_VALUE_NUMBER_NEG
;
326 ini_append_error_expecting(state
,
327 state
->scanner
, "value");
333 /* Positive integer */
334 uint64_t int_val
= state
->scanner
->value
.v_int64
;
336 if (int_val
> (1ULL << 63) - 1) {
337 g_string_append_printf(state
->ini_error
,
338 "Integer value %" PRIu64
" is outside the range of a 64-bit signed integer\n",
343 value
= bt_value_integer_create_init(
348 /* Positive floating point number */
349 value
= bt_value_float_create_init(
350 state
->scanner
->value
.v_float
);
354 value
= bt_value_string_create_init(
355 state
->scanner
->value
.v_string
);
357 case G_TOKEN_IDENTIFIER
:
360 * Using symbols would be appropriate here,
361 * but said symbols are allowed as map key,
362 * so it's easier to consider everything an
365 * If one of the known symbols is not
366 * recognized here, then fall back to creating
369 const char *id
= state
->scanner
->value
.v_identifier
;
371 if (!strcmp(id
, "null") || !strcmp(id
, "NULL") ||
372 !strcmp(id
, "nul")) {
373 value
= bt_value_null
;
374 } else if (!strcmp(id
, "true") || !strcmp(id
, "TRUE") ||
375 !strcmp(id
, "yes") ||
376 !strcmp(id
, "YES")) {
377 value
= bt_value_bool_create_init(true);
378 } else if (!strcmp(id
, "false") ||
379 !strcmp(id
, "FALSE") ||
382 value
= bt_value_bool_create_init(false);
384 value
= bt_value_string_create_init(id
);
389 /* Unset value variable will trigger the error */
394 ini_append_error_expecting(state
,
395 state
->scanner
, "value");
399 state
->expecting
= INI_EXPECT_COMMA
;
402 case INI_EXPECT_VALUE_NUMBER_NEG
:
404 switch (token_type
) {
407 /* Negative integer */
408 uint64_t int_val
= state
->scanner
->value
.v_int64
;
410 if (int_val
> (1ULL << 63) - 1) {
411 g_string_append_printf(state
->ini_error
,
412 "Integer value -%" PRIu64
" is outside the range of a 64-bit signed integer\n",
417 value
= bt_value_integer_create_init(
418 -((int64_t) int_val
));
422 /* Negative floating point number */
423 value
= bt_value_float_create_init(
424 -state
->scanner
->value
.v_float
);
427 /* Unset value variable will trigger the error */
432 ini_append_error_expecting(state
,
433 state
->scanner
, "value");
437 state
->expecting
= INI_EXPECT_COMMA
;
440 case INI_EXPECT_COMMA
:
441 if (token_type
!= G_TOKEN_CHAR
) {
442 ini_append_error_expecting(state
,
443 state
->scanner
, "','");
447 if (state
->scanner
->value
.v_char
!= ',') {
448 ini_append_error_expecting(state
,
449 state
->scanner
, "','");
453 state
->expecting
= INI_EXPECT_MAP_KEY
;
465 if (bt_value_map_insert(state
->params
,
466 state
->last_map_key
, value
)) {
467 /* Only override return value on error */
478 * Converts an INI-style argument to an equivalent map value object.
480 * Return value is owned by the caller.
483 struct bt_value
*bt_value_from_ini(const char *arg
, GString
*ini_error
)
485 /* Lexical scanner configuration */
486 GScannerConfig scanner_config
= {
487 /* Skip whitespaces */
488 .cset_skip_characters
= " \t\n",
490 /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
491 .cset_identifier_first
=
495 .cset_identifier_nth
=
500 /* "hello" and "Hello" two different keys */
501 .case_sensitive
= TRUE
,
504 .cpair_comment_single
= NULL
,
505 .skip_comment_multi
= TRUE
,
506 .skip_comment_single
= TRUE
,
507 .scan_comment_multi
= FALSE
,
510 * Do scan identifiers, including 1-char identifiers,
511 * but NULL is a normal identifier.
513 .scan_identifier
= TRUE
,
514 .scan_identifier_1char
= TRUE
,
515 .scan_identifier_NULL
= FALSE
,
518 * No specific symbols: null and boolean "symbols" are
519 * scanned as plain identifiers.
521 .scan_symbols
= FALSE
,
522 .symbol_2_token
= FALSE
,
523 .scope_0_fallback
= FALSE
,
526 * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
527 * integers prefixed with "$".
533 .scan_hex_dollar
= FALSE
,
535 /* Convert scanned numbers to integer tokens */
536 .numbers_2_int
= TRUE
,
538 /* Support both integers and floating-point numbers */
539 .int_2_float
= FALSE
,
541 /* Scan integers as 64-bit signed integers */
544 /* Only scan double-quoted strings */
545 .scan_string_sq
= FALSE
,
546 .scan_string_dq
= TRUE
,
548 /* Do not converter identifiers to string tokens */
549 .identifier_2_string
= FALSE
,
551 /* Scan characters as G_TOKEN_CHAR token */
552 .char_2_token
= FALSE
,
554 struct ini_parsing_state state
= {
557 .expecting
= INI_EXPECT_MAP_KEY
,
559 .ini_error
= ini_error
,
562 state
.params
= bt_value_map_create();
567 state
.scanner
= g_scanner_new(&scanner_config
);
568 if (!state
.scanner
) {
572 /* Let the scan begin */
573 g_scanner_input_text(state
.scanner
, arg
, strlen(arg
));
576 int ret
= ini_handle_state(&state
);
581 } else if (ret
> 0) {
590 BT_PUT(state
.params
);
594 g_scanner_destroy(state
.scanner
);
597 free(state
.last_map_key
);
602 * Returns the parameters map value object from a command-line
603 * parameter option's argument.
605 * Return value is owned by the caller.
608 struct bt_value
*bt_value_from_arg(const char *arg
)
610 struct bt_value
*params
= NULL
;
611 GString
*ini_error
= NULL
;
613 ini_error
= g_string_new(NULL
);
619 /* Try INI-style parsing */
620 params
= bt_value_from_ini(arg
, ini_error
);
622 printf_err("%s", ini_error
->str
);
628 g_string_free(ini_error
, TRUE
);
634 * Returns the plugin and component names from a command-line
635 * source/sink option's argument. arg must have the following format:
639 * where PLUGIN is the plugin name, and COMPONENT is the component
642 * On success, both *plugin and *component are not NULL. *plugin
643 * and *component are owned by the caller.
646 void plugin_component_names_from_arg(const char *arg
, char **plugin
,
652 size_t component_len
;
654 /* Initialize both return values to NULL: not found */
658 dot
= strchr(arg
, '.');
664 end
= arg
+ strlen(arg
);
665 plugin_len
= dot
- arg
;
666 component_len
= end
- dot
- 1;
667 if (plugin_len
== 0 || component_len
== 0) {
671 *plugin
= g_malloc0(plugin_len
+ 1);
677 g_strlcpy(*plugin
, arg
, plugin_len
+ 1);
678 *component
= g_malloc0(component_len
+ 1);
684 g_strlcpy(*component
, dot
+ 1, component_len
+ 1);
691 * Prints the Babeltrace version.
694 void print_version(void)
696 puts("Babeltrace " VERSION
);
700 * Prints the legacy, Babeltrace 1.x command usage. Those options are
701 * still compatible in Babeltrace 2.x, but it is recommended to use
702 * the more generic plugin/component parameters instead of those
703 * hard-coded option names.
706 void print_legacy_usage(FILE *fp
)
708 fprintf(fp
, "Usage: babeltrace [OPTIONS] INPUT...\n");
710 fprintf(fp
, "The following options are compatible with the Babeltrace 1.x options:\n");
712 fprintf(fp
, " --help-legacy Show this help\n");
713 fprintf(fp
, " -V, --version Show version\n");
714 fprintf(fp
, " --clock-force-correlate Assume that clocks are inherently correlated\n");
715 fprintf(fp
, " across traces\n");
716 fprintf(fp
, " -d, --debug Enable debug mode\n");
717 fprintf(fp
, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
718 fprintf(fp
, " -l, --list List available formats\n");
719 fprintf(fp
, " -o, --output-format=FORMAT Output trace format (default: text)\n");
720 fprintf(fp
, " -v, --verbose Enable verbose output\n");
722 fprintf(fp
, " Available input formats: ctf, lttng-live, ctf-metadata\n");
723 fprintf(fp
, " Available output formats: text, dummy\n");
725 fprintf(fp
, "Input formats specific options:\n");
727 fprintf(fp
, " INPUT... Input trace file(s), directory(ies), or URLs\n");
728 fprintf(fp
, " --clock-offset=SEC Set clock offset to SEC seconds\n");
729 fprintf(fp
, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
730 fprintf(fp
, " --stream-intersection Only process events when all streams are active\n");
732 fprintf(fp
, "text output format specific options:\n");
734 fprintf(fp
, " --clock-cycles Print timestamps in clock cycles\n");
735 fprintf(fp
, " --clock-date Print timestamp dates\n");
736 fprintf(fp
, " --clock-gmt Print and parse timestamps in GMT time zone\n");
737 fprintf(fp
, " (default: local time zone)\n");
738 fprintf(fp
, " --clock-seconds Print the timestamps as [SEC.NS]\n");
739 fprintf(fp
, " (default format: [HH:MM:SS.NS])\n");
740 fprintf(fp
, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
741 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
742 fprintf(fp
, " --debug-info-full-path Show full debug info source and binary paths\n");
743 fprintf(fp
, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
744 fprintf(fp
, " up executables during debug info analysis\n");
745 fprintf(fp
, " (default: `/usr/lib/debug`)\n");
746 fprintf(fp
, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
747 fprintf(fp
, " all, trace, trace:hostname, trace:domain,\n");
748 fprintf(fp
, " trace:procname, trace:vpid, loglevel, emf\n");
749 fprintf(fp
, " (default: trace:hostname, trace:procname,\n");
750 fprintf(fp
, " trace:vpid)\n");
751 fprintf(fp
, " -n, --names=NAME[,NAME]... Print field names:\n");
752 fprintf(fp
, " payload (or arg or args)\n");
753 fprintf(fp
, " none, all, scope, header, context (or ctx)\n");
754 fprintf(fp
, " (default: payload, context)\n");
755 fprintf(fp
, " --no-delta Do not print time delta between consecutive\n");
756 fprintf(fp
, " events\n");
757 fprintf(fp
, " -w, --output=PATH Write output to PATH (default: standard output)\n");
761 * Prints the Babeltrace 2.x usage.
764 void print_usage(FILE *fp
)
766 fprintf(fp
, "Usage: babeltrace [OPTIONS]\n");
768 fprintf(fp
, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
769 fprintf(fp
, " of the following source and sink component\n");
770 fprintf(fp
, " instances (see the exact format of PARAMS\n");
771 fprintf(fp
, " below)\n");
772 fprintf(fp
, " -d, --debug Enable debug mode\n");
773 fprintf(fp
, " -l, --list List available plugins and their components\n");
774 fprintf(fp
, " -P, --path=PATH Set the `path` parameter of the latest source\n");
775 fprintf(fp
, " or sink component to PATH\n");
776 fprintf(fp
, " -p, --params=PARAMS Set the parameters of the latest source or\n");
777 fprintf(fp
, " sink component instance (in command-line \n");
778 fprintf(fp
, " order) to PARAMS (see the exact format of\n");
779 fprintf(fp
, " PARAMS below)\n");
780 fprintf(fp
, " --plugin-path=PATH[:PATH]... Set paths from which dynamic plugins can be\n");
781 fprintf(fp
, " loaded to PATH\n");
782 fprintf(fp
, " -r, --reset-base-params Reset the current base parameters of the\n");
783 fprintf(fp
, " following source and sink component\n");
784 fprintf(fp
, " instances to an empty map\n");
785 fprintf(fp
, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
786 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
787 fprintf(fp
, " repeated)\n");
788 fprintf(fp
, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
789 fprintf(fp
, " PLUGIN and component class COMPCLS (may be\n");
790 fprintf(fp
, " repeated)\n");
791 fprintf(fp
, " --begin Start time: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
792 fprintf(fp
, " --end End time: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
793 fprintf(fp
, " --timerange Time range: begin,end or [begin,end] (where [] are actual brackets)\n");
794 fprintf(fp
, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
795 fprintf(fp
, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
796 fprintf(fp
, " -h --help Show this help\n");
797 fprintf(fp
, " --help-legacy Show Babeltrace 1.x legacy options\n");
798 fprintf(fp
, " -v, --verbose Enable verbose output\n");
799 fprintf(fp
, " -V, --version Show version\n");
801 fprintf(fp
, "Format of PARAMS\n");
802 fprintf(fp
, "----------------\n");
804 fprintf(fp
, " PARAM=VALUE[,PARAM=VALUE]...\n");
806 fprintf(fp
, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
807 fprintf(fp
, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
808 fprintf(fp
, "VALUE can be one of:\n");
810 fprintf(fp
, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
811 fprintf(fp
, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
812 fprintf(fp
, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
813 fprintf(fp
, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
814 fprintf(fp
, " (`0x` prefix) signed 64-bit integer.\n");
815 fprintf(fp
, "* Double precision floating point number (scientific notation is accepted).\n");
816 fprintf(fp
, "* Unquoted string with no special characters, and not matching any of\n");
817 fprintf(fp
, " the null and boolean value symbols above.\n");
818 fprintf(fp
, "* Double-quoted string (accepts escape characters).\n");
820 fprintf(fp
, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
822 fprintf(fp
, "Example:\n");
824 fprintf(fp
, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
825 fprintf(fp
, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
826 fprintf(fp
, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
828 fprintf(fp
, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
829 fprintf(fp
, "from a shell.\n");
833 * Destroys a component configuration.
836 void bt_config_component_destroy(struct bt_object
*obj
)
838 struct bt_config_component
*bt_config_component
=
839 container_of(obj
, struct bt_config_component
, base
);
845 if (bt_config_component
->plugin_name
) {
846 g_string_free(bt_config_component
->plugin_name
, TRUE
);
849 if (bt_config_component
->component_name
) {
850 g_string_free(bt_config_component
->component_name
, TRUE
);
853 BT_PUT(bt_config_component
->params
);
854 g_free(bt_config_component
);
861 * Creates a component configuration using the given plugin name and
862 * component name. plugin_name and component_name are copied (belong to
865 * Return value is owned by the caller.
868 struct bt_config_component
*bt_config_component_create(const char *plugin_name
,
869 const char *component_name
)
871 struct bt_config_component
*cfg_component
= NULL
;
873 cfg_component
= g_new0(struct bt_config_component
, 1);
874 if (!cfg_component
) {
879 bt_object_init(cfg_component
, bt_config_component_destroy
);
880 cfg_component
->plugin_name
= g_string_new(plugin_name
);
881 if (!cfg_component
->plugin_name
) {
886 cfg_component
->component_name
= g_string_new(component_name
);
887 if (!cfg_component
->component_name
) {
892 /* Start with empty parameters */
893 cfg_component
->params
= bt_value_map_create();
894 if (!cfg_component
->params
) {
902 BT_PUT(cfg_component
);
905 return cfg_component
;
909 * Creates a component configuration from a command-line source/sink
913 struct bt_config_component
*bt_config_component_from_arg(const char *arg
)
915 struct bt_config_component
*bt_config_component
= NULL
;
917 char *component_name
;
919 plugin_component_names_from_arg(arg
, &plugin_name
, &component_name
);
920 if (!plugin_name
|| !component_name
) {
921 printf_err("Cannot get plugin or component class name\n");
925 bt_config_component
= bt_config_component_create(plugin_name
,
927 if (!bt_config_component
) {
934 BT_PUT(bt_config_component
);
938 g_free(component_name
);
939 return bt_config_component
;
943 * Destroys a configuration.
946 void bt_config_destroy(struct bt_object
*obj
)
948 struct bt_config
*bt_config
=
949 container_of(obj
, struct bt_config
, base
);
955 if (bt_config
->sources
) {
956 g_ptr_array_free(bt_config
->sources
, TRUE
);
959 if (bt_config
->sinks
) {
960 g_ptr_array_free(bt_config
->sinks
, TRUE
);
963 BT_PUT(bt_config
->plugin_paths
);
971 bool is_setuid_setgid(void)
973 return (geteuid() != getuid() || getegid() != getgid());
977 * Extracts the various paths from the string arg, delimited by ':',
978 * and converts them to an array value object.
980 * Returned array value object is empty if arg is empty.
982 * Return value is owned by the caller.
985 enum bt_value_status
plugin_paths_from_arg(struct bt_value
*plugin_paths
,
988 const char *at
= arg
;
989 const char *end
= arg
+ strlen(arg
);
994 const char *next_colon
;
996 next_colon
= strchr(at
, ':');
997 if (next_colon
== at
) {
999 * Empty path: try next character (supported
1000 * to conform to the typical parsing of $PATH).
1004 } else if (!next_colon
) {
1005 /* No more colon: use the remaining */
1006 next_colon
= arg
+ strlen(arg
);
1009 path
= g_string_new(NULL
);
1015 g_string_append_len(path
, at
, next_colon
- at
);
1016 at
= next_colon
+ 1;
1017 ret
= bt_value_array_append_string(plugin_paths
, path
->str
);
1018 g_string_free(path
, TRUE
);
1025 return BT_VALUE_STATUS_OK
;
1027 return BT_VALUE_STATUS_ERROR
;
1031 * Creates a simple lexical scanner for parsing comma-delimited names
1034 * Return value is owned by the caller.
1037 GScanner
*create_csv_identifiers_scanner(void)
1039 GScannerConfig scanner_config
= {
1040 .cset_skip_characters
= " \t\n",
1041 .cset_identifier_first
= G_CSET_a_2_z G_CSET_A_2_Z
"_",
1042 .cset_identifier_nth
= G_CSET_a_2_z G_CSET_A_2_Z
":_-",
1043 .case_sensitive
= TRUE
,
1044 .cpair_comment_single
= NULL
,
1045 .skip_comment_multi
= TRUE
,
1046 .skip_comment_single
= TRUE
,
1047 .scan_comment_multi
= FALSE
,
1048 .scan_identifier
= TRUE
,
1049 .scan_identifier_1char
= TRUE
,
1050 .scan_identifier_NULL
= FALSE
,
1051 .scan_symbols
= FALSE
,
1052 .symbol_2_token
= FALSE
,
1053 .scope_0_fallback
= FALSE
,
1054 .scan_binary
= FALSE
,
1055 .scan_octal
= FALSE
,
1056 .scan_float
= FALSE
,
1058 .scan_hex_dollar
= FALSE
,
1059 .numbers_2_int
= FALSE
,
1060 .int_2_float
= FALSE
,
1061 .store_int64
= FALSE
,
1062 .scan_string_sq
= FALSE
,
1063 .scan_string_dq
= FALSE
,
1064 .identifier_2_string
= FALSE
,
1065 .char_2_token
= TRUE
,
1068 return g_scanner_new(&scanner_config
);
1072 * Inserts a string (if exists and not empty) or null to a map value
1076 enum bt_value_status
map_insert_string_or_null(struct bt_value
*map
,
1077 const char *key
, GString
*string
)
1079 enum bt_value_status ret
;
1081 if (string
&& string
->len
> 0) {
1082 ret
= bt_value_map_insert_string(map
, key
, string
->str
);
1084 ret
= bt_value_map_insert(map
, key
, bt_value_null
);
1090 * Converts a comma-delimited list of known names (--names option) to
1091 * an array value object containing those names as string value objects.
1093 * Return value is owned by the caller.
1096 struct bt_value
*names_from_arg(const char *arg
)
1098 GScanner
*scanner
= NULL
;
1099 struct bt_value
*names
= NULL
;
1100 bool found_all
= false, found_none
= false, found_item
= false;
1102 names
= bt_value_array_create();
1108 scanner
= create_csv_identifiers_scanner();
1114 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1117 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1119 switch (token_type
) {
1120 case G_TOKEN_IDENTIFIER
:
1122 const char *identifier
= scanner
->value
.v_identifier
;
1124 if (!strcmp(identifier
, "payload") ||
1125 !strcmp(identifier
, "args") ||
1126 !strcmp(identifier
, "arg")) {
1128 if (bt_value_array_append_string(names
,
1132 } else if (!strcmp(identifier
, "context") ||
1133 !strcmp(identifier
, "ctx")) {
1135 if (bt_value_array_append_string(names
,
1139 } else if (!strcmp(identifier
, "scope") ||
1140 !strcmp(identifier
, "header")) {
1142 if (bt_value_array_append_string(names
,
1146 } else if (!strcmp(identifier
, "all")) {
1148 if (bt_value_array_append_string(names
,
1152 } else if (!strcmp(identifier
, "none")) {
1154 if (bt_value_array_append_string(names
,
1159 printf_err("Unknown field name: `%s`\n",
1175 if (found_none
&& found_all
) {
1176 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
1180 * Legacy behavior is to clear the defaults (show none) when at
1181 * least one item is specified.
1183 if (found_item
&& !found_none
&& !found_all
) {
1184 if (bt_value_array_append_string(names
, "none")) {
1189 g_scanner_destroy(scanner
);
1196 g_scanner_destroy(scanner
);
1203 * Converts a comma-delimited list of known fields (--fields option) to
1204 * an array value object containing those fields as string
1207 * Return value is owned by the caller.
1210 struct bt_value
*fields_from_arg(const char *arg
)
1212 GScanner
*scanner
= NULL
;
1213 struct bt_value
*fields
;
1215 fields
= bt_value_array_create();
1221 scanner
= create_csv_identifiers_scanner();
1227 g_scanner_input_text(scanner
, arg
, strlen(arg
));
1230 GTokenType token_type
= g_scanner_get_next_token(scanner
);
1232 switch (token_type
) {
1233 case G_TOKEN_IDENTIFIER
:
1235 const char *identifier
= scanner
->value
.v_identifier
;
1237 if (!strcmp(identifier
, "trace") ||
1238 !strcmp(identifier
, "trace:hostname") ||
1239 !strcmp(identifier
, "trace:domain") ||
1240 !strcmp(identifier
, "trace:procname") ||
1241 !strcmp(identifier
, "trace:vpid") ||
1242 !strcmp(identifier
, "loglevel") ||
1243 !strcmp(identifier
, "emf") ||
1244 !strcmp(identifier
, "callsite") ||
1245 !strcmp(identifier
, "all")) {
1246 if (bt_value_array_append_string(fields
,
1251 printf_err("Unknown field name: `%s`\n",
1273 g_scanner_destroy(scanner
);
1279 * Inserts the equivalent "prefix-name" true boolean value objects into
1280 * map_obj where the names are in array_obj.
1283 int insert_flat_names_fields_from_array(struct bt_value
*map_obj
,
1284 struct bt_value
*array_obj
, const char *prefix
)
1288 GString
*tmpstr
= NULL
, *default_value
= NULL
;
1291 * array_obj may be NULL if no CLI options were specified to
1292 * trigger its creation.
1298 tmpstr
= g_string_new(NULL
);
1305 default_value
= g_string_new(NULL
);
1306 if (!default_value
) {
1312 for (i
= 0; i
< bt_value_array_size(array_obj
); i
++) {
1313 struct bt_value
*str_obj
= bt_value_array_get(array_obj
, i
);
1315 bool is_default
= false;
1318 printf_err("Unexpected error\n");
1323 ret
= bt_value_string_get(str_obj
, &suffix
);
1326 printf_err("Unexpected error\n");
1330 g_string_assign(tmpstr
, prefix
);
1331 g_string_append(tmpstr
, "-");
1333 /* Special-case for "all" and "none". */
1334 if (!strcmp(suffix
, "all")) {
1336 g_string_assign(default_value
, "show");
1337 } else if (!strcmp(suffix
, "none")) {
1339 g_string_assign(default_value
, "hide");
1342 g_string_append(tmpstr
, "default");
1343 ret
= map_insert_string_or_null(map_obj
,
1351 g_string_append(tmpstr
, suffix
);
1352 ret
= bt_value_map_insert_bool(map_obj
, tmpstr
->str
,
1362 if (default_value
) {
1363 g_string_free(default_value
, TRUE
);
1366 g_string_free(tmpstr
, TRUE
);
1373 * Returns the parameters (map value object) corresponding to the
1374 * legacy text format options.
1376 * Return value is owned by the caller.
1379 struct bt_value
*params_from_text_legacy_opts(
1380 struct text_legacy_opts
*text_legacy_opts
)
1382 struct bt_value
*params
;
1384 params
= bt_value_map_create();
1390 if (map_insert_string_or_null(params
, "output-path",
1391 text_legacy_opts
->output
)) {
1396 if (map_insert_string_or_null(params
, "debug-info-dir",
1397 text_legacy_opts
->dbg_info_dir
)) {
1402 if (map_insert_string_or_null(params
, "debug-info-target-prefix",
1403 text_legacy_opts
->dbg_info_target_prefix
)) {
1408 if (bt_value_map_insert_bool(params
, "debug-info-full-path",
1409 text_legacy_opts
->dbg_info_full_path
)) {
1414 if (bt_value_map_insert_bool(params
, "no-delta",
1415 text_legacy_opts
->no_delta
)) {
1420 if (bt_value_map_insert_bool(params
, "clock-cycles",
1421 text_legacy_opts
->clock_cycles
)) {
1426 if (bt_value_map_insert_bool(params
, "clock-seconds",
1427 text_legacy_opts
->clock_seconds
)) {
1432 if (bt_value_map_insert_bool(params
, "clock-date",
1433 text_legacy_opts
->clock_date
)) {
1438 if (bt_value_map_insert_bool(params
, "clock-gmt",
1439 text_legacy_opts
->clock_gmt
)) {
1444 if (insert_flat_names_fields_from_array(params
,
1445 text_legacy_opts
->names
, "name")) {
1449 if (insert_flat_names_fields_from_array(params
,
1450 text_legacy_opts
->fields
, "field")) {
1464 int append_sinks_from_legacy_opts(GPtrArray
*sinks
,
1465 enum legacy_output_format legacy_output_format
,
1466 struct text_legacy_opts
*text_legacy_opts
)
1469 struct bt_value
*params
= NULL
;
1470 const char *plugin_name
;
1471 const char *component_name
;
1472 struct bt_config_component
*bt_config_component
= NULL
;
1474 switch (legacy_output_format
) {
1475 case LEGACY_OUTPUT_FORMAT_TEXT
:
1476 plugin_name
= "text";
1477 component_name
= "text";
1479 case LEGACY_OUTPUT_FORMAT_CTF_METADATA
:
1480 plugin_name
= "ctf";
1481 component_name
= "metadata-text";
1483 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1484 plugin_name
= "dummy";
1485 component_name
= "dummy";
1492 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
) {
1493 /* Legacy "text" output format has parameters */
1494 params
= params_from_text_legacy_opts(text_legacy_opts
);
1500 * Legacy "dummy" and "ctf-metadata" output formats do
1501 * not have parameters.
1503 params
= bt_value_map_create();
1510 /* Create a component configuration */
1511 bt_config_component
= bt_config_component_create(plugin_name
,
1513 if (!bt_config_component
) {
1517 BT_MOVE(bt_config_component
->params
, params
);
1519 /* Move created component configuration to the array */
1520 g_ptr_array_add(sinks
, bt_config_component
);
1534 * Returns the parameters (map value object) corresponding to the
1535 * given legacy CTF format options.
1537 * Return value is owned by the caller.
1540 struct bt_value
*params_from_ctf_legacy_opts(
1541 struct ctf_legacy_opts
*ctf_legacy_opts
)
1543 struct bt_value
*params
;
1545 params
= bt_value_map_create();
1551 if (bt_value_map_insert_integer(params
, "offset-s",
1552 ctf_legacy_opts
->offset_s
.value
)) {
1557 if (bt_value_map_insert_integer(params
, "offset-ns",
1558 ctf_legacy_opts
->offset_ns
.value
)) {
1563 if (bt_value_map_insert_bool(params
, "stream-intersection",
1564 ctf_legacy_opts
->stream_intersection
)) {
1579 int append_sources_from_legacy_opts(GPtrArray
*sources
,
1580 enum legacy_input_format legacy_input_format
,
1581 struct ctf_legacy_opts
*ctf_legacy_opts
,
1582 struct bt_value
*legacy_input_paths
)
1586 struct bt_value
*base_params
;
1587 struct bt_value
*params
= NULL
;
1588 struct bt_value
*input_path
= NULL
;
1589 struct bt_value
*input_path_copy
= NULL
;
1590 const char *input_key
;
1591 const char *component_name
;
1593 switch (legacy_input_format
) {
1594 case LEGACY_INPUT_FORMAT_CTF
:
1596 component_name
= "fs";
1598 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1600 component_name
= "lttng-live";
1607 base_params
= params_from_ctf_legacy_opts(ctf_legacy_opts
);
1612 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1613 struct bt_config_component
*bt_config_component
= NULL
;
1615 /* Copy base parameters as current parameters */
1616 params
= bt_value_copy(base_params
);
1621 /* Get current input path string value object */
1622 input_path
= bt_value_array_get(legacy_input_paths
, i
);
1627 /* Copy current input path value object */
1628 input_path_copy
= bt_value_copy(input_path
);
1629 if (!input_path_copy
) {
1633 /* Insert input path value object into current parameters */
1634 ret
= bt_value_map_insert(params
, input_key
, input_path_copy
);
1639 /* Create a component configuration */
1640 bt_config_component
= bt_config_component_create("ctf",
1642 if (!bt_config_component
) {
1646 BT_MOVE(bt_config_component
->params
, params
);
1648 /* Move created component configuration to the array */
1649 g_ptr_array_add(sources
, bt_config_component
);
1651 /* Put current stuff */
1653 BT_PUT(input_path_copy
);
1662 BT_PUT(base_params
);
1665 BT_PUT(input_path_copy
);
1670 * Escapes a string for the shell. The string is escaped knowing that
1671 * it's a parameter string value (double-quoted), and that it will be
1672 * entered between single quotes in the shell.
1674 * Return value is owned by the caller.
1677 char *str_shell_escape(const char *input
)
1680 const char *at
= input
;
1681 GString
*str
= g_string_new(NULL
);
1687 while (*at
!= '\0') {
1690 g_string_append(str
, "\\\\");
1693 g_string_append(str
, "\\\"");
1696 g_string_append(str
, "'\"'\"'");
1699 g_string_append(str
, "\\n");
1702 g_string_append(str
, "\\t");
1705 g_string_append_c(str
, *at
);
1715 g_string_free(str
, FALSE
);
1722 int append_prefixed_flag_params(GString
*str
, struct bt_value
*flags
,
1732 for (i
= 0; i
< bt_value_array_size(flags
); i
++) {
1733 struct bt_value
*value
= bt_value_array_get(flags
, i
);
1741 if (bt_value_string_get(value
, &flag
)) {
1747 g_string_append_printf(str
, ",%s-%s=true", prefix
, flag
);
1756 * Appends a boolean parameter string.
1759 void g_string_append_bool_param(GString
*str
, const char *name
, bool value
)
1761 g_string_append_printf(str
, ",%s=%s", name
, value
? "true" : "false");
1765 * Appends a path parameter string, or null if it's empty.
1768 int g_string_append_string_path_param(GString
*str
, const char *name
,
1773 if (path
->len
> 0) {
1774 char *escaped_path
= str_shell_escape(path
->str
);
1776 if (!escaped_path
) {
1781 g_string_append_printf(str
, "%s=\"%s\"", name
, escaped_path
);
1784 g_string_append_printf(str
, "%s=null", name
);
1797 * Prints the non-legacy sink options equivalent to the specified
1798 * legacy output format options.
1801 void print_output_legacy_to_sinks(
1802 enum legacy_output_format legacy_output_format
,
1803 struct text_legacy_opts
*text_legacy_opts
)
1805 const char *input_format
;
1806 GString
*str
= NULL
;
1808 str
= g_string_new(" ");
1814 switch (legacy_output_format
) {
1815 case LEGACY_OUTPUT_FORMAT_TEXT
:
1816 input_format
= "text";
1818 case LEGACY_OUTPUT_FORMAT_CTF_METADATA
:
1819 input_format
= "ctf-metadata";
1821 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1822 input_format
= "dummy";
1828 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
1830 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
1832 g_string_append(str
, "-o ");
1834 switch (legacy_output_format
) {
1835 case LEGACY_OUTPUT_FORMAT_TEXT
:
1836 g_string_append(str
, "text.text");
1838 case LEGACY_OUTPUT_FORMAT_CTF_METADATA
:
1839 g_string_append(str
, "ctf.metadata-text");
1841 case LEGACY_OUTPUT_FORMAT_DUMMY
:
1842 g_string_append(str
, "dummy.dummy");
1848 if (legacy_output_format
== LEGACY_OUTPUT_FORMAT_TEXT
&&
1849 text_legacy_opts_is_any_set(text_legacy_opts
)) {
1852 g_string_append(str
, " -p '");
1854 if (g_string_append_string_path_param(str
, "output-path",
1855 text_legacy_opts
->output
)) {
1859 g_string_append(str
, ",");
1861 if (g_string_append_string_path_param(str
, "debug-info-dir",
1862 text_legacy_opts
->dbg_info_dir
)) {
1866 g_string_append(str
, ",");
1868 if (g_string_append_string_path_param(str
,
1869 "debug-info-target-prefix",
1870 text_legacy_opts
->dbg_info_target_prefix
)) {
1874 g_string_append_bool_param(str
, "no-delta",
1875 text_legacy_opts
->no_delta
);
1876 g_string_append_bool_param(str
, "clock-cycles",
1877 text_legacy_opts
->clock_cycles
);
1878 g_string_append_bool_param(str
, "clock-seconds",
1879 text_legacy_opts
->clock_seconds
);
1880 g_string_append_bool_param(str
, "clock-date",
1881 text_legacy_opts
->clock_date
);
1882 g_string_append_bool_param(str
, "clock-gmt",
1883 text_legacy_opts
->clock_gmt
);
1884 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->names
,
1890 ret
= append_prefixed_flag_params(str
, text_legacy_opts
->fields
,
1896 /* Remove last comma and close single quote */
1897 g_string_append(str
, "'");
1900 printf_err("%s\n\n", str
->str
);
1904 g_string_free(str
, TRUE
);
1910 * Prints the non-legacy source options equivalent to the specified
1911 * legacy input format options.
1914 void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format
,
1915 struct bt_value
*legacy_input_paths
,
1916 struct ctf_legacy_opts
*ctf_legacy_opts
)
1918 const char *input_format
;
1919 GString
*str
= NULL
;
1922 str
= g_string_new(" ");
1928 switch (legacy_input_format
) {
1929 case LEGACY_INPUT_FORMAT_CTF
:
1930 input_format
= "ctf";
1932 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1933 input_format
= "lttng-live";
1939 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
1941 printf_err("Specify the following non-legacy source component instance(s) instead of the\nlegacy `%s` input format options and positional arguments:\n\n",
1944 for (i
= 0; i
< bt_value_array_size(legacy_input_paths
); i
++) {
1945 struct bt_value
*input_value
=
1946 bt_value_array_get(legacy_input_paths
, i
);
1947 const char *input
= NULL
;
1948 char *escaped_input
;
1951 assert(input_value
);
1952 ret
= bt_value_string_get(input_value
, &input
);
1953 BT_PUT(input_value
);
1954 assert(!ret
&& input
);
1955 escaped_input
= str_shell_escape(input
);
1956 if (!escaped_input
) {
1961 g_string_append(str
, "-i ctf.");
1963 switch (legacy_input_format
) {
1964 case LEGACY_INPUT_FORMAT_CTF
:
1965 g_string_append(str
, "fs -p 'path=\"");
1967 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
1968 g_string_append(str
, "lttng-live -p 'url=\"");
1974 g_string_append(str
, escaped_input
);
1975 g_string_append(str
, "\"");
1976 g_string_append_printf(str
, ",offset-s=%" PRId64
,
1977 ctf_legacy_opts
->offset_s
.value
);
1978 g_string_append_printf(str
, ",offset-ns=%" PRId64
,
1979 ctf_legacy_opts
->offset_ns
.value
);
1980 g_string_append_bool_param(str
, "stream-intersection",
1981 ctf_legacy_opts
->stream_intersection
);
1982 g_string_append(str
, "' ");
1983 g_free(escaped_input
);
1986 printf_err("%s\n\n", str
->str
);
1990 g_string_free(str
, TRUE
);
1996 * Validates a given configuration, with optional legacy input and
1997 * output formats options. Prints useful error messages if anything
2000 * Returns true when the configuration is valid.
2003 bool validate_cfg(struct bt_config
*cfg
,
2004 enum legacy_input_format
*legacy_input_format
,
2005 enum legacy_output_format
*legacy_output_format
,
2006 struct bt_value
*legacy_input_paths
,
2007 struct ctf_legacy_opts
*ctf_legacy_opts
,
2008 struct text_legacy_opts
*text_legacy_opts
)
2010 bool legacy_input
= false;
2011 bool legacy_output
= false;
2013 /* Determine if the input and output should be legacy-style */
2014 if (*legacy_input_format
!= LEGACY_INPUT_FORMAT_NONE
||
2015 !bt_value_array_is_empty(legacy_input_paths
) ||
2016 ctf_legacy_opts_is_any_set(ctf_legacy_opts
)) {
2017 legacy_input
= true;
2020 if (*legacy_output_format
!= LEGACY_OUTPUT_FORMAT_NONE
||
2021 text_legacy_opts_is_any_set(text_legacy_opts
)) {
2022 legacy_output
= true;
2026 /* If no legacy input format was specified, default to CTF */
2027 if (*legacy_input_format
== LEGACY_INPUT_FORMAT_NONE
) {
2028 *legacy_input_format
= LEGACY_INPUT_FORMAT_CTF
;
2031 /* Make sure at least one input path exists */
2032 if (bt_value_array_is_empty(legacy_input_paths
)) {
2033 switch (*legacy_input_format
) {
2034 case LEGACY_INPUT_FORMAT_CTF
:
2035 printf_err("No input path specified for legacy `ctf` input format\n");
2037 case LEGACY_INPUT_FORMAT_LTTNG_LIVE
:
2038 printf_err("No URL specified for legacy `lttng-live` input format\n");
2046 /* Make sure no non-legacy sources are specified */
2047 if (cfg
->sources
->len
!= 0) {
2048 print_input_legacy_to_sources(*legacy_input_format
,
2049 legacy_input_paths
, ctf_legacy_opts
);
2054 if (legacy_output
) {
2056 * If no legacy output format was specified, default to
2059 if (*legacy_output_format
== LEGACY_OUTPUT_FORMAT_NONE
) {
2060 *legacy_output_format
= LEGACY_OUTPUT_FORMAT_TEXT
;
2064 * If any "text" option was specified, the output must be
2067 if (text_legacy_opts_is_any_set(text_legacy_opts
) &&
2068 *legacy_output_format
!=
2069 LEGACY_OUTPUT_FORMAT_TEXT
) {
2070 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
2074 /* Make sure no non-legacy sinks are specified */
2075 if (cfg
->sinks
->len
!= 0) {
2076 print_output_legacy_to_sinks(*legacy_output_format
,
2083 * If the output is the legacy "ctf-metadata" format, then the
2084 * input should be the legacy "ctf" input format.
2086 if (*legacy_output_format
== LEGACY_OUTPUT_FORMAT_CTF_METADATA
&&
2087 *legacy_input_format
!= LEGACY_INPUT_FORMAT_CTF
) {
2088 printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n");
2099 * Parses a 64-bit signed integer.
2101 * Returns a negative value if anything goes wrong.
2104 int parse_int64(const char *arg
, int64_t *val
)
2109 *val
= strtoll(arg
, &endptr
, 0);
2110 if (*endptr
!= '\0' || arg
== endptr
|| errno
!= 0) {
2124 OPT_CLOCK_FORCE_CORRELATE
,
2127 OPT_CLOCK_OFFSET_NS
,
2131 OPT_DEBUG_INFO_FULL_PATH
,
2132 OPT_DEBUG_INFO_TARGET_PREFIX
,
2146 OPT_RESET_BASE_PARAMS
,
2149 OPT_STREAM_INTERSECTION
,
2153 OPT_OMIT_SYSTEM_PLUGIN_PATH
,
2154 OPT_OMIT_HOME_PLUGIN_PATH
,
2157 /* popt long option descriptions */
2158 static struct poptOption long_options
[] = {
2159 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2160 { "base-params", 'b', POPT_ARG_STRING
, NULL
, OPT_BASE_PARAMS
, NULL
, NULL
},
2161 { "begin", '\0', POPT_ARG_STRING
, NULL
, OPT_BEGIN
, NULL
, NULL
},
2162 { "clock-cycles", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_CYCLES
, NULL
, NULL
},
2163 { "clock-date", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_DATE
, NULL
, NULL
},
2164 { "clock-force-correlate", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_FORCE_CORRELATE
, NULL
, NULL
},
2165 { "clock-gmt", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_GMT
, NULL
, NULL
},
2166 { "clock-offset", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET
, NULL
, NULL
},
2167 { "clock-offset-ns", '\0', POPT_ARG_STRING
, NULL
, OPT_CLOCK_OFFSET_NS
, NULL
, NULL
},
2168 { "clock-seconds", '\0', POPT_ARG_NONE
, NULL
, OPT_CLOCK_SECONDS
, NULL
, NULL
},
2169 { "debug", 'd', POPT_ARG_NONE
, NULL
, OPT_DEBUG
, NULL
, NULL
},
2170 { "debug-info-dir", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_DIR
, NULL
, NULL
},
2171 { "debug-info-full-path", 0, POPT_ARG_NONE
, NULL
, OPT_DEBUG_INFO_FULL_PATH
, NULL
, NULL
},
2172 { "debug-info-target-prefix", 0, POPT_ARG_STRING
, NULL
, OPT_DEBUG_INFO_TARGET_PREFIX
, NULL
, NULL
},
2173 { "end", '\0', POPT_ARG_STRING
, NULL
, OPT_END
, NULL
, NULL
},
2174 { "fields", 'f', POPT_ARG_STRING
, NULL
, OPT_FIELDS
, NULL
, NULL
},
2175 { "help", 'h', POPT_ARG_NONE
, NULL
, OPT_HELP
, NULL
, NULL
},
2176 { "help-legacy", '\0', POPT_ARG_NONE
, NULL
, OPT_HELP_LEGACY
, NULL
, NULL
},
2177 { "input-format", 'i', POPT_ARG_STRING
, NULL
, OPT_INPUT_FORMAT
, NULL
, NULL
},
2178 { "list", 'l', POPT_ARG_NONE
, NULL
, OPT_LIST
, NULL
, NULL
},
2179 { "names", 'n', POPT_ARG_STRING
, NULL
, OPT_NAMES
, NULL
, NULL
},
2180 { "no-delta", '\0', POPT_ARG_NONE
, NULL
, OPT_NO_DELTA
, NULL
, NULL
},
2181 { "output", 'w', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_PATH
, NULL
, NULL
},
2182 { "output-format", 'o', POPT_ARG_STRING
, NULL
, OPT_OUTPUT_FORMAT
, NULL
, NULL
},
2183 { "path", 'P', POPT_ARG_STRING
, NULL
, OPT_PATH
, NULL
, NULL
},
2184 { "params", 'p', POPT_ARG_STRING
, NULL
, OPT_PARAMS
, NULL
, NULL
},
2185 { "plugin-path", '\0', POPT_ARG_STRING
, NULL
, OPT_PLUGIN_PATH
, NULL
, NULL
},
2186 { "reset-base-params", 'r', POPT_ARG_NONE
, NULL
, OPT_RESET_BASE_PARAMS
, NULL
, NULL
},
2187 { "sink", '\0', POPT_ARG_STRING
, NULL
, OPT_SINK
, NULL
, NULL
},
2188 { "source", '\0', POPT_ARG_STRING
, NULL
, OPT_SOURCE
, NULL
, NULL
},
2189 { "stream-intersection", '\0', POPT_ARG_NONE
, NULL
, OPT_STREAM_INTERSECTION
, NULL
, NULL
},
2190 { "timerange", '\0', POPT_ARG_STRING
, NULL
, OPT_TIMERANGE
, NULL
, NULL
},
2191 { "verbose", 'v', POPT_ARG_NONE
, NULL
, OPT_VERBOSE
, NULL
, NULL
},
2192 { "version", 'V', POPT_ARG_NONE
, NULL
, OPT_VERSION
, NULL
, NULL
},
2193 { "omit-system-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_SYSTEM_PLUGIN_PATH
, NULL
, NULL
},
2194 { "omit-home-plugin-path", '\0', POPT_ARG_NONE
, NULL
, OPT_OMIT_HOME_PLUGIN_PATH
, NULL
, NULL
},
2195 { NULL
, 0, 0, NULL
, 0, NULL
, NULL
},
2199 * Sets the value of a given legacy offset option and marks it as set.
2201 static void set_offset_value(struct offset_opt
*offset_opt
, int64_t value
)
2203 offset_opt
->value
= value
;
2204 offset_opt
->is_set
= true;
2207 enum bt_config_component_dest
{
2208 BT_CONFIG_COMPONENT_DEST_SOURCE
,
2209 BT_CONFIG_COMPONENT_DEST_SINK
,
2213 * Adds a configuration component to the appropriate configuration
2214 * array depending on the destination.
2216 static void add_cfg_comp(struct bt_config
*cfg
,
2217 struct bt_config_component
*cfg_comp
,
2218 enum bt_config_component_dest dest
)
2220 if (dest
== BT_CONFIG_COMPONENT_DEST_SOURCE
) {
2221 g_ptr_array_add(cfg
->sources
, cfg_comp
);
2223 g_ptr_array_add(cfg
->sinks
, cfg_comp
);
2227 static int split_timerange(const char *arg
, const char **begin
, const char **end
)
2231 /* Try to match [begin,end] */
2232 c
= strchr(arg
, '[');
2246 /* Try to match begin,end */
2260 static char *bt_secure_getenv(const char *name
)
2262 if (is_setuid_setgid()) {
2263 printf_err("Disregarding %s environment variable for setuid/setgid binary", name
);
2266 return getenv(name
);
2269 static const char *get_home_dir(void)
2274 val
= bt_secure_getenv(HOME_ENV_VAR
);
2278 /* Fallback on password file. */
2279 pwd
= getpwuid(getuid());
2288 static int add_internal_plugin_paths(struct bt_config
*cfg
)
2290 if (!omit_home_plugin_path
) {
2291 char path
[PATH_MAX
];
2292 const char *home_dir
;
2294 if (is_setuid_setgid()) {
2295 printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
2297 home_dir
= get_home_dir();
2299 if (strlen(home_dir
) + strlen(HOME_SUBPATH
) + 1
2301 printf_err("Home directory path too long\n");
2304 strcpy(path
, home_dir
);
2305 strcat(path
, HOME_SUBPATH
);
2306 if (plugin_paths_from_arg(cfg
->plugin_paths
, path
)) {
2307 printf_err("Invalid home plugin path\n");
2314 if (!omit_system_plugin_path
) {
2315 if (plugin_paths_from_arg(cfg
->plugin_paths
,
2316 SYSTEM_PLUGIN_PATH
)) {
2317 printf_err("Invalid system plugin path\n");
2326 static int append_sources_from_implicit_params(GPtrArray
*sources
,
2327 struct bt_config_component
*implicit_source_comp
)
2330 size_t len
= sources
->len
;
2332 for (i
= 0; i
< len
; i
++) {
2333 struct bt_config_component
*comp
;
2334 struct bt_value
*params_to_set
;
2336 comp
= g_ptr_array_index(sources
, i
);
2337 params_to_set
= bt_value_map_extend(comp
->params
,
2338 implicit_source_comp
->params
);
2339 if (!params_to_set
) {
2340 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2343 BT_MOVE(comp
->params
, params_to_set
);
2351 * Returns a Babeltrace configuration, out of command-line arguments,
2352 * containing everything that is needed to instanciate specific
2353 * components with given parameters.
2355 * *exit_code is set to the appropriate exit code to use as far as this
2358 * Return value is NULL on error, otherwise it's owned by the caller.
2360 struct bt_config
*bt_config_from_args(int argc
, const char *argv
[], int *exit_code
)
2362 struct bt_config
*cfg
= NULL
;
2363 poptContext pc
= NULL
;
2365 struct ctf_legacy_opts ctf_legacy_opts
;
2366 struct text_legacy_opts text_legacy_opts
;
2367 enum legacy_input_format legacy_input_format
= LEGACY_INPUT_FORMAT_NONE
;
2368 enum legacy_output_format legacy_output_format
=
2369 LEGACY_OUTPUT_FORMAT_NONE
;
2370 struct bt_value
*legacy_input_paths
= NULL
;
2371 struct bt_config_component
*implicit_source_comp
= NULL
;
2372 struct bt_config_component
*cur_cfg_comp
= NULL
;
2373 bool cur_is_implicit_source
= false;
2374 bool use_implicit_source
= false;
2375 enum bt_config_component_dest cur_cfg_comp_dest
=
2376 BT_CONFIG_COMPONENT_DEST_SOURCE
;
2377 struct bt_value
*cur_base_params
= NULL
;
2378 int opt
, nr_omit_opt
= 0;
2380 memset(&ctf_legacy_opts
, 0, sizeof(ctf_legacy_opts
));
2381 memset(&text_legacy_opts
, 0, sizeof(text_legacy_opts
));
2384 text_legacy_opts
.output
= g_string_new(NULL
);
2385 if (!text_legacy_opts
.output
) {
2390 text_legacy_opts
.dbg_info_dir
= g_string_new(NULL
);
2391 if (!text_legacy_opts
.dbg_info_dir
) {
2396 text_legacy_opts
.dbg_info_target_prefix
= g_string_new(NULL
);
2397 if (!text_legacy_opts
.dbg_info_target_prefix
) {
2402 cur_base_params
= bt_value_map_create();
2403 if (!cur_base_params
) {
2409 cfg
= g_new0(struct bt_config
, 1);
2415 bt_object_init(cfg
, bt_config_destroy
);
2416 cfg
->sources
= g_ptr_array_new_with_free_func((GDestroyNotify
) bt_put
);
2417 if (!cfg
->sources
) {
2422 cfg
->sinks
= g_ptr_array_new_with_free_func((GDestroyNotify
) bt_put
);
2428 legacy_input_paths
= bt_value_array_create();
2429 if (!legacy_input_paths
) {
2434 /* Note: implicit source never gets positional base params. */
2435 implicit_source_comp
= bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME
);
2436 if (implicit_source_comp
) {
2437 cur_cfg_comp
= implicit_source_comp
;
2438 cur_is_implicit_source
= true;
2439 use_implicit_source
= true;
2441 printf_debug("Cannot find implicit source plugin \"%s\"",
2442 DEFAULT_SOURCE_COMPONENT_NAME
);
2445 cfg
->plugin_paths
= bt_value_array_create();
2446 if (!cfg
->plugin_paths
) {
2452 pc
= poptGetContext(NULL
, argc
, (const char **) argv
, long_options
, 0);
2454 printf_err("Cannot get popt context\n");
2458 poptReadDefaultConfig(pc
, 0);
2460 while ((opt
= poptGetNextOpt(pc
)) > 0) {
2461 arg
= poptGetOptArg(pc
);
2464 case OPT_PLUGIN_PATH
:
2465 if (is_setuid_setgid()) {
2466 printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
2468 if (plugin_paths_from_arg(cfg
->plugin_paths
, arg
)) {
2469 printf_err("Invalid --plugin-path option's argument\n");
2474 case OPT_OMIT_SYSTEM_PLUGIN_PATH
:
2475 omit_system_plugin_path
= true;
2478 case OPT_OMIT_HOME_PLUGIN_PATH
:
2479 omit_home_plugin_path
= true;
2482 case OPT_OUTPUT_PATH
:
2483 if (text_legacy_opts
.output
->len
> 0) {
2484 printf_err("Duplicate --output option\n");
2488 g_string_assign(text_legacy_opts
.output
, arg
);
2490 case OPT_DEBUG_INFO_DIR
:
2491 if (text_legacy_opts
.dbg_info_dir
->len
> 0) {
2492 printf_err("Duplicate --debug-info-dir option\n");
2496 g_string_assign(text_legacy_opts
.dbg_info_dir
, arg
);
2498 case OPT_DEBUG_INFO_TARGET_PREFIX
:
2499 if (text_legacy_opts
.dbg_info_target_prefix
->len
> 0) {
2500 printf_err("Duplicate --debug-info-target-prefix option\n");
2504 g_string_assign(text_legacy_opts
.dbg_info_target_prefix
, arg
);
2506 case OPT_INPUT_FORMAT
:
2509 if (opt
== OPT_INPUT_FORMAT
) {
2510 if (!strcmp(arg
, "ctf")) {
2511 /* Legacy CTF input format */
2512 if (legacy_input_format
) {
2513 print_err_dup_legacy_input();
2517 legacy_input_format
=
2518 LEGACY_INPUT_FORMAT_CTF
;
2520 } else if (!strcmp(arg
, "lttng-live")) {
2521 /* Legacy LTTng-live input format */
2522 if (legacy_input_format
) {
2523 print_err_dup_legacy_input();
2527 legacy_input_format
=
2528 LEGACY_INPUT_FORMAT_LTTNG_LIVE
;
2533 use_implicit_source
= false;
2535 /* Non-legacy: try to create a component config */
2536 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
2537 add_cfg_comp(cfg
, cur_cfg_comp
,
2541 cur_cfg_comp
= bt_config_component_from_arg(arg
);
2542 if (!cur_cfg_comp
) {
2543 printf_err("Invalid format for --source option's argument:\n %s\n",
2547 cur_is_implicit_source
= false;
2549 assert(cur_base_params
);
2550 bt_put(cur_cfg_comp
->params
);
2551 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
2552 if (!cur_cfg_comp
->params
) {
2557 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SOURCE
;
2560 case OPT_OUTPUT_FORMAT
:
2563 if (opt
== OPT_OUTPUT_FORMAT
) {
2564 if (!strcmp(arg
, "text")) {
2565 /* Legacy CTF-text output format */
2566 if (legacy_output_format
) {
2567 print_err_dup_legacy_output();
2571 legacy_output_format
=
2572 LEGACY_OUTPUT_FORMAT_TEXT
;
2574 } else if (!strcmp(arg
, "dummy")) {
2575 /* Legacy dummy output format */
2576 if (legacy_output_format
) {
2577 print_err_dup_legacy_output();
2581 legacy_output_format
=
2582 LEGACY_OUTPUT_FORMAT_DUMMY
;
2584 } else if (!strcmp(arg
, "ctf-metadata")) {
2585 /* Legacy CTF-metadata output format */
2586 if (legacy_output_format
) {
2587 print_err_dup_legacy_output();
2591 legacy_output_format
=
2592 LEGACY_OUTPUT_FORMAT_CTF_METADATA
;
2597 /* Non-legacy: try to create a component config */
2598 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
2599 add_cfg_comp(cfg
, cur_cfg_comp
,
2603 cur_cfg_comp
= bt_config_component_from_arg(arg
);
2604 if (!cur_cfg_comp
) {
2605 printf_err("Invalid format for --sink option's argument:\n %s\n",
2609 cur_is_implicit_source
= false;
2611 assert(cur_base_params
);
2612 bt_put(cur_cfg_comp
->params
);
2613 cur_cfg_comp
->params
= bt_value_copy(cur_base_params
);
2614 if (!cur_cfg_comp
->params
) {
2619 cur_cfg_comp_dest
= BT_CONFIG_COMPONENT_DEST_SINK
;
2624 struct bt_value
*params
;
2625 struct bt_value
*params_to_set
;
2627 if (!cur_cfg_comp
) {
2628 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2629 DEFAULT_SOURCE_COMPONENT_NAME
);
2633 params
= bt_value_from_arg(arg
);
2635 printf_err("Invalid format for --params option's argument:\n %s\n",
2640 params_to_set
= bt_value_map_extend(cur_cfg_comp
->params
,
2643 if (!params_to_set
) {
2644 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
2649 BT_MOVE(cur_cfg_comp
->params
, params_to_set
);
2653 if (!cur_cfg_comp
) {
2654 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2655 DEFAULT_SOURCE_COMPONENT_NAME
);
2659 assert(cur_cfg_comp
->params
);
2661 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
2667 case OPT_BASE_PARAMS
:
2669 struct bt_value
*params
= bt_value_from_arg(arg
);
2672 printf_err("Invalid format for --base-params option's argument:\n %s\n",
2677 BT_MOVE(cur_base_params
, params
);
2680 case OPT_RESET_BASE_PARAMS
:
2681 BT_PUT(cur_base_params
);
2682 cur_base_params
= bt_value_map_create();
2683 if (!cur_base_params
) {
2689 if (text_legacy_opts
.names
) {
2690 printf_err("Duplicate --names option\n");
2694 text_legacy_opts
.names
= names_from_arg(arg
);
2695 if (!text_legacy_opts
.names
) {
2696 printf_err("Invalid --names option's argument\n");
2701 if (text_legacy_opts
.fields
) {
2702 printf_err("Duplicate --fields option\n");
2706 text_legacy_opts
.fields
= fields_from_arg(arg
);
2707 if (!text_legacy_opts
.fields
) {
2708 printf_err("Invalid --fields option's argument\n");
2713 text_legacy_opts
.no_delta
= true;
2715 case OPT_CLOCK_CYCLES
:
2716 text_legacy_opts
.clock_cycles
= true;
2718 case OPT_CLOCK_SECONDS
:
2719 text_legacy_opts
.clock_seconds
= true;
2721 case OPT_CLOCK_DATE
:
2722 text_legacy_opts
.clock_date
= true;
2725 text_legacy_opts
.clock_gmt
= true;
2727 case OPT_DEBUG_INFO_FULL_PATH
:
2728 text_legacy_opts
.dbg_info_full_path
= true;
2730 case OPT_CLOCK_OFFSET
:
2734 if (ctf_legacy_opts
.offset_s
.is_set
) {
2735 printf_err("Duplicate --clock-offset option\n");
2739 if (parse_int64(arg
, &val
)) {
2740 printf_err("Invalid --clock-offset option's argument\n");
2744 set_offset_value(&ctf_legacy_opts
.offset_s
, val
);
2747 case OPT_CLOCK_OFFSET_NS
:
2751 if (ctf_legacy_opts
.offset_ns
.is_set
) {
2752 printf_err("Duplicate --clock-offset-ns option\n");
2756 if (parse_int64(arg
, &val
)) {
2757 printf_err("Invalid --clock-offset-ns option's argument\n");
2761 set_offset_value(&ctf_legacy_opts
.offset_ns
, val
);
2764 case OPT_STREAM_INTERSECTION
:
2765 ctf_legacy_opts
.stream_intersection
= true;
2767 case OPT_CLOCK_FORCE_CORRELATE
:
2768 cfg
->force_correlate
= true;
2771 if (!cur_cfg_comp
) {
2772 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2773 DEFAULT_SOURCE_COMPONENT_NAME
);
2776 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
2777 printf_err("--begin option must follow a --source option\n");
2780 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
2787 if (!cur_cfg_comp
) {
2788 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2789 DEFAULT_SOURCE_COMPONENT_NAME
);
2792 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
2793 printf_err("--end option must follow a --source option\n");
2796 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
2804 const char *begin
, *end
;
2806 if (!cur_cfg_comp
) {
2807 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2808 DEFAULT_SOURCE_COMPONENT_NAME
);
2811 if (cur_cfg_comp_dest
!= BT_CONFIG_COMPONENT_DEST_SOURCE
) {
2812 printf_err("--timerange option must follow a --source option\n");
2815 if (split_timerange(arg
, &begin
, &end
)) {
2816 printf_err("Invalid --timerange format, expecting: begin,end or [begin,end] (where [] are actual brackets)\n");
2819 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
2824 if (bt_value_map_insert_string(cur_cfg_comp
->params
,
2833 print_usage(stdout
);
2835 case OPT_HELP_LEGACY
:
2837 print_legacy_usage(stdout
);
2844 cfg
->do_list
= true;
2847 cfg
->verbose
= true;
2853 printf_err("Unknown command-line option specified (option code %d)\n",
2862 if (argc
- nr_omit_opt
<= 1) {
2863 print_usage(stdout
);
2867 /* Check for option parsing error */
2869 printf_err("While parsing command-line options, at option %s: %s\n",
2870 poptBadOption(pc
, 0), poptStrerror(opt
));
2874 /* Consume leftover arguments as legacy input paths */
2876 const char *input_path
= poptGetArg(pc
);
2882 if (bt_value_array_append_string(legacy_input_paths
,
2889 if (add_internal_plugin_paths(cfg
)) {
2893 /* Append current component configuration, if any */
2894 if (cur_cfg_comp
&& !cur_is_implicit_source
) {
2895 add_cfg_comp(cfg
, cur_cfg_comp
, cur_cfg_comp_dest
);
2897 cur_cfg_comp
= NULL
;
2899 /* Validate legacy/non-legacy options */
2900 if (!validate_cfg(cfg
, &legacy_input_format
, &legacy_output_format
,
2901 legacy_input_paths
, &ctf_legacy_opts
,
2902 &text_legacy_opts
)) {
2903 printf_err("Command-line options form an invalid configuration\n");
2908 * If there's a legacy input format, convert it to source
2909 * component configurations.
2911 if (legacy_input_format
) {
2912 if (append_sources_from_legacy_opts(cfg
->sources
,
2913 legacy_input_format
, &ctf_legacy_opts
,
2914 legacy_input_paths
)) {
2915 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
2918 if (append_sources_from_implicit_params(cfg
->sources
,
2919 implicit_source_comp
)) {
2920 printf_err("Cannot initialize legacy component parameters\n");
2923 use_implicit_source
= false;
2925 if (use_implicit_source
) {
2926 add_cfg_comp(cfg
, implicit_source_comp
,
2927 BT_CONFIG_COMPONENT_DEST_SOURCE
);
2928 implicit_source_comp
= NULL
;
2930 if (implicit_source_comp
2931 && !bt_value_map_is_empty(implicit_source_comp
->params
)) {
2932 printf_err("Arguments specified for implicit source, but an explicit source has been specified, overriding it\n");
2939 * If there's a legacy output format, convert it to sink
2940 * component configurations.
2942 if (legacy_output_format
) {
2943 if (append_sinks_from_legacy_opts(cfg
->sinks
,
2944 legacy_output_format
, &text_legacy_opts
)) {
2945 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
2950 if (cfg
->sinks
->len
== 0) {
2951 /* Use implicit sink as default. */
2952 cur_cfg_comp
= bt_config_component_from_arg(DEFAULT_SINK_COMPONENT_NAME
);
2953 if (!cur_cfg_comp
) {
2954 printf_error("Cannot find implicit sink plugin \"%s\"\n",
2955 DEFAULT_SINK_COMPONENT_NAME
);
2957 add_cfg_comp(cfg
, cur_cfg_comp
,
2958 BT_CONFIG_COMPONENT_DEST_SINK
);
2959 cur_cfg_comp
= NULL
;
2971 poptFreeContext(pc
);
2974 if (text_legacy_opts
.output
) {
2975 g_string_free(text_legacy_opts
.output
, TRUE
);
2978 if (text_legacy_opts
.dbg_info_dir
) {
2979 g_string_free(text_legacy_opts
.dbg_info_dir
, TRUE
);
2982 if (text_legacy_opts
.dbg_info_target_prefix
) {
2983 g_string_free(text_legacy_opts
.dbg_info_target_prefix
, TRUE
);
2987 BT_PUT(implicit_source_comp
);
2988 BT_PUT(cur_cfg_comp
);
2989 BT_PUT(cur_base_params
);
2990 BT_PUT(text_legacy_opts
.names
);
2991 BT_PUT(text_legacy_opts
.fields
);
2992 BT_PUT(legacy_input_paths
);