9eef511dac1d565026ba9f2902301e9ab8a6059a
[babeltrace.git] / cli / babeltrace.c
1 /*
2 * babeltrace.c
3 *
4 * Babeltrace Trace Converter
5 *
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #define BT_LOG_TAG "CLI"
30 #include "logging.h"
31
32 #include <babeltrace/babeltrace.h>
33 #include <babeltrace/plugin/plugin.h>
34 #include <babeltrace/common-internal.h>
35 #include <babeltrace/graph/component.h>
36 #include <babeltrace/graph/component-source.h>
37 #include <babeltrace/graph/component-sink.h>
38 #include <babeltrace/graph/component-filter.h>
39 #include <babeltrace/graph/component-class.h>
40 #include <babeltrace/graph/port.h>
41 #include <babeltrace/graph/graph.h>
42 #include <babeltrace/graph/connection.h>
43 #include <babeltrace/graph/notification-iterator.h>
44 #include <babeltrace/ref.h>
45 #include <babeltrace/values.h>
46 #include <babeltrace/values-internal.h>
47 #include <babeltrace/logging.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <popt.h>
51 #include <string.h>
52 #include <stdio.h>
53 #include <glib.h>
54 #include <inttypes.h>
55 #include <unistd.h>
56 #include <signal.h>
57 #include "babeltrace-cfg.h"
58 #include "babeltrace-cfg-cli-args.h"
59 #include "babeltrace-cfg-cli-args-default.h"
60
61 #define ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH "BABELTRACE_CLI_WARN_COMMAND_NAME_DIRECTORY_CLASH"
62 #define ENV_BABELTRACE_CLI_LOG_LEVEL "BABELTRACE_CLI_LOG_LEVEL"
63 #define NSEC_PER_SEC 1000000000LL
64
65 /*
66 * Known environment variable names for the log levels of the project's
67 * modules.
68 */
69 static const char* log_level_env_var_names[] = {
70 "BABELTRACE_COMMON_LOG_LEVEL",
71 "BABELTRACE_PLUGIN_CTF_BTR_LOG_LEVEL",
72 "BABELTRACE_PLUGIN_CTF_FS_SRC_LOG_LEVEL",
73 "BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_SRC_LOG_LEVEL",
74 "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL",
75 "BABELTRACE_PLUGIN_CTF_NOTIF_ITER_LOG_LEVEL",
76 "BABELTRACE_PLUGIN_LTTNG_UTILS_DEBUG_INFO_FLT_LOG_LEVEL",
77 "BABELTRACE_PLUGIN_TEXT_DMESG_SRC_LOG_LEVEL",
78 "BABELTRACE_PLUGIN_UTILS_MUXER_FLT_LOG_LEVEL",
79 "BABELTRACE_PLUGIN_UTILS_TRIMMER_FLT_LOG_LEVEL",
80 "BABELTRACE_PLUGIN_CTFCOPYTRACE_LIB_LOG_LEVEL",
81 "BABELTRACE_PLUGIN_CTF_FS_SINK_LOG_LEVEL",
82 "BABELTRACE_PYTHON_PLUGIN_PROVIDER_LOG_LEVEL",
83 NULL,
84 };
85
86 /* Application's processing graph (weak) */
87 static struct bt_graph *the_graph;
88 static bool canceled = false;
89
90 GPtrArray *loaded_plugins;
91
92 #ifdef __MINGW32__
93 #include <windows.h>
94
95 static
96 BOOL WINAPI signal_handler(DWORD signal) {
97 if (the_graph) {
98 bt_graph_cancel(the_graph);
99 }
100
101 canceled = true;
102
103 return TRUE;
104 }
105
106 static
107 void set_signal_handler(void)
108 {
109 if (!SetConsoleCtrlHandler(signal_handler, TRUE)) {
110 BT_LOGE("Failed to set the ctrl+c handler.");
111 }
112 }
113 #else /* __MINGW32__ */
114 static
115 void signal_handler(int signum)
116 {
117 if (signum != SIGINT) {
118 return;
119 }
120
121 if (the_graph) {
122 bt_graph_cancel(the_graph);
123 }
124
125 canceled = true;
126 }
127
128 static
129 void set_signal_handler(void)
130 {
131 struct sigaction new_action, old_action;
132
133 new_action.sa_handler = signal_handler;
134 sigemptyset(&new_action.sa_mask);
135 new_action.sa_flags = 0;
136 sigaction(SIGINT, NULL, &old_action);
137
138 if (old_action.sa_handler != SIG_IGN) {
139 sigaction(SIGINT, &new_action, NULL);
140 }
141 }
142 #endif /* __MINGW32__ */
143
144 static
145 void init_static_data(void)
146 {
147 loaded_plugins = g_ptr_array_new_with_free_func(bt_put);
148 }
149
150 static
151 void fini_static_data(void)
152 {
153 g_ptr_array_free(loaded_plugins, TRUE);
154 }
155
156 static
157 struct bt_plugin *find_plugin(const char *name)
158 {
159 int i;
160 struct bt_plugin *plugin = NULL;
161
162 assert(name);
163 BT_LOGD("Finding plugin: name=\"%s\"", name);
164
165 for (i = 0; i < loaded_plugins->len; i++) {
166 plugin = g_ptr_array_index(loaded_plugins, i);
167
168 if (strcmp(name, bt_plugin_get_name(plugin)) == 0) {
169 break;
170 }
171
172 plugin = NULL;
173 }
174
175 if (BT_LOG_ON_DEBUG) {
176 if (plugin) {
177 BT_LOGD("Found plugin: plugin-addr=%p", plugin);
178 } else {
179 BT_LOGD("Cannot find plugin.");
180 }
181 }
182
183 return bt_get(plugin);
184 }
185
186 static
187 struct bt_component_class *find_component_class(const char *plugin_name,
188 const char *comp_class_name,
189 enum bt_component_class_type comp_class_type)
190 {
191 struct bt_component_class *comp_class = NULL;
192 struct bt_plugin *plugin;
193
194 BT_LOGD("Finding component class: plugin-name=\"%s\", "
195 "comp-cls-name=\"%s\", comp-cls-type=%d",
196 plugin_name, comp_class_name, comp_class_type);
197
198 plugin = find_plugin(plugin_name);
199
200 if (!plugin) {
201 goto end;
202 }
203
204 comp_class = bt_plugin_get_component_class_by_name_and_type(plugin,
205 comp_class_name, comp_class_type);
206 BT_PUT(plugin);
207
208 end:
209 if (BT_LOG_ON_DEBUG) {
210 if (comp_class) {
211 BT_LOGD("Found component class: comp-cls-addr=%p",
212 comp_class);
213 } else {
214 BT_LOGD("Cannot find component class.");
215 }
216 }
217
218 return comp_class;
219 }
220
221 static
222 void print_indent(FILE *fp, size_t indent)
223 {
224 size_t i;
225
226 for (i = 0; i < indent; i++) {
227 fprintf(fp, " ");
228 }
229 }
230
231 static
232 const char *component_type_str(enum bt_component_class_type type)
233 {
234 switch (type) {
235 case BT_COMPONENT_CLASS_TYPE_SOURCE:
236 return "source";
237 case BT_COMPONENT_CLASS_TYPE_SINK:
238 return "sink";
239 case BT_COMPONENT_CLASS_TYPE_FILTER:
240 return "filter";
241 case BT_COMPONENT_CLASS_TYPE_UNKNOWN:
242 default:
243 return "(unknown)";
244 }
245 }
246
247 static
248 void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name,
249 const char *comp_cls_name, enum bt_component_class_type type)
250 {
251 GString *shell_plugin_name = NULL;
252 GString *shell_comp_cls_name = NULL;
253
254 shell_plugin_name = bt_common_shell_quote(plugin_name, false);
255 if (!shell_plugin_name) {
256 goto end;
257 }
258
259 shell_comp_cls_name = bt_common_shell_quote(comp_cls_name, false);
260 if (!shell_comp_cls_name) {
261 goto end;
262 }
263
264 fprintf(fh, "'%s%s%s%s.%s%s%s.%s%s%s'",
265 bt_common_color_bold(),
266 bt_common_color_fg_cyan(),
267 component_type_str(type),
268 bt_common_color_fg_default(),
269 bt_common_color_fg_blue(),
270 shell_plugin_name->str,
271 bt_common_color_fg_default(),
272 bt_common_color_fg_yellow(),
273 shell_comp_cls_name->str,
274 bt_common_color_reset());
275
276 end:
277 if (shell_plugin_name) {
278 g_string_free(shell_plugin_name, TRUE);
279 }
280
281 if (shell_comp_cls_name) {
282 g_string_free(shell_comp_cls_name, TRUE);
283 }
284 }
285
286 static
287 void print_value(FILE *, struct bt_value *, size_t);
288
289 static
290 void print_value_rec(FILE *, struct bt_value *, size_t);
291
292 struct print_map_value_data {
293 size_t indent;
294 FILE *fp;
295 };
296
297 static
298 bt_bool print_map_value(const char *key, struct bt_value *object, void *data)
299 {
300 struct print_map_value_data *print_map_value_data = data;
301
302 print_indent(print_map_value_data->fp, print_map_value_data->indent);
303 fprintf(print_map_value_data->fp, "%s: ", key);
304
305 if (bt_value_is_array(object) &&
306 bt_value_array_is_empty(object)) {
307 fprintf(print_map_value_data->fp, "[ ]\n");
308 return true;
309 }
310
311 if (bt_value_is_map(object) &&
312 bt_value_map_is_empty(object)) {
313 fprintf(print_map_value_data->fp, "{ }\n");
314 return true;
315 }
316
317 if (bt_value_is_array(object) ||
318 bt_value_is_map(object)) {
319 fprintf(print_map_value_data->fp, "\n");
320 }
321
322 print_value_rec(print_map_value_data->fp, object,
323 print_map_value_data->indent + 2);
324 return BT_TRUE;
325 }
326
327 static
328 void print_value_rec(FILE *fp, struct bt_value *value, size_t indent)
329 {
330 bt_bool bool_val;
331 int64_t int_val;
332 double dbl_val;
333 const char *str_val;
334 int size;
335 int i;
336 enum bt_value_status status;
337
338 if (!value) {
339 return;
340 }
341
342 switch (bt_value_get_type(value)) {
343 case BT_VALUE_TYPE_NULL:
344 fprintf(fp, "%snull%s\n", bt_common_color_bold(),
345 bt_common_color_reset());
346 break;
347 case BT_VALUE_TYPE_BOOL:
348 status = bt_value_bool_get(value, &bool_val);
349 if (status != BT_VALUE_STATUS_OK) {
350 goto error;
351 }
352 fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
353 bt_common_color_fg_cyan(), bool_val ? "yes" : "no",
354 bt_common_color_reset());
355 break;
356 case BT_VALUE_TYPE_INTEGER:
357 status = bt_value_integer_get(value, &int_val);
358 if (status != BT_VALUE_STATUS_OK) {
359 goto error;
360 }
361 fprintf(fp, "%s%s%" PRId64 "%s\n", bt_common_color_bold(),
362 bt_common_color_fg_red(), int_val,
363 bt_common_color_reset());
364 break;
365 case BT_VALUE_TYPE_FLOAT:
366 status = bt_value_float_get(value, &dbl_val);
367 if (status != BT_VALUE_STATUS_OK) {
368 goto error;
369 }
370 fprintf(fp, "%s%s%lf%s\n", bt_common_color_bold(),
371 bt_common_color_fg_red(), dbl_val,
372 bt_common_color_reset());
373 break;
374 case BT_VALUE_TYPE_STRING:
375 status = bt_value_string_get(value, &str_val);
376 if (status != BT_VALUE_STATUS_OK) {
377 goto error;
378 }
379 fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
380 bt_common_color_fg_green(), str_val,
381 bt_common_color_reset());
382 break;
383 case BT_VALUE_TYPE_ARRAY:
384 size = bt_value_array_size(value);
385 if (size < 0) {
386 goto error;
387 }
388
389 if (size == 0) {
390 print_indent(fp, indent);
391 fprintf(fp, "[ ]\n");
392 break;
393 }
394
395 for (i = 0; i < size; i++) {
396 struct bt_value *element =
397 bt_value_array_get(value, i);
398
399 if (!element) {
400 goto error;
401 }
402 print_indent(fp, indent);
403 fprintf(fp, "- ");
404
405 if (bt_value_is_array(element) &&
406 bt_value_array_is_empty(element)) {
407 fprintf(fp, "[ ]\n");
408 continue;
409 }
410
411 if (bt_value_is_map(element) &&
412 bt_value_map_is_empty(element)) {
413 fprintf(fp, "{ }\n");
414 continue;
415 }
416
417 if (bt_value_is_array(element) ||
418 bt_value_is_map(element)) {
419 fprintf(fp, "\n");
420 }
421
422 print_value_rec(fp, element, indent + 2);
423 BT_PUT(element);
424 }
425 break;
426 case BT_VALUE_TYPE_MAP:
427 {
428 struct print_map_value_data data = {
429 .indent = indent,
430 .fp = fp,
431 };
432
433 if (bt_value_map_is_empty(value)) {
434 print_indent(fp, indent);
435 fprintf(fp, "{ }\n");
436 break;
437 }
438
439 bt_value_map_foreach(value, print_map_value, &data);
440 break;
441 }
442 default:
443 abort();
444 }
445 return;
446
447 error:
448 BT_LOGE("Error printing value of type %s.",
449 bt_value_type_string(bt_value_get_type(value)));
450 }
451
452 static
453 void print_value(FILE *fp, struct bt_value *value, size_t indent)
454 {
455 if (!bt_value_is_array(value) && !bt_value_is_map(value)) {
456 print_indent(fp, indent);
457 }
458
459 print_value_rec(fp, value, indent);
460 }
461
462 static
463 void print_bt_config_component(struct bt_config_component *bt_config_component)
464 {
465 fprintf(stderr, " ");
466 print_plugin_comp_cls_opt(stderr, bt_config_component->plugin_name->str,
467 bt_config_component->comp_cls_name->str,
468 bt_config_component->type);
469 fprintf(stderr, ":\n");
470
471 if (bt_config_component->instance_name->len > 0) {
472 fprintf(stderr, " Name: %s\n",
473 bt_config_component->instance_name->str);
474 }
475
476 fprintf(stderr, " Parameters:\n");
477 print_value(stderr, bt_config_component->params, 8);
478 }
479
480 static
481 void print_bt_config_components(GPtrArray *array)
482 {
483 size_t i;
484
485 for (i = 0; i < array->len; i++) {
486 struct bt_config_component *cfg_component =
487 bt_config_get_component(array, i);
488 print_bt_config_component(cfg_component);
489 BT_PUT(cfg_component);
490 }
491 }
492
493 static
494 void print_plugin_paths(struct bt_value *plugin_paths)
495 {
496 fprintf(stderr, " Plugin paths:\n");
497 print_value(stderr, plugin_paths, 4);
498 }
499
500 static
501 void print_cfg_run(struct bt_config *cfg)
502 {
503 size_t i;
504
505 print_plugin_paths(cfg->plugin_paths);
506 fprintf(stderr, " Source component instances:\n");
507 print_bt_config_components(cfg->cmd_data.run.sources);
508
509 if (cfg->cmd_data.run.filters->len > 0) {
510 fprintf(stderr, " Filter component instances:\n");
511 print_bt_config_components(cfg->cmd_data.run.filters);
512 }
513
514 fprintf(stderr, " Sink component instances:\n");
515 print_bt_config_components(cfg->cmd_data.run.sinks);
516 fprintf(stderr, " Connections:\n");
517
518 for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
519 struct bt_config_connection *cfg_connection =
520 g_ptr_array_index(cfg->cmd_data.run.connections,
521 i);
522
523 fprintf(stderr, " %s%s%s -> %s%s%s\n",
524 cfg_connection->upstream_comp_name->str,
525 cfg_connection->upstream_port_glob->len > 0 ? "." : "",
526 cfg_connection->upstream_port_glob->str,
527 cfg_connection->downstream_comp_name->str,
528 cfg_connection->downstream_port_glob->len > 0 ? "." : "",
529 cfg_connection->downstream_port_glob->str);
530 }
531 }
532
533 static
534 void print_cfg_list_plugins(struct bt_config *cfg)
535 {
536 print_plugin_paths(cfg->plugin_paths);
537 }
538
539 static
540 void print_cfg_help(struct bt_config *cfg)
541 {
542 print_plugin_paths(cfg->plugin_paths);
543 }
544
545 static
546 void print_cfg_print_ctf_metadata(struct bt_config *cfg)
547 {
548 print_plugin_paths(cfg->plugin_paths);
549 fprintf(stderr, " Path: %s\n",
550 cfg->cmd_data.print_ctf_metadata.path->str);
551 }
552
553 static
554 void print_cfg_print_lttng_live_sessions(struct bt_config *cfg)
555 {
556 print_plugin_paths(cfg->plugin_paths);
557 fprintf(stderr, " URL: %s\n",
558 cfg->cmd_data.print_lttng_live_sessions.url->str);
559 }
560
561 static
562 void print_cfg_query(struct bt_config *cfg)
563 {
564 print_plugin_paths(cfg->plugin_paths);
565 fprintf(stderr, " Object: `%s`\n", cfg->cmd_data.query.object->str);
566 fprintf(stderr, " Component class:\n");
567 print_bt_config_component(cfg->cmd_data.query.cfg_component);
568 }
569
570 static
571 void print_cfg(struct bt_config *cfg)
572 {
573 if (!BT_LOG_ON_INFO) {
574 return;
575 }
576
577 BT_LOGI_STR("Configuration:");
578 fprintf(stderr, " Debug mode: %s\n", cfg->debug ? "yes" : "no");
579 fprintf(stderr, " Verbose mode: %s\n", cfg->verbose ? "yes" : "no");
580
581 switch (cfg->command) {
582 case BT_CONFIG_COMMAND_RUN:
583 print_cfg_run(cfg);
584 break;
585 case BT_CONFIG_COMMAND_LIST_PLUGINS:
586 print_cfg_list_plugins(cfg);
587 break;
588 case BT_CONFIG_COMMAND_HELP:
589 print_cfg_help(cfg);
590 break;
591 case BT_CONFIG_COMMAND_QUERY:
592 print_cfg_query(cfg);
593 break;
594 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
595 print_cfg_print_ctf_metadata(cfg);
596 break;
597 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
598 print_cfg_print_lttng_live_sessions(cfg);
599 break;
600 default:
601 abort();
602 }
603 }
604
605 static
606 void add_to_loaded_plugins(struct bt_plugin_set *plugin_set)
607 {
608 int64_t i;
609 int64_t count;
610
611 count = bt_plugin_set_get_plugin_count(plugin_set);
612 assert(count >= 0);
613
614 for (i = 0; i < count; i++) {
615 struct bt_plugin *plugin =
616 bt_plugin_set_get_plugin(plugin_set, i);
617 struct bt_plugin *loaded_plugin =
618 find_plugin(bt_plugin_get_name(plugin));
619
620 assert(plugin);
621
622 if (loaded_plugin) {
623 BT_LOGI("Not using plugin: another one already exists with the same name: "
624 "plugin-name=\"%s\", plugin-path=\"%s\", "
625 "existing-plugin-path=\"%s\"",
626 bt_plugin_get_name(plugin),
627 bt_plugin_get_path(plugin),
628 bt_plugin_get_path(loaded_plugin));
629 bt_put(loaded_plugin);
630 } else {
631 /* Add to global array. */
632 BT_LOGD("Adding plugin to loaded plugins: plugin-path=\"%s\"",
633 bt_plugin_get_name(plugin));
634 g_ptr_array_add(loaded_plugins, bt_get(plugin));
635 }
636
637 bt_put(plugin);
638 }
639 }
640
641 static
642 int load_dynamic_plugins(struct bt_value *plugin_paths)
643 {
644 int nr_paths, i, ret = 0;
645
646 nr_paths = bt_value_array_size(plugin_paths);
647 if (nr_paths < 0) {
648 BT_LOGE_STR("Cannot load dynamic plugins: no plugin path.");
649 ret = -1;
650 goto end;
651 }
652
653 BT_LOGI("Loading dynamic plugins.");
654
655 for (i = 0; i < nr_paths; i++) {
656 struct bt_value *plugin_path_value = NULL;
657 const char *plugin_path;
658 struct bt_plugin_set *plugin_set;
659 enum bt_value_status status;
660
661 plugin_path_value = bt_value_array_get(plugin_paths, i);
662 status = bt_value_string_get(plugin_path_value, &plugin_path);
663 if (status != BT_VALUE_STATUS_OK) {
664 BT_LOGD_STR("Cannot get plugin path string.");
665 BT_PUT(plugin_path_value);
666 continue;
667 }
668
669 /*
670 * Skip this if the directory does not exist because
671 * bt_plugin_create_all_from_dir() expects an existing
672 * directory.
673 */
674 if (!g_file_test(plugin_path, G_FILE_TEST_IS_DIR)) {
675 BT_LOGV("Skipping nonexistent directory path: "
676 "path=\"%s\"", plugin_path);
677 BT_PUT(plugin_path_value);
678 continue;
679 }
680
681 plugin_set = bt_plugin_create_all_from_dir(plugin_path, false);
682 if (!plugin_set) {
683 BT_LOGD("Unable to load dynamic plugins: path=\"%s\"",
684 plugin_path);
685 BT_PUT(plugin_path_value);
686 continue;
687 }
688
689 add_to_loaded_plugins(plugin_set);
690 bt_put(plugin_set);
691 BT_PUT(plugin_path_value);
692 }
693 end:
694 return ret;
695 }
696
697 static
698 int load_static_plugins(void)
699 {
700 int ret = 0;
701 struct bt_plugin_set *plugin_set;
702
703 BT_LOGI("Loading static plugins.");
704 plugin_set = bt_plugin_create_all_from_static();
705 if (!plugin_set) {
706 BT_LOGE("Unable to load static plugins.");
707 ret = -1;
708 goto end;
709 }
710
711 add_to_loaded_plugins(plugin_set);
712 bt_put(plugin_set);
713 end:
714 return ret;
715 }
716
717 static
718 int load_all_plugins(struct bt_value *plugin_paths)
719 {
720 int ret = 0;
721
722 if (load_dynamic_plugins(plugin_paths)) {
723 ret = -1;
724 goto end;
725 }
726
727 if (load_static_plugins()) {
728 ret = -1;
729 goto end;
730 }
731
732 BT_LOGI("Loaded all plugins: count=%u", loaded_plugins->len);
733
734 end:
735 return ret;
736 }
737
738 static
739 void print_plugin_info(struct bt_plugin *plugin)
740 {
741 unsigned int major, minor, patch;
742 const char *extra;
743 enum bt_plugin_status version_status;
744 const char *plugin_name;
745 const char *path;
746 const char *author;
747 const char *license;
748 const char *plugin_description;
749
750 plugin_name = bt_plugin_get_name(plugin);
751 path = bt_plugin_get_path(plugin);
752 author = bt_plugin_get_author(plugin);
753 license = bt_plugin_get_license(plugin);
754 plugin_description = bt_plugin_get_description(plugin);
755 version_status = bt_plugin_get_version(plugin, &major, &minor,
756 &patch, &extra);
757 printf("%s%s%s%s:\n", bt_common_color_bold(),
758 bt_common_color_fg_blue(), plugin_name,
759 bt_common_color_reset());
760 if (path) {
761 printf(" %sPath%s: %s\n", bt_common_color_bold(),
762 bt_common_color_reset(), path);
763 } else {
764 puts(" Built-in");
765 }
766
767 if (version_status == BT_PLUGIN_STATUS_OK) {
768 printf(" %sVersion%s: %u.%u.%u",
769 bt_common_color_bold(), bt_common_color_reset(),
770 major, minor, patch);
771
772 if (extra) {
773 printf("%s", extra);
774 }
775
776 printf("\n");
777 }
778
779 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
780 bt_common_color_reset(),
781 plugin_description ? plugin_description : "(None)");
782 printf(" %sAuthor%s: %s\n", bt_common_color_bold(),
783 bt_common_color_reset(), author ? author : "(Unknown)");
784 printf(" %sLicense%s: %s\n", bt_common_color_bold(),
785 bt_common_color_reset(),
786 license ? license : "(Unknown)");
787 }
788
789 static
790 int cmd_query(struct bt_config *cfg)
791 {
792 int ret = 0;
793 struct bt_component_class *comp_cls = NULL;
794 struct bt_value *results = NULL;
795
796 comp_cls = find_component_class(cfg->cmd_data.query.cfg_component->plugin_name->str,
797 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
798 cfg->cmd_data.query.cfg_component->type);
799 if (!comp_cls) {
800 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
801 "comp-cls-name=\"%s\", comp-cls-type=%d",
802 cfg->cmd_data.query.cfg_component->plugin_name->str,
803 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
804 cfg->cmd_data.query.cfg_component->type);
805 fprintf(stderr, "%s%sCannot find component class %s",
806 bt_common_color_bold(),
807 bt_common_color_fg_red(),
808 bt_common_color_reset());
809 print_plugin_comp_cls_opt(stderr,
810 cfg->cmd_data.query.cfg_component->plugin_name->str,
811 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
812 cfg->cmd_data.query.cfg_component->type);
813 fprintf(stderr, "\n");
814 ret = -1;
815 goto end;
816 }
817
818 results = bt_component_class_query(comp_cls,
819 cfg->cmd_data.query.object->str,
820 cfg->cmd_data.query.cfg_component->params);
821 if (!results) {
822 BT_LOGE("Failed to query component class: plugin-name=\"%s\", "
823 "comp-cls-name=\"%s\", comp-cls-type=%d "
824 "object=\"%s\"",
825 cfg->cmd_data.query.cfg_component->plugin_name->str,
826 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
827 cfg->cmd_data.query.cfg_component->type,
828 cfg->cmd_data.query.object->str);
829 fprintf(stderr, "%s%sFailed to query info to %s",
830 bt_common_color_bold(),
831 bt_common_color_fg_red(),
832 bt_common_color_reset());
833 print_plugin_comp_cls_opt(stderr,
834 cfg->cmd_data.query.cfg_component->plugin_name->str,
835 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
836 cfg->cmd_data.query.cfg_component->type);
837 fprintf(stderr, "%s%s with object `%s`%s\n",
838 bt_common_color_bold(),
839 bt_common_color_fg_red(),
840 cfg->cmd_data.query.object->str,
841 bt_common_color_reset());
842 ret = -1;
843 goto end;
844 }
845
846 print_value(stdout, results, 0);
847
848 end:
849 bt_put(comp_cls);
850 bt_put(results);
851 return ret;
852 }
853
854 static
855 int cmd_help(struct bt_config *cfg)
856 {
857 int ret = 0;
858 struct bt_plugin *plugin = NULL;
859 size_t i;
860
861 plugin = find_plugin(cfg->cmd_data.help.cfg_component->plugin_name->str);
862 if (!plugin) {
863 BT_LOGE("Cannot find plugin: plugin-name=\"%s\"",
864 cfg->cmd_data.help.cfg_component->plugin_name->str);
865 fprintf(stderr, "%s%sCannot find plugin %s%s%s\n",
866 bt_common_color_bold(), bt_common_color_fg_red(),
867 bt_common_color_fg_blue(),
868 cfg->cmd_data.help.cfg_component->plugin_name->str,
869 bt_common_color_reset());
870 ret = -1;
871 goto end;
872 }
873
874 print_plugin_info(plugin);
875 printf(" %sComponent classes%s: %d\n",
876 bt_common_color_bold(),
877 bt_common_color_reset(),
878 (int) bt_plugin_get_component_class_count(plugin));
879
880
881 if (cfg->cmd_data.help.cfg_component->type !=
882 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
883 struct bt_component_class *needed_comp_cls =
884 find_component_class(
885 cfg->cmd_data.help.cfg_component->plugin_name->str,
886 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
887 cfg->cmd_data.help.cfg_component->type);
888
889 if (!needed_comp_cls) {
890 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
891 "comp-cls-name=\"%s\", comp-cls-type=%d",
892 cfg->cmd_data.help.cfg_component->plugin_name->str,
893 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
894 cfg->cmd_data.help.cfg_component->type);
895 fprintf(stderr, "\n%s%sCannot find component class %s",
896 bt_common_color_bold(),
897 bt_common_color_fg_red(),
898 bt_common_color_reset());
899 print_plugin_comp_cls_opt(stderr,
900 cfg->cmd_data.help.cfg_component->plugin_name->str,
901 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
902 cfg->cmd_data.help.cfg_component->type);
903 fprintf(stderr, "\n");
904 ret = -1;
905 goto end;
906 }
907
908 bt_put(needed_comp_cls);
909 }
910
911 for (i = 0; i < bt_plugin_get_component_class_count(plugin); i++) {
912 struct bt_component_class *comp_cls =
913 bt_plugin_get_component_class_by_index(plugin, i);
914 const char *comp_class_name =
915 bt_component_class_get_name(comp_cls);
916 const char *comp_class_description =
917 bt_component_class_get_description(comp_cls);
918 const char *comp_class_help =
919 bt_component_class_get_help(comp_cls);
920 enum bt_component_class_type type =
921 bt_component_class_get_type(comp_cls);
922
923 assert(comp_cls);
924
925 if (cfg->cmd_data.help.cfg_component->type !=
926 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
927 if (strcmp(cfg->cmd_data.help.cfg_component->comp_cls_name->str,
928 comp_class_name) != 0 &&
929 type ==
930 cfg->cmd_data.help.cfg_component->type) {
931 bt_put(comp_cls);
932 continue;
933 }
934 }
935
936 printf("\n");
937 print_plugin_comp_cls_opt(stdout,
938 cfg->cmd_data.help.cfg_component->plugin_name->str,
939 comp_class_name,
940 type);
941 printf("\n");
942 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
943 bt_common_color_reset(),
944 comp_class_description ? comp_class_description : "(None)");
945
946 if (comp_class_help) {
947 printf("\n%s\n", comp_class_help);
948 }
949
950 bt_put(comp_cls);
951 }
952
953 end:
954 bt_put(plugin);
955 return ret;
956 }
957
958 static
959 int cmd_list_plugins(struct bt_config *cfg)
960 {
961 int ret = 0;
962 int plugins_count, component_classes_count = 0, i;
963
964 printf("From the following plugin paths:\n\n");
965 print_value(stdout, cfg->plugin_paths, 2);
966 printf("\n");
967 plugins_count = loaded_plugins->len;
968 if (plugins_count == 0) {
969 printf("No plugins found.\n");
970 goto end;
971 }
972
973 for (i = 0; i < plugins_count; i++) {
974 struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
975
976 component_classes_count += bt_plugin_get_component_class_count(plugin);
977 }
978
979 printf("Found %s%d%s component classes in %s%d%s plugins.\n",
980 bt_common_color_bold(),
981 component_classes_count,
982 bt_common_color_reset(),
983 bt_common_color_bold(),
984 plugins_count,
985 bt_common_color_reset());
986
987 for (i = 0; i < plugins_count; i++) {
988 int j;
989 struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
990
991 component_classes_count =
992 bt_plugin_get_component_class_count(plugin);
993 printf("\n");
994 print_plugin_info(plugin);
995
996 if (component_classes_count == 0) {
997 printf(" %sComponent classes%s: (none)\n",
998 bt_common_color_bold(),
999 bt_common_color_reset());
1000 } else {
1001 printf(" %sComponent classes%s:\n",
1002 bt_common_color_bold(),
1003 bt_common_color_reset());
1004 }
1005
1006 for (j = 0; j < component_classes_count; j++) {
1007 struct bt_component_class *comp_class =
1008 bt_plugin_get_component_class_by_index(
1009 plugin, j);
1010 const char *comp_class_name =
1011 bt_component_class_get_name(comp_class);
1012 const char *comp_class_description =
1013 bt_component_class_get_description(comp_class);
1014 enum bt_component_class_type type =
1015 bt_component_class_get_type(comp_class);
1016
1017 printf(" ");
1018 print_plugin_comp_cls_opt(stdout,
1019 bt_plugin_get_name(plugin), comp_class_name,
1020 type);
1021
1022 if (comp_class_description) {
1023 printf(": %s", comp_class_description);
1024 }
1025
1026 printf("\n");
1027 bt_put(comp_class);
1028 }
1029 }
1030
1031 end:
1032 return ret;
1033 }
1034
1035 static
1036 int cmd_print_lttng_live_sessions(struct bt_config *cfg)
1037 {
1038 int ret = 0;
1039 struct bt_component_class *comp_cls = NULL;
1040 struct bt_value *results = NULL;
1041 struct bt_value *params = NULL;
1042 struct bt_value *map = NULL;
1043 struct bt_value *v = NULL;
1044 static const char * const plugin_name = "ctf";
1045 static const char * const comp_cls_name = "lttng-live";
1046 static const enum bt_component_class_type comp_cls_type =
1047 BT_COMPONENT_CLASS_TYPE_SOURCE;
1048 int64_t array_size, i;
1049
1050 assert(cfg->cmd_data.print_lttng_live_sessions.url);
1051 comp_cls = find_component_class(plugin_name, comp_cls_name,
1052 comp_cls_type);
1053 if (!comp_cls) {
1054 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
1055 "comp-cls-name=\"%s\", comp-cls-type=%d",
1056 plugin_name, comp_cls_name,
1057 BT_COMPONENT_CLASS_TYPE_SOURCE);
1058 fprintf(stderr, "%s%sCannot find component class %s",
1059 bt_common_color_bold(),
1060 bt_common_color_fg_red(),
1061 bt_common_color_reset());
1062 print_plugin_comp_cls_opt(stderr, plugin_name,
1063 comp_cls_name, comp_cls_type);
1064 fprintf(stderr, "\n");
1065 goto error;
1066 }
1067
1068 params = bt_value_map_create();
1069 if (!params) {
1070 goto error;
1071 }
1072
1073 ret = bt_value_map_insert_string(params, "url",
1074 cfg->cmd_data.print_lttng_live_sessions.url->str);
1075 if (ret) {
1076 goto error;
1077 }
1078
1079 results = bt_component_class_query(comp_cls, "sessions",
1080 params);
1081 if (!results) {
1082 BT_LOGE_STR("Failed to query for sessions.");
1083 fprintf(stderr, "%s%sFailed to request sessions%s\n",
1084 bt_common_color_bold(),
1085 bt_common_color_fg_red(),
1086 bt_common_color_reset());
1087 goto error;
1088 }
1089
1090 if (!bt_value_is_array(results)) {
1091 BT_LOGE_STR("Expecting an array for sessions query.");
1092 fprintf(stderr, "%s%sUnexpected type returned by session query%s\n",
1093 bt_common_color_bold(),
1094 bt_common_color_fg_red(),
1095 bt_common_color_reset());
1096 goto error;
1097 }
1098
1099 array_size = bt_value_array_size(results);
1100 for (i = 0; i < array_size; i++) {
1101 const char *url_text;
1102 int64_t timer_us, streams, clients;
1103
1104 map = bt_value_array_get(results, i);
1105 if (!map) {
1106 BT_LOGE_STR("Unexpected empty array entry.");
1107 goto error;
1108 }
1109 if (!bt_value_is_map(map)) {
1110 BT_LOGE_STR("Unexpected entry type.");
1111 goto error;
1112 }
1113
1114 v = bt_value_map_get(map, "url");
1115 if (!v) {
1116 BT_LOGE_STR("Unexpected empty array \"url\" entry.");
1117 goto error;
1118 }
1119 ret = bt_value_string_get(v, &url_text);
1120 assert(ret == 0);
1121 printf("%s", url_text);
1122 BT_PUT(v);
1123
1124 v = bt_value_map_get(map, "timer-us");
1125 if (!v) {
1126 BT_LOGE_STR("Unexpected empty array \"timer-us\" entry.");
1127 goto error;
1128 }
1129 ret = bt_value_integer_get(v, &timer_us);
1130 assert(ret == 0);
1131 printf(" (timer = %" PRIu64 ", ", timer_us);
1132 BT_PUT(v);
1133
1134 v = bt_value_map_get(map, "stream-count");
1135 if (!v) {
1136 BT_LOGE_STR("Unexpected empty array \"stream-count\" entry.");
1137 goto error;
1138 }
1139 ret = bt_value_integer_get(v, &streams);
1140 assert(ret == 0);
1141 printf("%" PRIu64 " stream(s), ", streams);
1142 BT_PUT(v);
1143
1144 v = bt_value_map_get(map, "client-count");
1145 if (!v) {
1146 BT_LOGE_STR("Unexpected empty array \"client-count\" entry.");
1147 goto error;
1148 }
1149 ret = bt_value_integer_get(v, &clients);
1150 assert(ret == 0);
1151 printf("%" PRIu64 " client(s) connected)\n", clients);
1152 BT_PUT(v);
1153
1154 BT_PUT(map);
1155 }
1156 end:
1157 bt_put(v);
1158 bt_put(map);
1159 bt_put(results);
1160 bt_put(params);
1161 bt_put(comp_cls);
1162 return 0;
1163
1164 error:
1165 ret = -1;
1166 goto end;
1167 }
1168
1169 static
1170 int cmd_print_ctf_metadata(struct bt_config *cfg)
1171 {
1172 int ret = 0;
1173 struct bt_component_class *comp_cls = NULL;
1174 struct bt_value *results = NULL;
1175 struct bt_value *params = NULL;
1176 struct bt_value *metadata_text_value = NULL;
1177 const char *metadata_text = NULL;
1178 static const char * const plugin_name = "ctf";
1179 static const char * const comp_cls_name = "fs";
1180 static const enum bt_component_class_type comp_cls_type =
1181 BT_COMPONENT_CLASS_TYPE_SOURCE;
1182
1183 assert(cfg->cmd_data.print_ctf_metadata.path);
1184 comp_cls = find_component_class(plugin_name, comp_cls_name,
1185 comp_cls_type);
1186 if (!comp_cls) {
1187 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
1188 "comp-cls-name=\"%s\", comp-cls-type=%d",
1189 plugin_name, comp_cls_name,
1190 BT_COMPONENT_CLASS_TYPE_SOURCE);
1191 fprintf(stderr, "%s%sCannot find component class %s",
1192 bt_common_color_bold(),
1193 bt_common_color_fg_red(),
1194 bt_common_color_reset());
1195 print_plugin_comp_cls_opt(stderr, plugin_name,
1196 comp_cls_name, comp_cls_type);
1197 fprintf(stderr, "\n");
1198 ret = -1;
1199 goto end;
1200 }
1201
1202 params = bt_value_map_create();
1203 if (!params) {
1204 ret = -1;
1205 goto end;
1206 }
1207
1208 ret = bt_value_map_insert_string(params, "path",
1209 cfg->cmd_data.print_ctf_metadata.path->str);
1210 if (ret) {
1211 ret = -1;
1212 goto end;
1213 }
1214
1215 results = bt_component_class_query(comp_cls, "metadata-info",
1216 params);
1217 if (!results) {
1218 ret = -1;
1219 BT_LOGE_STR("Failed to query for metadata info.");
1220 fprintf(stderr, "%s%sFailed to request metadata info%s\n",
1221 bt_common_color_bold(),
1222 bt_common_color_fg_red(),
1223 bt_common_color_reset());
1224 goto end;
1225 }
1226
1227 metadata_text_value = bt_value_map_get(results, "text");
1228 if (!metadata_text_value) {
1229 BT_LOGE_STR("Cannot find `text` string value in the resulting metadata info object.");
1230 ret = -1;
1231 goto end;
1232 }
1233
1234 ret = bt_value_string_get(metadata_text_value, &metadata_text);
1235 assert(ret == 0);
1236 printf("%s\n", metadata_text);
1237
1238 end:
1239 bt_put(results);
1240 bt_put(params);
1241 bt_put(metadata_text_value);
1242 bt_put(comp_cls);
1243 return 0;
1244 }
1245
1246 struct port_id {
1247 char *instance_name;
1248 char *port_name;
1249 };
1250
1251 struct trace_range {
1252 uint64_t intersection_range_begin_ns;
1253 uint64_t intersection_range_end_ns;
1254 };
1255
1256 static
1257 guint port_id_hash(gconstpointer v)
1258 {
1259 const struct port_id *id = v;
1260
1261 assert(id->instance_name);
1262 assert(id->port_name);
1263
1264 return g_str_hash(id->instance_name) ^ g_str_hash(id->port_name);
1265 }
1266
1267 static
1268 gboolean port_id_equal(gconstpointer v1, gconstpointer v2)
1269 {
1270 const struct port_id *id1 = v1;
1271 const struct port_id *id2 = v2;
1272
1273 return !strcmp(id1->instance_name, id2->instance_name) &&
1274 !strcmp(id1->port_name, id2->port_name);
1275 }
1276
1277 static
1278 void port_id_destroy(gpointer data)
1279 {
1280 struct port_id *id = data;
1281
1282 free(id->instance_name);
1283 free(id->port_name);
1284 free(id);
1285 }
1286
1287 static
1288 void trace_range_destroy(gpointer data)
1289 {
1290 free(data);
1291 }
1292
1293 struct cmd_run_ctx {
1294 /* Owned by this */
1295 GHashTable *components;
1296
1297 /* Owned by this */
1298 struct bt_graph *graph;
1299
1300 /* Weak */
1301 struct bt_config *cfg;
1302
1303 bool connect_ports;
1304
1305 bool stream_intersection_mode;
1306
1307 /*
1308 * Association of struct port_id -> struct trace_range.
1309 */
1310 GHashTable *intersections;
1311 };
1312
1313 /* Returns a timestamp of the form "(-)s.ns" */
1314 static
1315 char *s_from_ns(int64_t ns)
1316 {
1317 int ret;
1318 char *s_ret = NULL;
1319 bool is_negative;
1320 int64_t ts_sec_abs, ts_nsec_abs;
1321 int64_t ts_sec = ns / NSEC_PER_SEC;
1322 int64_t ts_nsec = ns % NSEC_PER_SEC;
1323
1324 if (ts_sec >= 0 && ts_nsec >= 0) {
1325 is_negative = false;
1326 ts_sec_abs = ts_sec;
1327 ts_nsec_abs = ts_nsec;
1328 } else if (ts_sec > 0 && ts_nsec < 0) {
1329 is_negative = false;
1330 ts_sec_abs = ts_sec - 1;
1331 ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
1332 } else if (ts_sec == 0 && ts_nsec < 0) {
1333 is_negative = true;
1334 ts_sec_abs = ts_sec;
1335 ts_nsec_abs = -ts_nsec;
1336 } else if (ts_sec < 0 && ts_nsec > 0) {
1337 is_negative = true;
1338 ts_sec_abs = -(ts_sec + 1);
1339 ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
1340 } else if (ts_sec < 0 && ts_nsec == 0) {
1341 is_negative = true;
1342 ts_sec_abs = -ts_sec;
1343 ts_nsec_abs = ts_nsec;
1344 } else { /* (ts_sec < 0 && ts_nsec < 0) */
1345 is_negative = true;
1346 ts_sec_abs = -ts_sec;
1347 ts_nsec_abs = -ts_nsec;
1348 }
1349
1350 ret = asprintf(&s_ret, "%s%" PRId64 ".%09" PRId64,
1351 is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
1352 if (ret < 0) {
1353 s_ret = NULL;
1354 }
1355 return s_ret;
1356 }
1357
1358 static
1359 int cmd_run_ctx_connect_upstream_port_to_downstream_component(
1360 struct cmd_run_ctx *ctx, struct bt_component *upstream_comp,
1361 struct bt_port *upstream_port,
1362 struct bt_config_connection *cfg_conn)
1363 {
1364 int ret = 0;
1365 GQuark downstreamp_comp_name_quark;
1366 struct bt_component *downstream_comp;
1367 int64_t downstream_port_count;
1368 uint64_t i;
1369 int64_t (*port_count_fn)(struct bt_component *);
1370 struct bt_port *(*port_by_index_fn)(struct bt_component *, uint64_t);
1371 enum bt_graph_status status = BT_GRAPH_STATUS_ERROR;
1372 bool insert_trimmer = false;
1373 struct bt_value *trimmer_params = NULL;
1374 char *intersection_begin = NULL;
1375 char *intersection_end = NULL;
1376 struct bt_component *trimmer = NULL;
1377 struct bt_component_class *trimmer_class = NULL;
1378 struct bt_port *trimmer_input = NULL;
1379 struct bt_port *trimmer_output = NULL;
1380
1381 if (ctx->intersections &&
1382 bt_component_get_class_type(upstream_comp) ==
1383 BT_COMPONENT_CLASS_TYPE_SOURCE) {
1384 struct trace_range *range;
1385 struct port_id port_id = {
1386 .instance_name = (char *) bt_component_get_name(upstream_comp),
1387 .port_name = (char *) bt_port_get_name(upstream_port)
1388 };
1389
1390 if (!port_id.instance_name || !port_id.port_name) {
1391 goto error;
1392 }
1393
1394 range = (struct trace_range *) g_hash_table_lookup(
1395 ctx->intersections, &port_id);
1396 if (range) {
1397 enum bt_value_status status;
1398
1399 intersection_begin = s_from_ns(
1400 range->intersection_range_begin_ns);
1401 intersection_end = s_from_ns(
1402 range->intersection_range_end_ns);
1403 if (!intersection_begin || !intersection_end) {
1404 BT_LOGE_STR("Cannot create trimmer argument timestamp string.");
1405 goto error;
1406 }
1407
1408 insert_trimmer = true;
1409 trimmer_params = bt_value_map_create();
1410 if (!trimmer_params) {
1411 goto error;
1412 }
1413
1414 status = bt_value_map_insert_string(trimmer_params,
1415 "begin", intersection_begin);
1416 if (status != BT_VALUE_STATUS_OK) {
1417 goto error;
1418 }
1419 status = bt_value_map_insert_string(trimmer_params,
1420 "end", intersection_end);
1421 if (status != BT_VALUE_STATUS_OK) {
1422 goto error;
1423 }
1424 }
1425
1426 trimmer_class = find_component_class("utils", "trimmer",
1427 BT_COMPONENT_CLASS_TYPE_FILTER);
1428 if (!trimmer_class) {
1429 goto error;
1430 }
1431 }
1432
1433 BT_LOGI("Connecting upstream port to the next available downstream port: "
1434 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1435 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1436 upstream_port, bt_port_get_name(upstream_port),
1437 cfg_conn->downstream_comp_name->str,
1438 cfg_conn->arg->str);
1439 downstreamp_comp_name_quark = g_quark_from_string(
1440 cfg_conn->downstream_comp_name->str);
1441 assert(downstreamp_comp_name_quark > 0);
1442 downstream_comp = g_hash_table_lookup(ctx->components,
1443 GUINT_TO_POINTER(downstreamp_comp_name_quark));
1444 if (!downstream_comp) {
1445 BT_LOGE("Cannot find downstream component: comp-name=\"%s\", "
1446 "conn-arg=\"%s\"", cfg_conn->downstream_comp_name->str,
1447 cfg_conn->arg->str);
1448 fprintf(stderr, "Cannot create connection: cannot find downstream component: %s\n",
1449 cfg_conn->arg->str);
1450 goto error;
1451 }
1452
1453 if (bt_component_is_filter(downstream_comp)) {
1454 port_count_fn = bt_component_filter_get_input_port_count;
1455 port_by_index_fn = bt_component_filter_get_input_port_by_index;
1456 } else if (bt_component_is_sink(downstream_comp)) {
1457 port_count_fn = bt_component_sink_get_input_port_count;
1458 port_by_index_fn = bt_component_sink_get_input_port_by_index;
1459 } else {
1460 /*
1461 * Should never happen because the connections are
1462 * validated before we get here.
1463 */
1464 BT_LOGF("Invalid connection: downstream component is a source: "
1465 "conn-arg=\"%s\"", cfg_conn->arg->str);
1466 abort();
1467 }
1468
1469 downstream_port_count = port_count_fn(downstream_comp);
1470 assert(downstream_port_count >= 0);
1471
1472 for (i = 0; i < downstream_port_count; i++) {
1473 struct bt_port *downstream_port =
1474 port_by_index_fn(downstream_comp, i);
1475 const char *upstream_port_name;
1476 const char *downstream_port_name;
1477
1478 assert(downstream_port);
1479
1480 /* Skip port if it's already connected. */
1481 if (bt_port_is_connected(downstream_port)) {
1482 bt_put(downstream_port);
1483 BT_LOGD("Skipping downstream port: already connected: "
1484 "port-addr=%p, port-name=\"%s\"",
1485 downstream_port,
1486 bt_port_get_name(downstream_port));
1487 continue;
1488 }
1489
1490 downstream_port_name = bt_port_get_name(downstream_port);
1491 assert(downstream_port_name);
1492 upstream_port_name = bt_port_get_name(upstream_port);
1493 assert(upstream_port_name);
1494
1495 if (!bt_common_star_glob_match(
1496 cfg_conn->downstream_port_glob->str, SIZE_MAX,
1497 downstream_port_name, SIZE_MAX)) {
1498 bt_put(downstream_port);
1499 continue;
1500 }
1501
1502 if (insert_trimmer) {
1503 /*
1504 * In order to insert the trimmer between the two
1505 * components that were being connected, we create
1506 * a connection configuration entry which describes
1507 * a connection from the trimmer's output to the
1508 * original input that was being connected.
1509 *
1510 * Hence, the creation of the trimmer will cause the
1511 * graph "new port" listener to establish all downstream
1512 * connections as its output port is connected. We will
1513 * then establish the connection between the original
1514 * upstream source and the trimmer.
1515 */
1516 char *trimmer_name = NULL;
1517 enum bt_graph_status graph_status;
1518
1519 ret = asprintf(&trimmer_name, "%s-%s",
1520 "stream-intersection-trimmer",
1521 upstream_port_name);
1522 if (ret < 0) {
1523 goto error;
1524 }
1525 ret = 0;
1526
1527 ctx->connect_ports = false;
1528 graph_status = bt_graph_add_component(ctx->graph,
1529 trimmer_class, trimmer_name, trimmer_params,
1530 &trimmer);
1531 free(trimmer_name);
1532 if (graph_status != BT_GRAPH_STATUS_OK) {
1533 goto error;
1534 }
1535 assert(trimmer);
1536
1537 trimmer_input =
1538 bt_component_filter_get_input_port_by_index(
1539 trimmer, 0);
1540 if (!trimmer_input) {
1541 goto error;
1542 }
1543 trimmer_output =
1544 bt_component_filter_get_output_port_by_index(
1545 trimmer, 0);
1546 if (!trimmer_output) {
1547 goto error;
1548 }
1549
1550 /*
1551 * Replace the current downstream port by the trimmer's
1552 * upstream port.
1553 */
1554 BT_MOVE(downstream_port, trimmer_input);
1555 downstream_port_name = bt_port_get_name(
1556 downstream_port);
1557 if (!downstream_port_name) {
1558 goto error;
1559 }
1560 }
1561
1562 /* We have a winner! */
1563 status = bt_graph_connect_ports(ctx->graph,
1564 upstream_port, downstream_port, NULL);
1565 BT_PUT(downstream_port);
1566 switch (status) {
1567 case BT_GRAPH_STATUS_OK:
1568 break;
1569 case BT_GRAPH_STATUS_CANCELED:
1570 BT_LOGI_STR("Graph was canceled by user.");
1571 status = BT_GRAPH_STATUS_OK;
1572 break;
1573 case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
1574 BT_LOGE("A component refused a connection to one of its ports: "
1575 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1576 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1577 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1578 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1579 "conn-arg=\"%s\"",
1580 upstream_comp, bt_component_get_name(upstream_comp),
1581 upstream_port, bt_port_get_name(upstream_port),
1582 downstream_comp, cfg_conn->downstream_comp_name->str,
1583 downstream_port, downstream_port_name,
1584 cfg_conn->arg->str);
1585 fprintf(stderr,
1586 "A component refused a connection to one of its ports (`%s` to `%s`): %s\n",
1587 bt_port_get_name(upstream_port),
1588 downstream_port_name,
1589 cfg_conn->arg->str);
1590 break;
1591 default:
1592 BT_LOGE("Cannot create connection: graph refuses to connect ports: "
1593 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1594 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1595 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1596 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1597 "conn-arg=\"%s\"",
1598 upstream_comp, bt_component_get_name(upstream_comp),
1599 upstream_port, bt_port_get_name(upstream_port),
1600 downstream_comp, cfg_conn->downstream_comp_name->str,
1601 downstream_port, downstream_port_name,
1602 cfg_conn->arg->str);
1603 fprintf(stderr,
1604 "Cannot create connection: graph refuses to connect ports (`%s` to `%s`): %s\n",
1605 bt_port_get_name(upstream_port),
1606 downstream_port_name,
1607 cfg_conn->arg->str);
1608 goto error;
1609 }
1610
1611 BT_LOGI("Connected component ports: "
1612 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1613 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1614 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1615 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1616 "conn-arg=\"%s\"",
1617 upstream_comp, bt_component_get_name(upstream_comp),
1618 upstream_port, bt_port_get_name(upstream_port),
1619 downstream_comp, cfg_conn->downstream_comp_name->str,
1620 downstream_port, downstream_port_name,
1621 cfg_conn->arg->str);
1622
1623 if (insert_trimmer) {
1624 /*
1625 * The first connection, from the source to the trimmer,
1626 * has been done. We now connect the trimmer to the
1627 * original downstream port.
1628 */
1629 ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
1630 ctx, trimmer, trimmer_output, cfg_conn);
1631 if (ret) {
1632 goto error;
1633 }
1634 ctx->connect_ports = true;
1635 }
1636
1637 /*
1638 * We found a matching downstream port: the search is
1639 * over.
1640 */
1641 goto end;
1642 }
1643
1644 /* No downstream port found */
1645 BT_LOGE("Cannot create connection: cannot find a matching downstream port for upstream port: "
1646 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1647 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1648 upstream_port, bt_port_get_name(upstream_port),
1649 cfg_conn->downstream_comp_name->str,
1650 cfg_conn->arg->str);
1651 fprintf(stderr,
1652 "Cannot create connection: cannot find a matching downstream port for upstream port `%s`: %s\n",
1653 bt_port_get_name(upstream_port), cfg_conn->arg->str);
1654
1655 error:
1656 ret = -1;
1657
1658 end:
1659 free(intersection_begin);
1660 free(intersection_end);
1661 BT_PUT(trimmer_params);
1662 BT_PUT(trimmer_class);
1663 BT_PUT(trimmer);
1664 BT_PUT(trimmer_input);
1665 BT_PUT(trimmer_output);
1666 return ret;
1667 }
1668
1669 static
1670 int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx,
1671 struct bt_port *upstream_port)
1672 {
1673 int ret = 0;
1674 const char *upstream_port_name;
1675 const char *upstream_comp_name;
1676 struct bt_component *upstream_comp = NULL;
1677 size_t i;
1678
1679 assert(ctx);
1680 assert(upstream_port);
1681 upstream_port_name = bt_port_get_name(upstream_port);
1682 assert(upstream_port_name);
1683 upstream_comp = bt_port_get_component(upstream_port);
1684 if (!upstream_comp) {
1685 BT_LOGW("Upstream port to connect is not part of a component: "
1686 "port-addr=%p, port-name=\"%s\"",
1687 upstream_port, upstream_port_name);
1688 ret = -1;
1689 goto end;
1690 }
1691
1692 upstream_comp_name = bt_component_get_name(upstream_comp);
1693 assert(upstream_comp_name);
1694 BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", "
1695 "port-addr=%p, port-name=\"%s\"",
1696 upstream_comp, upstream_comp_name,
1697 upstream_port, upstream_port_name);
1698
1699 for (i = 0; i < ctx->cfg->cmd_data.run.connections->len; i++) {
1700 struct bt_config_connection *cfg_conn =
1701 g_ptr_array_index(
1702 ctx->cfg->cmd_data.run.connections, i);
1703
1704 if (strcmp(cfg_conn->upstream_comp_name->str,
1705 upstream_comp_name)) {
1706 continue;
1707 }
1708
1709 if (!bt_common_star_glob_match(
1710 cfg_conn->upstream_port_glob->str,
1711 SIZE_MAX, upstream_port_name, SIZE_MAX)) {
1712 continue;
1713 }
1714
1715 ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
1716 ctx, upstream_comp, upstream_port, cfg_conn);
1717 if (ret) {
1718 BT_LOGE("Cannot connect upstream port: "
1719 "port-addr=%p, port-name=\"%s\"",
1720 upstream_port,
1721 upstream_port_name);
1722 fprintf(stderr,
1723 "Cannot connect port `%s` of component `%s` to a downstream port: %s\n",
1724 upstream_port_name,
1725 upstream_comp_name,
1726 cfg_conn->arg->str);
1727 goto error;
1728 }
1729 goto end;
1730 }
1731
1732 BT_LOGE("Cannot connect upstream port: port does not match any connection argument: "
1733 "port-addr=%p, port-name=\"%s\"", upstream_port,
1734 upstream_port_name);
1735 fprintf(stderr,
1736 "Cannot create connection: upstream port `%s` does not match any connection\n",
1737 upstream_port_name);
1738
1739 error:
1740 ret = -1;
1741
1742 end:
1743 bt_put(upstream_comp);
1744 return ret;
1745 }
1746
1747 static
1748 void graph_port_added_listener(struct bt_port *port, void *data)
1749 {
1750 struct bt_component *comp = NULL;
1751 struct cmd_run_ctx *ctx = data;
1752
1753 comp = bt_port_get_component(port);
1754 BT_LOGI("Port added to a graph's component: comp-addr=%p, "
1755 "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
1756 comp, comp ? bt_component_get_name(comp) : "",
1757 port, bt_port_get_name(port));
1758
1759 if (!ctx->connect_ports) {
1760 goto end;
1761 }
1762
1763 if (!comp) {
1764 BT_LOGW_STR("Port has no component.");
1765 goto end;
1766 }
1767
1768 if (bt_port_is_connected(port)) {
1769 BT_LOGW_STR("Port is already connected.");
1770 goto end;
1771 }
1772
1773 if (!bt_port_is_output(port)) {
1774 BT_LOGI_STR("Skipping input port.");
1775 goto end;
1776 }
1777
1778 if (cmd_run_ctx_connect_upstream_port(ctx, port)) {
1779 BT_LOGF_STR("Cannot connect upstream port.");
1780 fprintf(stderr, "Added port could not be connected: aborting\n");
1781 abort();
1782 }
1783
1784 end:
1785 bt_put(comp);
1786 return;
1787 }
1788
1789 static
1790 void graph_port_removed_listener(struct bt_component *component,
1791 struct bt_port *port, void *data)
1792 {
1793 BT_LOGI("Port removed from a graph's component: comp-addr=%p, "
1794 "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
1795 component, bt_component_get_name(component),
1796 port, bt_port_get_name(port));
1797 }
1798
1799 static
1800 void graph_ports_connected_listener(struct bt_port *upstream_port,
1801 struct bt_port *downstream_port, void *data)
1802 {
1803 struct bt_component *upstream_comp = bt_port_get_component(upstream_port);
1804 struct bt_component *downstream_comp = bt_port_get_component(downstream_port);
1805
1806 assert(upstream_comp);
1807 assert(downstream_comp);
1808 BT_LOGI("Graph's component ports connected: "
1809 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1810 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1811 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1812 "downstream-port-addr=%p, downstream-port-name=\"%s\"",
1813 upstream_comp, bt_component_get_name(upstream_comp),
1814 upstream_port, bt_port_get_name(upstream_port),
1815 downstream_comp, bt_component_get_name(downstream_comp),
1816 downstream_port, bt_port_get_name(downstream_port));
1817 bt_put(upstream_comp);
1818 bt_put(downstream_comp);
1819 }
1820
1821 static
1822 void graph_ports_disconnected_listener(
1823 struct bt_component *upstream_component,
1824 struct bt_component *downstream_component,
1825 struct bt_port *upstream_port, struct bt_port *downstream_port,
1826 void *data)
1827 {
1828 BT_LOGI("Graph's component ports disconnected: "
1829 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1830 "downstream-port-addr=%p, downstream-port-name=\"%s\"",
1831 upstream_port, bt_port_get_name(upstream_port),
1832 downstream_port, bt_port_get_name(downstream_port));
1833 }
1834
1835 static
1836 void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx)
1837 {
1838 if (!ctx) {
1839 return;
1840 }
1841
1842 if (ctx->components) {
1843 g_hash_table_destroy(ctx->components);
1844 ctx->components = NULL;
1845 }
1846
1847 if (ctx->intersections) {
1848 g_hash_table_destroy(ctx->intersections);
1849 ctx->intersections = NULL;
1850 }
1851
1852 BT_PUT(ctx->graph);
1853 the_graph = NULL;
1854 ctx->cfg = NULL;
1855 }
1856
1857 static
1858 int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg)
1859 {
1860 int ret = 0;
1861
1862 ctx->cfg = cfg;
1863 ctx->connect_ports = false;
1864 ctx->components = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1865 NULL, bt_put);
1866 if (!ctx->components) {
1867 goto error;
1868 }
1869
1870 if (cfg->cmd_data.run.stream_intersection_mode) {
1871 ctx->stream_intersection_mode = true;
1872 ctx->intersections = g_hash_table_new_full(port_id_hash,
1873 port_id_equal, port_id_destroy, trace_range_destroy);
1874 if (!ctx->intersections) {
1875 goto error;
1876 }
1877 }
1878
1879 ctx->graph = bt_graph_create();
1880 if (!ctx->graph) {
1881 goto error;
1882 }
1883
1884 the_graph = ctx->graph;
1885 ret = bt_graph_add_port_added_listener(ctx->graph,
1886 graph_port_added_listener, NULL, ctx);
1887 if (ret < 0) {
1888 BT_LOGE_STR("Cannot add \"port added\" listener to graph.");
1889 goto error;
1890 }
1891
1892 ret = bt_graph_add_port_removed_listener(ctx->graph,
1893 graph_port_removed_listener, NULL, ctx);
1894 if (ret < 0) {
1895 BT_LOGE_STR("Cannot add \"port removed\" listener to graph.");
1896 goto error;
1897 }
1898
1899 ret = bt_graph_add_ports_connected_listener(ctx->graph,
1900 graph_ports_connected_listener, NULL, ctx);
1901 if (ret < 0) {
1902 BT_LOGE_STR("Cannot add \"ports connected\" listener to graph.");
1903 goto error;
1904 }
1905
1906 ret = bt_graph_add_ports_disconnected_listener(ctx->graph,
1907 graph_ports_disconnected_listener, NULL, ctx);
1908 if (ret < 0) {
1909 BT_LOGE_STR("Cannot add \"ports disconnected\" listener to graph.");
1910 goto error;
1911 }
1912
1913 goto end;
1914
1915 error:
1916 cmd_run_ctx_destroy(ctx);
1917 ret = -1;
1918
1919 end:
1920 return ret;
1921 }
1922
1923 static
1924 int set_stream_intersections(struct cmd_run_ctx *ctx,
1925 struct bt_config_component *cfg_comp,
1926 struct bt_component_class *comp_cls)
1927 {
1928 int ret = 0;
1929 uint64_t trace_idx;
1930 int64_t trace_count;
1931 enum bt_value_status value_status;
1932 const char *path = NULL;
1933 struct bt_value *component_path_value = NULL;
1934 struct bt_value *query_params = NULL;
1935 struct bt_value *query_result = NULL;
1936 struct bt_value *trace_info = NULL;
1937 struct bt_value *intersection_range = NULL;
1938 struct bt_value *intersection_begin = NULL;
1939 struct bt_value *intersection_end = NULL;
1940 struct bt_value *stream_path_value = NULL;
1941 struct bt_value *stream_paths = NULL;
1942 struct bt_value *stream_infos = NULL;
1943 struct bt_value *stream_info = NULL;
1944 struct port_id *port_id = NULL;
1945 struct trace_range *trace_range = NULL;
1946
1947 component_path_value = bt_value_map_get(cfg_comp->params, "path");
1948 if (!bt_value_is_string(component_path_value)) {
1949 BT_LOGD("Cannot get path parameter: component-name=%s",
1950 cfg_comp->instance_name->str);
1951 ret = -1;
1952 goto error;
1953 }
1954
1955 value_status = bt_value_string_get(component_path_value, &path);
1956 if (value_status != BT_VALUE_STATUS_OK) {
1957 BT_LOGD("Cannot get path string value: component-name=%s",
1958 cfg_comp->instance_name->str);
1959 ret = -1;
1960 goto error;
1961 }
1962
1963 query_params = bt_value_map_create();
1964 if (!query_params) {
1965 BT_LOGE_STR("Cannot create query parameters.");
1966 ret = -1;
1967 goto error;
1968 }
1969
1970 value_status = bt_value_map_insert(query_params, "path", component_path_value);
1971 if (value_status != BT_VALUE_STATUS_OK) {
1972 BT_LOGE_STR("Cannot insert path parameter in query paramater map.");
1973 ret = -1;
1974 goto error;
1975 }
1976
1977 query_result = bt_component_class_query(comp_cls, "trace-info",
1978 query_params);
1979 if (!query_result) {
1980 BT_LOGD("Component class \'%s\' does not support the \'trace-info\' query.",
1981 bt_component_class_get_name(comp_cls));
1982 ret = -1;
1983 goto error;
1984 }
1985
1986 if (!bt_value_is_array(query_result)) {
1987 BT_LOGD("Unexpected format of \'trace-info\' query result: "
1988 "component-class-name=%s",
1989 bt_component_class_get_name(comp_cls));
1990 ret = -1;
1991 goto error;
1992 }
1993
1994 trace_count = bt_value_array_size(query_result);
1995 if (trace_count < 0) {
1996 ret = -1;
1997 goto error;
1998 }
1999
2000 for (trace_idx = 0; trace_idx < trace_count; trace_idx++) {
2001 int64_t begin, end;
2002 uint64_t stream_idx;
2003 int64_t stream_count;
2004
2005 trace_info = bt_value_array_get(query_result, trace_idx);
2006 if (!trace_info || !bt_value_is_map(trace_info)) {
2007 ret = -1;
2008 BT_LOGD_STR("Cannot retrieve trace from query result.");
2009 goto error;
2010 }
2011
2012 intersection_range = bt_value_map_get(trace_info,
2013 "intersection-range-ns");
2014 if (!intersection_range) {
2015 ret = -1;
2016 BT_LOGD_STR("Cannot retrieve \'intersetion-range-ns\' field from query result.");
2017 goto error;
2018 }
2019
2020 intersection_begin = bt_value_map_get(intersection_range,
2021 "begin");
2022 if (!intersection_begin) {
2023 ret = -1;
2024 BT_LOGD_STR("Cannot retrieve intersection-range-ns \'begin\' field from query result.");
2025 goto error;
2026 }
2027
2028 intersection_end = bt_value_map_get(intersection_range,
2029 "end");
2030 if (!intersection_end) {
2031 ret = -1;
2032 BT_LOGD_STR("Cannot retrieve intersection-range-ns \'end\' field from query result.");
2033 goto error;
2034 }
2035
2036 value_status = bt_value_integer_get(intersection_begin, &begin);
2037 if (value_status != BT_VALUE_STATUS_OK) {
2038 ret = -1;
2039 BT_LOGD_STR("Cannot retrieve value of intersection-range-ns \'begin\' field from query result.");
2040 goto error;
2041 }
2042
2043 value_status = bt_value_integer_get(intersection_end, &end);
2044 if (value_status != BT_VALUE_STATUS_OK) {
2045 ret = -1;
2046 BT_LOGD_STR("Cannot retrieve value of intersection-range-ns \'end\' field from query result.");
2047 goto error;
2048 }
2049
2050 if (begin < 0 || end < 0 || end < begin) {
2051 BT_LOGW("Invalid trace stream intersection values: "
2052 "intersection-range-ns:begin=%" PRId64
2053 ", intersection-range-ns:end=%" PRId64,
2054 begin, end);
2055 ret = -1;
2056 goto error;
2057 }
2058
2059 stream_infos = bt_value_map_get(trace_info, "streams");
2060 if (!stream_infos || !bt_value_is_array(stream_infos)) {
2061 ret = -1;
2062 BT_LOGD_STR("Cannot retrieve stream informations from trace in query result.");
2063 goto error;
2064 }
2065
2066 stream_count = bt_value_array_size(stream_infos);
2067 if (stream_count < 0) {
2068 ret = -1;
2069 goto error;
2070 }
2071
2072 /*
2073 * FIXME
2074 *
2075 * The first path of a stream's "paths" is currently used to
2076 * associate streams/ports to a given trace intersection.
2077 *
2078 * This is a fragile hack as it relies on the port names
2079 * being set to the various streams path.
2080 *
2081 * A stream name should be introduced as part of the trace-info
2082 * query result.
2083 */
2084 for (stream_idx = 0; stream_idx < stream_count; stream_idx++) {
2085 const char *stream_path;
2086
2087 port_id = g_new0(struct port_id, 1);
2088 if (!port_id) {
2089 ret = -1;
2090 BT_LOGE_STR("Cannot allocate memory for port_id structure.");
2091 goto error;
2092 }
2093 port_id->instance_name = strdup(cfg_comp->instance_name->str);
2094 if (!port_id->instance_name) {
2095 ret = -1;
2096 BT_LOGE_STR("Cannot allocate memory for port_id component instance name.");
2097 goto error;
2098 }
2099
2100 trace_range = g_new0(struct trace_range, 1);
2101 if (!trace_range) {
2102 ret = -1;
2103 BT_LOGE_STR("Cannot allocate memory for trace_range structure.");
2104 goto error;
2105 }
2106 trace_range->intersection_range_begin_ns = begin;
2107 trace_range->intersection_range_end_ns = end;
2108
2109 stream_info = bt_value_array_get(stream_infos,
2110 stream_idx);
2111 if (!stream_info || !bt_value_is_map(stream_info)) {
2112 ret = -1;
2113 BT_LOGD_STR("Cannot retrieve stream informations from trace in query result.");
2114 goto error;
2115 }
2116
2117 stream_paths = bt_value_map_get(stream_info, "paths");
2118 if (!stream_paths || !bt_value_is_array(stream_paths)) {
2119 ret = -1;
2120 BT_LOGD_STR("Cannot retrieve stream paths from trace in query result.");
2121 goto error;
2122 }
2123
2124 stream_path_value = bt_value_array_get(stream_paths, 0);
2125 if (!stream_path_value ||
2126 !bt_value_is_string(stream_path_value)) {
2127 ret = -1;
2128 BT_LOGD_STR("Cannot retrieve stream path value from trace in query result.");
2129 goto error;
2130 }
2131
2132 value_status = bt_value_string_get(stream_path_value,
2133 &stream_path);
2134 if (value_status != BT_VALUE_STATUS_OK) {
2135 ret = -1;
2136 goto error;
2137 }
2138
2139 port_id->port_name = strdup(stream_path);
2140 if (!port_id->port_name) {
2141 ret = -1;
2142 BT_LOGE_STR("Cannot allocate memory for port_id port_name.");
2143 goto error;
2144 }
2145
2146 BT_LOGD("Inserting stream intersection ");
2147
2148 g_hash_table_insert(ctx->intersections, port_id, trace_range);
2149
2150 port_id = NULL;
2151 trace_range = NULL;
2152 BT_PUT(stream_info);
2153 BT_PUT(stream_paths);
2154 BT_PUT(stream_path_value);
2155 }
2156
2157 BT_PUT(trace_info);
2158 BT_PUT(stream_paths);
2159 BT_PUT(stream_path_value);
2160 BT_PUT(intersection_range);
2161 BT_PUT(intersection_begin);
2162 BT_PUT(intersection_end);
2163 BT_PUT(stream_paths);
2164 BT_PUT(stream_path_value);
2165 }
2166
2167 goto end;
2168
2169 error:
2170 fprintf(stderr, "%s%sCannot determine stream intersection of trace at path \'%s\'.%s\n",
2171 bt_common_color_bold(),
2172 bt_common_color_fg_yellow(),
2173 path ? path : "(unknown)",
2174 bt_common_color_reset());
2175 end:
2176 bt_put(component_path_value);
2177 bt_put(query_params);
2178 bt_put(query_result);
2179 bt_put(trace_info);
2180 bt_put(intersection_range);
2181 bt_put(intersection_begin);
2182 bt_put(intersection_end);
2183 bt_put(stream_infos);
2184 bt_put(stream_info);
2185 bt_put(stream_paths);
2186 bt_put(stream_path_value);
2187 g_free(port_id);
2188 g_free(trace_range);
2189 return ret;
2190 }
2191
2192 static
2193 int cmd_run_ctx_create_components_from_config_components(
2194 struct cmd_run_ctx *ctx, GPtrArray *cfg_components)
2195 {
2196 size_t i;
2197 struct bt_component_class *comp_cls = NULL;
2198 struct bt_component *comp = NULL;
2199 int ret = 0;
2200
2201 for (i = 0; i < cfg_components->len; i++) {
2202 struct bt_config_component *cfg_comp =
2203 g_ptr_array_index(cfg_components, i);
2204 GQuark quark;
2205
2206 comp_cls = find_component_class(cfg_comp->plugin_name->str,
2207 cfg_comp->comp_cls_name->str, cfg_comp->type);
2208 if (!comp_cls) {
2209 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
2210 "comp-cls-name=\"%s\", comp-cls-type=%d",
2211 cfg_comp->plugin_name->str,
2212 cfg_comp->comp_cls_name->str,
2213 cfg_comp->type);
2214 fprintf(stderr, "%s%sCannot find component class %s",
2215 bt_common_color_bold(),
2216 bt_common_color_fg_red(),
2217 bt_common_color_reset());
2218 print_plugin_comp_cls_opt(stderr,
2219 cfg_comp->plugin_name->str,
2220 cfg_comp->comp_cls_name->str,
2221 cfg_comp->type);
2222 fprintf(stderr, "\n");
2223 goto error;
2224 }
2225
2226 ret = bt_graph_add_component(ctx->graph, comp_cls,
2227 cfg_comp->instance_name->str, cfg_comp->params, &comp);
2228 if (ret) {
2229 BT_LOGE("Cannot create component: plugin-name=\"%s\", "
2230 "comp-cls-name=\"%s\", comp-cls-type=%d, "
2231 "comp-name=\"%s\"",
2232 cfg_comp->plugin_name->str,
2233 cfg_comp->comp_cls_name->str,
2234 cfg_comp->type, cfg_comp->instance_name->str);
2235 fprintf(stderr, "%s%sCannot create component `%s`%s\n",
2236 bt_common_color_bold(),
2237 bt_common_color_fg_red(),
2238 cfg_comp->instance_name->str,
2239 bt_common_color_reset());
2240 goto error;
2241 }
2242
2243 if (ctx->stream_intersection_mode &&
2244 cfg_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) {
2245 ret = set_stream_intersections(ctx, cfg_comp, comp_cls);
2246 if (ret) {
2247 goto error;
2248 }
2249 }
2250
2251 BT_LOGI("Created and inserted component: comp-addr=%p, comp-name=\"%s\"",
2252 comp, cfg_comp->instance_name->str);
2253 quark = g_quark_from_string(cfg_comp->instance_name->str);
2254 assert(quark > 0);
2255 g_hash_table_insert(ctx->components,
2256 GUINT_TO_POINTER(quark), comp);
2257 comp = NULL;
2258 BT_PUT(comp_cls);
2259 }
2260
2261 goto end;
2262
2263 error:
2264 ret = -1;
2265
2266 end:
2267 bt_put(comp);
2268 bt_put(comp_cls);
2269 return ret;
2270 }
2271
2272 static
2273 int cmd_run_ctx_create_components(struct cmd_run_ctx *ctx)
2274 {
2275 int ret = 0;
2276
2277 /*
2278 * Make sure that, during this phase, our graph's "port added"
2279 * listener does not connect ports while we are creating the
2280 * components because we have a special, initial phase for
2281 * this.
2282 */
2283 ctx->connect_ports = false;
2284
2285 ret = cmd_run_ctx_create_components_from_config_components(
2286 ctx, ctx->cfg->cmd_data.run.sources);
2287 if (ret) {
2288 ret = -1;
2289 goto end;
2290 }
2291
2292 ret = cmd_run_ctx_create_components_from_config_components(
2293 ctx, ctx->cfg->cmd_data.run.filters);
2294 if (ret) {
2295 ret = -1;
2296 goto end;
2297 }
2298
2299 ret = cmd_run_ctx_create_components_from_config_components(
2300 ctx, ctx->cfg->cmd_data.run.sinks);
2301 if (ret) {
2302 ret = -1;
2303 goto end;
2304 }
2305
2306 end:
2307 return ret;
2308 }
2309
2310 static
2311 int cmd_run_ctx_connect_comp_ports(struct cmd_run_ctx *ctx,
2312 struct bt_component *comp,
2313 int64_t (*port_count_fn)(struct bt_component *),
2314 struct bt_port *(*port_by_index_fn)(struct bt_component *, uint64_t))
2315 {
2316 int ret = 0;
2317 int64_t count;
2318 uint64_t i;
2319
2320 count = port_count_fn(comp);
2321 assert(count >= 0);
2322
2323 for (i = 0; i < count; i++) {
2324 struct bt_port *upstream_port = port_by_index_fn(comp, i);
2325
2326 assert(upstream_port);
2327 ret = cmd_run_ctx_connect_upstream_port(ctx, upstream_port);
2328 bt_put(upstream_port);
2329 if (ret) {
2330 goto end;
2331 }
2332 }
2333
2334 end:
2335 return ret;
2336 }
2337
2338 static
2339 int cmd_run_ctx_connect_ports(struct cmd_run_ctx *ctx)
2340 {
2341 int ret = 0;
2342 GHashTableIter iter;
2343 gpointer g_name_quark, g_comp;
2344
2345 ctx->connect_ports = true;
2346 g_hash_table_iter_init(&iter, ctx->components);
2347
2348 while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
2349 int64_t (*port_count_fn)(struct bt_component *);
2350 struct bt_port *(*port_by_index_fn)(struct bt_component *, uint64_t);
2351
2352 if (bt_component_is_source(g_comp)) {
2353 port_count_fn =
2354 bt_component_source_get_output_port_count;
2355 port_by_index_fn =
2356 bt_component_source_get_output_port_by_index;
2357 } else if (bt_component_is_filter(g_comp)) {
2358 port_count_fn =
2359 bt_component_filter_get_output_port_count;
2360 port_by_index_fn =
2361 bt_component_filter_get_output_port_by_index;
2362 } else {
2363 continue;
2364 }
2365
2366 ret = cmd_run_ctx_connect_comp_ports(ctx,
2367 g_comp, port_count_fn, port_by_index_fn);
2368 if (ret) {
2369 goto end;
2370 }
2371 }
2372
2373 end:
2374 return ret;
2375 }
2376
2377 static inline
2378 const char *bt_graph_status_str(enum bt_graph_status status)
2379 {
2380 switch (status) {
2381 case BT_GRAPH_STATUS_CANCELED:
2382 return "BT_GRAPH_STATUS_CANCELED";
2383 case BT_GRAPH_STATUS_AGAIN:
2384 return "BT_GRAPH_STATUS_AGAIN";
2385 case BT_GRAPH_STATUS_END:
2386 return "BT_GRAPH_STATUS_END";
2387 case BT_GRAPH_STATUS_OK:
2388 return "BT_GRAPH_STATUS_OK";
2389 case BT_GRAPH_STATUS_INVALID:
2390 return "BT_GRAPH_STATUS_INVALID";
2391 case BT_GRAPH_STATUS_NO_SINK:
2392 return "BT_GRAPH_STATUS_NO_SINK";
2393 case BT_GRAPH_STATUS_ERROR:
2394 return "BT_GRAPH_STATUS_ERROR";
2395 default:
2396 return "(unknown)";
2397 }
2398 }
2399
2400 static
2401 int cmd_run(struct bt_config *cfg)
2402 {
2403 int ret = 0;
2404 struct cmd_run_ctx ctx = { 0 };
2405
2406 /* Initialize the command's context and the graph object */
2407 if (cmd_run_ctx_init(&ctx, cfg)) {
2408 BT_LOGE_STR("Cannot initialize the command's context.");
2409 fprintf(stderr, "Cannot initialize the command's context\n");
2410 goto error;
2411 }
2412
2413 if (canceled) {
2414 BT_LOGI_STR("Canceled by user before creating components.");
2415 goto error;
2416 }
2417
2418 BT_LOGI_STR("Creating components.");
2419
2420 /* Create the requested component instances */
2421 if (cmd_run_ctx_create_components(&ctx)) {
2422 BT_LOGE_STR("Cannot create components.");
2423 fprintf(stderr, "Cannot create components\n");
2424 goto error;
2425 }
2426
2427 if (canceled) {
2428 BT_LOGI_STR("Canceled by user before connecting components.");
2429 goto error;
2430 }
2431
2432 BT_LOGI_STR("Connecting components.");
2433
2434 /* Connect the initially visible component ports */
2435 if (cmd_run_ctx_connect_ports(&ctx)) {
2436 BT_LOGE_STR("Cannot connect initial component ports.");
2437 fprintf(stderr, "Cannot connect initial component ports\n");
2438 goto error;
2439 }
2440
2441 if (canceled) {
2442 BT_LOGI_STR("Canceled by user before running the graph.");
2443 goto error;
2444 }
2445
2446 BT_LOGI_STR("Running the graph.");
2447
2448 /* Run the graph */
2449 while (true) {
2450 enum bt_graph_status graph_status = bt_graph_run(ctx.graph);
2451
2452 /*
2453 * Reset console in case something messed with console
2454 * codes during the graph's execution.
2455 */
2456 printf("%s", bt_common_color_reset());
2457 fflush(stdout);
2458 fprintf(stderr, "%s", bt_common_color_reset());
2459 BT_LOGV("bt_graph_run() returned: status=%s",
2460 bt_graph_status_str(graph_status));
2461
2462 switch (graph_status) {
2463 case BT_GRAPH_STATUS_OK:
2464 break;
2465 case BT_GRAPH_STATUS_CANCELED:
2466 BT_LOGI_STR("Graph was canceled by user.");
2467 goto error;
2468 case BT_GRAPH_STATUS_AGAIN:
2469 if (bt_graph_is_canceled(ctx.graph)) {
2470 BT_LOGI_STR("Graph was canceled by user.");
2471 goto error;
2472 }
2473
2474 if (cfg->cmd_data.run.retry_duration_us > 0) {
2475 BT_LOGV("Got BT_GRAPH_STATUS_AGAIN: sleeping: "
2476 "time-us=%" PRIu64,
2477 cfg->cmd_data.run.retry_duration_us);
2478
2479 if (usleep(cfg->cmd_data.run.retry_duration_us)) {
2480 if (bt_graph_is_canceled(ctx.graph)) {
2481 BT_LOGI_STR("Graph was canceled by user.");
2482 goto error;
2483 }
2484 }
2485 }
2486 break;
2487 case BT_COMPONENT_STATUS_END:
2488 goto end;
2489 default:
2490 BT_LOGE_STR("Graph failed to complete successfully");
2491 fprintf(stderr, "Graph failed to complete successfully\n");
2492 goto error;
2493 }
2494 }
2495
2496 goto end;
2497
2498 error:
2499 if (ret == 0) {
2500 ret = -1;
2501 }
2502
2503 end:
2504 cmd_run_ctx_destroy(&ctx);
2505 return ret;
2506 }
2507
2508 static
2509 void warn_command_name_and_directory_clash(struct bt_config *cfg)
2510 {
2511 const char *env_clash;
2512
2513 if (!cfg->command_name) {
2514 return;
2515 }
2516
2517 env_clash = getenv(ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH);
2518 if (env_clash && strcmp(env_clash, "0") == 0) {
2519 return;
2520 }
2521
2522 if (g_file_test(cfg->command_name,
2523 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
2524 fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
2525 cfg->command_name);
2526 fprintf(stderr, "trace located in the local `%s` directory, please use:\n",
2527 cfg->command_name);
2528 fprintf(stderr, "\n");
2529 fprintf(stderr, " babeltrace convert %s [OPTIONS]\n",
2530 cfg->command_name);
2531 }
2532 }
2533
2534 static
2535 void init_log_level(void)
2536 {
2537 bt_cli_log_level = bt_log_get_level_from_env(ENV_BABELTRACE_CLI_LOG_LEVEL);
2538 }
2539
2540 static
2541 void set_auto_log_levels(struct bt_config *cfg)
2542 {
2543 const char **env_var_name;
2544
2545 /*
2546 * Override the configuration's default log level if
2547 * BABELTRACE_VERBOSE or BABELTRACE_DEBUG environment variables
2548 * are found for backward compatibility with legacy Babetrace 1.
2549 */
2550 if (getenv("BABELTRACE_DEBUG") &&
2551 strcmp(getenv("BABELTRACE_DEBUG"), "1") == 0) {
2552 cfg->log_level = 'V';
2553 } else if (getenv("BABELTRACE_VERBOSE") &&
2554 strcmp(getenv("BABELTRACE_VERBOSE"), "1") == 0) {
2555 cfg->log_level = 'I';
2556 }
2557
2558 /*
2559 * Set log levels according to --debug or --verbose. For
2560 * backward compatibility, --debug is more verbose than
2561 * --verbose. So:
2562 *
2563 * --verbose: INFO log level
2564 * --debug: VERBOSE log level (includes DEBUG, which is
2565 * is less verbose than VERBOSE in the internal
2566 * logging framework)
2567 */
2568 if (!getenv("BABELTRACE_LOGGING_GLOBAL_LEVEL")) {
2569 if (cfg->verbose) {
2570 bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO);
2571 } else if (cfg->debug) {
2572 bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
2573 } else {
2574 /*
2575 * Set library's default log level if not
2576 * explicitly specified.
2577 */
2578 switch (cfg->log_level) {
2579 case 'N':
2580 bt_logging_set_global_level(BT_LOGGING_LEVEL_NONE);
2581 break;
2582 case 'V':
2583 bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
2584 break;
2585 case 'D':
2586 bt_logging_set_global_level(BT_LOGGING_LEVEL_DEBUG);
2587 break;
2588 case 'I':
2589 bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO);
2590 break;
2591 case 'W':
2592 bt_logging_set_global_level(BT_LOGGING_LEVEL_WARN);
2593 break;
2594 case 'E':
2595 bt_logging_set_global_level(BT_LOGGING_LEVEL_ERROR);
2596 break;
2597 case 'F':
2598 bt_logging_set_global_level(BT_LOGGING_LEVEL_FATAL);
2599 break;
2600 default:
2601 abort();
2602 }
2603 }
2604 }
2605
2606 if (!getenv(ENV_BABELTRACE_CLI_LOG_LEVEL)) {
2607 if (cfg->verbose) {
2608 bt_cli_log_level = BT_LOG_INFO;
2609 } else if (cfg->debug) {
2610 bt_cli_log_level = BT_LOG_VERBOSE;
2611 } else {
2612 /*
2613 * Set CLI's default log level if not explicitly
2614 * specified.
2615 */
2616 switch (cfg->log_level) {
2617 case 'N':
2618 bt_cli_log_level = BT_LOG_NONE;
2619 break;
2620 case 'V':
2621 bt_cli_log_level = BT_LOG_VERBOSE;
2622 break;
2623 case 'D':
2624 bt_cli_log_level = BT_LOG_DEBUG;
2625 break;
2626 case 'I':
2627 bt_cli_log_level = BT_LOG_INFO;
2628 break;
2629 case 'W':
2630 bt_cli_log_level = BT_LOG_WARN;
2631 break;
2632 case 'E':
2633 bt_cli_log_level = BT_LOG_ERROR;
2634 break;
2635 case 'F':
2636 bt_cli_log_level = BT_LOG_FATAL;
2637 break;
2638 default:
2639 abort();
2640 }
2641 }
2642 }
2643
2644 env_var_name = log_level_env_var_names;
2645
2646 while (*env_var_name) {
2647 if (!getenv(*env_var_name)) {
2648 if (cfg->verbose) {
2649 g_setenv(*env_var_name, "I", 1);
2650 } else if (cfg->debug) {
2651 g_setenv(*env_var_name, "V", 1);
2652 } else {
2653 char val[2] = { 0 };
2654
2655 /*
2656 * Set module's default log level if not
2657 * explicitly specified.
2658 */
2659 val[0] = cfg->log_level;
2660 g_setenv(*env_var_name, val, 1);
2661 }
2662 }
2663
2664 env_var_name++;
2665 }
2666 }
2667
2668 int main(int argc, const char **argv)
2669 {
2670 int ret;
2671 int retcode;
2672 struct bt_config *cfg;
2673
2674 init_log_level();
2675 set_signal_handler();
2676 init_static_data();
2677 cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode);
2678
2679 if (retcode < 0) {
2680 /* Quit without errors; typically usage/version */
2681 retcode = 0;
2682 BT_LOGI_STR("Quitting without errors.");
2683 goto end;
2684 }
2685
2686 if (retcode > 0) {
2687 BT_LOGE("Command-line error: retcode=%d", retcode);
2688 goto end;
2689 }
2690
2691 if (!cfg) {
2692 BT_LOGE_STR("Failed to create a valid Babeltrace configuration.");
2693 fprintf(stderr, "Failed to create Babeltrace configuration\n");
2694 retcode = 1;
2695 goto end;
2696 }
2697
2698 set_auto_log_levels(cfg);
2699 print_cfg(cfg);
2700
2701 if (cfg->command_needs_plugins) {
2702 ret = load_all_plugins(cfg->plugin_paths);
2703 if (ret) {
2704 BT_LOGE("Failed to load plugins: ret=%d", ret);
2705 retcode = 1;
2706 goto end;
2707 }
2708 }
2709
2710 BT_LOGI("Executing command: cmd=%d, command-name=\"%s\"",
2711 cfg->command, cfg->command_name);
2712
2713 switch (cfg->command) {
2714 case BT_CONFIG_COMMAND_RUN:
2715 ret = cmd_run(cfg);
2716 break;
2717 case BT_CONFIG_COMMAND_LIST_PLUGINS:
2718 ret = cmd_list_plugins(cfg);
2719 break;
2720 case BT_CONFIG_COMMAND_HELP:
2721 ret = cmd_help(cfg);
2722 break;
2723 case BT_CONFIG_COMMAND_QUERY:
2724 ret = cmd_query(cfg);
2725 break;
2726 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
2727 ret = cmd_print_ctf_metadata(cfg);
2728 break;
2729 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
2730 ret = cmd_print_lttng_live_sessions(cfg);
2731 break;
2732 default:
2733 BT_LOGF("Invalid/unknown command: cmd=%d", cfg->command);
2734 abort();
2735 }
2736
2737 BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", ret=%d",
2738 cfg->command, cfg->command_name, ret);
2739 warn_command_name_and_directory_clash(cfg);
2740 retcode = ret ? 1 : 0;
2741
2742 end:
2743 BT_PUT(cfg);
2744 fini_static_data();
2745 return retcode;
2746 }
This page took 0.130587 seconds and 3 git commands to generate.