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