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