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