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