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