babeltrace-cfg: put comp. class type within struct bt_config_component
[babeltrace.git] / converter / babeltrace-cfg.c
CommitLineData
c42c79ea
PP
1/*
2 * Babeltrace trace converter - parameter parsing
3 *
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
29#include <stdio.h>
30#include <stdbool.h>
31#include <inttypes.h>
32#include <babeltrace/babeltrace.h>
1670bffd 33#include <babeltrace/common-internal.h>
c42c79ea
PP
34#include <babeltrace/values.h>
35#include <popt.h>
36#include <glib.h>
98ecef32
MD
37#include <sys/types.h>
38#include <pwd.h>
c42c79ea 39#include "babeltrace-cfg.h"
ebba3338 40#include "babeltrace-cfg-connect.h"
c42c79ea 41
65582340 42#define DEFAULT_SOURCE_COMPONENT_NAME "ctf.fs"
bd9f0fa2 43#define DEFAULT_SINK_COMPONENT_NAME "text.text"
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
150/*
151 * Prints the "out of memory" error.
152 */
153static
154void print_err_oom(void)
155{
156 printf_err("Out of memory\n");
157}
158
159/*
160 * Prints duplicate legacy output format error.
161 */
162static
163void print_err_dup_legacy_output(void)
164{
165 printf_err("More than one legacy output format specified\n");
166}
167
168/*
169 * Prints duplicate legacy input format error.
170 */
171static
172void print_err_dup_legacy_input(void)
173{
174 printf_err("More than one legacy input format specified\n");
175}
176
177/*
178 * Checks if any of the "text" legacy options is set.
179 */
180static
181bool text_legacy_opts_is_any_set(struct text_legacy_opts *opts)
182{
183 return (opts->output && opts->output->len > 0) ||
184 (opts->dbg_info_dir && opts->dbg_info_dir->len > 0) ||
185 (opts->dbg_info_target_prefix &&
186 opts->dbg_info_target_prefix->len > 0) ||
187 bt_value_array_size(opts->names) > 0 ||
188 bt_value_array_size(opts->fields) > 0 ||
189 opts->no_delta || opts->clock_cycles || opts->clock_seconds ||
190 opts->clock_date || opts->clock_gmt ||
191 opts->dbg_info_full_path;
192}
193
194/*
195 * Checks if any of the "ctf" legacy options is set.
196 */
197static
198bool ctf_legacy_opts_is_any_set(struct ctf_legacy_opts *opts)
199{
200 return opts->offset_s.is_set || opts->offset_ns.is_set ||
201 opts->stream_intersection;
202}
203
204/*
205 * Appends an "expecting token" error to the INI-style parsing state's
206 * error buffer.
207 */
208static
209void ini_append_error_expecting(struct ini_parsing_state *state,
210 GScanner *scanner, const char *expecting)
211{
212 size_t i;
213 size_t pos;
214
215 g_string_append_printf(state->ini_error, "Expecting %s:\n", expecting);
216
217 /* Only print error if there's one line */
218 if (strchr(state->arg, '\n') != NULL || strlen(state->arg) == 0) {
219 return;
220 }
221
222 g_string_append_printf(state->ini_error, "\n %s\n", state->arg);
223 pos = g_scanner_cur_position(scanner) + 4;
224
225 if (!g_scanner_eof(scanner)) {
226 pos--;
227 }
228
229 for (i = 0; i < pos; ++i) {
230 g_string_append_printf(state->ini_error, " ");
231 }
232
233 g_string_append_printf(state->ini_error, "^\n\n");
234}
235
236static
237int ini_handle_state(struct ini_parsing_state *state)
238{
239 int ret = 0;
240 GTokenType token_type;
241 struct bt_value *value = NULL;
242
243 token_type = g_scanner_get_next_token(state->scanner);
244 if (token_type == G_TOKEN_EOF) {
245 if (state->expecting != INI_EXPECT_COMMA) {
246 switch (state->expecting) {
247 case INI_EXPECT_EQUAL:
248 ini_append_error_expecting(state,
249 state->scanner, "'='");
250 break;
251 case INI_EXPECT_VALUE:
252 case INI_EXPECT_VALUE_NUMBER_NEG:
253 ini_append_error_expecting(state,
254 state->scanner, "value");
255 break;
256 case INI_EXPECT_MAP_KEY:
257 ini_append_error_expecting(state,
258 state->scanner, "unquoted map key");
259 break;
260 default:
261 break;
262 }
263 goto error;
264 }
265
266 /* We're done! */
267 ret = 1;
268 goto success;
269 }
270
271 switch (state->expecting) {
272 case INI_EXPECT_MAP_KEY:
273 if (token_type != G_TOKEN_IDENTIFIER) {
274 ini_append_error_expecting(state, state->scanner,
275 "unquoted map key");
276 goto error;
277 }
278
279 free(state->last_map_key);
280 state->last_map_key =
281 strdup(state->scanner->value.v_identifier);
282 if (!state->last_map_key) {
283 g_string_append(state->ini_error,
284 "Out of memory\n");
285 goto error;
286 }
287
288 if (bt_value_map_has_key(state->params, state->last_map_key)) {
289 g_string_append_printf(state->ini_error,
6d1d5711 290 "Duplicate parameter key: `%s`\n",
c42c79ea
PP
291 state->last_map_key);
292 goto error;
293 }
294
295 state->expecting = INI_EXPECT_EQUAL;
296 goto success;
297 case INI_EXPECT_EQUAL:
298 if (token_type != G_TOKEN_CHAR) {
299 ini_append_error_expecting(state,
300 state->scanner, "'='");
301 goto error;
302 }
303
304 if (state->scanner->value.v_char != '=') {
305 ini_append_error_expecting(state,
306 state->scanner, "'='");
307 goto error;
308 }
309
310 state->expecting = INI_EXPECT_VALUE;
311 goto success;
312 case INI_EXPECT_VALUE:
313 {
314 switch (token_type) {
315 case G_TOKEN_CHAR:
316 if (state->scanner->value.v_char == '-') {
317 /* Negative number */
318 state->expecting =
319 INI_EXPECT_VALUE_NUMBER_NEG;
320 goto success;
321 } else {
322 ini_append_error_expecting(state,
323 state->scanner, "value");
324 goto error;
325 }
326 break;
327 case G_TOKEN_INT:
328 {
329 /* Positive integer */
330 uint64_t int_val = state->scanner->value.v_int64;
331
332 if (int_val > (1ULL << 63) - 1) {
333 g_string_append_printf(state->ini_error,
334 "Integer value %" PRIu64 " is outside the range of a 64-bit signed integer\n",
335 int_val);
336 goto error;
337 }
338
339 value = bt_value_integer_create_init(
340 (int64_t) int_val);
341 break;
342 }
343 case G_TOKEN_FLOAT:
344 /* Positive floating point number */
345 value = bt_value_float_create_init(
346 state->scanner->value.v_float);
347 break;
348 case G_TOKEN_STRING:
349 /* Quoted string */
350 value = bt_value_string_create_init(
351 state->scanner->value.v_string);
352 break;
353 case G_TOKEN_IDENTIFIER:
354 {
355 /*
356 * Using symbols would be appropriate here,
357 * but said symbols are allowed as map key,
358 * so it's easier to consider everything an
359 * identifier.
360 *
361 * If one of the known symbols is not
362 * recognized here, then fall back to creating
363 * a string value.
364 */
365 const char *id = state->scanner->value.v_identifier;
366
367 if (!strcmp(id, "null") || !strcmp(id, "NULL") ||
368 !strcmp(id, "nul")) {
369 value = bt_value_null;
370 } else if (!strcmp(id, "true") || !strcmp(id, "TRUE") ||
371 !strcmp(id, "yes") ||
372 !strcmp(id, "YES")) {
373 value = bt_value_bool_create_init(true);
374 } else if (!strcmp(id, "false") ||
375 !strcmp(id, "FALSE") ||
376 !strcmp(id, "no") ||
377 !strcmp(id, "NO")) {
378 value = bt_value_bool_create_init(false);
379 } else {
380 value = bt_value_string_create_init(id);
381 }
382 break;
383 }
384 default:
385 /* Unset value variable will trigger the error */
386 break;
387 }
388
389 if (!value) {
390 ini_append_error_expecting(state,
391 state->scanner, "value");
392 goto error;
393 }
394
395 state->expecting = INI_EXPECT_COMMA;
396 goto success;
397 }
398 case INI_EXPECT_VALUE_NUMBER_NEG:
399 {
400 switch (token_type) {
401 case G_TOKEN_INT:
402 {
403 /* Negative integer */
404 uint64_t int_val = state->scanner->value.v_int64;
405
406 if (int_val > (1ULL << 63) - 1) {
407 g_string_append_printf(state->ini_error,
408 "Integer value -%" PRIu64 " is outside the range of a 64-bit signed integer\n",
409 int_val);
410 goto error;
411 }
412
413 value = bt_value_integer_create_init(
414 -((int64_t) int_val));
415 break;
416 }
417 case G_TOKEN_FLOAT:
418 /* Negative floating point number */
419 value = bt_value_float_create_init(
420 -state->scanner->value.v_float);
421 break;
422 default:
423 /* Unset value variable will trigger the error */
424 break;
425 }
426
427 if (!value) {
428 ini_append_error_expecting(state,
429 state->scanner, "value");
430 goto error;
431 }
432
433 state->expecting = INI_EXPECT_COMMA;
434 goto success;
435 }
436 case INI_EXPECT_COMMA:
437 if (token_type != G_TOKEN_CHAR) {
438 ini_append_error_expecting(state,
439 state->scanner, "','");
440 goto error;
441 }
442
443 if (state->scanner->value.v_char != ',') {
444 ini_append_error_expecting(state,
445 state->scanner, "','");
446 goto error;
447 }
448
449 state->expecting = INI_EXPECT_MAP_KEY;
450 goto success;
451 default:
452 assert(false);
453 }
454
455error:
456 ret = -1;
457 goto end;
458
459success:
460 if (value) {
461 if (bt_value_map_insert(state->params,
462 state->last_map_key, value)) {
463 /* Only override return value on error */
464 ret = -1;
465 }
466 }
467
468end:
469 BT_PUT(value);
470 return ret;
471}
472
473/*
474 * Converts an INI-style argument to an equivalent map value object.
475 *
476 * Return value is owned by the caller.
477 */
478static
479struct bt_value *bt_value_from_ini(const char *arg, GString *ini_error)
480{
481 /* Lexical scanner configuration */
482 GScannerConfig scanner_config = {
483 /* Skip whitespaces */
484 .cset_skip_characters = " \t\n",
485
486 /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
487 .cset_identifier_first =
488 G_CSET_a_2_z
489 "_"
490 G_CSET_A_2_Z,
491 .cset_identifier_nth =
492 G_CSET_a_2_z
493 "_0123456789-.:"
494 G_CSET_A_2_Z,
495
496 /* "hello" and "Hello" two different keys */
497 .case_sensitive = TRUE,
498
499 /* No comments */
500 .cpair_comment_single = NULL,
501 .skip_comment_multi = TRUE,
502 .skip_comment_single = TRUE,
503 .scan_comment_multi = FALSE,
504
505 /*
506 * Do scan identifiers, including 1-char identifiers,
507 * but NULL is a normal identifier.
508 */
509 .scan_identifier = TRUE,
510 .scan_identifier_1char = TRUE,
511 .scan_identifier_NULL = FALSE,
512
513 /*
514 * No specific symbols: null and boolean "symbols" are
515 * scanned as plain identifiers.
516 */
517 .scan_symbols = FALSE,
518 .symbol_2_token = FALSE,
519 .scope_0_fallback = FALSE,
520
521 /*
522 * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
523 * integers prefixed with "$".
524 */
525 .scan_binary = TRUE,
526 .scan_octal = TRUE,
527 .scan_float = TRUE,
528 .scan_hex = TRUE,
529 .scan_hex_dollar = FALSE,
530
531 /* Convert scanned numbers to integer tokens */
532 .numbers_2_int = TRUE,
533
534 /* Support both integers and floating-point numbers */
535 .int_2_float = FALSE,
536
537 /* Scan integers as 64-bit signed integers */
538 .store_int64 = TRUE,
539
540 /* Only scan double-quoted strings */
541 .scan_string_sq = FALSE,
542 .scan_string_dq = TRUE,
543
544 /* Do not converter identifiers to string tokens */
545 .identifier_2_string = FALSE,
546
547 /* Scan characters as G_TOKEN_CHAR token */
548 .char_2_token = FALSE,
549 };
550 struct ini_parsing_state state = {
551 .scanner = NULL,
552 .params = NULL,
553 .expecting = INI_EXPECT_MAP_KEY,
554 .arg = arg,
555 .ini_error = ini_error,
556 };
557
558 state.params = bt_value_map_create();
559 if (!state.params) {
560 goto error;
561 }
562
563 state.scanner = g_scanner_new(&scanner_config);
564 if (!state.scanner) {
565 goto error;
566 }
567
568 /* Let the scan begin */
569 g_scanner_input_text(state.scanner, arg, strlen(arg));
570
571 while (true) {
572 int ret = ini_handle_state(&state);
573
574 if (ret < 0) {
575 /* Error */
576 goto error;
577 } else if (ret > 0) {
578 /* Done */
579 break;
580 }
581 }
582
583 goto end;
584
585error:
586 BT_PUT(state.params);
587
588end:
589 if (state.scanner) {
590 g_scanner_destroy(state.scanner);
591 }
592
593 free(state.last_map_key);
594 return state.params;
595}
596
597/*
598 * Returns the parameters map value object from a command-line
bdc61c70 599 * parameter option's argument.
c42c79ea
PP
600 *
601 * Return value is owned by the caller.
602 */
603static
604struct bt_value *bt_value_from_arg(const char *arg)
605{
606 struct bt_value *params = NULL;
c42c79ea
PP
607 GString *ini_error = NULL;
608
c42c79ea
PP
609 ini_error = g_string_new(NULL);
610 if (!ini_error) {
611 print_err_oom();
612 goto end;
613 }
614
615 /* Try INI-style parsing */
bdc61c70 616 params = bt_value_from_ini(arg, ini_error);
c42c79ea
PP
617 if (!params) {
618 printf_err("%s", ini_error->str);
619 goto end;
620 }
621
622end:
623 if (ini_error) {
624 g_string_free(ini_error, TRUE);
625 }
626 return params;
627}
628
629/*
630 * Returns the plugin and component names from a command-line
bdc61c70
PP
631 * source/sink option's argument. arg must have the following format:
632 *
633 * PLUGIN.COMPONENT
634 *
635 * where PLUGIN is the plugin name, and COMPONENT is the component
636 * name.
c42c79ea
PP
637 *
638 * On success, both *plugin and *component are not NULL. *plugin
639 * and *component are owned by the caller.
640 */
641static
642void plugin_component_names_from_arg(const char *arg, char **plugin,
643 char **component)
644{
645 const char *dot;
bdc61c70 646 const char *end;
c42c79ea
PP
647 size_t plugin_len;
648 size_t component_len;
649
bdc61c70 650 /* Initialize both return values to NULL: not found */
c42c79ea
PP
651 *plugin = NULL;
652 *component = NULL;
653
654 dot = strchr(arg, '.');
bdc61c70
PP
655 if (!dot) {
656 /* No dot */
c42c79ea
PP
657 goto end;
658 }
659
bdc61c70 660 end = arg + strlen(arg);
c42c79ea 661 plugin_len = dot - arg;
bdc61c70 662 component_len = end - dot - 1;
c42c79ea
PP
663 if (plugin_len == 0 || component_len == 0) {
664 goto end;
665 }
666
bdc61c70 667 *plugin = g_malloc0(plugin_len + 1);
c42c79ea
PP
668 if (!*plugin) {
669 print_err_oom();
670 goto end;
671 }
672
bdc61c70
PP
673 g_strlcpy(*plugin, arg, plugin_len + 1);
674 *component = g_malloc0(component_len + 1);
c42c79ea
PP
675 if (!*component) {
676 print_err_oom();
677 goto end;
678 }
679
bdc61c70 680 g_strlcpy(*component, dot + 1, component_len + 1);
c42c79ea
PP
681
682end:
683 return;
684}
685
686/*
687 * Prints the Babeltrace version.
688 */
689static
690void print_version(void)
691{
692 puts("Babeltrace " VERSION);
693}
694
c42c79ea
PP
695/*
696 * Destroys a component configuration.
697 */
698static
699void bt_config_component_destroy(struct bt_object *obj)
700{
701 struct bt_config_component *bt_config_component =
702 container_of(obj, struct bt_config_component, base);
703
704 if (!obj) {
705 goto end;
706 }
707
708 if (bt_config_component->plugin_name) {
709 g_string_free(bt_config_component->plugin_name, TRUE);
710 }
711
712 if (bt_config_component->component_name) {
713 g_string_free(bt_config_component->component_name, TRUE);
714 }
715
3b6cfcc5
PP
716 if (bt_config_component->instance_name) {
717 g_string_free(bt_config_component->instance_name, TRUE);
718 }
719
c42c79ea
PP
720 BT_PUT(bt_config_component->params);
721 g_free(bt_config_component);
722
723end:
724 return;
725}
726
727/*
bdc61c70
PP
728 * Creates a component configuration using the given plugin name and
729 * component name. plugin_name and component_name are copied (belong to
730 * the return value).
c42c79ea
PP
731 *
732 * Return value is owned by the caller.
733 */
734static
90de159b
PP
735struct bt_config_component *bt_config_component_create(
736 enum bt_component_class_type type,
737 const char *plugin_name, const char *component_name)
c42c79ea
PP
738{
739 struct bt_config_component *cfg_component = NULL;
740
741 cfg_component = g_new0(struct bt_config_component, 1);
742 if (!cfg_component) {
743 print_err_oom();
744 goto error;
745 }
746
747 bt_object_init(cfg_component, bt_config_component_destroy);
90de159b 748 cfg_component->type = type;
c42c79ea
PP
749 cfg_component->plugin_name = g_string_new(plugin_name);
750 if (!cfg_component->plugin_name) {
751 print_err_oom();
752 goto error;
753 }
754
755 cfg_component->component_name = g_string_new(component_name);
756 if (!cfg_component->component_name) {
757 print_err_oom();
758 goto error;
759 }
760
3b6cfcc5
PP
761 cfg_component->instance_name = g_string_new(NULL);
762 if (!cfg_component->instance_name) {
763 print_err_oom();
764 goto error;
765 }
766
bdc61c70
PP
767 /* Start with empty parameters */
768 cfg_component->params = bt_value_map_create();
769 if (!cfg_component->params) {
770 print_err_oom();
771 goto error;
772 }
773
c42c79ea
PP
774 goto end;
775
776error:
777 BT_PUT(cfg_component);
778
779end:
780 return cfg_component;
781}
782
783/*
784 * Creates a component configuration from a command-line source/sink
bdc61c70 785 * option's argument.
c42c79ea 786 */
90de159b
PP
787struct bt_config_component *bt_config_component_from_arg(
788 enum bt_component_class_type type, const char *arg)
c42c79ea
PP
789{
790 struct bt_config_component *bt_config_component = NULL;
791 char *plugin_name;
792 char *component_name;
c42c79ea
PP
793
794 plugin_component_names_from_arg(arg, &plugin_name, &component_name);
795 if (!plugin_name || !component_name) {
49849a47 796 printf_err("Cannot get plugin or component class name\n");
c42c79ea
PP
797 goto error;
798 }
799
90de159b 800 bt_config_component = bt_config_component_create(type, plugin_name,
bdc61c70 801 component_name);
c42c79ea
PP
802 if (!bt_config_component) {
803 goto error;
804 }
805
806 goto end;
807
808error:
809 BT_PUT(bt_config_component);
810
811end:
bdc61c70
PP
812 g_free(plugin_name);
813 g_free(component_name);
c42c79ea
PP
814 return bt_config_component;
815}
816
817/*
818 * Destroys a configuration.
819 */
820static
821void bt_config_destroy(struct bt_object *obj)
822{
290725f7 823 struct bt_config *cfg =
c42c79ea
PP
824 container_of(obj, struct bt_config, base);
825
826 if (!obj) {
827 goto end;
828 }
829
290725f7
PP
830 switch (cfg->command) {
831 case BT_CONFIG_COMMAND_CONVERT:
832 if (cfg->cmd_data.convert.sources) {
833 g_ptr_array_free(cfg->cmd_data.convert.sources, TRUE);
834 }
c42c79ea 835
ebba3338
PP
836 if (cfg->cmd_data.convert.filters) {
837 g_ptr_array_free(cfg->cmd_data.convert.filters, TRUE);
838 }
839
290725f7
PP
840 if (cfg->cmd_data.convert.sinks) {
841 g_ptr_array_free(cfg->cmd_data.convert.sinks, TRUE);
842 }
843
ebba3338
PP
844 if (cfg->cmd_data.convert.connections) {
845 g_ptr_array_free(cfg->cmd_data.convert.connections,
846 TRUE);
847 }
848
290725f7
PP
849 BT_PUT(cfg->cmd_data.convert.plugin_paths);
850 break;
290725f7
PP
851 case BT_CONFIG_COMMAND_LIST_PLUGINS:
852 BT_PUT(cfg->cmd_data.list_plugins.plugin_paths);
853 break;
22e22462
PP
854 case BT_CONFIG_COMMAND_HELP:
855 BT_PUT(cfg->cmd_data.help.plugin_paths);
90de159b 856 BT_PUT(cfg->cmd_data.help.cfg_component);
22e22462 857 break;
290725f7
PP
858 default:
859 assert(false);
c42c79ea
PP
860 }
861
290725f7 862 g_free(cfg);
c42c79ea
PP
863
864end:
865 return;
866}
867
1670bffd
PP
868static void destroy_gstring(void *data)
869{
870 g_string_free(data, TRUE);
871}
872
c42c79ea
PP
873/*
874 * Extracts the various paths from the string arg, delimited by ':',
5a3ee633 875 * and appends them to the array value object plugin_paths.
c42c79ea 876 */
5a3ee633
PP
877enum bt_value_status bt_config_append_plugin_paths(
878 struct bt_value *plugin_paths, const char *arg)
c42c79ea 879{
1670bffd
PP
880 enum bt_value_status status = BT_VALUE_STATUS_OK;
881 GPtrArray *dirs = g_ptr_array_new_with_free_func(destroy_gstring);
882 int ret;
883 size_t i;
c42c79ea 884
1670bffd
PP
885 if (!dirs) {
886 status = BT_VALUE_STATUS_ERROR;
887 goto end;
888 }
c42c79ea 889
1670bffd
PP
890 ret = bt_common_append_plugin_path_dirs(arg, dirs);
891 if (ret) {
892 status = BT_VALUE_STATUS_ERROR;
893 goto end;
894 }
c42c79ea 895
1670bffd
PP
896 for (i = 0; i < dirs->len; i++) {
897 GString *dir = g_ptr_array_index(dirs, i);
c42c79ea 898
1670bffd 899 bt_value_array_append_string(plugin_paths, dir->str);
c42c79ea
PP
900 }
901
1670bffd
PP
902end:
903 g_ptr_array_free(dirs, TRUE);
904 return status;
c42c79ea
PP
905}
906
907/*
908 * Creates a simple lexical scanner for parsing comma-delimited names
909 * and fields.
910 *
911 * Return value is owned by the caller.
912 */
913static
914GScanner *create_csv_identifiers_scanner(void)
915{
916 GScannerConfig scanner_config = {
917 .cset_skip_characters = " \t\n",
918 .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
919 .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
920 .case_sensitive = TRUE,
921 .cpair_comment_single = NULL,
922 .skip_comment_multi = TRUE,
923 .skip_comment_single = TRUE,
924 .scan_comment_multi = FALSE,
925 .scan_identifier = TRUE,
926 .scan_identifier_1char = TRUE,
927 .scan_identifier_NULL = FALSE,
928 .scan_symbols = FALSE,
929 .symbol_2_token = FALSE,
930 .scope_0_fallback = FALSE,
931 .scan_binary = FALSE,
932 .scan_octal = FALSE,
933 .scan_float = FALSE,
934 .scan_hex = FALSE,
935 .scan_hex_dollar = FALSE,
936 .numbers_2_int = FALSE,
937 .int_2_float = FALSE,
938 .store_int64 = FALSE,
939 .scan_string_sq = FALSE,
940 .scan_string_dq = FALSE,
941 .identifier_2_string = FALSE,
942 .char_2_token = TRUE,
943 };
944
945 return g_scanner_new(&scanner_config);
946}
947
6e1bc0df
MD
948/*
949 * Inserts a string (if exists and not empty) or null to a map value
950 * object.
951 */
952static
953enum bt_value_status map_insert_string_or_null(struct bt_value *map,
954 const char *key, GString *string)
955{
956 enum bt_value_status ret;
957
958 if (string && string->len > 0) {
959 ret = bt_value_map_insert_string(map, key, string->str);
960 } else {
961 ret = bt_value_map_insert(map, key, bt_value_null);
962 }
963 return ret;
964}
965
c42c79ea
PP
966/*
967 * Converts a comma-delimited list of known names (--names option) to
968 * an array value object containing those names as string value objects.
969 *
970 * Return value is owned by the caller.
971 */
972static
973struct bt_value *names_from_arg(const char *arg)
974{
975 GScanner *scanner = NULL;
976 struct bt_value *names = NULL;
6e1bc0df 977 bool found_all = false, found_none = false, found_item = false;
c42c79ea
PP
978
979 names = bt_value_array_create();
980 if (!names) {
981 print_err_oom();
982 goto error;
983 }
984
985 scanner = create_csv_identifiers_scanner();
986 if (!scanner) {
987 print_err_oom();
988 goto error;
989 }
990
991 g_scanner_input_text(scanner, arg, strlen(arg));
992
993 while (true) {
994 GTokenType token_type = g_scanner_get_next_token(scanner);
995
996 switch (token_type) {
997 case G_TOKEN_IDENTIFIER:
998 {
999 const char *identifier = scanner->value.v_identifier;
1000
1001 if (!strcmp(identifier, "payload") ||
1002 !strcmp(identifier, "args") ||
1003 !strcmp(identifier, "arg")) {
6e1bc0df 1004 found_item = true;
c42c79ea
PP
1005 if (bt_value_array_append_string(names,
1006 "payload")) {
1007 goto error;
1008 }
1009 } else if (!strcmp(identifier, "context") ||
1010 !strcmp(identifier, "ctx")) {
6e1bc0df 1011 found_item = true;
c42c79ea
PP
1012 if (bt_value_array_append_string(names,
1013 "context")) {
1014 goto error;
1015 }
1016 } else if (!strcmp(identifier, "scope") ||
1017 !strcmp(identifier, "header")) {
6e1bc0df 1018 found_item = true;
c42c79ea
PP
1019 if (bt_value_array_append_string(names,
1020 identifier)) {
1021 goto error;
1022 }
6e1bc0df
MD
1023 } else if (!strcmp(identifier, "all")) {
1024 found_all = true;
1025 if (bt_value_array_append_string(names,
1026 identifier)) {
c42c79ea
PP
1027 goto error;
1028 }
6e1bc0df
MD
1029 } else if (!strcmp(identifier, "none")) {
1030 found_none = true;
c42c79ea
PP
1031 if (bt_value_array_append_string(names,
1032 identifier)) {
1033 goto error;
1034 }
c42c79ea 1035 } else {
6d1d5711 1036 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1037 identifier);
1038 goto error;
1039 }
1040 break;
1041 }
1042 case G_TOKEN_COMMA:
1043 continue;
1044 case G_TOKEN_EOF:
1045 goto end;
1046 default:
1047 goto error;
1048 }
1049 }
1050
6e1bc0df
MD
1051end:
1052 if (found_none && found_all) {
6d1d5711 1053 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
6e1bc0df
MD
1054 goto error;
1055 }
1056 /*
1057 * Legacy behavior is to clear the defaults (show none) when at
1058 * least one item is specified.
1059 */
1060 if (found_item && !found_none && !found_all) {
1061 if (bt_value_array_append_string(names, "none")) {
1062 goto error;
1063 }
1064 }
1065 if (scanner) {
1066 g_scanner_destroy(scanner);
1067 }
1068 return names;
c42c79ea
PP
1069
1070error:
1071 BT_PUT(names);
c42c79ea
PP
1072 if (scanner) {
1073 g_scanner_destroy(scanner);
1074 }
1075 return names;
1076}
1077
1078
1079/*
1080 * Converts a comma-delimited list of known fields (--fields option) to
1081 * an array value object containing those fields as string
1082 * value objects.
1083 *
1084 * Return value is owned by the caller.
1085 */
1086static
1087struct bt_value *fields_from_arg(const char *arg)
1088{
1089 GScanner *scanner = NULL;
1090 struct bt_value *fields;
1091
1092 fields = bt_value_array_create();
1093 if (!fields) {
1094 print_err_oom();
1095 goto error;
1096 }
1097
1098 scanner = create_csv_identifiers_scanner();
1099 if (!scanner) {
1100 print_err_oom();
1101 goto error;
1102 }
1103
1104 g_scanner_input_text(scanner, arg, strlen(arg));
1105
1106 while (true) {
1107 GTokenType token_type = g_scanner_get_next_token(scanner);
1108
1109 switch (token_type) {
1110 case G_TOKEN_IDENTIFIER:
1111 {
1112 const char *identifier = scanner->value.v_identifier;
1113
1114 if (!strcmp(identifier, "trace") ||
1115 !strcmp(identifier, "trace:hostname") ||
1116 !strcmp(identifier, "trace:domain") ||
1117 !strcmp(identifier, "trace:procname") ||
1118 !strcmp(identifier, "trace:vpid") ||
1119 !strcmp(identifier, "loglevel") ||
1120 !strcmp(identifier, "emf") ||
6e1bc0df
MD
1121 !strcmp(identifier, "callsite") ||
1122 !strcmp(identifier, "all")) {
c42c79ea
PP
1123 if (bt_value_array_append_string(fields,
1124 identifier)) {
1125 goto error;
1126 }
c42c79ea 1127 } else {
6d1d5711 1128 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1129 identifier);
1130 goto error;
1131 }
1132 break;
1133 }
1134 case G_TOKEN_COMMA:
1135 continue;
1136 case G_TOKEN_EOF:
1137 goto end;
1138 default:
1139 goto error;
1140 }
1141 }
1142
1143 goto end;
1144
1145error:
1146 BT_PUT(fields);
1147
1148end:
1149 if (scanner) {
1150 g_scanner_destroy(scanner);
1151 }
1152 return fields;
1153}
1154
1155/*
1156 * Inserts the equivalent "prefix-name" true boolean value objects into
1157 * map_obj where the names are in array_obj.
1158 */
1159static
1160int insert_flat_names_fields_from_array(struct bt_value *map_obj,
1161 struct bt_value *array_obj, const char *prefix)
1162{
1163 int ret = 0;
1164 int i;
6e1bc0df 1165 GString *tmpstr = NULL, *default_value = NULL;
c42c79ea
PP
1166
1167 /*
1168 * array_obj may be NULL if no CLI options were specified to
1169 * trigger its creation.
1170 */
1171 if (!array_obj) {
1172 goto end;
1173 }
1174
1175 tmpstr = g_string_new(NULL);
1176 if (!tmpstr) {
1177 print_err_oom();
1178 ret = -1;
1179 goto end;
1180 }
1181
6e1bc0df
MD
1182 default_value = g_string_new(NULL);
1183 if (!default_value) {
1184 print_err_oom();
1185 ret = -1;
1186 goto end;
1187 }
1188
c42c79ea
PP
1189 for (i = 0; i < bt_value_array_size(array_obj); i++) {
1190 struct bt_value *str_obj = bt_value_array_get(array_obj, i);
1191 const char *suffix;
6e1bc0df 1192 bool is_default = false;
c42c79ea
PP
1193
1194 if (!str_obj) {
1195 printf_err("Unexpected error\n");
1196 ret = -1;
1197 goto end;
1198 }
1199
1200 ret = bt_value_string_get(str_obj, &suffix);
1201 BT_PUT(str_obj);
1202 if (ret) {
1203 printf_err("Unexpected error\n");
1204 goto end;
1205 }
1206
1207 g_string_assign(tmpstr, prefix);
1208 g_string_append(tmpstr, "-");
6e1bc0df
MD
1209
1210 /* Special-case for "all" and "none". */
1211 if (!strcmp(suffix, "all")) {
1212 is_default = true;
1213 g_string_assign(default_value, "show");
1214 } else if (!strcmp(suffix, "none")) {
1215 is_default = true;
1216 g_string_assign(default_value, "hide");
1217 }
1218 if (is_default) {
1219 g_string_append(tmpstr, "default");
1220 ret = map_insert_string_or_null(map_obj,
1221 tmpstr->str,
1222 default_value);
1223 if (ret) {
1224 print_err_oom();
1225 goto end;
1226 }
1227 } else {
1228 g_string_append(tmpstr, suffix);
1229 ret = bt_value_map_insert_bool(map_obj, tmpstr->str,
1230 true);
1231 if (ret) {
1232 print_err_oom();
1233 goto end;
1234 }
c42c79ea
PP
1235 }
1236 }
1237
1238end:
6e1bc0df
MD
1239 if (default_value) {
1240 g_string_free(default_value, TRUE);
1241 }
c42c79ea
PP
1242 if (tmpstr) {
1243 g_string_free(tmpstr, TRUE);
1244 }
1245
1246 return ret;
1247}
1248
c42c79ea
PP
1249/*
1250 * Returns the parameters (map value object) corresponding to the
1251 * legacy text format options.
1252 *
1253 * Return value is owned by the caller.
1254 */
1255static
1256struct bt_value *params_from_text_legacy_opts(
1257 struct text_legacy_opts *text_legacy_opts)
1258{
1259 struct bt_value *params;
1260
1261 params = bt_value_map_create();
1262 if (!params) {
1263 print_err_oom();
1264 goto error;
1265 }
1266
1267 if (map_insert_string_or_null(params, "output-path",
1268 text_legacy_opts->output)) {
1269 print_err_oom();
1270 goto error;
1271 }
1272
1273 if (map_insert_string_or_null(params, "debug-info-dir",
1274 text_legacy_opts->dbg_info_dir)) {
1275 print_err_oom();
1276 goto error;
1277 }
1278
1279 if (map_insert_string_or_null(params, "debug-info-target-prefix",
1280 text_legacy_opts->dbg_info_target_prefix)) {
1281 print_err_oom();
1282 goto error;
1283 }
1284
1285 if (bt_value_map_insert_bool(params, "debug-info-full-path",
1286 text_legacy_opts->dbg_info_full_path)) {
1287 print_err_oom();
1288 goto error;
1289 }
1290
1291 if (bt_value_map_insert_bool(params, "no-delta",
1292 text_legacy_opts->no_delta)) {
1293 print_err_oom();
1294 goto error;
1295 }
1296
1297 if (bt_value_map_insert_bool(params, "clock-cycles",
1298 text_legacy_opts->clock_cycles)) {
1299 print_err_oom();
1300 goto error;
1301 }
1302
1303 if (bt_value_map_insert_bool(params, "clock-seconds",
1304 text_legacy_opts->clock_seconds)) {
1305 print_err_oom();
1306 goto error;
1307 }
1308
1309 if (bt_value_map_insert_bool(params, "clock-date",
1310 text_legacy_opts->clock_date)) {
1311 print_err_oom();
1312 goto error;
1313 }
1314
1315 if (bt_value_map_insert_bool(params, "clock-gmt",
1316 text_legacy_opts->clock_gmt)) {
1317 print_err_oom();
1318 goto error;
1319 }
1320
1321 if (insert_flat_names_fields_from_array(params,
1322 text_legacy_opts->names, "name")) {
1323 goto error;
1324 }
1325
1326 if (insert_flat_names_fields_from_array(params,
1327 text_legacy_opts->fields, "field")) {
1328 goto error;
1329 }
1330
1331 goto end;
1332
1333error:
1334 BT_PUT(params);
1335
1336end:
1337 return params;
1338}
1339
1340static
1341int append_sinks_from_legacy_opts(GPtrArray *sinks,
1342 enum legacy_output_format legacy_output_format,
1343 struct text_legacy_opts *text_legacy_opts)
1344{
1345 int ret = 0;
1346 struct bt_value *params = NULL;
1347 const char *plugin_name;
1348 const char *component_name;
1349 struct bt_config_component *bt_config_component = NULL;
1350
1351 switch (legacy_output_format) {
1352 case LEGACY_OUTPUT_FORMAT_TEXT:
1353 plugin_name = "text";
1354 component_name = "text";
1355 break;
1356 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1357 plugin_name = "ctf";
1358 component_name = "metadata-text";
1359 break;
1360 case LEGACY_OUTPUT_FORMAT_DUMMY:
9987e1ac 1361 plugin_name = "utils";
c42c79ea
PP
1362 component_name = "dummy";
1363 break;
1364 default:
1365 assert(false);
1366 break;
1367 }
1368
1369 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT) {
1370 /* Legacy "text" output format has parameters */
1371 params = params_from_text_legacy_opts(text_legacy_opts);
1372 if (!params) {
1373 goto error;
1374 }
1375 } else {
1376 /*
1377 * Legacy "dummy" and "ctf-metadata" output formats do
1378 * not have parameters.
1379 */
1380 params = bt_value_map_create();
1381 if (!params) {
1382 print_err_oom();
1383 goto error;
1384 }
1385 }
1386
1387 /* Create a component configuration */
90de159b
PP
1388 bt_config_component = bt_config_component_create(
1389 BT_COMPONENT_CLASS_TYPE_SINK, plugin_name, component_name);
c42c79ea
PP
1390 if (!bt_config_component) {
1391 goto error;
1392 }
1393
bdc61c70
PP
1394 BT_MOVE(bt_config_component->params, params);
1395
c42c79ea
PP
1396 /* Move created component configuration to the array */
1397 g_ptr_array_add(sinks, bt_config_component);
1398
1399 goto end;
1400
1401error:
1402 ret = -1;
1403
1404end:
1405 BT_PUT(params);
1406
1407 return ret;
1408}
1409
1410/*
1411 * Returns the parameters (map value object) corresponding to the
1412 * given legacy CTF format options.
1413 *
1414 * Return value is owned by the caller.
1415 */
1416static
1417struct bt_value *params_from_ctf_legacy_opts(
1418 struct ctf_legacy_opts *ctf_legacy_opts)
1419{
1420 struct bt_value *params;
1421
1422 params = bt_value_map_create();
1423 if (!params) {
1424 print_err_oom();
1425 goto error;
1426 }
1427
1428 if (bt_value_map_insert_integer(params, "offset-s",
1429 ctf_legacy_opts->offset_s.value)) {
1430 print_err_oom();
1431 goto error;
1432 }
1433
1434 if (bt_value_map_insert_integer(params, "offset-ns",
1435 ctf_legacy_opts->offset_ns.value)) {
1436 print_err_oom();
1437 goto error;
1438 }
1439
1440 if (bt_value_map_insert_bool(params, "stream-intersection",
1441 ctf_legacy_opts->stream_intersection)) {
1442 print_err_oom();
1443 goto error;
1444 }
1445
1446 goto end;
1447
1448error:
1449 BT_PUT(params);
1450
1451end:
1452 return params;
1453}
1454
1455static
1456int append_sources_from_legacy_opts(GPtrArray *sources,
1457 enum legacy_input_format legacy_input_format,
1458 struct ctf_legacy_opts *ctf_legacy_opts,
528debdf 1459 struct bt_value *legacy_input_paths)
c42c79ea
PP
1460{
1461 int ret = 0;
1462 int i;
1463 struct bt_value *base_params;
1464 struct bt_value *params = NULL;
1465 struct bt_value *input_path = NULL;
1466 struct bt_value *input_path_copy = NULL;
1467 const char *input_key;
1468 const char *component_name;
1469
1470 switch (legacy_input_format) {
1471 case LEGACY_INPUT_FORMAT_CTF:
1472 input_key = "path";
1473 component_name = "fs";
1474 break;
1475 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1476 input_key = "url";
1477 component_name = "lttng-live";
1478 break;
1479 default:
1480 assert(false);
1481 break;
1482 }
1483
1484 base_params = params_from_ctf_legacy_opts(ctf_legacy_opts);
1485 if (!base_params) {
1486 goto error;
1487 }
1488
1489 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1490 struct bt_config_component *bt_config_component = NULL;
1491
1492 /* Copy base parameters as current parameters */
1493 params = bt_value_copy(base_params);
1494 if (!params) {
1495 goto error;
1496 }
1497
1498 /* Get current input path string value object */
1499 input_path = bt_value_array_get(legacy_input_paths, i);
1500 if (!input_path) {
1501 goto error;
1502 }
1503
1504 /* Copy current input path value object */
1505 input_path_copy = bt_value_copy(input_path);
1506 if (!input_path_copy) {
1507 goto error;
1508 }
1509
1510 /* Insert input path value object into current parameters */
1511 ret = bt_value_map_insert(params, input_key, input_path_copy);
1512 if (ret) {
1513 goto error;
1514 }
1515
1516 /* Create a component configuration */
90de159b
PP
1517 bt_config_component = bt_config_component_create(
1518 BT_COMPONENT_CLASS_TYPE_SOURCE, "ctf", component_name);
c42c79ea
PP
1519 if (!bt_config_component) {
1520 goto error;
1521 }
1522
bdc61c70
PP
1523 BT_MOVE(bt_config_component->params, params);
1524
c42c79ea
PP
1525 /* Move created component configuration to the array */
1526 g_ptr_array_add(sources, bt_config_component);
1527
1528 /* Put current stuff */
1529 BT_PUT(input_path);
1530 BT_PUT(input_path_copy);
c42c79ea
PP
1531 }
1532
1533 goto end;
1534
1535error:
1536 ret = -1;
1537
1538end:
1539 BT_PUT(base_params);
1540 BT_PUT(params);
1541 BT_PUT(input_path);
1542 BT_PUT(input_path_copy);
1543 return ret;
1544}
1545
1546/*
1547 * Escapes a string for the shell. The string is escaped knowing that
1548 * it's a parameter string value (double-quoted), and that it will be
1549 * entered between single quotes in the shell.
1550 *
1551 * Return value is owned by the caller.
1552 */
1553static
1554char *str_shell_escape(const char *input)
1555{
1556 char *ret = NULL;
1557 const char *at = input;
1558 GString *str = g_string_new(NULL);
1559
1560 if (!str) {
1561 goto end;
1562 }
1563
1564 while (*at != '\0') {
1565 switch (*at) {
1566 case '\\':
1567 g_string_append(str, "\\\\");
1568 break;
1569 case '"':
1570 g_string_append(str, "\\\"");
1571 break;
1572 case '\'':
1573 g_string_append(str, "'\"'\"'");
1574 break;
1575 case '\n':
1576 g_string_append(str, "\\n");
1577 break;
1578 case '\t':
1579 g_string_append(str, "\\t");
1580 break;
1581 default:
1582 g_string_append_c(str, *at);
1583 break;
1584 }
1585
1586 at++;
1587 }
1588
1589end:
1590 if (str) {
1591 ret = str->str;
1592 g_string_free(str, FALSE);
1593 }
1594
1595 return ret;
1596}
1597
1598static
1599int append_prefixed_flag_params(GString *str, struct bt_value *flags,
1600 const char *prefix)
1601{
1602 int ret = 0;
1603 int i;
1604
1605 if (!flags) {
1606 goto end;
1607 }
1608
1609 for (i = 0; i < bt_value_array_size(flags); i++) {
1610 struct bt_value *value = bt_value_array_get(flags, i);
1611 const char *flag;
1612
1613 if (!value) {
1614 ret = -1;
1615 goto end;
1616 }
1617
1618 if (bt_value_string_get(value, &flag)) {
1619 BT_PUT(value);
1620 ret = -1;
1621 goto end;
1622 }
1623
1624 g_string_append_printf(str, ",%s-%s=true", prefix, flag);
1625 BT_PUT(value);
1626 }
1627
1628end:
1629 return ret;
1630}
1631
1632/*
1633 * Appends a boolean parameter string.
1634 */
1635static
1636void g_string_append_bool_param(GString *str, const char *name, bool value)
1637{
1638 g_string_append_printf(str, ",%s=%s", name, value ? "true" : "false");
1639}
1640
1641/*
1642 * Appends a path parameter string, or null if it's empty.
1643 */
1644static
1645int g_string_append_string_path_param(GString *str, const char *name,
1646 GString *path)
1647{
1648 int ret = 0;
1649
1650 if (path->len > 0) {
1651 char *escaped_path = str_shell_escape(path->str);
1652
1653 if (!escaped_path) {
1654 print_err_oom();
1655 goto error;
1656 }
1657
1658 g_string_append_printf(str, "%s=\"%s\"", name, escaped_path);
1659 free(escaped_path);
1660 } else {
1661 g_string_append_printf(str, "%s=null", name);
1662 }
1663
1664 goto end;
1665
1666error:
1667 ret = -1;
1668
1669end:
1670 return ret;
1671}
1672
1673/*
1674 * Prints the non-legacy sink options equivalent to the specified
1675 * legacy output format options.
1676 */
1677static
1678void print_output_legacy_to_sinks(
1679 enum legacy_output_format legacy_output_format,
1680 struct text_legacy_opts *text_legacy_opts)
1681{
9987e1ac 1682 const char *output_format;
c42c79ea
PP
1683 GString *str = NULL;
1684
1685 str = g_string_new(" ");
1686 if (!str) {
1687 print_err_oom();
1688 goto end;
1689 }
1690
1691 switch (legacy_output_format) {
1692 case LEGACY_OUTPUT_FORMAT_TEXT:
9987e1ac 1693 output_format = "text";
c42c79ea
PP
1694 break;
1695 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
9987e1ac 1696 output_format = "ctf-metadata";
c42c79ea
PP
1697 break;
1698 case LEGACY_OUTPUT_FORMAT_DUMMY:
9987e1ac 1699 output_format = "dummy";
c42c79ea
PP
1700 break;
1701 default:
1702 assert(false);
1703 }
1704
49849a47 1705 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
9987e1ac 1706 output_format);
49849a47 1707 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
9987e1ac 1708 output_format);
c42c79ea
PP
1709 g_string_append(str, "-o ");
1710
1711 switch (legacy_output_format) {
1712 case LEGACY_OUTPUT_FORMAT_TEXT:
1713 g_string_append(str, "text.text");
1714 break;
1715 case LEGACY_OUTPUT_FORMAT_CTF_METADATA:
1716 g_string_append(str, "ctf.metadata-text");
1717 break;
1718 case LEGACY_OUTPUT_FORMAT_DUMMY:
9987e1ac 1719 g_string_append(str, "utils.dummy");
c42c79ea
PP
1720 break;
1721 default:
1722 assert(false);
1723 }
1724
1725 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT &&
1726 text_legacy_opts_is_any_set(text_legacy_opts)) {
1727 int ret;
1728
bdc61c70 1729 g_string_append(str, " -p '");
c42c79ea
PP
1730
1731 if (g_string_append_string_path_param(str, "output-path",
1732 text_legacy_opts->output)) {
1733 goto end;
1734 }
1735
1736 g_string_append(str, ",");
1737
1738 if (g_string_append_string_path_param(str, "debug-info-dir",
1739 text_legacy_opts->dbg_info_dir)) {
1740 goto end;
1741 }
1742
1743 g_string_append(str, ",");
1744
1745 if (g_string_append_string_path_param(str,
1746 "debug-info-target-prefix",
1747 text_legacy_opts->dbg_info_target_prefix)) {
1748 goto end;
1749 }
1750
1751 g_string_append_bool_param(str, "no-delta",
1752 text_legacy_opts->no_delta);
1753 g_string_append_bool_param(str, "clock-cycles",
1754 text_legacy_opts->clock_cycles);
1755 g_string_append_bool_param(str, "clock-seconds",
1756 text_legacy_opts->clock_seconds);
1757 g_string_append_bool_param(str, "clock-date",
1758 text_legacy_opts->clock_date);
1759 g_string_append_bool_param(str, "clock-gmt",
1760 text_legacy_opts->clock_gmt);
1761 ret = append_prefixed_flag_params(str, text_legacy_opts->names,
1762 "name");
1763 if (ret) {
1764 goto end;
1765 }
1766
1767 ret = append_prefixed_flag_params(str, text_legacy_opts->fields,
1768 "field");
1769 if (ret) {
1770 goto end;
1771 }
1772
1773 /* Remove last comma and close single quote */
1774 g_string_append(str, "'");
1775 }
1776
1777 printf_err("%s\n\n", str->str);
1778
1779end:
1780 if (str) {
1781 g_string_free(str, TRUE);
1782 }
1783 return;
1784}
1785
1786/*
1787 * Prints the non-legacy source options equivalent to the specified
1788 * legacy input format options.
1789 */
1790static
1791void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format,
1792 struct bt_value *legacy_input_paths,
1793 struct ctf_legacy_opts *ctf_legacy_opts)
1794{
1795 const char *input_format;
1796 GString *str = NULL;
1797 int i;
1798
1799 str = g_string_new(" ");
1800 if (!str) {
1801 print_err_oom();
1802 goto end;
1803 }
1804
1805 switch (legacy_input_format) {
1806 case LEGACY_INPUT_FORMAT_CTF:
1807 input_format = "ctf";
1808 break;
1809 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1810 input_format = "lttng-live";
1811 break;
1812 default:
1813 assert(false);
1814 }
1815
49849a47 1816 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
c42c79ea 1817 input_format);
49849a47 1818 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
1819 input_format);
1820
1821 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1822 struct bt_value *input_value =
1823 bt_value_array_get(legacy_input_paths, i);
1824 const char *input = NULL;
1825 char *escaped_input;
1826 int ret;
1827
1828 assert(input_value);
1829 ret = bt_value_string_get(input_value, &input);
1830 BT_PUT(input_value);
1831 assert(!ret && input);
1832 escaped_input = str_shell_escape(input);
1833 if (!escaped_input) {
1834 print_err_oom();
1835 goto end;
1836 }
1837
1838 g_string_append(str, "-i ctf.");
1839
1840 switch (legacy_input_format) {
1841 case LEGACY_INPUT_FORMAT_CTF:
bdc61c70 1842 g_string_append(str, "fs -p 'path=\"");
c42c79ea
PP
1843 break;
1844 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
bdc61c70 1845 g_string_append(str, "lttng-live -p 'url=\"");
c42c79ea
PP
1846 break;
1847 default:
1848 assert(false);
1849 }
1850
1851 g_string_append(str, escaped_input);
1852 g_string_append(str, "\"");
1853 g_string_append_printf(str, ",offset-s=%" PRId64,
1854 ctf_legacy_opts->offset_s.value);
1855 g_string_append_printf(str, ",offset-ns=%" PRId64,
1856 ctf_legacy_opts->offset_ns.value);
1857 g_string_append_bool_param(str, "stream-intersection",
1858 ctf_legacy_opts->stream_intersection);
1859 g_string_append(str, "' ");
1860 g_free(escaped_input);
1861 }
1862
1863 printf_err("%s\n\n", str->str);
1864
1865end:
1866 if (str) {
1867 g_string_free(str, TRUE);
1868 }
1869 return;
1870}
1871
1872/*
1873 * Validates a given configuration, with optional legacy input and
1874 * output formats options. Prints useful error messages if anything
1875 * is wrong.
1876 *
1877 * Returns true when the configuration is valid.
1878 */
1879static
1880bool validate_cfg(struct bt_config *cfg,
1881 enum legacy_input_format *legacy_input_format,
1882 enum legacy_output_format *legacy_output_format,
1883 struct bt_value *legacy_input_paths,
1884 struct ctf_legacy_opts *ctf_legacy_opts,
bd9f0fa2 1885 struct text_legacy_opts *text_legacy_opts)
c42c79ea
PP
1886{
1887 bool legacy_input = false;
1888 bool legacy_output = false;
1889
1890 /* Determine if the input and output should be legacy-style */
1891 if (*legacy_input_format != LEGACY_INPUT_FORMAT_NONE ||
c42c79ea
PP
1892 !bt_value_array_is_empty(legacy_input_paths) ||
1893 ctf_legacy_opts_is_any_set(ctf_legacy_opts)) {
1894 legacy_input = true;
1895 }
1896
1897 if (*legacy_output_format != LEGACY_OUTPUT_FORMAT_NONE ||
c42c79ea
PP
1898 text_legacy_opts_is_any_set(text_legacy_opts)) {
1899 legacy_output = true;
1900 }
1901
1902 if (legacy_input) {
1903 /* If no legacy input format was specified, default to CTF */
1904 if (*legacy_input_format == LEGACY_INPUT_FORMAT_NONE) {
1905 *legacy_input_format = LEGACY_INPUT_FORMAT_CTF;
1906 }
1907
1908 /* Make sure at least one input path exists */
1909 if (bt_value_array_is_empty(legacy_input_paths)) {
1910 switch (*legacy_input_format) {
1911 case LEGACY_INPUT_FORMAT_CTF:
6d1d5711 1912 printf_err("No input path specified for legacy `ctf` input format\n");
c42c79ea
PP
1913 break;
1914 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
6d1d5711 1915 printf_err("No URL specified for legacy `lttng-live` input format\n");
c42c79ea
PP
1916 break;
1917 default:
1918 assert(false);
1919 }
1920 goto error;
1921 }
1922
1923 /* Make sure no non-legacy sources are specified */
290725f7 1924 if (cfg->cmd_data.convert.sources->len != 0) {
c42c79ea
PP
1925 print_input_legacy_to_sources(*legacy_input_format,
1926 legacy_input_paths, ctf_legacy_opts);
1927 goto error;
1928 }
1929 }
1930
1931 if (legacy_output) {
1932 /*
1933 * If no legacy output format was specified, default to
1934 * "text".
1935 */
1936 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_NONE) {
1937 *legacy_output_format = LEGACY_OUTPUT_FORMAT_TEXT;
1938 }
1939
1940 /*
1941 * If any "text" option was specified, the output must be
1942 * legacy "text".
1943 */
1944 if (text_legacy_opts_is_any_set(text_legacy_opts) &&
1945 *legacy_output_format !=
1946 LEGACY_OUTPUT_FORMAT_TEXT) {
6d1d5711 1947 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
c42c79ea
PP
1948 goto error;
1949 }
1950
1951 /* Make sure no non-legacy sinks are specified */
290725f7 1952 if (cfg->cmd_data.convert.sinks->len != 0) {
c42c79ea
PP
1953 print_output_legacy_to_sinks(*legacy_output_format,
1954 text_legacy_opts);
1955 goto error;
1956 }
1957 }
1958
1959 /*
1960 * If the output is the legacy "ctf-metadata" format, then the
1961 * input should be the legacy "ctf" input format.
1962 */
1963 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_CTF_METADATA &&
1964 *legacy_input_format != LEGACY_INPUT_FORMAT_CTF) {
6d1d5711 1965 printf_err("Legacy `ctf-metadata` output format requires using legacy `ctf` input format\n");
c42c79ea
PP
1966 goto error;
1967 }
1968
1969 return true;
1970
1971error:
1972 return false;
1973}
1974
1975/*
1976 * Parses a 64-bit signed integer.
1977 *
1978 * Returns a negative value if anything goes wrong.
1979 */
1980static
1981int parse_int64(const char *arg, int64_t *val)
1982{
1983 char *endptr;
1984
1985 errno = 0;
1986 *val = strtoll(arg, &endptr, 0);
1987 if (*endptr != '\0' || arg == endptr || errno != 0) {
1988 return -1;
1989 }
1990
1991 return 0;
1992}
1993
1994/* popt options */
1995enum {
1996 OPT_NONE = 0,
b07ffa28 1997 OPT_BASE_PARAMS,
0f9915c6 1998 OPT_BEGIN,
c42c79ea
PP
1999 OPT_CLOCK_CYCLES,
2000 OPT_CLOCK_DATE,
2001 OPT_CLOCK_FORCE_CORRELATE,
2002 OPT_CLOCK_GMT,
2003 OPT_CLOCK_OFFSET,
2004 OPT_CLOCK_OFFSET_NS,
2005 OPT_CLOCK_SECONDS,
ebba3338 2006 OPT_CONNECT,
c42c79ea
PP
2007 OPT_DEBUG,
2008 OPT_DEBUG_INFO_DIR,
2009 OPT_DEBUG_INFO_FULL_PATH,
2010 OPT_DEBUG_INFO_TARGET_PREFIX,
0f9915c6 2011 OPT_END,
c42c79ea 2012 OPT_FIELDS,
22e22462 2013 OPT_FILTER,
c42c79ea 2014 OPT_HELP,
c42c79ea
PP
2015 OPT_INPUT_FORMAT,
2016 OPT_LIST,
3b6cfcc5 2017 OPT_NAME,
c42c79ea
PP
2018 OPT_NAMES,
2019 OPT_NO_DELTA,
290725f7
PP
2020 OPT_OMIT_HOME_PLUGIN_PATH,
2021 OPT_OMIT_SYSTEM_PLUGIN_PATH,
c42c79ea
PP
2022 OPT_OUTPUT_FORMAT,
2023 OPT_OUTPUT_PATH,
bdc61c70 2024 OPT_PARAMS,
290725f7 2025 OPT_PATH,
c42c79ea 2026 OPT_PLUGIN_PATH,
b07ffa28 2027 OPT_RESET_BASE_PARAMS,
c42c79ea
PP
2028 OPT_SINK,
2029 OPT_SOURCE,
2030 OPT_STREAM_INTERSECTION,
0f9915c6 2031 OPT_TIMERANGE,
c42c79ea 2032 OPT_VERBOSE,
c42c79ea
PP
2033};
2034
2035/*
2036 * Sets the value of a given legacy offset option and marks it as set.
2037 */
2038static void set_offset_value(struct offset_opt *offset_opt, int64_t value)
2039{
2040 offset_opt->value = value;
2041 offset_opt->is_set = true;
2042}
2043
bdc61c70
PP
2044enum bt_config_component_dest {
2045 BT_CONFIG_COMPONENT_DEST_SOURCE,
2046 BT_CONFIG_COMPONENT_DEST_SINK,
2047};
2048
2049/*
2050 * Adds a configuration component to the appropriate configuration
2051 * array depending on the destination.
2052 */
2053static void add_cfg_comp(struct bt_config *cfg,
2054 struct bt_config_component *cfg_comp,
2055 enum bt_config_component_dest dest)
2056{
2057 if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
290725f7 2058 g_ptr_array_add(cfg->cmd_data.convert.sources, cfg_comp);
bdc61c70 2059 } else {
290725f7 2060 g_ptr_array_add(cfg->cmd_data.convert.sinks, cfg_comp);
bdc61c70
PP
2061 }
2062}
2063
0f9915c6
MD
2064static int split_timerange(const char *arg, const char **begin, const char **end)
2065{
2066 const char *c;
2067
2068 /* Try to match [begin,end] */
2069 c = strchr(arg, '[');
2070 if (!c)
2071 goto skip;
2072 *begin = ++c;
2073 c = strchr(c, ',');
2074 if (!c)
2075 goto skip;
2076 *end = ++c;
2077 c = strchr(c, ']');
2078 if (!c)
2079 goto skip;
2080 goto found;
2081
2082skip:
2083 /* Try to match begin,end */
2084 c = arg;
2085 *begin = c;
2086 c = strchr(c, ',');
2087 if (!c)
2088 goto not_found;
2089 *end = ++c;
2090 /* fall-through */
2091found:
2092 return 0;
2093not_found:
2094 return -1;
2095}
2096
290725f7 2097static int append_env_var_plugin_paths(struct bt_value *plugin_paths)
5a3ee633
PP
2098{
2099 int ret = 0;
2100 const char *envvar;
2101
2102 if (bt_common_is_setuid_setgid()) {
2103 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2104 goto end;
2105 }
2106
2107 envvar = getenv("BABELTRACE_PLUGIN_PATH");
2108 if (!envvar) {
2109 goto end;
2110 }
2111
290725f7 2112 ret = bt_config_append_plugin_paths(plugin_paths, envvar);
5a3ee633
PP
2113
2114end:
2115 return ret;
2116}
2117
290725f7
PP
2118static int append_home_and_system_plugin_paths(struct bt_value *plugin_paths,
2119 bool omit_system_plugin_path, bool omit_home_plugin_path)
98ecef32 2120{
1670bffd 2121 int ret;
98ecef32 2122
290725f7 2123 if (!omit_home_plugin_path) {
1670bffd 2124 if (bt_common_is_setuid_setgid()) {
5a3ee633 2125 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
98ecef32 2126 } else {
1670bffd
PP
2127 char *home_plugin_dir =
2128 bt_common_get_home_plugin_path();
2129
2130 if (home_plugin_dir) {
290725f7
PP
2131 ret = bt_config_append_plugin_paths(
2132 plugin_paths,
1670bffd
PP
2133 home_plugin_dir);
2134 free(home_plugin_dir);
2135
2136 if (ret) {
98ecef32
MD
2137 printf_err("Invalid home plugin path\n");
2138 goto error;
2139 }
2140 }
2141 }
2142 }
2143
290725f7
PP
2144 if (!omit_system_plugin_path) {
2145 if (bt_config_append_plugin_paths(plugin_paths,
1670bffd 2146 bt_common_get_system_plugin_path())) {
98ecef32
MD
2147 printf_err("Invalid system plugin path\n");
2148 goto error;
2149 }
2150 }
2151 return 0;
2152error:
2153 return -1;
2154}
2155
bd9f0fa2
MD
2156static int append_sources_from_implicit_params(GPtrArray *sources,
2157 struct bt_config_component *implicit_source_comp)
2158{
2159 size_t i;
2160 size_t len = sources->len;
2161
2162 for (i = 0; i < len; i++) {
2163 struct bt_config_component *comp;
2164 struct bt_value *params_to_set;
2165
2166 comp = g_ptr_array_index(sources, i);
2167 params_to_set = bt_value_map_extend(comp->params,
2168 implicit_source_comp->params);
2169 if (!params_to_set) {
2170 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2171 goto error;
2172 }
2173 BT_MOVE(comp->params, params_to_set);
2174 }
2175 return 0;
2176error:
2177 return -1;
2178}
2179
290725f7 2180static struct bt_config *bt_config_base_create(enum bt_config_command command)
c1870f57
JG
2181{
2182 struct bt_config *cfg;
2183
2184 /* Create config */
2185 cfg = g_new0(struct bt_config, 1);
2186 if (!cfg) {
2187 print_err_oom();
2188 goto error;
2189 }
2190
2191 bt_object_init(cfg, bt_config_destroy);
290725f7
PP
2192 cfg->command = command;
2193 goto end;
c1870f57 2194
290725f7
PP
2195error:
2196 BT_PUT(cfg);
c1870f57 2197
c1870f57
JG
2198end:
2199 return cfg;
c1870f57
JG
2200}
2201
290725f7
PP
2202static struct bt_config *bt_config_convert_create(
2203 struct bt_value *initial_plugin_paths)
c42c79ea 2204{
290725f7 2205 struct bt_config *cfg;
c42c79ea 2206
290725f7
PP
2207 /* Create config */
2208 cfg = bt_config_base_create(BT_CONFIG_COMMAND_CONVERT);
2209 if (!cfg) {
c42c79ea
PP
2210 print_err_oom();
2211 goto error;
2212 }
2213
290725f7
PP
2214 cfg->cmd_data.convert.sources = g_ptr_array_new_with_free_func(
2215 (GDestroyNotify) bt_put);
2216 if (!cfg->cmd_data.convert.sources) {
c42c79ea
PP
2217 print_err_oom();
2218 goto error;
2219 }
2220
ebba3338
PP
2221 cfg->cmd_data.convert.filters = g_ptr_array_new_with_free_func(
2222 (GDestroyNotify) bt_put);
2223 if (!cfg->cmd_data.convert.filters) {
2224 print_err_oom();
2225 goto error;
2226 }
2227
290725f7
PP
2228 cfg->cmd_data.convert.sinks = g_ptr_array_new_with_free_func(
2229 (GDestroyNotify) bt_put);
2230 if (!cfg->cmd_data.convert.sinks) {
c42c79ea
PP
2231 print_err_oom();
2232 goto error;
2233 }
2234
ebba3338
PP
2235 cfg->cmd_data.convert.connections = g_ptr_array_new_with_free_func(
2236 (GDestroyNotify) bt_config_connection_destroy);
2237 if (!cfg->cmd_data.convert.connections) {
2238 print_err_oom();
2239 goto error;
2240 }
2241
290725f7
PP
2242 if (initial_plugin_paths) {
2243 cfg->cmd_data.convert.plugin_paths =
2244 bt_get(initial_plugin_paths);
2245 } else {
2246 cfg->cmd_data.convert.plugin_paths = bt_value_array_create();
2247 if (!cfg->cmd_data.convert.plugin_paths) {
2248 print_err_oom();
2249 goto error;
2250 }
b07ffa28
PP
2251 }
2252
290725f7 2253 goto end;
c42c79ea 2254
290725f7
PP
2255error:
2256 BT_PUT(cfg);
2257
2258end:
2259 return cfg;
2260}
2261
2262static struct bt_config *bt_config_list_plugins_create(
2263 struct bt_value *initial_plugin_paths)
2264{
2265 struct bt_config *cfg;
2266
2267 /* Create config */
2268 cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS);
2269 if (!cfg) {
2270 print_err_oom();
5a3ee633
PP
2271 goto error;
2272 }
2273
290725f7
PP
2274 if (initial_plugin_paths) {
2275 cfg->cmd_data.list_plugins.plugin_paths =
2276 bt_get(initial_plugin_paths);
65582340 2277 } else {
290725f7
PP
2278 cfg->cmd_data.list_plugins.plugin_paths =
2279 bt_value_array_create();
2280 if (!cfg->cmd_data.list_plugins.plugin_paths) {
2281 print_err_oom();
2282 goto error;
2283 }
c42c79ea
PP
2284 }
2285
290725f7
PP
2286 goto end;
2287
2288error:
2289 BT_PUT(cfg);
2290
2291end:
2292 return cfg;
2293}
2294
22e22462
PP
2295static struct bt_config *bt_config_help_create(
2296 struct bt_value *initial_plugin_paths)
2297{
2298 struct bt_config *cfg;
2299
2300 /* Create config */
2301 cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP);
2302 if (!cfg) {
2303 print_err_oom();
2304 goto error;
2305 }
2306
2307 if (initial_plugin_paths) {
2308 cfg->cmd_data.help.plugin_paths =
2309 bt_get(initial_plugin_paths);
2310 } else {
2311 cfg->cmd_data.help.plugin_paths =
2312 bt_value_array_create();
2313 if (!cfg->cmd_data.help.plugin_paths) {
2314 print_err_oom();
2315 goto error;
2316 }
2317 }
2318
90de159b
PP
2319 cfg->cmd_data.help.cfg_component =
2320 bt_config_component_create(BT_COMPONENT_CLASS_TYPE_UNKNOWN,
2321 NULL, NULL);
2322 if (!cfg->cmd_data.help.cfg_component) {
22e22462
PP
2323 print_err_oom();
2324 goto error;
2325 }
2326
2327 goto end;
2328
2329error:
2330 BT_PUT(cfg);
2331
2332end:
2333 return cfg;
2334}
2335
2336/*
2337 * Prints the help command usage.
2338 */
2339static
2340void print_help_usage(FILE *fp)
2341{
2342 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
2343 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source PLUGIN.COMPCLS\n");
2344 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter PLUGIN.COMPCLS\n");
2345 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink PLUGIN.COMPCLS\n");
2346 fprintf(fp, "\n");
2347 fprintf(fp, "Options:\n");
2348 fprintf(fp, "\n");
2349 fprintf(fp, " --filter=PLUGIN.COMPCLS Get help for the filter component class\n");
2350 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2351 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2352 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2353 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2354 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2355 fprintf(fp, " dynamic plugins can be loaded\n");
2356 fprintf(fp, " --sink=PLUGIN.COMPCLS Get help for the sink component class\n");
2357 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2358 fprintf(fp, " --source=PLUGIN.COMPCLS Get help for the source component class\n");
2359 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2360 fprintf(fp, " -h --help Show this help and quit\n");
2361 fprintf(fp, "\n");
2362 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
2363 fprintf(fp, "\n");
2364 fprintf(fp, "Use `babeltrace list-plugins` to show the list of available plugins.\n");
2365}
2366
2367static struct poptOption help_long_options[] = {
2368 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2369 { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, NULL, NULL },
2370 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2371 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2372 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2373 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2374 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2375 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2376 { NULL, 0, 0, NULL, 0, NULL, NULL },
2377};
2378
2379/*
2380 * Creates a Babeltrace config object from the arguments of a help
2381 * command.
2382 *
2383 * *retcode is set to the appropriate exit code to use.
2384 */
2385struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
2386 int *retcode, bool omit_system_plugin_path,
2387 bool omit_home_plugin_path,
2388 struct bt_value *initial_plugin_paths)
2389{
2390 poptContext pc = NULL;
2391 char *arg = NULL;
2392 int opt;
2393 int ret;
2394 struct bt_config *cfg = NULL;
2395 const char *leftover;
2396 char *plugin_name = NULL, *component_name = NULL;
2397 char *plugin_comp_cls_names = NULL;
2398
2399 *retcode = 0;
2400 cfg = bt_config_help_create(initial_plugin_paths);
2401 if (!cfg) {
2402 print_err_oom();
2403 goto error;
2404 }
2405
22e22462
PP
2406 cfg->cmd_data.help.omit_system_plugin_path = omit_system_plugin_path;
2407 cfg->cmd_data.help.omit_home_plugin_path = omit_home_plugin_path;
2408 ret = append_env_var_plugin_paths(cfg->cmd_data.help.plugin_paths);
2409 if (ret) {
2410 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2411 goto error;
2412 }
2413
2414 /* Parse options */
2415 pc = poptGetContext(NULL, argc, (const char **) argv,
2416 help_long_options, 0);
2417 if (!pc) {
2418 printf_err("Cannot get popt context\n");
2419 goto error;
2420 }
2421
2422 poptReadDefaultConfig(pc, 0);
2423
2424 while ((opt = poptGetNextOpt(pc)) > 0) {
2425 arg = poptGetOptArg(pc);
2426
2427 switch (opt) {
2428 case OPT_PLUGIN_PATH:
2429 if (bt_common_is_setuid_setgid()) {
2430 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2431 } else {
2432 if (bt_config_append_plugin_paths(
2433 cfg->cmd_data.help.plugin_paths,
2434 arg)) {
2435 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2436 arg);
2437 goto error;
2438 }
2439 }
2440 break;
2441 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
2442 cfg->cmd_data.help.omit_system_plugin_path = true;
2443 break;
2444 case OPT_OMIT_HOME_PLUGIN_PATH:
2445 cfg->cmd_data.help.omit_home_plugin_path = true;
2446 break;
2447 case OPT_SOURCE:
2448 case OPT_FILTER:
2449 case OPT_SINK:
90de159b 2450 if (cfg->cmd_data.help.cfg_component->type !=
22e22462
PP
2451 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2452 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2453 arg);
2454 goto error;
2455 }
2456
2457 switch (opt) {
2458 case OPT_SOURCE:
90de159b 2459 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2460 BT_COMPONENT_CLASS_TYPE_SOURCE;
2461 break;
2462 case OPT_FILTER:
90de159b 2463 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2464 BT_COMPONENT_CLASS_TYPE_FILTER;
2465 break;
2466 case OPT_SINK:
90de159b 2467 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2468 BT_COMPONENT_CLASS_TYPE_SINK;
2469 break;
2470 default:
2471 assert(false);
2472 }
2473 plugin_comp_cls_names = strdup(arg);
2474 if (!plugin_comp_cls_names) {
2475 print_err_oom();
2476 goto error;
2477 }
2478 break;
2479 case OPT_HELP:
2480 print_help_usage(stdout);
2481 *retcode = -1;
2482 BT_PUT(cfg);
2483 goto end;
2484 default:
2485 printf_err("Unknown command-line option specified (option code %d)\n",
2486 opt);
2487 goto error;
2488 }
2489
2490 free(arg);
2491 arg = NULL;
2492 }
2493
2494 /* Check for option parsing error */
2495 if (opt < -1) {
2496 printf_err("While parsing command-line options, at option %s: %s\n",
2497 poptBadOption(pc, 0), poptStrerror(opt));
2498 goto error;
2499 }
2500
2501 leftover = poptGetArg(pc);
2502 if (leftover) {
90de159b 2503 if (cfg->cmd_data.help.cfg_component->type !=
22e22462
PP
2504 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2505 printf_err("Cannot specify plugin name and --source/--filter/--sink component class:\n %s\n",
2506 leftover);
2507 goto error;
2508 }
2509
90de159b
PP
2510 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
2511 leftover);
22e22462 2512 } else {
90de159b 2513 if (cfg->cmd_data.help.cfg_component->type ==
22e22462
PP
2514 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2515 print_help_usage(stdout);
2516 *retcode = -1;
2517 BT_PUT(cfg);
2518 goto end;
2519 }
2520
2521 plugin_component_names_from_arg(plugin_comp_cls_names,
2522 &plugin_name, &component_name);
2523 if (plugin_name && component_name) {
90de159b
PP
2524 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
2525 plugin_name);
2526 g_string_assign(cfg->cmd_data.help.cfg_component->component_name,
22e22462
PP
2527 component_name);
2528 } else {
2529 printf_err("Invalid --source/--filter/--sink option's argument:\n %s\n",
2530 plugin_comp_cls_names);
2531 goto error;
2532 }
2533 }
2534
2535 if (append_home_and_system_plugin_paths(
2536 cfg->cmd_data.help.plugin_paths,
2537 cfg->cmd_data.help.omit_system_plugin_path,
2538 cfg->cmd_data.help.omit_home_plugin_path)) {
2539 printf_err("Cannot append home and system plugin paths\n");
2540 goto error;
2541 }
2542
2543 goto end;
2544
2545error:
2546 *retcode = 1;
2547 BT_PUT(cfg);
2548
2549end:
2550 free(plugin_comp_cls_names);
2551 g_free(plugin_name);
2552 g_free(component_name);
2553
2554 if (pc) {
2555 poptFreeContext(pc);
2556 }
2557
2558 free(arg);
2559 return cfg;
2560}
2561
290725f7
PP
2562/*
2563 * Prints the list-plugins command usage.
2564 */
2565static
2566void print_list_plugins_usage(FILE *fp)
2567{
2568 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
2569 fprintf(fp, "\n");
2570 fprintf(fp, "Options:\n");
2571 fprintf(fp, "\n");
2572 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2573 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2574 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2575 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2576 fprintf(fp, " dynamic plugins can be loaded\n");
2577 fprintf(fp, " -h --help Show this help and quit\n");
2578 fprintf(fp, "\n");
2579 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
22e22462
PP
2580 fprintf(fp, "\n");
2581 fprintf(fp, "Use `babeltrace help` to get help for a specific plugin or component class.\n");
290725f7
PP
2582}
2583
2584static struct poptOption list_plugins_long_options[] = {
2585 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2586 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2587 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2588 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2589 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2590 { NULL, 0, 0, NULL, 0, NULL, NULL },
2591};
2592
2593/*
2594 * Creates a Babeltrace config object from the arguments of a
2595 * list-plugins command.
2596 *
2597 * *retcode is set to the appropriate exit code to use.
2598 */
2599struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
2600 int *retcode, bool omit_system_plugin_path,
2601 bool omit_home_plugin_path,
2602 struct bt_value *initial_plugin_paths)
2603{
2604 poptContext pc = NULL;
2605 char *arg = NULL;
2606 int opt;
2607 int ret;
2608 struct bt_config *cfg = NULL;
2609 const char *leftover;
2610
2611 *retcode = 0;
2612 cfg = bt_config_list_plugins_create(initial_plugin_paths);
2613 if (!cfg) {
2614 print_err_oom();
2615 goto error;
2616 }
2617
2618 cfg->cmd_data.list_plugins.omit_system_plugin_path = omit_system_plugin_path;
2619 cfg->cmd_data.list_plugins.omit_home_plugin_path = omit_home_plugin_path;
2620 ret = append_env_var_plugin_paths(
2621 cfg->cmd_data.list_plugins.plugin_paths);
2622 if (ret) {
2623 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2624 goto error;
2625 }
2626
2627 /* Parse options */
2628 pc = poptGetContext(NULL, argc, (const char **) argv,
2629 list_plugins_long_options, 0);
2630 if (!pc) {
2631 printf_err("Cannot get popt context\n");
2632 goto error;
2633 }
2634
2635 poptReadDefaultConfig(pc, 0);
c42c79ea
PP
2636
2637 while ((opt = poptGetNextOpt(pc)) > 0) {
2638 arg = poptGetOptArg(pc);
2639
2640 switch (opt) {
2641 case OPT_PLUGIN_PATH:
5a3ee633
PP
2642 if (bt_common_is_setuid_setgid()) {
2643 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
98ecef32 2644 } else {
290725f7
PP
2645 if (bt_config_append_plugin_paths(
2646 cfg->cmd_data.list_plugins.plugin_paths,
2647 arg)) {
2703153b
PP
2648 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2649 arg);
98ecef32
MD
2650 goto error;
2651 }
c42c79ea
PP
2652 }
2653 break;
98ecef32 2654 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
290725f7 2655 cfg->cmd_data.list_plugins.omit_system_plugin_path = true;
98ecef32
MD
2656 break;
2657 case OPT_OMIT_HOME_PLUGIN_PATH:
290725f7
PP
2658 cfg->cmd_data.list_plugins.omit_home_plugin_path = true;
2659 break;
2660 case OPT_HELP:
2661 print_list_plugins_usage(stdout);
2662 *retcode = -1;
2663 BT_PUT(cfg);
2664 goto end;
2665 default:
2666 printf_err("Unknown command-line option specified (option code %d)\n",
2667 opt);
2668 goto error;
2669 }
2670
2671 free(arg);
2672 arg = NULL;
2673 }
2674
2675 /* Check for option parsing error */
2676 if (opt < -1) {
2677 printf_err("While parsing command-line options, at option %s: %s\n",
2678 poptBadOption(pc, 0), poptStrerror(opt));
2679 goto error;
2680 }
2681
2682 leftover = poptGetArg(pc);
2683 if (leftover) {
2684 printf_err("Invalid argument: %s\n", leftover);
2685 goto error;
2686 }
2687
2688 if (append_home_and_system_plugin_paths(
2689 cfg->cmd_data.list_plugins.plugin_paths,
2690 cfg->cmd_data.list_plugins.omit_system_plugin_path,
2691 cfg->cmd_data.list_plugins.omit_home_plugin_path)) {
2692 printf_err("Cannot append home and system plugin paths\n");
2693 goto error;
2694 }
2695
2696 goto end;
2697
2698error:
2699 *retcode = 1;
2700 BT_PUT(cfg);
2701
2702end:
2703 if (pc) {
2704 poptFreeContext(pc);
2705 }
2706
2707 free(arg);
2708 return cfg;
2709}
2710
290725f7
PP
2711/*
2712 * Prints the legacy, Babeltrace 1.x command usage. Those options are
2713 * still compatible in Babeltrace 2.x, but it is recommended to use
2714 * the more generic plugin/component parameters instead of those
2715 * hard-coded option names.
2716 */
2717static
2718void print_legacy_usage(FILE *fp)
2719{
2720 fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
2721 fprintf(fp, "\n");
2722 fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
2723 fprintf(fp, "\n");
2724 fprintf(fp, " --clock-force-correlate Assume that clocks are inherently correlated\n");
2725 fprintf(fp, " across traces\n");
2726 fprintf(fp, " -d, --debug Enable debug mode\n");
2727 fprintf(fp, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
2728 fprintf(fp, " -l, --list List available formats\n");
2729 fprintf(fp, " -o, --output-format=FORMAT Output trace format (default: text)\n");
2730 fprintf(fp, " -v, --verbose Enable verbose output\n");
2731 fprintf(fp, " --help-legacy Show this help and quit\n");
2732 fprintf(fp, " -V, --version Show version and quit\n");
2733 fprintf(fp, "\n");
2734 fprintf(fp, " Available input formats: ctf, lttng-live, ctf-metadata\n");
2735 fprintf(fp, " Available output formats: text, dummy\n");
2736 fprintf(fp, "\n");
2737 fprintf(fp, "Input formats specific options:\n");
2738 fprintf(fp, "\n");
2739 fprintf(fp, " INPUT... Input trace file(s), directory(ies), or URLs\n");
2740 fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n");
2741 fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
2742 fprintf(fp, " --stream-intersection Only process events when all streams are active\n");
2743 fprintf(fp, "\n");
2744 fprintf(fp, "text output format specific options:\n");
2745 fprintf(fp, " \n");
2746 fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n");
2747 fprintf(fp, " --clock-date Print timestamp dates\n");
2748 fprintf(fp, " --clock-gmt Print and parse timestamps in GMT time zone\n");
2749 fprintf(fp, " (default: local time zone)\n");
2750 fprintf(fp, " --clock-seconds Print the timestamps as [SEC.NS]\n");
2751 fprintf(fp, " (default format: [HH:MM:SS.NS])\n");
2752 fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
2753 fprintf(fp, " (default: `/usr/lib/debug`)\n");
2754 fprintf(fp, " --debug-info-full-path Show full debug info source and binary paths\n");
2755 fprintf(fp, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
2756 fprintf(fp, " up executables during debug info analysis\n");
2757 fprintf(fp, " (default: `/usr/lib/debug`)\n");
2758 fprintf(fp, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
2759 fprintf(fp, " all, trace, trace:hostname, trace:domain,\n");
2760 fprintf(fp, " trace:procname, trace:vpid, loglevel, emf\n");
2761 fprintf(fp, " (default: trace:hostname, trace:procname,\n");
2762 fprintf(fp, " trace:vpid)\n");
2763 fprintf(fp, " -n, --names=NAME[,NAME]... Print field names:\n");
2764 fprintf(fp, " payload (or arg or args)\n");
2765 fprintf(fp, " none, all, scope, header, context (or ctx)\n");
2766 fprintf(fp, " (default: payload, context)\n");
2767 fprintf(fp, " --no-delta Do not print time delta between consecutive\n");
2768 fprintf(fp, " events\n");
2769 fprintf(fp, " -w, --output=PATH Write output to PATH (default: standard output)\n");
2770}
2771
2772/*
2773 * Prints the convert command usage.
2774 */
2775static
2776void print_convert_usage(FILE *fp)
2777{
2778 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
2779 fprintf(fp, "\n");
2780 fprintf(fp, "Options:\n");
2781 fprintf(fp, "\n");
2782 fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
2783 fprintf(fp, " for the following component instances\n");
2784 fprintf(fp, " (see the expected format of PARAMS below)\n");
2785 fprintf(fp, " --begin=BEGIN Set the `begin` parameter of the latest\n");
2786 fprintf(fp, " source component instance to BEGIN\n");
2787 fprintf(fp, " (see the suggested format of BEGIN below)\n");
ebba3338
PP
2788 fprintf(fp, " -c, --connect=CONNECTION Connect two component instances (see the\n");
2789 fprintf(fp, " expected format of CONNECTION below)\n");
290725f7
PP
2790 fprintf(fp, " -d, --debug Enable debug mode\n");
2791 fprintf(fp, " --end=END Set the `end` parameter of the latest\n");
2792 fprintf(fp, " source component instance to END\n");
2793 fprintf(fp, " (see the suggested format of BEGIN below)\n");
3b6cfcc5
PP
2794 fprintf(fp, " --name=NAME Set the name of the latest component\n");
2795 fprintf(fp, " instance to NAME (must be unique amongst\n");
2796 fprintf(fp, " all the names of the component instances)\n");
290725f7
PP
2797 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2798 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2799 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2800 fprintf(fp, " -p, --params=PARAMS Set the parameters of the latest component\n");
2801 fprintf(fp, " instance (in command-line order) to PARAMS\n");
2802 fprintf(fp, " (see the expected format of PARAMS below)\n");
2803 fprintf(fp, " -P, --path=PATH Set the `path` parameter of the latest\n");
2804 fprintf(fp, " component instance to PATH\n");
2805 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2806 fprintf(fp, " dynamic plugins can be loaded\n");
2807 fprintf(fp, " -r, --reset-base-params Reset the current base parameters of the\n");
2808 fprintf(fp, " following source and sink component\n");
2809 fprintf(fp, " instances to an empty map\n");
2810 fprintf(fp, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
2811 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
2812 fprintf(fp, " repeated)\n");
2813 fprintf(fp, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
2814 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
2815 fprintf(fp, " repeated)\n");
2816 fprintf(fp, " --timerange=TIMERANGE Set time range to TIMERANGE: BEGIN,END or\n");
2817 fprintf(fp, " [BEGIN,END] (literally `[` and `]`)\n");
2818 fprintf(fp, " (suggested format of BEGIN/END below)\n");
2819 fprintf(fp, " -v, --verbose Enable verbose output\n");
2820 fprintf(fp, " -h --help Show this help and quit\n");
2821 fprintf(fp, "\n");
2822 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
2823 fprintf(fp, "\n\n");
2824 fprintf(fp, "Suggested format of BEGIN and END\n");
2825 fprintf(fp, "---------------------------------\n");
2826 fprintf(fp, "\n");
2827 fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
2828 fprintf(fp, "\n\n");
ebba3338
PP
2829 fprintf(fp, "Expected format of CONNECTION\n");
2830 fprintf(fp, "-----------------------------\n");
2831 fprintf(fp, "\n");
2832 fprintf(fp, " SRC[.SRCPORT]:DST[.DSTPORT]\n");
2833 fprintf(fp, "\n");
2834 fprintf(fp, "SRC and DST are the names of the source and destination component\n");
2835 fprintf(fp, "instances to connect together. You can set the name of a component\n");
2836 fprintf(fp, "instance with the --name option.\n");
2837 fprintf(fp, "\n");
2838 fprintf(fp, "SRCPORT and DSTPORT are the optional source and destination ports to use\n");
2839 fprintf(fp, "for the connection. When the port is not specified, the default port is\n");
2840 fprintf(fp, "used.\n");
2841 fprintf(fp, "\n");
2842 fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
2843 fprintf(fp, "can connect a filter component to a sink component.\n");
2844 fprintf(fp, "\n");
2845 fprintf(fp, "Example:\n");
2846 fprintf(fp, "\n");
2847 fprintf(fp, " my-filter.top10:json-out\n");
2848 fprintf(fp, "\n\n");
290725f7
PP
2849 fprintf(fp, "Expected format of PARAMS\n");
2850 fprintf(fp, "-------------------------\n");
2851 fprintf(fp, "\n");
2852 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
2853 fprintf(fp, "\n");
2854 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
2855 fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
2856 fprintf(fp, "VALUE can be one of:\n");
2857 fprintf(fp, "\n");
2858 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
2859 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
2860 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
2861 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
2862 fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n");
2863 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
2864 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
2865 fprintf(fp, " the null and boolean value symbols above.\n");
2866 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
2867 fprintf(fp, "\n");
2868 fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
2869 fprintf(fp, "\n");
2870 fprintf(fp, "Example:\n");
2871 fprintf(fp, "\n");
2872 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
2873 fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
2874 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
2875 fprintf(fp, "\n");
2876 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
2877 fprintf(fp, "from a shell.\n");
2878}
2879
2880static struct poptOption convert_long_options[] = {
2881 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2882 { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
2883 { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
2884 { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
2885 { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
2886 { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
2887 { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
2888 { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
2889 { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
2890 { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
ebba3338 2891 { "connect", 'c', POPT_ARG_STRING, NULL, OPT_CONNECT, NULL, NULL },
290725f7
PP
2892 { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
2893 { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
2894 { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
2895 { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
2896 { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
2897 { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
2898 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2899 { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
3b6cfcc5 2900 { "name", '\0', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
290725f7
PP
2901 { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
2902 { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
2903 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2904 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2905 { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
2906 { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
2907 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
2908 { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
2909 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2910 { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
2911 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2912 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2913 { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
2914 { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
2915 { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
2916 { NULL, 0, 0, NULL, 0, NULL, NULL },
2917};
2918
2919/*
2920 * Creates a Babeltrace config object from the arguments of a convert
2921 * command.
2922 *
2923 * *retcode is set to the appropriate exit code to use.
2924 */
2925struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
2926 int *retcode, bool omit_system_plugin_path,
2927 bool omit_home_plugin_path,
2928 struct bt_value *initial_plugin_paths)
2929{
2930 poptContext pc = NULL;
2931 char *arg = NULL;
2932 struct ctf_legacy_opts ctf_legacy_opts;
2933 struct text_legacy_opts text_legacy_opts;
2934 enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
2935 enum legacy_output_format legacy_output_format =
2936 LEGACY_OUTPUT_FORMAT_NONE;
2937 struct bt_value *legacy_input_paths = NULL;
2938 struct bt_config_component *implicit_source_comp = NULL;
2939 struct bt_config_component *cur_cfg_comp = NULL;
2940 bool cur_is_implicit_source = false;
2941 bool use_implicit_source = false;
2942 enum bt_config_component_dest cur_cfg_comp_dest =
2943 BT_CONFIG_COMPONENT_DEST_SOURCE;
2944 struct bt_value *cur_base_params = NULL;
2945 int opt, ret = 0;
2946 struct bt_config *cfg = NULL;
3b6cfcc5 2947 struct bt_value *instance_names = NULL;
ebba3338
PP
2948 struct bt_value *connection_args = NULL;
2949 char error_buf[256] = { 0 };
290725f7
PP
2950
2951 *retcode = 0;
2952 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
2953 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
2954
2955 if (argc <= 1) {
2956 print_convert_usage(stdout);
2957 *retcode = -1;
2958 goto end;
2959 }
2960
2961 cfg = bt_config_convert_create(initial_plugin_paths);
2962 if (!cfg) {
2963 print_err_oom();
2964 goto error;
2965 }
2966
2967 cfg->cmd_data.convert.omit_system_plugin_path = omit_system_plugin_path;
2968 cfg->cmd_data.convert.omit_home_plugin_path = omit_home_plugin_path;
2969 text_legacy_opts.output = g_string_new(NULL);
2970 if (!text_legacy_opts.output) {
2971 print_err_oom();
2972 goto error;
2973 }
2974
2975 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
2976 if (!text_legacy_opts.dbg_info_dir) {
2977 print_err_oom();
2978 goto error;
2979 }
2980
2981 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
2982 if (!text_legacy_opts.dbg_info_target_prefix) {
2983 print_err_oom();
2984 goto error;
2985 }
2986
2987 cur_base_params = bt_value_map_create();
2988 if (!cur_base_params) {
2989 print_err_oom();
2990 goto error;
2991 }
2992
2993 legacy_input_paths = bt_value_array_create();
2994 if (!legacy_input_paths) {
2995 print_err_oom();
2996 goto error;
2997 }
2998
3b6cfcc5
PP
2999 instance_names = bt_value_map_create();
3000 if (!instance_names) {
3001 print_err_oom();
3002 goto error;
3003 }
3004
ebba3338
PP
3005 connection_args = bt_value_array_create();
3006 if (!connection_args) {
3007 print_err_oom();
3008 goto error;
3009 }
3010
290725f7
PP
3011 ret = append_env_var_plugin_paths(cfg->cmd_data.convert.plugin_paths);
3012 if (ret) {
3013 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3014 goto error;
3015 }
3016
3017 /* Note: implicit source never gets positional base params. */
90de159b
PP
3018 implicit_source_comp = bt_config_component_from_arg(
3019 BT_COMPONENT_CLASS_TYPE_SOURCE, DEFAULT_SOURCE_COMPONENT_NAME);
22e22462
PP
3020 if (!implicit_source_comp) {
3021 print_err_oom();
3022 goto error;
290725f7
PP
3023 }
3024
22e22462
PP
3025 cur_cfg_comp = implicit_source_comp;
3026 cur_is_implicit_source = true;
3027 use_implicit_source = true;
3028
290725f7
PP
3029 /* Parse options */
3030 pc = poptGetContext(NULL, argc, (const char **) argv,
3031 convert_long_options, 0);
3032 if (!pc) {
3033 printf_err("Cannot get popt context\n");
3034 goto error;
3035 }
3036
3037 poptReadDefaultConfig(pc, 0);
3038
3039 while ((opt = poptGetNextOpt(pc)) > 0) {
3040 arg = poptGetOptArg(pc);
3041
3042 switch (opt) {
3043 case OPT_PLUGIN_PATH:
3044 if (bt_common_is_setuid_setgid()) {
3045 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3046 } else {
3047 if (bt_config_append_plugin_paths(
3048 cfg->cmd_data.convert.plugin_paths,
3049 arg)) {
2703153b
PP
3050 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3051 arg);
290725f7
PP
3052 goto error;
3053 }
3054 }
3055 break;
3056 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
3057 cfg->cmd_data.convert.omit_system_plugin_path = true;
3058 break;
3059 case OPT_OMIT_HOME_PLUGIN_PATH:
3060 cfg->cmd_data.convert.omit_home_plugin_path = true;
98ecef32 3061 break;
c42c79ea
PP
3062 case OPT_OUTPUT_PATH:
3063 if (text_legacy_opts.output->len > 0) {
3064 printf_err("Duplicate --output option\n");
3065 goto error;
3066 }
3067
3068 g_string_assign(text_legacy_opts.output, arg);
3069 break;
3070 case OPT_DEBUG_INFO_DIR:
3071 if (text_legacy_opts.dbg_info_dir->len > 0) {
3072 printf_err("Duplicate --debug-info-dir option\n");
3073 goto error;
3074 }
3075
3076 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
3077 break;
3078 case OPT_DEBUG_INFO_TARGET_PREFIX:
3079 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
3080 printf_err("Duplicate --debug-info-target-prefix option\n");
3081 goto error;
3082 }
3083
3084 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
3085 break;
3086 case OPT_INPUT_FORMAT:
3087 case OPT_SOURCE:
3088 {
c42c79ea
PP
3089 if (opt == OPT_INPUT_FORMAT) {
3090 if (!strcmp(arg, "ctf")) {
3091 /* Legacy CTF input format */
3092 if (legacy_input_format) {
3093 print_err_dup_legacy_input();
3094 goto error;
3095 }
3096
3097 legacy_input_format =
3098 LEGACY_INPUT_FORMAT_CTF;
3099 break;
3100 } else if (!strcmp(arg, "lttng-live")) {
3101 /* Legacy LTTng-live input format */
3102 if (legacy_input_format) {
3103 print_err_dup_legacy_input();
3104 goto error;
3105 }
3106
3107 legacy_input_format =
3108 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
3109 break;
3110 }
3111 }
3112
65582340
MD
3113 use_implicit_source = false;
3114
c42c79ea 3115 /* Non-legacy: try to create a component config */
65582340 3116 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3117 add_cfg_comp(cfg, cur_cfg_comp,
3118 cur_cfg_comp_dest);
3119 }
3120
90de159b
PP
3121 cur_cfg_comp = bt_config_component_from_arg(
3122 BT_COMPONENT_CLASS_TYPE_SOURCE, arg);
bdc61c70 3123 if (!cur_cfg_comp) {
49849a47 3124 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
3125 arg);
3126 goto error;
3127 }
65582340 3128 cur_is_implicit_source = false;
c42c79ea 3129
b07ffa28
PP
3130 assert(cur_base_params);
3131 bt_put(cur_cfg_comp->params);
c9313318 3132 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3133 if (!cur_cfg_comp->params) {
c9313318 3134 print_err_oom();
290725f7 3135 goto error;
c9313318
PP
3136 }
3137
bdc61c70 3138 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
c42c79ea
PP
3139 break;
3140 }
3141 case OPT_OUTPUT_FORMAT:
3142 case OPT_SINK:
3143 {
c42c79ea
PP
3144 if (opt == OPT_OUTPUT_FORMAT) {
3145 if (!strcmp(arg, "text")) {
3146 /* Legacy CTF-text output format */
3147 if (legacy_output_format) {
3148 print_err_dup_legacy_output();
3149 goto error;
3150 }
3151
3152 legacy_output_format =
3153 LEGACY_OUTPUT_FORMAT_TEXT;
3154 break;
3155 } else if (!strcmp(arg, "dummy")) {
3156 /* Legacy dummy output format */
3157 if (legacy_output_format) {
3158 print_err_dup_legacy_output();
3159 goto error;
3160 }
3161
3162 legacy_output_format =
3163 LEGACY_OUTPUT_FORMAT_DUMMY;
3164 break;
3165 } else if (!strcmp(arg, "ctf-metadata")) {
3166 /* Legacy CTF-metadata output format */
3167 if (legacy_output_format) {
3168 print_err_dup_legacy_output();
3169 goto error;
3170 }
3171
3172 legacy_output_format =
3173 LEGACY_OUTPUT_FORMAT_CTF_METADATA;
3174 break;
3175 }
3176 }
3177
3178 /* Non-legacy: try to create a component config */
65582340 3179 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3180 add_cfg_comp(cfg, cur_cfg_comp,
3181 cur_cfg_comp_dest);
3182 }
3183
90de159b
PP
3184 cur_cfg_comp = bt_config_component_from_arg(
3185 BT_COMPONENT_CLASS_TYPE_SINK, arg);
bdc61c70 3186 if (!cur_cfg_comp) {
49849a47 3187 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
3188 arg);
3189 goto error;
3190 }
65582340 3191 cur_is_implicit_source = false;
c42c79ea 3192
b07ffa28
PP
3193 assert(cur_base_params);
3194 bt_put(cur_cfg_comp->params);
c9313318 3195 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3196 if (!cur_cfg_comp->params) {
c9313318 3197 print_err_oom();
290725f7 3198 goto error;
c9313318
PP
3199 }
3200
bdc61c70 3201 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
bdc61c70
PP
3202 break;
3203 }
3204 case OPT_PARAMS:
3205 {
3206 struct bt_value *params;
b07ffa28 3207 struct bt_value *params_to_set;
bdc61c70
PP
3208
3209 if (!cur_cfg_comp) {
2703153b
PP
3210 printf_err("Cannot add parameters to unavailable default source component `%s`:\n %s\n",
3211 DEFAULT_SOURCE_COMPONENT_NAME, arg);
bdc61c70
PP
3212 goto error;
3213 }
3214
bdc61c70
PP
3215 params = bt_value_from_arg(arg);
3216 if (!params) {
3217 printf_err("Invalid format for --params option's argument:\n %s\n",
3218 arg);
3219 goto error;
3220 }
3221
560ff91c 3222 params_to_set = bt_value_map_extend(cur_cfg_comp->params,
b07ffa28
PP
3223 params);
3224 BT_PUT(params);
3225 if (!params_to_set) {
560ff91c 3226 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
b07ffa28
PP
3227 arg);
3228 goto error;
3229 }
3230
3231 BT_MOVE(cur_cfg_comp->params, params_to_set);
c42c79ea
PP
3232 break;
3233 }
ad6a19bd
PP
3234 case OPT_PATH:
3235 if (!cur_cfg_comp) {
2703153b
PP
3236 printf_err("Cannot add `path` parameter to unavailable default source component `%s`:\n %s\n",
3237 DEFAULT_SOURCE_COMPONENT_NAME, arg);
ad6a19bd
PP
3238 goto error;
3239 }
3240
3241 assert(cur_cfg_comp->params);
3242
3243 if (bt_value_map_insert_string(cur_cfg_comp->params,
3244 "path", arg)) {
3245 print_err_oom();
3246 goto error;
3247 }
3248 break;
3b6cfcc5
PP
3249 case OPT_NAME:
3250 if (!cur_cfg_comp) {
3251 printf_err("Cannot set the name of unavailable default source component `%s`:\n %s\n",
3252 DEFAULT_SOURCE_COMPONENT_NAME, arg);
3253 goto error;
3254 }
3255
3256 if (bt_value_map_has_key(instance_names, arg)) {
3257 printf_err("Duplicate component instance name:\n %s\n",
3258 arg);
3259 goto error;
3260 }
3261
3262 g_string_assign(cur_cfg_comp->instance_name, arg);
3263
3264 if (bt_value_map_insert(instance_names,
3265 arg, bt_value_null)) {
3266 print_err_oom();
3267 goto error;
3268 }
3269 break;
b07ffa28
PP
3270 case OPT_BASE_PARAMS:
3271 {
3272 struct bt_value *params = bt_value_from_arg(arg);
3273
3274 if (!params) {
3275 printf_err("Invalid format for --base-params option's argument:\n %s\n",
3276 arg);
3277 goto error;
3278 }
3279
3280 BT_MOVE(cur_base_params, params);
3281 break;
3282 }
3283 case OPT_RESET_BASE_PARAMS:
3284 BT_PUT(cur_base_params);
3285 cur_base_params = bt_value_map_create();
3286 if (!cur_base_params) {
3287 print_err_oom();
3288 goto error;
3289 }
3290 break;
c42c79ea
PP
3291 case OPT_NAMES:
3292 if (text_legacy_opts.names) {
3293 printf_err("Duplicate --names option\n");
3294 goto error;
3295 }
3296
3297 text_legacy_opts.names = names_from_arg(arg);
3298 if (!text_legacy_opts.names) {
2703153b
PP
3299 printf_err("Invalid --names option's argument:\n %s\n",
3300 arg);
c42c79ea
PP
3301 goto error;
3302 }
3303 break;
3304 case OPT_FIELDS:
3305 if (text_legacy_opts.fields) {
3306 printf_err("Duplicate --fields option\n");
3307 goto error;
3308 }
3309
3310 text_legacy_opts.fields = fields_from_arg(arg);
3311 if (!text_legacy_opts.fields) {
2703153b
PP
3312 printf_err("Invalid --fields option's argument:\n %s\n",
3313 arg);
c42c79ea
PP
3314 goto error;
3315 }
3316 break;
3317 case OPT_NO_DELTA:
3318 text_legacy_opts.no_delta = true;
3319 break;
3320 case OPT_CLOCK_CYCLES:
3321 text_legacy_opts.clock_cycles = true;
3322 break;
3323 case OPT_CLOCK_SECONDS:
3324 text_legacy_opts.clock_seconds = true;
3325 break;
3326 case OPT_CLOCK_DATE:
3327 text_legacy_opts.clock_date = true;
3328 break;
3329 case OPT_CLOCK_GMT:
3330 text_legacy_opts.clock_gmt = true;
3331 break;
3332 case OPT_DEBUG_INFO_FULL_PATH:
3333 text_legacy_opts.dbg_info_full_path = true;
3334 break;
3335 case OPT_CLOCK_OFFSET:
3336 {
3337 int64_t val;
3338
3339 if (ctf_legacy_opts.offset_s.is_set) {
3340 printf_err("Duplicate --clock-offset option\n");
3341 goto error;
3342 }
3343
3344 if (parse_int64(arg, &val)) {
2703153b
PP
3345 printf_err("Invalid --clock-offset option's argument:\n %s\n",
3346 arg);
c42c79ea
PP
3347 goto error;
3348 }
3349
3350 set_offset_value(&ctf_legacy_opts.offset_s, val);
3351 break;
3352 }
3353 case OPT_CLOCK_OFFSET_NS:
3354 {
3355 int64_t val;
3356
3357 if (ctf_legacy_opts.offset_ns.is_set) {
3358 printf_err("Duplicate --clock-offset-ns option\n");
3359 goto error;
3360 }
3361
3362 if (parse_int64(arg, &val)) {
2703153b
PP
3363 printf_err("Invalid --clock-offset-ns option's argument:\n %s\n",
3364 arg);
c42c79ea
PP
3365 goto error;
3366 }
3367
3368 set_offset_value(&ctf_legacy_opts.offset_ns, val);
3369 break;
3370 }
3371 case OPT_STREAM_INTERSECTION:
3372 ctf_legacy_opts.stream_intersection = true;
3373 break;
3374 case OPT_CLOCK_FORCE_CORRELATE:
290725f7 3375 cfg->cmd_data.convert.force_correlate = true;
c42c79ea 3376 break;
0f9915c6
MD
3377 case OPT_BEGIN:
3378 if (!cur_cfg_comp) {
2703153b
PP
3379 printf_err("Cannot add `begin` parameter to unavailable default source component `%s`:\n %s\n",
3380 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3381 goto error;
3382 }
3383 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3384 printf_err("--begin option must follow a --source option:\n %s\n",
3385 arg);
0f9915c6
MD
3386 goto error;
3387 }
3388 if (bt_value_map_insert_string(cur_cfg_comp->params,
3389 "begin", arg)) {
3390 print_err_oom();
3391 goto error;
3392 }
3393 break;
3394 case OPT_END:
3395 if (!cur_cfg_comp) {
2703153b
PP
3396 printf_err("Cannot add `end` parameter to unavailable default source component `%s`:\n %s\n",
3397 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3398 goto error;
3399 }
3400 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3401 printf_err("--end option must follow a --source option:\n %s\n",
3402 arg);
0f9915c6
MD
3403 goto error;
3404 }
3405 if (bt_value_map_insert_string(cur_cfg_comp->params,
3406 "end", arg)) {
3407 print_err_oom();
3408 goto error;
3409 }
3410 break;
3411 case OPT_TIMERANGE:
3412 {
3413 const char *begin, *end;
3414
3415 if (!cur_cfg_comp) {
2703153b
PP
3416 printf_err("Cannot add `begin` and `end` parameters to unavailable default source component `%s`:\n %s\n",
3417 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3418 goto error;
3419 }
3420 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3421 printf_err("--timerange option must follow a --source option:\n %s\n",
3422 arg);
0f9915c6
MD
3423 goto error;
3424 }
3425 if (split_timerange(arg, &begin, &end)) {
2703153b
PP
3426 printf_err("Invalid --timerange format: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
3427 arg);
0f9915c6
MD
3428 goto error;
3429 }
3430 if (bt_value_map_insert_string(cur_cfg_comp->params,
3431 "begin", begin)) {
3432 print_err_oom();
3433 goto error;
3434 }
3435 if (bt_value_map_insert_string(cur_cfg_comp->params,
3436 "end", end)) {
3437 print_err_oom();
3438 goto error;
3439 }
3440 break;
3441 }
ebba3338
PP
3442 case OPT_CONNECT:
3443 if (bt_value_array_append_string(connection_args,
3444 arg)) {
3445 print_err_oom();
3446 goto error;
3447 }
3448 break;
c42c79ea 3449 case OPT_HELP:
290725f7
PP
3450 print_convert_usage(stdout);
3451 *retcode = -1;
3452 BT_PUT(cfg);
c42c79ea
PP
3453 goto end;
3454 case OPT_VERBOSE:
3455 cfg->verbose = true;
3456 break;
3457 case OPT_DEBUG:
3458 cfg->debug = true;
3459 break;
3460 default:
3461 printf_err("Unknown command-line option specified (option code %d)\n",
3462 opt);
3463 goto error;
3464 }
3465
3466 free(arg);
3467 arg = NULL;
3468 }
3469
3470 /* Check for option parsing error */
3471 if (opt < -1) {
3472 printf_err("While parsing command-line options, at option %s: %s\n",
3473 poptBadOption(pc, 0), poptStrerror(opt));
3474 goto error;
3475 }
3476
3477 /* Consume leftover arguments as legacy input paths */
3478 while (true) {
3479 const char *input_path = poptGetArg(pc);
3480
3481 if (!input_path) {
3482 break;
3483 }
3484
3485 if (bt_value_array_append_string(legacy_input_paths,
3486 input_path)) {
3487 print_err_oom();
3488 goto error;
3489 }
3490 }
3491
290725f7
PP
3492 if (append_home_and_system_plugin_paths(
3493 cfg->cmd_data.convert.plugin_paths,
3494 cfg->cmd_data.convert.omit_system_plugin_path,
3495 cfg->cmd_data.convert.omit_home_plugin_path)) {
3496 printf_err("Cannot append home and system plugin paths\n");
6cf24c61
MD
3497 goto error;
3498 }
3499
3500 /* Append current component configuration, if any */
3501 if (cur_cfg_comp && !cur_is_implicit_source) {
3502 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
3503 }
3504 cur_cfg_comp = NULL;
3505
c42c79ea
PP
3506 /* Validate legacy/non-legacy options */
3507 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
3508 legacy_input_paths, &ctf_legacy_opts,
bd9f0fa2 3509 &text_legacy_opts)) {
c42c79ea
PP
3510 printf_err("Command-line options form an invalid configuration\n");
3511 goto error;
3512 }
3513
3514 /*
3515 * If there's a legacy input format, convert it to source
3516 * component configurations.
3517 */
3518 if (legacy_input_format) {
290725f7
PP
3519 if (append_sources_from_legacy_opts(
3520 cfg->cmd_data.convert.sources,
c42c79ea 3521 legacy_input_format, &ctf_legacy_opts,
528debdf 3522 legacy_input_paths)) {
49849a47 3523 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
3524 goto error;
3525 }
290725f7
PP
3526 if (append_sources_from_implicit_params(
3527 cfg->cmd_data.convert.sources,
bd9f0fa2
MD
3528 implicit_source_comp)) {
3529 printf_err("Cannot initialize legacy component parameters\n");
3530 goto error;
3531 }
3532 use_implicit_source = false;
3533 } else {
3534 if (use_implicit_source) {
3535 add_cfg_comp(cfg, implicit_source_comp,
3536 BT_CONFIG_COMPONENT_DEST_SOURCE);
3537 implicit_source_comp = NULL;
3538 } else {
3539 if (implicit_source_comp
3540 && !bt_value_map_is_empty(implicit_source_comp->params)) {
3541 printf_err("Arguments specified for implicit source, but an explicit source has been specified, overriding it\n");
3542 goto error;
3543 }
3544 }
c42c79ea
PP
3545 }
3546
3547 /*
3548 * If there's a legacy output format, convert it to sink
3549 * component configurations.
3550 */
3551 if (legacy_output_format) {
290725f7 3552 if (append_sinks_from_legacy_opts(cfg->cmd_data.convert.sinks,
c42c79ea 3553 legacy_output_format, &text_legacy_opts)) {
49849a47 3554 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
3555 goto error;
3556 }
3557 }
3558
290725f7 3559 if (cfg->cmd_data.convert.sinks->len == 0) {
bd9f0fa2 3560 /* Use implicit sink as default. */
90de159b
PP
3561 cur_cfg_comp = bt_config_component_from_arg(
3562 BT_COMPONENT_CLASS_TYPE_SINK,
3563 DEFAULT_SINK_COMPONENT_NAME);
bd9f0fa2 3564 if (!cur_cfg_comp) {
2703153b 3565 printf_error("Cannot find implicit sink plugin `%s`\n",
bd9f0fa2
MD
3566 DEFAULT_SINK_COMPONENT_NAME);
3567 }
3568 add_cfg_comp(cfg, cur_cfg_comp,
3569 BT_CONFIG_COMPONENT_DEST_SINK);
3570 cur_cfg_comp = NULL;
3571 }
3572
ebba3338
PP
3573 ret = bt_config_create_connections(cfg, connection_args,
3574 error_buf, 256);
3575 if (ret) {
3576 printf_err("Cannot creation connections:\n%s", error_buf);
3577 goto error;
3578 }
3579
c42c79ea
PP
3580 goto end;
3581
3582error:
290725f7
PP
3583 *retcode = 1;
3584 BT_PUT(cfg);
3585
c42c79ea
PP
3586end:
3587 if (pc) {
3588 poptFreeContext(pc);
3589 }
3590
3591 if (text_legacy_opts.output) {
3592 g_string_free(text_legacy_opts.output, TRUE);
3593 }
3594
3595 if (text_legacy_opts.dbg_info_dir) {
3596 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
3597 }
3598
3599 if (text_legacy_opts.dbg_info_target_prefix) {
3600 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
3601 }
3602
3603 free(arg);
65582340 3604 BT_PUT(implicit_source_comp);
bdc61c70 3605 BT_PUT(cur_cfg_comp);
b07ffa28 3606 BT_PUT(cur_base_params);
c42c79ea
PP
3607 BT_PUT(text_legacy_opts.names);
3608 BT_PUT(text_legacy_opts.fields);
3609 BT_PUT(legacy_input_paths);
3b6cfcc5 3610 BT_PUT(instance_names);
ebba3338 3611 BT_PUT(connection_args);
290725f7
PP
3612 return cfg;
3613}
3614
3615/*
3616 * Prints the Babeltrace 2.x general usage.
3617 */
3618static
3619void print_gen_usage(FILE *fp)
3620{
3621 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
3622 fprintf(fp, "\n");
3623 fprintf(fp, "General options:\n");
3624 fprintf(fp, "\n");
3625 fprintf(fp, " -d, --debug Enable debug mode\n");
3626 fprintf(fp, " -h --help Show this help and quit\n");
3627 fprintf(fp, " --help-legacy Show Babeltrace 1.x legacy help and quit\n");
3628 fprintf(fp, " -v, --verbose Enable verbose output\n");
3629 fprintf(fp, " -V, --version Show version and quit\n");
3630 fprintf(fp, "\n");
3631 fprintf(fp, "Available commands:\n");
3632 fprintf(fp, "\n");
3633 fprintf(fp, " convert Build a trace conversion graph and run it (default)\n");
22e22462 3634 fprintf(fp, " help Get help for a plugin or a component class\n");
290725f7
PP
3635 fprintf(fp, " list-plugins List available plugins and their content\n");
3636 fprintf(fp, "\n");
3637 fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
3638}
3639
3640struct bt_config *bt_config_from_args(int argc, const char *argv[],
3641 int *retcode, bool omit_system_plugin_path,
3642 bool omit_home_plugin_path,
3643 struct bt_value *initial_plugin_paths)
3644{
3645 struct bt_config *config = NULL;
3646 bool verbose = false;
3647 bool debug = false;
3648 int i;
3649 enum bt_config_command command = -1;
3650 const char **command_argv = NULL;
3651 int command_argc = -1;
3652 const char *command_name = NULL;
3653
3654 *retcode = -1;
3655
3656 if (argc <= 1) {
3657 print_gen_usage(stdout);
3658 goto end;
3659 }
3660
3661 for (i = 1; i < argc; i++) {
3662 const char *cur_arg = argv[i];
3663
3664 if (strcmp(cur_arg, "-d") == 0 ||
3665 strcmp(cur_arg, "--debug") == 0) {
3666 debug = true;
3667 } else if (strcmp(cur_arg, "-v") == 0 ||
3668 strcmp(cur_arg, "--verbose") == 0) {
3669 verbose = true;
3670 } else if (strcmp(cur_arg, "-V") == 0 ||
3671 strcmp(cur_arg, "--version") == 0) {
3672 print_version();
3673 goto end;
3674 } else if (strcmp(cur_arg, "-h") == 0 ||
3675 strcmp(cur_arg, "--help") == 0) {
3676 print_gen_usage(stdout);
3677 goto end;
3678 } else if (strcmp(cur_arg, "--help-legacy") == 0) {
3679 print_legacy_usage(stdout);
3680 goto end;
3681 } else {
22e22462
PP
3682 bool has_command = true;
3683
290725f7
PP
3684 /*
3685 * First unknown argument: is it a known command
3686 * name?
3687 */
3688 if (strcmp(cur_arg, "convert") == 0) {
3689 command = BT_CONFIG_COMMAND_CONVERT;
290725f7
PP
3690 } else if (strcmp(cur_arg, "list-plugins") == 0) {
3691 command = BT_CONFIG_COMMAND_LIST_PLUGINS;
22e22462
PP
3692 } else if (strcmp(cur_arg, "help") == 0) {
3693 command = BT_CONFIG_COMMAND_HELP;
290725f7
PP
3694 } else {
3695 /*
3696 * Unknown argument, but not a known
3697 * command name: assume the whole
3698 * arguments are for the default convert
3699 * command.
3700 */
3701 command = BT_CONFIG_COMMAND_CONVERT;
3702 command_argv = argv;
3703 command_argc = argc;
22e22462
PP
3704 has_command = false;
3705 }
3706
3707 if (has_command) {
3708 command_argv = &argv[i];
3709 command_argc = argc - i;
3710 command_name = cur_arg;
290725f7
PP
3711 }
3712 break;
3713 }
3714 }
3715
3716 if ((int) command < 0) {
3717 /*
3718 * We only got non-help, non-version general options
3719 * like --verbose and --debug, without any other
3720 * arguments, so we can't do anything useful: print the
3721 * usage and quit.
3722 */
3723 print_gen_usage(stdout);
3724 goto end;
3725 }
3726
3727 assert(command_argv);
3728 assert(command_argc >= 0);
3729
3730 switch (command) {
3731 case BT_CONFIG_COMMAND_CONVERT:
3732 config = bt_config_convert_from_args(command_argc, command_argv,
3733 retcode, omit_system_plugin_path,
3734 omit_home_plugin_path, initial_plugin_paths);
3735 break;
3736 case BT_CONFIG_COMMAND_LIST_PLUGINS:
3737 config = bt_config_list_plugins_from_args(command_argc,
3738 command_argv, retcode, omit_system_plugin_path,
3739 omit_home_plugin_path, initial_plugin_paths);
3740 break;
22e22462
PP
3741 case BT_CONFIG_COMMAND_HELP:
3742 config = bt_config_help_from_args(command_argc,
3743 command_argv, retcode, omit_system_plugin_path,
3744 omit_home_plugin_path, initial_plugin_paths);
3745 break;
290725f7
PP
3746 default:
3747 assert(false);
3748 }
3749
3750 if (config) {
3751 if (verbose) {
3752 config->verbose = true;
3753 }
3754
3755 if (debug) {
3756 config->debug = true;
3757 }
3758
3759 config->command_name = command_name;
3760 }
3761
3762end:
3763 return config;
c42c79ea 3764}
This page took 0.187071 seconds and 4 git commands to generate.