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