babeltrace-cfg.c: do not allow duplicate -v option
[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 */
82a498b7
PP
51#define printf_err(fmt, args...) \
52 do { \
53 if (is_first_error) { \
54 fprintf(stderr, "Command line error: "); \
55 is_first_error = false; \
56 } \
57 fprintf(stderr, fmt, ##args); \
c42c79ea
PP
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 };
ae3b9aa4 3313 bool got_verbose_opt = false;
290725f7
PP
3314
3315 *retcode = 0;
3316 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
3317 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
3318
3319 if (argc <= 1) {
3320 print_convert_usage(stdout);
3321 *retcode = -1;
3322 goto end;
3323 }
3324
3325 cfg = bt_config_convert_create(initial_plugin_paths);
3326 if (!cfg) {
3327 print_err_oom();
3328 goto error;
3329 }
3330
3331 cfg->cmd_data.convert.omit_system_plugin_path = omit_system_plugin_path;
3332 cfg->cmd_data.convert.omit_home_plugin_path = omit_home_plugin_path;
3333 text_legacy_opts.output = g_string_new(NULL);
3334 if (!text_legacy_opts.output) {
3335 print_err_oom();
3336 goto error;
3337 }
3338
3339 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
3340 if (!text_legacy_opts.dbg_info_dir) {
3341 print_err_oom();
3342 goto error;
3343 }
3344
3345 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
3346 if (!text_legacy_opts.dbg_info_target_prefix) {
3347 print_err_oom();
3348 goto error;
3349 }
3350
3351 cur_base_params = bt_value_map_create();
3352 if (!cur_base_params) {
3353 print_err_oom();
3354 goto error;
3355 }
3356
3357 legacy_input_paths = bt_value_array_create();
3358 if (!legacy_input_paths) {
3359 print_err_oom();
3360 goto error;
3361 }
3362
3b6cfcc5
PP
3363 instance_names = bt_value_map_create();
3364 if (!instance_names) {
3365 print_err_oom();
3366 goto error;
3367 }
3368
ebba3338
PP
3369 connection_args = bt_value_array_create();
3370 if (!connection_args) {
3371 print_err_oom();
3372 goto error;
3373 }
3374
290725f7
PP
3375 ret = append_env_var_plugin_paths(cfg->cmd_data.convert.plugin_paths);
3376 if (ret) {
3377 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3378 goto error;
3379 }
3380
3381 /* Note: implicit source never gets positional base params. */
90de159b
PP
3382 implicit_source_comp = bt_config_component_from_arg(
3383 BT_COMPONENT_CLASS_TYPE_SOURCE, DEFAULT_SOURCE_COMPONENT_NAME);
22e22462
PP
3384 if (!implicit_source_comp) {
3385 print_err_oom();
3386 goto error;
290725f7
PP
3387 }
3388
22e22462
PP
3389 cur_cfg_comp = implicit_source_comp;
3390 cur_is_implicit_source = true;
3391 use_implicit_source = true;
3392
290725f7
PP
3393 /* Parse options */
3394 pc = poptGetContext(NULL, argc, (const char **) argv,
3395 convert_long_options, 0);
3396 if (!pc) {
3397 printf_err("Cannot get popt context\n");
3398 goto error;
3399 }
3400
3401 poptReadDefaultConfig(pc, 0);
3402
3403 while ((opt = poptGetNextOpt(pc)) > 0) {
3404 arg = poptGetOptArg(pc);
3405
3406 switch (opt) {
3407 case OPT_PLUGIN_PATH:
3408 if (bt_common_is_setuid_setgid()) {
3409 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3410 } else {
3411 if (bt_config_append_plugin_paths(
3412 cfg->cmd_data.convert.plugin_paths,
3413 arg)) {
2703153b
PP
3414 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3415 arg);
290725f7
PP
3416 goto error;
3417 }
3418 }
3419 break;
3420 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
3421 cfg->cmd_data.convert.omit_system_plugin_path = true;
3422 break;
3423 case OPT_OMIT_HOME_PLUGIN_PATH:
3424 cfg->cmd_data.convert.omit_home_plugin_path = true;
98ecef32 3425 break;
c42c79ea
PP
3426 case OPT_OUTPUT_PATH:
3427 if (text_legacy_opts.output->len > 0) {
3428 printf_err("Duplicate --output option\n");
3429 goto error;
3430 }
3431
3432 g_string_assign(text_legacy_opts.output, arg);
3433 break;
3434 case OPT_DEBUG_INFO_DIR:
3435 if (text_legacy_opts.dbg_info_dir->len > 0) {
3436 printf_err("Duplicate --debug-info-dir option\n");
3437 goto error;
3438 }
3439
3440 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
3441 break;
3442 case OPT_DEBUG_INFO_TARGET_PREFIX:
3443 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
3444 printf_err("Duplicate --debug-info-target-prefix option\n");
3445 goto error;
3446 }
3447
3448 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
3449 break;
3450 case OPT_INPUT_FORMAT:
3451 case OPT_SOURCE:
3452 {
c42c79ea
PP
3453 if (opt == OPT_INPUT_FORMAT) {
3454 if (!strcmp(arg, "ctf")) {
3455 /* Legacy CTF input format */
3456 if (legacy_input_format) {
3457 print_err_dup_legacy_input();
3458 goto error;
3459 }
3460
3461 legacy_input_format =
3462 LEGACY_INPUT_FORMAT_CTF;
3463 break;
3464 } else if (!strcmp(arg, "lttng-live")) {
3465 /* Legacy LTTng-live input format */
3466 if (legacy_input_format) {
3467 print_err_dup_legacy_input();
3468 goto error;
3469 }
3470
3471 legacy_input_format =
3472 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
3473 break;
3474 }
3475 }
3476
65582340
MD
3477 use_implicit_source = false;
3478
c42c79ea 3479 /* Non-legacy: try to create a component config */
65582340 3480 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3481 add_cfg_comp(cfg, cur_cfg_comp,
3482 cur_cfg_comp_dest);
3483 }
3484
90de159b
PP
3485 cur_cfg_comp = bt_config_component_from_arg(
3486 BT_COMPONENT_CLASS_TYPE_SOURCE, arg);
bdc61c70 3487 if (!cur_cfg_comp) {
49849a47 3488 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
3489 arg);
3490 goto error;
3491 }
65582340 3492 cur_is_implicit_source = false;
c42c79ea 3493
b07ffa28
PP
3494 assert(cur_base_params);
3495 bt_put(cur_cfg_comp->params);
c9313318 3496 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3497 if (!cur_cfg_comp->params) {
c9313318 3498 print_err_oom();
290725f7 3499 goto error;
c9313318
PP
3500 }
3501
bdc61c70 3502 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
c42c79ea
PP
3503 break;
3504 }
355b476b
PP
3505 case OPT_FILTER:
3506 {
3507 if (cur_cfg_comp && !cur_is_implicit_source) {
3508 add_cfg_comp(cfg, cur_cfg_comp,
3509 cur_cfg_comp_dest);
3510 }
3511
3512 cur_cfg_comp = bt_config_component_from_arg(
3513 BT_COMPONENT_CLASS_TYPE_FILTER, arg);
3514 if (!cur_cfg_comp) {
3515 printf_err("Invalid format for --filter option's argument:\n %s\n",
3516 arg);
3517 goto error;
3518 }
3519 cur_is_implicit_source = false;
3520
3521 assert(cur_base_params);
3522 bt_put(cur_cfg_comp->params);
3523 cur_cfg_comp->params = bt_value_copy(cur_base_params);
3524 if (!cur_cfg_comp->params) {
3525 print_err_oom();
3526 goto error;
3527 }
3528
3529 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
3530 break;
3531 }
c42c79ea
PP
3532 case OPT_OUTPUT_FORMAT:
3533 case OPT_SINK:
3534 {
c42c79ea
PP
3535 if (opt == OPT_OUTPUT_FORMAT) {
3536 if (!strcmp(arg, "text")) {
3537 /* Legacy CTF-text output format */
3538 if (legacy_output_format) {
3539 print_err_dup_legacy_output();
3540 goto error;
3541 }
3542
3543 legacy_output_format =
3544 LEGACY_OUTPUT_FORMAT_TEXT;
3545 break;
3546 } else if (!strcmp(arg, "dummy")) {
3547 /* Legacy dummy output format */
3548 if (legacy_output_format) {
3549 print_err_dup_legacy_output();
3550 goto error;
3551 }
3552
3553 legacy_output_format =
3554 LEGACY_OUTPUT_FORMAT_DUMMY;
3555 break;
3556 } else if (!strcmp(arg, "ctf-metadata")) {
05a67631 3557 cfg->cmd_data.convert.print_ctf_metadata = true;
c42c79ea
PP
3558 break;
3559 }
3560 }
3561
3562 /* Non-legacy: try to create a component config */
65582340 3563 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3564 add_cfg_comp(cfg, cur_cfg_comp,
3565 cur_cfg_comp_dest);
3566 }
3567
90de159b
PP
3568 cur_cfg_comp = bt_config_component_from_arg(
3569 BT_COMPONENT_CLASS_TYPE_SINK, arg);
bdc61c70 3570 if (!cur_cfg_comp) {
49849a47 3571 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
3572 arg);
3573 goto error;
3574 }
65582340 3575 cur_is_implicit_source = false;
c42c79ea 3576
b07ffa28
PP
3577 assert(cur_base_params);
3578 bt_put(cur_cfg_comp->params);
c9313318 3579 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3580 if (!cur_cfg_comp->params) {
c9313318 3581 print_err_oom();
290725f7 3582 goto error;
c9313318
PP
3583 }
3584
bdc61c70 3585 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
bdc61c70
PP
3586 break;
3587 }
3588 case OPT_PARAMS:
3589 {
3590 struct bt_value *params;
b07ffa28 3591 struct bt_value *params_to_set;
bdc61c70
PP
3592
3593 if (!cur_cfg_comp) {
2703153b
PP
3594 printf_err("Cannot add parameters to unavailable default source component `%s`:\n %s\n",
3595 DEFAULT_SOURCE_COMPONENT_NAME, arg);
bdc61c70
PP
3596 goto error;
3597 }
3598
bdc61c70
PP
3599 params = bt_value_from_arg(arg);
3600 if (!params) {
3601 printf_err("Invalid format for --params option's argument:\n %s\n",
3602 arg);
3603 goto error;
3604 }
3605
560ff91c 3606 params_to_set = bt_value_map_extend(cur_cfg_comp->params,
b07ffa28
PP
3607 params);
3608 BT_PUT(params);
3609 if (!params_to_set) {
560ff91c 3610 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
b07ffa28
PP
3611 arg);
3612 goto error;
3613 }
3614
3615 BT_MOVE(cur_cfg_comp->params, params_to_set);
c42c79ea
PP
3616 break;
3617 }
ad6a19bd
PP
3618 case OPT_PATH:
3619 if (!cur_cfg_comp) {
2703153b
PP
3620 printf_err("Cannot add `path` parameter to unavailable default source component `%s`:\n %s\n",
3621 DEFAULT_SOURCE_COMPONENT_NAME, arg);
ad6a19bd
PP
3622 goto error;
3623 }
3624
3625 assert(cur_cfg_comp->params);
3626
3627 if (bt_value_map_insert_string(cur_cfg_comp->params,
3628 "path", arg)) {
3629 print_err_oom();
3630 goto error;
3631 }
3632 break;
3b6cfcc5
PP
3633 case OPT_NAME:
3634 if (!cur_cfg_comp) {
3635 printf_err("Cannot set the name of unavailable default source component `%s`:\n %s\n",
3636 DEFAULT_SOURCE_COMPONENT_NAME, arg);
3637 goto error;
3638 }
3639
3640 if (bt_value_map_has_key(instance_names, arg)) {
3641 printf_err("Duplicate component instance name:\n %s\n",
3642 arg);
3643 goto error;
3644 }
3645
3646 g_string_assign(cur_cfg_comp->instance_name, arg);
3647
3648 if (bt_value_map_insert(instance_names,
3649 arg, bt_value_null)) {
3650 print_err_oom();
3651 goto error;
3652 }
3653 break;
b07ffa28
PP
3654 case OPT_BASE_PARAMS:
3655 {
3656 struct bt_value *params = bt_value_from_arg(arg);
3657
3658 if (!params) {
3659 printf_err("Invalid format for --base-params option's argument:\n %s\n",
3660 arg);
3661 goto error;
3662 }
3663
3664 BT_MOVE(cur_base_params, params);
3665 break;
3666 }
3667 case OPT_RESET_BASE_PARAMS:
3668 BT_PUT(cur_base_params);
3669 cur_base_params = bt_value_map_create();
3670 if (!cur_base_params) {
3671 print_err_oom();
3672 goto error;
3673 }
3674 break;
c42c79ea
PP
3675 case OPT_NAMES:
3676 if (text_legacy_opts.names) {
3677 printf_err("Duplicate --names option\n");
3678 goto error;
3679 }
3680
3681 text_legacy_opts.names = names_from_arg(arg);
3682 if (!text_legacy_opts.names) {
2703153b
PP
3683 printf_err("Invalid --names option's argument:\n %s\n",
3684 arg);
c42c79ea
PP
3685 goto error;
3686 }
3687 break;
3688 case OPT_FIELDS:
3689 if (text_legacy_opts.fields) {
3690 printf_err("Duplicate --fields option\n");
3691 goto error;
3692 }
3693
3694 text_legacy_opts.fields = fields_from_arg(arg);
3695 if (!text_legacy_opts.fields) {
2703153b
PP
3696 printf_err("Invalid --fields option's argument:\n %s\n",
3697 arg);
c42c79ea
PP
3698 goto error;
3699 }
3700 break;
3701 case OPT_NO_DELTA:
3702 text_legacy_opts.no_delta = true;
3703 break;
3704 case OPT_CLOCK_CYCLES:
3705 text_legacy_opts.clock_cycles = true;
3706 break;
3707 case OPT_CLOCK_SECONDS:
3708 text_legacy_opts.clock_seconds = true;
3709 break;
3710 case OPT_CLOCK_DATE:
3711 text_legacy_opts.clock_date = true;
3712 break;
3713 case OPT_CLOCK_GMT:
3714 text_legacy_opts.clock_gmt = true;
3715 break;
3716 case OPT_DEBUG_INFO_FULL_PATH:
3717 text_legacy_opts.dbg_info_full_path = true;
3718 break;
3719 case OPT_CLOCK_OFFSET:
3720 {
3721 int64_t val;
3722
3723 if (ctf_legacy_opts.offset_s.is_set) {
3724 printf_err("Duplicate --clock-offset option\n");
3725 goto error;
3726 }
3727
3728 if (parse_int64(arg, &val)) {
2703153b
PP
3729 printf_err("Invalid --clock-offset option's argument:\n %s\n",
3730 arg);
c42c79ea
PP
3731 goto error;
3732 }
3733
3734 set_offset_value(&ctf_legacy_opts.offset_s, val);
3735 break;
3736 }
3737 case OPT_CLOCK_OFFSET_NS:
3738 {
3739 int64_t val;
3740
3741 if (ctf_legacy_opts.offset_ns.is_set) {
3742 printf_err("Duplicate --clock-offset-ns option\n");
3743 goto error;
3744 }
3745
3746 if (parse_int64(arg, &val)) {
2703153b
PP
3747 printf_err("Invalid --clock-offset-ns option's argument:\n %s\n",
3748 arg);
c42c79ea
PP
3749 goto error;
3750 }
3751
3752 set_offset_value(&ctf_legacy_opts.offset_ns, val);
3753 break;
3754 }
3755 case OPT_STREAM_INTERSECTION:
3756 ctf_legacy_opts.stream_intersection = true;
3757 break;
3758 case OPT_CLOCK_FORCE_CORRELATE:
290725f7 3759 cfg->cmd_data.convert.force_correlate = true;
c42c79ea 3760 break;
0f9915c6
MD
3761 case OPT_BEGIN:
3762 if (!cur_cfg_comp) {
2703153b
PP
3763 printf_err("Cannot add `begin` parameter to unavailable default source component `%s`:\n %s\n",
3764 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3765 goto error;
3766 }
3767 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3768 printf_err("--begin option must follow a --source option:\n %s\n",
3769 arg);
0f9915c6
MD
3770 goto error;
3771 }
3772 if (bt_value_map_insert_string(cur_cfg_comp->params,
3773 "begin", arg)) {
3774 print_err_oom();
3775 goto error;
3776 }
3777 break;
3778 case OPT_END:
3779 if (!cur_cfg_comp) {
2703153b
PP
3780 printf_err("Cannot add `end` parameter to unavailable default source component `%s`:\n %s\n",
3781 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3782 goto error;
3783 }
3784 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3785 printf_err("--end option must follow a --source option:\n %s\n",
3786 arg);
0f9915c6
MD
3787 goto error;
3788 }
3789 if (bt_value_map_insert_string(cur_cfg_comp->params,
3790 "end", arg)) {
3791 print_err_oom();
3792 goto error;
3793 }
3794 break;
3795 case OPT_TIMERANGE:
3796 {
3797 const char *begin, *end;
3798
3799 if (!cur_cfg_comp) {
2703153b
PP
3800 printf_err("Cannot add `begin` and `end` parameters to unavailable default source component `%s`:\n %s\n",
3801 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3802 goto error;
3803 }
3804 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3805 printf_err("--timerange option must follow a --source option:\n %s\n",
3806 arg);
0f9915c6
MD
3807 goto error;
3808 }
3809 if (split_timerange(arg, &begin, &end)) {
2703153b
PP
3810 printf_err("Invalid --timerange format: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
3811 arg);
0f9915c6
MD
3812 goto error;
3813 }
3814 if (bt_value_map_insert_string(cur_cfg_comp->params,
3815 "begin", begin)) {
3816 print_err_oom();
3817 goto error;
3818 }
3819 if (bt_value_map_insert_string(cur_cfg_comp->params,
3820 "end", end)) {
3821 print_err_oom();
3822 goto error;
3823 }
3824 break;
3825 }
ebba3338
PP
3826 case OPT_CONNECT:
3827 if (bt_value_array_append_string(connection_args,
3828 arg)) {
3829 print_err_oom();
3830 goto error;
3831 }
3832 break;
c42c79ea 3833 case OPT_HELP:
290725f7
PP
3834 print_convert_usage(stdout);
3835 *retcode = -1;
3836 BT_PUT(cfg);
c42c79ea
PP
3837 goto end;
3838 case OPT_VERBOSE:
ae3b9aa4
PP
3839 if (got_verbose_opt) {
3840 printf_err("Duplicate -v option\n");
3841 goto error;
3842 }
3843
a263021c 3844 text_legacy_opts.verbose = true;
c42c79ea 3845 cfg->verbose = true;
ae3b9aa4 3846 got_verbose_opt = true;
c42c79ea
PP
3847 break;
3848 case OPT_DEBUG:
3849 cfg->debug = true;
3850 break;
3851 default:
3852 printf_err("Unknown command-line option specified (option code %d)\n",
3853 opt);
3854 goto error;
3855 }
3856
3857 free(arg);
3858 arg = NULL;
3859 }
3860
3861 /* Check for option parsing error */
3862 if (opt < -1) {
3863 printf_err("While parsing command-line options, at option %s: %s\n",
3864 poptBadOption(pc, 0), poptStrerror(opt));
3865 goto error;
3866 }
3867
3868 /* Consume leftover arguments as legacy input paths */
3869 while (true) {
3870 const char *input_path = poptGetArg(pc);
3871
3872 if (!input_path) {
3873 break;
3874 }
3875
3876 if (bt_value_array_append_string(legacy_input_paths,
3877 input_path)) {
3878 print_err_oom();
3879 goto error;
3880 }
3881 }
3882
290725f7
PP
3883 if (append_home_and_system_plugin_paths(
3884 cfg->cmd_data.convert.plugin_paths,
3885 cfg->cmd_data.convert.omit_system_plugin_path,
3886 cfg->cmd_data.convert.omit_home_plugin_path)) {
3887 printf_err("Cannot append home and system plugin paths\n");
6cf24c61
MD
3888 goto error;
3889 }
3890
3891 /* Append current component configuration, if any */
3892 if (cur_cfg_comp && !cur_is_implicit_source) {
3893 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
3894 }
3895 cur_cfg_comp = NULL;
3896
c42c79ea
PP
3897 /* Validate legacy/non-legacy options */
3898 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
3899 legacy_input_paths, &ctf_legacy_opts,
bd9f0fa2 3900 &text_legacy_opts)) {
c42c79ea
PP
3901 printf_err("Command-line options form an invalid configuration\n");
3902 goto error;
3903 }
3904
3905 /*
3906 * If there's a legacy input format, convert it to source
3907 * component configurations.
3908 */
3909 if (legacy_input_format) {
290725f7
PP
3910 if (append_sources_from_legacy_opts(
3911 cfg->cmd_data.convert.sources,
c42c79ea 3912 legacy_input_format, &ctf_legacy_opts,
528debdf 3913 legacy_input_paths)) {
49849a47 3914 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
3915 goto error;
3916 }
290725f7
PP
3917 if (append_sources_from_implicit_params(
3918 cfg->cmd_data.convert.sources,
bd9f0fa2
MD
3919 implicit_source_comp)) {
3920 printf_err("Cannot initialize legacy component parameters\n");
3921 goto error;
3922 }
3923 use_implicit_source = false;
3924 } else {
3925 if (use_implicit_source) {
3926 add_cfg_comp(cfg, implicit_source_comp,
3927 BT_CONFIG_COMPONENT_DEST_SOURCE);
3928 implicit_source_comp = NULL;
3929 } else {
3930 if (implicit_source_comp
3931 && !bt_value_map_is_empty(implicit_source_comp->params)) {
05a67631 3932 printf_err("Arguments specified for implicit input format, but an explicit source component instance has been specified: overriding it\n");
bd9f0fa2
MD
3933 goto error;
3934 }
3935 }
c42c79ea
PP
3936 }
3937
05a67631
PP
3938 /*
3939 * At this point if we need to print the CTF metadata text, we
3940 * don't care about the legacy/implicit sinks and component
3941 * connections.
3942 */
3943 if (cfg->cmd_data.convert.print_ctf_metadata) {
3944 goto end;
3945 }
3946
c42c79ea
PP
3947 /*
3948 * If there's a legacy output format, convert it to sink
3949 * component configurations.
3950 */
3951 if (legacy_output_format) {
290725f7 3952 if (append_sinks_from_legacy_opts(cfg->cmd_data.convert.sinks,
c42c79ea 3953 legacy_output_format, &text_legacy_opts)) {
49849a47 3954 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
3955 goto error;
3956 }
3957 }
3958
290725f7 3959 if (cfg->cmd_data.convert.sinks->len == 0) {
bd9f0fa2 3960 /* Use implicit sink as default. */
90de159b
PP
3961 cur_cfg_comp = bt_config_component_from_arg(
3962 BT_COMPONENT_CLASS_TYPE_SINK,
3963 DEFAULT_SINK_COMPONENT_NAME);
bd9f0fa2 3964 if (!cur_cfg_comp) {
2703153b 3965 printf_error("Cannot find implicit sink plugin `%s`\n",
bd9f0fa2
MD
3966 DEFAULT_SINK_COMPONENT_NAME);
3967 }
3968 add_cfg_comp(cfg, cur_cfg_comp,
3969 BT_CONFIG_COMPONENT_DEST_SINK);
3970 cur_cfg_comp = NULL;
3971 }
3972
ebba3338
PP
3973 ret = bt_config_create_connections(cfg, connection_args,
3974 error_buf, 256);
3975 if (ret) {
3976 printf_err("Cannot creation connections:\n%s", error_buf);
3977 goto error;
3978 }
3979
c42c79ea
PP
3980 goto end;
3981
3982error:
290725f7
PP
3983 *retcode = 1;
3984 BT_PUT(cfg);
3985
c42c79ea
PP
3986end:
3987 if (pc) {
3988 poptFreeContext(pc);
3989 }
3990
3991 if (text_legacy_opts.output) {
3992 g_string_free(text_legacy_opts.output, TRUE);
3993 }
3994
3995 if (text_legacy_opts.dbg_info_dir) {
3996 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
3997 }
3998
3999 if (text_legacy_opts.dbg_info_target_prefix) {
4000 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
4001 }
4002
4003 free(arg);
65582340 4004 BT_PUT(implicit_source_comp);
bdc61c70 4005 BT_PUT(cur_cfg_comp);
b07ffa28 4006 BT_PUT(cur_base_params);
c42c79ea
PP
4007 BT_PUT(text_legacy_opts.names);
4008 BT_PUT(text_legacy_opts.fields);
4009 BT_PUT(legacy_input_paths);
3b6cfcc5 4010 BT_PUT(instance_names);
ebba3338 4011 BT_PUT(connection_args);
290725f7
PP
4012 return cfg;
4013}
4014
4015/*
4016 * Prints the Babeltrace 2.x general usage.
4017 */
4018static
4019void print_gen_usage(FILE *fp)
4020{
4021 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
4022 fprintf(fp, "\n");
4023 fprintf(fp, "General options:\n");
4024 fprintf(fp, "\n");
4025 fprintf(fp, " -d, --debug Enable debug mode\n");
4026 fprintf(fp, " -h --help Show this help and quit\n");
4027 fprintf(fp, " --help-legacy Show Babeltrace 1.x legacy help and quit\n");
4028 fprintf(fp, " -v, --verbose Enable verbose output\n");
4029 fprintf(fp, " -V, --version Show version and quit\n");
4030 fprintf(fp, "\n");
4031 fprintf(fp, "Available commands:\n");
4032 fprintf(fp, "\n");
4033 fprintf(fp, " convert Build a trace conversion graph and run it (default)\n");
22e22462 4034 fprintf(fp, " help Get help for a plugin or a component class\n");
290725f7 4035 fprintf(fp, " list-plugins List available plugins and their content\n");
a67681c1 4036 fprintf(fp, " query Query objects from a component class\n");
290725f7
PP
4037 fprintf(fp, "\n");
4038 fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
4039}
4040
4041struct bt_config *bt_config_from_args(int argc, const char *argv[],
4042 int *retcode, bool omit_system_plugin_path,
4043 bool omit_home_plugin_path,
4044 struct bt_value *initial_plugin_paths)
4045{
4046 struct bt_config *config = NULL;
4047 bool verbose = false;
4048 bool debug = false;
4049 int i;
4050 enum bt_config_command command = -1;
4051 const char **command_argv = NULL;
4052 int command_argc = -1;
4053 const char *command_name = NULL;
4054
4055 *retcode = -1;
4056
4057 if (argc <= 1) {
4058 print_gen_usage(stdout);
4059 goto end;
4060 }
4061
4062 for (i = 1; i < argc; i++) {
4063 const char *cur_arg = argv[i];
4064
4065 if (strcmp(cur_arg, "-d") == 0 ||
4066 strcmp(cur_arg, "--debug") == 0) {
4067 debug = true;
4068 } else if (strcmp(cur_arg, "-v") == 0 ||
4069 strcmp(cur_arg, "--verbose") == 0) {
4070 verbose = true;
4071 } else if (strcmp(cur_arg, "-V") == 0 ||
4072 strcmp(cur_arg, "--version") == 0) {
4073 print_version();
4074 goto end;
4075 } else if (strcmp(cur_arg, "-h") == 0 ||
4076 strcmp(cur_arg, "--help") == 0) {
4077 print_gen_usage(stdout);
4078 goto end;
4079 } else if (strcmp(cur_arg, "--help-legacy") == 0) {
4080 print_legacy_usage(stdout);
4081 goto end;
4082 } else {
22e22462
PP
4083 bool has_command = true;
4084
290725f7
PP
4085 /*
4086 * First unknown argument: is it a known command
4087 * name?
4088 */
4089 if (strcmp(cur_arg, "convert") == 0) {
4090 command = BT_CONFIG_COMMAND_CONVERT;
290725f7
PP
4091 } else if (strcmp(cur_arg, "list-plugins") == 0) {
4092 command = BT_CONFIG_COMMAND_LIST_PLUGINS;
22e22462
PP
4093 } else if (strcmp(cur_arg, "help") == 0) {
4094 command = BT_CONFIG_COMMAND_HELP;
a67681c1
PP
4095 } else if (strcmp(cur_arg, "query") == 0) {
4096 command = BT_CONFIG_COMMAND_QUERY;
290725f7
PP
4097 } else {
4098 /*
4099 * Unknown argument, but not a known
4100 * command name: assume the whole
4101 * arguments are for the default convert
4102 * command.
4103 */
4104 command = BT_CONFIG_COMMAND_CONVERT;
4105 command_argv = argv;
4106 command_argc = argc;
22e22462
PP
4107 has_command = false;
4108 }
4109
4110 if (has_command) {
4111 command_argv = &argv[i];
4112 command_argc = argc - i;
4113 command_name = cur_arg;
290725f7
PP
4114 }
4115 break;
4116 }
4117 }
4118
4119 if ((int) command < 0) {
4120 /*
4121 * We only got non-help, non-version general options
4122 * like --verbose and --debug, without any other
4123 * arguments, so we can't do anything useful: print the
4124 * usage and quit.
4125 */
4126 print_gen_usage(stdout);
4127 goto end;
4128 }
4129
4130 assert(command_argv);
4131 assert(command_argc >= 0);
4132
4133 switch (command) {
4134 case BT_CONFIG_COMMAND_CONVERT:
4135 config = bt_config_convert_from_args(command_argc, command_argv,
4136 retcode, omit_system_plugin_path,
4137 omit_home_plugin_path, initial_plugin_paths);
4138 break;
4139 case BT_CONFIG_COMMAND_LIST_PLUGINS:
4140 config = bt_config_list_plugins_from_args(command_argc,
4141 command_argv, retcode, omit_system_plugin_path,
4142 omit_home_plugin_path, initial_plugin_paths);
4143 break;
22e22462
PP
4144 case BT_CONFIG_COMMAND_HELP:
4145 config = bt_config_help_from_args(command_argc,
4146 command_argv, retcode, omit_system_plugin_path,
4147 omit_home_plugin_path, initial_plugin_paths);
4148 break;
a67681c1
PP
4149 case BT_CONFIG_COMMAND_QUERY:
4150 config = bt_config_query_from_args(command_argc,
63ce0e1d
PP
4151 command_argv, retcode, omit_system_plugin_path,
4152 omit_home_plugin_path, initial_plugin_paths);
4153 break;
290725f7
PP
4154 default:
4155 assert(false);
4156 }
4157
4158 if (config) {
4159 if (verbose) {
4160 config->verbose = true;
4161 }
4162
4163 if (debug) {
4164 config->debug = true;
4165 }
4166
4167 config->command_name = command_name;
4168 }
4169
4170end:
4171 return config;
c42c79ea 4172}
This page took 0.236077 seconds and 4 git commands to generate.