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