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