autodisc: cast when assigning to different enum type
[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 "autodisc.h"
28 #include "common/common.h"
29
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
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 */
44 typedef 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
52 /* Finalize and free a `struct auto_source_discovery_result`. */
53
54 static
55 void 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);
60 bt_value_put_ref(res->original_input_indices);
61 g_free(res);
62 }
63 }
64
65 /* Allocate and initialize a `struct auto_source_discovery_result`. */
66
67 static
68 struct auto_source_discovery_result *auto_source_discovery_result_create(
69 const char *plugin_name, const char *source_cc_name,
70 const char *group, bt_logging_level log_level)
71 {
72 struct auto_source_discovery_result *res;
73
74 res = g_new0(struct auto_source_discovery_result, 1);
75 if (!res) {
76 BT_AUTODISC_LOGE_APPEND_CAUSE(
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) {
85 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a string.");
86 goto error;
87 }
88
89 res->inputs = bt_value_array_create();
90 if (!res->inputs) {
91 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
92 goto error;
93 }
94
95 res->original_input_indices = bt_value_array_create();
96 if (!res->original_input_indices) {
97 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
98 goto error;
99 }
100
101 goto end;
102 error:
103 auto_source_discovery_result_destroy(res);
104 res = NULL;
105
106 end:
107 return res;
108 }
109
110 /* Finalize a `struct auto_source_discovery`. */
111
112 void 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
121 int 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
135 error:
136 auto_source_discovery_fini(auto_disc);
137 status = -1;
138
139 end:
140
141 return status;
142 }
143
144 static
145 const bt_value *borrow_array_value_last_element_const(const bt_value *array)
146 {
147 uint64_t last_index = bt_value_array_get_length(array) - 1;
148
149 return bt_value_array_borrow_element_by_index_const(array, last_index);
150 }
151
152 /*
153 * Assign `input` to source component class `source_cc_name` of plugin
154 * `plugin_name`, in the group with key `group`.
155 */
156
157 static
158 auto_source_discovery_internal_status auto_source_discovery_add(
159 struct auto_source_discovery *auto_disc,
160 const char *plugin_name,
161 const char *source_cc_name,
162 const char *group,
163 const char *input,
164 uint64_t original_input_index,
165 bt_logging_level log_level)
166 {
167 auto_source_discovery_internal_status status;
168 bt_value_array_append_element_status append_status;
169 guint len;
170 guint i;
171 struct auto_source_discovery_result *res = NULL;
172 bool append_index;
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,
200 source_cc_name, group, log_level);
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) {
210 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append a string value.");
211 goto error;
212 }
213
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) {
239 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append an unsigned integer value.");
240 goto error;
241 }
242 }
243
244 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK;
245 goto end;
246
247 error:
248 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
249
250 end:
251 return status;
252 }
253
254 static
255 int convert_weight_value(const bt_value *weight_value, double *weight,
256 const char *plugin_name, const char *source_cc_name,
257 const char *input, const char *input_type,
258 bt_logging_level log_level)
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 {
271 BT_LOGW("babeltrace.support-info query: unexpected type for weight: "
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) {
281 BT_LOGW("babeltrace.support-info query: weight value is out of range [0.0, 1.0]: "
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
291 error:
292 status = -1;
293
294 end:
295 return status;
296 }
297
298 static
299 bt_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
326 end:
327 bt_query_executor_put_ref(query_exec);
328
329 return status;
330 }
331
332
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.
342 */
343 static
344 auto_source_discovery_internal_status support_info_query_all_sources(
345 const char *input,
346 const char *input_type,
347 uint64_t original_input_index,
348 const bt_plugin **plugins,
349 size_t plugin_count,
350 const char *component_class_restrict,
351 enum bt_logging_level log_level,
352 struct auto_source_discovery *auto_disc,
353 const bt_interrupter *interrupter)
354 {
355 bt_value_map_insert_entry_status insert_status;
356 bt_value *query_params = NULL;
357 auto_source_discovery_internal_status status;
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
367 if (interrupter && bt_interrupter_is_set(interrupter)) {
368 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED;
369 goto end;
370 }
371
372 query_params = bt_value_map_create();
373 if (!query_params) {
374 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a map value.");
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) {
380 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
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) {
386 BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
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
396 plugin = plugins[i_plugins];
397 plugin_name = bt_plugin_get_name(plugin);
398
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
419 BT_LOGD("babeltrace.support-info query: before: component-class-name=source.%s.%s, input=%s, "
420 "type=%s", plugin_name, source_cc_name, input, input_type);
421
422 BT_VALUE_PUT_REF_AND_RESET(query_result);
423 query_status = simple_query(cc, "babeltrace.support-info",
424 query_params, log_level, &query_result);
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) {
436 if (convert_weight_value(query_result, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) {
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")) {
444 BT_LOGW("babeltrace.support-info query: result is missing `weight` entry: "
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
455 if (convert_weight_value(weight_value, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) {
456 /* convert_weight_value has already warned. */
457 continue;
458 }
459
460 if (bt_value_map_has_entry(query_result, "group")) {
461 enum bt_value_type group_value_type;
462
463 group_value = bt_value_map_borrow_entry_value_const(query_result, "group");
464 BT_ASSERT(group_value);
465
466 group_value_type = bt_value_get_type(group_value);
467
468 if (group_value_type == BT_VALUE_TYPE_NULL) {
469 /* Do as if no value was passed. */
470 group_value = NULL;
471 } else if (bt_value_get_type(group_value) != BT_VALUE_TYPE_STRING) {
472 BT_LOGW("babeltrace.support-info query: unexpected type for entry `group`: "
473 "component-class-name=source.%s.%s, input=%s, input-type=%s, "
474 "expected-entry-type=%s,%s, actual-entry-type=%s",
475 bt_plugin_get_name(plugin),
476 bt_component_class_get_name(cc), input,
477 input_type,
478 bt_common_value_type_string(BT_VALUE_TYPE_NULL),
479 bt_common_value_type_string(BT_VALUE_TYPE_STRING),
480 bt_common_value_type_string(bt_value_get_type(group_value)));
481 continue;
482 }
483 }
484 } else {
485 BT_LOGW("babeltrace.support-info query: unexpected result type: "
486 "component-class-name=source.%s.%s, input=%s, input-type=%s, "
487 "expected-types=%s,%s,%s, actual-type=%s",
488 bt_plugin_get_name(plugin),
489 bt_component_class_get_name(cc), input,
490 input_type,
491 bt_common_value_type_string(BT_VALUE_TYPE_REAL),
492 bt_common_value_type_string(BT_VALUE_TYPE_MAP),
493 bt_common_value_type_string(BT_VALUE_TYPE_SIGNED_INTEGER),
494 bt_common_value_type_string(bt_value_get_type(query_result)));
495 continue;
496 }
497
498 BT_LOGD("babeltrace.support-info query: success: component-class-name=source.%s.%s, input=%s, "
499 "type=%s, weight=%f\n",
500 bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
501 input_type, weight);
502
503 if (weight > winner.weigth) {
504 winner.source = source_cc;
505 winner.plugin = plugin;
506
507 bt_value_put_ref(winner.group);
508 winner.group = group_value;
509 bt_value_get_ref(winner.group);
510
511 winner.weigth = weight;
512 }
513 } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_ERROR) {
514 BT_AUTODISC_LOGE_APPEND_CAUSE("babeltrace.support-info query failed.");
515 goto error;
516 } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_MEMORY_ERROR) {
517 BT_AUTODISC_LOGE_APPEND_CAUSE("Memory error.");
518 goto error;
519 } else {
520 BT_LOGD("babeltrace.support-info query: failure: component-class-name=source.%s.%s, input=%s, "
521 "type=%s, status=%s\n",
522 bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
523 input_type,
524 bt_common_func_status_string(query_status));
525 }
526 }
527 }
528
529 if (winner.source) {
530 const char *source_name;
531 const char *plugin_name;
532 const char *group;
533
534 source_name = bt_component_class_get_name(
535 bt_component_class_source_as_component_class_const(winner.source));
536 plugin_name = bt_plugin_get_name(winner.plugin);
537 group = winner.group ? bt_value_string_get(winner.group) : NULL;
538
539 BT_LOGI("Input %s is awarded to component class source.%s.%s with weight %f",
540 input, plugin_name, source_name, winner.weigth);
541
542 status = auto_source_discovery_add(auto_disc, plugin_name,
543 source_name, group, input, original_input_index, log_level);
544 if (status != AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
545 goto error;
546 }
547 } else {
548 BT_LOGI("Input %s (%s) was not recognized by any source component class.",
549 input, input_type);
550 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
551 }
552
553 goto end;
554
555 error:
556 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
557
558 end:
559 bt_value_put_ref(query_result);
560 bt_value_put_ref(query_params);
561 bt_value_put_ref(winner.group);
562
563 return status;
564 }
565
566 /*
567 * Look for a source component class that recognizes `input` as an arbitrary
568 * string.
569 *
570 * Same return value semantic as `support_info_query_all_sources`.
571 */
572
573 static
574 auto_source_discovery_internal_status auto_discover_source_for_input_as_string(
575 const char *input,
576 uint64_t original_input_index,
577 const bt_plugin **plugins,
578 size_t plugin_count,
579 const char *component_class_restrict,
580 enum bt_logging_level log_level,
581 struct auto_source_discovery *auto_disc,
582 const bt_interrupter *interrupter)
583 {
584 return support_info_query_all_sources(input, "string",
585 original_input_index, plugins, plugin_count,
586 component_class_restrict, log_level, auto_disc,
587 interrupter);
588 }
589
590 static
591 auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file_rec(
592 GString *input,
593 uint64_t original_input_index,
594 const bt_plugin **plugins,
595 size_t plugin_count,
596 const char *component_class_restrict,
597 enum bt_logging_level log_level,
598 struct auto_source_discovery *auto_disc,
599 const bt_interrupter *interrupter)
600 {
601 auto_source_discovery_internal_status status;
602 GError *error = NULL;
603
604 if (g_file_test(input->str, G_FILE_TEST_IS_REGULAR)) {
605 /* It's a file. */
606 status = support_info_query_all_sources(input->str,
607 "file", original_input_index, plugins, plugin_count,
608 component_class_restrict, log_level, auto_disc,
609 interrupter);
610 } else if (g_file_test(input->str, G_FILE_TEST_IS_DIR)) {
611 GDir *dir;
612 const gchar *dirent;
613 gsize saved_input_len;
614 int dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
615
616 /* It's a directory. */
617 status = support_info_query_all_sources(input->str,
618 "directory", original_input_index, plugins,
619 plugin_count, component_class_restrict, log_level,
620 auto_disc, interrupter);
621
622 if (status < 0) {
623 /* Fatal error. */
624 goto error;
625 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK ||
626 status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
627 /*
628 * A component class claimed this input as a directory,
629 * don't recurse. Or, we got interrupted.
630 */
631 goto end;
632 }
633
634 dir = g_dir_open(input->str, 0, &error);
635 if (!dir) {
636 const char *fmt = "Failed to open directory %s: %s";
637 BT_LOGW(fmt, input->str, error->message);
638
639 if (error->code == G_FILE_ERROR_ACCES) {
640 /* This is not a fatal error, we just skip it. */
641 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
642 goto end;
643 } else {
644 BT_AUTODISC_LOGE_APPEND_CAUSE(fmt, input->str,
645 error->message);
646 goto error;
647 }
648 }
649
650 saved_input_len = input->len;
651
652 do {
653 errno = 0;
654 dirent = g_dir_read_name(dir);
655 if (dirent) {
656 g_string_append_c_inline(input, G_DIR_SEPARATOR);
657 g_string_append(input, dirent);
658
659 status = auto_discover_source_for_input_as_dir_or_file_rec(
660 input, original_input_index, plugins, plugin_count,
661 component_class_restrict, log_level, auto_disc,
662 interrupter);
663
664 g_string_truncate(input, saved_input_len);
665
666 if (status < 0) {
667 /* Fatal error. */
668 goto error;
669 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
670 goto end;
671 } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
672 dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK;
673 }
674 } else if (errno != 0) {
675 BT_LOGW_ERRNO("Failed to read directory entry", ": dir=%s", input->str);
676 goto error;
677 }
678 } while (dirent);
679
680 status = dir_status;
681
682 g_dir_close(dir);
683 } else {
684 BT_LOGD("Skipping %s, not a file or directory", input->str);
685 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH;
686 }
687
688 goto end;
689
690 error:
691 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
692
693 end:
694
695 if (error) {
696 g_error_free(error);
697 }
698
699 return status;
700 }
701
702 /*
703 * Look for a source component class that recognizes `input` as a directory or
704 * file. If `input` is a directory and is not directly recognized, recurse and
705 * apply the same logic to children nodes.
706 *
707 * Same return value semantic as `support_info_query_all_sources`.
708 */
709
710 static
711 auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file(
712 const char *input,
713 uint64_t original_input_index,
714 const bt_plugin **plugins,
715 size_t plugin_count,
716 const char *component_class_restrict,
717 enum bt_logging_level log_level,
718 struct auto_source_discovery *auto_disc,
719 const bt_interrupter *interrupter)
720 {
721 GString *mutable_input;
722 auto_source_discovery_internal_status status;
723
724 mutable_input = g_string_new(input);
725 if (!mutable_input) {
726 status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR;
727 goto end;
728 }
729
730 status = auto_discover_source_for_input_as_dir_or_file_rec(
731 mutable_input, original_input_index, plugins, plugin_count,
732 component_class_restrict, log_level, auto_disc,
733 interrupter);
734
735 g_string_free(mutable_input, TRUE);
736 end:
737 return status;
738 }
739
740 auto_source_discovery_status auto_discover_source_components(
741 const bt_value *inputs,
742 const bt_plugin **plugins,
743 size_t plugin_count,
744 const char *component_class_restrict,
745 enum bt_logging_level log_level,
746 struct auto_source_discovery *auto_disc,
747 const bt_interrupter *interrupter)
748 {
749 uint64_t i_inputs, input_count;
750 auto_source_discovery_internal_status internal_status;
751 auto_source_discovery_status status;
752
753 input_count = bt_value_array_get_length(inputs);
754
755 for (i_inputs = 0; i_inputs < input_count; i_inputs++) {
756 const bt_value *input_value;
757 const char *input;
758
759 input_value = bt_value_array_borrow_element_by_index_const(inputs, i_inputs);
760 input = bt_value_string_get(input_value);
761 internal_status = auto_discover_source_for_input_as_string(input, i_inputs,
762 plugins, plugin_count, component_class_restrict,
763 log_level, auto_disc, interrupter);
764 if (internal_status < 0 || internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
765 /* Fatal error or we got interrupted. */
766 status = (auto_source_discovery_status) internal_status;
767 goto end;
768 } else if (internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) {
769 /* A component class has claimed this input as an arbitrary string. */
770 continue;
771 }
772
773 internal_status = auto_discover_source_for_input_as_dir_or_file(input,
774 i_inputs, plugins, plugin_count,
775 component_class_restrict, log_level, auto_disc, interrupter);
776 if (internal_status < 0 || internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) {
777 /* Fatal error or we got interrupted. */
778 status = (auto_source_discovery_status) internal_status;
779 goto end;
780 } else if (internal_status == 0) {
781 /*
782 * This input (or something under it) was recognized.
783 */
784 continue;
785 }
786
787 BT_LOGW("No trace was found based on input `%s`.", input);
788 }
789
790 status = AUTO_SOURCE_DISCOVERY_STATUS_OK;
791 end:
792 return status;
793 }
This page took 0.055243 seconds and 5 git commands to generate.