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