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