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