Port: Use glib portable macros to convert gpointer to int
[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 void *conn = NULL;
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 conn = bt_graph_connect_ports(ctx->graph,
1247 upstream_port, downstream_port);
1248 bt_put(downstream_port);
1249 if (!conn) {
1250 BT_LOGE("Cannot create connection: graph refuses to connect ports: "
1251 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1252 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1253 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1254 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1255 "conn-arg=\"%s\"",
1256 upstream_comp, bt_component_get_name(upstream_comp),
1257 upstream_port, bt_port_get_name(upstream_port),
1258 downstream_comp, cfg_conn->downstream_comp_name->str,
1259 downstream_port, downstream_port_name,
1260 cfg_conn->arg->str);
1261 fprintf(stderr,
1262 "Cannot create connection: graph refuses to connect ports (`%s` to `%s`): %s\n",
1263 bt_port_get_name(upstream_port),
1264 downstream_port_name,
1265 cfg_conn->arg->str);
1266 goto error;
1267 }
1268
1269 BT_LOGI("Connected component ports: "
1270 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1271 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1272 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1273 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1274 "conn-arg=\"%s\"",
1275 upstream_comp, bt_component_get_name(upstream_comp),
1276 upstream_port, bt_port_get_name(upstream_port),
1277 downstream_comp, cfg_conn->downstream_comp_name->str,
1278 downstream_port, downstream_port_name,
1279 cfg_conn->arg->str);
1280
1281 goto end;
1282 }
1283
1284 bt_put(downstream_port);
1285 }
1286
1287 if (!conn) {
1288 BT_LOGE("Cannot create connection: cannot find a matching downstream port for upstream port: "
1289 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1290 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1291 upstream_port, bt_port_get_name(upstream_port),
1292 cfg_conn->downstream_comp_name->str,
1293 cfg_conn->arg->str);
1294 fprintf(stderr,
1295 "Cannot create connection: cannot find a matching downstream port for upstream port `%s`: %s\n",
1296 bt_port_get_name(upstream_port), cfg_conn->arg->str);
1297 goto error;
1298 }
1299
1300 goto end;
1301
1302 error:
1303 ret = -1;
1304
1305 end:
1306 bt_put(conn);
1307 return ret;
1308 }
1309
1310 static
1311 int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx,
1312 struct bt_port *upstream_port)
1313 {
1314 int ret = 0;
1315 const char *upstream_port_name;
1316 const char *upstream_comp_name;
1317 struct bt_component *upstream_comp = NULL;
1318 size_t i;
1319
1320 assert(ctx);
1321 assert(upstream_port);
1322 upstream_port_name = bt_port_get_name(upstream_port);
1323 assert(upstream_port_name);
1324 upstream_comp = bt_port_get_component(upstream_port);
1325 if (!upstream_comp) {
1326 BT_LOGW("Upstream port to connect is not part of a component: "
1327 "port-addr=%p, port-name=\"%s\"",
1328 upstream_port, upstream_port_name);
1329 ret = -1;
1330 goto end;
1331 }
1332
1333 upstream_comp_name = bt_component_get_name(upstream_comp);
1334 assert(upstream_comp_name);
1335 BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", "
1336 "port-addr=%p, port-name=\"%s\"",
1337 upstream_comp, upstream_comp_name,
1338 upstream_port, upstream_port_name);
1339
1340 for (i = 0; i < ctx->cfg->cmd_data.run.connections->len; i++) {
1341 struct bt_config_connection *cfg_conn =
1342 g_ptr_array_index(
1343 ctx->cfg->cmd_data.run.connections, i);
1344
1345 if (strcmp(cfg_conn->upstream_comp_name->str,
1346 upstream_comp_name) == 0) {
1347 if (bt_common_star_glob_match(
1348 cfg_conn->upstream_port_glob->str,
1349 -1ULL, upstream_port_name, -1ULL)) {
1350 ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
1351 ctx, upstream_comp, upstream_port,
1352 cfg_conn);
1353 if (ret) {
1354 BT_LOGE("Cannot connect upstream port: "
1355 "port-addr=%p, port-name=\"%s\"",
1356 upstream_port,
1357 upstream_port_name);
1358 fprintf(stderr,
1359 "Cannot connect port `%s` of component `%s` to a downstream port: %s\n",
1360 upstream_port_name,
1361 upstream_comp_name,
1362 cfg_conn->arg->str);
1363 goto error;
1364 }
1365
1366 goto end;
1367 }
1368 }
1369 }
1370
1371 BT_LOGE("Cannot connect upstream port: port does not match any connection argument: "
1372 "port-addr=%p, port-name=\"%s\"", upstream_port,
1373 upstream_port_name);
1374 fprintf(stderr,
1375 "Cannot create connection: upstream port `%s` does not match any connection\n",
1376 upstream_port_name);
1377
1378 error:
1379 ret = -1;
1380
1381 end:
1382 bt_put(upstream_comp);
1383 return ret;
1384 }
1385
1386 static
1387 void graph_port_added_listener(struct bt_port *port, void *data)
1388 {
1389 struct bt_component *comp = NULL;
1390 struct cmd_run_ctx *ctx = data;
1391
1392 comp = bt_port_get_component(port);
1393 BT_LOGI("Port added to a graph's component: comp-addr=%p, "
1394 "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
1395 comp, comp ? bt_component_get_name(comp) : "",
1396 port, bt_port_get_name(port));
1397 if (!comp) {
1398 BT_LOGW_STR("Port has no component.");
1399 goto end;
1400 }
1401
1402 if (bt_port_is_connected(port)) {
1403 BT_LOGW_STR("Port is already connected.");
1404 goto end;
1405 }
1406
1407 if (!bt_port_is_output(port)) {
1408 BT_LOGI_STR("Skipping input port.");
1409 goto end;
1410 }
1411
1412 if (cmd_run_ctx_connect_upstream_port(ctx, port)) {
1413 BT_LOGF_STR("Cannot connect upstream port.");
1414 fprintf(stderr, "Added port could not be connected: aborting\n");
1415 abort();
1416 }
1417
1418 end:
1419 bt_put(comp);
1420 return;
1421 }
1422
1423 static
1424 void graph_port_removed_listener(struct bt_component *component,
1425 struct bt_port *port, void *data)
1426 {
1427 BT_LOGI("Port removed from a graph's component: comp-addr=%p, "
1428 "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
1429 component, bt_component_get_name(component),
1430 port, bt_port_get_name(port));
1431 }
1432
1433 static
1434 void graph_ports_connected_listener(struct bt_port *upstream_port,
1435 struct bt_port *downstream_port, void *data)
1436 {
1437 struct bt_component *upstream_comp = bt_port_get_component(upstream_port);
1438 struct bt_component *downstream_comp = bt_port_get_component(downstream_port);
1439
1440 assert(upstream_comp);
1441 assert(downstream_comp);
1442 BT_LOGI("Graph's component ports connected: "
1443 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1444 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1445 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1446 "downstream-port-addr=%p, downstream-port-name=\"%s\"",
1447 upstream_comp, bt_component_get_name(upstream_comp),
1448 upstream_port, bt_port_get_name(upstream_port),
1449 downstream_comp, bt_component_get_name(downstream_comp),
1450 downstream_port, bt_port_get_name(downstream_port));
1451 bt_put(upstream_comp);
1452 bt_put(downstream_comp);
1453 }
1454
1455 static
1456 void graph_ports_disconnected_listener(
1457 struct bt_component *upstream_component,
1458 struct bt_component *downstream_component,
1459 struct bt_port *upstream_port, struct bt_port *downstream_port,
1460 void *data)
1461 {
1462 BT_LOGI("Graph's component ports disconnected: "
1463 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1464 "downstream-port-addr=%p, downstream-port-name=\"%s\"",
1465 upstream_port, bt_port_get_name(upstream_port),
1466 downstream_port, bt_port_get_name(downstream_port));
1467 }
1468
1469 static
1470 void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx)
1471 {
1472 if (!ctx) {
1473 return;
1474 }
1475
1476 if (ctx->components) {
1477 g_hash_table_destroy(ctx->components);
1478 ctx->components = NULL;
1479 }
1480
1481 BT_PUT(ctx->graph);
1482 the_graph = NULL;
1483 ctx->cfg = NULL;
1484 }
1485
1486 static
1487 int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg)
1488 {
1489 int ret = 0;
1490
1491 ctx->cfg = cfg;
1492 ctx->connect_ports = false;
1493 ctx->components = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1494 NULL, bt_put);
1495 if (!ctx->components) {
1496 goto error;
1497 }
1498
1499 ctx->graph = bt_graph_create();
1500 if (!ctx->graph) {
1501 goto error;
1502 }
1503
1504 the_graph = ctx->graph;
1505 ret = bt_graph_add_port_added_listener(ctx->graph,
1506 graph_port_added_listener, ctx);
1507 if (ret < 0) {
1508 BT_LOGE_STR("Cannot add \"port added\" listener to graph.");
1509 goto error;
1510 }
1511
1512 ret = bt_graph_add_port_removed_listener(ctx->graph,
1513 graph_port_removed_listener, ctx);
1514 if (ret < 0) {
1515 BT_LOGE_STR("Cannot add \"port removed\" listener to graph.");
1516 goto error;
1517 }
1518
1519 ret = bt_graph_add_ports_connected_listener(ctx->graph,
1520 graph_ports_connected_listener, ctx);
1521 if (ret < 0) {
1522 BT_LOGE_STR("Cannot add \"ports connected\" listener to graph.");
1523 goto error;
1524 }
1525
1526 ret = bt_graph_add_ports_disconnected_listener(ctx->graph,
1527 graph_ports_disconnected_listener, ctx);
1528 if (ret < 0) {
1529 BT_LOGE_STR("Cannot add \"ports disconnected\" listener to graph.");
1530 goto error;
1531 }
1532
1533 goto end;
1534
1535 error:
1536 cmd_run_ctx_destroy(ctx);
1537 ret = -1;
1538
1539 end:
1540 return ret;
1541 }
1542
1543 static
1544 int cmd_run_ctx_create_components_from_config_components(
1545 struct cmd_run_ctx *ctx, GPtrArray *cfg_components)
1546 {
1547 size_t i;
1548 struct bt_component_class *comp_cls = NULL;
1549 struct bt_component *comp = NULL;
1550 int ret = 0;
1551
1552 for (i = 0; i < cfg_components->len; i++) {
1553 struct bt_config_component *cfg_comp =
1554 g_ptr_array_index(cfg_components, i);
1555 GQuark quark;
1556
1557 comp_cls = find_component_class(cfg_comp->plugin_name->str,
1558 cfg_comp->comp_cls_name->str, cfg_comp->type);
1559 if (!comp_cls) {
1560 BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
1561 "comp-cls-name=\"%s\", comp-cls-type=%d",
1562 cfg_comp->plugin_name->str,
1563 cfg_comp->comp_cls_name->str,
1564 cfg_comp->type);
1565 fprintf(stderr, "%s%sCannot find component class %s",
1566 bt_common_color_bold(),
1567 bt_common_color_fg_red(),
1568 bt_common_color_reset());
1569 print_plugin_comp_cls_opt(stderr,
1570 cfg_comp->plugin_name->str,
1571 cfg_comp->comp_cls_name->str,
1572 cfg_comp->type);
1573 fprintf(stderr, "\n");
1574 goto error;
1575 }
1576
1577 comp = bt_component_create(comp_cls,
1578 cfg_comp->instance_name->str, cfg_comp->params);
1579 if (!comp) {
1580 BT_LOGE("Cannot create component: plugin-name=\"%s\", "
1581 "comp-cls-name=\"%s\", comp-cls-type=%d, "
1582 "comp-name=\"%s\"",
1583 cfg_comp->plugin_name->str,
1584 cfg_comp->comp_cls_name->str,
1585 cfg_comp->type, cfg_comp->instance_name->str);
1586 fprintf(stderr, "%s%sCannot create component `%s`%s\n",
1587 bt_common_color_bold(),
1588 bt_common_color_fg_red(),
1589 cfg_comp->instance_name->str,
1590 bt_common_color_reset());
1591 goto error;
1592 }
1593
1594 BT_LOGI("Created and inserted component: comp-addr=%p, comp-name=\"%s\"",
1595 comp, cfg_comp->instance_name->str);
1596 quark = g_quark_from_string(cfg_comp->instance_name->str);
1597 assert(quark > 0);
1598 g_hash_table_insert(ctx->components,
1599 GUINT_TO_POINTER(quark), comp);
1600 comp = NULL;
1601 BT_PUT(comp_cls);
1602 }
1603
1604 goto end;
1605
1606 error:
1607 ret = -1;
1608
1609 end:
1610 bt_put(comp);
1611 bt_put(comp_cls);
1612 return ret;
1613 }
1614
1615 static
1616 int cmd_run_ctx_create_components(struct cmd_run_ctx *ctx)
1617 {
1618 int ret = 0;
1619
1620 /*
1621 * Make sure that, during this phase, our graph's "port added"
1622 * listener does not connect ports while we are creating the
1623 * components because we have a special, initial phase for
1624 * this.
1625 */
1626 ctx->connect_ports = false;
1627
1628 ret = cmd_run_ctx_create_components_from_config_components(
1629 ctx, ctx->cfg->cmd_data.run.sources);
1630 if (ret) {
1631 ret = -1;
1632 goto end;
1633 }
1634
1635 ret = cmd_run_ctx_create_components_from_config_components(
1636 ctx, ctx->cfg->cmd_data.run.filters);
1637 if (ret) {
1638 ret = -1;
1639 goto end;
1640 }
1641
1642 ret = cmd_run_ctx_create_components_from_config_components(
1643 ctx, ctx->cfg->cmd_data.run.sinks);
1644 if (ret) {
1645 ret = -1;
1646 goto end;
1647 }
1648
1649 end:
1650 return ret;
1651 }
1652
1653 static
1654 int cmd_run_ctx_connect_comp_ports(struct cmd_run_ctx *ctx,
1655 struct bt_component *comp,
1656 int64_t (*port_count_fn)(struct bt_component *),
1657 struct bt_port *(*port_by_index_fn)(struct bt_component *, uint64_t))
1658 {
1659 int ret = 0;
1660 int64_t count;
1661 uint64_t i;
1662
1663 count = port_count_fn(comp);
1664 assert(count >= 0);
1665
1666 for (i = 0; i < count; i++) {
1667 struct bt_port *upstream_port = port_by_index_fn(comp, i);
1668
1669 assert(upstream_port);
1670 ret = cmd_run_ctx_connect_upstream_port(ctx, upstream_port);
1671 bt_put(upstream_port);
1672 if (ret) {
1673 goto end;
1674 }
1675 }
1676
1677 end:
1678 return ret;
1679 }
1680
1681 static
1682 int cmd_run_ctx_connect_ports(struct cmd_run_ctx *ctx)
1683 {
1684 int ret = 0;
1685 GHashTableIter iter;
1686 gpointer g_name_quark, g_comp;
1687
1688 ctx->connect_ports = true;
1689 g_hash_table_iter_init(&iter, ctx->components);
1690
1691 while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
1692 if (bt_component_is_source(g_comp)) {
1693 ret = cmd_run_ctx_connect_comp_ports(ctx,
1694 g_comp, bt_component_source_get_output_port_count,
1695 bt_component_source_get_output_port_by_index);
1696 } else if (bt_component_is_filter(g_comp)) {
1697 ret = cmd_run_ctx_connect_comp_ports(ctx,
1698 g_comp, bt_component_filter_get_output_port_count,
1699 bt_component_filter_get_output_port_by_index);
1700 }
1701
1702 if (ret) {
1703 goto end;
1704 }
1705 }
1706
1707 end:
1708 return ret;
1709 }
1710
1711 static inline
1712 const char *bt_graph_status_str(enum bt_graph_status status)
1713 {
1714 switch (status) {
1715 case BT_GRAPH_STATUS_CANCELED:
1716 return "BT_GRAPH_STATUS_CANCELED";
1717 case BT_GRAPH_STATUS_AGAIN:
1718 return "BT_GRAPH_STATUS_AGAIN";
1719 case BT_GRAPH_STATUS_END:
1720 return "BT_GRAPH_STATUS_END";
1721 case BT_GRAPH_STATUS_OK:
1722 return "BT_GRAPH_STATUS_OK";
1723 case BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH:
1724 return "BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH";
1725 case BT_GRAPH_STATUS_INVALID:
1726 return "BT_GRAPH_STATUS_INVALID";
1727 case BT_GRAPH_STATUS_NO_SINK:
1728 return "BT_GRAPH_STATUS_NO_SINK";
1729 case BT_GRAPH_STATUS_ERROR:
1730 return "BT_GRAPH_STATUS_ERROR";
1731 default:
1732 return "(unknown)";
1733 }
1734 }
1735
1736 static
1737 int cmd_run(struct bt_config *cfg)
1738 {
1739 int ret = 0;
1740 struct cmd_run_ctx ctx = { 0 };
1741
1742 /* Initialize the command's context and the graph object */
1743 if (cmd_run_ctx_init(&ctx, cfg)) {
1744 BT_LOGE_STR("Cannot initialize the command's context.");
1745 fprintf(stderr, "Cannot initialize the command's context\n");
1746 goto error;
1747 }
1748
1749 if (canceled) {
1750 BT_LOGI_STR("Canceled by user before creating components.");
1751 goto error;
1752 }
1753
1754 BT_LOGI_STR("Creating components.");
1755
1756 /* Create the requested component instances */
1757 if (cmd_run_ctx_create_components(&ctx)) {
1758 BT_LOGE_STR("Cannot create components.");
1759 fprintf(stderr, "Cannot create components\n");
1760 goto error;
1761 }
1762
1763 if (canceled) {
1764 BT_LOGI_STR("Canceled by user before connecting components.");
1765 goto error;
1766 }
1767
1768 BT_LOGI_STR("Connecting components.");
1769
1770 /* Connect the initially visible component ports */
1771 if (cmd_run_ctx_connect_ports(&ctx)) {
1772 BT_LOGE_STR("Cannot connect initial component ports.");
1773 fprintf(stderr, "Cannot connect initial component ports\n");
1774 goto error;
1775 }
1776
1777 if (canceled) {
1778 BT_LOGI_STR("Canceled by user before running the graph.");
1779 goto error;
1780 }
1781
1782 BT_LOGI_STR("Running the graph.");
1783
1784 /* Run the graph */
1785 while (true) {
1786 enum bt_graph_status graph_status = bt_graph_run(ctx.graph);
1787
1788 /*
1789 * Reset console in case something messed with console
1790 * codes during the graph's execution.
1791 */
1792 printf("%s", bt_common_color_reset());
1793 fflush(stdout);
1794 fprintf(stderr, "%s", bt_common_color_reset());
1795 BT_LOGV("bt_graph_run() returned: status=%s",
1796 bt_graph_status_str(graph_status));
1797
1798 switch (graph_status) {
1799 case BT_GRAPH_STATUS_OK:
1800 break;
1801 case BT_GRAPH_STATUS_CANCELED:
1802 BT_LOGI_STR("Graph was canceled by user.");
1803 goto error;
1804 case BT_GRAPH_STATUS_AGAIN:
1805 if (bt_graph_is_canceled(ctx.graph)) {
1806 BT_LOGI_STR("Graph was canceled by user.");
1807 goto error;
1808 }
1809
1810 if (cfg->cmd_data.run.retry_duration_us > 0) {
1811 BT_LOGV("Got BT_GRAPH_STATUS_AGAIN: sleeping: "
1812 "time-us=%" PRIu64,
1813 cfg->cmd_data.run.retry_duration_us);
1814
1815 if (usleep(cfg->cmd_data.run.retry_duration_us)) {
1816 if (bt_graph_is_canceled(ctx.graph)) {
1817 BT_LOGI_STR("Graph was canceled by user.");
1818 goto error;
1819 }
1820 }
1821 }
1822 break;
1823 case BT_COMPONENT_STATUS_END:
1824 goto end;
1825 default:
1826 BT_LOGE_STR("Graph failed to complete successfully");
1827 fprintf(stderr, "Graph failed to complete successfully\n");
1828 goto error;
1829 }
1830 }
1831
1832 goto end;
1833
1834 error:
1835 if (ret == 0) {
1836 ret = -1;
1837 }
1838
1839 end:
1840 cmd_run_ctx_destroy(&ctx);
1841 return ret;
1842 }
1843
1844 static
1845 void warn_command_name_and_directory_clash(struct bt_config *cfg)
1846 {
1847 const char *env_clash;
1848
1849 if (!cfg->command_name) {
1850 return;
1851 }
1852
1853 env_clash = getenv(ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH);
1854 if (env_clash && strcmp(env_clash, "0") == 0) {
1855 return;
1856 }
1857
1858 if (g_file_test(cfg->command_name,
1859 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
1860 fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
1861 cfg->command_name);
1862 fprintf(stderr, "trace located in the local `%s` directory, please use:\n",
1863 cfg->command_name);
1864 fprintf(stderr, "\n");
1865 fprintf(stderr, " babeltrace convert %s [OPTIONS]\n",
1866 cfg->command_name);
1867 }
1868 }
1869
1870 static
1871 void init_log_level(void)
1872 {
1873 bt_cli_log_level = bt_log_get_level_from_env("BABELTRACE_CLI_LOG_LEVEL");
1874 }
1875
1876 void set_sigint_handler(void)
1877 {
1878 struct sigaction new_action, old_action;
1879
1880 new_action.sa_handler = sigint_handler;
1881 sigemptyset(&new_action.sa_mask);
1882 new_action.sa_flags = 0;
1883 sigaction(SIGINT, NULL, &old_action);
1884
1885 if (old_action.sa_handler != SIG_IGN) {
1886 sigaction(SIGINT, &new_action, NULL);
1887 }
1888 }
1889
1890 int main(int argc, const char **argv)
1891 {
1892 int ret;
1893 int retcode;
1894 struct bt_config *cfg;
1895
1896 init_log_level();
1897 set_sigint_handler();
1898 init_static_data();
1899 cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode);
1900
1901 if (retcode < 0) {
1902 /* Quit without errors; typically usage/version */
1903 retcode = 0;
1904 BT_LOGI_STR("Quitting without errors.");
1905 goto end;
1906 }
1907
1908 if (retcode > 0) {
1909 BT_LOGE("Command-line error: retcode=%d", retcode);
1910 goto end;
1911 }
1912
1913 if (!cfg) {
1914 BT_LOGE_STR("Failed to create a valid Babeltrace configuration.");
1915 fprintf(stderr, "Failed to create Babeltrace configuration\n");
1916 retcode = 1;
1917 goto end;
1918 }
1919
1920 if (cfg->verbose) {
1921 bt_cli_log_level = BT_LOGGING_LEVEL_VERBOSE;
1922 bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
1923 // TODO: for backward compat., set the log level
1924 // environment variables of the known plugins
1925 // to VERBOSE
1926 } else if (cfg->debug) {
1927 bt_cli_log_level = BT_LOGGING_LEVEL_DEBUG;
1928 bt_logging_set_global_level(BT_LOGGING_LEVEL_DEBUG);
1929 // TODO: for backward compat., set the log level
1930 // environment variables of the known plugins
1931 // to DEBUG
1932 }
1933
1934 babeltrace_debug = cfg->debug;
1935 babeltrace_verbose = cfg->verbose;
1936 print_cfg(cfg);
1937
1938 if (cfg->command_needs_plugins) {
1939 ret = load_all_plugins(cfg->plugin_paths);
1940 if (ret) {
1941 BT_LOGE("Failed to load plugins: ret=%d", ret);
1942 retcode = 1;
1943 goto end;
1944 }
1945 }
1946
1947 BT_LOGI("Executing command: cmd=%d, command-name=\"%s\"",
1948 cfg->command, cfg->command_name);
1949
1950 switch (cfg->command) {
1951 case BT_CONFIG_COMMAND_RUN:
1952 ret = cmd_run(cfg);
1953 break;
1954 case BT_CONFIG_COMMAND_LIST_PLUGINS:
1955 ret = cmd_list_plugins(cfg);
1956 break;
1957 case BT_CONFIG_COMMAND_HELP:
1958 ret = cmd_help(cfg);
1959 break;
1960 case BT_CONFIG_COMMAND_QUERY:
1961 ret = cmd_query(cfg);
1962 break;
1963 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
1964 ret = cmd_print_ctf_metadata(cfg);
1965 break;
1966 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
1967 ret = cmd_print_lttng_live_sessions(cfg);
1968 break;
1969 default:
1970 BT_LOGF("Invalid/unknown command: cmd=%d", cfg->command);
1971 abort();
1972 }
1973
1974 BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", ret=%d",
1975 cfg->command, cfg->command_name, ret);
1976 warn_command_name_and_directory_clash(cfg);
1977 retcode = ret ? 1 : 0;
1978
1979 end:
1980 BT_PUT(cfg);
1981 fini_static_data();
1982 return retcode;
1983 }
This page took 0.109304 seconds and 5 git commands to generate.