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