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