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