src.ctf.lttng-live: remove some goto error-handling
[babeltrace.git] / src / autodisc / autodisc.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation
5 */
6
7 #define BT_LOG_TAG "CLI-CFG-SRC-AUTO-DISC"
8 #define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) log_level)
9 #include "logging/log.h"
10
11 #include <stdbool.h>
12
13 #include "autodisc.h"
14 #include "common/common.h"
15
16 #define BT_AUTODISC_LOG_AND_APPEND(_lvl, _fmt, ...) \
17 do { \
18 BT_LOG_WRITE_PRINTF(_lvl, BT_LOG_TAG, _fmt, ##__VA_ARGS__); \
19 (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( \
20 "Source auto-discovery", _fmt, ##__VA_ARGS__); \
21 } while (0)
22
23 #define BT_AUTODISC_LOGE_APPEND_CAUSE(_fmt, ...) \
24 BT_AUTODISC_LOG_AND_APPEND(BT_LOG_ERROR, _fmt, ##__VA_ARGS__)
25
26 /*
27 * Define a status enum for inside the auto source discovery code,
28 * as we don't want to return `NO_MATCH` to the caller.
29 */
30 typedef enum auto_source_discovery_internal_status {
31 AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK = AUTO_SOURCE_DISCOVERY_STATUS_OK,
32 AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR = AUTO_SOURCE_DISCOVERY_STATUS_ERROR,
33 AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_MEMORY_ERROR = AUTO_SOURCE_DISCOVERY_STATUS_MEMORY_ERROR,
34 AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED = AUTO_SOURCE_DISCOVERY_STATUS_INTERRUPTED,
35 AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH = __BT_FUNC_STATUS_NO_MATCH,
36 } auto_source_discovery_internal_status;
37
38 /* Finalize and free a `struct auto_source_discovery_result`. */
39
40 static
41 void auto_source_discovery_result_destroy(struct auto_source_discovery_result *res)
42 {
43 if (res) {
44 g_free(res->group);
45 bt_value_put_ref(res->inputs);
46 bt_value_put_ref(res->original_input_indices);
47 g_free(res);
48 }
49 }
50
51 /* Allocate and initialize a `struct auto_source_discovery_result`. */
52
53 static
54 struct auto_source_discovery_result *auto_source_discovery_result_create(
55 const char *plugin_name, const char *source_cc_name,
56 const char *group, bt_logging_level log_level)
57 {
58 struct auto_source_discovery_result *res;
59
60 res = g_new0(struct auto_source_discovery_result, 1);
61 if (!res) {
62 BT_AUTODISC_LOGE_APPEND_CAUSE(
63 "Failed to allocate a auto_source_discovery_result structure.");
64 goto error;
65 }
66
67 res->plugin_name = plugin_name;
68 res->source_cc_name = source_cc_name;
69 res->group = g_strdup(group);
70 if (group && !res->group) {
71 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a string.");
72 goto error;
73 }
74
75 res->inputs = bt_value_array_create();
76 if (!res->inputs) {
77 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
78 goto error;
79 }
80
81 res->original_input_indices = bt_value_array_create();
82 if (!res->original_input_indices) {
83 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
84 goto error;
85 }
86
87 goto end;
88 error:
89 auto_source_discovery_result_destroy(res);
90 res = NULL;
91
92 end:
93 return res;
94 }
95
96 /* Finalize a `struct auto_source_discovery`. */
97
98 void auto_source_discovery_fini(struct auto_source_discovery *auto_disc)
99 {
100 if (auto_disc->results) {
101 g_ptr_array_free(auto_disc->results, TRUE);
102 }
103 }
104
105 /* Initialize an already allocated `struct auto_source_discovery`. */
106
107 int auto_source_discovery_init(struct auto_source_discovery *auto_disc)
108 {
109 int status;
110
111 auto_disc->results = g_ptr_array_new_with_free_func(
112 (GDestroyNotify) auto_source_discovery_result_destroy);
113
114 if (!auto_disc->results) {
115 goto error;
116 }
117
118 status = 0;
119 goto end;
120
121 error:
122 auto_source_discovery_fini(auto_disc);
123 status = -1;
124
125 end:
126
127 return status;
128 }
129
130 static
131 const bt_value *borrow_array_value_last_element_const(const bt_value *array)
132 {
133 uint64_t last_index = bt_value_array_get_length(array) - 1;
134
135 return bt_value_array_borrow_element_by_index_const(array, last_index);
136 }
137
138 /*
139 * Assign `input` to source component class `source_cc_name` of plugin
140 * `plugin_name`, in the group with key `group`.
141 */
142
143 static
144 auto_source_discovery_internal_status auto_source_discovery_add(
145 struct auto_source_discovery *auto_disc,
146 const char *plugin_name,
147 const char *source_cc_name,
148 const char *group,
149 const char *input,
150 uint64_t original_input_index,
151 bt_logging_level log_level)
152 {
153 auto_source_discovery_internal_status status;
154 bt_value_array_append_element_status append_status;
155 guint len;
156 guint i;
157 struct auto_source_discovery_result *res = NULL;
158 bool append_index;
159
160 len = auto_disc->results->len;
161 i = len;
162
163 if (group) {
164 for (i = 0; i < len; i++) {
165 res = g_ptr_array_index(auto_disc->results, i);
166
167 if (strcmp(res->plugin_name, plugin_name) != 0) {
168 continue;
169 }
170
171 if (strcmp(res->source_cc_name, source_cc_name) != 0) {
172 continue;
173 }
174
175 if (g_strcmp0(res->group, group) != 0) {
176 continue;
177 }
178
179 break;
180 }
181 }
182
183 if (i == len) {
184 /* Add a new result entry. */
185 res = auto_source_discovery_result_create(plugin_name,
186 source_cc_name, group, log_level);
187 if (!res) {
188 goto error;
189 }
190
191 g_ptr_array_add(auto_disc->results, res);
192 }
193
194 append_status = bt_value_array_append_string_element(res->inputs, input);
195 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
196 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append a string value.");
197 goto error;
198 }
199
200 /*
201 * Append `original_input_index` to `original_input_indices` if not
202 * there already. We process the `inputs` array in order, so if it is
203 * present, it has to be the last element.
204 */
205 if (bt_value_array_is_empty(res->original_input_indices)) {
206 append_index = true;
207 } else {
208 const bt_value *last_index_value;
209 uint64_t last_index;
210
211 last_index_value =
212 borrow_array_value_last_element_const(res->original_input_indices);
213 last_index = bt_value_integer_unsigned_get(last_index_value);
214
215 BT_ASSERT(last_index <= original_input_index);
216
217 append_index = (last_index != original_input_index);
218 }
219
220 if (append_index) {
221 append_status = bt_value_array_append_unsigned_integer_element(
222 res->original_input_indices, original_input_index);
223
224 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
225 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append an unsigned integer value.");
226 goto error;
227 }
228 }
229
230 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK;
231 goto end;
232
233 error:
234 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
235
236 end:
237 return status;
238 }
239
240 static
241 int convert_weight_value(const bt_value *weight_value, double *weight,
242 const char *plugin_name, const char *source_cc_name,
243 const char *input, const char *input_type,
244 bt_logging_level log_level)
245 {
246 enum bt_value_type weight_value_type;
247 int status;
248
249 weight_value_type = bt_value_get_type(weight_value);
250
251 if (weight_value_type == BT_VALUE_TYPE_REAL) {
252 *weight = bt_value_real_get(weight_value);
253 } else if (weight_value_type == BT_VALUE_TYPE_SIGNED_INTEGER) {
254 /* Accept signed integer as a convenience for "return 0" or "return 1" in Python. */
255 *weight = bt_value_integer_signed_get(weight_value);
256 } else {
257 BT_LOGW("babeltrace.support-info query: unexpected type for weight: "
258 "component-class-name=source.%s.%s, input=%s, input-type=%s, "
259 "expected-entry-type=%s, actual-entry-type=%s",
260 plugin_name, source_cc_name, input, input_type,
261 bt_common_value_type_string(BT_VALUE_TYPE_REAL),
262 bt_common_value_type_string(bt_value_get_type(weight_value)));
263 goto error;
264 }
265
266 if (*weight < 0.0 || *weight > 1.0) {
267 BT_LOGW("babeltrace.support-info query: weight value is out of range [0.0, 1.0]: "
268 "component-class-name=source.%s.%s, input=%s, input-type=%s, "
269 "weight=%f",
270 plugin_name, source_cc_name, input, input_type, *weight);
271 goto error;
272 }
273
274 status = 0;
275 goto end;
276
277 error:
278 status = -1;
279
280 end:
281 return status;
282 }
283
284 static
285 bt_query_executor_query_status simple_query(const bt_component_class *comp_cls,
286 const char *obj, const bt_value *params,
287 bt_logging_level log_level, const bt_value **result)
288 {
289 bt_query_executor_query_status status;
290 bt_query_executor_set_logging_level_status set_logging_level_status;
291 bt_query_executor *query_exec;
292
293 query_exec = bt_query_executor_create(comp_cls, obj, params);
294 if (!query_exec) {
295 BT_AUTODISC_LOGE_APPEND_CAUSE("Cannot create a query executor.");
296 status = BT_QUERY_EXECUTOR_QUERY_STATUS_MEMORY_ERROR;
297 goto end;
298 }
299
300 set_logging_level_status = bt_query_executor_set_logging_level(query_exec, log_level);
301 if (set_logging_level_status != BT_QUERY_EXECUTOR_SET_LOGGING_LEVEL_STATUS_OK) {
302 BT_AUTODISC_LOGE_APPEND_CAUSE(
303 "Cannot set query executor's logging level: "
304 "log-level=%s",
305 bt_common_logging_level_string(log_level));
306 status = (int) set_logging_level_status;
307 goto end;
308 }
309
310 status = bt_query_executor_query(query_exec, result);
311
312 end:
313 bt_query_executor_put_ref(query_exec);
314
315 return status;
316 }
317
318
319 /*
320 * Query all known source components to see if any of them can handle `input`
321 * as the given `type`(arbitrary string, directory or file).
322 *
323 * If `plugin_restrict` is non-NULL, only query source component classes provided
324 * by the plugin with that name.
325 *
326 * If `component_class_restrict` is non-NULL, only query source component classes
327 * with that name.
328 */
329 static
330 auto_source_discovery_internal_status support_info_query_all_sources(
331 const char *input,
332 const char *input_type,
333 uint64_t original_input_index,
334 const bt_plugin **plugins,
335 size_t plugin_count,
336 const char *component_class_restrict,
337 enum bt_logging_level log_level,
338 struct auto_source_discovery *auto_disc,
339 const bt_interrupter *interrupter)
340 {
341 bt_value_map_insert_entry_status insert_status;
342 bt_value *query_params = NULL;
343 auto_source_discovery_internal_status status;
344 size_t i_plugins;
345 const struct bt_value *query_result = NULL;
346 struct {
347 const bt_component_class_source *source;
348 const bt_plugin *plugin;
349 const bt_value *group;
350 double weight;
351 } winner = { NULL, NULL, NULL, 0 };
352
353 if (interrupter && bt_interrupter_is_set(interrupter)) {
354 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED;
355 goto end;
356 }
357
358 query_params = bt_value_map_create();
359 if (!query_params) {
360 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a map value.");
361 goto error;
362 }
363
364 insert_status = bt_value_map_insert_string_entry(query_params, "input", input);
365 if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
366 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
367 goto error;
368 }
369
370 insert_status = bt_value_map_insert_string_entry(query_params, "type", input_type);
371 if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
372 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
373 goto error;
374 }
375
376 for (i_plugins = 0; i_plugins < plugin_count; i_plugins++) {
377 const bt_plugin *plugin;
378 const char *plugin_name;
379 uint64_t source_count;
380 uint64_t i_sources;
381
382 plugin = plugins[i_plugins];
383 plugin_name = bt_plugin_get_name(plugin);
384
385 source_count = bt_plugin_get_source_component_class_count(plugin);
386
387 for (i_sources = 0; i_sources < source_count; i_sources++) {
388 const bt_component_class_source *source_cc;
389 const bt_component_class *cc;
390 const char *source_cc_name;
391 bt_query_executor_query_status query_status;
392
393 source_cc = bt_plugin_borrow_source_component_class_by_index_const(plugin, i_sources);
394 cc = bt_component_class_source_as_component_class_const(source_cc);
395 source_cc_name = bt_component_class_get_name(cc);
396
397 /*
398 * If the search is restricted to a specific component class, only consider the
399 * component classes with that name.
400 */
401 if (component_class_restrict && strcmp(component_class_restrict, source_cc_name) != 0) {
402 continue;
403 }
404
405 BT_LOGD("babeltrace.support-info query: before: component-class-name=source.%s.%s, input=%s, "
406 "type=%s", plugin_name, source_cc_name, input, input_type);
407
408 BT_VALUE_PUT_REF_AND_RESET(query_result);
409 query_status = simple_query(cc, "babeltrace.support-info",
410 query_params, log_level, &query_result);
411
412 if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_OK) {
413 double weight;
414 const bt_value *group_value = NULL;
415 enum bt_value_type query_result_type;
416
417 BT_ASSERT(query_result);
418
419 query_result_type = bt_value_get_type(query_result);
420
421 if (query_result_type == BT_VALUE_TYPE_REAL || query_result_type == BT_VALUE_TYPE_SIGNED_INTEGER) {
422 if (convert_weight_value(query_result, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) {
423 /* convert_weight_value has already warned. */
424 continue;
425 }
426 } else if (query_result_type == BT_VALUE_TYPE_MAP) {
427 const bt_value *weight_value;
428
429 if (!bt_value_map_has_entry(query_result, "weight")) {
430 BT_LOGW("babeltrace.support-info query: result is missing `weight` entry: "
431 "component-class-name=source.%s.%s, input=%s, input-type=%s",
432 bt_plugin_get_name(plugin),
433 bt_component_class_get_name(cc), input,
434 input_type);
435 continue;
436 }
437
438 weight_value = bt_value_map_borrow_entry_value_const(query_result, "weight");
439 BT_ASSERT(weight_value);
440
441 if (convert_weight_value(weight_value, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) {
442 /* convert_weight_value has already warned. */
443 continue;
444 }
445
446 if (bt_value_map_has_entry(query_result, "group")) {
447 group_value = bt_value_map_borrow_entry_value_const(query_result, "group");
448 BT_ASSERT(group_value);
449
450 if (bt_value_get_type(group_value) != BT_VALUE_TYPE_STRING) {
451 BT_LOGW("babeltrace.support-info query: unexpected type for entry `group`: "
452 "component-class-name=source.%s.%s, input=%s, input-type=%s, "
453 "expected-entry-type=%s,%s, actual-entry-type=%s",
454 bt_plugin_get_name(plugin),
455 bt_component_class_get_name(cc), input,
456 input_type,
457 bt_common_value_type_string(BT_VALUE_TYPE_NULL),
458 bt_common_value_type_string(BT_VALUE_TYPE_STRING),
459 bt_common_value_type_string(bt_value_get_type(group_value)));
460 continue;
461 }
462 }
463 } else {
464 BT_LOGW("babeltrace.support-info query: unexpected result type: "
465 "component-class-name=source.%s.%s, input=%s, input-type=%s, "
466 "expected-types=%s,%s,%s, actual-type=%s",
467 bt_plugin_get_name(plugin),
468 bt_component_class_get_name(cc), input,
469 input_type,
470 bt_common_value_type_string(BT_VALUE_TYPE_REAL),
471 bt_common_value_type_string(BT_VALUE_TYPE_MAP),
472 bt_common_value_type_string(BT_VALUE_TYPE_SIGNED_INTEGER),
473 bt_common_value_type_string(bt_value_get_type(query_result)));
474 continue;
475 }
476
477 BT_LOGD("babeltrace.support-info query: success: component-class-name=source.%s.%s, input=%s, "
478 "type=%s, weight=%f, group=%s\n",
479 bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
480 input_type, weight, group_value ? bt_value_string_get(group_value) : "(none)");
481
482 if (weight > winner.weight) {
483 winner.source = source_cc;
484 winner.plugin = plugin;
485
486 bt_value_put_ref(winner.group);
487 winner.group = group_value;
488 bt_value_get_ref(winner.group);
489
490 winner.weight = weight;
491 }
492 } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_ERROR) {
493 BT_AUTODISC_LOGE_APPEND_CAUSE("babeltrace.support-info query failed.");
494 goto error;
495 } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_MEMORY_ERROR) {
496 BT_AUTODISC_LOGE_APPEND_CAUSE("Memory error.");
497 goto error;
498 } else {
499 BT_LOGD("babeltrace.support-info query: failure: component-class-name=source.%s.%s, input=%s, "
500 "type=%s, status=%s\n",
501 bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
502 input_type,
503 bt_common_func_status_string(query_status));
504 }
505 }
506 }
507
508 if (winner.source) {
509 const char *source_name;
510 const char *plugin_name;
511 const char *group;
512
513 source_name = bt_component_class_get_name(
514 bt_component_class_source_as_component_class_const(winner.source));
515 plugin_name = bt_plugin_get_name(winner.plugin);
516 group = winner.group ? bt_value_string_get(winner.group) : NULL;
517
518 BT_LOGI("Input awarded: input=%s, type=%s, component-class-name=source.%s.%s, weight=%f, group=%s",
519 input, input_type, plugin_name, source_name, winner.weight, group ? group : "(none)");
520
521 status = auto_source_discovery_add(auto_disc, plugin_name,
522 source_name, group, input, original_input_index, log_level);
523 if (status != AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
524 goto error;
525 }
526 } else {
527 BT_LOGI("Input not recognized: input=%s, type=%s",
528 input, input_type);
529 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
530 }
531
532 goto end;
533
534 error:
535 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
536
537 end:
538 bt_value_put_ref(query_result);
539 bt_value_put_ref(query_params);
540 bt_value_put_ref(winner.group);
541
542 return status;
543 }
544
545 /*
546 * Look for a source component class that recognizes `input` as an arbitrary
547 * string.
548 *
549 * Same return value semantic as `support_info_query_all_sources`.
550 */
551
552 static
553 auto_source_discovery_internal_status auto_discover_source_for_input_as_string(
554 const char *input,
555 uint64_t original_input_index,
556 const bt_plugin **plugins,
557 size_t plugin_count,
558 const char *component_class_restrict,
559 enum bt_logging_level log_level,
560 struct auto_source_discovery *auto_disc,
561 const bt_interrupter *interrupter)
562 {
563 return support_info_query_all_sources(input, "string",
564 original_input_index, plugins, plugin_count,
565 component_class_restrict, log_level, auto_disc,
566 interrupter);
567 }
568
569 static
570 auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file_rec(
571 GString *input,
572 uint64_t original_input_index,
573 const bt_plugin **plugins,
574 size_t plugin_count,
575 const char *component_class_restrict,
576 enum bt_logging_level log_level,
577 struct auto_source_discovery *auto_disc,
578 const bt_interrupter *interrupter)
579 {
580 auto_source_discovery_internal_status status;
581 GError *error = NULL;
582 GDir *dir = NULL;
583
584 if (g_file_test(input->str, G_FILE_TEST_IS_REGULAR)) {
585 /* It's a file. */
586 status = support_info_query_all_sources(input->str,
587 "file", original_input_index, plugins, plugin_count,
588 component_class_restrict, log_level, auto_disc,
589 interrupter);
590 } else if (g_file_test(input->str, G_FILE_TEST_IS_DIR)) {
591 const gchar *dirent;
592 gsize saved_input_len;
593 int dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
594
595 /* It's a directory. */
596 status = support_info_query_all_sources(input->str,
597 "directory", original_input_index, plugins,
598 plugin_count, component_class_restrict, log_level,
599 auto_disc, interrupter);
600
601 if (status < 0) {
602 /* Fatal error. */
603 goto error;
604 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK ||
605 status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
606 /*
607 * A component class claimed this input as a directory,
608 * don't recurse. Or, we got interrupted.
609 */
610 goto end;
611 }
612
613 dir = g_dir_open(input->str, 0, &error);
614 if (!dir) {
615 #define BT_FMT "Failed to open directory %s: %s"
616 BT_LOGW(BT_FMT, input->str, error->message);
617
618 if (error->code == G_FILE_ERROR_ACCES) {
619 /* This is not a fatal error, we just skip it. */
620 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
621 goto end;
622 } else {
623 BT_AUTODISC_LOGE_APPEND_CAUSE(BT_FMT, input->str,
624 error->message);
625 goto error;
626 }
627 #undef BT_FMT
628 }
629
630 saved_input_len = input->len;
631
632 do {
633 errno = 0;
634 dirent = g_dir_read_name(dir);
635 if (dirent) {
636 g_string_append_c_inline(input, G_DIR_SEPARATOR);
637 g_string_append(input, dirent);
638
639 status = auto_discover_source_for_input_as_dir_or_file_rec(
640 input, original_input_index, plugins, plugin_count,
641 component_class_restrict, log_level, auto_disc,
642 interrupter);
643
644 g_string_truncate(input, saved_input_len);
645
646 if (status < 0) {
647 /* Fatal error. */
648 goto error;
649 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
650 goto end;
651 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
652 dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK;
653 }
654 } else if (errno != 0) {
655 BT_LOGW_ERRNO("Failed to read directory entry", ": dir=%s", input->str);
656 goto error;
657 }
658 } while (dirent);
659
660 status = dir_status;
661 } else {
662 BT_LOGD("Skipping %s, not a file or directory", input->str);
663 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
664 }
665
666 goto end;
667
668 error:
669 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
670
671 end:
672 if (dir) {
673 g_dir_close(dir);
674 }
675
676 if (error) {
677 g_error_free(error);
678 }
679
680 return status;
681 }
682
683 /*
684 * Look for a source component class that recognizes `input` as a directory or
685 * file. If `input` is a directory and is not directly recognized, recurse and
686 * apply the same logic to children nodes.
687 *
688 * Same return value semantic as `support_info_query_all_sources`.
689 */
690
691 static
692 auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file(
693 const char *input,
694 uint64_t original_input_index,
695 const bt_plugin **plugins,
696 size_t plugin_count,
697 const char *component_class_restrict,
698 enum bt_logging_level log_level,
699 struct auto_source_discovery *auto_disc,
700 const bt_interrupter *interrupter)
701 {
702 GString *mutable_input;
703 auto_source_discovery_internal_status status;
704
705 mutable_input = g_string_new(input);
706 if (!mutable_input) {
707 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
708 goto end;
709 }
710
711 status = auto_discover_source_for_input_as_dir_or_file_rec(
712 mutable_input, original_input_index, plugins, plugin_count,
713 component_class_restrict, log_level, auto_disc,
714 interrupter);
715
716 g_string_free(mutable_input, TRUE);
717 end:
718 return status;
719 }
720
721 auto_source_discovery_status auto_discover_source_components(
722 const bt_value *inputs,
723 const bt_plugin **plugins,
724 size_t plugin_count,
725 const char *component_class_restrict,
726 enum bt_logging_level log_level,
727 struct auto_source_discovery *auto_disc,
728 const bt_interrupter *interrupter)
729 {
730 uint64_t i_inputs, input_count;
731 auto_source_discovery_internal_status internal_status;
732 auto_source_discovery_status status;
733
734 input_count = bt_value_array_get_length(inputs);
735
736 for (i_inputs = 0; i_inputs < input_count; i_inputs++) {
737 const bt_value *input_value;
738 const char *input;
739
740 input_value = bt_value_array_borrow_element_by_index_const(inputs, i_inputs);
741 input = bt_value_string_get(input_value);
742 internal_status = auto_discover_source_for_input_as_string(input, i_inputs,
743 plugins, plugin_count, component_class_restrict,
744 log_level, auto_disc, interrupter);
745 if (internal_status < 0 || internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
746 /* Fatal error or we got interrupted. */
747 status = (auto_source_discovery_status) internal_status;
748 goto end;
749 } else if (internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
750 /* A component class has claimed this input as an arbitrary string. */
751 continue;
752 }
753
754 internal_status = auto_discover_source_for_input_as_dir_or_file(input,
755 i_inputs, plugins, plugin_count,
756 component_class_restrict, log_level, auto_disc, interrupter);
757 if (internal_status < 0 || internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
758 /* Fatal error or we got interrupted. */
759 status = (auto_source_discovery_status) internal_status;
760 goto end;
761 } else if (internal_status == 0) {
762 /*
763 * This input (or something under it) was recognized.
764 */
765 continue;
766 }
767
768 BT_LOGW("No trace was found based on input `%s`.", input);
769 }
770
771 status = AUTO_SOURCE_DISCOVERY_STATUS_OK;
772 end:
773 return status;
774 }
This page took 0.043776 seconds and 5 git commands to generate.