f42b563e2a943f841f22b127424dfb7f61e7fd04
[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 #include <babeltrace/babeltrace.h>
30 #include <babeltrace/plugin/plugin.h>
31 #include <babeltrace/common-internal.h>
32 #include <babeltrace/graph/component.h>
33 #include <babeltrace/graph/component-source.h>
34 #include <babeltrace/graph/component-sink.h>
35 #include <babeltrace/graph/component-filter.h>
36 #include <babeltrace/graph/component-class.h>
37 #include <babeltrace/graph/port.h>
38 #include <babeltrace/graph/graph.h>
39 #include <babeltrace/graph/connection.h>
40 #include <babeltrace/graph/notification-iterator.h>
41 #include <babeltrace/ref.h>
42 #include <babeltrace/values.h>
43 #include <babeltrace/logging.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <popt.h>
47 #include <string.h>
48 #include <stdio.h>
49 #include <glib.h>
50 #include <inttypes.h>
51 #include "babeltrace-cfg.h"
52 #include "babeltrace-cfg-cli-args.h"
53 #include "babeltrace-cfg-cli-args-default.h"
54
55 #define BT_LOG_TAG "CLI"
56 #include "logging.h"
57
58 #define ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH "BABELTRACE_CLI_WARN_COMMAND_NAME_DIRECTORY_CLASH"
59
60 GPtrArray *loaded_plugins;
61
62 BT_HIDDEN
63 int bt_cli_log_level = BT_LOG_NONE;
64
65 static
66 void init_static_data(void)
67 {
68 loaded_plugins = g_ptr_array_new_with_free_func(bt_put);
69 }
70
71 static
72 void fini_static_data(void)
73 {
74 g_ptr_array_free(loaded_plugins, TRUE);
75 }
76
77 static
78 struct bt_plugin *find_plugin(const char *name)
79 {
80 int i;
81 struct bt_plugin *plugin = NULL;
82
83 assert(name);
84 BT_LOGD("Finding plugin: name=\"%s\"", name);
85
86 for (i = 0; i < loaded_plugins->len; i++) {
87 plugin = g_ptr_array_index(loaded_plugins, i);
88
89 if (strcmp(name, bt_plugin_get_name(plugin)) == 0) {
90 break;
91 }
92
93 plugin = NULL;
94 }
95
96 if (BT_LOG_ON_DEBUG) {
97 if (plugin) {
98 BT_LOGD("Found plugin: plugin-addr=%p", plugin);
99 } else {
100 BT_LOGD("Cannot find plugin.");
101 }
102 }
103
104 return bt_get(plugin);
105 }
106
107 static
108 struct bt_component_class *find_component_class(const char *plugin_name,
109 const char *comp_class_name,
110 enum bt_component_class_type comp_class_type)
111 {
112 struct bt_component_class *comp_class = NULL;
113 struct bt_plugin *plugin;
114
115 BT_LOGD("Finding component class: plugin-name=\"%s\", "
116 "comp-cls-name=\"%s\", comp-cls-type=%d",
117 plugin_name, comp_class_name, comp_class_type);
118
119 plugin = find_plugin(plugin_name);
120
121 if (!plugin) {
122 goto end;
123 }
124
125 comp_class = bt_plugin_get_component_class_by_name_and_type(plugin,
126 comp_class_name, comp_class_type);
127 BT_PUT(plugin);
128
129 end:
130 if (BT_LOG_ON_DEBUG) {
131 if (comp_class) {
132 BT_LOGD("Found component class: comp-cls-addr=%p",
133 comp_class);
134 } else {
135 BT_LOGD("Cannot find component class.");
136 }
137 }
138
139 return comp_class;
140 }
141
142 static
143 void print_indent(FILE *fp, size_t indent)
144 {
145 size_t i;
146
147 for (i = 0; i < indent; i++) {
148 fprintf(fp, " ");
149 }
150 }
151
152 static
153 const char *component_type_str(enum bt_component_class_type type)
154 {
155 switch (type) {
156 case BT_COMPONENT_CLASS_TYPE_SOURCE:
157 return "source";
158 case BT_COMPONENT_CLASS_TYPE_SINK:
159 return "sink";
160 case BT_COMPONENT_CLASS_TYPE_FILTER:
161 return "filter";
162 case BT_COMPONENT_CLASS_TYPE_UNKNOWN:
163 default:
164 return "unknown";
165 }
166 }
167
168 static
169 void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name,
170 const char *comp_cls_name, enum bt_component_class_type type)
171 {
172 GString *shell_plugin_name = NULL;
173 GString *shell_comp_cls_name = NULL;
174
175 shell_plugin_name = bt_common_shell_quote(plugin_name, false);
176 if (!shell_plugin_name) {
177 goto end;
178 }
179
180 shell_comp_cls_name = bt_common_shell_quote(comp_cls_name, false);
181 if (!shell_comp_cls_name) {
182 goto end;
183 }
184
185 fprintf(fh, "%s%s--%s%s %s'%s%s%s%s.%s%s%s'",
186 bt_common_color_bold(),
187 bt_common_color_fg_cyan(),
188 component_type_str(type),
189 bt_common_color_reset(),
190 bt_common_color_fg_default(),
191 bt_common_color_bold(),
192 bt_common_color_fg_blue(),
193 shell_plugin_name->str,
194 bt_common_color_fg_default(),
195 bt_common_color_fg_yellow(),
196 shell_comp_cls_name->str,
197 bt_common_color_reset());
198
199 end:
200 if (shell_plugin_name) {
201 g_string_free(shell_plugin_name, TRUE);
202 }
203
204 if (shell_comp_cls_name) {
205 g_string_free(shell_comp_cls_name, TRUE);
206 }
207 }
208
209 static
210 void print_value(FILE *, struct bt_value *, size_t);
211
212 static
213 void print_value_rec(FILE *, struct bt_value *, size_t);
214
215 struct print_map_value_data {
216 size_t indent;
217 FILE *fp;
218 };
219
220 static
221 bt_bool print_map_value(const char *key, struct bt_value *object, void *data)
222 {
223 struct print_map_value_data *print_map_value_data = data;
224
225 print_indent(print_map_value_data->fp, print_map_value_data->indent);
226 fprintf(print_map_value_data->fp, "%s: ", key);
227
228 if (bt_value_is_array(object) &&
229 bt_value_array_is_empty(object)) {
230 fprintf(print_map_value_data->fp, "[ ]\n");
231 return true;
232 }
233
234 if (bt_value_is_map(object) &&
235 bt_value_map_is_empty(object)) {
236 fprintf(print_map_value_data->fp, "{ }\n");
237 return true;
238 }
239
240 if (bt_value_is_array(object) ||
241 bt_value_is_map(object)) {
242 fprintf(print_map_value_data->fp, "\n");
243 }
244
245 print_value_rec(print_map_value_data->fp, object,
246 print_map_value_data->indent + 2);
247 return BT_TRUE;
248 }
249
250 static
251 void print_value_rec(FILE *fp, struct bt_value *value, size_t indent)
252 {
253 bt_bool bool_val;
254 int64_t int_val;
255 double dbl_val;
256 const char *str_val;
257 int size;
258 int i;
259
260 if (!value) {
261 return;
262 }
263
264 switch (bt_value_get_type(value)) {
265 case BT_VALUE_TYPE_NULL:
266 fprintf(fp, "%snull%s\n", bt_common_color_bold(),
267 bt_common_color_reset());
268 break;
269 case BT_VALUE_TYPE_BOOL:
270 bt_value_bool_get(value, &bool_val);
271 fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
272 bt_common_color_fg_cyan(), bool_val ? "yes" : "no",
273 bt_common_color_reset());
274 break;
275 case BT_VALUE_TYPE_INTEGER:
276 bt_value_integer_get(value, &int_val);
277 fprintf(fp, "%s%s%" PRId64 "%s\n", bt_common_color_bold(),
278 bt_common_color_fg_red(), int_val,
279 bt_common_color_reset());
280 break;
281 case BT_VALUE_TYPE_FLOAT:
282 bt_value_float_get(value, &dbl_val);
283 fprintf(fp, "%s%s%lf%s\n", bt_common_color_bold(),
284 bt_common_color_fg_red(), dbl_val,
285 bt_common_color_reset());
286 break;
287 case BT_VALUE_TYPE_STRING:
288 bt_value_string_get(value, &str_val);
289 fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
290 bt_common_color_fg_green(), str_val,
291 bt_common_color_reset());
292 break;
293 case BT_VALUE_TYPE_ARRAY:
294 size = bt_value_array_size(value);
295 assert(size >= 0);
296
297 if (size == 0) {
298 print_indent(fp, indent);
299 fprintf(fp, "[ ]\n");
300 break;
301 }
302
303 for (i = 0; i < size; i++) {
304 struct bt_value *element =
305 bt_value_array_get(value, i);
306
307 assert(element);
308 print_indent(fp, indent);
309 fprintf(fp, "- ");
310
311 if (bt_value_is_array(element) &&
312 bt_value_array_is_empty(element)) {
313 fprintf(fp, "[ ]\n");
314 continue;
315 }
316
317 if (bt_value_is_map(element) &&
318 bt_value_map_is_empty(element)) {
319 fprintf(fp, "{ }\n");
320 continue;
321 }
322
323 if (bt_value_is_array(element) ||
324 bt_value_is_map(element)) {
325 fprintf(fp, "\n");
326 }
327
328 print_value_rec(fp, element, indent + 2);
329 BT_PUT(element);
330 }
331 break;
332 case BT_VALUE_TYPE_MAP:
333 {
334 struct print_map_value_data data = {
335 .indent = indent,
336 .fp = fp,
337 };
338
339 if (bt_value_map_is_empty(value)) {
340 print_indent(fp, indent);
341 fprintf(fp, "{ }\n");
342 break;
343 }
344
345 bt_value_map_foreach(value, print_map_value, &data);
346 break;
347 }
348 default:
349 assert(false);
350 }
351 }
352
353 static
354 void print_value(FILE *fp, struct bt_value *value, size_t indent)
355 {
356 if (!bt_value_is_array(value) && !bt_value_is_map(value)) {
357 print_indent(fp, indent);
358 }
359
360 print_value_rec(fp, value, indent);
361 }
362
363 static
364 void print_bt_config_component(struct bt_config_component *bt_config_component)
365 {
366 fprintf(stderr, " ");
367 print_plugin_comp_cls_opt(stderr, bt_config_component->plugin_name->str,
368 bt_config_component->comp_cls_name->str,
369 bt_config_component->type);
370 fprintf(stderr, ":\n");
371
372 if (bt_config_component->instance_name->len > 0) {
373 fprintf(stderr, " Name: %s\n",
374 bt_config_component->instance_name->str);
375 }
376
377 fprintf(stderr, " Parameters:\n");
378 print_value(stderr, bt_config_component->params, 8);
379 }
380
381 static
382 void print_bt_config_components(GPtrArray *array)
383 {
384 size_t i;
385
386 for (i = 0; i < array->len; i++) {
387 struct bt_config_component *cfg_component =
388 bt_config_get_component(array, i);
389 print_bt_config_component(cfg_component);
390 BT_PUT(cfg_component);
391 }
392 }
393
394 static
395 void print_plugin_paths(struct bt_value *plugin_paths)
396 {
397 fprintf(stderr, " Plugin paths:\n");
398 print_value(stderr, plugin_paths, 4);
399 }
400
401 static
402 void print_cfg_run(struct bt_config *cfg)
403 {
404 size_t i;
405
406 print_plugin_paths(cfg->plugin_paths);
407 fprintf(stderr, " Source component instances:\n");
408 print_bt_config_components(cfg->cmd_data.run.sources);
409
410 if (cfg->cmd_data.run.filters->len > 0) {
411 fprintf(stderr, " Filter component instances:\n");
412 print_bt_config_components(cfg->cmd_data.run.filters);
413 }
414
415 fprintf(stderr, " Sink component instances:\n");
416 print_bt_config_components(cfg->cmd_data.run.sinks);
417 fprintf(stderr, " Connections:\n");
418
419 for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
420 struct bt_config_connection *cfg_connection =
421 g_ptr_array_index(cfg->cmd_data.run.connections,
422 i);
423
424 fprintf(stderr, " %s%s%s -> %s%s%s\n",
425 cfg_connection->upstream_comp_name->str,
426 cfg_connection->upstream_port_glob->len > 0 ? "." : "",
427 cfg_connection->upstream_port_glob->str,
428 cfg_connection->downstream_comp_name->str,
429 cfg_connection->downstream_port_glob->len > 0 ? "." : "",
430 cfg_connection->downstream_port_glob->str);
431 }
432 }
433
434 static
435 void print_cfg_list_plugins(struct bt_config *cfg)
436 {
437 print_plugin_paths(cfg->plugin_paths);
438 }
439
440 static
441 void print_cfg_help(struct bt_config *cfg)
442 {
443 print_plugin_paths(cfg->plugin_paths);
444 }
445
446 static
447 void print_cfg_print_ctf_metadata(struct bt_config *cfg)
448 {
449 print_plugin_paths(cfg->plugin_paths);
450 fprintf(stderr, " Path: %s\n",
451 cfg->cmd_data.print_ctf_metadata.path->str);
452 }
453
454 static
455 void print_cfg_print_lttng_live_sessions(struct bt_config *cfg)
456 {
457 print_plugin_paths(cfg->plugin_paths);
458 fprintf(stderr, " URL: %s\n",
459 cfg->cmd_data.print_lttng_live_sessions.url->str);
460 }
461
462 static
463 void print_cfg_query(struct bt_config *cfg)
464 {
465 print_plugin_paths(cfg->plugin_paths);
466 fprintf(stderr, " Object: `%s`\n", cfg->cmd_data.query.object->str);
467 fprintf(stderr, " Component class:\n");
468 print_bt_config_component(cfg->cmd_data.query.cfg_component);
469 }
470
471 static
472 void print_cfg(struct bt_config *cfg)
473 {
474 if (!BT_LOG_ON_INFO) {
475 return;
476 }
477
478 BT_LOGI_STR("Configuration:");
479 fprintf(stderr, " Debug mode: %s\n", cfg->debug ? "yes" : "no");
480 fprintf(stderr, " Verbose mode: %s\n", cfg->verbose ? "yes" : "no");
481
482 switch (cfg->command) {
483 case BT_CONFIG_COMMAND_RUN:
484 print_cfg_run(cfg);
485 break;
486 case BT_CONFIG_COMMAND_LIST_PLUGINS:
487 print_cfg_list_plugins(cfg);
488 break;
489 case BT_CONFIG_COMMAND_HELP:
490 print_cfg_help(cfg);
491 break;
492 case BT_CONFIG_COMMAND_QUERY:
493 print_cfg_query(cfg);
494 break;
495 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
496 print_cfg_print_ctf_metadata(cfg);
497 break;
498 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
499 print_cfg_print_lttng_live_sessions(cfg);
500 break;
501 default:
502 assert(false);
503 }
504 }
505
506 static
507 void add_to_loaded_plugins(struct bt_plugin_set *plugin_set)
508 {
509 int64_t i;
510 int64_t count;
511
512 count = bt_plugin_set_get_plugin_count(plugin_set);
513 assert(count >= 0);
514
515 for (i = 0; i < count; i++) {
516 struct bt_plugin *plugin =
517 bt_plugin_set_get_plugin(plugin_set, i);
518 struct bt_plugin *loaded_plugin =
519 find_plugin(bt_plugin_get_name(plugin));
520
521 assert(plugin);
522
523 if (loaded_plugin) {
524 BT_LOGI("Not using plugin: another one already exists with the same name: "
525 "plugin-name=\"%s\", plugin-path=\"%s\", "
526 "existing-plugin-path=\"%s\"",
527 bt_plugin_get_name(plugin),
528 bt_plugin_get_path(plugin),
529 bt_plugin_get_path(loaded_plugin));
530 bt_put(loaded_plugin);
531 } else {
532 /* Add to global array. */
533 BT_LOGD("Adding plugin to loaded plugins: plugin-path=\"%s\"",
534 bt_plugin_get_name(plugin));
535 g_ptr_array_add(loaded_plugins, bt_get(plugin));
536 }
537
538 bt_put(plugin);
539 }
540 }
541
542 static
543 int load_dynamic_plugins(struct bt_value *plugin_paths)
544 {
545 int nr_paths, i, ret = 0;
546
547 nr_paths = bt_value_array_size(plugin_paths);
548 if (nr_paths < 0) {
549 BT_LOGE_STR("Cannot load dynamic plugins: no plugin path.");
550 ret = -1;
551 goto end;
552 }
553
554 BT_LOGI("Loading dynamic plugins.");
555
556 for (i = 0; i < nr_paths; i++) {
557 struct bt_value *plugin_path_value = NULL;
558 const char *plugin_path;
559 struct bt_plugin_set *plugin_set;
560
561 plugin_path_value = bt_value_array_get(plugin_paths, i);
562 bt_value_string_get(plugin_path_value, &plugin_path);
563 assert(plugin_path);
564 plugin_set = bt_plugin_create_all_from_dir(plugin_path, false);
565 if (!plugin_set) {
566 BT_LOGD("Unable to load dynamic plugins: path=\"%s\"",
567 plugin_path);
568 BT_PUT(plugin_path_value);
569 continue;
570 }
571
572 add_to_loaded_plugins(plugin_set);
573 bt_put(plugin_set);
574 BT_PUT(plugin_path_value);
575 }
576 end:
577 return ret;
578 }
579
580 static
581 int load_static_plugins(void)
582 {
583 int ret = 0;
584 struct bt_plugin_set *plugin_set;
585
586 BT_LOGI("Loading static plugins.");
587 plugin_set = bt_plugin_create_all_from_static();
588 if (!plugin_set) {
589 BT_LOGE("Unable to load static plugins.");
590 ret = -1;
591 goto end;
592 }
593
594 add_to_loaded_plugins(plugin_set);
595 bt_put(plugin_set);
596 end:
597 return ret;
598 }
599
600 static
601 int load_all_plugins(struct bt_value *plugin_paths)
602 {
603 int ret = 0;
604
605 if (load_dynamic_plugins(plugin_paths)) {
606 ret = -1;
607 goto end;
608 }
609
610 if (load_static_plugins()) {
611 ret = -1;
612 goto end;
613 }
614
615 BT_LOGI("Loaded all plugins: count=%u", loaded_plugins->len);
616
617 end:
618 return ret;
619 }
620
621 static
622 void print_plugin_info(struct bt_plugin *plugin)
623 {
624 unsigned int major, minor, patch;
625 const char *extra;
626 enum bt_plugin_status version_status;
627 const char *plugin_name;
628 const char *path;
629 const char *author;
630 const char *license;
631 const char *plugin_description;
632
633 plugin_name = bt_plugin_get_name(plugin);
634 path = bt_plugin_get_path(plugin);
635 author = bt_plugin_get_author(plugin);
636 license = bt_plugin_get_license(plugin);
637 plugin_description = bt_plugin_get_description(plugin);
638 version_status = bt_plugin_get_version(plugin, &major, &minor,
639 &patch, &extra);
640 printf("%s%s%s%s:\n", bt_common_color_bold(),
641 bt_common_color_fg_blue(), plugin_name,
642 bt_common_color_reset());
643 printf(" %sPath%s: %s\n", bt_common_color_bold(),
644 bt_common_color_reset(), path ? path : "(None)");
645
646 if (version_status == BT_PLUGIN_STATUS_OK) {
647 printf(" %sVersion%s: %u.%u.%u",
648 bt_common_color_bold(), bt_common_color_reset(),
649 major, minor, patch);
650
651 if (extra) {
652 printf("%s", extra);
653 }
654
655 printf("\n");
656 }
657
658 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
659 bt_common_color_reset(),
660 plugin_description ? plugin_description : "(None)");
661 printf(" %sAuthor%s: %s\n", bt_common_color_bold(),
662 bt_common_color_reset(), author ? author : "(Unknown)");
663 printf(" %sLicense%s: %s\n", bt_common_color_bold(),
664 bt_common_color_reset(),
665 license ? license : "(Unknown)");
666 }
667
668 static
669 int cmd_query(struct bt_config *cfg)
670 {
671 int ret;
672 struct bt_component_class *comp_cls = NULL;
673 struct bt_value *results = NULL;
674
675 ret = load_all_plugins(cfg->plugin_paths);
676 if (ret) {
677 goto end;
678 }
679
680 comp_cls = find_component_class(cfg->cmd_data.query.cfg_component->plugin_name->str,
681 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
682 cfg->cmd_data.query.cfg_component->type);
683 if (!comp_cls) {
684 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
685 "comp-cls-name=\"%s\", comp-cls-type=%d",
686 cfg->cmd_data.query.cfg_component->plugin_name->str,
687 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
688 cfg->cmd_data.query.cfg_component->type);
689 fprintf(stderr, "%s%sCannot find component class %s",
690 bt_common_color_bold(),
691 bt_common_color_fg_red(),
692 bt_common_color_reset());
693 print_plugin_comp_cls_opt(stderr,
694 cfg->cmd_data.query.cfg_component->plugin_name->str,
695 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
696 cfg->cmd_data.query.cfg_component->type);
697 fprintf(stderr, "\n");
698 ret = -1;
699 goto end;
700 }
701
702 results = bt_component_class_query(comp_cls,
703 cfg->cmd_data.query.object->str,
704 cfg->cmd_data.query.cfg_component->params);
705 if (!results) {
706 BT_LOGE("Failed to query component class: plugin-name=\"%s\", "
707 "comp-cls-name=\"%s\", comp-cls-type=%d "
708 "object=\"%s\"",
709 cfg->cmd_data.query.cfg_component->plugin_name->str,
710 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
711 cfg->cmd_data.query.cfg_component->type,
712 cfg->cmd_data.query.object->str);
713 fprintf(stderr, "%s%sFailed to query info to %s",
714 bt_common_color_bold(),
715 bt_common_color_fg_red(),
716 bt_common_color_reset());
717 print_plugin_comp_cls_opt(stderr,
718 cfg->cmd_data.query.cfg_component->plugin_name->str,
719 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
720 cfg->cmd_data.query.cfg_component->type);
721 fprintf(stderr, "%s%s with object `%s`%s\n",
722 bt_common_color_bold(),
723 bt_common_color_fg_red(),
724 cfg->cmd_data.query.object->str,
725 bt_common_color_reset());
726 ret = -1;
727 goto end;
728 }
729
730 print_value(stdout, results, 0);
731
732 end:
733 bt_put(comp_cls);
734 bt_put(results);
735 return ret;
736 }
737
738 static
739 int cmd_help(struct bt_config *cfg)
740 {
741 int ret;
742 struct bt_plugin *plugin = NULL;
743 size_t i;
744
745 ret = load_all_plugins(cfg->plugin_paths);
746 if (ret) {
747 goto end;
748 }
749
750 plugin = find_plugin(cfg->cmd_data.help.cfg_component->plugin_name->str);
751 if (!plugin) {
752 BT_LOGE("Cannot find plugin: plugin-name=\"%s\"",
753 cfg->cmd_data.help.cfg_component->plugin_name->str);
754 fprintf(stderr, "%s%sCannot find plugin %s%s%s\n",
755 bt_common_color_bold(), bt_common_color_fg_red(),
756 bt_common_color_fg_blue(),
757 cfg->cmd_data.help.cfg_component->plugin_name->str,
758 bt_common_color_reset());
759 ret = -1;
760 goto end;
761 }
762
763 print_plugin_info(plugin);
764 printf(" %sComponent classes%s: %d\n",
765 bt_common_color_bold(),
766 bt_common_color_reset(),
767 (int) bt_plugin_get_component_class_count(plugin));
768
769
770 if (cfg->cmd_data.help.cfg_component->type !=
771 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
772 struct bt_component_class *needed_comp_cls =
773 find_component_class(
774 cfg->cmd_data.help.cfg_component->plugin_name->str,
775 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
776 cfg->cmd_data.help.cfg_component->type);
777
778 if (!needed_comp_cls) {
779 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
780 "comp-cls-name=\"%s\", comp-cls-type=%d",
781 cfg->cmd_data.help.cfg_component->plugin_name->str,
782 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
783 cfg->cmd_data.help.cfg_component->type);
784 fprintf(stderr, "\n%s%sCannot find component class %s",
785 bt_common_color_bold(),
786 bt_common_color_fg_red(),
787 bt_common_color_reset());
788 print_plugin_comp_cls_opt(stderr,
789 cfg->cmd_data.help.cfg_component->plugin_name->str,
790 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
791 cfg->cmd_data.help.cfg_component->type);
792 fprintf(stderr, "\n");
793 ret = -1;
794 goto end;
795 }
796
797 bt_put(needed_comp_cls);
798 }
799
800 for (i = 0; i < bt_plugin_get_component_class_count(plugin); i++) {
801 struct bt_component_class *comp_cls =
802 bt_plugin_get_component_class_by_index(plugin, i);
803 const char *comp_class_name =
804 bt_component_class_get_name(comp_cls);
805 const char *comp_class_description =
806 bt_component_class_get_description(comp_cls);
807 const char *comp_class_help =
808 bt_component_class_get_help(comp_cls);
809 enum bt_component_class_type type =
810 bt_component_class_get_type(comp_cls);
811
812 assert(comp_cls);
813
814 if (cfg->cmd_data.help.cfg_component->type !=
815 BT_COMPONENT_CLASS_TYPE_UNKNOWN) {
816 if (strcmp(cfg->cmd_data.help.cfg_component->comp_cls_name->str,
817 comp_class_name) != 0 &&
818 type ==
819 cfg->cmd_data.help.cfg_component->type) {
820 bt_put(comp_cls);
821 continue;
822 }
823 }
824
825 printf("\n");
826 print_plugin_comp_cls_opt(stdout,
827 cfg->cmd_data.help.cfg_component->plugin_name->str,
828 comp_class_name,
829 type);
830 printf("\n");
831 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
832 bt_common_color_reset(),
833 comp_class_description ? comp_class_description : "(None)");
834
835 if (comp_class_help) {
836 printf("\n%s\n", comp_class_help);
837 }
838
839 bt_put(comp_cls);
840 }
841
842 end:
843 bt_put(plugin);
844 return ret;
845 }
846
847 static
848 int cmd_list_plugins(struct bt_config *cfg)
849 {
850 int ret = 0;
851 int plugins_count, component_classes_count = 0, i;
852
853 ret = load_all_plugins(cfg->plugin_paths);
854 if (ret) {
855 goto end;
856 }
857
858 printf("From the following plugin paths:\n\n");
859 print_value(stdout, cfg->plugin_paths, 2);
860 printf("\n");
861 plugins_count = loaded_plugins->len;
862 if (plugins_count == 0) {
863 printf("No plugins found.\n");
864 goto end;
865 }
866
867 for (i = 0; i < plugins_count; i++) {
868 struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
869
870 component_classes_count += bt_plugin_get_component_class_count(plugin);
871 }
872
873 printf("Found %s%d%s component classes in %s%d%s plugins.\n",
874 bt_common_color_bold(),
875 component_classes_count,
876 bt_common_color_reset(),
877 bt_common_color_bold(),
878 plugins_count,
879 bt_common_color_reset());
880
881 for (i = 0; i < plugins_count; i++) {
882 int j;
883 struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
884
885 component_classes_count =
886 bt_plugin_get_component_class_count(plugin);
887 printf("\n");
888 print_plugin_info(plugin);
889
890 if (component_classes_count == 0) {
891 printf(" %sComponent classes%s: (none)\n",
892 bt_common_color_bold(),
893 bt_common_color_reset());
894 } else {
895 printf(" %sComponent classes%s:\n",
896 bt_common_color_bold(),
897 bt_common_color_reset());
898 }
899
900 for (j = 0; j < component_classes_count; j++) {
901 struct bt_component_class *comp_class =
902 bt_plugin_get_component_class_by_index(
903 plugin, j);
904 const char *comp_class_name =
905 bt_component_class_get_name(comp_class);
906 const char *comp_class_description =
907 bt_component_class_get_description(comp_class);
908 enum bt_component_class_type type =
909 bt_component_class_get_type(comp_class);
910
911 printf(" ");
912 print_plugin_comp_cls_opt(stdout,
913 bt_plugin_get_name(plugin), comp_class_name,
914 type);
915
916 if (comp_class_description) {
917 printf(": %s", comp_class_description);
918 }
919
920 printf("\n");
921 bt_put(comp_class);
922 }
923 }
924
925 end:
926 return ret;
927 }
928
929 static
930 int cmd_print_lttng_live_sessions(struct bt_config *cfg)
931 {
932 printf("TODO\n");
933 return -1;
934 }
935
936 static
937 int cmd_print_ctf_metadata(struct bt_config *cfg)
938 {
939 int ret = 0;
940 struct bt_component_class *comp_cls = NULL;
941 struct bt_value *results = NULL;
942 struct bt_value *params = NULL;
943 struct bt_value *metadata_text_value = NULL;
944 const char *metadata_text = NULL;
945 static const char * const plugin_name = "ctf";
946 static const char * const comp_cls_name = "fs";
947 static const enum bt_component_class_type comp_cls_type =
948 BT_COMPONENT_CLASS_TYPE_SOURCE;
949
950 assert(cfg->cmd_data.print_ctf_metadata.path);
951 comp_cls = find_component_class(plugin_name, comp_cls_name,
952 comp_cls_type);
953 if (!comp_cls) {
954 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
955 "comp-cls-name=\"%s\", comp-cls-type=%d",
956 plugin_name, comp_cls_name,
957 BT_COMPONENT_CLASS_TYPE_SOURCE);
958 fprintf(stderr, "%s%sCannot find component class %s",
959 bt_common_color_bold(),
960 bt_common_color_fg_red(),
961 bt_common_color_reset());
962 print_plugin_comp_cls_opt(stderr, plugin_name,
963 comp_cls_name, comp_cls_type);
964 fprintf(stderr, "\n");
965 ret = -1;
966 goto end;
967 }
968
969 params = bt_value_map_create();
970 if (!params) {
971 ret = -1;
972 goto end;
973 }
974
975 ret = bt_value_map_insert_string(params, "path",
976 cfg->cmd_data.print_ctf_metadata.path->str);
977 if (ret) {
978 ret = -1;
979 goto end;
980 }
981
982 results = bt_component_class_query(comp_cls, "metadata-info",
983 params);
984 if (!results) {
985 ret = -1;
986 BT_LOGE_STR("Failed to query for metadata info.");
987 fprintf(stderr, "%s%sFailed to request metadata info%s\n",
988 bt_common_color_bold(),
989 bt_common_color_fg_red(),
990 bt_common_color_reset());
991 goto end;
992 }
993
994 metadata_text_value = bt_value_map_get(results, "text");
995 if (!metadata_text_value) {
996 BT_LOGE_STR("Cannot find `text` string value in the resulting metadata info object.");
997 ret = -1;
998 goto end;
999 }
1000
1001 ret = bt_value_string_get(metadata_text_value, &metadata_text);
1002 assert(ret == 0);
1003 printf("%s\n", metadata_text);
1004
1005 end:
1006 bt_put(results);
1007 bt_put(params);
1008 bt_put(metadata_text_value);
1009 bt_put(comp_cls);
1010 return 0;
1011 }
1012
1013 struct cmd_run_ctx {
1014 /* Owned by this */
1015 GHashTable *components;
1016
1017 /* Owned by this */
1018 struct bt_graph *graph;
1019
1020 /* Weak */
1021 struct bt_config *cfg;
1022
1023 bool connect_ports;
1024 };
1025
1026 static
1027 int cmd_run_ctx_connect_upstream_port_to_downstream_component(
1028 struct cmd_run_ctx *ctx, struct bt_component *upstream_comp,
1029 struct bt_port *upstream_port,
1030 struct bt_config_connection *cfg_conn)
1031 {
1032 int ret = 0;
1033 GQuark downstreamp_comp_name_quark;
1034 struct bt_component *downstream_comp;
1035 int64_t downstream_port_count;
1036 uint64_t i;
1037 int64_t (*port_count_fn)(struct bt_component *);
1038 struct bt_port *(*port_by_index_fn)(struct bt_component *, uint64_t);
1039 void *conn = NULL;
1040
1041 BT_LOGI("Connecting upstream port to the next available downstream port: "
1042 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1043 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1044 upstream_port, bt_port_get_name(upstream_port),
1045 cfg_conn->downstream_comp_name->str,
1046 cfg_conn->arg->str);
1047 downstreamp_comp_name_quark = g_quark_from_string(
1048 cfg_conn->downstream_comp_name->str);
1049 assert(downstreamp_comp_name_quark > 0);
1050 downstream_comp = g_hash_table_lookup(ctx->components,
1051 (gpointer) (long) downstreamp_comp_name_quark);
1052 if (!downstream_comp) {
1053 BT_LOGE("Cannot find downstream component: comp-name=\"%s\", "
1054 "conn-arg=\"%s\"", cfg_conn->downstream_comp_name->str,
1055 cfg_conn->arg->str);
1056 fprintf(stderr, "Cannot create connection: cannot find downstream component: %s\n",
1057 cfg_conn->arg->str);
1058 goto error;
1059 }
1060
1061 if (bt_component_is_filter(downstream_comp)) {
1062 port_count_fn = bt_component_filter_get_input_port_count;
1063 port_by_index_fn = bt_component_filter_get_input_port_by_index;
1064 } else if (bt_component_is_sink(downstream_comp)) {
1065 port_count_fn = bt_component_sink_get_input_port_count;
1066 port_by_index_fn = bt_component_sink_get_input_port_by_index;
1067 } else {
1068 /*
1069 * Should never happen because the connections are
1070 * validated before we get here.
1071 */
1072 BT_LOGF("Invalid connection: downstream component is a source: "
1073 "conn-arg=\"%s\"", cfg_conn->arg->str);
1074 assert(false);
1075 }
1076
1077 downstream_port_count = port_count_fn(downstream_comp);
1078 assert(downstream_port_count >= 0);
1079
1080 for (i = 0; i < downstream_port_count; i++) {
1081 struct bt_port *downstream_port =
1082 port_by_index_fn(downstream_comp, i);
1083 const char *downstream_port_name;
1084
1085 assert(downstream_port);
1086
1087 /* Skip port if it's already connected */
1088 if (bt_port_is_connected(downstream_port)) {
1089 bt_put(downstream_port);
1090 BT_LOGD("Skipping downstream port: already connected: "
1091 "port-addr=%p, port-name=\"%s\"",
1092 downstream_port,
1093 bt_port_get_name(downstream_port));
1094 continue;
1095 }
1096
1097 downstream_port_name = bt_port_get_name(downstream_port);
1098 assert(downstream_port_name);
1099
1100 if (bt_common_star_glob_match(
1101 cfg_conn->downstream_port_glob->str, -1ULL,
1102 downstream_port_name, -1ULL)) {
1103 /* We have a winner! */
1104 conn = bt_graph_connect_ports(ctx->graph,
1105 upstream_port, downstream_port);
1106 bt_put(downstream_port);
1107 if (!conn) {
1108 BT_LOGE("Cannot create connection: graph refuses to connect ports: "
1109 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1110 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1111 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1112 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1113 "conn-arg=\"%s\"",
1114 upstream_comp, bt_component_get_name(upstream_comp),
1115 upstream_port, bt_port_get_name(upstream_port),
1116 downstream_comp, cfg_conn->downstream_comp_name->str,
1117 downstream_port, downstream_port_name,
1118 cfg_conn->arg->str);
1119 fprintf(stderr,
1120 "Cannot create connection: graph refuses to connect ports (`%s` to `%s`): %s\n",
1121 bt_port_get_name(upstream_port),
1122 downstream_port_name,
1123 cfg_conn->arg->str);
1124 goto error;
1125 }
1126
1127 BT_LOGI("Connected component ports: "
1128 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1129 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1130 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1131 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1132 "conn-arg=\"%s\"",
1133 upstream_comp, bt_component_get_name(upstream_comp),
1134 upstream_port, bt_port_get_name(upstream_port),
1135 downstream_comp, cfg_conn->downstream_comp_name->str,
1136 downstream_port, downstream_port_name,
1137 cfg_conn->arg->str);
1138
1139 goto end;
1140 }
1141
1142 bt_put(downstream_port);
1143 }
1144
1145 if (!conn) {
1146 BT_LOGE("Cannot create connection: cannot find a matching downstream port for upstream port: "
1147 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1148 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1149 upstream_port, bt_port_get_name(upstream_port),
1150 cfg_conn->downstream_comp_name->str,
1151 cfg_conn->arg->str);
1152 fprintf(stderr,
1153 "Cannot create connection: cannot find a matching downstream port for upstream port `%s`: %s\n",
1154 bt_port_get_name(upstream_port), cfg_conn->arg->str);
1155 goto error;
1156 }
1157
1158 goto end;
1159
1160 error:
1161 ret = -1;
1162
1163 end:
1164 bt_put(conn);
1165 return ret;
1166 }
1167
1168 static
1169 int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx,
1170 struct bt_port *upstream_port)
1171 {
1172 int ret = 0;
1173 const char *upstream_port_name;
1174 const char *upstream_comp_name;
1175 struct bt_component *upstream_comp = NULL;
1176 size_t i;
1177
1178 assert(ctx);
1179 assert(upstream_port);
1180 upstream_port_name = bt_port_get_name(upstream_port);
1181 assert(upstream_port_name);
1182 upstream_comp = bt_port_get_component(upstream_port);
1183 if (!upstream_comp) {
1184 BT_LOGW("Upstream port to connect is not part of a component: "
1185 "port-addr=%p, port-name=\"%s\"",
1186 upstream_port, upstream_port_name);
1187 ret = -1;
1188 goto end;
1189 }
1190
1191 upstream_comp_name = bt_component_get_name(upstream_comp);
1192 assert(upstream_comp_name);
1193 BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", "
1194 "port-addr=%p, port-name=\"%s\"",
1195 upstream_comp, upstream_comp_name,
1196 upstream_port, upstream_port_name);
1197
1198 for (i = 0; i < ctx->cfg->cmd_data.run.connections->len; i++) {
1199 struct bt_config_connection *cfg_conn =
1200 g_ptr_array_index(
1201 ctx->cfg->cmd_data.run.connections, i);
1202
1203 if (strcmp(cfg_conn->upstream_comp_name->str,
1204 upstream_comp_name) == 0) {
1205 if (bt_common_star_glob_match(
1206 cfg_conn->upstream_port_glob->str,
1207 -1ULL, upstream_port_name, -1ULL)) {
1208 ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
1209 ctx, upstream_comp, upstream_port,
1210 cfg_conn);
1211 if (ret) {
1212 BT_LOGE("Cannot connect upstream port: "
1213 "port-addr=%p, port-name=\"%s\"",
1214 upstream_port,
1215 upstream_port_name);
1216 fprintf(stderr,
1217 "Cannot connect port `%s` of component `%s` to a downstream port: %s\n",
1218 upstream_port_name,
1219 upstream_comp_name,
1220 cfg_conn->arg->str);
1221 goto error;
1222 }
1223
1224 goto end;
1225 }
1226 }
1227 }
1228
1229 BT_LOGE("Cannot connect upstream port: port does not match any connection argument: "
1230 "port-addr=%p, port-name=\"%s\"", upstream_port,
1231 upstream_port_name);
1232 fprintf(stderr,
1233 "Cannot create connection: upstream port `%s` does not match any connection\n",
1234 upstream_port_name);
1235
1236 error:
1237 ret = -1;
1238
1239 end:
1240 bt_put(upstream_comp);
1241 return ret;
1242 }
1243
1244 static
1245 void graph_port_added_listener(struct bt_port *port, void *data)
1246 {
1247 struct bt_component *comp = NULL;
1248 struct cmd_run_ctx *ctx = data;
1249
1250 BT_LOGI("Port added to a graph's component: port-addr=%p, port-name=\"%s\"",
1251 port, bt_port_get_name(port));
1252
1253 if (bt_port_is_connected(port)) {
1254 BT_LOGW_STR("Port is already connected.");
1255 goto end;
1256 }
1257
1258 comp = bt_port_get_component(port);
1259 if (!comp) {
1260 BT_LOGW_STR("Port has no component.");
1261 goto end;
1262 }
1263
1264 if (!bt_port_is_output(port)) {
1265 BT_LOGI_STR("Skipping input port.");
1266 goto end;
1267 }
1268
1269 if (cmd_run_ctx_connect_upstream_port(ctx, port)) {
1270 BT_LOGF_STR("Cannot connect upstream port.");
1271 fprintf(stderr, "Added port could not be connected: aborting\n");
1272 abort();
1273 }
1274
1275 end:
1276 bt_put(comp);
1277 return;
1278 }
1279
1280 static
1281 void graph_port_removed_listener(struct bt_component *component,
1282 struct bt_port *port, void *data)
1283 {
1284 BT_LOGI("Port removed from a graph's component: comp-addr=%p, "
1285 "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
1286 component, bt_component_get_name(component),
1287 port, bt_port_get_name(port));
1288 }
1289
1290 static
1291 void graph_ports_connected_listener(struct bt_port *upstream_port,
1292 struct bt_port *downstream_port, void *data)
1293 {
1294 BT_LOGI("Graph's component ports connected: "
1295 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1296 "downstream-port-addr=%p, downstream-port-name=\"%s\"",
1297 upstream_port, bt_port_get_name(upstream_port),
1298 downstream_port, bt_port_get_name(downstream_port));
1299 }
1300
1301 static
1302 void graph_ports_disconnected_listener(
1303 struct bt_component *upstream_component,
1304 struct bt_component *downstream_component,
1305 struct bt_port *upstream_port, struct bt_port *downstream_port,
1306 void *data)
1307 {
1308 BT_LOGI("Graph's component ports disconnected: "
1309 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1310 "downstream-port-addr=%p, downstream-port-name=\"%s\"",
1311 upstream_port, bt_port_get_name(upstream_port),
1312 downstream_port, bt_port_get_name(downstream_port));
1313 }
1314
1315 static
1316 void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx)
1317 {
1318 if (!ctx) {
1319 return;
1320 }
1321
1322 if (ctx->components) {
1323 g_hash_table_destroy(ctx->components);
1324 ctx->components = NULL;
1325 }
1326
1327 BT_PUT(ctx->graph);
1328 ctx->cfg = NULL;
1329 }
1330
1331 static
1332 int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg)
1333 {
1334 int ret = 0;
1335
1336 ctx->cfg = cfg;
1337 ctx->connect_ports = false;
1338 ctx->components = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1339 NULL, bt_put);
1340 if (!ctx->components) {
1341 goto error;
1342 }
1343
1344 ctx->graph = bt_graph_create();
1345 if (!ctx->graph) {
1346 goto error;
1347 }
1348
1349 ret = bt_graph_add_port_added_listener(ctx->graph,
1350 graph_port_added_listener, ctx);
1351 if (ret) {
1352 goto error;
1353 }
1354
1355 ret = bt_graph_add_port_removed_listener(ctx->graph,
1356 graph_port_removed_listener, ctx);
1357 if (ret) {
1358 goto error;
1359 }
1360
1361 ret = bt_graph_add_ports_connected_listener(ctx->graph,
1362 graph_ports_connected_listener, ctx);
1363 if (ret) {
1364 goto error;
1365 }
1366
1367 ret = bt_graph_add_ports_disconnected_listener(ctx->graph,
1368 graph_ports_disconnected_listener, ctx);
1369 if (ret) {
1370 goto error;
1371 }
1372
1373 goto end;
1374
1375 error:
1376 cmd_run_ctx_destroy(ctx);
1377 ret = -1;
1378
1379 end:
1380 return ret;
1381 }
1382
1383 static
1384 int cmd_run_ctx_create_components_from_config_components(
1385 struct cmd_run_ctx *ctx, GPtrArray *cfg_components)
1386 {
1387 size_t i;
1388 struct bt_component_class *comp_cls = NULL;
1389 struct bt_component *comp = NULL;
1390 int ret = 0;
1391
1392 for (i = 0; i < cfg_components->len; i++) {
1393 struct bt_config_component *cfg_comp =
1394 g_ptr_array_index(cfg_components, i);
1395 GQuark quark;
1396
1397 comp_cls = find_component_class(cfg_comp->plugin_name->str,
1398 cfg_comp->comp_cls_name->str, cfg_comp->type);
1399 if (!comp_cls) {
1400 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
1401 "comp-cls-name=\"%s\", comp-cls-type=%d",
1402 cfg_comp->plugin_name->str,
1403 cfg_comp->comp_cls_name->str,
1404 cfg_comp->type);
1405 fprintf(stderr, "%s%sCannot find component class %s",
1406 bt_common_color_bold(),
1407 bt_common_color_fg_red(),
1408 bt_common_color_reset());
1409 print_plugin_comp_cls_opt(stderr,
1410 cfg_comp->plugin_name->str,
1411 cfg_comp->comp_cls_name->str,
1412 cfg_comp->type);
1413 fprintf(stderr, "\n");
1414 goto error;
1415 }
1416
1417 comp = bt_component_create(comp_cls,
1418 cfg_comp->instance_name->str, cfg_comp->params);
1419 if (!comp) {
1420 BT_LOGE("Cannot create component: plugin-name=\"%s\", "
1421 "comp-cls-name=\"%s\", comp-cls-type=%d",
1422 "comp-name=\"%s\"",
1423 cfg_comp->plugin_name->str,
1424 cfg_comp->comp_cls_name->str,
1425 cfg_comp->type, cfg_comp->instance_name->str);
1426 fprintf(stderr, "%s%sCannot create component `%s`%s\n",
1427 bt_common_color_bold(),
1428 bt_common_color_fg_red(),
1429 cfg_comp->instance_name->str,
1430 bt_common_color_reset());
1431 goto error;
1432 }
1433
1434 BT_LOGI("Created and inserted component: comp-addr=%p, comp-name=\"%s\"",
1435 comp, cfg_comp->instance_name->str);
1436 quark = g_quark_from_string(cfg_comp->instance_name->str);
1437 assert(quark > 0);
1438 g_hash_table_insert(ctx->components,
1439 (gpointer) (long) quark, comp);
1440 comp = NULL;
1441 BT_PUT(comp_cls);
1442 }
1443
1444 goto end;
1445
1446 error:
1447 ret = -1;
1448
1449 end:
1450 bt_put(comp);
1451 bt_put(comp_cls);
1452 return ret;
1453 }
1454
1455 static
1456 int cmd_run_ctx_create_components(struct cmd_run_ctx *ctx)
1457 {
1458 int ret = 0;
1459
1460 /*
1461 * Make sure that, during this phase, our graph's "port added"
1462 * listener does not connect ports while we are creating the
1463 * components because we have a special, initial phase for
1464 * this.
1465 */
1466 ctx->connect_ports = false;
1467
1468 ret = cmd_run_ctx_create_components_from_config_components(
1469 ctx, ctx->cfg->cmd_data.run.sources);
1470 if (ret) {
1471 ret = -1;
1472 goto end;
1473 }
1474
1475 ret = cmd_run_ctx_create_components_from_config_components(
1476 ctx, ctx->cfg->cmd_data.run.filters);
1477 if (ret) {
1478 ret = -1;
1479 goto end;
1480 }
1481
1482 ret = cmd_run_ctx_create_components_from_config_components(
1483 ctx, ctx->cfg->cmd_data.run.sinks);
1484 if (ret) {
1485 ret = -1;
1486 goto end;
1487 }
1488
1489 end:
1490 return ret;
1491 }
1492
1493 static
1494 int cmd_run_ctx_connect_comp_ports(struct cmd_run_ctx *ctx,
1495 struct bt_component *comp,
1496 int64_t (*port_count_fn)(struct bt_component *),
1497 struct bt_port *(*port_by_index_fn)(struct bt_component *, uint64_t))
1498 {
1499 int ret = 0;
1500 int64_t count;
1501 uint64_t i;
1502
1503 count = port_count_fn(comp);
1504 assert(count >= 0);
1505
1506 for (i = 0; i < count; i++) {
1507 struct bt_port *upstream_port = port_by_index_fn(comp, i);
1508
1509 assert(upstream_port);
1510 ret = cmd_run_ctx_connect_upstream_port(ctx, upstream_port);
1511 bt_put(upstream_port);
1512 if (ret) {
1513 goto end;
1514 }
1515 }
1516
1517 end:
1518 return ret;
1519 }
1520
1521 static
1522 int cmd_run_ctx_connect_ports(struct cmd_run_ctx *ctx)
1523 {
1524 int ret = 0;
1525 GHashTableIter iter;
1526 gpointer g_name_quark, g_comp;
1527
1528 ctx->connect_ports = true;
1529 g_hash_table_iter_init(&iter, ctx->components);
1530
1531 while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
1532 if (bt_component_is_source(g_comp)) {
1533 ret = cmd_run_ctx_connect_comp_ports(ctx,
1534 g_comp, bt_component_source_get_output_port_count,
1535 bt_component_source_get_output_port_by_index);
1536 } else if (bt_component_is_filter(g_comp)) {
1537 ret = cmd_run_ctx_connect_comp_ports(ctx,
1538 g_comp, bt_component_filter_get_output_port_count,
1539 bt_component_filter_get_output_port_by_index);
1540 }
1541
1542 if (ret) {
1543 goto end;
1544 }
1545 }
1546
1547 end:
1548 return ret;
1549 }
1550
1551 static
1552 int cmd_run(struct bt_config *cfg)
1553 {
1554 int ret = 0;
1555 struct cmd_run_ctx ctx = { 0 };
1556
1557 ret = load_all_plugins(cfg->plugin_paths);
1558 if (ret) {
1559 goto error;
1560 }
1561
1562 /* Initialize the command's context and the graph object */
1563 if (cmd_run_ctx_init(&ctx, cfg)) {
1564 BT_LOGE_STR("Cannot initialize the command's context.");
1565 fprintf(stderr, "Cannot initialize the command's context\n");
1566 goto error;
1567 }
1568
1569 /* Create the requested component instances */
1570 if (cmd_run_ctx_create_components(&ctx)) {
1571 BT_LOGE_STR("Cannot create components.");
1572 fprintf(stderr, "Cannot create components\n");
1573 goto error;
1574 }
1575
1576 /* Connect the initially visible component ports */
1577 if (cmd_run_ctx_connect_ports(&ctx)) {
1578 BT_LOGE_STR("Cannot connect initial component ports.");
1579 fprintf(stderr, "Cannot connect initial component ports\n");
1580 goto error;
1581 }
1582
1583 BT_LOGI_STR("Running the graph.");
1584
1585 /* Run the graph */
1586 while (true) {
1587 enum bt_graph_status graph_status = bt_graph_run(ctx.graph);
1588
1589 switch (graph_status) {
1590 case BT_GRAPH_STATUS_OK:
1591 break;
1592 case BT_GRAPH_STATUS_AGAIN:
1593 if (cfg->cmd_data.run.retry_duration_us > 0) {
1594 BT_LOGV("Got BT_GRAPH_STATUS_AGAIN: sleeping: "
1595 "time-us=%" PRIu64,
1596 cfg->cmd_data.run.retry_duration_us);
1597
1598 if (usleep(cfg->cmd_data.run.retry_duration_us)) {
1599 // TODO: check EINTR and signal handler
1600 }
1601 }
1602 break;
1603 case BT_COMPONENT_STATUS_END:
1604 goto end;
1605 default:
1606 BT_LOGE_STR("Graph failed to complete successfully");
1607 fprintf(stderr, "Graph failed to complete successfully\n");
1608 goto error;
1609 }
1610 }
1611
1612 goto end;
1613
1614 error:
1615 if (ret == 0) {
1616 ret = -1;
1617 }
1618
1619 end:
1620 cmd_run_ctx_destroy(&ctx);
1621 return ret;
1622 }
1623
1624 static
1625 void warn_command_name_and_directory_clash(struct bt_config *cfg)
1626 {
1627 const char *env_clash;
1628
1629 if (!cfg->command_name) {
1630 return;
1631 }
1632
1633 env_clash = getenv(ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH);
1634 if (env_clash && strcmp(env_clash, "0") == 0) {
1635 return;
1636 }
1637
1638 if (g_file_test(cfg->command_name,
1639 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
1640 fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
1641 cfg->command_name);
1642 fprintf(stderr, "trace located in the local `%s` directory, please use:\n",
1643 cfg->command_name);
1644 fprintf(stderr, "\n");
1645 fprintf(stderr, " babeltrace convert %s [OPTIONS]\n",
1646 cfg->command_name);
1647 }
1648 }
1649
1650 static
1651 void init_log_level(void)
1652 {
1653 enum bt_logging_level log_level = BT_LOG_NONE;
1654 const char *log_level_env = getenv("BABELTRACE_CLI_LOG_LEVEL");
1655
1656 if (!log_level_env) {
1657 goto set_level;
1658 }
1659
1660 if (strcmp(log_level_env, "VERBOSE") == 0) {
1661 log_level = BT_LOGGING_LEVEL_VERBOSE;
1662 } else if (strcmp(log_level_env, "DEBUG") == 0) {
1663 log_level = BT_LOGGING_LEVEL_DEBUG;
1664 } else if (strcmp(log_level_env, "INFO") == 0) {
1665 log_level = BT_LOGGING_LEVEL_INFO;
1666 } else if (strcmp(log_level_env, "WARN") == 0) {
1667 log_level = BT_LOGGING_LEVEL_WARN;
1668 } else if (strcmp(log_level_env, "ERROR") == 0) {
1669 log_level = BT_LOGGING_LEVEL_ERROR;
1670 } else if (strcmp(log_level_env, "FATAL") == 0) {
1671 log_level = BT_LOGGING_LEVEL_FATAL;
1672 } else if (strcmp(log_level_env, "NONE") == 0) {
1673 log_level = BT_LOGGING_LEVEL_NONE;
1674 }
1675
1676 set_level:
1677 bt_cli_log_level = log_level;
1678 }
1679
1680 int main(int argc, const char **argv)
1681 {
1682 int ret;
1683 int retcode;
1684 struct bt_config *cfg;
1685
1686 init_log_level();
1687 init_static_data();
1688 cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode);
1689
1690 if (retcode < 0) {
1691 /* Quit without errors; typically usage/version */
1692 retcode = 0;
1693 BT_LOGI_STR("Quitting without errors.");
1694 goto end;
1695 }
1696
1697 if (retcode > 0) {
1698 BT_LOGE("Command-line error: retcode=%d", retcode);
1699 goto end;
1700 }
1701
1702 if (!cfg) {
1703 BT_LOGE_STR("Failed to create a valid Babeltrace configuration.");
1704 fprintf(stderr, "Failed to create Babeltrace configuration\n");
1705 retcode = 1;
1706 goto end;
1707 }
1708
1709 if (cfg->verbose) {
1710 bt_cli_log_level = BT_LOGGING_LEVEL_VERBOSE;
1711 bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
1712 // TODO: for backward compat., set the log level
1713 // environment variables of the known plugins
1714 // to VERBOSE
1715 } else if (cfg->debug) {
1716 bt_cli_log_level = BT_LOGGING_LEVEL_DEBUG;
1717 bt_logging_set_global_level(BT_LOGGING_LEVEL_DEBUG);
1718 // TODO: for backward compat., set the log level
1719 // environment variables of the known plugins
1720 // to DEBUG
1721 }
1722
1723 babeltrace_debug = cfg->debug;
1724 babeltrace_verbose = cfg->verbose;
1725 print_cfg(cfg);
1726
1727 if (cfg->command_needs_plugins) {
1728 ret = load_all_plugins(cfg->plugin_paths);
1729 if (ret) {
1730 BT_LOGE("Failed to load plugins: ret=%d", ret);
1731 retcode = 1;
1732 goto end;
1733 }
1734 }
1735
1736 BT_LOGI("Executing command: cmd=%d, command-name=\"%s\"",
1737 cfg->command, cfg->command_name);
1738
1739 switch (cfg->command) {
1740 case BT_CONFIG_COMMAND_RUN:
1741 ret = cmd_run(cfg);
1742 break;
1743 case BT_CONFIG_COMMAND_LIST_PLUGINS:
1744 ret = cmd_list_plugins(cfg);
1745 break;
1746 case BT_CONFIG_COMMAND_HELP:
1747 ret = cmd_help(cfg);
1748 break;
1749 case BT_CONFIG_COMMAND_QUERY:
1750 ret = cmd_query(cfg);
1751 break;
1752 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
1753 ret = cmd_print_ctf_metadata(cfg);
1754 break;
1755 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
1756 ret = cmd_print_lttng_live_sessions(cfg);
1757 break;
1758 default:
1759 BT_LOGF("Invalid command: cmd=%d", cfg->command);
1760 assert(false);
1761 }
1762
1763 warn_command_name_and_directory_clash(cfg);
1764 retcode = ret ? 1 : 0;
1765
1766 end:
1767 BT_PUT(cfg);
1768 fini_static_data();
1769 return retcode;
1770 }
This page took 0.104582 seconds and 3 git commands to generate.