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