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