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