Fix: babeltrace launch wrapper script
[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,
2007 struct text_legacy_opts *text_legacy_opts)
2008{
2009 bool legacy_input = false;
2010 bool legacy_output = false;
2011
2012 /* Determine if the input and output should be legacy-style */
2013 if (*legacy_input_format != LEGACY_INPUT_FORMAT_NONE ||
2014 cfg->sources->len == 0 ||
2015 !bt_value_array_is_empty(legacy_input_paths) ||
2016 ctf_legacy_opts_is_any_set(ctf_legacy_opts)) {
2017 legacy_input = true;
2018 }
2019
2020 if (*legacy_output_format != LEGACY_OUTPUT_FORMAT_NONE ||
2021 cfg->sinks->len == 0 ||
2022 text_legacy_opts_is_any_set(text_legacy_opts)) {
2023 legacy_output = true;
2024 }
2025
2026 if (legacy_input) {
2027 /* If no legacy input format was specified, default to CTF */
2028 if (*legacy_input_format == LEGACY_INPUT_FORMAT_NONE) {
2029 *legacy_input_format = LEGACY_INPUT_FORMAT_CTF;
2030 }
2031
2032 /* Make sure at least one input path exists */
2033 if (bt_value_array_is_empty(legacy_input_paths)) {
2034 switch (*legacy_input_format) {
2035 case LEGACY_INPUT_FORMAT_CTF:
6d1d5711 2036 printf_err("No input path specified for legacy `ctf` input format\n");
c42c79ea
PP
2037 break;
2038 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
6d1d5711 2039 printf_err("No URL specified for legacy `lttng-live` input format\n");
c42c79ea
PP
2040 break;
2041 default:
2042 assert(false);
2043 }
2044 goto error;
2045 }
2046
2047 /* Make sure no non-legacy sources are specified */
2048 if (cfg->sources->len != 0) {
2049 print_input_legacy_to_sources(*legacy_input_format,
2050 legacy_input_paths, ctf_legacy_opts);
2051 goto error;
2052 }
2053 }
2054
2055 if (legacy_output) {
2056 /*
2057 * If no legacy output format was specified, default to
2058 * "text".
2059 */
2060 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_NONE) {
2061 *legacy_output_format = LEGACY_OUTPUT_FORMAT_TEXT;
2062 }
2063
2064 /*
2065 * If any "text" option was specified, the output must be
2066 * legacy "text".
2067 */
2068 if (text_legacy_opts_is_any_set(text_legacy_opts) &&
2069 *legacy_output_format !=
2070 LEGACY_OUTPUT_FORMAT_TEXT) {
6d1d5711 2071 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
c42c79ea
PP
2072 goto error;
2073 }
2074
2075 /* Make sure no non-legacy sinks are specified */
2076 if (cfg->sinks->len != 0) {
2077 print_output_legacy_to_sinks(*legacy_output_format,
2078 text_legacy_opts);
2079 goto error;
2080 }
2081 }
2082
2083 /*
2084 * If the output is the legacy "ctf-metadata" format, then the
2085 * input should be the legacy "ctf" input format.
2086 */
2087 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_CTF_METADATA &&
2088 *legacy_input_format != LEGACY_INPUT_FORMAT_CTF) {
6d1d5711 2089 printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n");
c42c79ea
PP
2090 goto error;
2091 }
2092
2093 return true;
2094
2095error:
2096 return false;
2097}
2098
2099/*
2100 * Parses a 64-bit signed integer.
2101 *
2102 * Returns a negative value if anything goes wrong.
2103 */
2104static
2105int parse_int64(const char *arg, int64_t *val)
2106{
2107 char *endptr;
2108
2109 errno = 0;
2110 *val = strtoll(arg, &endptr, 0);
2111 if (*endptr != '\0' || arg == endptr || errno != 0) {
2112 return -1;
2113 }
2114
2115 return 0;
2116}
2117
2118/* popt options */
2119enum {
2120 OPT_NONE = 0,
b07ffa28 2121 OPT_BASE_PARAMS,
0f9915c6 2122 OPT_BEGIN,
c42c79ea
PP
2123 OPT_CLOCK_CYCLES,
2124 OPT_CLOCK_DATE,
2125 OPT_CLOCK_FORCE_CORRELATE,
2126 OPT_CLOCK_GMT,
2127 OPT_CLOCK_OFFSET,
2128 OPT_CLOCK_OFFSET_NS,
2129 OPT_CLOCK_SECONDS,
2130 OPT_DEBUG,
2131 OPT_DEBUG_INFO_DIR,
2132 OPT_DEBUG_INFO_FULL_PATH,
2133 OPT_DEBUG_INFO_TARGET_PREFIX,
0f9915c6 2134 OPT_END,
c42c79ea
PP
2135 OPT_FIELDS,
2136 OPT_HELP,
2137 OPT_HELP_LEGACY,
2138 OPT_INPUT_FORMAT,
2139 OPT_LIST,
2140 OPT_NAMES,
2141 OPT_NO_DELTA,
2142 OPT_OUTPUT_FORMAT,
2143 OPT_OUTPUT_PATH,
ad6a19bd 2144 OPT_PATH,
bdc61c70 2145 OPT_PARAMS,
c42c79ea 2146 OPT_PLUGIN_PATH,
b07ffa28 2147 OPT_RESET_BASE_PARAMS,
c42c79ea
PP
2148 OPT_SINK,
2149 OPT_SOURCE,
2150 OPT_STREAM_INTERSECTION,
0f9915c6 2151 OPT_TIMERANGE,
c42c79ea
PP
2152 OPT_VERBOSE,
2153 OPT_VERSION,
98ecef32
MD
2154 OPT_OMIT_SYSTEM_PLUGIN_PATH,
2155 OPT_OMIT_HOME_PLUGIN_PATH,
c42c79ea
PP
2156};
2157
2158/* popt long option descriptions */
2159static struct poptOption long_options[] = {
2160 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
b07ffa28 2161 { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
0f9915c6 2162 { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
c42c79ea
PP
2163 { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
2164 { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
2165 { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
2166 { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
2167 { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
2168 { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
2169 { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
2170 { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
2171 { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
2172 { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
2173 { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
0f9915c6 2174 { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
c42c79ea
PP
2175 { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
2176 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2177 { "help-legacy", '\0', POPT_ARG_NONE, NULL, OPT_HELP_LEGACY, NULL, NULL },
2178 { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
2179 { "list", 'l', POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL },
2180 { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
2181 { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
2182 { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
2183 { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
ad6a19bd 2184 { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
bdc61c70 2185 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
ad6a19bd 2186 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
b07ffa28 2187 { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
c42c79ea
PP
2188 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2189 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2190 { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
0f9915c6 2191 { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
c42c79ea
PP
2192 { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
2193 { "version", 'V', POPT_ARG_NONE, NULL, OPT_VERSION, NULL, NULL },
98ecef32
MD
2194 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2195 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
c42c79ea
PP
2196 { NULL, 0, 0, NULL, 0, NULL, NULL },
2197};
2198
2199/*
2200 * Sets the value of a given legacy offset option and marks it as set.
2201 */
2202static void set_offset_value(struct offset_opt *offset_opt, int64_t value)
2203{
2204 offset_opt->value = value;
2205 offset_opt->is_set = true;
2206}
2207
bdc61c70
PP
2208enum bt_config_component_dest {
2209 BT_CONFIG_COMPONENT_DEST_SOURCE,
2210 BT_CONFIG_COMPONENT_DEST_SINK,
2211};
2212
2213/*
2214 * Adds a configuration component to the appropriate configuration
2215 * array depending on the destination.
2216 */
2217static void add_cfg_comp(struct bt_config *cfg,
2218 struct bt_config_component *cfg_comp,
2219 enum bt_config_component_dest dest)
2220{
2221 if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
2222 g_ptr_array_add(cfg->sources, cfg_comp);
2223 } else {
2224 g_ptr_array_add(cfg->sinks, cfg_comp);
2225 }
2226}
2227
0f9915c6
MD
2228static int split_timerange(const char *arg, const char **begin, const char **end)
2229{
2230 const char *c;
2231
2232 /* Try to match [begin,end] */
2233 c = strchr(arg, '[');
2234 if (!c)
2235 goto skip;
2236 *begin = ++c;
2237 c = strchr(c, ',');
2238 if (!c)
2239 goto skip;
2240 *end = ++c;
2241 c = strchr(c, ']');
2242 if (!c)
2243 goto skip;
2244 goto found;
2245
2246skip:
2247 /* Try to match begin,end */
2248 c = arg;
2249 *begin = c;
2250 c = strchr(c, ',');
2251 if (!c)
2252 goto not_found;
2253 *end = ++c;
2254 /* fall-through */
2255found:
2256 return 0;
2257not_found:
2258 return -1;
2259}
2260
98ecef32
MD
2261static char *bt_secure_getenv(const char *name)
2262{
2263 if (is_setuid_setgid()) {
2264 printf_err("Disregarding %s environment variable for setuid/setgid binary", name);
2265 return NULL;
2266 }
2267 return getenv(name);
2268}
2269
2270static const char *get_home_dir(void)
2271{
2272 char *val = NULL;
2273 struct passwd *pwd;
2274
2275 val = bt_secure_getenv(HOME_ENV_VAR);
2276 if (val) {
2277 goto end;
2278 }
2279 /* Fallback on password file. */
2280 pwd = getpwuid(getuid());
2281 if (!pwd) {
2282 goto end;
2283 }
2284 val = pwd->pw_dir;
2285end:
2286 return val;
2287}
2288
2289static int add_internal_plugin_paths(struct bt_config *cfg)
2290{
2291 if (!omit_home_plugin_path) {
2292 char path[PATH_MAX];
2293 const char *home_dir;
2294
2295 if (is_setuid_setgid()) {
2296 printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
2297 } else {
2298 home_dir = get_home_dir();
2299 if (home_dir) {
2300 if (strlen(home_dir) + strlen(HOME_SUBPATH) + 1
2301 >= PATH_MAX) {
2302 printf_err("Home directory path too long\n");
2303 goto error;
2304 }
2305 strcpy(path, home_dir);
2306 strcat(path, HOME_SUBPATH);
2307 if (plugin_paths_from_arg(cfg->plugin_paths, path)) {
2308 printf_err("Invalid home plugin path\n");
2309 goto error;
2310 }
2311 }
2312 }
2313 }
2314
2315 if (!omit_system_plugin_path) {
2316 if (plugin_paths_from_arg(cfg->plugin_paths,
2317 SYSTEM_PLUGIN_PATH)) {
2318 printf_err("Invalid system plugin path\n");
2319 goto error;
2320 }
2321 }
2322 return 0;
2323error:
2324 return -1;
2325}
2326
c42c79ea
PP
2327/*
2328 * Returns a Babeltrace configuration, out of command-line arguments,
2329 * containing everything that is needed to instanciate specific
2330 * components with given parameters.
2331 *
2332 * *exit_code is set to the appropriate exit code to use as far as this
2333 * function goes.
2334 *
2335 * Return value is NULL on error, otherwise it's owned by the caller.
2336 */
528debdf 2337struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_code)
c42c79ea
PP
2338{
2339 struct bt_config *cfg = NULL;
2340 poptContext pc = NULL;
2341 char *arg = NULL;
b7726e32
MD
2342 struct ctf_legacy_opts ctf_legacy_opts;
2343 struct text_legacy_opts text_legacy_opts;
c42c79ea
PP
2344 enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
2345 enum legacy_output_format legacy_output_format =
2346 LEGACY_OUTPUT_FORMAT_NONE;
2347 struct bt_value *legacy_input_paths = NULL;
65582340 2348 struct bt_config_component *implicit_source_comp = NULL;
bdc61c70 2349 struct bt_config_component *cur_cfg_comp = NULL;
65582340
MD
2350 bool cur_is_implicit_source = false;
2351 bool use_implicit_source = false;
bdc61c70
PP
2352 enum bt_config_component_dest cur_cfg_comp_dest =
2353 BT_CONFIG_COMPONENT_DEST_SOURCE;
b07ffa28 2354 struct bt_value *cur_base_params = NULL;
c42c79ea
PP
2355 int opt;
2356
b7726e32
MD
2357 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
2358 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
c42c79ea
PP
2359 *exit_code = 0;
2360
2361 if (argc <= 1) {
2362 print_usage(stdout);
2363 goto end;
2364 }
2365
2366 text_legacy_opts.output = g_string_new(NULL);
2367 if (!text_legacy_opts.output) {
2368 print_err_oom();
2369 goto error;
2370 }
2371
2372 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
2373 if (!text_legacy_opts.dbg_info_dir) {
2374 print_err_oom();
2375 goto error;
2376 }
2377
2378 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
2379 if (!text_legacy_opts.dbg_info_target_prefix) {
2380 print_err_oom();
2381 goto error;
2382 }
2383
b07ffa28
PP
2384 cur_base_params = bt_value_map_create();
2385 if (!cur_base_params) {
2386 print_err_oom();
2387 goto error;
2388 }
2389
c42c79ea
PP
2390 /* Create config */
2391 cfg = g_new0(struct bt_config, 1);
2392 if (!cfg) {
2393 print_err_oom();
2394 goto error;
2395 }
2396
2397 bt_object_init(cfg, bt_config_destroy);
2398 cfg->sources = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
2399 if (!cfg->sources) {
2400 print_err_oom();
2401 goto error;
2402 }
2403
2404 cfg->sinks = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
2405 if (!cfg->sinks) {
2406 print_err_oom();
2407 goto error;
2408 }
2409
2410 legacy_input_paths = bt_value_array_create();
2411 if (!legacy_input_paths) {
2412 print_err_oom();
2413 goto error;
2414 }
2415
65582340
MD
2416 /* Note: implicit source never gets positional base params. */
2417 implicit_source_comp = bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME);
2418 if (implicit_source_comp) {
2419 cur_cfg_comp = implicit_source_comp;
2420 cur_is_implicit_source = true;
2421 use_implicit_source = true;
2422 } else {
2423 printf_debug("Cannot find implicit source plugin \"%s\"",
2424 DEFAULT_SOURCE_COMPONENT_NAME);
2425 }
2426
98ecef32
MD
2427 cfg->plugin_paths = bt_value_array_create();
2428 if (!cfg->plugin_paths) {
2429 print_err_oom();
2430 goto error;
2431 }
2432
c42c79ea
PP
2433 /* Parse options */
2434 pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
2435 if (!pc) {
2436 printf_err("Cannot get popt context\n");
2437 goto error;
2438 }
2439
2440 poptReadDefaultConfig(pc, 0);
2441
2442 while ((opt = poptGetNextOpt(pc)) > 0) {
2443 arg = poptGetOptArg(pc);
2444
2445 switch (opt) {
2446 case OPT_PLUGIN_PATH:
98ecef32
MD
2447 if (is_setuid_setgid()) {
2448 printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
2449 } else {
2450 if (plugin_paths_from_arg(cfg->plugin_paths, arg)) {
2451 printf_err("Invalid --plugin-path option's argument\n");
2452 goto error;
2453 }
c42c79ea
PP
2454 }
2455 break;
98ecef32
MD
2456 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
2457 omit_system_plugin_path = true;
2458 break;
2459 case OPT_OMIT_HOME_PLUGIN_PATH:
2460 omit_home_plugin_path = true;
2461 break;
c42c79ea
PP
2462 case OPT_OUTPUT_PATH:
2463 if (text_legacy_opts.output->len > 0) {
2464 printf_err("Duplicate --output option\n");
2465 goto error;
2466 }
2467
2468 g_string_assign(text_legacy_opts.output, arg);
2469 break;
2470 case OPT_DEBUG_INFO_DIR:
2471 if (text_legacy_opts.dbg_info_dir->len > 0) {
2472 printf_err("Duplicate --debug-info-dir option\n");
2473 goto error;
2474 }
2475
2476 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
2477 break;
2478 case OPT_DEBUG_INFO_TARGET_PREFIX:
2479 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
2480 printf_err("Duplicate --debug-info-target-prefix option\n");
2481 goto error;
2482 }
2483
2484 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
2485 break;
2486 case OPT_INPUT_FORMAT:
2487 case OPT_SOURCE:
2488 {
c42c79ea
PP
2489 if (opt == OPT_INPUT_FORMAT) {
2490 if (!strcmp(arg, "ctf")) {
2491 /* Legacy CTF input format */
2492 if (legacy_input_format) {
2493 print_err_dup_legacy_input();
2494 goto error;
2495 }
2496
2497 legacy_input_format =
2498 LEGACY_INPUT_FORMAT_CTF;
2499 break;
2500 } else if (!strcmp(arg, "lttng-live")) {
2501 /* Legacy LTTng-live input format */
2502 if (legacy_input_format) {
2503 print_err_dup_legacy_input();
2504 goto error;
2505 }
2506
2507 legacy_input_format =
2508 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
2509 break;
2510 }
2511 }
2512
65582340
MD
2513 use_implicit_source = false;
2514
c42c79ea 2515 /* Non-legacy: try to create a component config */
65582340 2516 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
2517 add_cfg_comp(cfg, cur_cfg_comp,
2518 cur_cfg_comp_dest);
2519 }
2520
2521 cur_cfg_comp = bt_config_component_from_arg(arg);
2522 if (!cur_cfg_comp) {
49849a47 2523 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
2524 arg);
2525 goto error;
2526 }
65582340 2527 cur_is_implicit_source = false;
c42c79ea 2528
b07ffa28
PP
2529 assert(cur_base_params);
2530 bt_put(cur_cfg_comp->params);
c9313318
PP
2531 cur_cfg_comp->params = bt_value_copy(cur_base_params);
2532 if (!cur_cfg_comp) {
2533 print_err_oom();
2534 goto end;
2535 }
2536
bdc61c70 2537 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
c42c79ea
PP
2538 break;
2539 }
2540 case OPT_OUTPUT_FORMAT:
2541 case OPT_SINK:
2542 {
c42c79ea
PP
2543 if (opt == OPT_OUTPUT_FORMAT) {
2544 if (!strcmp(arg, "text")) {
2545 /* Legacy CTF-text output format */
2546 if (legacy_output_format) {
2547 print_err_dup_legacy_output();
2548 goto error;
2549 }
2550
2551 legacy_output_format =
2552 LEGACY_OUTPUT_FORMAT_TEXT;
2553 break;
2554 } else if (!strcmp(arg, "dummy")) {
2555 /* Legacy dummy output format */
2556 if (legacy_output_format) {
2557 print_err_dup_legacy_output();
2558 goto error;
2559 }
2560
2561 legacy_output_format =
2562 LEGACY_OUTPUT_FORMAT_DUMMY;
2563 break;
2564 } else if (!strcmp(arg, "ctf-metadata")) {
2565 /* Legacy CTF-metadata output format */
2566 if (legacy_output_format) {
2567 print_err_dup_legacy_output();
2568 goto error;
2569 }
2570
2571 legacy_output_format =
2572 LEGACY_OUTPUT_FORMAT_CTF_METADATA;
2573 break;
2574 }
2575 }
2576
2577 /* Non-legacy: try to create a component config */
65582340 2578 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
2579 add_cfg_comp(cfg, cur_cfg_comp,
2580 cur_cfg_comp_dest);
2581 }
2582
2583 cur_cfg_comp = bt_config_component_from_arg(arg);
2584 if (!cur_cfg_comp) {
49849a47 2585 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
2586 arg);
2587 goto error;
2588 }
65582340 2589 cur_is_implicit_source = false;
c42c79ea 2590
b07ffa28
PP
2591 assert(cur_base_params);
2592 bt_put(cur_cfg_comp->params);
c9313318
PP
2593 cur_cfg_comp->params = bt_value_copy(cur_base_params);
2594 if (!cur_cfg_comp) {
2595 print_err_oom();
2596 goto end;
2597 }
2598
bdc61c70 2599 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
bdc61c70
PP
2600 break;
2601 }
2602 case OPT_PARAMS:
2603 {
2604 struct bt_value *params;
b07ffa28 2605 struct bt_value *params_to_set;
bdc61c70
PP
2606
2607 if (!cur_cfg_comp) {
65582340
MD
2608 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2609 DEFAULT_SOURCE_COMPONENT_NAME);
bdc61c70
PP
2610 goto error;
2611 }
2612
bdc61c70
PP
2613 params = bt_value_from_arg(arg);
2614 if (!params) {
2615 printf_err("Invalid format for --params option's argument:\n %s\n",
2616 arg);
2617 goto error;
2618 }
2619
560ff91c 2620 params_to_set = bt_value_map_extend(cur_cfg_comp->params,
b07ffa28
PP
2621 params);
2622 BT_PUT(params);
2623 if (!params_to_set) {
560ff91c 2624 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
b07ffa28
PP
2625 arg);
2626 goto error;
2627 }
2628
2629 BT_MOVE(cur_cfg_comp->params, params_to_set);
c42c79ea
PP
2630 break;
2631 }
ad6a19bd
PP
2632 case OPT_PATH:
2633 if (!cur_cfg_comp) {
65582340
MD
2634 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2635 DEFAULT_SOURCE_COMPONENT_NAME);
ad6a19bd
PP
2636 goto error;
2637 }
2638
2639 assert(cur_cfg_comp->params);
2640
2641 if (bt_value_map_insert_string(cur_cfg_comp->params,
2642 "path", arg)) {
2643 print_err_oom();
2644 goto error;
2645 }
2646 break;
b07ffa28
PP
2647 case OPT_BASE_PARAMS:
2648 {
2649 struct bt_value *params = bt_value_from_arg(arg);
2650
2651 if (!params) {
2652 printf_err("Invalid format for --base-params option's argument:\n %s\n",
2653 arg);
2654 goto error;
2655 }
2656
2657 BT_MOVE(cur_base_params, params);
2658 break;
2659 }
2660 case OPT_RESET_BASE_PARAMS:
2661 BT_PUT(cur_base_params);
2662 cur_base_params = bt_value_map_create();
2663 if (!cur_base_params) {
2664 print_err_oom();
2665 goto error;
2666 }
2667 break;
c42c79ea
PP
2668 case OPT_NAMES:
2669 if (text_legacy_opts.names) {
2670 printf_err("Duplicate --names option\n");
2671 goto error;
2672 }
2673
2674 text_legacy_opts.names = names_from_arg(arg);
2675 if (!text_legacy_opts.names) {
2676 printf_err("Invalid --names option's argument\n");
2677 goto error;
2678 }
2679 break;
2680 case OPT_FIELDS:
2681 if (text_legacy_opts.fields) {
2682 printf_err("Duplicate --fields option\n");
2683 goto error;
2684 }
2685
2686 text_legacy_opts.fields = fields_from_arg(arg);
2687 if (!text_legacy_opts.fields) {
2688 printf_err("Invalid --fields option's argument\n");
2689 goto error;
2690 }
2691 break;
2692 case OPT_NO_DELTA:
2693 text_legacy_opts.no_delta = true;
2694 break;
2695 case OPT_CLOCK_CYCLES:
2696 text_legacy_opts.clock_cycles = true;
2697 break;
2698 case OPT_CLOCK_SECONDS:
2699 text_legacy_opts.clock_seconds = true;
2700 break;
2701 case OPT_CLOCK_DATE:
2702 text_legacy_opts.clock_date = true;
2703 break;
2704 case OPT_CLOCK_GMT:
2705 text_legacy_opts.clock_gmt = true;
2706 break;
2707 case OPT_DEBUG_INFO_FULL_PATH:
2708 text_legacy_opts.dbg_info_full_path = true;
2709 break;
2710 case OPT_CLOCK_OFFSET:
2711 {
2712 int64_t val;
2713
2714 if (ctf_legacy_opts.offset_s.is_set) {
2715 printf_err("Duplicate --clock-offset option\n");
2716 goto error;
2717 }
2718
2719 if (parse_int64(arg, &val)) {
2720 printf_err("Invalid --clock-offset option's argument\n");
2721 goto error;
2722 }
2723
2724 set_offset_value(&ctf_legacy_opts.offset_s, val);
2725 break;
2726 }
2727 case OPT_CLOCK_OFFSET_NS:
2728 {
2729 int64_t val;
2730
2731 if (ctf_legacy_opts.offset_ns.is_set) {
2732 printf_err("Duplicate --clock-offset-ns option\n");
2733 goto error;
2734 }
2735
2736 if (parse_int64(arg, &val)) {
2737 printf_err("Invalid --clock-offset-ns option's argument\n");
2738 goto error;
2739 }
2740
2741 set_offset_value(&ctf_legacy_opts.offset_ns, val);
2742 break;
2743 }
2744 case OPT_STREAM_INTERSECTION:
2745 ctf_legacy_opts.stream_intersection = true;
2746 break;
2747 case OPT_CLOCK_FORCE_CORRELATE:
2748 cfg->force_correlate = true;
2749 break;
0f9915c6
MD
2750 case OPT_BEGIN:
2751 if (!cur_cfg_comp) {
65582340
MD
2752 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2753 DEFAULT_SOURCE_COMPONENT_NAME);
0f9915c6
MD
2754 goto error;
2755 }
2756 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2757 printf_err("--begin option must follow a --source option\n");
2758 goto error;
2759 }
2760 if (bt_value_map_insert_string(cur_cfg_comp->params,
2761 "begin", arg)) {
2762 print_err_oom();
2763 goto error;
2764 }
2765 break;
2766 case OPT_END:
2767 if (!cur_cfg_comp) {
65582340
MD
2768 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2769 DEFAULT_SOURCE_COMPONENT_NAME);
0f9915c6
MD
2770 goto error;
2771 }
2772 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2773 printf_err("--end option must follow a --source option\n");
2774 goto error;
2775 }
2776 if (bt_value_map_insert_string(cur_cfg_comp->params,
2777 "end", arg)) {
2778 print_err_oom();
2779 goto error;
2780 }
2781 break;
2782 case OPT_TIMERANGE:
2783 {
2784 const char *begin, *end;
2785
2786 if (!cur_cfg_comp) {
65582340
MD
2787 printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
2788 DEFAULT_SOURCE_COMPONENT_NAME);
0f9915c6
MD
2789 goto error;
2790 }
2791 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2792 printf_err("--timerange option must follow a --source option\n");
2793 goto error;
2794 }
2795 if (split_timerange(arg, &begin, &end)) {
2796 printf_err("Invalid --timerange format, expecting: begin,end or [begin,end] (where [] are actual brackets)\n");
2797 goto error;
2798 }
2799 if (bt_value_map_insert_string(cur_cfg_comp->params,
2800 "begin", begin)) {
2801 print_err_oom();
2802 goto error;
2803 }
2804 if (bt_value_map_insert_string(cur_cfg_comp->params,
2805 "end", end)) {
2806 print_err_oom();
2807 goto error;
2808 }
2809 break;
2810 }
c42c79ea
PP
2811 case OPT_HELP:
2812 BT_PUT(cfg);
2813 print_usage(stdout);
2814 goto end;
2815 case OPT_HELP_LEGACY:
2816 BT_PUT(cfg);
2817 print_legacy_usage(stdout);
2818 goto end;
2819 case OPT_VERSION:
2820 BT_PUT(cfg);
2821 print_version();
2822 goto end;
2823 case OPT_LIST:
2824 cfg->do_list = true;
2825 goto end;
2826 case OPT_VERBOSE:
2827 cfg->verbose = true;
2828 break;
2829 case OPT_DEBUG:
2830 cfg->debug = true;
2831 break;
2832 default:
2833 printf_err("Unknown command-line option specified (option code %d)\n",
2834 opt);
2835 goto error;
2836 }
2837
2838 free(arg);
2839 arg = NULL;
2840 }
2841
98ecef32
MD
2842 if (add_internal_plugin_paths(cfg)) {
2843 goto error;
2844 }
2845
bdc61c70 2846 /* Append current component configuration, if any */
65582340 2847 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70 2848 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
65582340
MD
2849 }
2850 cur_cfg_comp = NULL;
2851
2852 if (use_implicit_source) {
2853 add_cfg_comp(cfg, implicit_source_comp,
2854 BT_CONFIG_COMPONENT_DEST_SOURCE);
2855 implicit_source_comp = NULL;
2856 } else {
2857 if (implicit_source_comp
2858 && !bt_value_map_is_empty(implicit_source_comp->params)) {
2859 printf_err("Arguments specified for implicit source, but an explicit source has been specified, overriding it\n");
2860 goto error;
2861 }
bdc61c70
PP
2862 }
2863
c42c79ea
PP
2864 /* Check for option parsing error */
2865 if (opt < -1) {
2866 printf_err("While parsing command-line options, at option %s: %s\n",
2867 poptBadOption(pc, 0), poptStrerror(opt));
2868 goto error;
2869 }
2870
2871 /* Consume leftover arguments as legacy input paths */
2872 while (true) {
2873 const char *input_path = poptGetArg(pc);
2874
2875 if (!input_path) {
2876 break;
2877 }
2878
2879 if (bt_value_array_append_string(legacy_input_paths,
2880 input_path)) {
2881 print_err_oom();
2882 goto error;
2883 }
2884 }
2885
2886 /* Validate legacy/non-legacy options */
2887 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
2888 legacy_input_paths, &ctf_legacy_opts,
2889 &text_legacy_opts)) {
2890 printf_err("Command-line options form an invalid configuration\n");
2891 goto error;
2892 }
2893
2894 /*
2895 * If there's a legacy input format, convert it to source
2896 * component configurations.
2897 */
2898 if (legacy_input_format) {
2899 if (append_sources_from_legacy_opts(cfg->sources,
2900 legacy_input_format, &ctf_legacy_opts,
528debdf 2901 legacy_input_paths)) {
49849a47 2902 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
2903 goto error;
2904 }
2905 }
2906
2907 /*
2908 * If there's a legacy output format, convert it to sink
2909 * component configurations.
2910 */
2911 if (legacy_output_format) {
2912 if (append_sinks_from_legacy_opts(cfg->sinks,
2913 legacy_output_format, &text_legacy_opts)) {
49849a47 2914 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
2915 goto error;
2916 }
2917 }
2918
2919 goto end;
2920
2921error:
2922 BT_PUT(cfg);
2923 cfg = NULL;
2924 *exit_code = 1;
2925
2926end:
2927 if (pc) {
2928 poptFreeContext(pc);
2929 }
2930
2931 if (text_legacy_opts.output) {
2932 g_string_free(text_legacy_opts.output, TRUE);
2933 }
2934
2935 if (text_legacy_opts.dbg_info_dir) {
2936 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
2937 }
2938
2939 if (text_legacy_opts.dbg_info_target_prefix) {
2940 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
2941 }
2942
2943 free(arg);
65582340 2944 BT_PUT(implicit_source_comp);
bdc61c70 2945 BT_PUT(cur_cfg_comp);
b07ffa28 2946 BT_PUT(cur_base_params);
c42c79ea
PP
2947 BT_PUT(text_legacy_opts.names);
2948 BT_PUT(text_legacy_opts.fields);
2949 BT_PUT(legacy_input_paths);
2950 return cfg;
2951}
This page took 0.14085 seconds and 4 git commands to generate.