Move to kernel style SPDX license identifiers
[babeltrace.git] / src / autodisc / autodisc.c
CommitLineData
73760435 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
73760435 3 *
0235b0db 4 * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation
73760435
SM
5 */
6
7#define BT_LOG_TAG "CLI-CFG-SRC-AUTO-DISC"
97010665
SM
8#define BT_LOG_OUTPUT_LEVEL log_level
9#include "logging/log.h"
73760435 10
c4f23e30
FD
11#include <stdbool.h>
12
97010665 13#include "autodisc.h"
73760435
SM
14#include "common/common.h"
15
97010665
SM
16#define BT_AUTODISC_LOG_AND_APPEND(_lvl, _fmt, ...) \
17 do { \
18 BT_LOG_WRITE(_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
3dae1685
SM
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 */
30typedef 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
73760435
SM
38/* Finalize and free a `struct auto_source_discovery_result`. */
39
40static
41void 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);
45bab744 46 bt_value_put_ref(res->original_input_indices);
73760435
SM
47 g_free(res);
48 }
49}
50
51/* Allocate and initialize a `struct auto_source_discovery_result`. */
52
53static
54struct auto_source_discovery_result *auto_source_discovery_result_create(
55 const char *plugin_name, const char *source_cc_name,
97010665 56 const char *group, bt_logging_level log_level)
73760435
SM
57{
58 struct auto_source_discovery_result *res;
59
60 res = g_new0(struct auto_source_discovery_result, 1);
61 if (!res) {
97010665 62 BT_AUTODISC_LOGE_APPEND_CAUSE(
73760435
SM
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) {
97010665 71 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a string.");
73760435
SM
72 goto error;
73 }
74
75 res->inputs = bt_value_array_create();
76 if (!res->inputs) {
97010665 77 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
73760435
SM
78 goto error;
79 }
80
1ead9076
SM
81 res->original_input_indices = bt_value_array_create();
82 if (!res->original_input_indices) {
97010665 83 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
1ead9076
SM
84 goto error;
85 }
86
73760435
SM
87 goto end;
88error:
89 auto_source_discovery_result_destroy(res);
cc611878 90 res = NULL;
73760435
SM
91
92end:
93 return res;
94}
95
96/* Finalize a `struct auto_source_discovery`. */
97
98void 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
107int 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
121error:
122 auto_source_discovery_fini(auto_disc);
123 status = -1;
124
125end:
126
127 return status;
128}
129
1ead9076
SM
130static
131const bt_value *borrow_array_value_last_element_const(const bt_value *array)
132{
393729a6 133 uint64_t last_index = bt_value_array_get_length(array) - 1;
1ead9076
SM
134
135 return bt_value_array_borrow_element_by_index_const(array, last_index);
136}
137
73760435
SM
138/*
139 * Assign `input` to source component class `source_cc_name` of plugin
140 * `plugin_name`, in the group with key `group`.
141 */
142
143static
3dae1685
SM
144auto_source_discovery_internal_status auto_source_discovery_add(
145 struct auto_source_discovery *auto_disc,
73760435
SM
146 const char *plugin_name,
147 const char *source_cc_name,
148 const char *group,
1ead9076 149 const char *input,
97010665
SM
150 uint64_t original_input_index,
151 bt_logging_level log_level)
73760435 152{
3dae1685 153 auto_source_discovery_internal_status status;
73760435
SM
154 bt_value_array_append_element_status append_status;
155 guint len;
156 guint i;
157 struct auto_source_discovery_result *res = NULL;
1ead9076 158 bool append_index;
73760435
SM
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,
97010665 186 source_cc_name, group, log_level);
73760435
SM
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) {
97010665 196 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append a string value.");
73760435
SM
197 goto error;
198 }
199
1ead9076
SM
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) {
97010665 225 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append an unsigned integer value.");
1ead9076
SM
226 goto error;
227 }
228 }
73760435 229
3dae1685 230 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK;
73760435
SM
231 goto end;
232
233error:
3dae1685 234 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
73760435
SM
235
236end:
237 return status;
238}
239
240static
241int convert_weight_value(const bt_value *weight_value, double *weight,
242 const char *plugin_name, const char *source_cc_name,
97010665
SM
243 const char *input, const char *input_type,
244 bt_logging_level log_level)
73760435
SM
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 {
1a29b831 257 BT_LOGW("babeltrace.support-info query: unexpected type for weight: "
73760435
SM
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) {
1a29b831 267 BT_LOGW("babeltrace.support-info query: weight value is out of range [0.0, 1.0]: "
73760435
SM
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
277error:
278 status = -1;
279
280end:
281 return status;
282}
283
97010665
SM
284static
285bt_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
312end:
313 bt_query_executor_put_ref(query_exec);
314
315 return status;
316}
317
318
73760435
SM
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.
73760435
SM
328 */
329static
3dae1685
SM
330auto_source_discovery_internal_status support_info_query_all_sources(
331 const char *input,
1ead9076
SM
332 const char *input_type,
333 uint64_t original_input_index,
97010665 334 const bt_plugin **plugins,
1ead9076 335 size_t plugin_count,
73760435
SM
336 const char *component_class_restrict,
337 enum bt_logging_level log_level,
3dae1685
SM
338 struct auto_source_discovery *auto_disc,
339 const bt_interrupter *interrupter)
73760435
SM
340{
341 bt_value_map_insert_entry_status insert_status;
342 bt_value *query_params = NULL;
3dae1685 343 auto_source_discovery_internal_status status;
73760435
SM
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 weigth;
351 } winner = { NULL, NULL, NULL, 0 };
352
3dae1685
SM
353 if (interrupter && bt_interrupter_is_set(interrupter)) {
354 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED;
355 goto end;
356 }
357
73760435
SM
358 query_params = bt_value_map_create();
359 if (!query_params) {
97010665 360 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a map value.");
73760435
SM
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) {
97010665 366 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
73760435
SM
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) {
97010665 372 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
73760435
SM
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
97010665 382 plugin = plugins[i_plugins];
73760435
SM
383 plugin_name = bt_plugin_get_name(plugin);
384
73760435
SM
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
1a29b831 405 BT_LOGD("babeltrace.support-info query: before: component-class-name=source.%s.%s, input=%s, "
73760435
SM
406 "type=%s", plugin_name, source_cc_name, input, input_type);
407
408 BT_VALUE_PUT_REF_AND_RESET(query_result);
97010665
SM
409 query_status = simple_query(cc, "babeltrace.support-info",
410 query_params, log_level, &query_result);
73760435
SM
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) {
97010665 422 if (convert_weight_value(query_result, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) {
73760435
SM
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")) {
1a29b831 430 BT_LOGW("babeltrace.support-info query: result is missing `weight` entry: "
73760435
SM
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
97010665 441 if (convert_weight_value(weight_value, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) {
73760435
SM
442 /* convert_weight_value has already warned. */
443 continue;
444 }
445
446 if (bt_value_map_has_entry(query_result, "group")) {
73760435
SM
447 group_value = bt_value_map_borrow_entry_value_const(query_result, "group");
448 BT_ASSERT(group_value);
449
282a37f5 450 if (bt_value_get_type(group_value) != BT_VALUE_TYPE_STRING) {
1a29b831 451 BT_LOGW("babeltrace.support-info query: unexpected type for entry `group`: "
73760435
SM
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 {
1a29b831 464 BT_LOGW("babeltrace.support-info query: unexpected result type: "
73760435
SM
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
1a29b831 477 BT_LOGD("babeltrace.support-info query: success: component-class-name=source.%s.%s, input=%s, "
61de0522 478 "type=%s, weight=%f, group=%s\n",
73760435 479 bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
61de0522 480 input_type, weight, group_value ? bt_value_string_get(group_value) : "(none)");
73760435
SM
481
482 if (weight > winner.weigth) {
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.weigth = weight;
491 }
492 } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_ERROR) {
97010665 493 BT_AUTODISC_LOGE_APPEND_CAUSE("babeltrace.support-info query failed.");
73760435
SM
494 goto error;
495 } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_MEMORY_ERROR) {
97010665 496 BT_AUTODISC_LOGE_APPEND_CAUSE("Memory error.");
73760435
SM
497 goto error;
498 } else {
1a29b831 499 BT_LOGD("babeltrace.support-info query: failure: component-class-name=source.%s.%s, input=%s, "
73760435
SM
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
61de0522
SM
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.weigth, group ? group : "(none)");
73760435 520
1ead9076 521 status = auto_source_discovery_add(auto_disc, plugin_name,
97010665 522 source_name, group, input, original_input_index, log_level);
3dae1685 523 if (status != AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
73760435
SM
524 goto error;
525 }
526 } else {
61de0522 527 BT_LOGI("Input not recognized: input=%s, type=%s",
73760435 528 input, input_type);
3dae1685 529 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
73760435
SM
530 }
531
532 goto end;
533
534error:
3dae1685 535 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
73760435
SM
536
537end:
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
552static
3dae1685
SM
553auto_source_discovery_internal_status auto_discover_source_for_input_as_string(
554 const char *input,
1ead9076 555 uint64_t original_input_index,
97010665
SM
556 const bt_plugin **plugins,
557 size_t plugin_count,
73760435
SM
558 const char *component_class_restrict,
559 enum bt_logging_level log_level,
3dae1685
SM
560 struct auto_source_discovery *auto_disc,
561 const bt_interrupter *interrupter)
73760435
SM
562{
563 return support_info_query_all_sources(input, "string",
97010665 564 original_input_index, plugins, plugin_count,
3dae1685
SM
565 component_class_restrict, log_level, auto_disc,
566 interrupter);
73760435
SM
567}
568
569static
3dae1685
SM
570auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file_rec(
571 GString *input,
1ead9076 572 uint64_t original_input_index,
97010665
SM
573 const bt_plugin **plugins,
574 size_t plugin_count,
73760435
SM
575 const char *component_class_restrict,
576 enum bt_logging_level log_level,
3dae1685
SM
577 struct auto_source_discovery *auto_disc,
578 const bt_interrupter *interrupter)
73760435 579{
3dae1685 580 auto_source_discovery_internal_status status;
73760435
SM
581 GError *error = NULL;
582
583 if (g_file_test(input->str, G_FILE_TEST_IS_REGULAR)) {
584 /* It's a file. */
585 status = support_info_query_all_sources(input->str,
97010665 586 "file", original_input_index, plugins, plugin_count,
3dae1685
SM
587 component_class_restrict, log_level, auto_disc,
588 interrupter);
73760435
SM
589 } else if (g_file_test(input->str, G_FILE_TEST_IS_DIR)) {
590 GDir *dir;
591 const gchar *dirent;
592 gsize saved_input_len;
3dae1685 593 int dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
73760435
SM
594
595 /* It's a directory. */
596 status = support_info_query_all_sources(input->str,
97010665
SM
597 "directory", original_input_index, plugins,
598 plugin_count, component_class_restrict, log_level,
3dae1685 599 auto_disc, interrupter);
73760435
SM
600
601 if (status < 0) {
602 /* Fatal error. */
603 goto error;
3dae1685
SM
604 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK ||
605 status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
73760435
SM
606 /*
607 * A component class claimed this input as a directory,
3dae1685 608 * don't recurse. Or, we got interrupted.
73760435
SM
609 */
610 goto end;
611 }
612
613 dir = g_dir_open(input->str, 0, &error);
614 if (!dir) {
615 const char *fmt = "Failed to open directory %s: %s";
616 BT_LOGW(fmt, input->str, error->message);
617
d847ef86 618 if (error->code == G_FILE_ERROR_ACCES) {
73760435 619 /* This is not a fatal error, we just skip it. */
3dae1685 620 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
73760435
SM
621 goto end;
622 } else {
97010665 623 BT_AUTODISC_LOGE_APPEND_CAUSE(fmt, input->str,
73760435
SM
624 error->message);
625 goto error;
626 }
627 }
628
629 saved_input_len = input->len;
630
631 do {
632 errno = 0;
633 dirent = g_dir_read_name(dir);
634 if (dirent) {
635 g_string_append_c_inline(input, G_DIR_SEPARATOR);
636 g_string_append(input, dirent);
637
638 status = auto_discover_source_for_input_as_dir_or_file_rec(
97010665 639 input, original_input_index, plugins, plugin_count,
3dae1685
SM
640 component_class_restrict, log_level, auto_disc,
641 interrupter);
73760435
SM
642
643 g_string_truncate(input, saved_input_len);
644
645 if (status < 0) {
646 /* Fatal error. */
647 goto error;
3dae1685
SM
648 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
649 goto end;
650 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
651 dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK;
73760435
SM
652 }
653 } else if (errno != 0) {
654 BT_LOGW_ERRNO("Failed to read directory entry", ": dir=%s", input->str);
655 goto error;
656 }
5084732e 657 } while (dirent);
73760435
SM
658
659 status = dir_status;
660
661 g_dir_close(dir);
662 } else {
663 BT_LOGD("Skipping %s, not a file or directory", input->str);
3dae1685 664 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
73760435
SM
665 }
666
667 goto end;
668
669error:
3dae1685 670 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
73760435
SM
671
672end:
673
674 if (error) {
675 g_error_free(error);
676 }
677
678 return status;
679}
680
681/*
682 * Look for a source component class that recognizes `input` as a directory or
683 * file. If `input` is a directory and is not directly recognized, recurse and
684 * apply the same logic to children nodes.
685 *
686 * Same return value semantic as `support_info_query_all_sources`.
687 */
688
689static
3dae1685
SM
690auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file(
691 const char *input,
1ead9076 692 uint64_t original_input_index,
97010665
SM
693 const bt_plugin **plugins,
694 size_t plugin_count,
73760435
SM
695 const char *component_class_restrict,
696 enum bt_logging_level log_level,
3dae1685
SM
697 struct auto_source_discovery *auto_disc,
698 const bt_interrupter *interrupter)
73760435
SM
699{
700 GString *mutable_input;
3dae1685 701 auto_source_discovery_internal_status status;
73760435
SM
702
703 mutable_input = g_string_new(input);
704 if (!mutable_input) {
3dae1685 705 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
73760435
SM
706 goto end;
707 }
708
709 status = auto_discover_source_for_input_as_dir_or_file_rec(
97010665 710 mutable_input, original_input_index, plugins, plugin_count,
3dae1685
SM
711 component_class_restrict, log_level, auto_disc,
712 interrupter);
73760435
SM
713
714 g_string_free(mutable_input, TRUE);
715end:
716 return status;
717}
718
3dae1685 719auto_source_discovery_status auto_discover_source_components(
73760435 720 const bt_value *inputs,
97010665
SM
721 const bt_plugin **plugins,
722 size_t plugin_count,
73760435
SM
723 const char *component_class_restrict,
724 enum bt_logging_level log_level,
3dae1685
SM
725 struct auto_source_discovery *auto_disc,
726 const bt_interrupter *interrupter)
73760435
SM
727{
728 uint64_t i_inputs, input_count;
3dae1685
SM
729 auto_source_discovery_internal_status internal_status;
730 auto_source_discovery_status status;
73760435 731
393729a6 732 input_count = bt_value_array_get_length(inputs);
73760435 733
73760435
SM
734 for (i_inputs = 0; i_inputs < input_count; i_inputs++) {
735 const bt_value *input_value;
736 const char *input;
737
738 input_value = bt_value_array_borrow_element_by_index_const(inputs, i_inputs);
739 input = bt_value_string_get(input_value);
3dae1685 740 internal_status = auto_discover_source_for_input_as_string(input, i_inputs,
97010665 741 plugins, plugin_count, component_class_restrict,
3dae1685
SM
742 log_level, auto_disc, interrupter);
743 if (internal_status < 0 || internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
744 /* Fatal error or we got interrupted. */
764d8fd9 745 status = (auto_source_discovery_status) internal_status;
73760435 746 goto end;
3dae1685 747 } else if (internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
73760435
SM
748 /* A component class has claimed this input as an arbitrary string. */
749 continue;
750 }
751
3dae1685 752 internal_status = auto_discover_source_for_input_as_dir_or_file(input,
97010665 753 i_inputs, plugins, plugin_count,
3dae1685
SM
754 component_class_restrict, log_level, auto_disc, interrupter);
755 if (internal_status < 0 || internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
756 /* Fatal error or we got interrupted. */
764d8fd9 757 status = (auto_source_discovery_status) internal_status;
73760435 758 goto end;
3dae1685 759 } else if (internal_status == 0) {
73760435
SM
760 /*
761 * This input (or something under it) was recognized.
762 */
763 continue;
764 }
765
766 BT_LOGW("No trace was found based on input `%s`.", input);
767 }
768
3dae1685 769 status = AUTO_SOURCE_DISCOVERY_STATUS_OK;
73760435 770end:
73760435
SM
771 return status;
772}
This page took 0.082018 seconds and 4 git commands to generate.