Trimmer: Filter-out packet that are not in the specified range
[babeltrace.git] / converter / babeltrace-cfg.c
CommitLineData
c42c79ea
PP
1/*
2 * Babeltrace trace converter - parameter parsing
3 *
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
29#include <stdio.h>
30#include <stdbool.h>
31#include <inttypes.h>
32#include <babeltrace/babeltrace.h>
33#include <babeltrace/values.h>
34#include <popt.h>
35#include <glib.h>
36#include "babeltrace-cfg.h"
37
38/*
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.
43 */
44#define printf_err(fmt, args...) \
45 do { \
46 if (is_first_error) { \
47 fprintf(stderr, "Error: "); \
48 is_first_error = false; \
49 } \
50 fprintf(stderr, fmt, ##args); \
51 } while (0)
52
53static bool is_first_error = true;
54
55/* INI-style parsing FSM states */
56enum ini_parsing_fsm_state {
57 /* Expect a map key (identifier) */
58 INI_EXPECT_MAP_KEY,
59
60 /* Expect an equal character ('=') */
61 INI_EXPECT_EQUAL,
62
63 /* Expect a value */
64 INI_EXPECT_VALUE,
65
66 /* Expect a negative number value */
67 INI_EXPECT_VALUE_NUMBER_NEG,
68
69 /* Expect a comma character (',') */
70 INI_EXPECT_COMMA,
71};
72
73/* INI-style parsing state variables */
74struct ini_parsing_state {
75 /* Lexical scanner (owned by this) */
76 GScanner *scanner;
77
78 /* Output map value object being filled (owned by this) */
79 struct bt_value *params;
80
81 /* Next expected FSM state */
82 enum ini_parsing_fsm_state expecting;
83
84 /* Last decoded map key (owned by this) */
85 char *last_map_key;
86
87 /* Complete INI-style string to parse (not owned by this) */
88 const char *arg;
89
90 /* Error buffer (not owned by this) */
91 GString *ini_error;
92};
93
94/* Offset option with "is set" boolean */
95struct offset_opt {
96 int64_t value;
97 bool is_set;
98};
99
100/* Legacy "ctf"/"lttng-live" format options */
101struct ctf_legacy_opts {
102 struct offset_opt offset_s;
103 struct offset_opt offset_ns;
104 bool stream_intersection;
105};
106
107/* Legacy "text" format options */
108struct text_legacy_opts {
109 /*
110 * output, dbg_info_dir, dbg_info_target_prefix, names,
111 * and fields are owned by this.
112 */
113 GString *output;
114 GString *dbg_info_dir;
115 GString *dbg_info_target_prefix;
116 struct bt_value *names;
117 struct bt_value *fields;
118
119 /* Flags */
120 bool no_delta;
121 bool clock_cycles;
122 bool clock_seconds;
123 bool clock_date;
124 bool clock_gmt;
125 bool dbg_info_full_path;
126};
127
128/* Legacy input format format */
129enum legacy_input_format {
130 LEGACY_INPUT_FORMAT_NONE = 0,
131 LEGACY_INPUT_FORMAT_CTF,
132 LEGACY_INPUT_FORMAT_LTTNG_LIVE,
133};
134
135/* Legacy output format format */
136enum 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,
141};
142
143/*
144 * Prints the "out of memory" error.
145 */
146static
147void print_err_oom(void)
148{
149 printf_err("Out of memory\n");
150}
151
152/*
153 * Prints duplicate legacy output format error.
154 */
155static
156void print_err_dup_legacy_output(void)
157{
158 printf_err("More than one legacy output format specified\n");
159}
160
161/*
162 * Prints duplicate legacy input format error.
163 */
164static
165void print_err_dup_legacy_input(void)
166{
167 printf_err("More than one legacy input format specified\n");
168}
169
170/*
171 * Checks if any of the "text" legacy options is set.
172 */
173static
174bool text_legacy_opts_is_any_set(struct text_legacy_opts *opts)
175{
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;
185}
186
187/*
188 * Checks if any of the "ctf" legacy options is set.
189 */
190static
191bool ctf_legacy_opts_is_any_set(struct ctf_legacy_opts *opts)
192{
193 return opts->offset_s.is_set || opts->offset_ns.is_set ||
194 opts->stream_intersection;
195}
196
197/*
198 * Appends an "expecting token" error to the INI-style parsing state's
199 * error buffer.
200 */
201static
202void ini_append_error_expecting(struct ini_parsing_state *state,
203 GScanner *scanner, const char *expecting)
204{
205 size_t i;
206 size_t pos;
207
208 g_string_append_printf(state->ini_error, "Expecting %s:\n", expecting);
209
210 /* Only print error if there's one line */
211 if (strchr(state->arg, '\n') != NULL || strlen(state->arg) == 0) {
212 return;
213 }
214
215 g_string_append_printf(state->ini_error, "\n %s\n", state->arg);
216 pos = g_scanner_cur_position(scanner) + 4;
217
218 if (!g_scanner_eof(scanner)) {
219 pos--;
220 }
221
222 for (i = 0; i < pos; ++i) {
223 g_string_append_printf(state->ini_error, " ");
224 }
225
226 g_string_append_printf(state->ini_error, "^\n\n");
227}
228
229static
230int ini_handle_state(struct ini_parsing_state *state)
231{
232 int ret = 0;
233 GTokenType token_type;
234 struct bt_value *value = NULL;
235
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, "'='");
243 break;
244 case INI_EXPECT_VALUE:
245 case INI_EXPECT_VALUE_NUMBER_NEG:
246 ini_append_error_expecting(state,
247 state->scanner, "value");
248 break;
249 case INI_EXPECT_MAP_KEY:
250 ini_append_error_expecting(state,
251 state->scanner, "unquoted map key");
252 break;
253 default:
254 break;
255 }
256 goto error;
257 }
258
259 /* We're done! */
260 ret = 1;
261 goto success;
262 }
263
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,
268 "unquoted map key");
269 goto error;
270 }
271
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,
277 "Out of memory\n");
278 goto error;
279 }
280
281 if (bt_value_map_has_key(state->params, state->last_map_key)) {
282 g_string_append_printf(state->ini_error,
6d1d5711 283 "Duplicate parameter key: `%s`\n",
c42c79ea
PP
284 state->last_map_key);
285 goto error;
286 }
287
288 state->expecting = INI_EXPECT_EQUAL;
289 goto success;
290 case INI_EXPECT_EQUAL:
291 if (token_type != G_TOKEN_CHAR) {
292 ini_append_error_expecting(state,
293 state->scanner, "'='");
294 goto error;
295 }
296
297 if (state->scanner->value.v_char != '=') {
298 ini_append_error_expecting(state,
299 state->scanner, "'='");
300 goto error;
301 }
302
303 state->expecting = INI_EXPECT_VALUE;
304 goto success;
305 case INI_EXPECT_VALUE:
306 {
307 switch (token_type) {
308 case G_TOKEN_CHAR:
309 if (state->scanner->value.v_char == '-') {
310 /* Negative number */
311 state->expecting =
312 INI_EXPECT_VALUE_NUMBER_NEG;
313 goto success;
314 } else {
315 ini_append_error_expecting(state,
316 state->scanner, "value");
317 goto error;
318 }
319 break;
320 case G_TOKEN_INT:
321 {
322 /* Positive integer */
323 uint64_t int_val = state->scanner->value.v_int64;
324
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",
328 int_val);
329 goto error;
330 }
331
332 value = bt_value_integer_create_init(
333 (int64_t) int_val);
334 break;
335 }
336 case G_TOKEN_FLOAT:
337 /* Positive floating point number */
338 value = bt_value_float_create_init(
339 state->scanner->value.v_float);
340 break;
341 case G_TOKEN_STRING:
342 /* Quoted string */
343 value = bt_value_string_create_init(
344 state->scanner->value.v_string);
345 break;
346 case G_TOKEN_IDENTIFIER:
347 {
348 /*
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
352 * identifier.
353 *
354 * If one of the known symbols is not
355 * recognized here, then fall back to creating
356 * a string value.
357 */
358 const char *id = state->scanner->value.v_identifier;
359
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") ||
369 !strcmp(id, "no") ||
370 !strcmp(id, "NO")) {
371 value = bt_value_bool_create_init(false);
372 } else {
373 value = bt_value_string_create_init(id);
374 }
375 break;
376 }
377 default:
378 /* Unset value variable will trigger the error */
379 break;
380 }
381
382 if (!value) {
383 ini_append_error_expecting(state,
384 state->scanner, "value");
385 goto error;
386 }
387
388 state->expecting = INI_EXPECT_COMMA;
389 goto success;
390 }
391 case INI_EXPECT_VALUE_NUMBER_NEG:
392 {
393 switch (token_type) {
394 case G_TOKEN_INT:
395 {
396 /* Negative integer */
397 uint64_t int_val = state->scanner->value.v_int64;
398
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",
402 int_val);
403 goto error;
404 }
405
406 value = bt_value_integer_create_init(
407 -((int64_t) int_val));
408 break;
409 }
410 case G_TOKEN_FLOAT:
411 /* Negative floating point number */
412 value = bt_value_float_create_init(
413 -state->scanner->value.v_float);
414 break;
415 default:
416 /* Unset value variable will trigger the error */
417 break;
418 }
419
420 if (!value) {
421 ini_append_error_expecting(state,
422 state->scanner, "value");
423 goto error;
424 }
425
426 state->expecting = INI_EXPECT_COMMA;
427 goto success;
428 }
429 case INI_EXPECT_COMMA:
430 if (token_type != G_TOKEN_CHAR) {
431 ini_append_error_expecting(state,
432 state->scanner, "','");
433 goto error;
434 }
435
436 if (state->scanner->value.v_char != ',') {
437 ini_append_error_expecting(state,
438 state->scanner, "','");
439 goto error;
440 }
441
442 state->expecting = INI_EXPECT_MAP_KEY;
443 goto success;
444 default:
445 assert(false);
446 }
447
448error:
449 ret = -1;
450 goto end;
451
452success:
453 if (value) {
454 if (bt_value_map_insert(state->params,
455 state->last_map_key, value)) {
456 /* Only override return value on error */
457 ret = -1;
458 }
459 }
460
461end:
462 BT_PUT(value);
463 return ret;
464}
465
466/*
467 * Converts an INI-style argument to an equivalent map value object.
468 *
469 * Return value is owned by the caller.
470 */
471static
472struct bt_value *bt_value_from_ini(const char *arg, GString *ini_error)
473{
474 /* Lexical scanner configuration */
475 GScannerConfig scanner_config = {
476 /* Skip whitespaces */
477 .cset_skip_characters = " \t\n",
478
479 /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
480 .cset_identifier_first =
481 G_CSET_a_2_z
482 "_"
483 G_CSET_A_2_Z,
484 .cset_identifier_nth =
485 G_CSET_a_2_z
486 "_0123456789-.:"
487 G_CSET_A_2_Z,
488
489 /* "hello" and "Hello" two different keys */
490 .case_sensitive = TRUE,
491
492 /* No comments */
493 .cpair_comment_single = NULL,
494 .skip_comment_multi = TRUE,
495 .skip_comment_single = TRUE,
496 .scan_comment_multi = FALSE,
497
498 /*
499 * Do scan identifiers, including 1-char identifiers,
500 * but NULL is a normal identifier.
501 */
502 .scan_identifier = TRUE,
503 .scan_identifier_1char = TRUE,
504 .scan_identifier_NULL = FALSE,
505
506 /*
507 * No specific symbols: null and boolean "symbols" are
508 * scanned as plain identifiers.
509 */
510 .scan_symbols = FALSE,
511 .symbol_2_token = FALSE,
512 .scope_0_fallback = FALSE,
513
514 /*
515 * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
516 * integers prefixed with "$".
517 */
518 .scan_binary = TRUE,
519 .scan_octal = TRUE,
520 .scan_float = TRUE,
521 .scan_hex = TRUE,
522 .scan_hex_dollar = FALSE,
523
524 /* Convert scanned numbers to integer tokens */
525 .numbers_2_int = TRUE,
526
527 /* Support both integers and floating-point numbers */
528 .int_2_float = FALSE,
529
530 /* Scan integers as 64-bit signed integers */
531 .store_int64 = TRUE,
532
533 /* Only scan double-quoted strings */
534 .scan_string_sq = FALSE,
535 .scan_string_dq = TRUE,
536
537 /* Do not converter identifiers to string tokens */
538 .identifier_2_string = FALSE,
539
540 /* Scan characters as G_TOKEN_CHAR token */
541 .char_2_token = FALSE,
542 };
543 struct ini_parsing_state state = {
544 .scanner = NULL,
545 .params = NULL,
546 .expecting = INI_EXPECT_MAP_KEY,
547 .arg = arg,
548 .ini_error = ini_error,
549 };
550
551 state.params = bt_value_map_create();
552 if (!state.params) {
553 goto error;
554 }
555
556 state.scanner = g_scanner_new(&scanner_config);
557 if (!state.scanner) {
558 goto error;
559 }
560
561 /* Let the scan begin */
562 g_scanner_input_text(state.scanner, arg, strlen(arg));
563
564 while (true) {
565 int ret = ini_handle_state(&state);
566
567 if (ret < 0) {
568 /* Error */
569 goto error;
570 } else if (ret > 0) {
571 /* Done */
572 break;
573 }
574 }
575
576 goto end;
577
578error:
579 BT_PUT(state.params);
580
581end:
582 if (state.scanner) {
583 g_scanner_destroy(state.scanner);
584 }
585
586 free(state.last_map_key);
587 return state.params;
588}
589
590/*
591 * Returns the parameters map value object from a command-line
bdc61c70 592 * parameter option's argument.
c42c79ea
PP
593 *
594 * Return value is owned by the caller.
595 */
596static
597struct bt_value *bt_value_from_arg(const char *arg)
598{
599 struct bt_value *params = NULL;
c42c79ea
PP
600 GString *ini_error = NULL;
601
c42c79ea
PP
602 ini_error = g_string_new(NULL);
603 if (!ini_error) {
604 print_err_oom();
605 goto end;
606 }
607
608 /* Try INI-style parsing */
bdc61c70 609 params = bt_value_from_ini(arg, ini_error);
c42c79ea
PP
610 if (!params) {
611 printf_err("%s", ini_error->str);
612 goto end;
613 }
614
615end:
616 if (ini_error) {
617 g_string_free(ini_error, TRUE);
618 }
619 return params;
620}
621
622/*
623 * Returns the plugin and component names from a command-line
bdc61c70
PP
624 * source/sink option's argument. arg must have the following format:
625 *
626 * PLUGIN.COMPONENT
627 *
628 * where PLUGIN is the plugin name, and COMPONENT is the component
629 * name.
c42c79ea
PP
630 *
631 * On success, both *plugin and *component are not NULL. *plugin
632 * and *component are owned by the caller.
633 */
634static
635void plugin_component_names_from_arg(const char *arg, char **plugin,
636 char **component)
637{
638 const char *dot;
bdc61c70 639 const char *end;
c42c79ea
PP
640 size_t plugin_len;
641 size_t component_len;
642
bdc61c70 643 /* Initialize both return values to NULL: not found */
c42c79ea
PP
644 *plugin = NULL;
645 *component = NULL;
646
647 dot = strchr(arg, '.');
bdc61c70
PP
648 if (!dot) {
649 /* No dot */
c42c79ea
PP
650 goto end;
651 }
652
bdc61c70 653 end = arg + strlen(arg);
c42c79ea 654 plugin_len = dot - arg;
bdc61c70 655 component_len = end - dot - 1;
c42c79ea
PP
656 if (plugin_len == 0 || component_len == 0) {
657 goto end;
658 }
659
bdc61c70 660 *plugin = g_malloc0(plugin_len + 1);
c42c79ea
PP
661 if (!*plugin) {
662 print_err_oom();
663 goto end;
664 }
665
bdc61c70
PP
666 g_strlcpy(*plugin, arg, plugin_len + 1);
667 *component = g_malloc0(component_len + 1);
c42c79ea
PP
668 if (!*component) {
669 print_err_oom();
670 goto end;
671 }
672
bdc61c70 673 g_strlcpy(*component, dot + 1, component_len + 1);
c42c79ea
PP
674
675end:
676 return;
677}
678
679/*
680 * Prints the Babeltrace version.
681 */
682static
683void print_version(void)
684{
685 puts("Babeltrace " VERSION);
686}
687
688/*
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.
693 */
694static
695void print_legacy_usage(FILE *fp)
696{
697 fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
698 fprintf(fp, "\n");
699 fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
700 fprintf(fp, "\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");
710 fprintf(fp, "\n");
711 fprintf(fp, " Available input formats: ctf, lttng-live, ctf-metadata\n");
712 fprintf(fp, " Available output formats: text, dummy\n");
713 fprintf(fp, "\n");
714 fprintf(fp, "Input formats specific options:\n");
715 fprintf(fp, "\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");
720 fprintf(fp, "\n");
721 fprintf(fp, "text output format specific options:\n");
722 fprintf(fp, " \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");
6d1d5711 730 fprintf(fp, " (default: `/usr/lib/debug`)\n");
c42c79ea
PP
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");
6d1d5711 734 fprintf(fp, " (default: `/usr/lib/debug`)\n");
c42c79ea
PP
735 fprintf(fp, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
736 fprintf(fp, " all, trace, trace:hostname, trace:domain,\n");
d9b99e4e 737 fprintf(fp, " trace:procname, trace:vpid, loglevel, emf\n");
c42c79ea
PP
738 fprintf(fp, " (default: trace:hostname, trace:procname,\n");
739 fprintf(fp, " trace:vpid)\n");
740 fprintf(fp, " -n, --names=NAME[,NAME]... Print field names:\n");
741 fprintf(fp, " payload (or arg or args)\n");
742 fprintf(fp, " none, all, scope, header, context (or ctx)\n");
743 fprintf(fp, " (default: payload, context)\n");
744 fprintf(fp, " --no-delta Do not print time delta between consecutive\n");
745 fprintf(fp, " events\n");
746 fprintf(fp, " -w, --output=PATH Write output to PATH (default: standard output)\n");
747}
748
749/*
750 * Prints the Babeltrace 2.x usage.
751 */
752static
753void print_usage(FILE *fp)
754{
755 fprintf(fp, "Usage: babeltrace [OPTIONS]\n");
756 fprintf(fp, "\n");
015cee23
PP
757 fprintf(fp, " -B, --base-begin-ns=NS Set NS as the current base beginning\n");
758 fprintf(fp, " timestamp of the following source component\n");
759 fprintf(fp, " instances\n");
760 fprintf(fp, " -E, --base-end-ns=NS Set NS as the current base end timestamp\n");
761 fprintf(fp, " of the following source component instances\n");
b07ffa28
PP
762 fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
763 fprintf(fp, " of the following source and sink component\n");
764 fprintf(fp, " instances (see the exact format of PARAMS\n");
765 fprintf(fp, " below)\n");
015cee23
PP
766 fprintf(fp, " --begin-ns=NS Set the beginning timestamp of the latest\n");
767 fprintf(fp, " source component instance to NS\n");
c42c79ea 768 fprintf(fp, " -d, --debug Enable debug mode\n");
015cee23
PP
769 fprintf(fp, " --end-ns=NS Set the end timestamp of the latest source\n");
770 fprintf(fp, " component instance to NS\n");
c42c79ea 771 fprintf(fp, " -l, --list List available plugins and their components\n");
ad6a19bd
PP
772 fprintf(fp, " -P, --path=PATH Set the `path` parameter of the latest source\n");
773 fprintf(fp, " or sink component to PATH\n");
bdc61c70 774 fprintf(fp, " -p, --params=PARAMS Set the parameters of the latest source or\n");
b07ffa28
PP
775 fprintf(fp, " sink component instance (in command-line \n");
776 fprintf(fp, " order) to PARAMS (see the exact format of\n");
777 fprintf(fp, " PARAMS below)\n");
ad6a19bd 778 fprintf(fp, " --plugin-path=PATH[:PATH]... Set paths from which dynamic plugins can be\n");
015cee23
PP
779 fprintf(fp, " loaded to PATH\n");
780 fprintf(fp, " --reset-base-begin-ns Reset the current base beginning timestamp\n");
781 fprintf(fp, " of the following source component instances\n");
782 fprintf(fp, " --reset-base-end-ns Reset the current base end timestamp of the\n");
783 fprintf(fp, " following source component instances\n");
b07ffa28
PP
784 fprintf(fp, " -r, --reset-base-params Reset the current base parameters of the\n");
785 fprintf(fp, " following source and sink component\n");
786 fprintf(fp, " instances to an empty map\n");
015cee23
PP
787 fprintf(fp, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
788 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
789 fprintf(fp, " repeated)\n");
790 fprintf(fp, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
791 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
792 fprintf(fp, " repeated)\n");
bdc61c70
PP
793 fprintf(fp, " -h --help Show this help\n");
794 fprintf(fp, " --help-legacy Show Babeltrace 1.x legacy options\n");
c42c79ea
PP
795 fprintf(fp, " -v, --verbose Enable verbose output\n");
796 fprintf(fp, " -V, --version Show version\n");
bdc61c70 797 fprintf(fp, "\n\n");
b07ffa28
PP
798 fprintf(fp, "Format of PARAMS\n");
799 fprintf(fp, "----------------\n");
c42c79ea 800 fprintf(fp, "\n");
bdc61c70 801 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
c42c79ea 802 fprintf(fp, "\n");
bdc61c70
PP
803 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
804 fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
805 fprintf(fp, "VALUE can be one of:\n");
c42c79ea 806 fprintf(fp, "\n");
bdc61c70
PP
807 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
808 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
809 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
810 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
811 fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n");
812 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
813 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
814 fprintf(fp, " the null and boolean value symbols above.\n");
815 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
c42c79ea 816 fprintf(fp, "\n");
bdc61c70 817 fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
c42c79ea 818 fprintf(fp, "\n");
bdc61c70 819 fprintf(fp, "Example:\n");
c42c79ea 820 fprintf(fp, "\n");
bdc61c70
PP
821 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
822 fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
823 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
c42c79ea 824 fprintf(fp, "\n");
bdc61c70
PP
825 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
826 fprintf(fp, "from a shell.\n");
c42c79ea
PP
827}
828
829/*
830 * Destroys a component configuration.
831 */
832static
833void bt_config_component_destroy(struct bt_object *obj)
834{
835 struct bt_config_component *bt_config_component =
836 container_of(obj, struct bt_config_component, base);
837
838 if (!obj) {
839 goto end;
840 }
841
842 if (bt_config_component->plugin_name) {
843 g_string_free(bt_config_component->plugin_name, TRUE);
844 }
845
846 if (bt_config_component->component_name) {
847 g_string_free(bt_config_component->component_name, TRUE);
848 }
849
850 BT_PUT(bt_config_component->params);
851 g_free(bt_config_component);
852
853end:
854 return;
855}
856
857/*
bdc61c70
PP
858 * Creates a component configuration using the given plugin name and
859 * component name. plugin_name and component_name are copied (belong to
860 * the return value).
c42c79ea
PP
861 *
862 * Return value is owned by the caller.
863 */
864static
865struct bt_config_component *bt_config_component_create(const char *plugin_name,
bdc61c70 866 const char *component_name)
c42c79ea
PP
867{
868 struct bt_config_component *cfg_component = NULL;
869
870 cfg_component = g_new0(struct bt_config_component, 1);
871 if (!cfg_component) {
872 print_err_oom();
873 goto error;
874 }
875
876 bt_object_init(cfg_component, bt_config_component_destroy);
877 cfg_component->plugin_name = g_string_new(plugin_name);
878 if (!cfg_component->plugin_name) {
879 print_err_oom();
880 goto error;
881 }
882
883 cfg_component->component_name = g_string_new(component_name);
884 if (!cfg_component->component_name) {
885 print_err_oom();
886 goto error;
887 }
888
bdc61c70
PP
889 /* Start with empty parameters */
890 cfg_component->params = bt_value_map_create();
891 if (!cfg_component->params) {
892 print_err_oom();
893 goto error;
894 }
895
c42c79ea
PP
896 goto end;
897
898error:
899 BT_PUT(cfg_component);
900
901end:
902 return cfg_component;
903}
904
905/*
906 * Creates a component configuration from a command-line source/sink
bdc61c70 907 * option's argument.
c42c79ea
PP
908 */
909static
910struct bt_config_component *bt_config_component_from_arg(const char *arg)
911{
912 struct bt_config_component *bt_config_component = NULL;
913 char *plugin_name;
914 char *component_name;
c42c79ea
PP
915
916 plugin_component_names_from_arg(arg, &plugin_name, &component_name);
917 if (!plugin_name || !component_name) {
49849a47 918 printf_err("Cannot get plugin or component class name\n");
c42c79ea
PP
919 goto error;
920 }
921
c42c79ea 922 bt_config_component = bt_config_component_create(plugin_name,
bdc61c70 923 component_name);
c42c79ea
PP
924 if (!bt_config_component) {
925 goto error;
926 }
927
928 goto end;
929
930error:
931 BT_PUT(bt_config_component);
932
933end:
bdc61c70
PP
934 g_free(plugin_name);
935 g_free(component_name);
c42c79ea
PP
936 return bt_config_component;
937}
938
939/*
940 * Destroys a configuration.
941 */
942static
943void bt_config_destroy(struct bt_object *obj)
944{
945 struct bt_config *bt_config =
946 container_of(obj, struct bt_config, base);
947
948 if (!obj) {
949 goto end;
950 }
951
952 if (bt_config->sources) {
953 g_ptr_array_free(bt_config->sources, TRUE);
954 }
955
956 if (bt_config->sinks) {
957 g_ptr_array_free(bt_config->sinks, TRUE);
958 }
959
960 BT_PUT(bt_config->plugin_paths);
961 g_free(bt_config);
962
963end:
964 return;
965}
966
967/*
968 * Extracts the various paths from the string arg, delimited by ':',
969 * and converts them to an array value object.
970 *
971 * Returned array value object is empty if arg is empty.
972 *
973 * Return value is owned by the caller.
974 */
975static
976struct bt_value *plugin_paths_from_arg(const char *arg)
977{
978 struct bt_value *plugin_paths;
979 const char *at = arg;
980 const char *end = arg + strlen(arg);
981
982 plugin_paths = bt_value_array_create();
983 if (!plugin_paths) {
984 print_err_oom();
985 goto error;
986 }
987
988 while (at < end) {
989 int ret;
990 GString *path;
991 const char *next_colon;
992
993 next_colon = strchr(at, ':');
994 if (next_colon == at) {
995 /*
996 * Empty path: try next character (supported
997 * to conform to the typical parsing of $PATH).
998 */
999 at++;
1000 continue;
1001 } else if (!next_colon) {
1002 /* No more colon: use the remaining */
1003 next_colon = arg + strlen(arg);
1004 }
1005
1006 path = g_string_new(NULL);
1007 if (!path) {
1008 print_err_oom();
1009 goto error;
1010 }
1011
1012 g_string_append_len(path, at, next_colon - at);
1013 at = next_colon + 1;
1014 ret = bt_value_array_append_string(plugin_paths, path->str);
1015 g_string_free(path, TRUE);
1016 if (ret) {
1017 print_err_oom();
1018 goto error;
1019 }
1020 }
1021
1022 goto end;
1023
1024error:
1025 BT_PUT(plugin_paths);
1026
1027end:
1028 return plugin_paths;
1029}
1030
1031/*
1032 * Creates a simple lexical scanner for parsing comma-delimited names
1033 * and fields.
1034 *
1035 * Return value is owned by the caller.
1036 */
1037static
1038GScanner *create_csv_identifiers_scanner(void)
1039{
1040 GScannerConfig scanner_config = {
1041 .cset_skip_characters = " \t\n",
1042 .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
1043 .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
1044 .case_sensitive = TRUE,
1045 .cpair_comment_single = NULL,
1046 .skip_comment_multi = TRUE,
1047 .skip_comment_single = TRUE,
1048 .scan_comment_multi = FALSE,
1049 .scan_identifier = TRUE,
1050 .scan_identifier_1char = TRUE,
1051 .scan_identifier_NULL = FALSE,
1052 .scan_symbols = FALSE,
1053 .symbol_2_token = FALSE,
1054 .scope_0_fallback = FALSE,
1055 .scan_binary = FALSE,
1056 .scan_octal = FALSE,
1057 .scan_float = FALSE,
1058 .scan_hex = FALSE,
1059 .scan_hex_dollar = FALSE,
1060 .numbers_2_int = FALSE,
1061 .int_2_float = FALSE,
1062 .store_int64 = FALSE,
1063 .scan_string_sq = FALSE,
1064 .scan_string_dq = FALSE,
1065 .identifier_2_string = FALSE,
1066 .char_2_token = TRUE,
1067 };
1068
1069 return g_scanner_new(&scanner_config);
1070}
1071
6e1bc0df
MD
1072/*
1073 * Inserts a string (if exists and not empty) or null to a map value
1074 * object.
1075 */
1076static
1077enum bt_value_status map_insert_string_or_null(struct bt_value *map,
1078 const char *key, GString *string)
1079{
1080 enum bt_value_status ret;
1081
1082 if (string && string->len > 0) {
1083 ret = bt_value_map_insert_string(map, key, string->str);
1084 } else {
1085 ret = bt_value_map_insert(map, key, bt_value_null);
1086 }
1087 return ret;
1088}
1089
c42c79ea
PP
1090/*
1091 * Converts a comma-delimited list of known names (--names option) to
1092 * an array value object containing those names as string value objects.
1093 *
1094 * Return value is owned by the caller.
1095 */
1096static
1097struct bt_value *names_from_arg(const char *arg)
1098{
1099 GScanner *scanner = NULL;
1100 struct bt_value *names = NULL;
6e1bc0df 1101 bool found_all = false, found_none = false, found_item = false;
c42c79ea
PP
1102
1103 names = bt_value_array_create();
1104 if (!names) {
1105 print_err_oom();
1106 goto error;
1107 }
1108
1109 scanner = create_csv_identifiers_scanner();
1110 if (!scanner) {
1111 print_err_oom();
1112 goto error;
1113 }
1114
1115 g_scanner_input_text(scanner, arg, strlen(arg));
1116
1117 while (true) {
1118 GTokenType token_type = g_scanner_get_next_token(scanner);
1119
1120 switch (token_type) {
1121 case G_TOKEN_IDENTIFIER:
1122 {
1123 const char *identifier = scanner->value.v_identifier;
1124
1125 if (!strcmp(identifier, "payload") ||
1126 !strcmp(identifier, "args") ||
1127 !strcmp(identifier, "arg")) {
6e1bc0df 1128 found_item = true;
c42c79ea
PP
1129 if (bt_value_array_append_string(names,
1130 "payload")) {
1131 goto error;
1132 }
1133 } else if (!strcmp(identifier, "context") ||
1134 !strcmp(identifier, "ctx")) {
6e1bc0df 1135 found_item = true;
c42c79ea
PP
1136 if (bt_value_array_append_string(names,
1137 "context")) {
1138 goto error;
1139 }
1140 } else if (!strcmp(identifier, "scope") ||
1141 !strcmp(identifier, "header")) {
6e1bc0df 1142 found_item = true;
c42c79ea
PP
1143 if (bt_value_array_append_string(names,
1144 identifier)) {
1145 goto error;
1146 }
6e1bc0df
MD
1147 } else if (!strcmp(identifier, "all")) {
1148 found_all = true;
1149 if (bt_value_array_append_string(names,
1150 identifier)) {
c42c79ea
PP
1151 goto error;
1152 }
6e1bc0df
MD
1153 } else if (!strcmp(identifier, "none")) {
1154 found_none = true;
c42c79ea
PP
1155 if (bt_value_array_append_string(names,
1156 identifier)) {
1157 goto error;
1158 }
c42c79ea 1159 } else {
6d1d5711 1160 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1161 identifier);
1162 goto error;
1163 }
1164 break;
1165 }
1166 case G_TOKEN_COMMA:
1167 continue;
1168 case G_TOKEN_EOF:
1169 goto end;
1170 default:
1171 goto error;
1172 }
1173 }
1174
6e1bc0df
MD
1175end:
1176 if (found_none && found_all) {
6d1d5711 1177 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
6e1bc0df
MD
1178 goto error;
1179 }
1180 /*
1181 * Legacy behavior is to clear the defaults (show none) when at
1182 * least one item is specified.
1183 */
1184 if (found_item && !found_none && !found_all) {
1185 if (bt_value_array_append_string(names, "none")) {
1186 goto error;
1187 }
1188 }
1189 if (scanner) {
1190 g_scanner_destroy(scanner);
1191 }
1192 return names;
c42c79ea
PP
1193
1194error:
1195 BT_PUT(names);
c42c79ea
PP
1196 if (scanner) {
1197 g_scanner_destroy(scanner);
1198 }
1199 return names;
1200}
1201
1202
1203/*
1204 * Converts a comma-delimited list of known fields (--fields option) to
1205 * an array value object containing those fields as string
1206 * value objects.
1207 *
1208 * Return value is owned by the caller.
1209 */
1210static
1211struct bt_value *fields_from_arg(const char *arg)
1212{
1213 GScanner *scanner = NULL;
1214 struct bt_value *fields;
1215
1216 fields = bt_value_array_create();
1217 if (!fields) {
1218 print_err_oom();
1219 goto error;
1220 }
1221
1222 scanner = create_csv_identifiers_scanner();
1223 if (!scanner) {
1224 print_err_oom();
1225 goto error;
1226 }
1227
1228 g_scanner_input_text(scanner, arg, strlen(arg));
1229
1230 while (true) {
1231 GTokenType token_type = g_scanner_get_next_token(scanner);
1232
1233 switch (token_type) {
1234 case G_TOKEN_IDENTIFIER:
1235 {
1236 const char *identifier = scanner->value.v_identifier;
1237
1238 if (!strcmp(identifier, "trace") ||
1239 !strcmp(identifier, "trace:hostname") ||
1240 !strcmp(identifier, "trace:domain") ||
1241 !strcmp(identifier, "trace:procname") ||
1242 !strcmp(identifier, "trace:vpid") ||
1243 !strcmp(identifier, "loglevel") ||
1244 !strcmp(identifier, "emf") ||
6e1bc0df
MD
1245 !strcmp(identifier, "callsite") ||
1246 !strcmp(identifier, "all")) {
c42c79ea
PP
1247 if (bt_value_array_append_string(fields,
1248 identifier)) {
1249 goto error;
1250 }
c42c79ea 1251 } else {
6d1d5711 1252 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1253 identifier);
1254 goto error;
1255 }
1256 break;
1257 }
1258 case G_TOKEN_COMMA:
1259 continue;
1260 case G_TOKEN_EOF:
1261 goto end;
1262 default:
1263 goto error;
1264 }
1265 }
1266
1267 goto end;
1268
1269error:
1270 BT_PUT(fields);
1271
1272end:
1273 if (scanner) {
1274 g_scanner_destroy(scanner);
1275 }
1276 return fields;
1277}
1278
1279/*
1280 * Inserts the equivalent "prefix-name" true boolean value objects into
1281 * map_obj where the names are in array_obj.
1282 */
1283static
1284int insert_flat_names_fields_from_array(struct bt_value *map_obj,
1285 struct bt_value *array_obj, const char *prefix)
1286{
1287 int ret = 0;
1288 int i;
6e1bc0df 1289 GString *tmpstr = NULL, *default_value = NULL;
c42c79ea
PP
1290
1291 /*
1292 * array_obj may be NULL if no CLI options were specified to
1293 * trigger its creation.
1294 */
1295 if (!array_obj) {
1296 goto end;
1297 }
1298
1299 tmpstr = g_string_new(NULL);
1300 if (!tmpstr) {
1301 print_err_oom();
1302 ret = -1;
1303 goto end;
1304 }
1305
6e1bc0df
MD
1306 default_value = g_string_new(NULL);
1307 if (!default_value) {
1308 print_err_oom();
1309 ret = -1;
1310 goto end;
1311 }
1312
c42c79ea
PP
1313 for (i = 0; i < bt_value_array_size(array_obj); i++) {
1314 struct bt_value *str_obj = bt_value_array_get(array_obj, i);
1315 const char *suffix;
6e1bc0df 1316 bool is_default = false;
c42c79ea
PP
1317
1318 if (!str_obj) {
1319 printf_err("Unexpected error\n");
1320 ret = -1;
1321 goto end;
1322 }
1323
1324 ret = bt_value_string_get(str_obj, &suffix);
1325 BT_PUT(str_obj);
1326 if (ret) {
1327 printf_err("Unexpected error\n");
1328 goto end;
1329 }
1330
1331 g_string_assign(tmpstr, prefix);
1332 g_string_append(tmpstr, "-");
6e1bc0df
MD
1333
1334 /* Special-case for "all" and "none". */
1335 if (!strcmp(suffix, "all")) {
1336 is_default = true;
1337 g_string_assign(default_value, "show");
1338 } else if (!strcmp(suffix, "none")) {
1339 is_default = true;
1340 g_string_assign(default_value, "hide");
1341 }
1342 if (is_default) {
1343 g_string_append(tmpstr, "default");
1344 ret = map_insert_string_or_null(map_obj,
1345 tmpstr->str,
1346 default_value);
1347 if (ret) {
1348 print_err_oom();
1349 goto end;
1350 }
1351 } else {
1352 g_string_append(tmpstr, suffix);
1353 ret = bt_value_map_insert_bool(map_obj, tmpstr->str,
1354 true);
1355 if (ret) {
1356 print_err_oom();
1357 goto end;
1358 }
c42c79ea
PP
1359 }
1360 }
1361
1362end:
6e1bc0df
MD
1363 if (default_value) {
1364 g_string_free(default_value, TRUE);
1365 }
c42c79ea
PP
1366 if (tmpstr) {
1367 g_string_free(tmpstr, TRUE);
1368 }
1369
1370 return ret;
1371}
1372
c42c79ea
PP
1373/*
1374 * Returns the parameters (map value object) corresponding to the
1375 * legacy text format options.
1376 *
1377 * Return value is owned by the caller.
1378 */
1379static
1380struct bt_value *params_from_text_legacy_opts(
1381 struct text_legacy_opts *text_legacy_opts)
1382{
1383 struct bt_value *params;
1384
1385 params = bt_value_map_create();
1386 if (!params) {
1387 print_err_oom();
1388 goto error;
1389 }
1390
1391 if (map_insert_string_or_null(params, "output-path",
1392 text_legacy_opts->output)) {
1393 print_err_oom();
1394 goto error;
1395 }
1396
1397 if (map_insert_string_or_null(params, "debug-info-dir",
1398 text_legacy_opts->dbg_info_dir)) {
1399 print_err_oom();
1400 goto error;
1401 }
1402
1403 if (map_insert_string_or_null(params, "debug-info-target-prefix",
1404 text_legacy_opts->dbg_info_target_prefix)) {
1405 print_err_oom();
1406 goto error;
1407 }
1408
1409 if (bt_value_map_insert_bool(params, "debug-info-full-path",
1410 text_legacy_opts->dbg_info_full_path)) {
1411 print_err_oom();
1412 goto error;
1413 }
1414
1415 if (bt_value_map_insert_bool(params, "no-delta",
1416 text_legacy_opts->no_delta)) {
1417 print_err_oom();
1418 goto error;
1419 }
1420
1421 if (bt_value_map_insert_bool(params, "clock-cycles",
1422 text_legacy_opts->clock_cycles)) {
1423 print_err_oom();
1424 goto error;
1425 }
1426
1427 if (bt_value_map_insert_bool(params, "clock-seconds",
1428 text_legacy_opts->clock_seconds)) {
1429 print_err_oom();
1430 goto error;
1431 }
1432
1433 if (bt_value_map_insert_bool(params, "clock-date",
1434 text_legacy_opts->clock_date)) {
1435 print_err_oom();
1436 goto error;
1437 }
1438
1439 if (bt_value_map_insert_bool(params, "clock-gmt",
1440 text_legacy_opts->clock_gmt)) {
1441 print_err_oom();
1442 goto error;
1443 }
1444
1445 if (insert_flat_names_fields_from_array(params,
1446 text_legacy_opts->names, "name")) {
1447 goto error;
1448 }
1449
1450 if (insert_flat_names_fields_from_array(params,
1451 text_legacy_opts->fields, "field")) {
1452 goto error;
1453 }
1454
1455 goto end;
1456
1457error:
1458 BT_PUT(params);
1459
1460end:
1461 return params;
1462}
1463
1464static
1465int append_sinks_from_legacy_opts(GPtrArray *sinks,
1466 enum legacy_output_format legacy_output_format,
1467 struct text_legacy_opts *text_legacy_opts)
1468{
1469 int ret = 0;
1470 struct bt_value *params = NULL;
1471 const char *plugin_name;
1472 const char *component_name;
1473 struct bt_config_component *bt_config_component = NULL;
1474
1475 switch (legacy_output_format) {
1476 case LEGACY_OUTPUT_FORMAT_TEXT:
1477 plugin_name = "text";
1478 component_name = "text";
1479 break;
1480 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1481 plugin_name = "ctf";
1482 component_name = "metadata-text";
1483 break;
1484 case LEGACY_OUTPUT_FORMAT_DUMMY:
1485 plugin_name = "dummy";
1486 component_name = "dummy";
1487 break;
1488 default:
1489 assert(false);
1490 break;
1491 }
1492
1493 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT) {
1494 /* Legacy "text" output format has parameters */
1495 params = params_from_text_legacy_opts(text_legacy_opts);
1496 if (!params) {
1497 goto error;
1498 }
1499 } else {
1500 /*
1501 * Legacy "dummy" and "ctf-metadata" output formats do
1502 * not have parameters.
1503 */
1504 params = bt_value_map_create();
1505 if (!params) {
1506 print_err_oom();
1507 goto error;
1508 }
1509 }
1510
1511 /* Create a component configuration */
1512 bt_config_component = bt_config_component_create(plugin_name,
bdc61c70 1513 component_name);
c42c79ea
PP
1514 if (!bt_config_component) {
1515 goto error;
1516 }
1517
bdc61c70
PP
1518 BT_MOVE(bt_config_component->params, params);
1519
c42c79ea
PP
1520 /* Move created component configuration to the array */
1521 g_ptr_array_add(sinks, bt_config_component);
1522
1523 goto end;
1524
1525error:
1526 ret = -1;
1527
1528end:
1529 BT_PUT(params);
1530
1531 return ret;
1532}
1533
1534/*
1535 * Returns the parameters (map value object) corresponding to the
1536 * given legacy CTF format options.
1537 *
1538 * Return value is owned by the caller.
1539 */
1540static
1541struct bt_value *params_from_ctf_legacy_opts(
1542 struct ctf_legacy_opts *ctf_legacy_opts)
1543{
1544 struct bt_value *params;
1545
1546 params = bt_value_map_create();
1547 if (!params) {
1548 print_err_oom();
1549 goto error;
1550 }
1551
1552 if (bt_value_map_insert_integer(params, "offset-s",
1553 ctf_legacy_opts->offset_s.value)) {
1554 print_err_oom();
1555 goto error;
1556 }
1557
1558 if (bt_value_map_insert_integer(params, "offset-ns",
1559 ctf_legacy_opts->offset_ns.value)) {
1560 print_err_oom();
1561 goto error;
1562 }
1563
1564 if (bt_value_map_insert_bool(params, "stream-intersection",
1565 ctf_legacy_opts->stream_intersection)) {
1566 print_err_oom();
1567 goto error;
1568 }
1569
1570 goto end;
1571
1572error:
1573 BT_PUT(params);
1574
1575end:
1576 return params;
1577}
1578
1579static
1580int append_sources_from_legacy_opts(GPtrArray *sources,
1581 enum legacy_input_format legacy_input_format,
1582 struct ctf_legacy_opts *ctf_legacy_opts,
015cee23 1583 struct bt_value *legacy_input_paths,
8ff0b830 1584 int64_t *begin_ns, int64_t *end_ns)
c42c79ea
PP
1585{
1586 int ret = 0;
1587 int i;
1588 struct bt_value *base_params;
1589 struct bt_value *params = NULL;
1590 struct bt_value *input_path = NULL;
1591 struct bt_value *input_path_copy = NULL;
1592 const char *input_key;
1593 const char *component_name;
1594
1595 switch (legacy_input_format) {
1596 case LEGACY_INPUT_FORMAT_CTF:
1597 input_key = "path";
1598 component_name = "fs";
1599 break;
1600 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1601 input_key = "url";
1602 component_name = "lttng-live";
1603 break;
1604 default:
1605 assert(false);
1606 break;
1607 }
1608
1609 base_params = params_from_ctf_legacy_opts(ctf_legacy_opts);
1610 if (!base_params) {
1611 goto error;
1612 }
1613
1614 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1615 struct bt_config_component *bt_config_component = NULL;
1616
1617 /* Copy base parameters as current parameters */
1618 params = bt_value_copy(base_params);
1619 if (!params) {
1620 goto error;
1621 }
1622
1623 /* Get current input path string value object */
1624 input_path = bt_value_array_get(legacy_input_paths, i);
1625 if (!input_path) {
1626 goto error;
1627 }
1628
1629 /* Copy current input path value object */
1630 input_path_copy = bt_value_copy(input_path);
1631 if (!input_path_copy) {
1632 goto error;
1633 }
1634
1635 /* Insert input path value object into current parameters */
1636 ret = bt_value_map_insert(params, input_key, input_path_copy);
1637 if (ret) {
1638 goto error;
1639 }
1640
1641 /* Create a component configuration */
1642 bt_config_component = bt_config_component_create("ctf",
bdc61c70 1643 component_name);
c42c79ea
PP
1644 if (!bt_config_component) {
1645 goto error;
1646 }
1647
bdc61c70 1648 BT_MOVE(bt_config_component->params, params);
8ff0b830
JG
1649 bt_config_component->begin.value_ns = begin_ns ? *begin_ns : 0;
1650 bt_config_component->begin.set = !!begin_ns;
1651 bt_config_component->end.value_ns = end_ns ? *end_ns : 0;
1652 bt_config_component->end.set = !!end_ns;
bdc61c70 1653
c42c79ea
PP
1654 /* Move created component configuration to the array */
1655 g_ptr_array_add(sources, bt_config_component);
1656
1657 /* Put current stuff */
1658 BT_PUT(input_path);
1659 BT_PUT(input_path_copy);
c42c79ea
PP
1660 }
1661
1662 goto end;
1663
1664error:
1665 ret = -1;
1666
1667end:
1668 BT_PUT(base_params);
1669 BT_PUT(params);
1670 BT_PUT(input_path);
1671 BT_PUT(input_path_copy);
1672 return ret;
1673}
1674
1675/*
1676 * Escapes a string for the shell. The string is escaped knowing that
1677 * it's a parameter string value (double-quoted), and that it will be
1678 * entered between single quotes in the shell.
1679 *
1680 * Return value is owned by the caller.
1681 */
1682static
1683char *str_shell_escape(const char *input)
1684{
1685 char *ret = NULL;
1686 const char *at = input;
1687 GString *str = g_string_new(NULL);
1688
1689 if (!str) {
1690 goto end;
1691 }
1692
1693 while (*at != '\0') {
1694 switch (*at) {
1695 case '\\':
1696 g_string_append(str, "\\\\");
1697 break;
1698 case '"':
1699 g_string_append(str, "\\\"");
1700 break;
1701 case '\'':
1702 g_string_append(str, "'\"'\"'");
1703 break;
1704 case '\n':
1705 g_string_append(str, "\\n");
1706 break;
1707 case '\t':
1708 g_string_append(str, "\\t");
1709 break;
1710 default:
1711 g_string_append_c(str, *at);
1712 break;
1713 }
1714
1715 at++;
1716 }
1717
1718end:
1719 if (str) {
1720 ret = str->str;
1721 g_string_free(str, FALSE);
1722 }
1723
1724 return ret;
1725}
1726
1727static
1728int append_prefixed_flag_params(GString *str, struct bt_value *flags,
1729 const char *prefix)
1730{
1731 int ret = 0;
1732 int i;
1733
1734 if (!flags) {
1735 goto end;
1736 }
1737
1738 for (i = 0; i < bt_value_array_size(flags); i++) {
1739 struct bt_value *value = bt_value_array_get(flags, i);
1740 const char *flag;
1741
1742 if (!value) {
1743 ret = -1;
1744 goto end;
1745 }
1746
1747 if (bt_value_string_get(value, &flag)) {
1748 BT_PUT(value);
1749 ret = -1;
1750 goto end;
1751 }
1752
1753 g_string_append_printf(str, ",%s-%s=true", prefix, flag);
1754 BT_PUT(value);
1755 }
1756
1757end:
1758 return ret;
1759}
1760
1761/*
1762 * Appends a boolean parameter string.
1763 */
1764static
1765void g_string_append_bool_param(GString *str, const char *name, bool value)
1766{
1767 g_string_append_printf(str, ",%s=%s", name, value ? "true" : "false");
1768}
1769
1770/*
1771 * Appends a path parameter string, or null if it's empty.
1772 */
1773static
1774int g_string_append_string_path_param(GString *str, const char *name,
1775 GString *path)
1776{
1777 int ret = 0;
1778
1779 if (path->len > 0) {
1780 char *escaped_path = str_shell_escape(path->str);
1781
1782 if (!escaped_path) {
1783 print_err_oom();
1784 goto error;
1785 }
1786
1787 g_string_append_printf(str, "%s=\"%s\"", name, escaped_path);
1788 free(escaped_path);
1789 } else {
1790 g_string_append_printf(str, "%s=null", name);
1791 }
1792
1793 goto end;
1794
1795error:
1796 ret = -1;
1797
1798end:
1799 return ret;
1800}
1801
1802/*
1803 * Prints the non-legacy sink options equivalent to the specified
1804 * legacy output format options.
1805 */
1806static
1807void print_output_legacy_to_sinks(
1808 enum legacy_output_format legacy_output_format,
1809 struct text_legacy_opts *text_legacy_opts)
1810{
1811 const char *input_format;
1812 GString *str = NULL;
1813
1814 str = g_string_new(" ");
1815 if (!str) {
1816 print_err_oom();
1817 goto end;
1818 }
1819
1820 switch (legacy_output_format) {
1821 case LEGACY_OUTPUT_FORMAT_TEXT:
1822 input_format = "text";
1823 break;
1824 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1825 input_format = "ctf-metadata";
1826 break;
1827 case LEGACY_OUTPUT_FORMAT_DUMMY:
1828 input_format = "dummy";
1829 break;
1830 default:
1831 assert(false);
1832 }
1833
49849a47 1834 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
c42c79ea 1835 input_format);
49849a47 1836 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
c42c79ea
PP
1837 input_format);
1838 g_string_append(str, "-o ");
1839
1840 switch (legacy_output_format) {
1841 case LEGACY_OUTPUT_FORMAT_TEXT:
1842 g_string_append(str, "text.text");
1843 break;
1844 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1845 g_string_append(str, "ctf.metadata-text");
1846 break;
1847 case LEGACY_OUTPUT_FORMAT_DUMMY:
1848 g_string_append(str, "dummy.dummy");
1849 break;
1850 default:
1851 assert(false);
1852 }
1853
1854 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT &&
1855 text_legacy_opts_is_any_set(text_legacy_opts)) {
1856 int ret;
1857
bdc61c70 1858 g_string_append(str, " -p '");
c42c79ea
PP
1859
1860 if (g_string_append_string_path_param(str, "output-path",
1861 text_legacy_opts->output)) {
1862 goto end;
1863 }
1864
1865 g_string_append(str, ",");
1866
1867 if (g_string_append_string_path_param(str, "debug-info-dir",
1868 text_legacy_opts->dbg_info_dir)) {
1869 goto end;
1870 }
1871
1872 g_string_append(str, ",");
1873
1874 if (g_string_append_string_path_param(str,
1875 "debug-info-target-prefix",
1876 text_legacy_opts->dbg_info_target_prefix)) {
1877 goto end;
1878 }
1879
1880 g_string_append_bool_param(str, "no-delta",
1881 text_legacy_opts->no_delta);
1882 g_string_append_bool_param(str, "clock-cycles",
1883 text_legacy_opts->clock_cycles);
1884 g_string_append_bool_param(str, "clock-seconds",
1885 text_legacy_opts->clock_seconds);
1886 g_string_append_bool_param(str, "clock-date",
1887 text_legacy_opts->clock_date);
1888 g_string_append_bool_param(str, "clock-gmt",
1889 text_legacy_opts->clock_gmt);
1890 ret = append_prefixed_flag_params(str, text_legacy_opts->names,
1891 "name");
1892 if (ret) {
1893 goto end;
1894 }
1895
1896 ret = append_prefixed_flag_params(str, text_legacy_opts->fields,
1897 "field");
1898 if (ret) {
1899 goto end;
1900 }
1901
1902 /* Remove last comma and close single quote */
1903 g_string_append(str, "'");
1904 }
1905
1906 printf_err("%s\n\n", str->str);
1907
1908end:
1909 if (str) {
1910 g_string_free(str, TRUE);
1911 }
1912 return;
1913}
1914
1915/*
1916 * Prints the non-legacy source options equivalent to the specified
1917 * legacy input format options.
1918 */
1919static
1920void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format,
1921 struct bt_value *legacy_input_paths,
1922 struct ctf_legacy_opts *ctf_legacy_opts)
1923{
1924 const char *input_format;
1925 GString *str = NULL;
1926 int i;
1927
1928 str = g_string_new(" ");
1929 if (!str) {
1930 print_err_oom();
1931 goto end;
1932 }
1933
1934 switch (legacy_input_format) {
1935 case LEGACY_INPUT_FORMAT_CTF:
1936 input_format = "ctf";
1937 break;
1938 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1939 input_format = "lttng-live";
1940 break;
1941 default:
1942 assert(false);
1943 }
1944
49849a47 1945 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
c42c79ea 1946 input_format);
49849a47 1947 printf_err("Specify the following non-legacy source component instance(s) instead of the\nlegacy `%s` input format options and positional arguments:\n\n",
c42c79ea
PP
1948 input_format);
1949
1950 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1951 struct bt_value *input_value =
1952 bt_value_array_get(legacy_input_paths, i);
1953 const char *input = NULL;
1954 char *escaped_input;
1955 int ret;
1956
1957 assert(input_value);
1958 ret = bt_value_string_get(input_value, &input);
1959 BT_PUT(input_value);
1960 assert(!ret && input);
1961 escaped_input = str_shell_escape(input);
1962 if (!escaped_input) {
1963 print_err_oom();
1964 goto end;
1965 }
1966
1967 g_string_append(str, "-i ctf.");
1968
1969 switch (legacy_input_format) {
1970 case LEGACY_INPUT_FORMAT_CTF:
bdc61c70 1971 g_string_append(str, "fs -p 'path=\"");
c42c79ea
PP
1972 break;
1973 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
bdc61c70 1974 g_string_append(str, "lttng-live -p 'url=\"");
c42c79ea
PP
1975 break;
1976 default:
1977 assert(false);
1978 }
1979
1980 g_string_append(str, escaped_input);
1981 g_string_append(str, "\"");
1982 g_string_append_printf(str, ",offset-s=%" PRId64,
1983 ctf_legacy_opts->offset_s.value);
1984 g_string_append_printf(str, ",offset-ns=%" PRId64,
1985 ctf_legacy_opts->offset_ns.value);
1986 g_string_append_bool_param(str, "stream-intersection",
1987 ctf_legacy_opts->stream_intersection);
1988 g_string_append(str, "' ");
1989 g_free(escaped_input);
1990 }
1991
1992 printf_err("%s\n\n", str->str);
1993
1994end:
1995 if (str) {
1996 g_string_free(str, TRUE);
1997 }
1998 return;
1999}
2000
015cee23
PP
2001/*
2002 * Validates a given source component configuration.
2003 */
2004static
2005bool validate_source_config_component(struct bt_config_component *cfg_comp)
2006{
2007 bool valid = false;
2008
8ff0b830
JG
2009 if (cfg_comp->begin.set && cfg_comp->end.set) {
2010 if (cfg_comp->begin.value_ns > cfg_comp->end.value_ns) {
015cee23 2011 printf_err("Beginning timestamp (%" PRIu64 ") is greater than end timestamp (%" PRIu64 ")\n",
8ff0b830
JG
2012 cfg_comp->begin.value_ns,
2013 cfg_comp->end.value_ns);
015cee23
PP
2014 goto end;
2015 }
2016 }
2017
2018 valid = true;
2019
2020end:
2021 return valid;
2022}
2023
c42c79ea
PP
2024/*
2025 * Validates a given configuration, with optional legacy input and
2026 * output formats options. Prints useful error messages if anything
2027 * is wrong.
2028 *
2029 * Returns true when the configuration is valid.
2030 */
2031static
2032bool validate_cfg(struct bt_config *cfg,
2033 enum legacy_input_format *legacy_input_format,
2034 enum legacy_output_format *legacy_output_format,
2035 struct bt_value *legacy_input_paths,
2036 struct ctf_legacy_opts *ctf_legacy_opts,
2037 struct text_legacy_opts *text_legacy_opts)
2038{
2039 bool legacy_input = false;
2040 bool legacy_output = false;
2041
2042 /* Determine if the input and output should be legacy-style */
2043 if (*legacy_input_format != LEGACY_INPUT_FORMAT_NONE ||
2044 cfg->sources->len == 0 ||
2045 !bt_value_array_is_empty(legacy_input_paths) ||
2046 ctf_legacy_opts_is_any_set(ctf_legacy_opts)) {
2047 legacy_input = true;
2048 }
2049
2050 if (*legacy_output_format != LEGACY_OUTPUT_FORMAT_NONE ||
2051 cfg->sinks->len == 0 ||
2052 text_legacy_opts_is_any_set(text_legacy_opts)) {
2053 legacy_output = true;
2054 }
2055
2056 if (legacy_input) {
2057 /* If no legacy input format was specified, default to CTF */
2058 if (*legacy_input_format == LEGACY_INPUT_FORMAT_NONE) {
2059 *legacy_input_format = LEGACY_INPUT_FORMAT_CTF;
2060 }
2061
2062 /* Make sure at least one input path exists */
2063 if (bt_value_array_is_empty(legacy_input_paths)) {
2064 switch (*legacy_input_format) {
2065 case LEGACY_INPUT_FORMAT_CTF:
6d1d5711 2066 printf_err("No input path specified for legacy `ctf` input format\n");
c42c79ea
PP
2067 break;
2068 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
6d1d5711 2069 printf_err("No URL specified for legacy `lttng-live` input format\n");
c42c79ea
PP
2070 break;
2071 default:
2072 assert(false);
2073 }
2074 goto error;
2075 }
2076
2077 /* Make sure no non-legacy sources are specified */
2078 if (cfg->sources->len != 0) {
2079 print_input_legacy_to_sources(*legacy_input_format,
2080 legacy_input_paths, ctf_legacy_opts);
2081 goto error;
2082 }
2083 }
2084
2085 if (legacy_output) {
2086 /*
2087 * If no legacy output format was specified, default to
2088 * "text".
2089 */
2090 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_NONE) {
2091 *legacy_output_format = LEGACY_OUTPUT_FORMAT_TEXT;
2092 }
2093
2094 /*
2095 * If any "text" option was specified, the output must be
2096 * legacy "text".
2097 */
2098 if (text_legacy_opts_is_any_set(text_legacy_opts) &&
2099 *legacy_output_format !=
2100 LEGACY_OUTPUT_FORMAT_TEXT) {
6d1d5711 2101 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
c42c79ea
PP
2102 goto error;
2103 }
2104
2105 /* Make sure no non-legacy sinks are specified */
2106 if (cfg->sinks->len != 0) {
2107 print_output_legacy_to_sinks(*legacy_output_format,
2108 text_legacy_opts);
2109 goto error;
2110 }
2111 }
2112
2113 /*
2114 * If the output is the legacy "ctf-metadata" format, then the
2115 * input should be the legacy "ctf" input format.
2116 */
2117 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_CTF_METADATA &&
2118 *legacy_input_format != LEGACY_INPUT_FORMAT_CTF) {
6d1d5711 2119 printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n");
c42c79ea
PP
2120 goto error;
2121 }
2122
2123 return true;
2124
2125error:
2126 return false;
2127}
2128
2129/*
2130 * Parses a 64-bit signed integer.
2131 *
2132 * Returns a negative value if anything goes wrong.
2133 */
2134static
2135int parse_int64(const char *arg, int64_t *val)
2136{
2137 char *endptr;
2138
2139 errno = 0;
2140 *val = strtoll(arg, &endptr, 0);
2141 if (*endptr != '\0' || arg == endptr || errno != 0) {
2142 return -1;
2143 }
2144
2145 return 0;
2146}
2147
015cee23
PP
2148/*
2149 * Parses a time in nanoseconds.
2150 *
2151 * Returns a negative value if anything goes wrong.
2152 */
2153static
8ff0b830 2154int ns_from_arg(const char *arg, int64_t *ns)
015cee23
PP
2155{
2156 int ret = 0;
2157 int64_t value;
2158
2159 if (parse_int64(arg, &value)) {
2160 ret = -1;
2161 goto end;
2162 }
2163
2164 if (value < 0) {
2165 ret = -1;
2166 goto end;
2167 }
2168
8ff0b830 2169 *ns = value;
015cee23
PP
2170
2171end:
2172 return ret;
2173}
2174
c42c79ea
PP
2175/* popt options */
2176enum {
2177 OPT_NONE = 0,
015cee23
PP
2178 OPT_BASE_BEGIN_NS,
2179 OPT_BASE_END_NS,
b07ffa28 2180 OPT_BASE_PARAMS,
015cee23 2181 OPT_BEGIN_NS,
c42c79ea
PP
2182 OPT_CLOCK_CYCLES,
2183 OPT_CLOCK_DATE,
2184 OPT_CLOCK_FORCE_CORRELATE,
2185 OPT_CLOCK_GMT,
2186 OPT_CLOCK_OFFSET,
2187 OPT_CLOCK_OFFSET_NS,
2188 OPT_CLOCK_SECONDS,
2189 OPT_DEBUG,
2190 OPT_DEBUG_INFO_DIR,
2191 OPT_DEBUG_INFO_FULL_PATH,
2192 OPT_DEBUG_INFO_TARGET_PREFIX,
015cee23 2193 OPT_END_NS,
c42c79ea
PP
2194 OPT_FIELDS,
2195 OPT_HELP,
2196 OPT_HELP_LEGACY,
2197 OPT_INPUT_FORMAT,
2198 OPT_LIST,
2199 OPT_NAMES,
2200 OPT_NO_DELTA,
2201 OPT_OUTPUT_FORMAT,
2202 OPT_OUTPUT_PATH,
ad6a19bd 2203 OPT_PATH,
bdc61c70 2204 OPT_PARAMS,
c42c79ea 2205 OPT_PLUGIN_PATH,
015cee23
PP
2206 OPT_RESET_BASE_BEGIN_NS,
2207 OPT_RESET_BASE_END_NS,
b07ffa28 2208 OPT_RESET_BASE_PARAMS,
c42c79ea
PP
2209 OPT_SINK,
2210 OPT_SOURCE,
2211 OPT_STREAM_INTERSECTION,
2212 OPT_VERBOSE,
2213 OPT_VERSION,
2214};
2215
2216/* popt long option descriptions */
2217static struct poptOption long_options[] = {
2218 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
015cee23
PP
2219 { "base-begin-ns", 'B', POPT_ARG_STRING, NULL, OPT_BASE_BEGIN_NS, NULL, NULL },
2220 { "base-end-ns", 'E', POPT_ARG_STRING, NULL, OPT_BASE_END_NS, NULL, NULL },
b07ffa28 2221 { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
015cee23 2222 { "begin-ns", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN_NS, NULL, NULL },
c42c79ea
PP
2223 { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
2224 { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
2225 { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
2226 { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
2227 { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
2228 { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
2229 { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
2230 { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
2231 { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
2232 { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
2233 { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
015cee23 2234 { "end-ns", '\0', POPT_ARG_STRING, NULL, OPT_END_NS, NULL, NULL },
c42c79ea
PP
2235 { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
2236 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2237 { "help-legacy", '\0', POPT_ARG_NONE, NULL, OPT_HELP_LEGACY, NULL, NULL },
2238 { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
2239 { "list", 'l', POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL },
2240 { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
2241 { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
2242 { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
2243 { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
ad6a19bd 2244 { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
bdc61c70 2245 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
ad6a19bd 2246 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
015cee23
PP
2247 { "reset-base-begin-ns", '\0', POPT_ARG_NONE, NULL, OPT_RESET_BASE_BEGIN_NS, NULL, NULL },
2248 { "reset-base-end-ns", '\0', POPT_ARG_NONE, NULL, OPT_RESET_BASE_END_NS, NULL, NULL },
b07ffa28 2249 { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
c42c79ea
PP
2250 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2251 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2252 { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
2253 { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
2254 { "version", 'V', POPT_ARG_NONE, NULL, OPT_VERSION, NULL, NULL },
2255 { NULL, 0, 0, NULL, 0, NULL, NULL },
2256};
2257
2258/*
2259 * Sets the value of a given legacy offset option and marks it as set.
2260 */
2261static void set_offset_value(struct offset_opt *offset_opt, int64_t value)
2262{
2263 offset_opt->value = value;
2264 offset_opt->is_set = true;
2265}
2266
bdc61c70
PP
2267enum bt_config_component_dest {
2268 BT_CONFIG_COMPONENT_DEST_SOURCE,
2269 BT_CONFIG_COMPONENT_DEST_SINK,
2270};
2271
2272/*
2273 * Adds a configuration component to the appropriate configuration
2274 * array depending on the destination.
2275 */
2276static void add_cfg_comp(struct bt_config *cfg,
2277 struct bt_config_component *cfg_comp,
2278 enum bt_config_component_dest dest)
2279{
2280 if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
2281 g_ptr_array_add(cfg->sources, cfg_comp);
2282 } else {
2283 g_ptr_array_add(cfg->sinks, cfg_comp);
2284 }
2285}
2286
c42c79ea
PP
2287/*
2288 * Returns a Babeltrace configuration, out of command-line arguments,
2289 * containing everything that is needed to instanciate specific
2290 * components with given parameters.
2291 *
2292 * *exit_code is set to the appropriate exit code to use as far as this
2293 * function goes.
2294 *
2295 * Return value is NULL on error, otherwise it's owned by the caller.
2296 */
2297struct bt_config *bt_config_from_args(int argc, char *argv[], int *exit_code)
2298{
2299 struct bt_config *cfg = NULL;
2300 poptContext pc = NULL;
2301 char *arg = NULL;
b7726e32
MD
2302 struct ctf_legacy_opts ctf_legacy_opts;
2303 struct text_legacy_opts text_legacy_opts;
c42c79ea
PP
2304 enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
2305 enum legacy_output_format legacy_output_format =
2306 LEGACY_OUTPUT_FORMAT_NONE;
2307 struct bt_value *legacy_input_paths = NULL;
bdc61c70
PP
2308 struct bt_config_component *cur_cfg_comp = NULL;
2309 enum bt_config_component_dest cur_cfg_comp_dest =
2310 BT_CONFIG_COMPONENT_DEST_SOURCE;
b07ffa28 2311 struct bt_value *cur_base_params = NULL;
8ff0b830
JG
2312 int64_t cur_base_begin_ns = 0;
2313 bool cur_base_begin_ns_set = false;
2314 int64_t cur_base_end_ns = 0;
2315 bool cur_base_end_ns_set = false;
c42c79ea 2316 int opt;
bdc61c70 2317 bool cur_cfg_comp_params_set = false;
015cee23 2318 unsigned int i;
c42c79ea 2319
b7726e32
MD
2320 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
2321 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
c42c79ea
PP
2322 *exit_code = 0;
2323
2324 if (argc <= 1) {
2325 print_usage(stdout);
2326 goto end;
2327 }
2328
2329 text_legacy_opts.output = g_string_new(NULL);
2330 if (!text_legacy_opts.output) {
2331 print_err_oom();
2332 goto error;
2333 }
2334
2335 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
2336 if (!text_legacy_opts.dbg_info_dir) {
2337 print_err_oom();
2338 goto error;
2339 }
2340
2341 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
2342 if (!text_legacy_opts.dbg_info_target_prefix) {
2343 print_err_oom();
2344 goto error;
2345 }
2346
b07ffa28
PP
2347 cur_base_params = bt_value_map_create();
2348 if (!cur_base_params) {
2349 print_err_oom();
2350 goto error;
2351 }
2352
c42c79ea
PP
2353 /* Create config */
2354 cfg = g_new0(struct bt_config, 1);
2355 if (!cfg) {
2356 print_err_oom();
2357 goto error;
2358 }
2359
2360 bt_object_init(cfg, bt_config_destroy);
2361 cfg->sources = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
2362 if (!cfg->sources) {
2363 print_err_oom();
2364 goto error;
2365 }
2366
2367 cfg->sinks = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
2368 if (!cfg->sinks) {
2369 print_err_oom();
2370 goto error;
2371 }
2372
2373 legacy_input_paths = bt_value_array_create();
2374 if (!legacy_input_paths) {
2375 print_err_oom();
2376 goto error;
2377 }
2378
2379 /* Parse options */
2380 pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
2381 if (!pc) {
2382 printf_err("Cannot get popt context\n");
2383 goto error;
2384 }
2385
2386 poptReadDefaultConfig(pc, 0);
2387
2388 while ((opt = poptGetNextOpt(pc)) > 0) {
2389 arg = poptGetOptArg(pc);
2390
2391 switch (opt) {
2392 case OPT_PLUGIN_PATH:
2393 if (cfg->plugin_paths) {
2394 printf_err("Duplicate --plugin-path option\n");
2395 goto error;
2396 }
2397
2398 cfg->plugin_paths = plugin_paths_from_arg(arg);
2399 if (!cfg->plugin_paths) {
2400 printf_err("Invalid --plugin-path option's argument\n");
2401 goto error;
2402 }
2403 break;
2404 case OPT_OUTPUT_PATH:
2405 if (text_legacy_opts.output->len > 0) {
2406 printf_err("Duplicate --output option\n");
2407 goto error;
2408 }
2409
2410 g_string_assign(text_legacy_opts.output, arg);
2411 break;
2412 case OPT_DEBUG_INFO_DIR:
2413 if (text_legacy_opts.dbg_info_dir->len > 0) {
2414 printf_err("Duplicate --debug-info-dir option\n");
2415 goto error;
2416 }
2417
2418 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
2419 break;
2420 case OPT_DEBUG_INFO_TARGET_PREFIX:
2421 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
2422 printf_err("Duplicate --debug-info-target-prefix option\n");
2423 goto error;
2424 }
2425
2426 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
2427 break;
2428 case OPT_INPUT_FORMAT:
2429 case OPT_SOURCE:
2430 {
c42c79ea
PP
2431 if (opt == OPT_INPUT_FORMAT) {
2432 if (!strcmp(arg, "ctf")) {
2433 /* Legacy CTF input format */
2434 if (legacy_input_format) {
2435 print_err_dup_legacy_input();
2436 goto error;
2437 }
2438
2439 legacy_input_format =
2440 LEGACY_INPUT_FORMAT_CTF;
2441 break;
2442 } else if (!strcmp(arg, "lttng-live")) {
2443 /* Legacy LTTng-live input format */
2444 if (legacy_input_format) {
2445 print_err_dup_legacy_input();
2446 goto error;
2447 }
2448
2449 legacy_input_format =
2450 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
2451 break;
2452 }
2453 }
2454
2455 /* Non-legacy: try to create a component config */
bdc61c70
PP
2456 if (cur_cfg_comp) {
2457 add_cfg_comp(cfg, cur_cfg_comp,
2458 cur_cfg_comp_dest);
2459 }
2460
2461 cur_cfg_comp = bt_config_component_from_arg(arg);
2462 if (!cur_cfg_comp) {
49849a47 2463 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
2464 arg);
2465 goto error;
2466 }
2467
b07ffa28
PP
2468 assert(cur_base_params);
2469 bt_put(cur_cfg_comp->params);
c9313318
PP
2470 cur_cfg_comp->params = bt_value_copy(cur_base_params);
2471 if (!cur_cfg_comp) {
2472 print_err_oom();
2473 goto end;
2474 }
2475
8ff0b830
JG
2476 cur_cfg_comp->begin.value_ns = cur_base_begin_ns;
2477 cur_cfg_comp->begin.set = cur_base_begin_ns_set;
2478
2479 cur_cfg_comp->end.value_ns = cur_base_end_ns;
2480 cur_cfg_comp->end.set = cur_base_end_ns_set;
2481
bdc61c70
PP
2482 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
2483 cur_cfg_comp_params_set = false;
c42c79ea
PP
2484 break;
2485 }
2486 case OPT_OUTPUT_FORMAT:
2487 case OPT_SINK:
2488 {
c42c79ea
PP
2489 if (opt == OPT_OUTPUT_FORMAT) {
2490 if (!strcmp(arg, "text")) {
2491 /* Legacy CTF-text output format */
2492 if (legacy_output_format) {
2493 print_err_dup_legacy_output();
2494 goto error;
2495 }
2496
2497 legacy_output_format =
2498 LEGACY_OUTPUT_FORMAT_TEXT;
2499 break;
2500 } else if (!strcmp(arg, "dummy")) {
2501 /* Legacy dummy output format */
2502 if (legacy_output_format) {
2503 print_err_dup_legacy_output();
2504 goto error;
2505 }
2506
2507 legacy_output_format =
2508 LEGACY_OUTPUT_FORMAT_DUMMY;
2509 break;
2510 } else if (!strcmp(arg, "ctf-metadata")) {
2511 /* Legacy CTF-metadata output format */
2512 if (legacy_output_format) {
2513 print_err_dup_legacy_output();
2514 goto error;
2515 }
2516
2517 legacy_output_format =
2518 LEGACY_OUTPUT_FORMAT_CTF_METADATA;
2519 break;
2520 }
2521 }
2522
2523 /* Non-legacy: try to create a component config */
bdc61c70
PP
2524 if (cur_cfg_comp) {
2525 add_cfg_comp(cfg, cur_cfg_comp,
2526 cur_cfg_comp_dest);
2527 }
2528
2529 cur_cfg_comp = bt_config_component_from_arg(arg);
2530 if (!cur_cfg_comp) {
49849a47 2531 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
2532 arg);
2533 goto error;
2534 }
2535
b07ffa28
PP
2536 assert(cur_base_params);
2537 bt_put(cur_cfg_comp->params);
c9313318
PP
2538 cur_cfg_comp->params = bt_value_copy(cur_base_params);
2539 if (!cur_cfg_comp) {
2540 print_err_oom();
2541 goto end;
2542 }
2543
bdc61c70
PP
2544 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
2545 cur_cfg_comp_params_set = false;
2546 break;
2547 }
2548 case OPT_PARAMS:
2549 {
2550 struct bt_value *params;
b07ffa28 2551 struct bt_value *params_to_set;
bdc61c70
PP
2552
2553 if (!cur_cfg_comp) {
2554 printf_err("--params option must follow a --source or --sink option\n");
2555 goto error;
2556 }
2557
2558 if (cur_cfg_comp_params_set) {
49849a47 2559 printf_err("Duplicate --params option for the same current component\ninstance (class %s.%s)\n",
bdc61c70
PP
2560 cur_cfg_comp->plugin_name->str,
2561 cur_cfg_comp->component_name->str);
2562 goto error;
2563 }
2564
2565 params = bt_value_from_arg(arg);
2566 if (!params) {
2567 printf_err("Invalid format for --params option's argument:\n %s\n",
2568 arg);
2569 goto error;
2570 }
2571
b07ffa28
PP
2572 params_to_set = bt_value_map_extend(cur_base_params,
2573 params);
2574 BT_PUT(params);
2575 if (!params_to_set) {
2576 printf_err("Cannot extend current base parameters with --params option's argument:\n %s\n",
2577 arg);
2578 goto error;
2579 }
2580
2581 BT_MOVE(cur_cfg_comp->params, params_to_set);
bdc61c70 2582 cur_cfg_comp_params_set = true;
c42c79ea
PP
2583 break;
2584 }
ad6a19bd
PP
2585 case OPT_PATH:
2586 if (!cur_cfg_comp) {
2587 printf_err("--path option must follow a --source or --sink option\n");
2588 goto error;
2589 }
2590
2591 assert(cur_cfg_comp->params);
2592
2593 if (bt_value_map_insert_string(cur_cfg_comp->params,
2594 "path", arg)) {
2595 print_err_oom();
2596 goto error;
2597 }
2598 break;
b07ffa28
PP
2599 case OPT_BASE_PARAMS:
2600 {
2601 struct bt_value *params = bt_value_from_arg(arg);
2602
2603 if (!params) {
2604 printf_err("Invalid format for --base-params option's argument:\n %s\n",
2605 arg);
2606 goto error;
2607 }
2608
2609 BT_MOVE(cur_base_params, params);
2610 break;
2611 }
2612 case OPT_RESET_BASE_PARAMS:
2613 BT_PUT(cur_base_params);
2614 cur_base_params = bt_value_map_create();
2615 if (!cur_base_params) {
2616 print_err_oom();
2617 goto error;
2618 }
2619 break;
015cee23
PP
2620 case OPT_BASE_BEGIN_NS:
2621 if (ns_from_arg(arg, &cur_base_begin_ns)) {
2622 printf_err("Invalid --base-begin-ns option's argument:\n %s\n",
2623 arg);
2624 goto error;
2625 }
8ff0b830 2626 cur_base_begin_ns_set = true;
015cee23
PP
2627 break;
2628 case OPT_BASE_END_NS:
2629 if (ns_from_arg(arg, &cur_base_end_ns)) {
2630 printf_err("Invalid --base-end-ns option's argument:\n %s\n",
2631 arg);
2632 goto error;
2633 }
8ff0b830 2634 cur_base_end_ns_set = true;
015cee23
PP
2635 break;
2636 case OPT_RESET_BASE_BEGIN_NS:
8ff0b830
JG
2637 cur_base_begin_ns = 0;
2638 cur_base_begin_ns = false;
015cee23
PP
2639 break;
2640 case OPT_RESET_BASE_END_NS:
8ff0b830
JG
2641 cur_base_end_ns = 0;
2642 cur_base_end_ns = false;
015cee23
PP
2643 break;
2644 case OPT_BEGIN_NS:
2645 if (!cur_cfg_comp || cur_cfg_comp_dest ==
2646 BT_CONFIG_COMPONENT_DEST_SINK) {
2647 printf_err("--begin-ns option must follow a --source option\n");
2648 goto error;
2649 }
2650
8ff0b830 2651 if (ns_from_arg(arg, &cur_cfg_comp->begin.value_ns)) {
015cee23
PP
2652 printf_err("Invalid --begin-ns option's argument:\n %s\n",
2653 arg);
2654 goto error;
2655 }
8ff0b830 2656 cur_cfg_comp->begin.set = true;
015cee23
PP
2657 break;
2658 case OPT_END_NS:
2659 if (!cur_cfg_comp || cur_cfg_comp_dest ==
2660 BT_CONFIG_COMPONENT_DEST_SINK) {
2661 printf_err("--end-ns option must follow a --source option\n");
2662 goto error;
2663 }
2664
8ff0b830 2665 if (ns_from_arg(arg, &cur_cfg_comp->end.value_ns)) {
015cee23
PP
2666 printf_err("Invalid --end-ns option's argument:\n %s\n",
2667 arg);
2668 goto error;
2669 }
8ff0b830 2670 cur_cfg_comp->end.set = true;
015cee23 2671 break;
c42c79ea
PP
2672 case OPT_NAMES:
2673 if (text_legacy_opts.names) {
2674 printf_err("Duplicate --names option\n");
2675 goto error;
2676 }
2677
2678 text_legacy_opts.names = names_from_arg(arg);
2679 if (!text_legacy_opts.names) {
2680 printf_err("Invalid --names option's argument\n");
2681 goto error;
2682 }
2683 break;
2684 case OPT_FIELDS:
2685 if (text_legacy_opts.fields) {
2686 printf_err("Duplicate --fields option\n");
2687 goto error;
2688 }
2689
2690 text_legacy_opts.fields = fields_from_arg(arg);
2691 if (!text_legacy_opts.fields) {
2692 printf_err("Invalid --fields option's argument\n");
2693 goto error;
2694 }
2695 break;
2696 case OPT_NO_DELTA:
2697 text_legacy_opts.no_delta = true;
2698 break;
2699 case OPT_CLOCK_CYCLES:
2700 text_legacy_opts.clock_cycles = true;
2701 break;
2702 case OPT_CLOCK_SECONDS:
2703 text_legacy_opts.clock_seconds = true;
2704 break;
2705 case OPT_CLOCK_DATE:
2706 text_legacy_opts.clock_date = true;
2707 break;
2708 case OPT_CLOCK_GMT:
2709 text_legacy_opts.clock_gmt = true;
2710 break;
2711 case OPT_DEBUG_INFO_FULL_PATH:
2712 text_legacy_opts.dbg_info_full_path = true;
2713 break;
2714 case OPT_CLOCK_OFFSET:
2715 {
2716 int64_t val;
2717
2718 if (ctf_legacy_opts.offset_s.is_set) {
2719 printf_err("Duplicate --clock-offset option\n");
2720 goto error;
2721 }
2722
2723 if (parse_int64(arg, &val)) {
2724 printf_err("Invalid --clock-offset option's argument\n");
2725 goto error;
2726 }
2727
2728 set_offset_value(&ctf_legacy_opts.offset_s, val);
2729 break;
2730 }
2731 case OPT_CLOCK_OFFSET_NS:
2732 {
2733 int64_t val;
2734
2735 if (ctf_legacy_opts.offset_ns.is_set) {
2736 printf_err("Duplicate --clock-offset-ns option\n");
2737 goto error;
2738 }
2739
2740 if (parse_int64(arg, &val)) {
2741 printf_err("Invalid --clock-offset-ns option's argument\n");
2742 goto error;
2743 }
2744
2745 set_offset_value(&ctf_legacy_opts.offset_ns, val);
2746 break;
2747 }
2748 case OPT_STREAM_INTERSECTION:
2749 ctf_legacy_opts.stream_intersection = true;
2750 break;
2751 case OPT_CLOCK_FORCE_CORRELATE:
2752 cfg->force_correlate = true;
2753 break;
2754 case OPT_HELP:
2755 BT_PUT(cfg);
2756 print_usage(stdout);
2757 goto end;
2758 case OPT_HELP_LEGACY:
2759 BT_PUT(cfg);
2760 print_legacy_usage(stdout);
2761 goto end;
2762 case OPT_VERSION:
2763 BT_PUT(cfg);
2764 print_version();
2765 goto end;
2766 case OPT_LIST:
2767 cfg->do_list = true;
2768 goto end;
2769 case OPT_VERBOSE:
2770 cfg->verbose = true;
2771 break;
2772 case OPT_DEBUG:
2773 cfg->debug = true;
2774 break;
2775 default:
2776 printf_err("Unknown command-line option specified (option code %d)\n",
2777 opt);
2778 goto error;
2779 }
2780
2781 free(arg);
2782 arg = NULL;
2783 }
2784
bdc61c70
PP
2785 /* Append current component configuration, if any */
2786 if (cur_cfg_comp) {
2787 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
2788 cur_cfg_comp = NULL;
2789 }
2790
c42c79ea
PP
2791 /* Check for option parsing error */
2792 if (opt < -1) {
2793 printf_err("While parsing command-line options, at option %s: %s\n",
2794 poptBadOption(pc, 0), poptStrerror(opt));
2795 goto error;
2796 }
2797
2798 /* Consume leftover arguments as legacy input paths */
2799 while (true) {
2800 const char *input_path = poptGetArg(pc);
2801
2802 if (!input_path) {
2803 break;
2804 }
2805
2806 if (bt_value_array_append_string(legacy_input_paths,
2807 input_path)) {
2808 print_err_oom();
2809 goto error;
2810 }
2811 }
2812
2813 /* Validate legacy/non-legacy options */
2814 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
2815 legacy_input_paths, &ctf_legacy_opts,
2816 &text_legacy_opts)) {
2817 printf_err("Command-line options form an invalid configuration\n");
2818 goto error;
2819 }
2820
2821 /*
2822 * If there's a legacy input format, convert it to source
2823 * component configurations.
2824 */
2825 if (legacy_input_format) {
2826 if (append_sources_from_legacy_opts(cfg->sources,
2827 legacy_input_format, &ctf_legacy_opts,
8ff0b830
JG
2828 legacy_input_paths,
2829 cur_base_begin_ns_set ? &cur_base_begin_ns : NULL,
2830 cur_base_end_ns_set ? &cur_base_end_ns : NULL)) {
49849a47 2831 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
2832 goto error;
2833 }
2834 }
2835
2836 /*
2837 * If there's a legacy output format, convert it to sink
2838 * component configurations.
2839 */
2840 if (legacy_output_format) {
2841 if (append_sinks_from_legacy_opts(cfg->sinks,
2842 legacy_output_format, &text_legacy_opts)) {
49849a47 2843 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
2844 goto error;
2845 }
2846 }
2847
015cee23
PP
2848 for (i = 0; i < cfg->sources->len; i++) {
2849 struct bt_config_component *cfg_component =
2850 bt_config_get_component(cfg->sources, i);
2851
2852 /* Only peek */
2853 bt_put(cfg_component);
2854
2855 if (!validate_source_config_component(cfg_component)) {
49849a47 2856 printf_err("Invalid source component instance (class %s.%s)\n",
015cee23
PP
2857 cfg_component->plugin_name->str,
2858 cfg_component->component_name->str);
2859 goto error;
2860 }
2861 }
2862
c42c79ea
PP
2863 goto end;
2864
2865error:
2866 BT_PUT(cfg);
2867 cfg = NULL;
2868 *exit_code = 1;
2869
2870end:
2871 if (pc) {
2872 poptFreeContext(pc);
2873 }
2874
2875 if (text_legacy_opts.output) {
2876 g_string_free(text_legacy_opts.output, TRUE);
2877 }
2878
2879 if (text_legacy_opts.dbg_info_dir) {
2880 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
2881 }
2882
2883 if (text_legacy_opts.dbg_info_target_prefix) {
2884 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
2885 }
2886
2887 free(arg);
bdc61c70 2888 BT_PUT(cur_cfg_comp);
b07ffa28 2889 BT_PUT(cur_base_params);
c42c79ea
PP
2890 BT_PUT(text_legacy_opts.names);
2891 BT_PUT(text_legacy_opts.fields);
2892 BT_PUT(legacy_input_paths);
2893 return cfg;
2894}
This page took 0.138712 seconds and 4 git commands to generate.