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