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