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