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