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