babeltrace-cfg.c: do not infer text.text sink with -v
[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;
a263021c 133 bool verbose;
c42c79ea
PP
134};
135
136/* Legacy input format format */
137enum legacy_input_format {
138 LEGACY_INPUT_FORMAT_NONE = 0,
139 LEGACY_INPUT_FORMAT_CTF,
140 LEGACY_INPUT_FORMAT_LTTNG_LIVE,
141};
142
143/* Legacy output format format */
144enum legacy_output_format {
145 LEGACY_OUTPUT_FORMAT_NONE = 0,
146 LEGACY_OUTPUT_FORMAT_TEXT,
c42c79ea
PP
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 ||
a1e34893 190 opts->clock_date || opts->clock_gmt ||
c42c79ea
PP
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{
87796884
PP
645 const char *arg_ch = arg;
646 char *ch;
647 bool in_component = false;
c42c79ea 648
87796884
PP
649 /* Initialize both return values */
650 *plugin = g_malloc0(strlen(arg) + 1);
651 ch = *plugin;
c42c79ea
PP
652 if (!*plugin) {
653 print_err_oom();
87796884 654 goto error;
c42c79ea
PP
655 }
656
87796884 657 *component = g_malloc0(strlen(arg) + 1);
c42c79ea
PP
658 if (!*component) {
659 print_err_oom();
87796884 660 goto error;
c42c79ea
PP
661 }
662
87796884
PP
663 while (*arg_ch != '\0') {
664 switch (*arg_ch) {
665 case '\\':
666 if (arg_ch[1] == '\0') {
667 /* `\` at the end of the string */
668 *ch = *arg_ch;
669 ch++;
670 arg_ch++;
671 } else if (arg_ch[1] == '\\' || arg_ch[1] == '.') {
672 /* Escaped `\` or `.` */
673 *ch = arg_ch[1];
674 ch++;
675 arg_ch += 2;
676 } else {
677 /* Unknown escaped character (write `\` too) */
678 ch[0] = arg_ch[0];
679 ch[1] = arg_ch[1];
680 ch += 2;
681 arg_ch += 2;
682
683 }
684 continue;
685 case '.':
686 if (in_component) {
687 goto error;
688 }
689
690 in_component = true;
691 ch = *component;
692 arg_ch++;
693 break;
694 default:
695 *ch = *arg_ch;
696 ch++;
697 arg_ch++;
698 break;
699 }
700 }
701
702 if (strlen(*plugin) == 0 || strlen(*component) == 0) {
703 goto error;
704 }
705
706 goto end;
707
708error:
709 g_free(*plugin);
710 *plugin = NULL;
711 g_free(*component);
712 *component = NULL;
c42c79ea
PP
713
714end:
715 return;
716}
717
718/*
719 * Prints the Babeltrace version.
720 */
721static
722void print_version(void)
723{
724 puts("Babeltrace " VERSION);
725}
726
c42c79ea
PP
727/*
728 * Destroys a component configuration.
729 */
730static
731void bt_config_component_destroy(struct bt_object *obj)
732{
733 struct bt_config_component *bt_config_component =
734 container_of(obj, struct bt_config_component, base);
735
736 if (!obj) {
737 goto end;
738 }
739
740 if (bt_config_component->plugin_name) {
741 g_string_free(bt_config_component->plugin_name, TRUE);
742 }
743
744 if (bt_config_component->component_name) {
745 g_string_free(bt_config_component->component_name, TRUE);
746 }
747
3b6cfcc5
PP
748 if (bt_config_component->instance_name) {
749 g_string_free(bt_config_component->instance_name, TRUE);
750 }
751
c42c79ea
PP
752 BT_PUT(bt_config_component->params);
753 g_free(bt_config_component);
754
755end:
756 return;
757}
758
759/*
bdc61c70
PP
760 * Creates a component configuration using the given plugin name and
761 * component name. plugin_name and component_name are copied (belong to
762 * the return value).
c42c79ea
PP
763 *
764 * Return value is owned by the caller.
765 */
766static
90de159b
PP
767struct bt_config_component *bt_config_component_create(
768 enum bt_component_class_type type,
769 const char *plugin_name, const char *component_name)
c42c79ea
PP
770{
771 struct bt_config_component *cfg_component = NULL;
772
773 cfg_component = g_new0(struct bt_config_component, 1);
774 if (!cfg_component) {
775 print_err_oom();
776 goto error;
777 }
778
779 bt_object_init(cfg_component, bt_config_component_destroy);
90de159b 780 cfg_component->type = type;
c42c79ea
PP
781 cfg_component->plugin_name = g_string_new(plugin_name);
782 if (!cfg_component->plugin_name) {
783 print_err_oom();
784 goto error;
785 }
786
787 cfg_component->component_name = g_string_new(component_name);
788 if (!cfg_component->component_name) {
789 print_err_oom();
790 goto error;
791 }
792
3b6cfcc5
PP
793 cfg_component->instance_name = g_string_new(NULL);
794 if (!cfg_component->instance_name) {
795 print_err_oom();
796 goto error;
797 }
798
bdc61c70
PP
799 /* Start with empty parameters */
800 cfg_component->params = bt_value_map_create();
801 if (!cfg_component->params) {
802 print_err_oom();
803 goto error;
804 }
805
c42c79ea
PP
806 goto end;
807
808error:
809 BT_PUT(cfg_component);
810
811end:
812 return cfg_component;
813}
814
815/*
816 * Creates a component configuration from a command-line source/sink
bdc61c70 817 * option's argument.
c42c79ea 818 */
90de159b
PP
819struct bt_config_component *bt_config_component_from_arg(
820 enum bt_component_class_type type, const char *arg)
c42c79ea
PP
821{
822 struct bt_config_component *bt_config_component = NULL;
823 char *plugin_name;
824 char *component_name;
c42c79ea
PP
825
826 plugin_component_names_from_arg(arg, &plugin_name, &component_name);
827 if (!plugin_name || !component_name) {
49849a47 828 printf_err("Cannot get plugin or component class name\n");
c42c79ea
PP
829 goto error;
830 }
831
90de159b 832 bt_config_component = bt_config_component_create(type, plugin_name,
bdc61c70 833 component_name);
c42c79ea
PP
834 if (!bt_config_component) {
835 goto error;
836 }
837
838 goto end;
839
840error:
841 BT_PUT(bt_config_component);
842
843end:
bdc61c70
PP
844 g_free(plugin_name);
845 g_free(component_name);
c42c79ea
PP
846 return bt_config_component;
847}
848
849/*
850 * Destroys a configuration.
851 */
852static
853void bt_config_destroy(struct bt_object *obj)
854{
290725f7 855 struct bt_config *cfg =
c42c79ea
PP
856 container_of(obj, struct bt_config, base);
857
858 if (!obj) {
859 goto end;
860 }
861
290725f7
PP
862 switch (cfg->command) {
863 case BT_CONFIG_COMMAND_CONVERT:
864 if (cfg->cmd_data.convert.sources) {
865 g_ptr_array_free(cfg->cmd_data.convert.sources, TRUE);
866 }
c42c79ea 867
ebba3338
PP
868 if (cfg->cmd_data.convert.filters) {
869 g_ptr_array_free(cfg->cmd_data.convert.filters, TRUE);
870 }
871
290725f7
PP
872 if (cfg->cmd_data.convert.sinks) {
873 g_ptr_array_free(cfg->cmd_data.convert.sinks, TRUE);
874 }
875
ebba3338
PP
876 if (cfg->cmd_data.convert.connections) {
877 g_ptr_array_free(cfg->cmd_data.convert.connections,
878 TRUE);
879 }
880
290725f7
PP
881 BT_PUT(cfg->cmd_data.convert.plugin_paths);
882 break;
290725f7
PP
883 case BT_CONFIG_COMMAND_LIST_PLUGINS:
884 BT_PUT(cfg->cmd_data.list_plugins.plugin_paths);
885 break;
22e22462
PP
886 case BT_CONFIG_COMMAND_HELP:
887 BT_PUT(cfg->cmd_data.help.plugin_paths);
90de159b 888 BT_PUT(cfg->cmd_data.help.cfg_component);
22e22462 889 break;
a67681c1
PP
890 case BT_CONFIG_COMMAND_QUERY:
891 BT_PUT(cfg->cmd_data.query.plugin_paths);
892 BT_PUT(cfg->cmd_data.query.cfg_component);
63ce0e1d 893
a67681c1
PP
894 if (cfg->cmd_data.query.object) {
895 g_string_free(cfg->cmd_data.query.object, TRUE);
63ce0e1d
PP
896 }
897 break;
290725f7
PP
898 default:
899 assert(false);
c42c79ea
PP
900 }
901
290725f7 902 g_free(cfg);
c42c79ea
PP
903
904end:
905 return;
906}
907
1670bffd
PP
908static void destroy_gstring(void *data)
909{
910 g_string_free(data, TRUE);
911}
912
c42c79ea
PP
913/*
914 * Extracts the various paths from the string arg, delimited by ':',
5a3ee633 915 * and appends them to the array value object plugin_paths.
c42c79ea 916 */
5a3ee633
PP
917enum bt_value_status bt_config_append_plugin_paths(
918 struct bt_value *plugin_paths, const char *arg)
c42c79ea 919{
1670bffd
PP
920 enum bt_value_status status = BT_VALUE_STATUS_OK;
921 GPtrArray *dirs = g_ptr_array_new_with_free_func(destroy_gstring);
922 int ret;
923 size_t i;
c42c79ea 924
1670bffd
PP
925 if (!dirs) {
926 status = BT_VALUE_STATUS_ERROR;
927 goto end;
928 }
c42c79ea 929
1670bffd
PP
930 ret = bt_common_append_plugin_path_dirs(arg, dirs);
931 if (ret) {
932 status = BT_VALUE_STATUS_ERROR;
933 goto end;
934 }
c42c79ea 935
1670bffd
PP
936 for (i = 0; i < dirs->len; i++) {
937 GString *dir = g_ptr_array_index(dirs, i);
c42c79ea 938
1670bffd 939 bt_value_array_append_string(plugin_paths, dir->str);
c42c79ea
PP
940 }
941
1670bffd
PP
942end:
943 g_ptr_array_free(dirs, TRUE);
944 return status;
c42c79ea
PP
945}
946
947/*
948 * Creates a simple lexical scanner for parsing comma-delimited names
949 * and fields.
950 *
951 * Return value is owned by the caller.
952 */
953static
954GScanner *create_csv_identifiers_scanner(void)
955{
956 GScannerConfig scanner_config = {
957 .cset_skip_characters = " \t\n",
958 .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
959 .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
960 .case_sensitive = TRUE,
961 .cpair_comment_single = NULL,
962 .skip_comment_multi = TRUE,
963 .skip_comment_single = TRUE,
964 .scan_comment_multi = FALSE,
965 .scan_identifier = TRUE,
966 .scan_identifier_1char = TRUE,
967 .scan_identifier_NULL = FALSE,
968 .scan_symbols = FALSE,
969 .symbol_2_token = FALSE,
970 .scope_0_fallback = FALSE,
971 .scan_binary = FALSE,
972 .scan_octal = FALSE,
973 .scan_float = FALSE,
974 .scan_hex = FALSE,
975 .scan_hex_dollar = FALSE,
976 .numbers_2_int = FALSE,
977 .int_2_float = FALSE,
978 .store_int64 = FALSE,
979 .scan_string_sq = FALSE,
980 .scan_string_dq = FALSE,
981 .identifier_2_string = FALSE,
982 .char_2_token = TRUE,
983 };
984
985 return g_scanner_new(&scanner_config);
986}
987
6e1bc0df
MD
988/*
989 * Inserts a string (if exists and not empty) or null to a map value
990 * object.
991 */
992static
993enum bt_value_status map_insert_string_or_null(struct bt_value *map,
994 const char *key, GString *string)
995{
996 enum bt_value_status ret;
997
998 if (string && string->len > 0) {
999 ret = bt_value_map_insert_string(map, key, string->str);
1000 } else {
1001 ret = bt_value_map_insert(map, key, bt_value_null);
1002 }
1003 return ret;
1004}
1005
c42c79ea
PP
1006/*
1007 * Converts a comma-delimited list of known names (--names option) to
1008 * an array value object containing those names as string value objects.
1009 *
1010 * Return value is owned by the caller.
1011 */
1012static
1013struct bt_value *names_from_arg(const char *arg)
1014{
1015 GScanner *scanner = NULL;
1016 struct bt_value *names = NULL;
6e1bc0df 1017 bool found_all = false, found_none = false, found_item = false;
c42c79ea
PP
1018
1019 names = bt_value_array_create();
1020 if (!names) {
1021 print_err_oom();
1022 goto error;
1023 }
1024
1025 scanner = create_csv_identifiers_scanner();
1026 if (!scanner) {
1027 print_err_oom();
1028 goto error;
1029 }
1030
1031 g_scanner_input_text(scanner, arg, strlen(arg));
1032
1033 while (true) {
1034 GTokenType token_type = g_scanner_get_next_token(scanner);
1035
1036 switch (token_type) {
1037 case G_TOKEN_IDENTIFIER:
1038 {
1039 const char *identifier = scanner->value.v_identifier;
1040
1041 if (!strcmp(identifier, "payload") ||
1042 !strcmp(identifier, "args") ||
1043 !strcmp(identifier, "arg")) {
6e1bc0df 1044 found_item = true;
c42c79ea
PP
1045 if (bt_value_array_append_string(names,
1046 "payload")) {
1047 goto error;
1048 }
1049 } else if (!strcmp(identifier, "context") ||
1050 !strcmp(identifier, "ctx")) {
6e1bc0df 1051 found_item = true;
c42c79ea
PP
1052 if (bt_value_array_append_string(names,
1053 "context")) {
1054 goto error;
1055 }
1056 } else if (!strcmp(identifier, "scope") ||
1057 !strcmp(identifier, "header")) {
6e1bc0df 1058 found_item = true;
c42c79ea
PP
1059 if (bt_value_array_append_string(names,
1060 identifier)) {
1061 goto error;
1062 }
6e1bc0df
MD
1063 } else if (!strcmp(identifier, "all")) {
1064 found_all = true;
1065 if (bt_value_array_append_string(names,
1066 identifier)) {
c42c79ea
PP
1067 goto error;
1068 }
6e1bc0df
MD
1069 } else if (!strcmp(identifier, "none")) {
1070 found_none = true;
c42c79ea
PP
1071 if (bt_value_array_append_string(names,
1072 identifier)) {
1073 goto error;
1074 }
c42c79ea 1075 } else {
6d1d5711 1076 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1077 identifier);
1078 goto error;
1079 }
1080 break;
1081 }
1082 case G_TOKEN_COMMA:
1083 continue;
1084 case G_TOKEN_EOF:
1085 goto end;
1086 default:
1087 goto error;
1088 }
1089 }
1090
6e1bc0df
MD
1091end:
1092 if (found_none && found_all) {
6d1d5711 1093 printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
6e1bc0df
MD
1094 goto error;
1095 }
1096 /*
1097 * Legacy behavior is to clear the defaults (show none) when at
1098 * least one item is specified.
1099 */
1100 if (found_item && !found_none && !found_all) {
1101 if (bt_value_array_append_string(names, "none")) {
1102 goto error;
1103 }
1104 }
1105 if (scanner) {
1106 g_scanner_destroy(scanner);
1107 }
1108 return names;
c42c79ea
PP
1109
1110error:
1111 BT_PUT(names);
c42c79ea
PP
1112 if (scanner) {
1113 g_scanner_destroy(scanner);
1114 }
1115 return names;
1116}
1117
1118
1119/*
1120 * Converts a comma-delimited list of known fields (--fields option) to
1121 * an array value object containing those fields as string
1122 * value objects.
1123 *
1124 * Return value is owned by the caller.
1125 */
1126static
1127struct bt_value *fields_from_arg(const char *arg)
1128{
1129 GScanner *scanner = NULL;
1130 struct bt_value *fields;
1131
1132 fields = bt_value_array_create();
1133 if (!fields) {
1134 print_err_oom();
1135 goto error;
1136 }
1137
1138 scanner = create_csv_identifiers_scanner();
1139 if (!scanner) {
1140 print_err_oom();
1141 goto error;
1142 }
1143
1144 g_scanner_input_text(scanner, arg, strlen(arg));
1145
1146 while (true) {
1147 GTokenType token_type = g_scanner_get_next_token(scanner);
1148
1149 switch (token_type) {
1150 case G_TOKEN_IDENTIFIER:
1151 {
1152 const char *identifier = scanner->value.v_identifier;
1153
1154 if (!strcmp(identifier, "trace") ||
1155 !strcmp(identifier, "trace:hostname") ||
1156 !strcmp(identifier, "trace:domain") ||
1157 !strcmp(identifier, "trace:procname") ||
1158 !strcmp(identifier, "trace:vpid") ||
1159 !strcmp(identifier, "loglevel") ||
1160 !strcmp(identifier, "emf") ||
6e1bc0df
MD
1161 !strcmp(identifier, "callsite") ||
1162 !strcmp(identifier, "all")) {
c42c79ea
PP
1163 if (bt_value_array_append_string(fields,
1164 identifier)) {
1165 goto error;
1166 }
c42c79ea 1167 } else {
6d1d5711 1168 printf_err("Unknown field name: `%s`\n",
c42c79ea
PP
1169 identifier);
1170 goto error;
1171 }
1172 break;
1173 }
1174 case G_TOKEN_COMMA:
1175 continue;
1176 case G_TOKEN_EOF:
1177 goto end;
1178 default:
1179 goto error;
1180 }
1181 }
1182
1183 goto end;
1184
1185error:
1186 BT_PUT(fields);
1187
1188end:
1189 if (scanner) {
1190 g_scanner_destroy(scanner);
1191 }
1192 return fields;
1193}
1194
1195/*
1196 * Inserts the equivalent "prefix-name" true boolean value objects into
1197 * map_obj where the names are in array_obj.
1198 */
1199static
1200int insert_flat_names_fields_from_array(struct bt_value *map_obj,
1201 struct bt_value *array_obj, const char *prefix)
1202{
1203 int ret = 0;
1204 int i;
6e1bc0df 1205 GString *tmpstr = NULL, *default_value = NULL;
c42c79ea
PP
1206
1207 /*
1208 * array_obj may be NULL if no CLI options were specified to
1209 * trigger its creation.
1210 */
1211 if (!array_obj) {
1212 goto end;
1213 }
1214
1215 tmpstr = g_string_new(NULL);
1216 if (!tmpstr) {
1217 print_err_oom();
1218 ret = -1;
1219 goto end;
1220 }
1221
6e1bc0df
MD
1222 default_value = g_string_new(NULL);
1223 if (!default_value) {
1224 print_err_oom();
1225 ret = -1;
1226 goto end;
1227 }
1228
c42c79ea
PP
1229 for (i = 0; i < bt_value_array_size(array_obj); i++) {
1230 struct bt_value *str_obj = bt_value_array_get(array_obj, i);
1231 const char *suffix;
6e1bc0df 1232 bool is_default = false;
c42c79ea
PP
1233
1234 if (!str_obj) {
1235 printf_err("Unexpected error\n");
1236 ret = -1;
1237 goto end;
1238 }
1239
1240 ret = bt_value_string_get(str_obj, &suffix);
1241 BT_PUT(str_obj);
1242 if (ret) {
1243 printf_err("Unexpected error\n");
1244 goto end;
1245 }
1246
1247 g_string_assign(tmpstr, prefix);
1248 g_string_append(tmpstr, "-");
6e1bc0df
MD
1249
1250 /* Special-case for "all" and "none". */
1251 if (!strcmp(suffix, "all")) {
1252 is_default = true;
1253 g_string_assign(default_value, "show");
1254 } else if (!strcmp(suffix, "none")) {
1255 is_default = true;
1256 g_string_assign(default_value, "hide");
1257 }
1258 if (is_default) {
1259 g_string_append(tmpstr, "default");
1260 ret = map_insert_string_or_null(map_obj,
1261 tmpstr->str,
1262 default_value);
1263 if (ret) {
1264 print_err_oom();
1265 goto end;
1266 }
1267 } else {
1268 g_string_append(tmpstr, suffix);
1269 ret = bt_value_map_insert_bool(map_obj, tmpstr->str,
1270 true);
1271 if (ret) {
1272 print_err_oom();
1273 goto end;
1274 }
c42c79ea
PP
1275 }
1276 }
1277
1278end:
6e1bc0df
MD
1279 if (default_value) {
1280 g_string_free(default_value, TRUE);
1281 }
c42c79ea
PP
1282 if (tmpstr) {
1283 g_string_free(tmpstr, TRUE);
1284 }
1285
1286 return ret;
1287}
1288
c42c79ea
PP
1289/*
1290 * Returns the parameters (map value object) corresponding to the
1291 * legacy text format options.
1292 *
1293 * Return value is owned by the caller.
1294 */
1295static
1296struct bt_value *params_from_text_legacy_opts(
1297 struct text_legacy_opts *text_legacy_opts)
1298{
1299 struct bt_value *params;
1300
1301 params = bt_value_map_create();
1302 if (!params) {
1303 print_err_oom();
1304 goto error;
1305 }
1306
1307 if (map_insert_string_or_null(params, "output-path",
1308 text_legacy_opts->output)) {
1309 print_err_oom();
1310 goto error;
1311 }
1312
1313 if (map_insert_string_or_null(params, "debug-info-dir",
1314 text_legacy_opts->dbg_info_dir)) {
1315 print_err_oom();
1316 goto error;
1317 }
1318
1319 if (map_insert_string_or_null(params, "debug-info-target-prefix",
1320 text_legacy_opts->dbg_info_target_prefix)) {
1321 print_err_oom();
1322 goto error;
1323 }
1324
1325 if (bt_value_map_insert_bool(params, "debug-info-full-path",
1326 text_legacy_opts->dbg_info_full_path)) {
1327 print_err_oom();
1328 goto error;
1329 }
1330
1331 if (bt_value_map_insert_bool(params, "no-delta",
1332 text_legacy_opts->no_delta)) {
1333 print_err_oom();
1334 goto error;
1335 }
1336
1337 if (bt_value_map_insert_bool(params, "clock-cycles",
1338 text_legacy_opts->clock_cycles)) {
1339 print_err_oom();
1340 goto error;
1341 }
1342
1343 if (bt_value_map_insert_bool(params, "clock-seconds",
1344 text_legacy_opts->clock_seconds)) {
1345 print_err_oom();
1346 goto error;
1347 }
1348
1349 if (bt_value_map_insert_bool(params, "clock-date",
1350 text_legacy_opts->clock_date)) {
1351 print_err_oom();
1352 goto error;
1353 }
1354
1355 if (bt_value_map_insert_bool(params, "clock-gmt",
1356 text_legacy_opts->clock_gmt)) {
1357 print_err_oom();
1358 goto error;
1359 }
1360
a263021c
JD
1361 if (bt_value_map_insert_bool(params, "verbose",
1362 text_legacy_opts->verbose)) {
1363 print_err_oom();
1364 goto error;
1365 }
1366
c42c79ea
PP
1367 if (insert_flat_names_fields_from_array(params,
1368 text_legacy_opts->names, "name")) {
1369 goto error;
1370 }
1371
1372 if (insert_flat_names_fields_from_array(params,
1373 text_legacy_opts->fields, "field")) {
1374 goto error;
1375 }
1376
1377 goto end;
1378
1379error:
1380 BT_PUT(params);
1381
1382end:
1383 return params;
1384}
1385
1386static
1387int append_sinks_from_legacy_opts(GPtrArray *sinks,
1388 enum legacy_output_format legacy_output_format,
1389 struct text_legacy_opts *text_legacy_opts)
1390{
1391 int ret = 0;
1392 struct bt_value *params = NULL;
1393 const char *plugin_name;
1394 const char *component_name;
1395 struct bt_config_component *bt_config_component = NULL;
1396
1397 switch (legacy_output_format) {
1398 case LEGACY_OUTPUT_FORMAT_TEXT:
1399 plugin_name = "text";
1400 component_name = "text";
1401 break;
c42c79ea 1402 case LEGACY_OUTPUT_FORMAT_DUMMY:
9987e1ac 1403 plugin_name = "utils";
c42c79ea
PP
1404 component_name = "dummy";
1405 break;
1406 default:
1407 assert(false);
1408 break;
1409 }
1410
1411 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT) {
1412 /* Legacy "text" output format has parameters */
1413 params = params_from_text_legacy_opts(text_legacy_opts);
1414 if (!params) {
1415 goto error;
1416 }
1417 } else {
1418 /*
1419 * Legacy "dummy" and "ctf-metadata" output formats do
1420 * not have parameters.
1421 */
1422 params = bt_value_map_create();
1423 if (!params) {
1424 print_err_oom();
1425 goto error;
1426 }
1427 }
1428
1429 /* Create a component configuration */
90de159b
PP
1430 bt_config_component = bt_config_component_create(
1431 BT_COMPONENT_CLASS_TYPE_SINK, plugin_name, component_name);
c42c79ea
PP
1432 if (!bt_config_component) {
1433 goto error;
1434 }
1435
bdc61c70
PP
1436 BT_MOVE(bt_config_component->params, params);
1437
c42c79ea
PP
1438 /* Move created component configuration to the array */
1439 g_ptr_array_add(sinks, bt_config_component);
1440
1441 goto end;
1442
1443error:
1444 ret = -1;
1445
1446end:
1447 BT_PUT(params);
1448
1449 return ret;
1450}
1451
1452/*
1453 * Returns the parameters (map value object) corresponding to the
1454 * given legacy CTF format options.
1455 *
1456 * Return value is owned by the caller.
1457 */
1458static
1459struct bt_value *params_from_ctf_legacy_opts(
1460 struct ctf_legacy_opts *ctf_legacy_opts)
1461{
1462 struct bt_value *params;
1463
1464 params = bt_value_map_create();
1465 if (!params) {
1466 print_err_oom();
1467 goto error;
1468 }
1469
1470 if (bt_value_map_insert_integer(params, "offset-s",
1471 ctf_legacy_opts->offset_s.value)) {
1472 print_err_oom();
1473 goto error;
1474 }
1475
1476 if (bt_value_map_insert_integer(params, "offset-ns",
1477 ctf_legacy_opts->offset_ns.value)) {
1478 print_err_oom();
1479 goto error;
1480 }
1481
1482 if (bt_value_map_insert_bool(params, "stream-intersection",
1483 ctf_legacy_opts->stream_intersection)) {
1484 print_err_oom();
1485 goto error;
1486 }
1487
1488 goto end;
1489
1490error:
1491 BT_PUT(params);
1492
1493end:
1494 return params;
1495}
1496
1497static
1498int append_sources_from_legacy_opts(GPtrArray *sources,
1499 enum legacy_input_format legacy_input_format,
1500 struct ctf_legacy_opts *ctf_legacy_opts,
528debdf 1501 struct bt_value *legacy_input_paths)
c42c79ea
PP
1502{
1503 int ret = 0;
1504 int i;
1505 struct bt_value *base_params;
1506 struct bt_value *params = NULL;
1507 struct bt_value *input_path = NULL;
1508 struct bt_value *input_path_copy = NULL;
1509 const char *input_key;
1510 const char *component_name;
1511
1512 switch (legacy_input_format) {
1513 case LEGACY_INPUT_FORMAT_CTF:
1514 input_key = "path";
1515 component_name = "fs";
1516 break;
1517 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1518 input_key = "url";
1519 component_name = "lttng-live";
1520 break;
1521 default:
1522 assert(false);
1523 break;
1524 }
1525
1526 base_params = params_from_ctf_legacy_opts(ctf_legacy_opts);
1527 if (!base_params) {
1528 goto error;
1529 }
1530
1531 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1532 struct bt_config_component *bt_config_component = NULL;
1533
1534 /* Copy base parameters as current parameters */
1535 params = bt_value_copy(base_params);
1536 if (!params) {
1537 goto error;
1538 }
1539
1540 /* Get current input path string value object */
1541 input_path = bt_value_array_get(legacy_input_paths, i);
1542 if (!input_path) {
1543 goto error;
1544 }
1545
1546 /* Copy current input path value object */
1547 input_path_copy = bt_value_copy(input_path);
1548 if (!input_path_copy) {
1549 goto error;
1550 }
1551
1552 /* Insert input path value object into current parameters */
1553 ret = bt_value_map_insert(params, input_key, input_path_copy);
1554 if (ret) {
1555 goto error;
1556 }
1557
1558 /* Create a component configuration */
90de159b
PP
1559 bt_config_component = bt_config_component_create(
1560 BT_COMPONENT_CLASS_TYPE_SOURCE, "ctf", component_name);
c42c79ea
PP
1561 if (!bt_config_component) {
1562 goto error;
1563 }
1564
bdc61c70
PP
1565 BT_MOVE(bt_config_component->params, params);
1566
c42c79ea
PP
1567 /* Move created component configuration to the array */
1568 g_ptr_array_add(sources, bt_config_component);
1569
1570 /* Put current stuff */
1571 BT_PUT(input_path);
1572 BT_PUT(input_path_copy);
c42c79ea
PP
1573 }
1574
1575 goto end;
1576
1577error:
1578 ret = -1;
1579
1580end:
1581 BT_PUT(base_params);
1582 BT_PUT(params);
1583 BT_PUT(input_path);
1584 BT_PUT(input_path_copy);
1585 return ret;
1586}
1587
1588/*
1589 * Escapes a string for the shell. The string is escaped knowing that
1590 * it's a parameter string value (double-quoted), and that it will be
1591 * entered between single quotes in the shell.
1592 *
1593 * Return value is owned by the caller.
1594 */
1595static
1596char *str_shell_escape(const char *input)
1597{
1598 char *ret = NULL;
1599 const char *at = input;
1600 GString *str = g_string_new(NULL);
1601
1602 if (!str) {
1603 goto end;
1604 }
1605
1606 while (*at != '\0') {
1607 switch (*at) {
1608 case '\\':
1609 g_string_append(str, "\\\\");
1610 break;
1611 case '"':
1612 g_string_append(str, "\\\"");
1613 break;
1614 case '\'':
1615 g_string_append(str, "'\"'\"'");
1616 break;
1617 case '\n':
1618 g_string_append(str, "\\n");
1619 break;
1620 case '\t':
1621 g_string_append(str, "\\t");
1622 break;
1623 default:
1624 g_string_append_c(str, *at);
1625 break;
1626 }
1627
1628 at++;
1629 }
1630
1631end:
1632 if (str) {
1633 ret = str->str;
1634 g_string_free(str, FALSE);
1635 }
1636
1637 return ret;
1638}
1639
1640static
1641int append_prefixed_flag_params(GString *str, struct bt_value *flags,
1642 const char *prefix)
1643{
1644 int ret = 0;
1645 int i;
1646
1647 if (!flags) {
1648 goto end;
1649 }
1650
1651 for (i = 0; i < bt_value_array_size(flags); i++) {
1652 struct bt_value *value = bt_value_array_get(flags, i);
1653 const char *flag;
1654
1655 if (!value) {
1656 ret = -1;
1657 goto end;
1658 }
1659
1660 if (bt_value_string_get(value, &flag)) {
1661 BT_PUT(value);
1662 ret = -1;
1663 goto end;
1664 }
1665
1666 g_string_append_printf(str, ",%s-%s=true", prefix, flag);
1667 BT_PUT(value);
1668 }
1669
1670end:
1671 return ret;
1672}
1673
1674/*
1675 * Appends a boolean parameter string.
1676 */
1677static
1678void g_string_append_bool_param(GString *str, const char *name, bool value)
1679{
1680 g_string_append_printf(str, ",%s=%s", name, value ? "true" : "false");
1681}
1682
1683/*
1684 * Appends a path parameter string, or null if it's empty.
1685 */
1686static
1687int g_string_append_string_path_param(GString *str, const char *name,
1688 GString *path)
1689{
1690 int ret = 0;
1691
1692 if (path->len > 0) {
1693 char *escaped_path = str_shell_escape(path->str);
1694
1695 if (!escaped_path) {
1696 print_err_oom();
1697 goto error;
1698 }
1699
1700 g_string_append_printf(str, "%s=\"%s\"", name, escaped_path);
1701 free(escaped_path);
1702 } else {
1703 g_string_append_printf(str, "%s=null", name);
1704 }
1705
1706 goto end;
1707
1708error:
1709 ret = -1;
1710
1711end:
1712 return ret;
1713}
1714
1715/*
1716 * Prints the non-legacy sink options equivalent to the specified
1717 * legacy output format options.
1718 */
1719static
1720void print_output_legacy_to_sinks(
1721 enum legacy_output_format legacy_output_format,
1722 struct text_legacy_opts *text_legacy_opts)
1723{
9987e1ac 1724 const char *output_format;
c42c79ea
PP
1725 GString *str = NULL;
1726
1727 str = g_string_new(" ");
1728 if (!str) {
1729 print_err_oom();
1730 goto end;
1731 }
1732
1733 switch (legacy_output_format) {
1734 case LEGACY_OUTPUT_FORMAT_TEXT:
9987e1ac 1735 output_format = "text";
c42c79ea 1736 break;
c42c79ea 1737 case LEGACY_OUTPUT_FORMAT_DUMMY:
9987e1ac 1738 output_format = "dummy";
c42c79ea
PP
1739 break;
1740 default:
1741 assert(false);
1742 }
1743
49849a47 1744 printf_err("Both `%s` legacy output format and non-legacy sink component\ninstances(s) specified.\n\n",
9987e1ac 1745 output_format);
49849a47 1746 printf_err("Specify the following non-legacy sink component instance instead of the\nlegacy `%s` output format options:\n\n",
9987e1ac 1747 output_format);
c42c79ea
PP
1748 g_string_append(str, "-o ");
1749
1750 switch (legacy_output_format) {
1751 case LEGACY_OUTPUT_FORMAT_TEXT:
1752 g_string_append(str, "text.text");
1753 break;
c42c79ea 1754 case LEGACY_OUTPUT_FORMAT_DUMMY:
9987e1ac 1755 g_string_append(str, "utils.dummy");
c42c79ea
PP
1756 break;
1757 default:
1758 assert(false);
1759 }
1760
1761 if (legacy_output_format == LEGACY_OUTPUT_FORMAT_TEXT &&
1762 text_legacy_opts_is_any_set(text_legacy_opts)) {
1763 int ret;
1764
bdc61c70 1765 g_string_append(str, " -p '");
c42c79ea
PP
1766
1767 if (g_string_append_string_path_param(str, "output-path",
1768 text_legacy_opts->output)) {
1769 goto end;
1770 }
1771
1772 g_string_append(str, ",");
1773
1774 if (g_string_append_string_path_param(str, "debug-info-dir",
1775 text_legacy_opts->dbg_info_dir)) {
1776 goto end;
1777 }
1778
1779 g_string_append(str, ",");
1780
1781 if (g_string_append_string_path_param(str,
1782 "debug-info-target-prefix",
1783 text_legacy_opts->dbg_info_target_prefix)) {
1784 goto end;
1785 }
1786
1787 g_string_append_bool_param(str, "no-delta",
1788 text_legacy_opts->no_delta);
1789 g_string_append_bool_param(str, "clock-cycles",
1790 text_legacy_opts->clock_cycles);
1791 g_string_append_bool_param(str, "clock-seconds",
1792 text_legacy_opts->clock_seconds);
1793 g_string_append_bool_param(str, "clock-date",
1794 text_legacy_opts->clock_date);
1795 g_string_append_bool_param(str, "clock-gmt",
1796 text_legacy_opts->clock_gmt);
a263021c
JD
1797 g_string_append_bool_param(str, "verbose",
1798 text_legacy_opts->verbose);
c42c79ea
PP
1799 ret = append_prefixed_flag_params(str, text_legacy_opts->names,
1800 "name");
1801 if (ret) {
1802 goto end;
1803 }
1804
1805 ret = append_prefixed_flag_params(str, text_legacy_opts->fields,
1806 "field");
1807 if (ret) {
1808 goto end;
1809 }
1810
1811 /* Remove last comma and close single quote */
1812 g_string_append(str, "'");
1813 }
1814
1815 printf_err("%s\n\n", str->str);
1816
1817end:
1818 if (str) {
1819 g_string_free(str, TRUE);
1820 }
1821 return;
1822}
1823
1824/*
1825 * Prints the non-legacy source options equivalent to the specified
1826 * legacy input format options.
1827 */
1828static
1829void print_input_legacy_to_sources(enum legacy_input_format legacy_input_format,
1830 struct bt_value *legacy_input_paths,
1831 struct ctf_legacy_opts *ctf_legacy_opts)
1832{
1833 const char *input_format;
1834 GString *str = NULL;
1835 int i;
1836
1837 str = g_string_new(" ");
1838 if (!str) {
1839 print_err_oom();
1840 goto end;
1841 }
1842
1843 switch (legacy_input_format) {
1844 case LEGACY_INPUT_FORMAT_CTF:
1845 input_format = "ctf";
1846 break;
1847 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
1848 input_format = "lttng-live";
1849 break;
1850 default:
1851 assert(false);
1852 }
1853
49849a47 1854 printf_err("Both `%s` legacy input format and non-legacy source component\ninstance(s) specified.\n\n",
c42c79ea 1855 input_format);
49849a47 1856 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
1857 input_format);
1858
1859 for (i = 0; i < bt_value_array_size(legacy_input_paths); i++) {
1860 struct bt_value *input_value =
1861 bt_value_array_get(legacy_input_paths, i);
1862 const char *input = NULL;
1863 char *escaped_input;
1864 int ret;
1865
1866 assert(input_value);
1867 ret = bt_value_string_get(input_value, &input);
1868 BT_PUT(input_value);
1869 assert(!ret && input);
1870 escaped_input = str_shell_escape(input);
1871 if (!escaped_input) {
1872 print_err_oom();
1873 goto end;
1874 }
1875
1876 g_string_append(str, "-i ctf.");
1877
1878 switch (legacy_input_format) {
1879 case LEGACY_INPUT_FORMAT_CTF:
bdc61c70 1880 g_string_append(str, "fs -p 'path=\"");
c42c79ea
PP
1881 break;
1882 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
bdc61c70 1883 g_string_append(str, "lttng-live -p 'url=\"");
c42c79ea
PP
1884 break;
1885 default:
1886 assert(false);
1887 }
1888
1889 g_string_append(str, escaped_input);
1890 g_string_append(str, "\"");
1891 g_string_append_printf(str, ",offset-s=%" PRId64,
1892 ctf_legacy_opts->offset_s.value);
1893 g_string_append_printf(str, ",offset-ns=%" PRId64,
1894 ctf_legacy_opts->offset_ns.value);
1895 g_string_append_bool_param(str, "stream-intersection",
1896 ctf_legacy_opts->stream_intersection);
1897 g_string_append(str, "' ");
1898 g_free(escaped_input);
1899 }
1900
1901 printf_err("%s\n\n", str->str);
1902
1903end:
1904 if (str) {
1905 g_string_free(str, TRUE);
1906 }
1907 return;
1908}
1909
1910/*
1911 * Validates a given configuration, with optional legacy input and
1912 * output formats options. Prints useful error messages if anything
1913 * is wrong.
1914 *
1915 * Returns true when the configuration is valid.
1916 */
1917static
1918bool validate_cfg(struct bt_config *cfg,
1919 enum legacy_input_format *legacy_input_format,
1920 enum legacy_output_format *legacy_output_format,
1921 struct bt_value *legacy_input_paths,
1922 struct ctf_legacy_opts *ctf_legacy_opts,
bd9f0fa2 1923 struct text_legacy_opts *text_legacy_opts)
c42c79ea
PP
1924{
1925 bool legacy_input = false;
1926 bool legacy_output = false;
1927
1928 /* Determine if the input and output should be legacy-style */
05a67631
PP
1929 if (cfg->cmd_data.convert.print_ctf_metadata ||
1930 *legacy_input_format != LEGACY_INPUT_FORMAT_NONE ||
c42c79ea
PP
1931 !bt_value_array_is_empty(legacy_input_paths) ||
1932 ctf_legacy_opts_is_any_set(ctf_legacy_opts)) {
1933 legacy_input = true;
1934 }
1935
1936 if (*legacy_output_format != LEGACY_OUTPUT_FORMAT_NONE ||
c42c79ea
PP
1937 text_legacy_opts_is_any_set(text_legacy_opts)) {
1938 legacy_output = true;
1939 }
1940
1941 if (legacy_input) {
1942 /* If no legacy input format was specified, default to CTF */
1943 if (*legacy_input_format == LEGACY_INPUT_FORMAT_NONE) {
1944 *legacy_input_format = LEGACY_INPUT_FORMAT_CTF;
1945 }
1946
1947 /* Make sure at least one input path exists */
1948 if (bt_value_array_is_empty(legacy_input_paths)) {
1949 switch (*legacy_input_format) {
1950 case LEGACY_INPUT_FORMAT_CTF:
6d1d5711 1951 printf_err("No input path specified for legacy `ctf` input format\n");
c42c79ea
PP
1952 break;
1953 case LEGACY_INPUT_FORMAT_LTTNG_LIVE:
6d1d5711 1954 printf_err("No URL specified for legacy `lttng-live` input format\n");
c42c79ea
PP
1955 break;
1956 default:
1957 assert(false);
1958 }
1959 goto error;
1960 }
1961
1962 /* Make sure no non-legacy sources are specified */
290725f7 1963 if (cfg->cmd_data.convert.sources->len != 0) {
05a67631
PP
1964 if (cfg->cmd_data.convert.print_ctf_metadata) {
1965 printf_err("You cannot instantiate a source component with the `ctf-metadata` output format\n");
1966 } else {
1967 print_input_legacy_to_sources(
1968 *legacy_input_format,
1969 legacy_input_paths, ctf_legacy_opts);
1970 }
1971
c42c79ea
PP
1972 goto error;
1973 }
1974 }
1975
05a67631
PP
1976 /*
1977 * Strict rule: if we need to print the CTF metadata, the input
1978 * format must be legacy and CTF. Also there should be no
1979 * other sinks, and no legacy output format.
1980 */
1981 if (cfg->cmd_data.convert.print_ctf_metadata) {
1982 if (*legacy_input_format != LEGACY_INPUT_FORMAT_CTF) {
1983 printf_err("The `ctf-metadata` output format requires legacy `ctf` input format\n");
1984 goto error;
1985 }
1986
1987 if (bt_value_array_size(legacy_input_paths) != 1) {
1988 printf_err("You need to specify exactly one path with the `ctf-metadata` output format\n");
1989 goto error;
1990 }
1991
1992 if (legacy_output) {
1993 printf_err("You cannot use another legacy output format with the `ctf-metadata` output format\n");
1994 goto error;
1995 }
1996
1997 if (cfg->cmd_data.convert.sinks->len != 0) {
1998 printf_err("You cannot instantiate a sink component with the `ctf-metadata` output format\n");
1999 goto error;
2000 goto error;
2001 }
2002 } else if (legacy_output) {
c42c79ea
PP
2003 /*
2004 * If no legacy output format was specified, default to
2005 * "text".
2006 */
2007 if (*legacy_output_format == LEGACY_OUTPUT_FORMAT_NONE) {
2008 *legacy_output_format = LEGACY_OUTPUT_FORMAT_TEXT;
2009 }
2010
2011 /*
2012 * If any "text" option was specified, the output must be
2013 * legacy "text".
2014 */
2015 if (text_legacy_opts_is_any_set(text_legacy_opts) &&
2016 *legacy_output_format !=
2017 LEGACY_OUTPUT_FORMAT_TEXT) {
6d1d5711 2018 printf_err("Options for legacy `text` output format specified with a different legacy output format\n");
c42c79ea
PP
2019 goto error;
2020 }
2021
2022 /* Make sure no non-legacy sinks are specified */
290725f7 2023 if (cfg->cmd_data.convert.sinks->len != 0) {
c42c79ea
PP
2024 print_output_legacy_to_sinks(*legacy_output_format,
2025 text_legacy_opts);
2026 goto error;
2027 }
2028 }
2029
c42c79ea
PP
2030 return true;
2031
2032error:
2033 return false;
2034}
2035
2036/*
2037 * Parses a 64-bit signed integer.
2038 *
2039 * Returns a negative value if anything goes wrong.
2040 */
2041static
2042int parse_int64(const char *arg, int64_t *val)
2043{
2044 char *endptr;
2045
2046 errno = 0;
2047 *val = strtoll(arg, &endptr, 0);
2048 if (*endptr != '\0' || arg == endptr || errno != 0) {
2049 return -1;
2050 }
2051
2052 return 0;
2053}
2054
2055/* popt options */
2056enum {
2057 OPT_NONE = 0,
b07ffa28 2058 OPT_BASE_PARAMS,
0f9915c6 2059 OPT_BEGIN,
c42c79ea
PP
2060 OPT_CLOCK_CYCLES,
2061 OPT_CLOCK_DATE,
2062 OPT_CLOCK_FORCE_CORRELATE,
2063 OPT_CLOCK_GMT,
2064 OPT_CLOCK_OFFSET,
2065 OPT_CLOCK_OFFSET_NS,
2066 OPT_CLOCK_SECONDS,
ebba3338 2067 OPT_CONNECT,
c42c79ea
PP
2068 OPT_DEBUG,
2069 OPT_DEBUG_INFO_DIR,
2070 OPT_DEBUG_INFO_FULL_PATH,
2071 OPT_DEBUG_INFO_TARGET_PREFIX,
0f9915c6 2072 OPT_END,
c42c79ea 2073 OPT_FIELDS,
22e22462 2074 OPT_FILTER,
c42c79ea 2075 OPT_HELP,
c42c79ea
PP
2076 OPT_INPUT_FORMAT,
2077 OPT_LIST,
3b6cfcc5 2078 OPT_NAME,
c42c79ea
PP
2079 OPT_NAMES,
2080 OPT_NO_DELTA,
290725f7
PP
2081 OPT_OMIT_HOME_PLUGIN_PATH,
2082 OPT_OMIT_SYSTEM_PLUGIN_PATH,
c42c79ea
PP
2083 OPT_OUTPUT_FORMAT,
2084 OPT_OUTPUT_PATH,
bdc61c70 2085 OPT_PARAMS,
290725f7 2086 OPT_PATH,
c42c79ea 2087 OPT_PLUGIN_PATH,
b07ffa28 2088 OPT_RESET_BASE_PARAMS,
c42c79ea
PP
2089 OPT_SINK,
2090 OPT_SOURCE,
2091 OPT_STREAM_INTERSECTION,
0f9915c6 2092 OPT_TIMERANGE,
c42c79ea 2093 OPT_VERBOSE,
c42c79ea
PP
2094};
2095
2096/*
2097 * Sets the value of a given legacy offset option and marks it as set.
2098 */
2099static void set_offset_value(struct offset_opt *offset_opt, int64_t value)
2100{
2101 offset_opt->value = value;
2102 offset_opt->is_set = true;
2103}
2104
bdc61c70
PP
2105enum bt_config_component_dest {
2106 BT_CONFIG_COMPONENT_DEST_SOURCE,
355b476b 2107 BT_CONFIG_COMPONENT_DEST_FILTER,
bdc61c70
PP
2108 BT_CONFIG_COMPONENT_DEST_SINK,
2109};
2110
2111/*
2112 * Adds a configuration component to the appropriate configuration
2113 * array depending on the destination.
2114 */
2115static void add_cfg_comp(struct bt_config *cfg,
2116 struct bt_config_component *cfg_comp,
2117 enum bt_config_component_dest dest)
2118{
355b476b
PP
2119 switch (dest) {
2120 case BT_CONFIG_COMPONENT_DEST_SOURCE:
290725f7 2121 g_ptr_array_add(cfg->cmd_data.convert.sources, cfg_comp);
355b476b
PP
2122 break;
2123 case BT_CONFIG_COMPONENT_DEST_FILTER:
2124 g_ptr_array_add(cfg->cmd_data.convert.filters, cfg_comp);
2125 break;
2126 case BT_CONFIG_COMPONENT_DEST_SINK:
290725f7 2127 g_ptr_array_add(cfg->cmd_data.convert.sinks, cfg_comp);
355b476b
PP
2128 break;
2129 default:
2130 assert(false);
bdc61c70
PP
2131 }
2132}
2133
0f9915c6
MD
2134static int split_timerange(const char *arg, const char **begin, const char **end)
2135{
2136 const char *c;
2137
2138 /* Try to match [begin,end] */
2139 c = strchr(arg, '[');
2140 if (!c)
2141 goto skip;
2142 *begin = ++c;
2143 c = strchr(c, ',');
2144 if (!c)
2145 goto skip;
2146 *end = ++c;
2147 c = strchr(c, ']');
2148 if (!c)
2149 goto skip;
2150 goto found;
2151
2152skip:
2153 /* Try to match begin,end */
2154 c = arg;
2155 *begin = c;
2156 c = strchr(c, ',');
2157 if (!c)
2158 goto not_found;
2159 *end = ++c;
2160 /* fall-through */
2161found:
2162 return 0;
2163not_found:
2164 return -1;
2165}
2166
290725f7 2167static int append_env_var_plugin_paths(struct bt_value *plugin_paths)
5a3ee633
PP
2168{
2169 int ret = 0;
2170 const char *envvar;
2171
2172 if (bt_common_is_setuid_setgid()) {
2173 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2174 goto end;
2175 }
2176
2177 envvar = getenv("BABELTRACE_PLUGIN_PATH");
2178 if (!envvar) {
2179 goto end;
2180 }
2181
290725f7 2182 ret = bt_config_append_plugin_paths(plugin_paths, envvar);
5a3ee633
PP
2183
2184end:
2185 return ret;
2186}
2187
290725f7
PP
2188static int append_home_and_system_plugin_paths(struct bt_value *plugin_paths,
2189 bool omit_system_plugin_path, bool omit_home_plugin_path)
98ecef32 2190{
1670bffd 2191 int ret;
98ecef32 2192
290725f7 2193 if (!omit_home_plugin_path) {
1670bffd 2194 if (bt_common_is_setuid_setgid()) {
5a3ee633 2195 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
98ecef32 2196 } else {
1670bffd
PP
2197 char *home_plugin_dir =
2198 bt_common_get_home_plugin_path();
2199
2200 if (home_plugin_dir) {
290725f7
PP
2201 ret = bt_config_append_plugin_paths(
2202 plugin_paths,
1670bffd
PP
2203 home_plugin_dir);
2204 free(home_plugin_dir);
2205
2206 if (ret) {
98ecef32
MD
2207 printf_err("Invalid home plugin path\n");
2208 goto error;
2209 }
2210 }
2211 }
2212 }
2213
290725f7
PP
2214 if (!omit_system_plugin_path) {
2215 if (bt_config_append_plugin_paths(plugin_paths,
1670bffd 2216 bt_common_get_system_plugin_path())) {
98ecef32
MD
2217 printf_err("Invalid system plugin path\n");
2218 goto error;
2219 }
2220 }
2221 return 0;
2222error:
2223 return -1;
2224}
2225
bd9f0fa2
MD
2226static int append_sources_from_implicit_params(GPtrArray *sources,
2227 struct bt_config_component *implicit_source_comp)
2228{
2229 size_t i;
2230 size_t len = sources->len;
2231
2232 for (i = 0; i < len; i++) {
2233 struct bt_config_component *comp;
2234 struct bt_value *params_to_set;
2235
2236 comp = g_ptr_array_index(sources, i);
2237 params_to_set = bt_value_map_extend(comp->params,
2238 implicit_source_comp->params);
2239 if (!params_to_set) {
2240 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2241 goto error;
2242 }
2243 BT_MOVE(comp->params, params_to_set);
2244 }
2245 return 0;
2246error:
2247 return -1;
2248}
2249
290725f7 2250static struct bt_config *bt_config_base_create(enum bt_config_command command)
c1870f57
JG
2251{
2252 struct bt_config *cfg;
2253
2254 /* Create config */
2255 cfg = g_new0(struct bt_config, 1);
2256 if (!cfg) {
2257 print_err_oom();
2258 goto error;
2259 }
2260
2261 bt_object_init(cfg, bt_config_destroy);
290725f7
PP
2262 cfg->command = command;
2263 goto end;
c1870f57 2264
290725f7
PP
2265error:
2266 BT_PUT(cfg);
c1870f57 2267
c1870f57
JG
2268end:
2269 return cfg;
c1870f57
JG
2270}
2271
290725f7
PP
2272static struct bt_config *bt_config_convert_create(
2273 struct bt_value *initial_plugin_paths)
c42c79ea 2274{
290725f7 2275 struct bt_config *cfg;
c42c79ea 2276
290725f7
PP
2277 /* Create config */
2278 cfg = bt_config_base_create(BT_CONFIG_COMMAND_CONVERT);
2279 if (!cfg) {
c42c79ea
PP
2280 print_err_oom();
2281 goto error;
2282 }
2283
290725f7
PP
2284 cfg->cmd_data.convert.sources = g_ptr_array_new_with_free_func(
2285 (GDestroyNotify) bt_put);
2286 if (!cfg->cmd_data.convert.sources) {
c42c79ea
PP
2287 print_err_oom();
2288 goto error;
2289 }
2290
ebba3338
PP
2291 cfg->cmd_data.convert.filters = g_ptr_array_new_with_free_func(
2292 (GDestroyNotify) bt_put);
2293 if (!cfg->cmd_data.convert.filters) {
2294 print_err_oom();
2295 goto error;
2296 }
2297
290725f7
PP
2298 cfg->cmd_data.convert.sinks = g_ptr_array_new_with_free_func(
2299 (GDestroyNotify) bt_put);
2300 if (!cfg->cmd_data.convert.sinks) {
c42c79ea
PP
2301 print_err_oom();
2302 goto error;
2303 }
2304
ebba3338
PP
2305 cfg->cmd_data.convert.connections = g_ptr_array_new_with_free_func(
2306 (GDestroyNotify) bt_config_connection_destroy);
2307 if (!cfg->cmd_data.convert.connections) {
2308 print_err_oom();
2309 goto error;
2310 }
2311
290725f7
PP
2312 if (initial_plugin_paths) {
2313 cfg->cmd_data.convert.plugin_paths =
2314 bt_get(initial_plugin_paths);
2315 } else {
2316 cfg->cmd_data.convert.plugin_paths = bt_value_array_create();
2317 if (!cfg->cmd_data.convert.plugin_paths) {
2318 print_err_oom();
2319 goto error;
2320 }
b07ffa28
PP
2321 }
2322
290725f7 2323 goto end;
c42c79ea 2324
290725f7
PP
2325error:
2326 BT_PUT(cfg);
2327
2328end:
2329 return cfg;
2330}
2331
2332static struct bt_config *bt_config_list_plugins_create(
2333 struct bt_value *initial_plugin_paths)
2334{
2335 struct bt_config *cfg;
2336
2337 /* Create config */
2338 cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS);
2339 if (!cfg) {
2340 print_err_oom();
5a3ee633
PP
2341 goto error;
2342 }
2343
290725f7
PP
2344 if (initial_plugin_paths) {
2345 cfg->cmd_data.list_plugins.plugin_paths =
2346 bt_get(initial_plugin_paths);
65582340 2347 } else {
290725f7
PP
2348 cfg->cmd_data.list_plugins.plugin_paths =
2349 bt_value_array_create();
2350 if (!cfg->cmd_data.list_plugins.plugin_paths) {
2351 print_err_oom();
2352 goto error;
2353 }
c42c79ea
PP
2354 }
2355
290725f7
PP
2356 goto end;
2357
2358error:
2359 BT_PUT(cfg);
2360
2361end:
2362 return cfg;
2363}
2364
22e22462
PP
2365static struct bt_config *bt_config_help_create(
2366 struct bt_value *initial_plugin_paths)
2367{
2368 struct bt_config *cfg;
2369
2370 /* Create config */
2371 cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP);
2372 if (!cfg) {
2373 print_err_oom();
2374 goto error;
2375 }
2376
2377 if (initial_plugin_paths) {
2378 cfg->cmd_data.help.plugin_paths =
2379 bt_get(initial_plugin_paths);
2380 } else {
2381 cfg->cmd_data.help.plugin_paths =
2382 bt_value_array_create();
2383 if (!cfg->cmd_data.help.plugin_paths) {
2384 print_err_oom();
2385 goto error;
2386 }
2387 }
2388
90de159b
PP
2389 cfg->cmd_data.help.cfg_component =
2390 bt_config_component_create(BT_COMPONENT_CLASS_TYPE_UNKNOWN,
2391 NULL, NULL);
2392 if (!cfg->cmd_data.help.cfg_component) {
22e22462
PP
2393 print_err_oom();
2394 goto error;
2395 }
2396
2397 goto end;
2398
2399error:
2400 BT_PUT(cfg);
2401
2402end:
2403 return cfg;
2404}
2405
a67681c1 2406static struct bt_config *bt_config_query_create(
63ce0e1d
PP
2407 struct bt_value *initial_plugin_paths)
2408{
2409 struct bt_config *cfg;
2410
2411 /* Create config */
a67681c1 2412 cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY);
63ce0e1d
PP
2413 if (!cfg) {
2414 print_err_oom();
2415 goto error;
2416 }
2417
2418 if (initial_plugin_paths) {
a67681c1 2419 cfg->cmd_data.query.plugin_paths =
63ce0e1d
PP
2420 bt_get(initial_plugin_paths);
2421 } else {
a67681c1 2422 cfg->cmd_data.query.plugin_paths =
63ce0e1d 2423 bt_value_array_create();
a67681c1 2424 if (!cfg->cmd_data.query.plugin_paths) {
63ce0e1d
PP
2425 print_err_oom();
2426 goto error;
2427 }
2428 }
2429
a67681c1
PP
2430 cfg->cmd_data.query.object = g_string_new(NULL);
2431 if (!cfg->cmd_data.query.object) {
63ce0e1d
PP
2432 print_err_oom();
2433 goto error;
2434 }
2435
2436 goto end;
2437
2438error:
2439 BT_PUT(cfg);
2440
2441end:
2442 return cfg;
2443}
2444
2445/*
2446 * Prints the expected format for a --params option.
2447 */
2448static
2449void print_expected_params_format(FILE *fp)
2450{
2451 fprintf(fp, "Expected format of PARAMS\n");
2452 fprintf(fp, "-------------------------\n");
2453 fprintf(fp, "\n");
2454 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
2455 fprintf(fp, "\n");
2456 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
2457 fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
2458 fprintf(fp, "VALUE can be one of:\n");
2459 fprintf(fp, "\n");
2460 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
2461 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
2462 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
2463 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
2464 fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n");
2465 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
2466 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
2467 fprintf(fp, " the null and boolean value symbols above.\n");
2468 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
2469 fprintf(fp, "\n");
2470 fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
2471 fprintf(fp, "\n");
2472 fprintf(fp, "Example:\n");
2473 fprintf(fp, "\n");
2474 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
2475 fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
2476 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
2477 fprintf(fp, "\n");
2478 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
2479 fprintf(fp, "from a shell.\n");
2480}
2481
2482
22e22462
PP
2483/*
2484 * Prints the help command usage.
2485 */
2486static
2487void print_help_usage(FILE *fp)
2488{
2489 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
63ce0e1d
PP
2490 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source=PLUGIN.COMPCLS\n");
2491 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter=PLUGIN.COMPCLS\n");
2492 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink=PLUGIN.COMPCLS\n");
22e22462
PP
2493 fprintf(fp, "\n");
2494 fprintf(fp, "Options:\n");
2495 fprintf(fp, "\n");
2496 fprintf(fp, " --filter=PLUGIN.COMPCLS Get help for the filter component class\n");
2497 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2498 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2499 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2500 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2501 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2502 fprintf(fp, " dynamic plugins can be loaded\n");
2503 fprintf(fp, " --sink=PLUGIN.COMPCLS Get help for the sink component class\n");
2504 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2505 fprintf(fp, " --source=PLUGIN.COMPCLS Get help for the source component class\n");
2506 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2507 fprintf(fp, " -h --help Show this help and quit\n");
2508 fprintf(fp, "\n");
2509 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
2510 fprintf(fp, "\n");
2511 fprintf(fp, "Use `babeltrace list-plugins` to show the list of available plugins.\n");
2512}
2513
2514static struct poptOption help_long_options[] = {
2515 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2516 { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, NULL, NULL },
2517 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2518 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2519 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2520 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2521 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2522 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2523 { NULL, 0, 0, NULL, 0, NULL, NULL },
2524};
2525
2526/*
2527 * Creates a Babeltrace config object from the arguments of a help
2528 * command.
2529 *
2530 * *retcode is set to the appropriate exit code to use.
2531 */
2532struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
2533 int *retcode, bool omit_system_plugin_path,
2534 bool omit_home_plugin_path,
2535 struct bt_value *initial_plugin_paths)
2536{
2537 poptContext pc = NULL;
2538 char *arg = NULL;
2539 int opt;
2540 int ret;
2541 struct bt_config *cfg = NULL;
2542 const char *leftover;
2543 char *plugin_name = NULL, *component_name = NULL;
2544 char *plugin_comp_cls_names = NULL;
2545
2546 *retcode = 0;
2547 cfg = bt_config_help_create(initial_plugin_paths);
2548 if (!cfg) {
2549 print_err_oom();
2550 goto error;
2551 }
2552
22e22462
PP
2553 cfg->cmd_data.help.omit_system_plugin_path = omit_system_plugin_path;
2554 cfg->cmd_data.help.omit_home_plugin_path = omit_home_plugin_path;
2555 ret = append_env_var_plugin_paths(cfg->cmd_data.help.plugin_paths);
2556 if (ret) {
2557 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2558 goto error;
2559 }
2560
2561 /* Parse options */
2562 pc = poptGetContext(NULL, argc, (const char **) argv,
2563 help_long_options, 0);
2564 if (!pc) {
2565 printf_err("Cannot get popt context\n");
2566 goto error;
2567 }
2568
2569 poptReadDefaultConfig(pc, 0);
2570
2571 while ((opt = poptGetNextOpt(pc)) > 0) {
2572 arg = poptGetOptArg(pc);
2573
2574 switch (opt) {
2575 case OPT_PLUGIN_PATH:
2576 if (bt_common_is_setuid_setgid()) {
2577 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2578 } else {
2579 if (bt_config_append_plugin_paths(
2580 cfg->cmd_data.help.plugin_paths,
2581 arg)) {
2582 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2583 arg);
2584 goto error;
2585 }
2586 }
2587 break;
2588 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
2589 cfg->cmd_data.help.omit_system_plugin_path = true;
2590 break;
2591 case OPT_OMIT_HOME_PLUGIN_PATH:
2592 cfg->cmd_data.help.omit_home_plugin_path = true;
2593 break;
2594 case OPT_SOURCE:
2595 case OPT_FILTER:
2596 case OPT_SINK:
90de159b 2597 if (cfg->cmd_data.help.cfg_component->type !=
22e22462
PP
2598 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2599 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2600 arg);
2601 goto error;
2602 }
2603
2604 switch (opt) {
2605 case OPT_SOURCE:
90de159b 2606 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2607 BT_COMPONENT_CLASS_TYPE_SOURCE;
2608 break;
2609 case OPT_FILTER:
90de159b 2610 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2611 BT_COMPONENT_CLASS_TYPE_FILTER;
2612 break;
2613 case OPT_SINK:
90de159b 2614 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2615 BT_COMPONENT_CLASS_TYPE_SINK;
2616 break;
2617 default:
2618 assert(false);
2619 }
2620 plugin_comp_cls_names = strdup(arg);
2621 if (!plugin_comp_cls_names) {
2622 print_err_oom();
2623 goto error;
2624 }
2625 break;
2626 case OPT_HELP:
2627 print_help_usage(stdout);
2628 *retcode = -1;
2629 BT_PUT(cfg);
2630 goto end;
2631 default:
2632 printf_err("Unknown command-line option specified (option code %d)\n",
2633 opt);
2634 goto error;
2635 }
2636
2637 free(arg);
2638 arg = NULL;
2639 }
2640
2641 /* Check for option parsing error */
2642 if (opt < -1) {
2643 printf_err("While parsing command-line options, at option %s: %s\n",
2644 poptBadOption(pc, 0), poptStrerror(opt));
2645 goto error;
2646 }
2647
2648 leftover = poptGetArg(pc);
2649 if (leftover) {
90de159b 2650 if (cfg->cmd_data.help.cfg_component->type !=
22e22462
PP
2651 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2652 printf_err("Cannot specify plugin name and --source/--filter/--sink component class:\n %s\n",
2653 leftover);
2654 goto error;
2655 }
2656
90de159b
PP
2657 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
2658 leftover);
22e22462 2659 } else {
90de159b 2660 if (cfg->cmd_data.help.cfg_component->type ==
22e22462
PP
2661 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2662 print_help_usage(stdout);
2663 *retcode = -1;
2664 BT_PUT(cfg);
2665 goto end;
2666 }
2667
2668 plugin_component_names_from_arg(plugin_comp_cls_names,
2669 &plugin_name, &component_name);
2670 if (plugin_name && component_name) {
90de159b
PP
2671 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
2672 plugin_name);
2673 g_string_assign(cfg->cmd_data.help.cfg_component->component_name,
22e22462
PP
2674 component_name);
2675 } else {
2676 printf_err("Invalid --source/--filter/--sink option's argument:\n %s\n",
2677 plugin_comp_cls_names);
2678 goto error;
2679 }
2680 }
2681
2682 if (append_home_and_system_plugin_paths(
2683 cfg->cmd_data.help.plugin_paths,
2684 cfg->cmd_data.help.omit_system_plugin_path,
2685 cfg->cmd_data.help.omit_home_plugin_path)) {
2686 printf_err("Cannot append home and system plugin paths\n");
2687 goto error;
2688 }
2689
2690 goto end;
2691
2692error:
2693 *retcode = 1;
2694 BT_PUT(cfg);
2695
2696end:
2697 free(plugin_comp_cls_names);
2698 g_free(plugin_name);
2699 g_free(component_name);
2700
2701 if (pc) {
2702 poptFreeContext(pc);
2703 }
2704
2705 free(arg);
2706 return cfg;
2707}
2708
63ce0e1d
PP
2709/*
2710 * Prints the help command usage.
2711 */
2712static
a67681c1 2713void print_query_usage(FILE *fp)
63ce0e1d 2714{
a67681c1
PP
2715 fprintf(fp, "Usage: babeltrace [GEN OPTS] query [OPTS] OBJECT --source=PLUGIN.COMPCLS\n");
2716 fprintf(fp, " babeltrace [GEN OPTS] query [OPTS] OBJECT --filter=PLUGIN.COMPCLS\n");
2717 fprintf(fp, " babeltrace [GEN OPTS] query [OPTS] OBJECT --sink=PLUGIN.COMPCLS\n");
63ce0e1d
PP
2718 fprintf(fp, "\n");
2719 fprintf(fp, "Options:\n");
2720 fprintf(fp, "\n");
a67681c1
PP
2721 fprintf(fp, " --filter=PLUGIN.COMPCLS Query object from the filter component\n");
2722 fprintf(fp, " class COMPCLS found in the plugin PLUGIN\n");
63ce0e1d
PP
2723 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2724 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2725 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2726 fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS\n");
2727 fprintf(fp, " (see the expected format of PARAMS below)\n");
2728 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2729 fprintf(fp, " dynamic plugins can be loaded\n");
a67681c1 2730 fprintf(fp, " --sink=PLUGIN.COMPCLS Query object from the sink component class\n");
63ce0e1d 2731 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
a67681c1
PP
2732 fprintf(fp, " --source=PLUGIN.COMPCLS Query object from the source component\n");
2733 fprintf(fp, " class COMPCLS found in the plugin PLUGIN\n");
63ce0e1d
PP
2734 fprintf(fp, " -h --help Show this help and quit\n");
2735 fprintf(fp, "\n\n");
2736 print_expected_params_format(fp);
2737}
2738
a67681c1 2739static struct poptOption query_long_options[] = {
63ce0e1d
PP
2740 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2741 { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, NULL, NULL },
2742 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2743 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2744 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2745 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
2746 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2747 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2748 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2749 { NULL, 0, 0, NULL, 0, NULL, NULL },
2750};
2751
2752/*
a67681c1 2753 * Creates a Babeltrace config object from the arguments of a query
63ce0e1d
PP
2754 * command.
2755 *
2756 * *retcode is set to the appropriate exit code to use.
2757 */
a67681c1 2758struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
63ce0e1d
PP
2759 int *retcode, bool omit_system_plugin_path,
2760 bool omit_home_plugin_path,
2761 struct bt_value *initial_plugin_paths)
2762{
2763 poptContext pc = NULL;
2764 char *arg = NULL;
2765 int opt;
2766 int ret;
2767 struct bt_config *cfg = NULL;
2768 const char *leftover;
2769 struct bt_value *params = bt_value_null;
2770
2771 *retcode = 0;
a67681c1 2772 cfg = bt_config_query_create(initial_plugin_paths);
63ce0e1d
PP
2773 if (!cfg) {
2774 print_err_oom();
2775 goto error;
2776 }
2777
a67681c1 2778 cfg->cmd_data.query.omit_system_plugin_path =
63ce0e1d 2779 omit_system_plugin_path;
a67681c1
PP
2780 cfg->cmd_data.query.omit_home_plugin_path = omit_home_plugin_path;
2781 ret = append_env_var_plugin_paths(cfg->cmd_data.query.plugin_paths);
63ce0e1d
PP
2782 if (ret) {
2783 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2784 goto error;
2785 }
2786
2787 /* Parse options */
2788 pc = poptGetContext(NULL, argc, (const char **) argv,
a67681c1 2789 query_long_options, 0);
63ce0e1d
PP
2790 if (!pc) {
2791 printf_err("Cannot get popt context\n");
2792 goto error;
2793 }
2794
2795 poptReadDefaultConfig(pc, 0);
2796
2797 while ((opt = poptGetNextOpt(pc)) > 0) {
2798 arg = poptGetOptArg(pc);
2799
2800 switch (opt) {
2801 case OPT_PLUGIN_PATH:
2802 if (bt_common_is_setuid_setgid()) {
2803 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2804 } else {
2805 if (bt_config_append_plugin_paths(
a67681c1 2806 cfg->cmd_data.query.plugin_paths,
63ce0e1d
PP
2807 arg)) {
2808 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2809 arg);
2810 goto error;
2811 }
2812 }
2813 break;
2814 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
a67681c1 2815 cfg->cmd_data.query.omit_system_plugin_path = true;
63ce0e1d
PP
2816 break;
2817 case OPT_OMIT_HOME_PLUGIN_PATH:
a67681c1 2818 cfg->cmd_data.query.omit_home_plugin_path = true;
63ce0e1d
PP
2819 break;
2820 case OPT_SOURCE:
2821 case OPT_FILTER:
2822 case OPT_SINK:
2823 {
2824 enum bt_component_class_type type;
2825
a67681c1 2826 if (cfg->cmd_data.query.cfg_component) {
63ce0e1d
PP
2827 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2828 arg);
2829 goto error;
2830 }
2831
2832 switch (opt) {
2833 case OPT_SOURCE:
2834 type = BT_COMPONENT_CLASS_TYPE_SOURCE;
2835 break;
2836 case OPT_FILTER:
2837 type = BT_COMPONENT_CLASS_TYPE_FILTER;
2838 break;
2839 case OPT_SINK:
2840 type = BT_COMPONENT_CLASS_TYPE_SINK;
2841 break;
2842 default:
2843 assert(false);
2844 }
2845
a67681c1 2846 cfg->cmd_data.query.cfg_component =
63ce0e1d 2847 bt_config_component_from_arg(type, arg);
a67681c1 2848 if (!cfg->cmd_data.query.cfg_component) {
63ce0e1d
PP
2849 printf_err("Invalid format for --source/--filter/--sink option's argument:\n %s\n",
2850 arg);
2851 goto error;
2852 }
2853
2854 /* Default parameters: null */
a67681c1
PP
2855 bt_put(cfg->cmd_data.query.cfg_component->params);
2856 cfg->cmd_data.query.cfg_component->params =
63ce0e1d
PP
2857 bt_value_null;
2858 break;
2859 }
2860 case OPT_PARAMS:
2861 {
2862 params = bt_value_from_arg(arg);
2863 if (!params) {
2864 printf_err("Invalid format for --params option's argument:\n %s\n",
2865 arg);
2866 goto error;
2867 }
2868 break;
2869 }
2870 case OPT_HELP:
a67681c1 2871 print_query_usage(stdout);
63ce0e1d
PP
2872 *retcode = -1;
2873 BT_PUT(cfg);
2874 goto end;
2875 default:
2876 printf_err("Unknown command-line option specified (option code %d)\n",
2877 opt);
2878 goto error;
2879 }
2880
2881 free(arg);
2882 arg = NULL;
2883 }
2884
a67681c1 2885 if (!cfg->cmd_data.query.cfg_component) {
63ce0e1d
PP
2886 printf_err("No target component class specified with --source/--filter/--sink option\n");
2887 goto error;
2888 }
2889
2890 assert(params);
a67681c1 2891 BT_MOVE(cfg->cmd_data.query.cfg_component->params, params);
63ce0e1d
PP
2892
2893 /* Check for option parsing error */
2894 if (opt < -1) {
2895 printf_err("While parsing command-line options, at option %s: %s\n",
2896 poptBadOption(pc, 0), poptStrerror(opt));
2897 goto error;
2898 }
2899
2900 /*
2901 * We need exactly one leftover argument which is the
a67681c1 2902 * mandatory object.
63ce0e1d
PP
2903 */
2904 leftover = poptGetArg(pc);
2905 if (leftover) {
2906 if (strlen(leftover) == 0) {
a67681c1 2907 printf_err("Invalid empty object\n");
63ce0e1d
PP
2908 goto error;
2909 }
2910
a67681c1 2911 g_string_assign(cfg->cmd_data.query.object, leftover);
63ce0e1d 2912 } else {
a67681c1 2913 print_query_usage(stdout);
63ce0e1d
PP
2914 *retcode = -1;
2915 BT_PUT(cfg);
2916 goto end;
2917 }
2918
2919 leftover = poptGetArg(pc);
2920 if (leftover) {
2921 printf_err("Invalid argument: %s\n", leftover);
2922 goto error;
2923 }
2924
2925 if (append_home_and_system_plugin_paths(
a67681c1
PP
2926 cfg->cmd_data.query.plugin_paths,
2927 cfg->cmd_data.query.omit_system_plugin_path,
2928 cfg->cmd_data.query.omit_home_plugin_path)) {
63ce0e1d
PP
2929 printf_err("Cannot append home and system plugin paths\n");
2930 goto error;
2931 }
2932
2933 goto end;
2934
2935error:
2936 *retcode = 1;
2937 BT_PUT(cfg);
2938
2939end:
2940 if (pc) {
2941 poptFreeContext(pc);
2942 }
2943
2944 BT_PUT(params);
2945 free(arg);
2946 return cfg;
2947}
2948
290725f7
PP
2949/*
2950 * Prints the list-plugins command usage.
2951 */
2952static
2953void print_list_plugins_usage(FILE *fp)
2954{
2955 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
2956 fprintf(fp, "\n");
2957 fprintf(fp, "Options:\n");
2958 fprintf(fp, "\n");
2959 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2960 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2961 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2962 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2963 fprintf(fp, " dynamic plugins can be loaded\n");
2964 fprintf(fp, " -h --help Show this help and quit\n");
2965 fprintf(fp, "\n");
2966 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
22e22462
PP
2967 fprintf(fp, "\n");
2968 fprintf(fp, "Use `babeltrace help` to get help for a specific plugin or component class.\n");
290725f7
PP
2969}
2970
2971static struct poptOption list_plugins_long_options[] = {
2972 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2973 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2974 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2975 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2976 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2977 { NULL, 0, 0, NULL, 0, NULL, NULL },
2978};
2979
2980/*
2981 * Creates a Babeltrace config object from the arguments of a
2982 * list-plugins command.
2983 *
2984 * *retcode is set to the appropriate exit code to use.
2985 */
2986struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
2987 int *retcode, bool omit_system_plugin_path,
2988 bool omit_home_plugin_path,
2989 struct bt_value *initial_plugin_paths)
2990{
2991 poptContext pc = NULL;
2992 char *arg = NULL;
2993 int opt;
2994 int ret;
2995 struct bt_config *cfg = NULL;
2996 const char *leftover;
2997
2998 *retcode = 0;
2999 cfg = bt_config_list_plugins_create(initial_plugin_paths);
3000 if (!cfg) {
3001 print_err_oom();
3002 goto error;
3003 }
3004
3005 cfg->cmd_data.list_plugins.omit_system_plugin_path = omit_system_plugin_path;
3006 cfg->cmd_data.list_plugins.omit_home_plugin_path = omit_home_plugin_path;
3007 ret = append_env_var_plugin_paths(
3008 cfg->cmd_data.list_plugins.plugin_paths);
3009 if (ret) {
3010 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3011 goto error;
3012 }
3013
3014 /* Parse options */
3015 pc = poptGetContext(NULL, argc, (const char **) argv,
3016 list_plugins_long_options, 0);
3017 if (!pc) {
3018 printf_err("Cannot get popt context\n");
3019 goto error;
3020 }
3021
3022 poptReadDefaultConfig(pc, 0);
c42c79ea
PP
3023
3024 while ((opt = poptGetNextOpt(pc)) > 0) {
3025 arg = poptGetOptArg(pc);
3026
3027 switch (opt) {
3028 case OPT_PLUGIN_PATH:
5a3ee633
PP
3029 if (bt_common_is_setuid_setgid()) {
3030 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
98ecef32 3031 } else {
290725f7
PP
3032 if (bt_config_append_plugin_paths(
3033 cfg->cmd_data.list_plugins.plugin_paths,
3034 arg)) {
2703153b
PP
3035 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3036 arg);
98ecef32
MD
3037 goto error;
3038 }
c42c79ea
PP
3039 }
3040 break;
98ecef32 3041 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
290725f7 3042 cfg->cmd_data.list_plugins.omit_system_plugin_path = true;
98ecef32
MD
3043 break;
3044 case OPT_OMIT_HOME_PLUGIN_PATH:
290725f7
PP
3045 cfg->cmd_data.list_plugins.omit_home_plugin_path = true;
3046 break;
3047 case OPT_HELP:
3048 print_list_plugins_usage(stdout);
3049 *retcode = -1;
3050 BT_PUT(cfg);
3051 goto end;
3052 default:
3053 printf_err("Unknown command-line option specified (option code %d)\n",
3054 opt);
3055 goto error;
3056 }
3057
3058 free(arg);
3059 arg = NULL;
3060 }
3061
3062 /* Check for option parsing error */
3063 if (opt < -1) {
3064 printf_err("While parsing command-line options, at option %s: %s\n",
3065 poptBadOption(pc, 0), poptStrerror(opt));
3066 goto error;
3067 }
3068
3069 leftover = poptGetArg(pc);
3070 if (leftover) {
3071 printf_err("Invalid argument: %s\n", leftover);
3072 goto error;
3073 }
3074
3075 if (append_home_and_system_plugin_paths(
3076 cfg->cmd_data.list_plugins.plugin_paths,
3077 cfg->cmd_data.list_plugins.omit_system_plugin_path,
3078 cfg->cmd_data.list_plugins.omit_home_plugin_path)) {
3079 printf_err("Cannot append home and system plugin paths\n");
3080 goto error;
3081 }
3082
3083 goto end;
3084
3085error:
3086 *retcode = 1;
3087 BT_PUT(cfg);
3088
3089end:
3090 if (pc) {
3091 poptFreeContext(pc);
3092 }
3093
3094 free(arg);
3095 return cfg;
3096}
3097
290725f7
PP
3098/*
3099 * Prints the legacy, Babeltrace 1.x command usage. Those options are
3100 * still compatible in Babeltrace 2.x, but it is recommended to use
3101 * the more generic plugin/component parameters instead of those
3102 * hard-coded option names.
3103 */
3104static
3105void print_legacy_usage(FILE *fp)
3106{
3107 fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
3108 fprintf(fp, "\n");
3109 fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
3110 fprintf(fp, "\n");
3111 fprintf(fp, " --clock-force-correlate Assume that clocks are inherently correlated\n");
3112 fprintf(fp, " across traces\n");
3113 fprintf(fp, " -d, --debug Enable debug mode\n");
3114 fprintf(fp, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
3115 fprintf(fp, " -l, --list List available formats\n");
3116 fprintf(fp, " -o, --output-format=FORMAT Output trace format (default: text)\n");
3117 fprintf(fp, " -v, --verbose Enable verbose output\n");
3118 fprintf(fp, " --help-legacy Show this help and quit\n");
3119 fprintf(fp, " -V, --version Show version and quit\n");
3120 fprintf(fp, "\n");
3121 fprintf(fp, " Available input formats: ctf, lttng-live, ctf-metadata\n");
3122 fprintf(fp, " Available output formats: text, dummy\n");
3123 fprintf(fp, "\n");
3124 fprintf(fp, "Input formats specific options:\n");
3125 fprintf(fp, "\n");
3126 fprintf(fp, " INPUT... Input trace file(s), directory(ies), or URLs\n");
3127 fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n");
3128 fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
3129 fprintf(fp, " --stream-intersection Only process events when all streams are active\n");
3130 fprintf(fp, "\n");
3131 fprintf(fp, "text output format specific options:\n");
3132 fprintf(fp, " \n");
3133 fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n");
3134 fprintf(fp, " --clock-date Print timestamp dates\n");
3135 fprintf(fp, " --clock-gmt Print and parse timestamps in GMT time zone\n");
3136 fprintf(fp, " (default: local time zone)\n");
3137 fprintf(fp, " --clock-seconds Print the timestamps as [SEC.NS]\n");
3138 fprintf(fp, " (default format: [HH:MM:SS.NS])\n");
3139 fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
3140 fprintf(fp, " (default: `/usr/lib/debug`)\n");
3141 fprintf(fp, " --debug-info-full-path Show full debug info source and binary paths\n");
3142 fprintf(fp, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
3143 fprintf(fp, " up executables during debug info analysis\n");
3144 fprintf(fp, " (default: `/usr/lib/debug`)\n");
3145 fprintf(fp, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
3146 fprintf(fp, " all, trace, trace:hostname, trace:domain,\n");
3147 fprintf(fp, " trace:procname, trace:vpid, loglevel, emf\n");
3148 fprintf(fp, " (default: trace:hostname, trace:procname,\n");
3149 fprintf(fp, " trace:vpid)\n");
3150 fprintf(fp, " -n, --names=NAME[,NAME]... Print field names:\n");
3151 fprintf(fp, " payload (or arg or args)\n");
3152 fprintf(fp, " none, all, scope, header, context (or ctx)\n");
3153 fprintf(fp, " (default: payload, context)\n");
3154 fprintf(fp, " --no-delta Do not print time delta between consecutive\n");
3155 fprintf(fp, " events\n");
3156 fprintf(fp, " -w, --output=PATH Write output to PATH (default: standard output)\n");
3157}
3158
3159/*
3160 * Prints the convert command usage.
3161 */
3162static
3163void print_convert_usage(FILE *fp)
3164{
3165 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
3166 fprintf(fp, "\n");
3167 fprintf(fp, "Options:\n");
3168 fprintf(fp, "\n");
3169 fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
3170 fprintf(fp, " for the following component instances\n");
3171 fprintf(fp, " (see the expected format of PARAMS below)\n");
3172 fprintf(fp, " --begin=BEGIN Set the `begin` parameter of the latest\n");
3173 fprintf(fp, " source component instance to BEGIN\n");
3174 fprintf(fp, " (see the suggested format of BEGIN below)\n");
ebba3338
PP
3175 fprintf(fp, " -c, --connect=CONNECTION Connect two component instances (see the\n");
3176 fprintf(fp, " expected format of CONNECTION below)\n");
290725f7
PP
3177 fprintf(fp, " -d, --debug Enable debug mode\n");
3178 fprintf(fp, " --end=END Set the `end` parameter of the latest\n");
3179 fprintf(fp, " source component instance to END\n");
3180 fprintf(fp, " (see the suggested format of BEGIN below)\n");
355b476b
PP
3181 fprintf(fp, " --filter=PLUGIN.COMPCLS Instantiate a filter component from plugin\n");
3182 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
3183 fprintf(fp, " repeated)\n");
3b6cfcc5
PP
3184 fprintf(fp, " --name=NAME Set the name of the latest component\n");
3185 fprintf(fp, " instance to NAME (must be unique amongst\n");
3186 fprintf(fp, " all the names of the component instances)\n");
290725f7
PP
3187 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
3188 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
3189 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
3190 fprintf(fp, " -p, --params=PARAMS Set the parameters of the latest component\n");
3191 fprintf(fp, " instance (in command-line order) to PARAMS\n");
3192 fprintf(fp, " (see the expected format of PARAMS below)\n");
3193 fprintf(fp, " -P, --path=PATH Set the `path` parameter of the latest\n");
3194 fprintf(fp, " component instance to PATH\n");
3195 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
3196 fprintf(fp, " dynamic plugins can be loaded\n");
3197 fprintf(fp, " -r, --reset-base-params Reset the current base parameters of the\n");
3198 fprintf(fp, " following source and sink component\n");
3199 fprintf(fp, " instances to an empty map\n");
3200 fprintf(fp, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
3201 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
3202 fprintf(fp, " repeated)\n");
3203 fprintf(fp, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
3204 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
3205 fprintf(fp, " repeated)\n");
3206 fprintf(fp, " --timerange=TIMERANGE Set time range to TIMERANGE: BEGIN,END or\n");
3207 fprintf(fp, " [BEGIN,END] (literally `[` and `]`)\n");
3208 fprintf(fp, " (suggested format of BEGIN/END below)\n");
3209 fprintf(fp, " -v, --verbose Enable verbose output\n");
3210 fprintf(fp, " -h --help Show this help and quit\n");
3211 fprintf(fp, "\n");
3212 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
3213 fprintf(fp, "\n\n");
3214 fprintf(fp, "Suggested format of BEGIN and END\n");
3215 fprintf(fp, "---------------------------------\n");
3216 fprintf(fp, "\n");
3217 fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
3218 fprintf(fp, "\n\n");
ebba3338
PP
3219 fprintf(fp, "Expected format of CONNECTION\n");
3220 fprintf(fp, "-----------------------------\n");
3221 fprintf(fp, "\n");
3222 fprintf(fp, " SRC[.SRCPORT]:DST[.DSTPORT]\n");
3223 fprintf(fp, "\n");
3224 fprintf(fp, "SRC and DST are the names of the source and destination component\n");
3225 fprintf(fp, "instances to connect together. You can set the name of a component\n");
3226 fprintf(fp, "instance with the --name option.\n");
3227 fprintf(fp, "\n");
3228 fprintf(fp, "SRCPORT and DSTPORT are the optional source and destination ports to use\n");
3229 fprintf(fp, "for the connection. When the port is not specified, the default port is\n");
3230 fprintf(fp, "used.\n");
3231 fprintf(fp, "\n");
3232 fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
3233 fprintf(fp, "can connect a filter component to a sink component.\n");
3234 fprintf(fp, "\n");
3235 fprintf(fp, "Example:\n");
3236 fprintf(fp, "\n");
3237 fprintf(fp, " my-filter.top10:json-out\n");
3238 fprintf(fp, "\n\n");
63ce0e1d 3239 print_expected_params_format(fp);
290725f7
PP
3240}
3241
3242static struct poptOption convert_long_options[] = {
3243 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
3244 { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
3245 { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
3246 { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
3247 { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
3248 { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
3249 { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
3250 { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
3251 { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
3252 { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
ebba3338 3253 { "connect", 'c', POPT_ARG_STRING, NULL, OPT_CONNECT, NULL, NULL },
290725f7
PP
3254 { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
3255 { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
3256 { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
3257 { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
3258 { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
3259 { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
355b476b 3260 { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, NULL, NULL },
290725f7
PP
3261 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
3262 { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
3b6cfcc5 3263 { "name", '\0', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
290725f7
PP
3264 { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
3265 { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
3266 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
3267 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
3268 { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
3269 { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
3270 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
3271 { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
3272 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
3273 { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
3274 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
3275 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
3276 { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
3277 { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
3278 { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
3279 { NULL, 0, 0, NULL, 0, NULL, NULL },
3280};
3281
3282/*
3283 * Creates a Babeltrace config object from the arguments of a convert
3284 * command.
3285 *
3286 * *retcode is set to the appropriate exit code to use.
3287 */
3288struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
3289 int *retcode, bool omit_system_plugin_path,
3290 bool omit_home_plugin_path,
3291 struct bt_value *initial_plugin_paths)
3292{
3293 poptContext pc = NULL;
3294 char *arg = NULL;
3295 struct ctf_legacy_opts ctf_legacy_opts;
3296 struct text_legacy_opts text_legacy_opts;
3297 enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
3298 enum legacy_output_format legacy_output_format =
3299 LEGACY_OUTPUT_FORMAT_NONE;
3300 struct bt_value *legacy_input_paths = NULL;
3301 struct bt_config_component *implicit_source_comp = NULL;
3302 struct bt_config_component *cur_cfg_comp = NULL;
3303 bool cur_is_implicit_source = false;
3304 bool use_implicit_source = false;
3305 enum bt_config_component_dest cur_cfg_comp_dest =
3306 BT_CONFIG_COMPONENT_DEST_SOURCE;
3307 struct bt_value *cur_base_params = NULL;
3308 int opt, ret = 0;
3309 struct bt_config *cfg = NULL;
3b6cfcc5 3310 struct bt_value *instance_names = NULL;
ebba3338
PP
3311 struct bt_value *connection_args = NULL;
3312 char error_buf[256] = { 0 };
290725f7
PP
3313
3314 *retcode = 0;
3315 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
3316 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
3317
3318 if (argc <= 1) {
3319 print_convert_usage(stdout);
3320 *retcode = -1;
3321 goto end;
3322 }
3323
3324 cfg = bt_config_convert_create(initial_plugin_paths);
3325 if (!cfg) {
3326 print_err_oom();
3327 goto error;
3328 }
3329
3330 cfg->cmd_data.convert.omit_system_plugin_path = omit_system_plugin_path;
3331 cfg->cmd_data.convert.omit_home_plugin_path = omit_home_plugin_path;
3332 text_legacy_opts.output = g_string_new(NULL);
3333 if (!text_legacy_opts.output) {
3334 print_err_oom();
3335 goto error;
3336 }
3337
3338 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
3339 if (!text_legacy_opts.dbg_info_dir) {
3340 print_err_oom();
3341 goto error;
3342 }
3343
3344 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
3345 if (!text_legacy_opts.dbg_info_target_prefix) {
3346 print_err_oom();
3347 goto error;
3348 }
3349
3350 cur_base_params = bt_value_map_create();
3351 if (!cur_base_params) {
3352 print_err_oom();
3353 goto error;
3354 }
3355
3356 legacy_input_paths = bt_value_array_create();
3357 if (!legacy_input_paths) {
3358 print_err_oom();
3359 goto error;
3360 }
3361
3b6cfcc5
PP
3362 instance_names = bt_value_map_create();
3363 if (!instance_names) {
3364 print_err_oom();
3365 goto error;
3366 }
3367
ebba3338
PP
3368 connection_args = bt_value_array_create();
3369 if (!connection_args) {
3370 print_err_oom();
3371 goto error;
3372 }
3373
290725f7
PP
3374 ret = append_env_var_plugin_paths(cfg->cmd_data.convert.plugin_paths);
3375 if (ret) {
3376 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3377 goto error;
3378 }
3379
3380 /* Note: implicit source never gets positional base params. */
90de159b
PP
3381 implicit_source_comp = bt_config_component_from_arg(
3382 BT_COMPONENT_CLASS_TYPE_SOURCE, DEFAULT_SOURCE_COMPONENT_NAME);
22e22462
PP
3383 if (!implicit_source_comp) {
3384 print_err_oom();
3385 goto error;
290725f7
PP
3386 }
3387
22e22462
PP
3388 cur_cfg_comp = implicit_source_comp;
3389 cur_is_implicit_source = true;
3390 use_implicit_source = true;
3391
290725f7
PP
3392 /* Parse options */
3393 pc = poptGetContext(NULL, argc, (const char **) argv,
3394 convert_long_options, 0);
3395 if (!pc) {
3396 printf_err("Cannot get popt context\n");
3397 goto error;
3398 }
3399
3400 poptReadDefaultConfig(pc, 0);
3401
3402 while ((opt = poptGetNextOpt(pc)) > 0) {
3403 arg = poptGetOptArg(pc);
3404
3405 switch (opt) {
3406 case OPT_PLUGIN_PATH:
3407 if (bt_common_is_setuid_setgid()) {
3408 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3409 } else {
3410 if (bt_config_append_plugin_paths(
3411 cfg->cmd_data.convert.plugin_paths,
3412 arg)) {
2703153b
PP
3413 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3414 arg);
290725f7
PP
3415 goto error;
3416 }
3417 }
3418 break;
3419 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
3420 cfg->cmd_data.convert.omit_system_plugin_path = true;
3421 break;
3422 case OPT_OMIT_HOME_PLUGIN_PATH:
3423 cfg->cmd_data.convert.omit_home_plugin_path = true;
98ecef32 3424 break;
c42c79ea
PP
3425 case OPT_OUTPUT_PATH:
3426 if (text_legacy_opts.output->len > 0) {
3427 printf_err("Duplicate --output option\n");
3428 goto error;
3429 }
3430
3431 g_string_assign(text_legacy_opts.output, arg);
3432 break;
3433 case OPT_DEBUG_INFO_DIR:
3434 if (text_legacy_opts.dbg_info_dir->len > 0) {
3435 printf_err("Duplicate --debug-info-dir option\n");
3436 goto error;
3437 }
3438
3439 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
3440 break;
3441 case OPT_DEBUG_INFO_TARGET_PREFIX:
3442 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
3443 printf_err("Duplicate --debug-info-target-prefix option\n");
3444 goto error;
3445 }
3446
3447 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
3448 break;
3449 case OPT_INPUT_FORMAT:
3450 case OPT_SOURCE:
3451 {
c42c79ea
PP
3452 if (opt == OPT_INPUT_FORMAT) {
3453 if (!strcmp(arg, "ctf")) {
3454 /* Legacy CTF input format */
3455 if (legacy_input_format) {
3456 print_err_dup_legacy_input();
3457 goto error;
3458 }
3459
3460 legacy_input_format =
3461 LEGACY_INPUT_FORMAT_CTF;
3462 break;
3463 } else if (!strcmp(arg, "lttng-live")) {
3464 /* Legacy LTTng-live input format */
3465 if (legacy_input_format) {
3466 print_err_dup_legacy_input();
3467 goto error;
3468 }
3469
3470 legacy_input_format =
3471 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
3472 break;
3473 }
3474 }
3475
65582340
MD
3476 use_implicit_source = false;
3477
c42c79ea 3478 /* Non-legacy: try to create a component config */
65582340 3479 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3480 add_cfg_comp(cfg, cur_cfg_comp,
3481 cur_cfg_comp_dest);
3482 }
3483
90de159b
PP
3484 cur_cfg_comp = bt_config_component_from_arg(
3485 BT_COMPONENT_CLASS_TYPE_SOURCE, arg);
bdc61c70 3486 if (!cur_cfg_comp) {
49849a47 3487 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
3488 arg);
3489 goto error;
3490 }
65582340 3491 cur_is_implicit_source = false;
c42c79ea 3492
b07ffa28
PP
3493 assert(cur_base_params);
3494 bt_put(cur_cfg_comp->params);
c9313318 3495 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3496 if (!cur_cfg_comp->params) {
c9313318 3497 print_err_oom();
290725f7 3498 goto error;
c9313318
PP
3499 }
3500
bdc61c70 3501 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
c42c79ea
PP
3502 break;
3503 }
355b476b
PP
3504 case OPT_FILTER:
3505 {
3506 if (cur_cfg_comp && !cur_is_implicit_source) {
3507 add_cfg_comp(cfg, cur_cfg_comp,
3508 cur_cfg_comp_dest);
3509 }
3510
3511 cur_cfg_comp = bt_config_component_from_arg(
3512 BT_COMPONENT_CLASS_TYPE_FILTER, arg);
3513 if (!cur_cfg_comp) {
3514 printf_err("Invalid format for --filter option's argument:\n %s\n",
3515 arg);
3516 goto error;
3517 }
3518 cur_is_implicit_source = false;
3519
3520 assert(cur_base_params);
3521 bt_put(cur_cfg_comp->params);
3522 cur_cfg_comp->params = bt_value_copy(cur_base_params);
3523 if (!cur_cfg_comp->params) {
3524 print_err_oom();
3525 goto error;
3526 }
3527
3528 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
3529 break;
3530 }
c42c79ea
PP
3531 case OPT_OUTPUT_FORMAT:
3532 case OPT_SINK:
3533 {
c42c79ea
PP
3534 if (opt == OPT_OUTPUT_FORMAT) {
3535 if (!strcmp(arg, "text")) {
3536 /* Legacy CTF-text output format */
3537 if (legacy_output_format) {
3538 print_err_dup_legacy_output();
3539 goto error;
3540 }
3541
3542 legacy_output_format =
3543 LEGACY_OUTPUT_FORMAT_TEXT;
3544 break;
3545 } else if (!strcmp(arg, "dummy")) {
3546 /* Legacy dummy output format */
3547 if (legacy_output_format) {
3548 print_err_dup_legacy_output();
3549 goto error;
3550 }
3551
3552 legacy_output_format =
3553 LEGACY_OUTPUT_FORMAT_DUMMY;
3554 break;
3555 } else if (!strcmp(arg, "ctf-metadata")) {
05a67631 3556 cfg->cmd_data.convert.print_ctf_metadata = true;
c42c79ea
PP
3557 break;
3558 }
3559 }
3560
3561 /* Non-legacy: try to create a component config */
65582340 3562 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3563 add_cfg_comp(cfg, cur_cfg_comp,
3564 cur_cfg_comp_dest);
3565 }
3566
90de159b
PP
3567 cur_cfg_comp = bt_config_component_from_arg(
3568 BT_COMPONENT_CLASS_TYPE_SINK, arg);
bdc61c70 3569 if (!cur_cfg_comp) {
49849a47 3570 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
3571 arg);
3572 goto error;
3573 }
65582340 3574 cur_is_implicit_source = false;
c42c79ea 3575
b07ffa28
PP
3576 assert(cur_base_params);
3577 bt_put(cur_cfg_comp->params);
c9313318 3578 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3579 if (!cur_cfg_comp->params) {
c9313318 3580 print_err_oom();
290725f7 3581 goto error;
c9313318
PP
3582 }
3583
bdc61c70 3584 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
bdc61c70
PP
3585 break;
3586 }
3587 case OPT_PARAMS:
3588 {
3589 struct bt_value *params;
b07ffa28 3590 struct bt_value *params_to_set;
bdc61c70
PP
3591
3592 if (!cur_cfg_comp) {
2703153b
PP
3593 printf_err("Cannot add parameters to unavailable default source component `%s`:\n %s\n",
3594 DEFAULT_SOURCE_COMPONENT_NAME, arg);
bdc61c70
PP
3595 goto error;
3596 }
3597
bdc61c70
PP
3598 params = bt_value_from_arg(arg);
3599 if (!params) {
3600 printf_err("Invalid format for --params option's argument:\n %s\n",
3601 arg);
3602 goto error;
3603 }
3604
560ff91c 3605 params_to_set = bt_value_map_extend(cur_cfg_comp->params,
b07ffa28
PP
3606 params);
3607 BT_PUT(params);
3608 if (!params_to_set) {
560ff91c 3609 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
b07ffa28
PP
3610 arg);
3611 goto error;
3612 }
3613
3614 BT_MOVE(cur_cfg_comp->params, params_to_set);
c42c79ea
PP
3615 break;
3616 }
ad6a19bd
PP
3617 case OPT_PATH:
3618 if (!cur_cfg_comp) {
2703153b
PP
3619 printf_err("Cannot add `path` parameter to unavailable default source component `%s`:\n %s\n",
3620 DEFAULT_SOURCE_COMPONENT_NAME, arg);
ad6a19bd
PP
3621 goto error;
3622 }
3623
3624 assert(cur_cfg_comp->params);
3625
3626 if (bt_value_map_insert_string(cur_cfg_comp->params,
3627 "path", arg)) {
3628 print_err_oom();
3629 goto error;
3630 }
3631 break;
3b6cfcc5
PP
3632 case OPT_NAME:
3633 if (!cur_cfg_comp) {
3634 printf_err("Cannot set the name of unavailable default source component `%s`:\n %s\n",
3635 DEFAULT_SOURCE_COMPONENT_NAME, arg);
3636 goto error;
3637 }
3638
3639 if (bt_value_map_has_key(instance_names, arg)) {
3640 printf_err("Duplicate component instance name:\n %s\n",
3641 arg);
3642 goto error;
3643 }
3644
3645 g_string_assign(cur_cfg_comp->instance_name, arg);
3646
3647 if (bt_value_map_insert(instance_names,
3648 arg, bt_value_null)) {
3649 print_err_oom();
3650 goto error;
3651 }
3652 break;
b07ffa28
PP
3653 case OPT_BASE_PARAMS:
3654 {
3655 struct bt_value *params = bt_value_from_arg(arg);
3656
3657 if (!params) {
3658 printf_err("Invalid format for --base-params option's argument:\n %s\n",
3659 arg);
3660 goto error;
3661 }
3662
3663 BT_MOVE(cur_base_params, params);
3664 break;
3665 }
3666 case OPT_RESET_BASE_PARAMS:
3667 BT_PUT(cur_base_params);
3668 cur_base_params = bt_value_map_create();
3669 if (!cur_base_params) {
3670 print_err_oom();
3671 goto error;
3672 }
3673 break;
c42c79ea
PP
3674 case OPT_NAMES:
3675 if (text_legacy_opts.names) {
3676 printf_err("Duplicate --names option\n");
3677 goto error;
3678 }
3679
3680 text_legacy_opts.names = names_from_arg(arg);
3681 if (!text_legacy_opts.names) {
2703153b
PP
3682 printf_err("Invalid --names option's argument:\n %s\n",
3683 arg);
c42c79ea
PP
3684 goto error;
3685 }
3686 break;
3687 case OPT_FIELDS:
3688 if (text_legacy_opts.fields) {
3689 printf_err("Duplicate --fields option\n");
3690 goto error;
3691 }
3692
3693 text_legacy_opts.fields = fields_from_arg(arg);
3694 if (!text_legacy_opts.fields) {
2703153b
PP
3695 printf_err("Invalid --fields option's argument:\n %s\n",
3696 arg);
c42c79ea
PP
3697 goto error;
3698 }
3699 break;
3700 case OPT_NO_DELTA:
3701 text_legacy_opts.no_delta = true;
3702 break;
3703 case OPT_CLOCK_CYCLES:
3704 text_legacy_opts.clock_cycles = true;
3705 break;
3706 case OPT_CLOCK_SECONDS:
3707 text_legacy_opts.clock_seconds = true;
3708 break;
3709 case OPT_CLOCK_DATE:
3710 text_legacy_opts.clock_date = true;
3711 break;
3712 case OPT_CLOCK_GMT:
3713 text_legacy_opts.clock_gmt = true;
3714 break;
3715 case OPT_DEBUG_INFO_FULL_PATH:
3716 text_legacy_opts.dbg_info_full_path = true;
3717 break;
3718 case OPT_CLOCK_OFFSET:
3719 {
3720 int64_t val;
3721
3722 if (ctf_legacy_opts.offset_s.is_set) {
3723 printf_err("Duplicate --clock-offset option\n");
3724 goto error;
3725 }
3726
3727 if (parse_int64(arg, &val)) {
2703153b
PP
3728 printf_err("Invalid --clock-offset option's argument:\n %s\n",
3729 arg);
c42c79ea
PP
3730 goto error;
3731 }
3732
3733 set_offset_value(&ctf_legacy_opts.offset_s, val);
3734 break;
3735 }
3736 case OPT_CLOCK_OFFSET_NS:
3737 {
3738 int64_t val;
3739
3740 if (ctf_legacy_opts.offset_ns.is_set) {
3741 printf_err("Duplicate --clock-offset-ns option\n");
3742 goto error;
3743 }
3744
3745 if (parse_int64(arg, &val)) {
2703153b
PP
3746 printf_err("Invalid --clock-offset-ns option's argument:\n %s\n",
3747 arg);
c42c79ea
PP
3748 goto error;
3749 }
3750
3751 set_offset_value(&ctf_legacy_opts.offset_ns, val);
3752 break;
3753 }
3754 case OPT_STREAM_INTERSECTION:
3755 ctf_legacy_opts.stream_intersection = true;
3756 break;
3757 case OPT_CLOCK_FORCE_CORRELATE:
290725f7 3758 cfg->cmd_data.convert.force_correlate = true;
c42c79ea 3759 break;
0f9915c6
MD
3760 case OPT_BEGIN:
3761 if (!cur_cfg_comp) {
2703153b
PP
3762 printf_err("Cannot add `begin` parameter to unavailable default source component `%s`:\n %s\n",
3763 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3764 goto error;
3765 }
3766 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3767 printf_err("--begin option must follow a --source option:\n %s\n",
3768 arg);
0f9915c6
MD
3769 goto error;
3770 }
3771 if (bt_value_map_insert_string(cur_cfg_comp->params,
3772 "begin", arg)) {
3773 print_err_oom();
3774 goto error;
3775 }
3776 break;
3777 case OPT_END:
3778 if (!cur_cfg_comp) {
2703153b
PP
3779 printf_err("Cannot add `end` parameter to unavailable default source component `%s`:\n %s\n",
3780 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3781 goto error;
3782 }
3783 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3784 printf_err("--end option must follow a --source option:\n %s\n",
3785 arg);
0f9915c6
MD
3786 goto error;
3787 }
3788 if (bt_value_map_insert_string(cur_cfg_comp->params,
3789 "end", arg)) {
3790 print_err_oom();
3791 goto error;
3792 }
3793 break;
3794 case OPT_TIMERANGE:
3795 {
3796 const char *begin, *end;
3797
3798 if (!cur_cfg_comp) {
2703153b
PP
3799 printf_err("Cannot add `begin` and `end` parameters to unavailable default source component `%s`:\n %s\n",
3800 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3801 goto error;
3802 }
3803 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3804 printf_err("--timerange option must follow a --source option:\n %s\n",
3805 arg);
0f9915c6
MD
3806 goto error;
3807 }
3808 if (split_timerange(arg, &begin, &end)) {
2703153b
PP
3809 printf_err("Invalid --timerange format: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
3810 arg);
0f9915c6
MD
3811 goto error;
3812 }
3813 if (bt_value_map_insert_string(cur_cfg_comp->params,
3814 "begin", begin)) {
3815 print_err_oom();
3816 goto error;
3817 }
3818 if (bt_value_map_insert_string(cur_cfg_comp->params,
3819 "end", end)) {
3820 print_err_oom();
3821 goto error;
3822 }
3823 break;
3824 }
ebba3338
PP
3825 case OPT_CONNECT:
3826 if (bt_value_array_append_string(connection_args,
3827 arg)) {
3828 print_err_oom();
3829 goto error;
3830 }
3831 break;
c42c79ea 3832 case OPT_HELP:
290725f7
PP
3833 print_convert_usage(stdout);
3834 *retcode = -1;
3835 BT_PUT(cfg);
c42c79ea
PP
3836 goto end;
3837 case OPT_VERBOSE:
a263021c 3838 text_legacy_opts.verbose = true;
c42c79ea
PP
3839 cfg->verbose = true;
3840 break;
3841 case OPT_DEBUG:
3842 cfg->debug = true;
3843 break;
3844 default:
3845 printf_err("Unknown command-line option specified (option code %d)\n",
3846 opt);
3847 goto error;
3848 }
3849
3850 free(arg);
3851 arg = NULL;
3852 }
3853
3854 /* Check for option parsing error */
3855 if (opt < -1) {
3856 printf_err("While parsing command-line options, at option %s: %s\n",
3857 poptBadOption(pc, 0), poptStrerror(opt));
3858 goto error;
3859 }
3860
3861 /* Consume leftover arguments as legacy input paths */
3862 while (true) {
3863 const char *input_path = poptGetArg(pc);
3864
3865 if (!input_path) {
3866 break;
3867 }
3868
3869 if (bt_value_array_append_string(legacy_input_paths,
3870 input_path)) {
3871 print_err_oom();
3872 goto error;
3873 }
3874 }
3875
290725f7
PP
3876 if (append_home_and_system_plugin_paths(
3877 cfg->cmd_data.convert.plugin_paths,
3878 cfg->cmd_data.convert.omit_system_plugin_path,
3879 cfg->cmd_data.convert.omit_home_plugin_path)) {
3880 printf_err("Cannot append home and system plugin paths\n");
6cf24c61
MD
3881 goto error;
3882 }
3883
3884 /* Append current component configuration, if any */
3885 if (cur_cfg_comp && !cur_is_implicit_source) {
3886 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
3887 }
3888 cur_cfg_comp = NULL;
3889
c42c79ea
PP
3890 /* Validate legacy/non-legacy options */
3891 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
3892 legacy_input_paths, &ctf_legacy_opts,
bd9f0fa2 3893 &text_legacy_opts)) {
c42c79ea
PP
3894 printf_err("Command-line options form an invalid configuration\n");
3895 goto error;
3896 }
3897
3898 /*
3899 * If there's a legacy input format, convert it to source
3900 * component configurations.
3901 */
3902 if (legacy_input_format) {
290725f7
PP
3903 if (append_sources_from_legacy_opts(
3904 cfg->cmd_data.convert.sources,
c42c79ea 3905 legacy_input_format, &ctf_legacy_opts,
528debdf 3906 legacy_input_paths)) {
49849a47 3907 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
3908 goto error;
3909 }
290725f7
PP
3910 if (append_sources_from_implicit_params(
3911 cfg->cmd_data.convert.sources,
bd9f0fa2
MD
3912 implicit_source_comp)) {
3913 printf_err("Cannot initialize legacy component parameters\n");
3914 goto error;
3915 }
3916 use_implicit_source = false;
3917 } else {
3918 if (use_implicit_source) {
3919 add_cfg_comp(cfg, implicit_source_comp,
3920 BT_CONFIG_COMPONENT_DEST_SOURCE);
3921 implicit_source_comp = NULL;
3922 } else {
3923 if (implicit_source_comp
3924 && !bt_value_map_is_empty(implicit_source_comp->params)) {
05a67631 3925 printf_err("Arguments specified for implicit input format, but an explicit source component instance has been specified: overriding it\n");
bd9f0fa2
MD
3926 goto error;
3927 }
3928 }
c42c79ea
PP
3929 }
3930
05a67631
PP
3931 /*
3932 * At this point if we need to print the CTF metadata text, we
3933 * don't care about the legacy/implicit sinks and component
3934 * connections.
3935 */
3936 if (cfg->cmd_data.convert.print_ctf_metadata) {
3937 goto end;
3938 }
3939
c42c79ea
PP
3940 /*
3941 * If there's a legacy output format, convert it to sink
3942 * component configurations.
3943 */
3944 if (legacy_output_format) {
290725f7 3945 if (append_sinks_from_legacy_opts(cfg->cmd_data.convert.sinks,
c42c79ea 3946 legacy_output_format, &text_legacy_opts)) {
49849a47 3947 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
3948 goto error;
3949 }
3950 }
3951
290725f7 3952 if (cfg->cmd_data.convert.sinks->len == 0) {
bd9f0fa2 3953 /* Use implicit sink as default. */
90de159b
PP
3954 cur_cfg_comp = bt_config_component_from_arg(
3955 BT_COMPONENT_CLASS_TYPE_SINK,
3956 DEFAULT_SINK_COMPONENT_NAME);
bd9f0fa2 3957 if (!cur_cfg_comp) {
2703153b 3958 printf_error("Cannot find implicit sink plugin `%s`\n",
bd9f0fa2
MD
3959 DEFAULT_SINK_COMPONENT_NAME);
3960 }
3961 add_cfg_comp(cfg, cur_cfg_comp,
3962 BT_CONFIG_COMPONENT_DEST_SINK);
3963 cur_cfg_comp = NULL;
3964 }
3965
ebba3338
PP
3966 ret = bt_config_create_connections(cfg, connection_args,
3967 error_buf, 256);
3968 if (ret) {
3969 printf_err("Cannot creation connections:\n%s", error_buf);
3970 goto error;
3971 }
3972
c42c79ea
PP
3973 goto end;
3974
3975error:
290725f7
PP
3976 *retcode = 1;
3977 BT_PUT(cfg);
3978
c42c79ea
PP
3979end:
3980 if (pc) {
3981 poptFreeContext(pc);
3982 }
3983
3984 if (text_legacy_opts.output) {
3985 g_string_free(text_legacy_opts.output, TRUE);
3986 }
3987
3988 if (text_legacy_opts.dbg_info_dir) {
3989 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
3990 }
3991
3992 if (text_legacy_opts.dbg_info_target_prefix) {
3993 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
3994 }
3995
3996 free(arg);
65582340 3997 BT_PUT(implicit_source_comp);
bdc61c70 3998 BT_PUT(cur_cfg_comp);
b07ffa28 3999 BT_PUT(cur_base_params);
c42c79ea
PP
4000 BT_PUT(text_legacy_opts.names);
4001 BT_PUT(text_legacy_opts.fields);
4002 BT_PUT(legacy_input_paths);
3b6cfcc5 4003 BT_PUT(instance_names);
ebba3338 4004 BT_PUT(connection_args);
290725f7
PP
4005 return cfg;
4006}
4007
4008/*
4009 * Prints the Babeltrace 2.x general usage.
4010 */
4011static
4012void print_gen_usage(FILE *fp)
4013{
4014 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
4015 fprintf(fp, "\n");
4016 fprintf(fp, "General options:\n");
4017 fprintf(fp, "\n");
4018 fprintf(fp, " -d, --debug Enable debug mode\n");
4019 fprintf(fp, " -h --help Show this help and quit\n");
4020 fprintf(fp, " --help-legacy Show Babeltrace 1.x legacy help and quit\n");
4021 fprintf(fp, " -v, --verbose Enable verbose output\n");
4022 fprintf(fp, " -V, --version Show version and quit\n");
4023 fprintf(fp, "\n");
4024 fprintf(fp, "Available commands:\n");
4025 fprintf(fp, "\n");
4026 fprintf(fp, " convert Build a trace conversion graph and run it (default)\n");
22e22462 4027 fprintf(fp, " help Get help for a plugin or a component class\n");
290725f7 4028 fprintf(fp, " list-plugins List available plugins and their content\n");
a67681c1 4029 fprintf(fp, " query Query objects from a component class\n");
290725f7
PP
4030 fprintf(fp, "\n");
4031 fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
4032}
4033
4034struct bt_config *bt_config_from_args(int argc, const char *argv[],
4035 int *retcode, bool omit_system_plugin_path,
4036 bool omit_home_plugin_path,
4037 struct bt_value *initial_plugin_paths)
4038{
4039 struct bt_config *config = NULL;
4040 bool verbose = false;
4041 bool debug = false;
4042 int i;
4043 enum bt_config_command command = -1;
4044 const char **command_argv = NULL;
4045 int command_argc = -1;
4046 const char *command_name = NULL;
4047
4048 *retcode = -1;
4049
4050 if (argc <= 1) {
4051 print_gen_usage(stdout);
4052 goto end;
4053 }
4054
4055 for (i = 1; i < argc; i++) {
4056 const char *cur_arg = argv[i];
4057
4058 if (strcmp(cur_arg, "-d") == 0 ||
4059 strcmp(cur_arg, "--debug") == 0) {
4060 debug = true;
4061 } else if (strcmp(cur_arg, "-v") == 0 ||
4062 strcmp(cur_arg, "--verbose") == 0) {
4063 verbose = true;
4064 } else if (strcmp(cur_arg, "-V") == 0 ||
4065 strcmp(cur_arg, "--version") == 0) {
4066 print_version();
4067 goto end;
4068 } else if (strcmp(cur_arg, "-h") == 0 ||
4069 strcmp(cur_arg, "--help") == 0) {
4070 print_gen_usage(stdout);
4071 goto end;
4072 } else if (strcmp(cur_arg, "--help-legacy") == 0) {
4073 print_legacy_usage(stdout);
4074 goto end;
4075 } else {
22e22462
PP
4076 bool has_command = true;
4077
290725f7
PP
4078 /*
4079 * First unknown argument: is it a known command
4080 * name?
4081 */
4082 if (strcmp(cur_arg, "convert") == 0) {
4083 command = BT_CONFIG_COMMAND_CONVERT;
290725f7
PP
4084 } else if (strcmp(cur_arg, "list-plugins") == 0) {
4085 command = BT_CONFIG_COMMAND_LIST_PLUGINS;
22e22462
PP
4086 } else if (strcmp(cur_arg, "help") == 0) {
4087 command = BT_CONFIG_COMMAND_HELP;
a67681c1
PP
4088 } else if (strcmp(cur_arg, "query") == 0) {
4089 command = BT_CONFIG_COMMAND_QUERY;
290725f7
PP
4090 } else {
4091 /*
4092 * Unknown argument, but not a known
4093 * command name: assume the whole
4094 * arguments are for the default convert
4095 * command.
4096 */
4097 command = BT_CONFIG_COMMAND_CONVERT;
4098 command_argv = argv;
4099 command_argc = argc;
22e22462
PP
4100 has_command = false;
4101 }
4102
4103 if (has_command) {
4104 command_argv = &argv[i];
4105 command_argc = argc - i;
4106 command_name = cur_arg;
290725f7
PP
4107 }
4108 break;
4109 }
4110 }
4111
4112 if ((int) command < 0) {
4113 /*
4114 * We only got non-help, non-version general options
4115 * like --verbose and --debug, without any other
4116 * arguments, so we can't do anything useful: print the
4117 * usage and quit.
4118 */
4119 print_gen_usage(stdout);
4120 goto end;
4121 }
4122
4123 assert(command_argv);
4124 assert(command_argc >= 0);
4125
4126 switch (command) {
4127 case BT_CONFIG_COMMAND_CONVERT:
4128 config = bt_config_convert_from_args(command_argc, command_argv,
4129 retcode, omit_system_plugin_path,
4130 omit_home_plugin_path, initial_plugin_paths);
4131 break;
4132 case BT_CONFIG_COMMAND_LIST_PLUGINS:
4133 config = bt_config_list_plugins_from_args(command_argc,
4134 command_argv, retcode, omit_system_plugin_path,
4135 omit_home_plugin_path, initial_plugin_paths);
4136 break;
22e22462
PP
4137 case BT_CONFIG_COMMAND_HELP:
4138 config = bt_config_help_from_args(command_argc,
4139 command_argv, retcode, omit_system_plugin_path,
4140 omit_home_plugin_path, initial_plugin_paths);
4141 break;
a67681c1
PP
4142 case BT_CONFIG_COMMAND_QUERY:
4143 config = bt_config_query_from_args(command_argc,
63ce0e1d
PP
4144 command_argv, retcode, omit_system_plugin_path,
4145 omit_home_plugin_path, initial_plugin_paths);
4146 break;
290725f7
PP
4147 default:
4148 assert(false);
4149 }
4150
4151 if (config) {
4152 if (verbose) {
4153 config->verbose = true;
4154 }
4155
4156 if (debug) {
4157 config->debug = true;
4158 }
4159
4160 config->command_name = command_name;
4161 }
4162
4163end:
4164 return config;
c42c79ea 4165}
This page took 0.202567 seconds and 4 git commands to generate.