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