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