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