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