bt2: test comp. class help attribute
[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");
c42c79ea
PP
767 fprintf(fp, " -d, --debug Enable debug mode\n");
768 fprintf(fp, " -l, --list List available plugins and their components\n");
ad6a19bd
PP
769 fprintf(fp, " -P, --path=PATH Set the `path` parameter of the latest source\n");
770 fprintf(fp, " or sink component to PATH\n");
bdc61c70 771 fprintf(fp, " -p, --params=PARAMS Set the parameters of the latest source or\n");
b07ffa28
PP
772 fprintf(fp, " sink component instance (in command-line \n");
773 fprintf(fp, " order) to PARAMS (see the exact format of\n");
774 fprintf(fp, " PARAMS below)\n");
ad6a19bd 775 fprintf(fp, " --plugin-path=PATH[:PATH]... Set paths from which dynamic plugins can be\n");
015cee23 776 fprintf(fp, " loaded to PATH\n");
b07ffa28
PP
777 fprintf(fp, " -r, --reset-base-params Reset the current base parameters of the\n");
778 fprintf(fp, " following source and sink component\n");
779 fprintf(fp, " instances to an empty map\n");
015cee23
PP
780 fprintf(fp, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
781 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
782 fprintf(fp, " repeated)\n");
783 fprintf(fp, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
784 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
785 fprintf(fp, " repeated)\n");
0f9915c6
MD
786 fprintf(fp, " --begin Start time: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
787 fprintf(fp, " --end End time: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
788 fprintf(fp, " --timerange Time range: begin,end or [begin,end] (where [] are actual brackets)\n");
98ecef32
MD
789 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
790 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
bdc61c70
PP
791 fprintf(fp, " -h --help Show this help\n");
792 fprintf(fp, " --help-legacy Show Babeltrace 1.x legacy options\n");
c42c79ea
PP
793 fprintf(fp, " -v, --verbose Enable verbose output\n");
794 fprintf(fp, " -V, --version Show version\n");
bdc61c70 795 fprintf(fp, "\n\n");
b07ffa28
PP
796 fprintf(fp, "Format of PARAMS\n");
797 fprintf(fp, "----------------\n");
c42c79ea 798 fprintf(fp, "\n");
bdc61c70 799 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
c42c79ea 800 fprintf(fp, "\n");
bdc61c70
PP
801 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
802 fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
803 fprintf(fp, "VALUE can be one of:\n");
c42c79ea 804 fprintf(fp, "\n");
bdc61c70
PP
805 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
806 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
807 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
808 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
809 fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n");
810 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
811 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
812 fprintf(fp, " the null and boolean value symbols above.\n");
813 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
c42c79ea 814 fprintf(fp, "\n");
bdc61c70 815 fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
c42c79ea 816 fprintf(fp, "\n");
bdc61c70 817 fprintf(fp, "Example:\n");
c42c79ea 818 fprintf(fp, "\n");
bdc61c70
PP
819 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
820 fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
821 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
c42c79ea 822 fprintf(fp, "\n");
bdc61c70
PP
823 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
824 fprintf(fp, "from a shell.\n");
c42c79ea
PP
825}
826
827/*
828 * Destroys a component configuration.
829 */
830static
831void bt_config_component_destroy(struct bt_object *obj)
832{
833 struct bt_config_component *bt_config_component =
834 container_of(obj, struct bt_config_component, base);
835
836 if (!obj) {
837 goto end;
838 }
839
840 if (bt_config_component->plugin_name) {
841 g_string_free(bt_config_component->plugin_name, TRUE);
842 }
843
844 if (bt_config_component->component_name) {
845 g_string_free(bt_config_component->component_name, TRUE);
846 }
847
848 BT_PUT(bt_config_component->params);
849 g_free(bt_config_component);
850
851end:
852 return;
853}
854
855/*
bdc61c70
PP
856 * Creates a component configuration using the given plugin name and
857 * component name. plugin_name and component_name are copied (belong to
858 * the return value).
c42c79ea
PP
859 *
860 * Return value is owned by the caller.
861 */
862static
863struct bt_config_component *bt_config_component_create(const char *plugin_name,
bdc61c70 864 const char *component_name)
c42c79ea
PP
865{
866 struct bt_config_component *cfg_component = NULL;
867
868 cfg_component = g_new0(struct bt_config_component, 1);
869 if (!cfg_component) {
870 print_err_oom();
871 goto error;
872 }
873
874 bt_object_init(cfg_component, bt_config_component_destroy);
875 cfg_component->plugin_name = g_string_new(plugin_name);
876 if (!cfg_component->plugin_name) {
877 print_err_oom();
878 goto error;
879 }
880
881 cfg_component->component_name = g_string_new(component_name);
882 if (!cfg_component->component_name) {
883 print_err_oom();
884 goto error;
885 }
886
bdc61c70
PP
887 /* Start with empty parameters */
888 cfg_component->params = bt_value_map_create();
889 if (!cfg_component->params) {
890 print_err_oom();
891 goto error;
892 }
893
c42c79ea
PP
894 goto end;
895
896error:
897 BT_PUT(cfg_component);
898
899end:
900 return cfg_component;
901}
902
903/*
904 * Creates a component configuration from a command-line source/sink
bdc61c70 905 * option's argument.
c42c79ea
PP
906 */
907static
908struct bt_config_component *bt_config_component_from_arg(const char *arg)
909{
910 struct bt_config_component *bt_config_component = NULL;
911 char *plugin_name;
912 char *component_name;
c42c79ea
PP
913
914 plugin_component_names_from_arg(arg, &plugin_name, &component_name);
915 if (!plugin_name || !component_name) {
49849a47 916 printf_err("Cannot get plugin or component class name\n");
c42c79ea
PP
917 goto error;
918 }
919
c42c79ea 920 bt_config_component = bt_config_component_create(plugin_name,
bdc61c70 921 component_name);
c42c79ea
PP
922 if (!bt_config_component) {
923 goto error;
924 }
925
926 goto end;
927
928error:
929 BT_PUT(bt_config_component);
930
931end:
bdc61c70
PP
932 g_free(plugin_name);
933 g_free(component_name);
c42c79ea
PP
934 return bt_config_component;
935}
936
937/*
938 * Destroys a configuration.
939 */
940static
941void bt_config_destroy(struct bt_object *obj)
942{
943 struct bt_config *bt_config =
944 container_of(obj, struct bt_config, base);
945
946 if (!obj) {
947 goto end;
948 }
949
950 if (bt_config->sources) {
951 g_ptr_array_free(bt_config->sources, TRUE);
952 }
953
954 if (bt_config->sinks) {
955 g_ptr_array_free(bt_config->sinks, TRUE);
956 }
957
958 BT_PUT(bt_config->plugin_paths);
959 g_free(bt_config);
960
961end:
962 return;
963}
964
98ecef32
MD
965static
966bool is_setuid_setgid(void)
967{
968 return (geteuid() != getuid() || getegid() != getgid());
969}
970
1670bffd
PP
971static void destroy_gstring(void *data)
972{
973 g_string_free(data, TRUE);
974}
975
c42c79ea
PP
976/*
977 * Extracts the various paths from the string arg, delimited by ':',
978 * and converts them to an array value object.
979 *
980 * Returned array value object is empty if arg is empty.
981 *
982 * Return value is owned by the caller.
983 */
984static
98ecef32
MD
985enum bt_value_status plugin_paths_from_arg(struct bt_value *plugin_paths,
986 const char *arg)
c42c79ea 987{
1670bffd
PP
988 enum bt_value_status status = BT_VALUE_STATUS_OK;
989 GPtrArray *dirs = g_ptr_array_new_with_free_func(destroy_gstring);
990 int ret;
991 size_t i;
c42c79ea 992
1670bffd
PP
993 if (!dirs) {
994 status = BT_VALUE_STATUS_ERROR;
995 goto end;
996 }
c42c79ea 997
1670bffd
PP
998 ret = bt_common_append_plugin_path_dirs(arg, dirs);
999 if (ret) {
1000 status = BT_VALUE_STATUS_ERROR;
1001 goto end;
1002 }
c42c79ea 1003
1670bffd
PP
1004 for (i = 0; i < dirs->len; i++) {
1005 GString *dir = g_ptr_array_index(dirs, i);
c42c79ea 1006
1670bffd 1007 bt_value_array_append_string(plugin_paths, dir->str);
c42c79ea
PP
1008 }
1009
1670bffd
PP
1010end:
1011 g_ptr_array_free(dirs, TRUE);
1012 return status;
c42c79ea
PP
1013}
1014
1015/*
1016 * Creates a simple lexical scanner for parsing comma-delimited names
1017 * and fields.
1018 *
1019 * Return value is owned by the caller.
1020 */
1021static
1022GScanner *create_csv_identifiers_scanner(void)
1023{
1024 GScannerConfig scanner_config = {
1025 .cset_skip_characters = " \t\n",
1026 .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
1027 .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
1028 .case_sensitive = TRUE,
1029 .cpair_comment_single = NULL,
1030 .skip_comment_multi = TRUE,
1031 .skip_comment_single = TRUE,
1032 .scan_comment_multi = FALSE,
1033 .scan_identifier = TRUE,
1034 .scan_identifier_1char = TRUE,
1035 .scan_identifier_NULL = FALSE,
1036 .scan_symbols = FALSE,
1037 .symbol_2_token = FALSE,
1038 .scope_0_fallback = FALSE,
1039 .scan_binary = FALSE,
1040 .scan_octal = FALSE,
1041 .scan_float = FALSE,
1042 .scan_hex = FALSE,
1043 .scan_hex_dollar = FALSE,
1044 .numbers_2_int = FALSE,
1045 .int_2_float = FALSE,
1046 .store_int64 = FALSE,
1047 .scan_string_sq = FALSE,
1048 .scan_string_dq = FALSE,
1049 .identifier_2_string = FALSE,
1050 .char_2_token = TRUE,
1051 };
1052
1053 return g_scanner_new(&scanner_config);
1054}
1055
6e1bc0df
MD
1056/*
1057 * Inserts a string (if exists and not empty) or null to a map value
1058 * object.
1059 */
1060static
1061enum bt_value_status map_insert_string_or_null(struct bt_value *map,
1062 const char *key, GString *string)
1063{
1064 enum bt_value_status ret;
1065
1066 if (string && string->len > 0) {
1067 ret = bt_value_map_insert_string(map, key, string->str);
1068 } else {
1069 ret = bt_value_map_insert(map, key, bt_value_null);
1070 }
1071 return ret;
1072}
1073
c42c79ea
PP
1074/*
1075 * Converts a comma-delimited list of known names (--names option) to
1076 * an array value object containing those names as string value objects.
1077 *
1078 * Return value is owned by the caller.
1079 */
1080static
1081struct bt_value *names_from_arg(const char *arg)
1082{
1083 GScanner *scanner = NULL;
1084 struct bt_value *names = NULL;
6e1bc0df 1085 bool found_all = false, found_none = false, found_item = false;
c42c79ea
PP
1086
1087 names = bt_value_array_create();
1088 if (!names) {
1089 print_err_oom();
1090 goto error;
1091 }
1092
1093 scanner = create_csv_identifiers_scanner();
1094 if (!scanner) {
1095 print_err_oom();
1096 goto error;
1097 }
1098
1099 g_scanner_input_text(scanner, arg, strlen(arg));
1100
1101 while (true) {
1102 GTokenType token_type = g_scanner_get_next_token(scanner);
1103
1104 switch (token_type) {
1105 case G_TOKEN_IDENTIFIER:
1106 {
1107 const char *identifier = scanner->value.v_identifier;
1108
1109 if (!strcmp(identifier, "payload") ||
1110 !strcmp(identifier, "args") ||
1111 !strcmp(identifier, "arg")) {
6e1bc0df 1112 found_item = true;
c42c79ea
PP
1113 if (bt_value_array_append_string(names,
1114 "payload")) {
1115 goto error;
1116 }
1117 } else if (!strcmp(identifier, "context") ||
1118 !strcmp(identifier, "ctx")) {
6e1bc0df 1119 found_item = true;
c42c79ea
PP
1120 if (bt_value_array_append_string(names,
1121 "context")) {
1122 goto error;
1123 }
1124 } else if (!strcmp(identifier, "scope") ||
1125 !strcmp(identifier, "header")) {
6e1bc0df 1126 found_item = true;
c42c79ea
PP
1127 if (bt_value_array_append_string(names,
1128 identifier)) {
1129 goto error;
1130 }
6e1bc0df
MD
1131 } else if (!strcmp(identifier, "all")) {
1132 found_all = true;
1133 if (bt_value_array_append_string(names,
1134 identifier)) {
c42c79ea
PP
1135 goto error;
1136 }
6e1bc0df
MD
1137 } else if (!strcmp(identifier, "none")) {
1138 found_none = true;
c42c79ea
PP
1139 if (bt_value_array_append_string(names,
1140 identifier)) {
1141 goto error;
1142 }
c42c79ea 1143 } else {
6d1d5711 1144 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1145 identifier);
1146 goto error;
1147 }
1148 break;
1149 }
1150 case G_TOKEN_COMMA:
1151 continue;
1152 case G_TOKEN_EOF:
1153 goto end;
1154 default:
1155 goto error;
1156 }
1157 }
1158
6e1bc0df
MD
1159end:
1160 if (found_none && found_all) {
6d1d5711 1161 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
6e1bc0df
MD
1162 goto error;
1163 }
1164 /*
1165 * Legacy behavior is to clear the defaults (show none) when at
1166 * least one item is specified.
1167 */
1168 if (found_item && !found_none && !found_all) {
1169 if (bt_value_array_append_string(names, "none")) {
1170 goto error;
1171 }
1172 }
1173 if (scanner) {
1174 g_scanner_destroy(scanner);
1175 }
1176 return names;
c42c79ea
PP
1177
1178error:
1179 BT_PUT(names);
c42c79ea
PP
1180 if (scanner) {
1181 g_scanner_destroy(scanner);
1182 }
1183 return names;
1184}
1185
1186
1187/*
1188 * Converts a comma-delimited list of known fields (--fields option) to
1189 * an array value object containing those fields as string
1190 * value objects.
1191 *
1192 * Return value is owned by the caller.
1193 */
1194static
1195struct bt_value *fields_from_arg(const char *arg)
1196{
1197 GScanner *scanner = NULL;
1198 struct bt_value *fields;
1199
1200 fields = bt_value_array_create();
1201 if (!fields) {
1202 print_err_oom();
1203 goto error;
1204 }
1205
1206 scanner = create_csv_identifiers_scanner();
1207 if (!scanner) {
1208 print_err_oom();
1209 goto error;
1210 }
1211
1212 g_scanner_input_text(scanner, arg, strlen(arg));
1213
1214 while (true) {
1215 GTokenType token_type = g_scanner_get_next_token(scanner);
1216
1217 switch (token_type) {
1218 case G_TOKEN_IDENTIFIER:
1219 {
1220 const char *identifier = scanner->value.v_identifier;
1221
1222 if (!strcmp(identifier, "trace") ||
1223 !strcmp(identifier, "trace:hostname") ||
1224 !strcmp(identifier, "trace:domain") ||
1225 !strcmp(identifier, "trace:procname") ||
1226 !strcmp(identifier, "trace:vpid") ||
1227 !strcmp(identifier, "loglevel") ||
1228 !strcmp(identifier, "emf") ||
6e1bc0df
MD
1229 !strcmp(identifier, "callsite") ||
1230 !strcmp(identifier, "all")) {
c42c79ea
PP
1231 if (bt_value_array_append_string(fields,
1232 identifier)) {
1233 goto error;
1234 }
c42c79ea 1235 } else {
6d1d5711 1236 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1237 identifier);
1238 goto error;
1239 }
1240 break;
1241 }
1242 case G_TOKEN_COMMA:
1243 continue;
1244 case G_TOKEN_EOF:
1245 goto end;
1246 default:
1247 goto error;
1248 }
1249 }
1250
1251 goto end;
1252
1253error:
1254 BT_PUT(fields);
1255
1256end:
1257 if (scanner) {
1258 g_scanner_destroy(scanner);
1259 }
1260 return fields;
1261}
1262
1263/*
1264 * Inserts the equivalent "prefix-name" true boolean value objects into
1265 * map_obj where the names are in array_obj.
1266 */
1267static
1268int insert_flat_names_fields_from_array(struct bt_value *map_obj,
1269 struct bt_value *array_obj, const char *prefix)
1270{
1271 int ret = 0;
1272 int i;
6e1bc0df 1273 GString *tmpstr = NULL, *default_value = NULL;
c42c79ea
PP
1274
1275 /*
1276 * array_obj may be NULL if no CLI options were specified to
1277 * trigger its creation.
1278 */
1279 if (!array_obj) {
1280 goto end;
1281 }
1282
1283 tmpstr = g_string_new(NULL);
1284 if (!tmpstr) {
1285 print_err_oom();
1286 ret = -1;
1287 goto end;
1288 }
1289
6e1bc0df
MD
1290 default_value = g_string_new(NULL);
1291 if (!default_value) {
1292 print_err_oom();
1293 ret = -1;
1294 goto end;
1295 }
1296
c42c79ea
PP
1297 for (i = 0; i < bt_value_array_size(array_obj); i++) {
1298 struct bt_value *str_obj = bt_value_array_get(array_obj, i);
1299 const char *suffix;
6e1bc0df 1300 bool is_default = false;
c42c79ea
PP
1301
1302 if (!str_obj) {
1303 printf_err("Unexpected error\n");
1304 ret = -1;
1305 goto end;
1306 }
1307
1308 ret = bt_value_string_get(str_obj, &suffix);
1309 BT_PUT(str_obj);
1310 if (ret) {
1311 printf_err("Unexpected error\n");
1312 goto end;
1313 }
1314
1315 g_string_assign(tmpstr, prefix);
1316 g_string_append(tmpstr, "-");
6e1bc0df
MD
1317
1318 /* Special-case for "all" and "none". */
1319 if (!strcmp(suffix, "all")) {
1320 is_default = true;
1321 g_string_assign(default_value, "show");
1322 } else if (!strcmp(suffix, "none")) {
1323 is_default = true;
1324 g_string_assign(default_value, "hide");
1325 }
1326 if (is_default) {
1327 g_string_append(tmpstr, "default");
1328 ret = map_insert_string_or_null(map_obj,
1329 tmpstr->str,
1330 default_value);
1331 if (ret) {
1332 print_err_oom();
1333 goto end;
1334 }
1335 } else {
1336 g_string_append(tmpstr, suffix);
1337 ret = bt_value_map_insert_bool(map_obj, tmpstr->str,
1338 true);
1339 if (ret) {
1340 print_err_oom();
1341 goto end;
1342 }
c42c79ea
PP
1343 }
1344 }
1345
1346end:
6e1bc0df
MD
1347 if (default_value) {
1348 g_string_free(default_value, TRUE);
1349 }
c42c79ea
PP
1350 if (tmpstr) {
1351 g_string_free(tmpstr, TRUE);
1352 }
1353
1354 return ret;
1355}
1356
c42c79ea
PP
1357/*
1358 * Returns the parameters (map value object) corresponding to the
1359 * legacy text format options.
1360 *
1361 * Return value is owned by the caller.
1362 */
1363static
1364struct bt_value *params_from_text_legacy_opts(
1365 struct text_legacy_opts *text_legacy_opts)
1366{
1367 struct bt_value *params;
1368
1369 params = bt_value_map_create();
1370 if (!params) {
1371 print_err_oom();
1372 goto error;
1373 }
1374
1375 if (map_insert_string_or_null(params, "output-path",
1376 text_legacy_opts->output)) {
1377 print_err_oom();
1378 goto error;
1379 }
1380
1381 if (map_insert_string_or_null(params, "debug-info-dir",
1382 text_legacy_opts->dbg_info_dir)) {
1383 print_err_oom();
1384 goto error;
1385 }
1386
1387 if (map_insert_string_or_null(params, "debug-info-target-prefix",
1388 text_legacy_opts->dbg_info_target_prefix)) {
1389 print_err_oom();
1390 goto error;
1391 }
1392
1393 if (bt_value_map_insert_bool(params, "debug-info-full-path",
1394 text_legacy_opts->dbg_info_full_path)) {
1395 print_err_oom();
1396 goto error;
1397 }
1398
1399 if (bt_value_map_insert_bool(params, "no-delta",
1400 text_legacy_opts->no_delta)) {
1401 print_err_oom();
1402 goto error;
1403 }
1404
1405 if (bt_value_map_insert_bool(params, "clock-cycles",
1406 text_legacy_opts->clock_cycles)) {
1407 print_err_oom();
1408 goto error;
1409 }
1410
1411 if (bt_value_map_insert_bool(params, "clock-seconds",
1412 text_legacy_opts->clock_seconds)) {
1413 print_err_oom();
1414 goto error;
1415 }
1416
1417 if (bt_value_map_insert_bool(params, "clock-date",
1418 text_legacy_opts->clock_date)) {
1419 print_err_oom();
1420 goto error;
1421 }
1422
1423 if (bt_value_map_insert_bool(params, "clock-gmt",
1424 text_legacy_opts->clock_gmt)) {
1425 print_err_oom();
1426 goto error;
1427 }
1428
1429 if (insert_flat_names_fields_from_array(params,
1430 text_legacy_opts->names, "name")) {
1431 goto error;
1432 }
1433
1434 if (insert_flat_names_fields_from_array(params,
1435 text_legacy_opts->fields, "field")) {
1436 goto error;
1437 }
1438
1439 goto end;
1440
1441error:
1442 BT_PUT(params);
1443
1444end:
1445 return params;
1446}
1447
1448static
1449int append_sinks_from_legacy_opts(GPtrArray *sinks,
1450 enum legacy_output_format legacy_output_format,
1451 struct text_legacy_opts *text_legacy_opts)
1452{
1453 int ret = 0;
1454 struct bt_value *params = NULL;
1455 const char *plugin_name;
1456 const char *component_name;
1457 struct bt_config_component *bt_config_component = NULL;
1458
1459 switch (legacy_output_format) {
1460 case LEGACY_OUTPUT_FORMAT_TEXT:
1461 plugin_name = "text";
1462 component_name = "text";
1463 break;
1464 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1465 plugin_name = "ctf";
1466 component_name = "metadata-text";
1467 break;
1468 case LEGACY_OUTPUT_FORMAT_DUMMY:
1469 plugin_name = "dummy";
1470 component_name = "dummy";
1471 break;
1472 default:
1473 assert(false);
1474 break;
1475 }
1476
1477 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT) {
1478 /* Legacy "text" output format has parameters */
1479 params = params_from_text_legacy_opts(text_legacy_opts);
1480 if (!params) {
1481 goto error;
1482 }
1483 } else {
1484 /*
1485 * Legacy "dummy" and "ctf-metadata" output formats do
1486 * not have parameters.
1487 */
1488 params = bt_value_map_create();
1489 if (!params) {
1490 print_err_oom();
1491 goto error;
1492 }
1493 }
1494
1495 /* Create a component configuration */
1496 bt_config_component = bt_config_component_create(plugin_name,
bdc61c70 1497 component_name);
c42c79ea
PP
1498 if (!bt_config_component) {
1499 goto error;
1500 }
1501
bdc61c70
PP
1502 BT_MOVE(bt_config_component->params, params);
1503
c42c79ea
PP
1504 /* Move created component configuration to the array */
1505 g_ptr_array_add(sinks, bt_config_component);
1506
1507 goto end;
1508
1509error:
1510 ret = -1;
1511
1512end:
1513 BT_PUT(params);
1514
1515 return ret;
1516}
1517
1518/*
1519 * Returns the parameters (map value object) corresponding to the
1520 * given legacy CTF format options.
1521 *
1522 * Return value is owned by the caller.
1523 */
1524static
1525struct bt_value *params_from_ctf_legacy_opts(
1526 struct ctf_legacy_opts *ctf_legacy_opts)
1527{
1528 struct bt_value *params;
1529
1530 params = bt_value_map_create();
1531 if (!params) {
1532 print_err_oom();
1533 goto error;
1534 }
1535
1536 if (bt_value_map_insert_integer(params, "offset-s",
1537 ctf_legacy_opts->offset_s.value)) {
1538 print_err_oom();
1539 goto error;
1540 }
1541
1542 if (bt_value_map_insert_integer(params, "offset-ns",
1543 ctf_legacy_opts->offset_ns.value)) {
1544 print_err_oom();
1545 goto error;
1546 }
1547
1548 if (bt_value_map_insert_bool(params, "stream-intersection",
1549 ctf_legacy_opts->stream_intersection)) {
1550 print_err_oom();
1551 goto error;
1552 }
1553
1554 goto end;
1555
1556error:
1557 BT_PUT(params);
1558
1559end:
1560 return params;
1561}
1562
1563static
1564int append_sources_from_legacy_opts(GPtrArray *sources,
1565 enum legacy_input_format legacy_input_format,
1566 struct ctf_legacy_opts *ctf_legacy_opts,
528debdf 1567 struct bt_value *legacy_input_paths)
c42c79ea
PP
1568{
1569 int ret = 0;
1570 int i;
1571 struct bt_value *base_params;
1572 struct bt_value *params = NULL;
1573 struct bt_value *input_path = NULL;
1574 struct bt_value *input_path_copy = NULL;
1575 const char *input_key;
1576 const char *component_name;
1577
1578 switch (legacy_input_format) {
1579 case LEGACY_INPUT_FORMAT_CTF:
1580 input_key = "path";
1581 component_name = "fs";
1582 break;
1583 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1584 input_key = "url";
1585 component_name = "lttng-live";
1586 break;
1587 default:
1588 assert(false);
1589 break;
1590 }
1591
1592 base_params = params_from_ctf_legacy_opts(ctf_legacy_opts);
1593 if (!base_params) {
1594 goto error;
1595 }
1596
1597 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1598 struct bt_config_component *bt_config_component = NULL;
1599
1600 /* Copy base parameters as current parameters */
1601 params = bt_value_copy(base_params);
1602 if (!params) {
1603 goto error;
1604 }
1605
1606 /* Get current input path string value object */
1607 input_path = bt_value_array_get(legacy_input_paths, i);
1608 if (!input_path) {
1609 goto error;
1610 }
1611
1612 /* Copy current input path value object */
1613 input_path_copy = bt_value_copy(input_path);
1614 if (!input_path_copy) {
1615 goto error;
1616 }
1617
1618 /* Insert input path value object into current parameters */
1619 ret = bt_value_map_insert(params, input_key, input_path_copy);
1620 if (ret) {
1621 goto error;
1622 }
1623
1624 /* Create a component configuration */
1625 bt_config_component = bt_config_component_create("ctf",
bdc61c70 1626 component_name);
c42c79ea
PP
1627 if (!bt_config_component) {
1628 goto error;
1629 }
1630
bdc61c70
PP
1631 BT_MOVE(bt_config_component->params, params);
1632
c42c79ea
PP
1633 /* Move created component configuration to the array */
1634 g_ptr_array_add(sources, bt_config_component);
1635
1636 /* Put current stuff */
1637 BT_PUT(input_path);
1638 BT_PUT(input_path_copy);
c42c79ea
PP
1639 }
1640
1641 goto end;
1642
1643error:
1644 ret = -1;
1645
1646end:
1647 BT_PUT(base_params);
1648 BT_PUT(params);
1649 BT_PUT(input_path);
1650 BT_PUT(input_path_copy);
1651 return ret;
1652}
1653
1654/*
1655 * Escapes a string for the shell. The string is escaped knowing that
1656 * it's a parameter string value (double-quoted), and that it will be
1657 * entered between single quotes in the shell.
1658 *
1659 * Return value is owned by the caller.
1660 */
1661static
1662char *str_shell_escape(const char *input)
1663{
1664 char *ret = NULL;
1665 const char *at = input;
1666 GString *str = g_string_new(NULL);
1667
1668 if (!str) {
1669 goto end;
1670 }
1671
1672 while (*at != '\0') {
1673 switch (*at) {
1674 case '\\':
1675 g_string_append(str, "\\\\");
1676 break;
1677 case '"':
1678 g_string_append(str, "\\\"");
1679 break;
1680 case '\'':
1681 g_string_append(str, "'\"'\"'");
1682 break;
1683 case '\n':
1684 g_string_append(str, "\\n");
1685 break;
1686 case '\t':
1687 g_string_append(str, "\\t");
1688 break;
1689 default:
1690 g_string_append_c(str, *at);
1691 break;
1692 }
1693
1694 at++;
1695 }
1696
1697end:
1698 if (str) {
1699 ret = str->str;
1700 g_string_free(str, FALSE);
1701 }
1702
1703 return ret;
1704}
1705
1706static
1707int append_prefixed_flag_params(GString *str, struct bt_value *flags,
1708 const char *prefix)
1709{
1710 int ret = 0;
1711 int i;
1712
1713 if (!flags) {
1714 goto end;
1715 }
1716
1717 for (i = 0; i < bt_value_array_size(flags); i++) {
1718 struct bt_value *value = bt_value_array_get(flags, i);
1719 const char *flag;
1720
1721 if (!value) {
1722 ret = -1;
1723 goto end;
1724 }
1725
1726 if (bt_value_string_get(value, &flag)) {
1727 BT_PUT(value);
1728 ret = -1;
1729 goto end;
1730 }
1731
1732 g_string_append_printf(str, ",%s-%s=true", prefix, flag);
1733 BT_PUT(value);
1734 }
1735
1736end:
1737 return ret;
1738}
1739
1740/*
1741 * Appends a boolean parameter string.
1742 */
1743static
1744void g_string_append_bool_param(GString *str, const char *name, bool value)
1745{
1746 g_string_append_printf(str, ",%s=%s", name, value ? "true" : "false");
1747}
1748
1749/*
1750 * Appends a path parameter string, or null if it's empty.
1751 */
1752static
1753int g_string_append_string_path_param(GString *str, const char *name,
1754 GString *path)
1755{
1756 int ret = 0;
1757
1758 if (path->len > 0) {
1759 char *escaped_path = str_shell_escape(path->str);
1760
1761 if (!escaped_path) {
1762 print_err_oom();
1763 goto error;
1764 }
1765
1766 g_string_append_printf(str, "%s=\"%s\"", name, escaped_path);
1767 free(escaped_path);
1768 } else {
1769 g_string_append_printf(str, "%s=null", name);
1770 }
1771
1772 goto end;
1773
1774error:
1775 ret = -1;
1776
1777end:
1778 return ret;
1779}
1780
1781/*
1782 * Prints the non-legacy sink options equivalent to the specified
1783 * legacy output format options.
1784 */
1785static
1786void print_output_legacy_to_sinks(
1787 enum legacy_output_format legacy_output_format,
1788 struct text_legacy_opts *text_legacy_opts)
1789{
1790 const char *input_format;
1791 GString *str = NULL;
1792
1793 str = g_string_new(" ");
1794 if (!str) {
1795 print_err_oom();
1796 goto end;
1797 }
1798
1799 switch (legacy_output_format) {
1800 case LEGACY_OUTPUT_FORMAT_TEXT:
1801 input_format = "text";
1802 break;
1803 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1804 input_format = "ctf-metadata";
1805 break;
1806 case LEGACY_OUTPUT_FORMAT_DUMMY:
1807 input_format = "dummy";
1808 break;
1809 default:
1810 assert(false);
1811 }
1812
49849a47 1813 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
c42c79ea 1814 input_format);
49849a47 1815 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
c42c79ea
PP
1816 input_format);
1817 g_string_append(str, "-o ");
1818
1819 switch (legacy_output_format) {
1820 case LEGACY_OUTPUT_FORMAT_TEXT:
1821 g_string_append(str, "text.text");
1822 break;
1823 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1824 g_string_append(str, "ctf.metadata-text");
1825 break;
1826 case LEGACY_OUTPUT_FORMAT_DUMMY:
1827 g_string_append(str, "dummy.dummy");
1828 break;
1829 default:
1830 assert(false);
1831 }
1832
1833 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT &&
1834 text_legacy_opts_is_any_set(text_legacy_opts)) {
1835 int ret;
1836
bdc61c70 1837 g_string_append(str, " -p '");
c42c79ea
PP
1838
1839 if (g_string_append_string_path_param(str, "output-path",
1840 text_legacy_opts->output)) {
1841 goto end;
1842 }
1843
1844 g_string_append(str, ",");
1845
1846 if (g_string_append_string_path_param(str, "debug-info-dir",
1847 text_legacy_opts->dbg_info_dir)) {
1848 goto end;
1849 }
1850
1851 g_string_append(str, ",");
1852
1853 if (g_string_append_string_path_param(str,
1854 "debug-info-target-prefix",
1855 text_legacy_opts->dbg_info_target_prefix)) {
1856 goto end;
1857 }
1858
1859 g_string_append_bool_param(str, "no-delta",
1860 text_legacy_opts->no_delta);
1861 g_string_append_bool_param(str, "clock-cycles",
1862 text_legacy_opts->clock_cycles);
1863 g_string_append_bool_param(str, "clock-seconds",
1864 text_legacy_opts->clock_seconds);
1865 g_string_append_bool_param(str, "clock-date",
1866 text_legacy_opts->clock_date);
1867 g_string_append_bool_param(str, "clock-gmt",
1868 text_legacy_opts->clock_gmt);
1869 ret = append_prefixed_flag_params(str, text_legacy_opts->names,
1870 "name");
1871 if (ret) {
1872 goto end;
1873 }
1874
1875 ret = append_prefixed_flag_params(str, text_legacy_opts->fields,
1876 "field");
1877 if (ret) {
1878 goto end;
1879 }
1880
1881 /* Remove last comma and close single quote */
1882 g_string_append(str, "'");
1883 }
1884
1885 printf_err("%s\n\n", str->str);
1886
1887end:
1888 if (str) {
1889 g_string_free(str, TRUE);
1890 }
1891 return;
1892}
1893
1894/*
1895 * Prints the non-legacy source options equivalent to the specified
1896 * legacy input format options.
1897 */
1898static
1899void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format,
1900 struct bt_value *legacy_input_paths,
1901 struct ctf_legacy_opts *ctf_legacy_opts)
1902{
1903 const char *input_format;
1904 GString *str = NULL;
1905 int i;
1906
1907 str = g_string_new(" ");
1908 if (!str) {
1909 print_err_oom();
1910 goto end;
1911 }
1912
1913 switch (legacy_input_format) {
1914 case LEGACY_INPUT_FORMAT_CTF:
1915 input_format = "ctf";
1916 break;
1917 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1918 input_format = "lttng-live";
1919 break;
1920 default:
1921 assert(false);
1922 }
1923
49849a47 1924 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
c42c79ea 1925 input_format);
49849a47 1926 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
1927 input_format);
1928
1929 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1930 struct bt_value *input_value =
1931 bt_value_array_get(legacy_input_paths, i);
1932 const char *input = NULL;
1933 char *escaped_input;
1934 int ret;
1935
1936 assert(input_value);
1937 ret = bt_value_string_get(input_value, &input);
1938 BT_PUT(input_value);
1939 assert(!ret && input);
1940 escaped_input = str_shell_escape(input);
1941 if (!escaped_input) {
1942 print_err_oom();
1943 goto end;
1944 }
1945
1946 g_string_append(str, "-i ctf.");
1947
1948 switch (legacy_input_format) {
1949 case LEGACY_INPUT_FORMAT_CTF:
bdc61c70 1950 g_string_append(str, "fs -p 'path=\"");
c42c79ea
PP
1951 break;
1952 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
bdc61c70 1953 g_string_append(str, "lttng-live -p 'url=\"");
c42c79ea
PP
1954 break;
1955 default:
1956 assert(false);
1957 }
1958
1959 g_string_append(str, escaped_input);
1960 g_string_append(str, "\"");
1961 g_string_append_printf(str, ",offset-s=%" PRId64,
1962 ctf_legacy_opts->offset_s.value);
1963 g_string_append_printf(str, ",offset-ns=%" PRId64,
1964 ctf_legacy_opts->offset_ns.value);
1965 g_string_append_bool_param(str, "stream-intersection",
1966 ctf_legacy_opts->stream_intersection);
1967 g_string_append(str, "' ");
1968 g_free(escaped_input);
1969 }
1970
1971 printf_err("%s\n\n", str->str);
1972
1973end:
1974 if (str) {
1975 g_string_free(str, TRUE);
1976 }
1977 return;
1978}
1979
1980/*
1981 * Validates a given configuration, with optional legacy input and
1982 * output formats options. Prints useful error messages if anything
1983 * is wrong.
1984 *
1985 * Returns true when the configuration is valid.
1986 */
1987static
1988bool validate_cfg(struct bt_config *cfg,
1989 enum legacy_input_format *legacy_input_format,
1990 enum legacy_output_format *legacy_output_format,
1991 struct bt_value *legacy_input_paths,
1992 struct ctf_legacy_opts *ctf_legacy_opts,
bd9f0fa2 1993 struct text_legacy_opts *text_legacy_opts)
c42c79ea
PP
1994{
1995 bool legacy_input = false;
1996 bool legacy_output = false;
1997
1998 /* Determine if the input and output should be legacy-style */
1999 if (*legacy_input_format != LEGACY_INPUT_FORMAT_NONE ||
c42c79ea
PP
2000 !bt_value_array_is_empty(legacy_input_paths) ||
2001 ctf_legacy_opts_is_any_set(ctf_legacy_opts)) {
2002 legacy_input = true;
2003 }
2004
2005 if (*legacy_output_format != LEGACY_OUTPUT_FORMAT_NONE ||
c42c79ea
PP
2006 text_legacy_opts_is_any_set(text_legacy_opts)) {
2007 legacy_output = true;
2008 }
2009
2010 if (legacy_input) {
2011 /* If no legacy input format was specified, default to CTF */
2012 if (*legacy_input_format == LEGACY_INPUT_FORMAT_NONE) {
2013 *legacy_input_format = LEGACY_INPUT_FORMAT_CTF;
2014 }
2015
2016 /* Make sure at least one input path exists */
2017 if (bt_value_array_is_empty(legacy_input_paths)) {
2018 switch (*legacy_input_format) {
2019 case LEGACY_INPUT_FORMAT_CTF:
6d1d5711 2020 printf_err("No input path specified for legacy `ctf` input format\n");
c42c79ea
PP
2021 break;
2022 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
6d1d5711 2023 printf_err("No URL specified for legacy `lttng-live` input format\n");
c42c79ea
PP
2024 break;
2025 default:
2026 assert(false);
2027 }
2028 goto error;
2029 }
2030
2031 /* Make sure no non-legacy sources are specified */
2032 if (cfg->sources->len != 0) {
2033 print_input_legacy_to_sources(*legacy_input_format,
2034 legacy_input_paths, ctf_legacy_opts);
2035 goto error;
2036 }
2037 }
2038
2039 if (legacy_output) {
2040 /*
2041 * If no legacy output format was specified, default to
2042 * "text".
2043 */
2044 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_NONE) {
2045 *legacy_output_format = LEGACY_OUTPUT_FORMAT_TEXT;
2046 }
2047
2048 /*
2049 * If any "text" option was specified, the output must be
2050 * legacy "text".
2051 */
2052 if (text_legacy_opts_is_any_set(text_legacy_opts) &&
2053 *legacy_output_format !=
2054 LEGACY_OUTPUT_FORMAT_TEXT) {
6d1d5711 2055 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
c42c79ea
PP
2056 goto error;
2057 }
2058
2059 /* Make sure no non-legacy sinks are specified */
2060 if (cfg->sinks->len != 0) {
2061 print_output_legacy_to_sinks(*legacy_output_format,
2062 text_legacy_opts);
2063 goto error;
2064 }
2065 }
2066
2067 /*
2068 * If the output is the legacy "ctf-metadata" format, then the
2069 * input should be the legacy "ctf" input format.
2070 */
2071 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_CTF_METADATA &&
2072 *legacy_input_format != LEGACY_INPUT_FORMAT_CTF) {
6d1d5711 2073 printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n");
c42c79ea
PP
2074 goto error;
2075 }
2076
2077 return true;
2078
2079error:
2080 return false;
2081}
2082
2083/*
2084 * Parses a 64-bit signed integer.
2085 *
2086 * Returns a negative value if anything goes wrong.
2087 */
2088static
2089int parse_int64(const char *arg, int64_t *val)
2090{
2091 char *endptr;
2092
2093 errno = 0;
2094 *val = strtoll(arg, &endptr, 0);
2095 if (*endptr != '\0' || arg == endptr || errno != 0) {
2096 return -1;
2097 }
2098
2099 return 0;
2100}
2101
2102/* popt options */
2103enum {
2104 OPT_NONE = 0,
b07ffa28 2105 OPT_BASE_PARAMS,
0f9915c6 2106 OPT_BEGIN,
c42c79ea
PP
2107 OPT_CLOCK_CYCLES,
2108 OPT_CLOCK_DATE,
2109 OPT_CLOCK_FORCE_CORRELATE,
2110 OPT_CLOCK_GMT,
2111 OPT_CLOCK_OFFSET,
2112 OPT_CLOCK_OFFSET_NS,
2113 OPT_CLOCK_SECONDS,
2114 OPT_DEBUG,
2115 OPT_DEBUG_INFO_DIR,
2116 OPT_DEBUG_INFO_FULL_PATH,
2117 OPT_DEBUG_INFO_TARGET_PREFIX,
0f9915c6 2118 OPT_END,
c42c79ea
PP
2119 OPT_FIELDS,
2120 OPT_HELP,
2121 OPT_HELP_LEGACY,
2122 OPT_INPUT_FORMAT,
2123 OPT_LIST,
2124 OPT_NAMES,
2125 OPT_NO_DELTA,
2126 OPT_OUTPUT_FORMAT,
2127 OPT_OUTPUT_PATH,
ad6a19bd 2128 OPT_PATH,
bdc61c70 2129 OPT_PARAMS,
c42c79ea 2130 OPT_PLUGIN_PATH,
b07ffa28 2131 OPT_RESET_BASE_PARAMS,
c42c79ea
PP
2132 OPT_SINK,
2133 OPT_SOURCE,
2134 OPT_STREAM_INTERSECTION,
0f9915c6 2135 OPT_TIMERANGE,
c42c79ea
PP
2136 OPT_VERBOSE,
2137 OPT_VERSION,
98ecef32
MD
2138 OPT_OMIT_SYSTEM_PLUGIN_PATH,
2139 OPT_OMIT_HOME_PLUGIN_PATH,
c42c79ea
PP
2140};
2141
2142/* popt long option descriptions */
2143static struct poptOption long_options[] = {
2144 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
b07ffa28 2145 { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
0f9915c6 2146 { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
c42c79ea
PP
2147 { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
2148 { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
2149 { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
2150 { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
2151 { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
2152 { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
2153 { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
2154 { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
2155 { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
2156 { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
2157 { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
0f9915c6 2158 { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
c42c79ea
PP
2159 { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
2160 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2161 { "help-legacy", '\0', POPT_ARG_NONE, NULL, OPT_HELP_LEGACY, NULL, NULL },
2162 { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
2163 { "list", 'l', POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL },
2164 { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
2165 { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
2166 { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
2167 { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
ad6a19bd 2168 { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
bdc61c70 2169 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
ad6a19bd 2170 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
b07ffa28 2171 { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
c42c79ea
PP
2172 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2173 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2174 { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
0f9915c6 2175 { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
c42c79ea
PP
2176 { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
2177 { "version", 'V', POPT_ARG_NONE, NULL, OPT_VERSION, NULL, NULL },
98ecef32
MD
2178 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2179 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
c42c79ea
PP
2180 { NULL, 0, 0, NULL, 0, NULL, NULL },
2181};
2182
2183/*
2184 * Sets the value of a given legacy offset option and marks it as set.
2185 */
2186static void set_offset_value(struct offset_opt *offset_opt, int64_t value)
2187{
2188 offset_opt->value = value;
2189 offset_opt->is_set = true;
2190}
2191
bdc61c70
PP
2192enum bt_config_component_dest {
2193 BT_CONFIG_COMPONENT_DEST_SOURCE,
2194 BT_CONFIG_COMPONENT_DEST_SINK,
2195};
2196
2197/*
2198 * Adds a configuration component to the appropriate configuration
2199 * array depending on the destination.
2200 */
2201static void add_cfg_comp(struct bt_config *cfg,
2202 struct bt_config_component *cfg_comp,
2203 enum bt_config_component_dest dest)
2204{
2205 if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
2206 g_ptr_array_add(cfg->sources, cfg_comp);
2207 } else {
2208 g_ptr_array_add(cfg->sinks, cfg_comp);
2209 }
2210}
2211
0f9915c6
MD
2212static int split_timerange(const char *arg, const char **begin, const char **end)
2213{
2214 const char *c;
2215
2216 /* Try to match [begin,end] */
2217 c = strchr(arg, '[');
2218 if (!c)
2219 goto skip;
2220 *begin = ++c;
2221 c = strchr(c, ',');
2222 if (!c)
2223 goto skip;
2224 *end = ++c;
2225 c = strchr(c, ']');
2226 if (!c)
2227 goto skip;
2228 goto found;
2229
2230skip:
2231 /* Try to match begin,end */
2232 c = arg;
2233 *begin = c;
2234 c = strchr(c, ',');
2235 if (!c)
2236 goto not_found;
2237 *end = ++c;
2238 /* fall-through */
2239found:
2240 return 0;
2241not_found:
2242 return -1;
2243}
2244
98ecef32
MD
2245static int add_internal_plugin_paths(struct bt_config *cfg)
2246{
1670bffd 2247 int ret;
98ecef32 2248
1670bffd
PP
2249 if (!cfg->omit_home_plugin_path) {
2250 if (bt_common_is_setuid_setgid()) {
98ecef32
MD
2251 printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
2252 } else {
1670bffd
PP
2253 char *home_plugin_dir =
2254 bt_common_get_home_plugin_path();
2255
2256 if (home_plugin_dir) {
2257 ret = plugin_paths_from_arg(cfg->plugin_paths,
2258 home_plugin_dir);
2259 free(home_plugin_dir);
2260
2261 if (ret) {
98ecef32
MD
2262 printf_err("Invalid home plugin path\n");
2263 goto error;
2264 }
2265 }
2266 }
2267 }
2268
c1870f57 2269 if (!cfg->omit_system_plugin_path) {
98ecef32 2270 if (plugin_paths_from_arg(cfg->plugin_paths,
1670bffd 2271 bt_common_get_system_plugin_path())) {
98ecef32
MD
2272 printf_err("Invalid system plugin path\n");
2273 goto error;
2274 }
2275 }
2276 return 0;
2277error:
2278 return -1;
2279}
2280
bd9f0fa2
MD
2281static int append_sources_from_implicit_params(GPtrArray *sources,
2282 struct bt_config_component *implicit_source_comp)
2283{
2284 size_t i;
2285 size_t len = sources->len;
2286
2287 for (i = 0; i < len; i++) {
2288 struct bt_config_component *comp;
2289 struct bt_value *params_to_set;
2290
2291 comp = g_ptr_array_index(sources, i);
2292 params_to_set = bt_value_map_extend(comp->params,
2293 implicit_source_comp->params);
2294 if (!params_to_set) {
2295 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2296 goto error;
2297 }
2298 BT_MOVE(comp->params, params_to_set);
2299 }
2300 return 0;
2301error:
2302 return -1;
2303}
2304
c1870f57
JG
2305struct bt_config *bt_config_create(void)
2306{
2307 struct bt_config *cfg;
2308
2309 /* Create config */
2310 cfg = g_new0(struct bt_config, 1);
2311 if (!cfg) {
2312 print_err_oom();
2313 goto error;
2314 }
2315
2316 bt_object_init(cfg, bt_config_destroy);
2317 cfg->sources = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
2318 if (!cfg->sources) {
2319 print_err_oom();
2320 goto error;
2321 }
2322
2323 cfg->sinks = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
2324 if (!cfg->sinks) {
2325 print_err_oom();
2326 goto error;
2327 }
2328
2329 cfg->plugin_paths = bt_value_array_create();
2330 if (!cfg->plugin_paths) {
2331 print_err_oom();
2332 goto error;
2333 }
2334end:
2335 return cfg;
2336error:
2337 BT_PUT(cfg);
2338 goto end;
2339}
2340
c42c79ea
PP
2341/*
2342 * Returns a Babeltrace configuration, out of command-line arguments,
2343 * containing everything that is needed to instanciate specific
2344 * components with given parameters.
2345 *
c1870f57 2346 * Return value is set to the appropriate exit code to use.
c42c79ea 2347 */
c1870f57 2348int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[])
c42c79ea 2349{
c42c79ea
PP
2350 poptContext pc = NULL;
2351 char *arg = NULL;
b7726e32
MD
2352 struct ctf_legacy_opts ctf_legacy_opts;
2353 struct text_legacy_opts text_legacy_opts;
c42c79ea
PP
2354 enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
2355 enum legacy_output_format legacy_output_format =
9a8a7bae 2356 LEGACY_OUTPUT_FORMAT_NONE;
c42c79ea 2357 struct bt_value *legacy_input_paths = NULL;
65582340 2358 struct bt_config_component *implicit_source_comp = NULL;
bdc61c70 2359 struct bt_config_component *cur_cfg_comp = NULL;
65582340
MD
2360 bool cur_is_implicit_source = false;
2361 bool use_implicit_source = false;
bdc61c70
PP
2362 enum bt_config_component_dest cur_cfg_comp_dest =
2363 BT_CONFIG_COMPONENT_DEST_SOURCE;
b07ffa28 2364 struct bt_value *cur_base_params = NULL;
c1870f57 2365 int opt, ret = 0;
c42c79ea 2366
b7726e32
MD
2367 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
2368 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
c42c79ea 2369
c42c79ea
PP
2370 text_legacy_opts.output = g_string_new(NULL);
2371 if (!text_legacy_opts.output) {
2372 print_err_oom();
2373 goto error;
2374 }
2375
2376 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
2377 if (!text_legacy_opts.dbg_info_dir) {
2378 print_err_oom();
2379 goto error;
2380 }
2381
2382 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
2383 if (!text_legacy_opts.dbg_info_target_prefix) {
2384 print_err_oom();
2385 goto error;
2386 }
2387
b07ffa28
PP
2388 cur_base_params = bt_value_map_create();
2389 if (!cur_base_params) {
2390 print_err_oom();
2391 goto error;
2392 }
2393
c42c79ea
PP
2394 legacy_input_paths = bt_value_array_create();
2395 if (!legacy_input_paths) {
2396 print_err_oom();
2397 goto error;
2398 }
2399
65582340
MD
2400 /* Note: implicit source never gets positional base params. */
2401 implicit_source_comp = bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME);
2402 if (implicit_source_comp) {
2403 cur_cfg_comp = implicit_source_comp;
2404 cur_is_implicit_source = true;
2405 use_implicit_source = true;
2406 } else {
2407 printf_debug("Cannot find implicit source plugin \"%s\"",
2408 DEFAULT_SOURCE_COMPONENT_NAME);
2409 }
2410
c42c79ea
PP
2411 /* Parse options */
2412 pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
2413 if (!pc) {
2414 printf_err("Cannot get popt context\n");
2415 goto error;
2416 }
2417
2418 poptReadDefaultConfig(pc, 0);
2419
2420 while ((opt = poptGetNextOpt(pc)) > 0) {
2421 arg = poptGetOptArg(pc);
2422
2423 switch (opt) {
2424 case OPT_PLUGIN_PATH:
98ecef32
MD
2425 if (is_setuid_setgid()) {
2426 printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
2427 } else {
2428 if (plugin_paths_from_arg(cfg->plugin_paths, arg)) {
2429 printf_err("Invalid --plugin-path option's argument\n");
2430 goto error;
2431 }
c42c79ea
PP
2432 }
2433 break;
98ecef32 2434 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
c1870f57 2435 cfg->omit_system_plugin_path = true;
98ecef32
MD
2436 break;
2437 case OPT_OMIT_HOME_PLUGIN_PATH:
c1870f57 2438 cfg->omit_home_plugin_path = true;
98ecef32 2439 break;
c42c79ea
PP
2440 case OPT_OUTPUT_PATH:
2441 if (text_legacy_opts.output->len > 0) {
2442 printf_err("Duplicate --output option\n");
2443 goto error;
2444 }
2445
2446 g_string_assign(text_legacy_opts.output, arg);
2447 break;
2448 case OPT_DEBUG_INFO_DIR:
2449 if (text_legacy_opts.dbg_info_dir->len > 0) {
2450 printf_err("Duplicate --debug-info-dir option\n");
2451 goto error;
2452 }
2453
2454 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
2455 break;
2456 case OPT_DEBUG_INFO_TARGET_PREFIX:
2457 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
2458 printf_err("Duplicate --debug-info-target-prefix option\n");
2459 goto error;
2460 }
2461
2462 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
2463 break;
2464 case OPT_INPUT_FORMAT:
2465 case OPT_SOURCE:
2466 {
c42c79ea
PP
2467 if (opt == OPT_INPUT_FORMAT) {
2468 if (!strcmp(arg, "ctf")) {
2469 /* Legacy CTF input format */
2470 if (legacy_input_format) {
2471 print_err_dup_legacy_input();
2472 goto error;
2473 }
2474
2475 legacy_input_format =
2476 LEGACY_INPUT_FORMAT_CTF;
2477 break;
2478 } else if (!strcmp(arg, "lttng-live")) {
2479 /* Legacy LTTng-live input format */
2480 if (legacy_input_format) {
2481 print_err_dup_legacy_input();
2482 goto error;
2483 }
2484
2485 legacy_input_format =
2486 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
2487 break;
2488 }
2489 }
2490
65582340
MD
2491 use_implicit_source = false;
2492
c42c79ea 2493 /* Non-legacy: try to create a component config */
65582340 2494 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
2495 add_cfg_comp(cfg, cur_cfg_comp,
2496 cur_cfg_comp_dest);
2497 }
2498
2499 cur_cfg_comp = bt_config_component_from_arg(arg);
2500 if (!cur_cfg_comp) {
49849a47 2501 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
2502 arg);
2503 goto error;
2504 }
65582340 2505 cur_is_implicit_source = false;
c42c79ea 2506
b07ffa28
PP
2507 assert(cur_base_params);
2508 bt_put(cur_cfg_comp->params);
c9313318 2509 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 2510 if (!cur_cfg_comp->params) {
c9313318
PP
2511 print_err_oom();
2512 goto end;
2513 }
2514
bdc61c70 2515 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
c42c79ea
PP
2516 break;
2517 }
2518 case OPT_OUTPUT_FORMAT:
2519 case OPT_SINK:
2520 {
c42c79ea
PP
2521 if (opt == OPT_OUTPUT_FORMAT) {
2522 if (!strcmp(arg, "text")) {
2523 /* Legacy CTF-text output format */
2524 if (legacy_output_format) {
2525 print_err_dup_legacy_output();
2526 goto error;
2527 }
2528
2529 legacy_output_format =
2530 LEGACY_OUTPUT_FORMAT_TEXT;
2531 break;
2532 } else if (!strcmp(arg, "dummy")) {
2533 /* Legacy dummy output format */
2534 if (legacy_output_format) {
2535 print_err_dup_legacy_output();
2536 goto error;
2537 }
2538
2539 legacy_output_format =
2540 LEGACY_OUTPUT_FORMAT_DUMMY;
2541 break;
2542 } else if (!strcmp(arg, "ctf-metadata")) {
2543 /* Legacy CTF-metadata output format */
2544 if (legacy_output_format) {
2545 print_err_dup_legacy_output();
2546 goto error;
2547 }
2548
2549 legacy_output_format =
2550 LEGACY_OUTPUT_FORMAT_CTF_METADATA;
2551 break;
2552 }
2553 }
2554
2555 /* Non-legacy: try to create a component config */
65582340 2556 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
2557 add_cfg_comp(cfg, cur_cfg_comp,
2558 cur_cfg_comp_dest);
2559 }
2560
2561 cur_cfg_comp = bt_config_component_from_arg(arg);
2562 if (!cur_cfg_comp) {
49849a47 2563 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
2564 arg);
2565 goto error;
2566 }
65582340 2567 cur_is_implicit_source = false;
c42c79ea 2568
b07ffa28
PP
2569 assert(cur_base_params);
2570 bt_put(cur_cfg_comp->params);
c9313318 2571 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 2572 if (!cur_cfg_comp->params) {
c9313318
PP
2573 print_err_oom();
2574 goto end;
2575 }
2576
bdc61c70 2577 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
bdc61c70
PP
2578 break;
2579 }
2580 case OPT_PARAMS:
2581 {
2582 struct bt_value *params;
b07ffa28 2583 struct bt_value *params_to_set;
bdc61c70
PP
2584
2585 if (!cur_cfg_comp) {
65582340
MD
2586 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2587 DEFAULT_SOURCE_COMPONENT_NAME);
bdc61c70
PP
2588 goto error;
2589 }
2590
bdc61c70
PP
2591 params = bt_value_from_arg(arg);
2592 if (!params) {
2593 printf_err("Invalid format for --params option's argument:\n %s\n",
2594 arg);
2595 goto error;
2596 }
2597
560ff91c 2598 params_to_set = bt_value_map_extend(cur_cfg_comp->params,
b07ffa28
PP
2599 params);
2600 BT_PUT(params);
2601 if (!params_to_set) {
560ff91c 2602 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
b07ffa28
PP
2603 arg);
2604 goto error;
2605 }
2606
2607 BT_MOVE(cur_cfg_comp->params, params_to_set);
c42c79ea
PP
2608 break;
2609 }
ad6a19bd
PP
2610 case OPT_PATH:
2611 if (!cur_cfg_comp) {
65582340
MD
2612 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2613 DEFAULT_SOURCE_COMPONENT_NAME);
ad6a19bd
PP
2614 goto error;
2615 }
2616
2617 assert(cur_cfg_comp->params);
2618
2619 if (bt_value_map_insert_string(cur_cfg_comp->params,
2620 "path", arg)) {
2621 print_err_oom();
2622 goto error;
2623 }
2624 break;
b07ffa28
PP
2625 case OPT_BASE_PARAMS:
2626 {
2627 struct bt_value *params = bt_value_from_arg(arg);
2628
2629 if (!params) {
2630 printf_err("Invalid format for --base-params option's argument:\n %s\n",
2631 arg);
2632 goto error;
2633 }
2634
2635 BT_MOVE(cur_base_params, params);
2636 break;
2637 }
2638 case OPT_RESET_BASE_PARAMS:
2639 BT_PUT(cur_base_params);
2640 cur_base_params = bt_value_map_create();
2641 if (!cur_base_params) {
2642 print_err_oom();
2643 goto error;
2644 }
2645 break;
c42c79ea
PP
2646 case OPT_NAMES:
2647 if (text_legacy_opts.names) {
2648 printf_err("Duplicate --names option\n");
2649 goto error;
2650 }
2651
2652 text_legacy_opts.names = names_from_arg(arg);
2653 if (!text_legacy_opts.names) {
2654 printf_err("Invalid --names option's argument\n");
2655 goto error;
2656 }
2657 break;
2658 case OPT_FIELDS:
2659 if (text_legacy_opts.fields) {
2660 printf_err("Duplicate --fields option\n");
2661 goto error;
2662 }
2663
2664 text_legacy_opts.fields = fields_from_arg(arg);
2665 if (!text_legacy_opts.fields) {
2666 printf_err("Invalid --fields option's argument\n");
2667 goto error;
2668 }
2669 break;
2670 case OPT_NO_DELTA:
2671 text_legacy_opts.no_delta = true;
2672 break;
2673 case OPT_CLOCK_CYCLES:
2674 text_legacy_opts.clock_cycles = true;
2675 break;
2676 case OPT_CLOCK_SECONDS:
2677 text_legacy_opts.clock_seconds = true;
2678 break;
2679 case OPT_CLOCK_DATE:
2680 text_legacy_opts.clock_date = true;
2681 break;
2682 case OPT_CLOCK_GMT:
2683 text_legacy_opts.clock_gmt = true;
2684 break;
2685 case OPT_DEBUG_INFO_FULL_PATH:
2686 text_legacy_opts.dbg_info_full_path = true;
2687 break;
2688 case OPT_CLOCK_OFFSET:
2689 {
2690 int64_t val;
2691
2692 if (ctf_legacy_opts.offset_s.is_set) {
2693 printf_err("Duplicate --clock-offset option\n");
2694 goto error;
2695 }
2696
2697 if (parse_int64(arg, &val)) {
2698 printf_err("Invalid --clock-offset option's argument\n");
2699 goto error;
2700 }
2701
2702 set_offset_value(&ctf_legacy_opts.offset_s, val);
2703 break;
2704 }
2705 case OPT_CLOCK_OFFSET_NS:
2706 {
2707 int64_t val;
2708
2709 if (ctf_legacy_opts.offset_ns.is_set) {
2710 printf_err("Duplicate --clock-offset-ns option\n");
2711 goto error;
2712 }
2713
2714 if (parse_int64(arg, &val)) {
2715 printf_err("Invalid --clock-offset-ns option's argument\n");
2716 goto error;
2717 }
2718
2719 set_offset_value(&ctf_legacy_opts.offset_ns, val);
2720 break;
2721 }
2722 case OPT_STREAM_INTERSECTION:
2723 ctf_legacy_opts.stream_intersection = true;
2724 break;
2725 case OPT_CLOCK_FORCE_CORRELATE:
2726 cfg->force_correlate = true;
2727 break;
0f9915c6
MD
2728 case OPT_BEGIN:
2729 if (!cur_cfg_comp) {
65582340
MD
2730 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2731 DEFAULT_SOURCE_COMPONENT_NAME);
0f9915c6
MD
2732 goto error;
2733 }
2734 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2735 printf_err("--begin option must follow a --source option\n");
2736 goto error;
2737 }
2738 if (bt_value_map_insert_string(cur_cfg_comp->params,
2739 "begin", arg)) {
2740 print_err_oom();
2741 goto error;
2742 }
2743 break;
2744 case OPT_END:
2745 if (!cur_cfg_comp) {
65582340
MD
2746 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2747 DEFAULT_SOURCE_COMPONENT_NAME);
0f9915c6
MD
2748 goto error;
2749 }
2750 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2751 printf_err("--end option must follow a --source option\n");
2752 goto error;
2753 }
2754 if (bt_value_map_insert_string(cur_cfg_comp->params,
2755 "end", arg)) {
2756 print_err_oom();
2757 goto error;
2758 }
2759 break;
2760 case OPT_TIMERANGE:
2761 {
2762 const char *begin, *end;
2763
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("--timerange option must follow a --source option\n");
2771 goto error;
2772 }
2773 if (split_timerange(arg, &begin, &end)) {
2774 printf_err("Invalid --timerange format, expecting: begin,end or [begin,end] (where [] are actual brackets)\n");
2775 goto error;
2776 }
2777 if (bt_value_map_insert_string(cur_cfg_comp->params,
2778 "begin", begin)) {
2779 print_err_oom();
2780 goto error;
2781 }
2782 if (bt_value_map_insert_string(cur_cfg_comp->params,
2783 "end", end)) {
2784 print_err_oom();
2785 goto error;
2786 }
2787 break;
2788 }
c42c79ea 2789 case OPT_HELP:
c42c79ea
PP
2790 print_usage(stdout);
2791 goto end;
2792 case OPT_HELP_LEGACY:
c42c79ea
PP
2793 print_legacy_usage(stdout);
2794 goto end;
2795 case OPT_VERSION:
c42c79ea
PP
2796 print_version();
2797 goto end;
2798 case OPT_LIST:
2799 cfg->do_list = true;
2800 goto end;
2801 case OPT_VERBOSE:
2802 cfg->verbose = true;
2803 break;
2804 case OPT_DEBUG:
2805 cfg->debug = true;
2806 break;
2807 default:
2808 printf_err("Unknown command-line option specified (option code %d)\n",
2809 opt);
2810 goto error;
2811 }
2812
2813 free(arg);
2814 arg = NULL;
2815 }
2816
c1870f57 2817 if (argc <= 1) {
ea103fa0 2818 print_usage(stdout);
c1870f57 2819 goto end;
ea103fa0
MD
2820 }
2821
c42c79ea
PP
2822 /* Check for option parsing error */
2823 if (opt < -1) {
2824 printf_err("While parsing command-line options, at option %s: %s\n",
2825 poptBadOption(pc, 0), poptStrerror(opt));
2826 goto error;
2827 }
2828
2829 /* Consume leftover arguments as legacy input paths */
2830 while (true) {
2831 const char *input_path = poptGetArg(pc);
2832
2833 if (!input_path) {
2834 break;
2835 }
2836
2837 if (bt_value_array_append_string(legacy_input_paths,
2838 input_path)) {
2839 print_err_oom();
2840 goto error;
2841 }
2842 }
2843
6cf24c61
MD
2844 if (add_internal_plugin_paths(cfg)) {
2845 goto error;
2846 }
2847
2848 /* Append current component configuration, if any */
2849 if (cur_cfg_comp && !cur_is_implicit_source) {
2850 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
2851 }
2852 cur_cfg_comp = NULL;
2853
c42c79ea
PP
2854 /* Validate legacy/non-legacy options */
2855 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
2856 legacy_input_paths, &ctf_legacy_opts,
bd9f0fa2 2857 &text_legacy_opts)) {
c42c79ea
PP
2858 printf_err("Command-line options form an invalid configuration\n");
2859 goto error;
2860 }
2861
2862 /*
2863 * If there's a legacy input format, convert it to source
2864 * component configurations.
2865 */
2866 if (legacy_input_format) {
2867 if (append_sources_from_legacy_opts(cfg->sources,
2868 legacy_input_format, &ctf_legacy_opts,
528debdf 2869 legacy_input_paths)) {
49849a47 2870 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
2871 goto error;
2872 }
bd9f0fa2
MD
2873 if (append_sources_from_implicit_params(cfg->sources,
2874 implicit_source_comp)) {
2875 printf_err("Cannot initialize legacy component parameters\n");
2876 goto error;
2877 }
2878 use_implicit_source = false;
2879 } else {
2880 if (use_implicit_source) {
2881 add_cfg_comp(cfg, implicit_source_comp,
2882 BT_CONFIG_COMPONENT_DEST_SOURCE);
2883 implicit_source_comp = NULL;
2884 } else {
2885 if (implicit_source_comp
2886 && !bt_value_map_is_empty(implicit_source_comp->params)) {
2887 printf_err("Arguments specified for implicit source, but an explicit source has been specified, overriding it\n");
2888 goto error;
2889 }
2890 }
c42c79ea
PP
2891 }
2892
2893 /*
2894 * If there's a legacy output format, convert it to sink
2895 * component configurations.
2896 */
2897 if (legacy_output_format) {
2898 if (append_sinks_from_legacy_opts(cfg->sinks,
2899 legacy_output_format, &text_legacy_opts)) {
49849a47 2900 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
2901 goto error;
2902 }
2903 }
2904
bd9f0fa2
MD
2905 if (cfg->sinks->len == 0) {
2906 /* Use implicit sink as default. */
2907 cur_cfg_comp = bt_config_component_from_arg(DEFAULT_SINK_COMPONENT_NAME);
2908 if (!cur_cfg_comp) {
2909 printf_error("Cannot find implicit sink plugin \"%s\"\n",
2910 DEFAULT_SINK_COMPONENT_NAME);
2911 }
2912 add_cfg_comp(cfg, cur_cfg_comp,
2913 BT_CONFIG_COMPONENT_DEST_SINK);
2914 cur_cfg_comp = NULL;
2915 }
2916
c42c79ea
PP
2917 goto end;
2918
2919error:
c1870f57 2920 ret = 1;
c42c79ea
PP
2921end:
2922 if (pc) {
2923 poptFreeContext(pc);
2924 }
2925
2926 if (text_legacy_opts.output) {
2927 g_string_free(text_legacy_opts.output, TRUE);
2928 }
2929
2930 if (text_legacy_opts.dbg_info_dir) {
2931 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
2932 }
2933
2934 if (text_legacy_opts.dbg_info_target_prefix) {
2935 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
2936 }
2937
2938 free(arg);
65582340 2939 BT_PUT(implicit_source_comp);
bdc61c70 2940 BT_PUT(cur_cfg_comp);
b07ffa28 2941 BT_PUT(cur_base_params);
c42c79ea
PP
2942 BT_PUT(text_legacy_opts.names);
2943 BT_PUT(text_legacy_opts.fields);
2944 BT_PUT(legacy_input_paths);
c1870f57 2945 return ret;
c42c79ea 2946}
This page took 0.146323 seconds and 4 git commands to generate.