babeltrace(1): escape '.' in PLUGIN.COMPCLS arguments
[babeltrace.git] / converter / babeltrace-cfg.c
CommitLineData
c42c79ea
PP
1/*
2 * Babeltrace trace converter - parameter parsing
3 *
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
29#include <stdio.h>
30#include <stdbool.h>
31#include <inttypes.h>
32#include <babeltrace/babeltrace.h>
1670bffd 33#include <babeltrace/common-internal.h>
c42c79ea
PP
34#include <babeltrace/values.h>
35#include <popt.h>
36#include <glib.h>
98ecef32
MD
37#include <sys/types.h>
38#include <pwd.h>
c42c79ea 39#include "babeltrace-cfg.h"
ebba3338 40#include "babeltrace-cfg-connect.h"
c42c79ea 41
65582340 42#define DEFAULT_SOURCE_COMPONENT_NAME "ctf.fs"
bd9f0fa2 43#define DEFAULT_SINK_COMPONENT_NAME "text.text"
65582340 44
c42c79ea
PP
45/*
46 * Error printf() macro which prepends "Error: " the first time it's
47 * called. This gives a nicer feel than having a bunch of error prefixes
48 * (since the following lines usually describe the error and possible
49 * solutions), or the error prefix just at the end.
50 */
51#define printf_err(fmt, args...) \
52 do { \
53 if (is_first_error) { \
54 fprintf(stderr, "Error: "); \
55 is_first_error = false; \
56 } \
57 fprintf(stderr, fmt, ##args); \
58 } while (0)
59
60static bool is_first_error = true;
61
62/* INI-style parsing FSM states */
63enum ini_parsing_fsm_state {
64 /* Expect a map key (identifier) */
65 INI_EXPECT_MAP_KEY,
66
67 /* Expect an equal character ('=') */
68 INI_EXPECT_EQUAL,
69
70 /* Expect a value */
71 INI_EXPECT_VALUE,
72
73 /* Expect a negative number value */
74 INI_EXPECT_VALUE_NUMBER_NEG,
75
76 /* Expect a comma character (',') */
77 INI_EXPECT_COMMA,
78};
79
80/* INI-style parsing state variables */
81struct ini_parsing_state {
82 /* Lexical scanner (owned by this) */
83 GScanner *scanner;
84
85 /* Output map value object being filled (owned by this) */
86 struct bt_value *params;
87
88 /* Next expected FSM state */
89 enum ini_parsing_fsm_state expecting;
90
91 /* Last decoded map key (owned by this) */
92 char *last_map_key;
93
94 /* Complete INI-style string to parse (not owned by this) */
95 const char *arg;
96
97 /* Error buffer (not owned by this) */
98 GString *ini_error;
99};
100
101/* Offset option with "is set" boolean */
102struct offset_opt {
103 int64_t value;
104 bool is_set;
105};
106
107/* Legacy "ctf"/"lttng-live" format options */
108struct ctf_legacy_opts {
109 struct offset_opt offset_s;
110 struct offset_opt offset_ns;
111 bool stream_intersection;
112};
113
114/* Legacy "text" format options */
115struct text_legacy_opts {
116 /*
117 * output, dbg_info_dir, dbg_info_target_prefix, names,
118 * and fields are owned by this.
119 */
120 GString *output;
121 GString *dbg_info_dir;
122 GString *dbg_info_target_prefix;
123 struct bt_value *names;
124 struct bt_value *fields;
125
126 /* Flags */
127 bool no_delta;
128 bool clock_cycles;
129 bool clock_seconds;
130 bool clock_date;
131 bool clock_gmt;
132 bool dbg_info_full_path;
a263021c 133 bool verbose;
c42c79ea
PP
134};
135
136/* Legacy input format format */
137enum legacy_input_format {
138 LEGACY_INPUT_FORMAT_NONE = 0,
139 LEGACY_INPUT_FORMAT_CTF,
140 LEGACY_INPUT_FORMAT_LTTNG_LIVE,
141};
142
143/* Legacy output format format */
144enum legacy_output_format {
145 LEGACY_OUTPUT_FORMAT_NONE = 0,
146 LEGACY_OUTPUT_FORMAT_TEXT,
c42c79ea
PP
147 LEGACY_OUTPUT_FORMAT_DUMMY,
148};
149
150/*
151 * Prints the "out of memory" error.
152 */
153static
154void print_err_oom(void)
155{
156 printf_err("Out of memory\n");
157}
158
159/*
160 * Prints duplicate legacy output format error.
161 */
162static
163void print_err_dup_legacy_output(void)
164{
165 printf_err("More than one legacy output format specified\n");
166}
167
168/*
169 * Prints duplicate legacy input format error.
170 */
171static
172void print_err_dup_legacy_input(void)
173{
174 printf_err("More than one legacy input format specified\n");
175}
176
177/*
178 * Checks if any of the "text" legacy options is set.
179 */
180static
181bool text_legacy_opts_is_any_set(struct text_legacy_opts *opts)
182{
183 return (opts->output && opts->output->len > 0) ||
184 (opts->dbg_info_dir && opts->dbg_info_dir->len > 0) ||
185 (opts->dbg_info_target_prefix &&
186 opts->dbg_info_target_prefix->len > 0) ||
187 bt_value_array_size(opts->names) > 0 ||
188 bt_value_array_size(opts->fields) > 0 ||
189 opts->no_delta || opts->clock_cycles || opts->clock_seconds ||
a263021c 190 opts->clock_date || opts->clock_gmt || opts->verbose ||
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,
2107 BT_CONFIG_COMPONENT_DEST_SINK,
2108};
2109
2110/*
2111 * Adds a configuration component to the appropriate configuration
2112 * array depending on the destination.
2113 */
2114static void add_cfg_comp(struct bt_config *cfg,
2115 struct bt_config_component *cfg_comp,
2116 enum bt_config_component_dest dest)
2117{
2118 if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
290725f7 2119 g_ptr_array_add(cfg->cmd_data.convert.sources, cfg_comp);
bdc61c70 2120 } else {
290725f7 2121 g_ptr_array_add(cfg->cmd_data.convert.sinks, cfg_comp);
bdc61c70
PP
2122 }
2123}
2124
0f9915c6
MD
2125static int split_timerange(const char *arg, const char **begin, const char **end)
2126{
2127 const char *c;
2128
2129 /* Try to match [begin,end] */
2130 c = strchr(arg, '[');
2131 if (!c)
2132 goto skip;
2133 *begin = ++c;
2134 c = strchr(c, ',');
2135 if (!c)
2136 goto skip;
2137 *end = ++c;
2138 c = strchr(c, ']');
2139 if (!c)
2140 goto skip;
2141 goto found;
2142
2143skip:
2144 /* Try to match begin,end */
2145 c = arg;
2146 *begin = c;
2147 c = strchr(c, ',');
2148 if (!c)
2149 goto not_found;
2150 *end = ++c;
2151 /* fall-through */
2152found:
2153 return 0;
2154not_found:
2155 return -1;
2156}
2157
290725f7 2158static int append_env_var_plugin_paths(struct bt_value *plugin_paths)
5a3ee633
PP
2159{
2160 int ret = 0;
2161 const char *envvar;
2162
2163 if (bt_common_is_setuid_setgid()) {
2164 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2165 goto end;
2166 }
2167
2168 envvar = getenv("BABELTRACE_PLUGIN_PATH");
2169 if (!envvar) {
2170 goto end;
2171 }
2172
290725f7 2173 ret = bt_config_append_plugin_paths(plugin_paths, envvar);
5a3ee633
PP
2174
2175end:
2176 return ret;
2177}
2178
290725f7
PP
2179static int append_home_and_system_plugin_paths(struct bt_value *plugin_paths,
2180 bool omit_system_plugin_path, bool omit_home_plugin_path)
98ecef32 2181{
1670bffd 2182 int ret;
98ecef32 2183
290725f7 2184 if (!omit_home_plugin_path) {
1670bffd 2185 if (bt_common_is_setuid_setgid()) {
5a3ee633 2186 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
98ecef32 2187 } else {
1670bffd
PP
2188 char *home_plugin_dir =
2189 bt_common_get_home_plugin_path();
2190
2191 if (home_plugin_dir) {
290725f7
PP
2192 ret = bt_config_append_plugin_paths(
2193 plugin_paths,
1670bffd
PP
2194 home_plugin_dir);
2195 free(home_plugin_dir);
2196
2197 if (ret) {
98ecef32
MD
2198 printf_err("Invalid home plugin path\n");
2199 goto error;
2200 }
2201 }
2202 }
2203 }
2204
290725f7
PP
2205 if (!omit_system_plugin_path) {
2206 if (bt_config_append_plugin_paths(plugin_paths,
1670bffd 2207 bt_common_get_system_plugin_path())) {
98ecef32
MD
2208 printf_err("Invalid system plugin path\n");
2209 goto error;
2210 }
2211 }
2212 return 0;
2213error:
2214 return -1;
2215}
2216
bd9f0fa2
MD
2217static int append_sources_from_implicit_params(GPtrArray *sources,
2218 struct bt_config_component *implicit_source_comp)
2219{
2220 size_t i;
2221 size_t len = sources->len;
2222
2223 for (i = 0; i < len; i++) {
2224 struct bt_config_component *comp;
2225 struct bt_value *params_to_set;
2226
2227 comp = g_ptr_array_index(sources, i);
2228 params_to_set = bt_value_map_extend(comp->params,
2229 implicit_source_comp->params);
2230 if (!params_to_set) {
2231 printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
2232 goto error;
2233 }
2234 BT_MOVE(comp->params, params_to_set);
2235 }
2236 return 0;
2237error:
2238 return -1;
2239}
2240
290725f7 2241static struct bt_config *bt_config_base_create(enum bt_config_command command)
c1870f57
JG
2242{
2243 struct bt_config *cfg;
2244
2245 /* Create config */
2246 cfg = g_new0(struct bt_config, 1);
2247 if (!cfg) {
2248 print_err_oom();
2249 goto error;
2250 }
2251
2252 bt_object_init(cfg, bt_config_destroy);
290725f7
PP
2253 cfg->command = command;
2254 goto end;
c1870f57 2255
290725f7
PP
2256error:
2257 BT_PUT(cfg);
c1870f57 2258
c1870f57
JG
2259end:
2260 return cfg;
c1870f57
JG
2261}
2262
290725f7
PP
2263static struct bt_config *bt_config_convert_create(
2264 struct bt_value *initial_plugin_paths)
c42c79ea 2265{
290725f7 2266 struct bt_config *cfg;
c42c79ea 2267
290725f7
PP
2268 /* Create config */
2269 cfg = bt_config_base_create(BT_CONFIG_COMMAND_CONVERT);
2270 if (!cfg) {
c42c79ea
PP
2271 print_err_oom();
2272 goto error;
2273 }
2274
290725f7
PP
2275 cfg->cmd_data.convert.sources = g_ptr_array_new_with_free_func(
2276 (GDestroyNotify) bt_put);
2277 if (!cfg->cmd_data.convert.sources) {
c42c79ea
PP
2278 print_err_oom();
2279 goto error;
2280 }
2281
ebba3338
PP
2282 cfg->cmd_data.convert.filters = g_ptr_array_new_with_free_func(
2283 (GDestroyNotify) bt_put);
2284 if (!cfg->cmd_data.convert.filters) {
2285 print_err_oom();
2286 goto error;
2287 }
2288
290725f7
PP
2289 cfg->cmd_data.convert.sinks = g_ptr_array_new_with_free_func(
2290 (GDestroyNotify) bt_put);
2291 if (!cfg->cmd_data.convert.sinks) {
c42c79ea
PP
2292 print_err_oom();
2293 goto error;
2294 }
2295
ebba3338
PP
2296 cfg->cmd_data.convert.connections = g_ptr_array_new_with_free_func(
2297 (GDestroyNotify) bt_config_connection_destroy);
2298 if (!cfg->cmd_data.convert.connections) {
2299 print_err_oom();
2300 goto error;
2301 }
2302
290725f7
PP
2303 if (initial_plugin_paths) {
2304 cfg->cmd_data.convert.plugin_paths =
2305 bt_get(initial_plugin_paths);
2306 } else {
2307 cfg->cmd_data.convert.plugin_paths = bt_value_array_create();
2308 if (!cfg->cmd_data.convert.plugin_paths) {
2309 print_err_oom();
2310 goto error;
2311 }
b07ffa28
PP
2312 }
2313
290725f7 2314 goto end;
c42c79ea 2315
290725f7
PP
2316error:
2317 BT_PUT(cfg);
2318
2319end:
2320 return cfg;
2321}
2322
2323static struct bt_config *bt_config_list_plugins_create(
2324 struct bt_value *initial_plugin_paths)
2325{
2326 struct bt_config *cfg;
2327
2328 /* Create config */
2329 cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS);
2330 if (!cfg) {
2331 print_err_oom();
5a3ee633
PP
2332 goto error;
2333 }
2334
290725f7
PP
2335 if (initial_plugin_paths) {
2336 cfg->cmd_data.list_plugins.plugin_paths =
2337 bt_get(initial_plugin_paths);
65582340 2338 } else {
290725f7
PP
2339 cfg->cmd_data.list_plugins.plugin_paths =
2340 bt_value_array_create();
2341 if (!cfg->cmd_data.list_plugins.plugin_paths) {
2342 print_err_oom();
2343 goto error;
2344 }
c42c79ea
PP
2345 }
2346
290725f7
PP
2347 goto end;
2348
2349error:
2350 BT_PUT(cfg);
2351
2352end:
2353 return cfg;
2354}
2355
22e22462
PP
2356static struct bt_config *bt_config_help_create(
2357 struct bt_value *initial_plugin_paths)
2358{
2359 struct bt_config *cfg;
2360
2361 /* Create config */
2362 cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP);
2363 if (!cfg) {
2364 print_err_oom();
2365 goto error;
2366 }
2367
2368 if (initial_plugin_paths) {
2369 cfg->cmd_data.help.plugin_paths =
2370 bt_get(initial_plugin_paths);
2371 } else {
2372 cfg->cmd_data.help.plugin_paths =
2373 bt_value_array_create();
2374 if (!cfg->cmd_data.help.plugin_paths) {
2375 print_err_oom();
2376 goto error;
2377 }
2378 }
2379
90de159b
PP
2380 cfg->cmd_data.help.cfg_component =
2381 bt_config_component_create(BT_COMPONENT_CLASS_TYPE_UNKNOWN,
2382 NULL, NULL);
2383 if (!cfg->cmd_data.help.cfg_component) {
22e22462
PP
2384 print_err_oom();
2385 goto error;
2386 }
2387
2388 goto end;
2389
2390error:
2391 BT_PUT(cfg);
2392
2393end:
2394 return cfg;
2395}
2396
a67681c1 2397static struct bt_config *bt_config_query_create(
63ce0e1d
PP
2398 struct bt_value *initial_plugin_paths)
2399{
2400 struct bt_config *cfg;
2401
2402 /* Create config */
a67681c1 2403 cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY);
63ce0e1d
PP
2404 if (!cfg) {
2405 print_err_oom();
2406 goto error;
2407 }
2408
2409 if (initial_plugin_paths) {
a67681c1 2410 cfg->cmd_data.query.plugin_paths =
63ce0e1d
PP
2411 bt_get(initial_plugin_paths);
2412 } else {
a67681c1 2413 cfg->cmd_data.query.plugin_paths =
63ce0e1d 2414 bt_value_array_create();
a67681c1 2415 if (!cfg->cmd_data.query.plugin_paths) {
63ce0e1d
PP
2416 print_err_oom();
2417 goto error;
2418 }
2419 }
2420
a67681c1
PP
2421 cfg->cmd_data.query.object = g_string_new(NULL);
2422 if (!cfg->cmd_data.query.object) {
63ce0e1d
PP
2423 print_err_oom();
2424 goto error;
2425 }
2426
2427 goto end;
2428
2429error:
2430 BT_PUT(cfg);
2431
2432end:
2433 return cfg;
2434}
2435
2436/*
2437 * Prints the expected format for a --params option.
2438 */
2439static
2440void print_expected_params_format(FILE *fp)
2441{
2442 fprintf(fp, "Expected format of PARAMS\n");
2443 fprintf(fp, "-------------------------\n");
2444 fprintf(fp, "\n");
2445 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
2446 fprintf(fp, "\n");
2447 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
2448 fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
2449 fprintf(fp, "VALUE can be one of:\n");
2450 fprintf(fp, "\n");
2451 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
2452 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
2453 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
2454 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
2455 fprintf(fp, " (`0x` prefix) signed 64-bit integer.\n");
2456 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
2457 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
2458 fprintf(fp, " the null and boolean value symbols above.\n");
2459 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
2460 fprintf(fp, "\n");
2461 fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
2462 fprintf(fp, "\n");
2463 fprintf(fp, "Example:\n");
2464 fprintf(fp, "\n");
2465 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
2466 fprintf(fp, " observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
2467 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
2468 fprintf(fp, "\n");
2469 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
2470 fprintf(fp, "from a shell.\n");
2471}
2472
2473
22e22462
PP
2474/*
2475 * Prints the help command usage.
2476 */
2477static
2478void print_help_usage(FILE *fp)
2479{
2480 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
63ce0e1d
PP
2481 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --source=PLUGIN.COMPCLS\n");
2482 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --filter=PLUGIN.COMPCLS\n");
2483 fprintf(fp, " babeltrace [GENERAL OPTIONS] help [OPTIONS] --sink=PLUGIN.COMPCLS\n");
22e22462
PP
2484 fprintf(fp, "\n");
2485 fprintf(fp, "Options:\n");
2486 fprintf(fp, "\n");
2487 fprintf(fp, " --filter=PLUGIN.COMPCLS Get help for the filter component class\n");
2488 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2489 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2490 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2491 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2492 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2493 fprintf(fp, " dynamic plugins can be loaded\n");
2494 fprintf(fp, " --sink=PLUGIN.COMPCLS Get help for the sink component class\n");
2495 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2496 fprintf(fp, " --source=PLUGIN.COMPCLS Get help for the source component class\n");
2497 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
2498 fprintf(fp, " -h --help Show this help and quit\n");
2499 fprintf(fp, "\n");
2500 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
2501 fprintf(fp, "\n");
2502 fprintf(fp, "Use `babeltrace list-plugins` to show the list of available plugins.\n");
2503}
2504
2505static struct poptOption help_long_options[] = {
2506 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2507 { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, NULL, NULL },
2508 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2509 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2510 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2511 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2512 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2513 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2514 { NULL, 0, 0, NULL, 0, NULL, NULL },
2515};
2516
2517/*
2518 * Creates a Babeltrace config object from the arguments of a help
2519 * command.
2520 *
2521 * *retcode is set to the appropriate exit code to use.
2522 */
2523struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
2524 int *retcode, bool omit_system_plugin_path,
2525 bool omit_home_plugin_path,
2526 struct bt_value *initial_plugin_paths)
2527{
2528 poptContext pc = NULL;
2529 char *arg = NULL;
2530 int opt;
2531 int ret;
2532 struct bt_config *cfg = NULL;
2533 const char *leftover;
2534 char *plugin_name = NULL, *component_name = NULL;
2535 char *plugin_comp_cls_names = NULL;
2536
2537 *retcode = 0;
2538 cfg = bt_config_help_create(initial_plugin_paths);
2539 if (!cfg) {
2540 print_err_oom();
2541 goto error;
2542 }
2543
22e22462
PP
2544 cfg->cmd_data.help.omit_system_plugin_path = omit_system_plugin_path;
2545 cfg->cmd_data.help.omit_home_plugin_path = omit_home_plugin_path;
2546 ret = append_env_var_plugin_paths(cfg->cmd_data.help.plugin_paths);
2547 if (ret) {
2548 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2549 goto error;
2550 }
2551
2552 /* Parse options */
2553 pc = poptGetContext(NULL, argc, (const char **) argv,
2554 help_long_options, 0);
2555 if (!pc) {
2556 printf_err("Cannot get popt context\n");
2557 goto error;
2558 }
2559
2560 poptReadDefaultConfig(pc, 0);
2561
2562 while ((opt = poptGetNextOpt(pc)) > 0) {
2563 arg = poptGetOptArg(pc);
2564
2565 switch (opt) {
2566 case OPT_PLUGIN_PATH:
2567 if (bt_common_is_setuid_setgid()) {
2568 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2569 } else {
2570 if (bt_config_append_plugin_paths(
2571 cfg->cmd_data.help.plugin_paths,
2572 arg)) {
2573 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2574 arg);
2575 goto error;
2576 }
2577 }
2578 break;
2579 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
2580 cfg->cmd_data.help.omit_system_plugin_path = true;
2581 break;
2582 case OPT_OMIT_HOME_PLUGIN_PATH:
2583 cfg->cmd_data.help.omit_home_plugin_path = true;
2584 break;
2585 case OPT_SOURCE:
2586 case OPT_FILTER:
2587 case OPT_SINK:
90de159b 2588 if (cfg->cmd_data.help.cfg_component->type !=
22e22462
PP
2589 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2590 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2591 arg);
2592 goto error;
2593 }
2594
2595 switch (opt) {
2596 case OPT_SOURCE:
90de159b 2597 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2598 BT_COMPONENT_CLASS_TYPE_SOURCE;
2599 break;
2600 case OPT_FILTER:
90de159b 2601 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2602 BT_COMPONENT_CLASS_TYPE_FILTER;
2603 break;
2604 case OPT_SINK:
90de159b 2605 cfg->cmd_data.help.cfg_component->type =
22e22462
PP
2606 BT_COMPONENT_CLASS_TYPE_SINK;
2607 break;
2608 default:
2609 assert(false);
2610 }
2611 plugin_comp_cls_names = strdup(arg);
2612 if (!plugin_comp_cls_names) {
2613 print_err_oom();
2614 goto error;
2615 }
2616 break;
2617 case OPT_HELP:
2618 print_help_usage(stdout);
2619 *retcode = -1;
2620 BT_PUT(cfg);
2621 goto end;
2622 default:
2623 printf_err("Unknown command-line option specified (option code %d)\n",
2624 opt);
2625 goto error;
2626 }
2627
2628 free(arg);
2629 arg = NULL;
2630 }
2631
2632 /* Check for option parsing error */
2633 if (opt < -1) {
2634 printf_err("While parsing command-line options, at option %s: %s\n",
2635 poptBadOption(pc, 0), poptStrerror(opt));
2636 goto error;
2637 }
2638
2639 leftover = poptGetArg(pc);
2640 if (leftover) {
90de159b 2641 if (cfg->cmd_data.help.cfg_component->type !=
22e22462
PP
2642 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2643 printf_err("Cannot specify plugin name and --source/--filter/--sink component class:\n %s\n",
2644 leftover);
2645 goto error;
2646 }
2647
90de159b
PP
2648 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
2649 leftover);
22e22462 2650 } else {
90de159b 2651 if (cfg->cmd_data.help.cfg_component->type ==
22e22462
PP
2652 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
2653 print_help_usage(stdout);
2654 *retcode = -1;
2655 BT_PUT(cfg);
2656 goto end;
2657 }
2658
2659 plugin_component_names_from_arg(plugin_comp_cls_names,
2660 &plugin_name, &component_name);
2661 if (plugin_name && component_name) {
90de159b
PP
2662 g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
2663 plugin_name);
2664 g_string_assign(cfg->cmd_data.help.cfg_component->component_name,
22e22462
PP
2665 component_name);
2666 } else {
2667 printf_err("Invalid --source/--filter/--sink option's argument:\n %s\n",
2668 plugin_comp_cls_names);
2669 goto error;
2670 }
2671 }
2672
2673 if (append_home_and_system_plugin_paths(
2674 cfg->cmd_data.help.plugin_paths,
2675 cfg->cmd_data.help.omit_system_plugin_path,
2676 cfg->cmd_data.help.omit_home_plugin_path)) {
2677 printf_err("Cannot append home and system plugin paths\n");
2678 goto error;
2679 }
2680
2681 goto end;
2682
2683error:
2684 *retcode = 1;
2685 BT_PUT(cfg);
2686
2687end:
2688 free(plugin_comp_cls_names);
2689 g_free(plugin_name);
2690 g_free(component_name);
2691
2692 if (pc) {
2693 poptFreeContext(pc);
2694 }
2695
2696 free(arg);
2697 return cfg;
2698}
2699
63ce0e1d
PP
2700/*
2701 * Prints the help command usage.
2702 */
2703static
a67681c1 2704void print_query_usage(FILE *fp)
63ce0e1d 2705{
a67681c1
PP
2706 fprintf(fp, "Usage: babeltrace [GEN OPTS] query [OPTS] OBJECT --source=PLUGIN.COMPCLS\n");
2707 fprintf(fp, " babeltrace [GEN OPTS] query [OPTS] OBJECT --filter=PLUGIN.COMPCLS\n");
2708 fprintf(fp, " babeltrace [GEN OPTS] query [OPTS] OBJECT --sink=PLUGIN.COMPCLS\n");
63ce0e1d
PP
2709 fprintf(fp, "\n");
2710 fprintf(fp, "Options:\n");
2711 fprintf(fp, "\n");
a67681c1
PP
2712 fprintf(fp, " --filter=PLUGIN.COMPCLS Query object from the filter component\n");
2713 fprintf(fp, " class COMPCLS found in the plugin PLUGIN\n");
63ce0e1d
PP
2714 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2715 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2716 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2717 fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS\n");
2718 fprintf(fp, " (see the expected format of PARAMS below)\n");
2719 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2720 fprintf(fp, " dynamic plugins can be loaded\n");
a67681c1 2721 fprintf(fp, " --sink=PLUGIN.COMPCLS Query object from the sink component class\n");
63ce0e1d 2722 fprintf(fp, " COMPCLS found in the plugin PLUGIN\n");
a67681c1
PP
2723 fprintf(fp, " --source=PLUGIN.COMPCLS Query object from the source component\n");
2724 fprintf(fp, " class COMPCLS found in the plugin PLUGIN\n");
63ce0e1d
PP
2725 fprintf(fp, " -h --help Show this help and quit\n");
2726 fprintf(fp, "\n\n");
2727 print_expected_params_format(fp);
2728}
2729
a67681c1 2730static struct poptOption query_long_options[] = {
63ce0e1d
PP
2731 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2732 { "filter", '\0', POPT_ARG_STRING, NULL, OPT_FILTER, NULL, NULL },
2733 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2734 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2735 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2736 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
2737 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2738 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
2739 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
2740 { NULL, 0, 0, NULL, 0, NULL, NULL },
2741};
2742
2743/*
a67681c1 2744 * Creates a Babeltrace config object from the arguments of a query
63ce0e1d
PP
2745 * command.
2746 *
2747 * *retcode is set to the appropriate exit code to use.
2748 */
a67681c1 2749struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
63ce0e1d
PP
2750 int *retcode, bool omit_system_plugin_path,
2751 bool omit_home_plugin_path,
2752 struct bt_value *initial_plugin_paths)
2753{
2754 poptContext pc = NULL;
2755 char *arg = NULL;
2756 int opt;
2757 int ret;
2758 struct bt_config *cfg = NULL;
2759 const char *leftover;
2760 struct bt_value *params = bt_value_null;
2761
2762 *retcode = 0;
a67681c1 2763 cfg = bt_config_query_create(initial_plugin_paths);
63ce0e1d
PP
2764 if (!cfg) {
2765 print_err_oom();
2766 goto error;
2767 }
2768
a67681c1 2769 cfg->cmd_data.query.omit_system_plugin_path =
63ce0e1d 2770 omit_system_plugin_path;
a67681c1
PP
2771 cfg->cmd_data.query.omit_home_plugin_path = omit_home_plugin_path;
2772 ret = append_env_var_plugin_paths(cfg->cmd_data.query.plugin_paths);
63ce0e1d
PP
2773 if (ret) {
2774 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
2775 goto error;
2776 }
2777
2778 /* Parse options */
2779 pc = poptGetContext(NULL, argc, (const char **) argv,
a67681c1 2780 query_long_options, 0);
63ce0e1d
PP
2781 if (!pc) {
2782 printf_err("Cannot get popt context\n");
2783 goto error;
2784 }
2785
2786 poptReadDefaultConfig(pc, 0);
2787
2788 while ((opt = poptGetNextOpt(pc)) > 0) {
2789 arg = poptGetOptArg(pc);
2790
2791 switch (opt) {
2792 case OPT_PLUGIN_PATH:
2793 if (bt_common_is_setuid_setgid()) {
2794 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
2795 } else {
2796 if (bt_config_append_plugin_paths(
a67681c1 2797 cfg->cmd_data.query.plugin_paths,
63ce0e1d
PP
2798 arg)) {
2799 printf_err("Invalid --plugin-path option's argument:\n %s\n",
2800 arg);
2801 goto error;
2802 }
2803 }
2804 break;
2805 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
a67681c1 2806 cfg->cmd_data.query.omit_system_plugin_path = true;
63ce0e1d
PP
2807 break;
2808 case OPT_OMIT_HOME_PLUGIN_PATH:
a67681c1 2809 cfg->cmd_data.query.omit_home_plugin_path = true;
63ce0e1d
PP
2810 break;
2811 case OPT_SOURCE:
2812 case OPT_FILTER:
2813 case OPT_SINK:
2814 {
2815 enum bt_component_class_type type;
2816
a67681c1 2817 if (cfg->cmd_data.query.cfg_component) {
63ce0e1d
PP
2818 printf_err("Cannot specify more than one plugin and component class:\n %s\n",
2819 arg);
2820 goto error;
2821 }
2822
2823 switch (opt) {
2824 case OPT_SOURCE:
2825 type = BT_COMPONENT_CLASS_TYPE_SOURCE;
2826 break;
2827 case OPT_FILTER:
2828 type = BT_COMPONENT_CLASS_TYPE_FILTER;
2829 break;
2830 case OPT_SINK:
2831 type = BT_COMPONENT_CLASS_TYPE_SINK;
2832 break;
2833 default:
2834 assert(false);
2835 }
2836
a67681c1 2837 cfg->cmd_data.query.cfg_component =
63ce0e1d 2838 bt_config_component_from_arg(type, arg);
a67681c1 2839 if (!cfg->cmd_data.query.cfg_component) {
63ce0e1d
PP
2840 printf_err("Invalid format for --source/--filter/--sink option's argument:\n %s\n",
2841 arg);
2842 goto error;
2843 }
2844
2845 /* Default parameters: null */
a67681c1
PP
2846 bt_put(cfg->cmd_data.query.cfg_component->params);
2847 cfg->cmd_data.query.cfg_component->params =
63ce0e1d
PP
2848 bt_value_null;
2849 break;
2850 }
2851 case OPT_PARAMS:
2852 {
2853 params = bt_value_from_arg(arg);
2854 if (!params) {
2855 printf_err("Invalid format for --params option's argument:\n %s\n",
2856 arg);
2857 goto error;
2858 }
2859 break;
2860 }
2861 case OPT_HELP:
a67681c1 2862 print_query_usage(stdout);
63ce0e1d
PP
2863 *retcode = -1;
2864 BT_PUT(cfg);
2865 goto end;
2866 default:
2867 printf_err("Unknown command-line option specified (option code %d)\n",
2868 opt);
2869 goto error;
2870 }
2871
2872 free(arg);
2873 arg = NULL;
2874 }
2875
a67681c1 2876 if (!cfg->cmd_data.query.cfg_component) {
63ce0e1d
PP
2877 printf_err("No target component class specified with --source/--filter/--sink option\n");
2878 goto error;
2879 }
2880
2881 assert(params);
a67681c1 2882 BT_MOVE(cfg->cmd_data.query.cfg_component->params, params);
63ce0e1d
PP
2883
2884 /* Check for option parsing error */
2885 if (opt < -1) {
2886 printf_err("While parsing command-line options, at option %s: %s\n",
2887 poptBadOption(pc, 0), poptStrerror(opt));
2888 goto error;
2889 }
2890
2891 /*
2892 * We need exactly one leftover argument which is the
a67681c1 2893 * mandatory object.
63ce0e1d
PP
2894 */
2895 leftover = poptGetArg(pc);
2896 if (leftover) {
2897 if (strlen(leftover) == 0) {
a67681c1 2898 printf_err("Invalid empty object\n");
63ce0e1d
PP
2899 goto error;
2900 }
2901
a67681c1 2902 g_string_assign(cfg->cmd_data.query.object, leftover);
63ce0e1d 2903 } else {
a67681c1 2904 print_query_usage(stdout);
63ce0e1d
PP
2905 *retcode = -1;
2906 BT_PUT(cfg);
2907 goto end;
2908 }
2909
2910 leftover = poptGetArg(pc);
2911 if (leftover) {
2912 printf_err("Invalid argument: %s\n", leftover);
2913 goto error;
2914 }
2915
2916 if (append_home_and_system_plugin_paths(
a67681c1
PP
2917 cfg->cmd_data.query.plugin_paths,
2918 cfg->cmd_data.query.omit_system_plugin_path,
2919 cfg->cmd_data.query.omit_home_plugin_path)) {
63ce0e1d
PP
2920 printf_err("Cannot append home and system plugin paths\n");
2921 goto error;
2922 }
2923
2924 goto end;
2925
2926error:
2927 *retcode = 1;
2928 BT_PUT(cfg);
2929
2930end:
2931 if (pc) {
2932 poptFreeContext(pc);
2933 }
2934
2935 BT_PUT(params);
2936 free(arg);
2937 return cfg;
2938}
2939
290725f7
PP
2940/*
2941 * Prints the list-plugins command usage.
2942 */
2943static
2944void print_list_plugins_usage(FILE *fp)
2945{
2946 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
2947 fprintf(fp, "\n");
2948 fprintf(fp, "Options:\n");
2949 fprintf(fp, "\n");
2950 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2951 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
2952 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2953 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2954 fprintf(fp, " dynamic plugins can be loaded\n");
2955 fprintf(fp, " -h --help Show this help and quit\n");
2956 fprintf(fp, "\n");
2957 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
22e22462
PP
2958 fprintf(fp, "\n");
2959 fprintf(fp, "Use `babeltrace help` to get help for a specific plugin or component class.\n");
290725f7
PP
2960}
2961
2962static struct poptOption list_plugins_long_options[] = {
2963 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
2964 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
2965 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
2966 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
2967 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
2968 { NULL, 0, 0, NULL, 0, NULL, NULL },
2969};
2970
2971/*
2972 * Creates a Babeltrace config object from the arguments of a
2973 * list-plugins command.
2974 *
2975 * *retcode is set to the appropriate exit code to use.
2976 */
2977struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
2978 int *retcode, bool omit_system_plugin_path,
2979 bool omit_home_plugin_path,
2980 struct bt_value *initial_plugin_paths)
2981{
2982 poptContext pc = NULL;
2983 char *arg = NULL;
2984 int opt;
2985 int ret;
2986 struct bt_config *cfg = NULL;
2987 const char *leftover;
2988
2989 *retcode = 0;
2990 cfg = bt_config_list_plugins_create(initial_plugin_paths);
2991 if (!cfg) {
2992 print_err_oom();
2993 goto error;
2994 }
2995
2996 cfg->cmd_data.list_plugins.omit_system_plugin_path = omit_system_plugin_path;
2997 cfg->cmd_data.list_plugins.omit_home_plugin_path = omit_home_plugin_path;
2998 ret = append_env_var_plugin_paths(
2999 cfg->cmd_data.list_plugins.plugin_paths);
3000 if (ret) {
3001 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3002 goto error;
3003 }
3004
3005 /* Parse options */
3006 pc = poptGetContext(NULL, argc, (const char **) argv,
3007 list_plugins_long_options, 0);
3008 if (!pc) {
3009 printf_err("Cannot get popt context\n");
3010 goto error;
3011 }
3012
3013 poptReadDefaultConfig(pc, 0);
c42c79ea
PP
3014
3015 while ((opt = poptGetNextOpt(pc)) > 0) {
3016 arg = poptGetOptArg(pc);
3017
3018 switch (opt) {
3019 case OPT_PLUGIN_PATH:
5a3ee633
PP
3020 if (bt_common_is_setuid_setgid()) {
3021 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
98ecef32 3022 } else {
290725f7
PP
3023 if (bt_config_append_plugin_paths(
3024 cfg->cmd_data.list_plugins.plugin_paths,
3025 arg)) {
2703153b
PP
3026 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3027 arg);
98ecef32
MD
3028 goto error;
3029 }
c42c79ea
PP
3030 }
3031 break;
98ecef32 3032 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
290725f7 3033 cfg->cmd_data.list_plugins.omit_system_plugin_path = true;
98ecef32
MD
3034 break;
3035 case OPT_OMIT_HOME_PLUGIN_PATH:
290725f7
PP
3036 cfg->cmd_data.list_plugins.omit_home_plugin_path = true;
3037 break;
3038 case OPT_HELP:
3039 print_list_plugins_usage(stdout);
3040 *retcode = -1;
3041 BT_PUT(cfg);
3042 goto end;
3043 default:
3044 printf_err("Unknown command-line option specified (option code %d)\n",
3045 opt);
3046 goto error;
3047 }
3048
3049 free(arg);
3050 arg = NULL;
3051 }
3052
3053 /* Check for option parsing error */
3054 if (opt < -1) {
3055 printf_err("While parsing command-line options, at option %s: %s\n",
3056 poptBadOption(pc, 0), poptStrerror(opt));
3057 goto error;
3058 }
3059
3060 leftover = poptGetArg(pc);
3061 if (leftover) {
3062 printf_err("Invalid argument: %s\n", leftover);
3063 goto error;
3064 }
3065
3066 if (append_home_and_system_plugin_paths(
3067 cfg->cmd_data.list_plugins.plugin_paths,
3068 cfg->cmd_data.list_plugins.omit_system_plugin_path,
3069 cfg->cmd_data.list_plugins.omit_home_plugin_path)) {
3070 printf_err("Cannot append home and system plugin paths\n");
3071 goto error;
3072 }
3073
3074 goto end;
3075
3076error:
3077 *retcode = 1;
3078 BT_PUT(cfg);
3079
3080end:
3081 if (pc) {
3082 poptFreeContext(pc);
3083 }
3084
3085 free(arg);
3086 return cfg;
3087}
3088
290725f7
PP
3089/*
3090 * Prints the legacy, Babeltrace 1.x command usage. Those options are
3091 * still compatible in Babeltrace 2.x, but it is recommended to use
3092 * the more generic plugin/component parameters instead of those
3093 * hard-coded option names.
3094 */
3095static
3096void print_legacy_usage(FILE *fp)
3097{
3098 fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
3099 fprintf(fp, "\n");
3100 fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
3101 fprintf(fp, "\n");
3102 fprintf(fp, " --clock-force-correlate Assume that clocks are inherently correlated\n");
3103 fprintf(fp, " across traces\n");
3104 fprintf(fp, " -d, --debug Enable debug mode\n");
3105 fprintf(fp, " -i, --input-format=FORMAT Input trace format (default: ctf)\n");
3106 fprintf(fp, " -l, --list List available formats\n");
3107 fprintf(fp, " -o, --output-format=FORMAT Output trace format (default: text)\n");
3108 fprintf(fp, " -v, --verbose Enable verbose output\n");
3109 fprintf(fp, " --help-legacy Show this help and quit\n");
3110 fprintf(fp, " -V, --version Show version and quit\n");
3111 fprintf(fp, "\n");
3112 fprintf(fp, " Available input formats: ctf, lttng-live, ctf-metadata\n");
3113 fprintf(fp, " Available output formats: text, dummy\n");
3114 fprintf(fp, "\n");
3115 fprintf(fp, "Input formats specific options:\n");
3116 fprintf(fp, "\n");
3117 fprintf(fp, " INPUT... Input trace file(s), directory(ies), or URLs\n");
3118 fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n");
3119 fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS nanoseconds\n");
3120 fprintf(fp, " --stream-intersection Only process events when all streams are active\n");
3121 fprintf(fp, "\n");
3122 fprintf(fp, "text output format specific options:\n");
3123 fprintf(fp, " \n");
3124 fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n");
3125 fprintf(fp, " --clock-date Print timestamp dates\n");
3126 fprintf(fp, " --clock-gmt Print and parse timestamps in GMT time zone\n");
3127 fprintf(fp, " (default: local time zone)\n");
3128 fprintf(fp, " --clock-seconds Print the timestamps as [SEC.NS]\n");
3129 fprintf(fp, " (default format: [HH:MM:SS.NS])\n");
3130 fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
3131 fprintf(fp, " (default: `/usr/lib/debug`)\n");
3132 fprintf(fp, " --debug-info-full-path Show full debug info source and binary paths\n");
3133 fprintf(fp, " --debug-info-target-prefix=DIR Use directory DIR as a prefix when looking\n");
3134 fprintf(fp, " up executables during debug info analysis\n");
3135 fprintf(fp, " (default: `/usr/lib/debug`)\n");
3136 fprintf(fp, " -f, --fields=NAME[,NAME]... Print additional fields:\n");
3137 fprintf(fp, " all, trace, trace:hostname, trace:domain,\n");
3138 fprintf(fp, " trace:procname, trace:vpid, loglevel, emf\n");
3139 fprintf(fp, " (default: trace:hostname, trace:procname,\n");
3140 fprintf(fp, " trace:vpid)\n");
3141 fprintf(fp, " -n, --names=NAME[,NAME]... Print field names:\n");
3142 fprintf(fp, " payload (or arg or args)\n");
3143 fprintf(fp, " none, all, scope, header, context (or ctx)\n");
3144 fprintf(fp, " (default: payload, context)\n");
3145 fprintf(fp, " --no-delta Do not print time delta between consecutive\n");
3146 fprintf(fp, " events\n");
3147 fprintf(fp, " -w, --output=PATH Write output to PATH (default: standard output)\n");
3148}
3149
3150/*
3151 * Prints the convert command usage.
3152 */
3153static
3154void print_convert_usage(FILE *fp)
3155{
3156 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
3157 fprintf(fp, "\n");
3158 fprintf(fp, "Options:\n");
3159 fprintf(fp, "\n");
3160 fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
3161 fprintf(fp, " for the following component instances\n");
3162 fprintf(fp, " (see the expected format of PARAMS below)\n");
3163 fprintf(fp, " --begin=BEGIN Set the `begin` parameter of the latest\n");
3164 fprintf(fp, " source component instance to BEGIN\n");
3165 fprintf(fp, " (see the suggested format of BEGIN below)\n");
ebba3338
PP
3166 fprintf(fp, " -c, --connect=CONNECTION Connect two component instances (see the\n");
3167 fprintf(fp, " expected format of CONNECTION below)\n");
290725f7
PP
3168 fprintf(fp, " -d, --debug Enable debug mode\n");
3169 fprintf(fp, " --end=END Set the `end` parameter of the latest\n");
3170 fprintf(fp, " source component instance to END\n");
3171 fprintf(fp, " (see the suggested format of BEGIN below)\n");
3b6cfcc5
PP
3172 fprintf(fp, " --name=NAME Set the name of the latest component\n");
3173 fprintf(fp, " instance to NAME (must be unique amongst\n");
3174 fprintf(fp, " all the names of the component instances)\n");
290725f7
PP
3175 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
3176 fprintf(fp, " (~/.local/lib/babeltrace/plugins)\n");
3177 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
3178 fprintf(fp, " -p, --params=PARAMS Set the parameters of the latest component\n");
3179 fprintf(fp, " instance (in command-line order) to PARAMS\n");
3180 fprintf(fp, " (see the expected format of PARAMS below)\n");
3181 fprintf(fp, " -P, --path=PATH Set the `path` parameter of the latest\n");
3182 fprintf(fp, " component instance to PATH\n");
3183 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
3184 fprintf(fp, " dynamic plugins can be loaded\n");
3185 fprintf(fp, " -r, --reset-base-params Reset the current base parameters of the\n");
3186 fprintf(fp, " following source and sink component\n");
3187 fprintf(fp, " instances to an empty map\n");
3188 fprintf(fp, " -o, --sink=PLUGIN.COMPCLS Instantiate a sink component from plugin\n");
3189 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
3190 fprintf(fp, " repeated)\n");
3191 fprintf(fp, " -i, --source=PLUGIN.COMPCLS Instantiate a source component from plugin\n");
3192 fprintf(fp, " PLUGIN and component class COMPCLS (may be\n");
3193 fprintf(fp, " repeated)\n");
3194 fprintf(fp, " --timerange=TIMERANGE Set time range to TIMERANGE: BEGIN,END or\n");
3195 fprintf(fp, " [BEGIN,END] (literally `[` and `]`)\n");
3196 fprintf(fp, " (suggested format of BEGIN/END below)\n");
3197 fprintf(fp, " -v, --verbose Enable verbose output\n");
3198 fprintf(fp, " -h --help Show this help and quit\n");
3199 fprintf(fp, "\n");
3200 fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
3201 fprintf(fp, "\n\n");
3202 fprintf(fp, "Suggested format of BEGIN and END\n");
3203 fprintf(fp, "---------------------------------\n");
3204 fprintf(fp, "\n");
3205 fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
3206 fprintf(fp, "\n\n");
ebba3338
PP
3207 fprintf(fp, "Expected format of CONNECTION\n");
3208 fprintf(fp, "-----------------------------\n");
3209 fprintf(fp, "\n");
3210 fprintf(fp, " SRC[.SRCPORT]:DST[.DSTPORT]\n");
3211 fprintf(fp, "\n");
3212 fprintf(fp, "SRC and DST are the names of the source and destination component\n");
3213 fprintf(fp, "instances to connect together. You can set the name of a component\n");
3214 fprintf(fp, "instance with the --name option.\n");
3215 fprintf(fp, "\n");
3216 fprintf(fp, "SRCPORT and DSTPORT are the optional source and destination ports to use\n");
3217 fprintf(fp, "for the connection. When the port is not specified, the default port is\n");
3218 fprintf(fp, "used.\n");
3219 fprintf(fp, "\n");
3220 fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
3221 fprintf(fp, "can connect a filter component to a sink component.\n");
3222 fprintf(fp, "\n");
3223 fprintf(fp, "Example:\n");
3224 fprintf(fp, "\n");
3225 fprintf(fp, " my-filter.top10:json-out\n");
3226 fprintf(fp, "\n\n");
63ce0e1d 3227 print_expected_params_format(fp);
290725f7
PP
3228}
3229
3230static struct poptOption convert_long_options[] = {
3231 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
3232 { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
3233 { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
3234 { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
3235 { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
3236 { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
3237 { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
3238 { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
3239 { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
3240 { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
ebba3338 3241 { "connect", 'c', POPT_ARG_STRING, NULL, OPT_CONNECT, NULL, NULL },
290725f7
PP
3242 { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
3243 { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
3244 { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
3245 { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
3246 { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
3247 { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
3248 { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
3249 { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
3b6cfcc5 3250 { "name", '\0', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
290725f7
PP
3251 { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
3252 { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
3253 { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
3254 { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
3255 { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
3256 { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
3257 { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
3258 { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
3259 { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
3260 { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
3261 { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
3262 { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
3263 { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
3264 { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
3265 { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
3266 { NULL, 0, 0, NULL, 0, NULL, NULL },
3267};
3268
3269/*
3270 * Creates a Babeltrace config object from the arguments of a convert
3271 * command.
3272 *
3273 * *retcode is set to the appropriate exit code to use.
3274 */
3275struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
3276 int *retcode, bool omit_system_plugin_path,
3277 bool omit_home_plugin_path,
3278 struct bt_value *initial_plugin_paths)
3279{
3280 poptContext pc = NULL;
3281 char *arg = NULL;
3282 struct ctf_legacy_opts ctf_legacy_opts;
3283 struct text_legacy_opts text_legacy_opts;
3284 enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
3285 enum legacy_output_format legacy_output_format =
3286 LEGACY_OUTPUT_FORMAT_NONE;
3287 struct bt_value *legacy_input_paths = NULL;
3288 struct bt_config_component *implicit_source_comp = NULL;
3289 struct bt_config_component *cur_cfg_comp = NULL;
3290 bool cur_is_implicit_source = false;
3291 bool use_implicit_source = false;
3292 enum bt_config_component_dest cur_cfg_comp_dest =
3293 BT_CONFIG_COMPONENT_DEST_SOURCE;
3294 struct bt_value *cur_base_params = NULL;
3295 int opt, ret = 0;
3296 struct bt_config *cfg = NULL;
3b6cfcc5 3297 struct bt_value *instance_names = NULL;
ebba3338
PP
3298 struct bt_value *connection_args = NULL;
3299 char error_buf[256] = { 0 };
290725f7
PP
3300
3301 *retcode = 0;
3302 memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
3303 memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
3304
3305 if (argc <= 1) {
3306 print_convert_usage(stdout);
3307 *retcode = -1;
3308 goto end;
3309 }
3310
3311 cfg = bt_config_convert_create(initial_plugin_paths);
3312 if (!cfg) {
3313 print_err_oom();
3314 goto error;
3315 }
3316
3317 cfg->cmd_data.convert.omit_system_plugin_path = omit_system_plugin_path;
3318 cfg->cmd_data.convert.omit_home_plugin_path = omit_home_plugin_path;
3319 text_legacy_opts.output = g_string_new(NULL);
3320 if (!text_legacy_opts.output) {
3321 print_err_oom();
3322 goto error;
3323 }
3324
3325 text_legacy_opts.dbg_info_dir = g_string_new(NULL);
3326 if (!text_legacy_opts.dbg_info_dir) {
3327 print_err_oom();
3328 goto error;
3329 }
3330
3331 text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
3332 if (!text_legacy_opts.dbg_info_target_prefix) {
3333 print_err_oom();
3334 goto error;
3335 }
3336
3337 cur_base_params = bt_value_map_create();
3338 if (!cur_base_params) {
3339 print_err_oom();
3340 goto error;
3341 }
3342
3343 legacy_input_paths = bt_value_array_create();
3344 if (!legacy_input_paths) {
3345 print_err_oom();
3346 goto error;
3347 }
3348
3b6cfcc5
PP
3349 instance_names = bt_value_map_create();
3350 if (!instance_names) {
3351 print_err_oom();
3352 goto error;
3353 }
3354
ebba3338
PP
3355 connection_args = bt_value_array_create();
3356 if (!connection_args) {
3357 print_err_oom();
3358 goto error;
3359 }
3360
290725f7
PP
3361 ret = append_env_var_plugin_paths(cfg->cmd_data.convert.plugin_paths);
3362 if (ret) {
3363 printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
3364 goto error;
3365 }
3366
3367 /* Note: implicit source never gets positional base params. */
90de159b
PP
3368 implicit_source_comp = bt_config_component_from_arg(
3369 BT_COMPONENT_CLASS_TYPE_SOURCE, DEFAULT_SOURCE_COMPONENT_NAME);
22e22462
PP
3370 if (!implicit_source_comp) {
3371 print_err_oom();
3372 goto error;
290725f7
PP
3373 }
3374
22e22462
PP
3375 cur_cfg_comp = implicit_source_comp;
3376 cur_is_implicit_source = true;
3377 use_implicit_source = true;
3378
290725f7
PP
3379 /* Parse options */
3380 pc = poptGetContext(NULL, argc, (const char **) argv,
3381 convert_long_options, 0);
3382 if (!pc) {
3383 printf_err("Cannot get popt context\n");
3384 goto error;
3385 }
3386
3387 poptReadDefaultConfig(pc, 0);
3388
3389 while ((opt = poptGetNextOpt(pc)) > 0) {
3390 arg = poptGetOptArg(pc);
3391
3392 switch (opt) {
3393 case OPT_PLUGIN_PATH:
3394 if (bt_common_is_setuid_setgid()) {
3395 printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
3396 } else {
3397 if (bt_config_append_plugin_paths(
3398 cfg->cmd_data.convert.plugin_paths,
3399 arg)) {
2703153b
PP
3400 printf_err("Invalid --plugin-path option's argument:\n %s\n",
3401 arg);
290725f7
PP
3402 goto error;
3403 }
3404 }
3405 break;
3406 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
3407 cfg->cmd_data.convert.omit_system_plugin_path = true;
3408 break;
3409 case OPT_OMIT_HOME_PLUGIN_PATH:
3410 cfg->cmd_data.convert.omit_home_plugin_path = true;
98ecef32 3411 break;
c42c79ea
PP
3412 case OPT_OUTPUT_PATH:
3413 if (text_legacy_opts.output->len > 0) {
3414 printf_err("Duplicate --output option\n");
3415 goto error;
3416 }
3417
3418 g_string_assign(text_legacy_opts.output, arg);
3419 break;
3420 case OPT_DEBUG_INFO_DIR:
3421 if (text_legacy_opts.dbg_info_dir->len > 0) {
3422 printf_err("Duplicate --debug-info-dir option\n");
3423 goto error;
3424 }
3425
3426 g_string_assign(text_legacy_opts.dbg_info_dir, arg);
3427 break;
3428 case OPT_DEBUG_INFO_TARGET_PREFIX:
3429 if (text_legacy_opts.dbg_info_target_prefix->len > 0) {
3430 printf_err("Duplicate --debug-info-target-prefix option\n");
3431 goto error;
3432 }
3433
3434 g_string_assign(text_legacy_opts.dbg_info_target_prefix, arg);
3435 break;
3436 case OPT_INPUT_FORMAT:
3437 case OPT_SOURCE:
3438 {
c42c79ea
PP
3439 if (opt == OPT_INPUT_FORMAT) {
3440 if (!strcmp(arg, "ctf")) {
3441 /* Legacy CTF input format */
3442 if (legacy_input_format) {
3443 print_err_dup_legacy_input();
3444 goto error;
3445 }
3446
3447 legacy_input_format =
3448 LEGACY_INPUT_FORMAT_CTF;
3449 break;
3450 } else if (!strcmp(arg, "lttng-live")) {
3451 /* Legacy LTTng-live input format */
3452 if (legacy_input_format) {
3453 print_err_dup_legacy_input();
3454 goto error;
3455 }
3456
3457 legacy_input_format =
3458 LEGACY_INPUT_FORMAT_LTTNG_LIVE;
3459 break;
3460 }
3461 }
3462
65582340
MD
3463 use_implicit_source = false;
3464
c42c79ea 3465 /* Non-legacy: try to create a component config */
65582340 3466 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3467 add_cfg_comp(cfg, cur_cfg_comp,
3468 cur_cfg_comp_dest);
3469 }
3470
90de159b
PP
3471 cur_cfg_comp = bt_config_component_from_arg(
3472 BT_COMPONENT_CLASS_TYPE_SOURCE, arg);
bdc61c70 3473 if (!cur_cfg_comp) {
49849a47 3474 printf_err("Invalid format for --source option's argument:\n %s\n",
c42c79ea
PP
3475 arg);
3476 goto error;
3477 }
65582340 3478 cur_is_implicit_source = false;
c42c79ea 3479
b07ffa28
PP
3480 assert(cur_base_params);
3481 bt_put(cur_cfg_comp->params);
c9313318 3482 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3483 if (!cur_cfg_comp->params) {
c9313318 3484 print_err_oom();
290725f7 3485 goto error;
c9313318
PP
3486 }
3487
bdc61c70 3488 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
c42c79ea
PP
3489 break;
3490 }
3491 case OPT_OUTPUT_FORMAT:
3492 case OPT_SINK:
3493 {
c42c79ea
PP
3494 if (opt == OPT_OUTPUT_FORMAT) {
3495 if (!strcmp(arg, "text")) {
3496 /* Legacy CTF-text output format */
3497 if (legacy_output_format) {
3498 print_err_dup_legacy_output();
3499 goto error;
3500 }
3501
3502 legacy_output_format =
3503 LEGACY_OUTPUT_FORMAT_TEXT;
3504 break;
3505 } else if (!strcmp(arg, "dummy")) {
3506 /* Legacy dummy output format */
3507 if (legacy_output_format) {
3508 print_err_dup_legacy_output();
3509 goto error;
3510 }
3511
3512 legacy_output_format =
3513 LEGACY_OUTPUT_FORMAT_DUMMY;
3514 break;
3515 } else if (!strcmp(arg, "ctf-metadata")) {
05a67631 3516 cfg->cmd_data.convert.print_ctf_metadata = true;
c42c79ea
PP
3517 break;
3518 }
3519 }
3520
3521 /* Non-legacy: try to create a component config */
65582340 3522 if (cur_cfg_comp && !cur_is_implicit_source) {
bdc61c70
PP
3523 add_cfg_comp(cfg, cur_cfg_comp,
3524 cur_cfg_comp_dest);
3525 }
3526
90de159b
PP
3527 cur_cfg_comp = bt_config_component_from_arg(
3528 BT_COMPONENT_CLASS_TYPE_SINK, arg);
bdc61c70 3529 if (!cur_cfg_comp) {
49849a47 3530 printf_err("Invalid format for --sink option's argument:\n %s\n",
c42c79ea
PP
3531 arg);
3532 goto error;
3533 }
65582340 3534 cur_is_implicit_source = false;
c42c79ea 3535
b07ffa28
PP
3536 assert(cur_base_params);
3537 bt_put(cur_cfg_comp->params);
c9313318 3538 cur_cfg_comp->params = bt_value_copy(cur_base_params);
bd9f0fa2 3539 if (!cur_cfg_comp->params) {
c9313318 3540 print_err_oom();
290725f7 3541 goto error;
c9313318
PP
3542 }
3543
bdc61c70 3544 cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
bdc61c70
PP
3545 break;
3546 }
3547 case OPT_PARAMS:
3548 {
3549 struct bt_value *params;
b07ffa28 3550 struct bt_value *params_to_set;
bdc61c70
PP
3551
3552 if (!cur_cfg_comp) {
2703153b
PP
3553 printf_err("Cannot add parameters to unavailable default source component `%s`:\n %s\n",
3554 DEFAULT_SOURCE_COMPONENT_NAME, arg);
bdc61c70
PP
3555 goto error;
3556 }
3557
bdc61c70
PP
3558 params = bt_value_from_arg(arg);
3559 if (!params) {
3560 printf_err("Invalid format for --params option's argument:\n %s\n",
3561 arg);
3562 goto error;
3563 }
3564
560ff91c 3565 params_to_set = bt_value_map_extend(cur_cfg_comp->params,
b07ffa28
PP
3566 params);
3567 BT_PUT(params);
3568 if (!params_to_set) {
560ff91c 3569 printf_err("Cannot extend current component parameters with --params option's argument:\n %s\n",
b07ffa28
PP
3570 arg);
3571 goto error;
3572 }
3573
3574 BT_MOVE(cur_cfg_comp->params, params_to_set);
c42c79ea
PP
3575 break;
3576 }
ad6a19bd
PP
3577 case OPT_PATH:
3578 if (!cur_cfg_comp) {
2703153b
PP
3579 printf_err("Cannot add `path` parameter to unavailable default source component `%s`:\n %s\n",
3580 DEFAULT_SOURCE_COMPONENT_NAME, arg);
ad6a19bd
PP
3581 goto error;
3582 }
3583
3584 assert(cur_cfg_comp->params);
3585
3586 if (bt_value_map_insert_string(cur_cfg_comp->params,
3587 "path", arg)) {
3588 print_err_oom();
3589 goto error;
3590 }
3591 break;
3b6cfcc5
PP
3592 case OPT_NAME:
3593 if (!cur_cfg_comp) {
3594 printf_err("Cannot set the name of unavailable default source component `%s`:\n %s\n",
3595 DEFAULT_SOURCE_COMPONENT_NAME, arg);
3596 goto error;
3597 }
3598
3599 if (bt_value_map_has_key(instance_names, arg)) {
3600 printf_err("Duplicate component instance name:\n %s\n",
3601 arg);
3602 goto error;
3603 }
3604
3605 g_string_assign(cur_cfg_comp->instance_name, arg);
3606
3607 if (bt_value_map_insert(instance_names,
3608 arg, bt_value_null)) {
3609 print_err_oom();
3610 goto error;
3611 }
3612 break;
b07ffa28
PP
3613 case OPT_BASE_PARAMS:
3614 {
3615 struct bt_value *params = bt_value_from_arg(arg);
3616
3617 if (!params) {
3618 printf_err("Invalid format for --base-params option's argument:\n %s\n",
3619 arg);
3620 goto error;
3621 }
3622
3623 BT_MOVE(cur_base_params, params);
3624 break;
3625 }
3626 case OPT_RESET_BASE_PARAMS:
3627 BT_PUT(cur_base_params);
3628 cur_base_params = bt_value_map_create();
3629 if (!cur_base_params) {
3630 print_err_oom();
3631 goto error;
3632 }
3633 break;
c42c79ea
PP
3634 case OPT_NAMES:
3635 if (text_legacy_opts.names) {
3636 printf_err("Duplicate --names option\n");
3637 goto error;
3638 }
3639
3640 text_legacy_opts.names = names_from_arg(arg);
3641 if (!text_legacy_opts.names) {
2703153b
PP
3642 printf_err("Invalid --names option's argument:\n %s\n",
3643 arg);
c42c79ea
PP
3644 goto error;
3645 }
3646 break;
3647 case OPT_FIELDS:
3648 if (text_legacy_opts.fields) {
3649 printf_err("Duplicate --fields option\n");
3650 goto error;
3651 }
3652
3653 text_legacy_opts.fields = fields_from_arg(arg);
3654 if (!text_legacy_opts.fields) {
2703153b
PP
3655 printf_err("Invalid --fields option's argument:\n %s\n",
3656 arg);
c42c79ea
PP
3657 goto error;
3658 }
3659 break;
3660 case OPT_NO_DELTA:
3661 text_legacy_opts.no_delta = true;
3662 break;
3663 case OPT_CLOCK_CYCLES:
3664 text_legacy_opts.clock_cycles = true;
3665 break;
3666 case OPT_CLOCK_SECONDS:
3667 text_legacy_opts.clock_seconds = true;
3668 break;
3669 case OPT_CLOCK_DATE:
3670 text_legacy_opts.clock_date = true;
3671 break;
3672 case OPT_CLOCK_GMT:
3673 text_legacy_opts.clock_gmt = true;
3674 break;
3675 case OPT_DEBUG_INFO_FULL_PATH:
3676 text_legacy_opts.dbg_info_full_path = true;
3677 break;
3678 case OPT_CLOCK_OFFSET:
3679 {
3680 int64_t val;
3681
3682 if (ctf_legacy_opts.offset_s.is_set) {
3683 printf_err("Duplicate --clock-offset option\n");
3684 goto error;
3685 }
3686
3687 if (parse_int64(arg, &val)) {
2703153b
PP
3688 printf_err("Invalid --clock-offset option's argument:\n %s\n",
3689 arg);
c42c79ea
PP
3690 goto error;
3691 }
3692
3693 set_offset_value(&ctf_legacy_opts.offset_s, val);
3694 break;
3695 }
3696 case OPT_CLOCK_OFFSET_NS:
3697 {
3698 int64_t val;
3699
3700 if (ctf_legacy_opts.offset_ns.is_set) {
3701 printf_err("Duplicate --clock-offset-ns option\n");
3702 goto error;
3703 }
3704
3705 if (parse_int64(arg, &val)) {
2703153b
PP
3706 printf_err("Invalid --clock-offset-ns option's argument:\n %s\n",
3707 arg);
c42c79ea
PP
3708 goto error;
3709 }
3710
3711 set_offset_value(&ctf_legacy_opts.offset_ns, val);
3712 break;
3713 }
3714 case OPT_STREAM_INTERSECTION:
3715 ctf_legacy_opts.stream_intersection = true;
3716 break;
3717 case OPT_CLOCK_FORCE_CORRELATE:
290725f7 3718 cfg->cmd_data.convert.force_correlate = true;
c42c79ea 3719 break;
0f9915c6
MD
3720 case OPT_BEGIN:
3721 if (!cur_cfg_comp) {
2703153b
PP
3722 printf_err("Cannot add `begin` parameter to unavailable default source component `%s`:\n %s\n",
3723 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3724 goto error;
3725 }
3726 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3727 printf_err("--begin option must follow a --source option:\n %s\n",
3728 arg);
0f9915c6
MD
3729 goto error;
3730 }
3731 if (bt_value_map_insert_string(cur_cfg_comp->params,
3732 "begin", arg)) {
3733 print_err_oom();
3734 goto error;
3735 }
3736 break;
3737 case OPT_END:
3738 if (!cur_cfg_comp) {
2703153b
PP
3739 printf_err("Cannot add `end` parameter to unavailable default source component `%s`:\n %s\n",
3740 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3741 goto error;
3742 }
3743 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3744 printf_err("--end option must follow a --source option:\n %s\n",
3745 arg);
0f9915c6
MD
3746 goto error;
3747 }
3748 if (bt_value_map_insert_string(cur_cfg_comp->params,
3749 "end", arg)) {
3750 print_err_oom();
3751 goto error;
3752 }
3753 break;
3754 case OPT_TIMERANGE:
3755 {
3756 const char *begin, *end;
3757
3758 if (!cur_cfg_comp) {
2703153b
PP
3759 printf_err("Cannot add `begin` and `end` parameters to unavailable default source component `%s`:\n %s\n",
3760 DEFAULT_SOURCE_COMPONENT_NAME, arg);
0f9915c6
MD
3761 goto error;
3762 }
3763 if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
2703153b
PP
3764 printf_err("--timerange option must follow a --source option:\n %s\n",
3765 arg);
0f9915c6
MD
3766 goto error;
3767 }
3768 if (split_timerange(arg, &begin, &end)) {
2703153b
PP
3769 printf_err("Invalid --timerange format: expecting BEGIN,END or [BEGIN,END]:\n %s\n",
3770 arg);
0f9915c6
MD
3771 goto error;
3772 }
3773 if (bt_value_map_insert_string(cur_cfg_comp->params,
3774 "begin", begin)) {
3775 print_err_oom();
3776 goto error;
3777 }
3778 if (bt_value_map_insert_string(cur_cfg_comp->params,
3779 "end", end)) {
3780 print_err_oom();
3781 goto error;
3782 }
3783 break;
3784 }
ebba3338
PP
3785 case OPT_CONNECT:
3786 if (bt_value_array_append_string(connection_args,
3787 arg)) {
3788 print_err_oom();
3789 goto error;
3790 }
3791 break;
c42c79ea 3792 case OPT_HELP:
290725f7
PP
3793 print_convert_usage(stdout);
3794 *retcode = -1;
3795 BT_PUT(cfg);
c42c79ea
PP
3796 goto end;
3797 case OPT_VERBOSE:
a263021c 3798 text_legacy_opts.verbose = true;
c42c79ea
PP
3799 cfg->verbose = true;
3800 break;
3801 case OPT_DEBUG:
3802 cfg->debug = true;
3803 break;
3804 default:
3805 printf_err("Unknown command-line option specified (option code %d)\n",
3806 opt);
3807 goto error;
3808 }
3809
3810 free(arg);
3811 arg = NULL;
3812 }
3813
3814 /* Check for option parsing error */
3815 if (opt < -1) {
3816 printf_err("While parsing command-line options, at option %s: %s\n",
3817 poptBadOption(pc, 0), poptStrerror(opt));
3818 goto error;
3819 }
3820
3821 /* Consume leftover arguments as legacy input paths */
3822 while (true) {
3823 const char *input_path = poptGetArg(pc);
3824
3825 if (!input_path) {
3826 break;
3827 }
3828
3829 if (bt_value_array_append_string(legacy_input_paths,
3830 input_path)) {
3831 print_err_oom();
3832 goto error;
3833 }
3834 }
3835
290725f7
PP
3836 if (append_home_and_system_plugin_paths(
3837 cfg->cmd_data.convert.plugin_paths,
3838 cfg->cmd_data.convert.omit_system_plugin_path,
3839 cfg->cmd_data.convert.omit_home_plugin_path)) {
3840 printf_err("Cannot append home and system plugin paths\n");
6cf24c61
MD
3841 goto error;
3842 }
3843
3844 /* Append current component configuration, if any */
3845 if (cur_cfg_comp && !cur_is_implicit_source) {
3846 add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
3847 }
3848 cur_cfg_comp = NULL;
3849
c42c79ea
PP
3850 /* Validate legacy/non-legacy options */
3851 if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
3852 legacy_input_paths, &ctf_legacy_opts,
bd9f0fa2 3853 &text_legacy_opts)) {
c42c79ea
PP
3854 printf_err("Command-line options form an invalid configuration\n");
3855 goto error;
3856 }
3857
3858 /*
3859 * If there's a legacy input format, convert it to source
3860 * component configurations.
3861 */
3862 if (legacy_input_format) {
290725f7
PP
3863 if (append_sources_from_legacy_opts(
3864 cfg->cmd_data.convert.sources,
c42c79ea 3865 legacy_input_format, &ctf_legacy_opts,
528debdf 3866 legacy_input_paths)) {
49849a47 3867 printf_err("Cannot convert legacy input format options to source component instance(s)\n");
c42c79ea
PP
3868 goto error;
3869 }
290725f7
PP
3870 if (append_sources_from_implicit_params(
3871 cfg->cmd_data.convert.sources,
bd9f0fa2
MD
3872 implicit_source_comp)) {
3873 printf_err("Cannot initialize legacy component parameters\n");
3874 goto error;
3875 }
3876 use_implicit_source = false;
3877 } else {
3878 if (use_implicit_source) {
3879 add_cfg_comp(cfg, implicit_source_comp,
3880 BT_CONFIG_COMPONENT_DEST_SOURCE);
3881 implicit_source_comp = NULL;
3882 } else {
3883 if (implicit_source_comp
3884 && !bt_value_map_is_empty(implicit_source_comp->params)) {
05a67631 3885 printf_err("Arguments specified for implicit input format, but an explicit source component instance has been specified: overriding it\n");
bd9f0fa2
MD
3886 goto error;
3887 }
3888 }
c42c79ea
PP
3889 }
3890
05a67631
PP
3891 /*
3892 * At this point if we need to print the CTF metadata text, we
3893 * don't care about the legacy/implicit sinks and component
3894 * connections.
3895 */
3896 if (cfg->cmd_data.convert.print_ctf_metadata) {
3897 goto end;
3898 }
3899
c42c79ea
PP
3900 /*
3901 * If there's a legacy output format, convert it to sink
3902 * component configurations.
3903 */
3904 if (legacy_output_format) {
290725f7 3905 if (append_sinks_from_legacy_opts(cfg->cmd_data.convert.sinks,
c42c79ea 3906 legacy_output_format, &text_legacy_opts)) {
49849a47 3907 printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
c42c79ea
PP
3908 goto error;
3909 }
3910 }
3911
290725f7 3912 if (cfg->cmd_data.convert.sinks->len == 0) {
bd9f0fa2 3913 /* Use implicit sink as default. */
90de159b
PP
3914 cur_cfg_comp = bt_config_component_from_arg(
3915 BT_COMPONENT_CLASS_TYPE_SINK,
3916 DEFAULT_SINK_COMPONENT_NAME);
bd9f0fa2 3917 if (!cur_cfg_comp) {
2703153b 3918 printf_error("Cannot find implicit sink plugin `%s`\n",
bd9f0fa2
MD
3919 DEFAULT_SINK_COMPONENT_NAME);
3920 }
3921 add_cfg_comp(cfg, cur_cfg_comp,
3922 BT_CONFIG_COMPONENT_DEST_SINK);
3923 cur_cfg_comp = NULL;
3924 }
3925
ebba3338
PP
3926 ret = bt_config_create_connections(cfg, connection_args,
3927 error_buf, 256);
3928 if (ret) {
3929 printf_err("Cannot creation connections:\n%s", error_buf);
3930 goto error;
3931 }
3932
c42c79ea
PP
3933 goto end;
3934
3935error:
290725f7
PP
3936 *retcode = 1;
3937 BT_PUT(cfg);
3938
c42c79ea
PP
3939end:
3940 if (pc) {
3941 poptFreeContext(pc);
3942 }
3943
3944 if (text_legacy_opts.output) {
3945 g_string_free(text_legacy_opts.output, TRUE);
3946 }
3947
3948 if (text_legacy_opts.dbg_info_dir) {
3949 g_string_free(text_legacy_opts.dbg_info_dir, TRUE);
3950 }
3951
3952 if (text_legacy_opts.dbg_info_target_prefix) {
3953 g_string_free(text_legacy_opts.dbg_info_target_prefix, TRUE);
3954 }
3955
3956 free(arg);
65582340 3957 BT_PUT(implicit_source_comp);
bdc61c70 3958 BT_PUT(cur_cfg_comp);
b07ffa28 3959 BT_PUT(cur_base_params);
c42c79ea
PP
3960 BT_PUT(text_legacy_opts.names);
3961 BT_PUT(text_legacy_opts.fields);
3962 BT_PUT(legacy_input_paths);
3b6cfcc5 3963 BT_PUT(instance_names);
ebba3338 3964 BT_PUT(connection_args);
290725f7
PP
3965 return cfg;
3966}
3967
3968/*
3969 * Prints the Babeltrace 2.x general usage.
3970 */
3971static
3972void print_gen_usage(FILE *fp)
3973{
3974 fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
3975 fprintf(fp, "\n");
3976 fprintf(fp, "General options:\n");
3977 fprintf(fp, "\n");
3978 fprintf(fp, " -d, --debug Enable debug mode\n");
3979 fprintf(fp, " -h --help Show this help and quit\n");
3980 fprintf(fp, " --help-legacy Show Babeltrace 1.x legacy help and quit\n");
3981 fprintf(fp, " -v, --verbose Enable verbose output\n");
3982 fprintf(fp, " -V, --version Show version and quit\n");
3983 fprintf(fp, "\n");
3984 fprintf(fp, "Available commands:\n");
3985 fprintf(fp, "\n");
3986 fprintf(fp, " convert Build a trace conversion graph and run it (default)\n");
22e22462 3987 fprintf(fp, " help Get help for a plugin or a component class\n");
290725f7 3988 fprintf(fp, " list-plugins List available plugins and their content\n");
a67681c1 3989 fprintf(fp, " query Query objects from a component class\n");
290725f7
PP
3990 fprintf(fp, "\n");
3991 fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
3992}
3993
3994struct bt_config *bt_config_from_args(int argc, const char *argv[],
3995 int *retcode, bool omit_system_plugin_path,
3996 bool omit_home_plugin_path,
3997 struct bt_value *initial_plugin_paths)
3998{
3999 struct bt_config *config = NULL;
4000 bool verbose = false;
4001 bool debug = false;
4002 int i;
4003 enum bt_config_command command = -1;
4004 const char **command_argv = NULL;
4005 int command_argc = -1;
4006 const char *command_name = NULL;
4007
4008 *retcode = -1;
4009
4010 if (argc <= 1) {
4011 print_gen_usage(stdout);
4012 goto end;
4013 }
4014
4015 for (i = 1; i < argc; i++) {
4016 const char *cur_arg = argv[i];
4017
4018 if (strcmp(cur_arg, "-d") == 0 ||
4019 strcmp(cur_arg, "--debug") == 0) {
4020 debug = true;
4021 } else if (strcmp(cur_arg, "-v") == 0 ||
4022 strcmp(cur_arg, "--verbose") == 0) {
4023 verbose = true;
4024 } else if (strcmp(cur_arg, "-V") == 0 ||
4025 strcmp(cur_arg, "--version") == 0) {
4026 print_version();
4027 goto end;
4028 } else if (strcmp(cur_arg, "-h") == 0 ||
4029 strcmp(cur_arg, "--help") == 0) {
4030 print_gen_usage(stdout);
4031 goto end;
4032 } else if (strcmp(cur_arg, "--help-legacy") == 0) {
4033 print_legacy_usage(stdout);
4034 goto end;
4035 } else {
22e22462
PP
4036 bool has_command = true;
4037
290725f7
PP
4038 /*
4039 * First unknown argument: is it a known command
4040 * name?
4041 */
4042 if (strcmp(cur_arg, "convert") == 0) {
4043 command = BT_CONFIG_COMMAND_CONVERT;
290725f7
PP
4044 } else if (strcmp(cur_arg, "list-plugins") == 0) {
4045 command = BT_CONFIG_COMMAND_LIST_PLUGINS;
22e22462
PP
4046 } else if (strcmp(cur_arg, "help") == 0) {
4047 command = BT_CONFIG_COMMAND_HELP;
a67681c1
PP
4048 } else if (strcmp(cur_arg, "query") == 0) {
4049 command = BT_CONFIG_COMMAND_QUERY;
290725f7
PP
4050 } else {
4051 /*
4052 * Unknown argument, but not a known
4053 * command name: assume the whole
4054 * arguments are for the default convert
4055 * command.
4056 */
4057 command = BT_CONFIG_COMMAND_CONVERT;
4058 command_argv = argv;
4059 command_argc = argc;
22e22462
PP
4060 has_command = false;
4061 }
4062
4063 if (has_command) {
4064 command_argv = &argv[i];
4065 command_argc = argc - i;
4066 command_name = cur_arg;
290725f7
PP
4067 }
4068 break;
4069 }
4070 }
4071
4072 if ((int) command < 0) {
4073 /*
4074 * We only got non-help, non-version general options
4075 * like --verbose and --debug, without any other
4076 * arguments, so we can't do anything useful: print the
4077 * usage and quit.
4078 */
4079 print_gen_usage(stdout);
4080 goto end;
4081 }
4082
4083 assert(command_argv);
4084 assert(command_argc >= 0);
4085
4086 switch (command) {
4087 case BT_CONFIG_COMMAND_CONVERT:
4088 config = bt_config_convert_from_args(command_argc, command_argv,
4089 retcode, omit_system_plugin_path,
4090 omit_home_plugin_path, initial_plugin_paths);
4091 break;
4092 case BT_CONFIG_COMMAND_LIST_PLUGINS:
4093 config = bt_config_list_plugins_from_args(command_argc,
4094 command_argv, retcode, omit_system_plugin_path,
4095 omit_home_plugin_path, initial_plugin_paths);
4096 break;
22e22462
PP
4097 case BT_CONFIG_COMMAND_HELP:
4098 config = bt_config_help_from_args(command_argc,
4099 command_argv, retcode, omit_system_plugin_path,
4100 omit_home_plugin_path, initial_plugin_paths);
4101 break;
a67681c1
PP
4102 case BT_CONFIG_COMMAND_QUERY:
4103 config = bt_config_query_from_args(command_argc,
63ce0e1d
PP
4104 command_argv, retcode, omit_system_plugin_path,
4105 omit_home_plugin_path, initial_plugin_paths);
4106 break;
290725f7
PP
4107 default:
4108 assert(false);
4109 }
4110
4111 if (config) {
4112 if (verbose) {
4113 config->verbose = true;
4114 }
4115
4116 if (debug) {
4117 config->debug = true;
4118 }
4119
4120 config->command_name = command_name;
4121 }
4122
4123end:
4124 return config;
c42c79ea 4125}
This page took 0.202018 seconds and 4 git commands to generate.