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