Commit | Line | Data |
---|---|---|
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 | |
c4f23e30 FD |
27 | #include <stdbool.h> |
28 | ||
97010665 | 29 | #include "autodisc.h" |
73760435 SM |
30 | #include "common/common.h" |
31 | ||
97010665 SM |
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 | ||
3dae1685 SM |
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 | ||
73760435 SM |
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); | |
45bab744 | 62 | bt_value_put_ref(res->original_input_indices); |
73760435 SM |
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, | |
97010665 | 72 | const char *group, bt_logging_level log_level) |
73760435 SM |
73 | { |
74 | struct auto_source_discovery_result *res; | |
75 | ||
76 | res = g_new0(struct auto_source_discovery_result, 1); | |
77 | if (!res) { | |
97010665 | 78 | BT_AUTODISC_LOGE_APPEND_CAUSE( |
73760435 SM |
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) { | |
97010665 | 87 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a string."); |
73760435 SM |
88 | goto error; |
89 | } | |
90 | ||
91 | res->inputs = bt_value_array_create(); | |
92 | if (!res->inputs) { | |
97010665 | 93 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value."); |
73760435 SM |
94 | goto error; |
95 | } | |
96 | ||
1ead9076 SM |
97 | res->original_input_indices = bt_value_array_create(); |
98 | if (!res->original_input_indices) { | |
97010665 | 99 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate an array value."); |
1ead9076 SM |
100 | goto error; |
101 | } | |
102 | ||
73760435 SM |
103 | goto end; |
104 | error: | |
105 | auto_source_discovery_result_destroy(res); | |
cc611878 | 106 | res = NULL; |
73760435 SM |
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 | ||
1ead9076 SM |
146 | static |
147 | const bt_value *borrow_array_value_last_element_const(const bt_value *array) | |
148 | { | |
393729a6 | 149 | uint64_t last_index = bt_value_array_get_length(array) - 1; |
1ead9076 SM |
150 | |
151 | return bt_value_array_borrow_element_by_index_const(array, last_index); | |
152 | } | |
153 | ||
73760435 SM |
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 | |
3dae1685 SM |
160 | auto_source_discovery_internal_status auto_source_discovery_add( |
161 | struct auto_source_discovery *auto_disc, | |
73760435 SM |
162 | const char *plugin_name, |
163 | const char *source_cc_name, | |
164 | const char *group, | |
1ead9076 | 165 | const char *input, |
97010665 SM |
166 | uint64_t original_input_index, |
167 | bt_logging_level log_level) | |
73760435 | 168 | { |
3dae1685 | 169 | auto_source_discovery_internal_status status; |
73760435 SM |
170 | bt_value_array_append_element_status append_status; |
171 | guint len; | |
172 | guint i; | |
173 | struct auto_source_discovery_result *res = NULL; | |
1ead9076 | 174 | bool append_index; |
73760435 SM |
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, | |
97010665 | 202 | source_cc_name, group, log_level); |
73760435 SM |
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) { | |
97010665 | 212 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append a string value."); |
73760435 SM |
213 | goto error; |
214 | } | |
215 | ||
1ead9076 SM |
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) { | |
97010665 | 241 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to append an unsigned integer value."); |
1ead9076 SM |
242 | goto error; |
243 | } | |
244 | } | |
73760435 | 245 | |
3dae1685 | 246 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK; |
73760435 SM |
247 | goto end; |
248 | ||
249 | error: | |
3dae1685 | 250 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR; |
73760435 SM |
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, | |
97010665 SM |
259 | const char *input, const char *input_type, |
260 | bt_logging_level log_level) | |
73760435 SM |
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 { | |
1a29b831 | 273 | BT_LOGW("babeltrace.support-info query: unexpected type for weight: " |
73760435 SM |
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) { | |
1a29b831 | 283 | BT_LOGW("babeltrace.support-info query: weight value is out of range [0.0, 1.0]: " |
73760435 SM |
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 | ||
97010665 SM |
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 | ||
73760435 SM |
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. | |
73760435 SM |
344 | */ |
345 | static | |
3dae1685 SM |
346 | auto_source_discovery_internal_status support_info_query_all_sources( |
347 | const char *input, | |
1ead9076 SM |
348 | const char *input_type, |
349 | uint64_t original_input_index, | |
97010665 | 350 | const bt_plugin **plugins, |
1ead9076 | 351 | size_t plugin_count, |
73760435 SM |
352 | const char *component_class_restrict, |
353 | enum bt_logging_level log_level, | |
3dae1685 SM |
354 | struct auto_source_discovery *auto_disc, |
355 | const bt_interrupter *interrupter) | |
73760435 SM |
356 | { |
357 | bt_value_map_insert_entry_status insert_status; | |
358 | bt_value *query_params = NULL; | |
3dae1685 | 359 | auto_source_discovery_internal_status status; |
73760435 SM |
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 | ||
3dae1685 SM |
369 | if (interrupter && bt_interrupter_is_set(interrupter)) { |
370 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED; | |
371 | goto end; | |
372 | } | |
373 | ||
73760435 SM |
374 | query_params = bt_value_map_create(); |
375 | if (!query_params) { | |
97010665 | 376 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to allocate a map value."); |
73760435 SM |
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) { | |
97010665 | 382 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry."); |
73760435 SM |
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) { | |
97010665 | 388 | BT_AUTODISC_LOGE_APPEND_CAUSE("Failed to insert a map entry."); |
73760435 SM |
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 | ||
97010665 | 398 | plugin = plugins[i_plugins]; |
73760435 SM |
399 | plugin_name = bt_plugin_get_name(plugin); |
400 | ||
73760435 SM |
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 | ||
1a29b831 | 421 | BT_LOGD("babeltrace.support-info query: before: component-class-name=source.%s.%s, input=%s, " |
73760435 SM |
422 | "type=%s", plugin_name, source_cc_name, input, input_type); |
423 | ||
424 | BT_VALUE_PUT_REF_AND_RESET(query_result); | |
97010665 SM |
425 | query_status = simple_query(cc, "babeltrace.support-info", |
426 | query_params, log_level, &query_result); | |
73760435 SM |
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) { | |
97010665 | 438 | if (convert_weight_value(query_result, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) { |
73760435 SM |
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")) { | |
1a29b831 | 446 | BT_LOGW("babeltrace.support-info query: result is missing `weight` entry: " |
73760435 SM |
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 | ||
97010665 | 457 | if (convert_weight_value(weight_value, &weight, plugin_name, source_cc_name, input, input_type, log_level) != 0) { |
73760435 SM |
458 | /* convert_weight_value has already warned. */ |
459 | continue; | |
460 | } | |
461 | ||
462 | if (bt_value_map_has_entry(query_result, "group")) { | |
73760435 SM |
463 | group_value = bt_value_map_borrow_entry_value_const(query_result, "group"); |
464 | BT_ASSERT(group_value); | |
465 | ||
282a37f5 | 466 | if (bt_value_get_type(group_value) != BT_VALUE_TYPE_STRING) { |
1a29b831 | 467 | BT_LOGW("babeltrace.support-info query: unexpected type for entry `group`: " |
73760435 SM |
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 { | |
1a29b831 | 480 | BT_LOGW("babeltrace.support-info query: unexpected result type: " |
73760435 SM |
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 | ||
1a29b831 | 493 | BT_LOGD("babeltrace.support-info query: success: component-class-name=source.%s.%s, input=%s, " |
61de0522 | 494 | "type=%s, weight=%f, group=%s\n", |
73760435 | 495 | bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input, |
61de0522 | 496 | input_type, weight, group_value ? bt_value_string_get(group_value) : "(none)"); |
73760435 SM |
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) { | |
97010665 | 509 | BT_AUTODISC_LOGE_APPEND_CAUSE("babeltrace.support-info query failed."); |
73760435 SM |
510 | goto error; |
511 | } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_MEMORY_ERROR) { | |
97010665 | 512 | BT_AUTODISC_LOGE_APPEND_CAUSE("Memory error."); |
73760435 SM |
513 | goto error; |
514 | } else { | |
1a29b831 | 515 | BT_LOGD("babeltrace.support-info query: failure: component-class-name=source.%s.%s, input=%s, " |
73760435 SM |
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 | ||
61de0522 SM |
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)"); | |
73760435 | 536 | |
1ead9076 | 537 | status = auto_source_discovery_add(auto_disc, plugin_name, |
97010665 | 538 | source_name, group, input, original_input_index, log_level); |
3dae1685 | 539 | if (status != AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) { |
73760435 SM |
540 | goto error; |
541 | } | |
542 | } else { | |
61de0522 | 543 | BT_LOGI("Input not recognized: input=%s, type=%s", |
73760435 | 544 | input, input_type); |
3dae1685 | 545 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH; |
73760435 SM |
546 | } |
547 | ||
548 | goto end; | |
549 | ||
550 | error: | |
3dae1685 | 551 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR; |
73760435 SM |
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 | |
3dae1685 SM |
569 | auto_source_discovery_internal_status auto_discover_source_for_input_as_string( |
570 | const char *input, | |
1ead9076 | 571 | uint64_t original_input_index, |
97010665 SM |
572 | const bt_plugin **plugins, |
573 | size_t plugin_count, | |
73760435 SM |
574 | const char *component_class_restrict, |
575 | enum bt_logging_level log_level, | |
3dae1685 SM |
576 | struct auto_source_discovery *auto_disc, |
577 | const bt_interrupter *interrupter) | |
73760435 SM |
578 | { |
579 | return support_info_query_all_sources(input, "string", | |
97010665 | 580 | original_input_index, plugins, plugin_count, |
3dae1685 SM |
581 | component_class_restrict, log_level, auto_disc, |
582 | interrupter); | |
73760435 SM |
583 | } |
584 | ||
585 | static | |
3dae1685 SM |
586 | auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file_rec( |
587 | GString *input, | |
1ead9076 | 588 | uint64_t original_input_index, |
97010665 SM |
589 | const bt_plugin **plugins, |
590 | size_t plugin_count, | |
73760435 SM |
591 | const char *component_class_restrict, |
592 | enum bt_logging_level log_level, | |
3dae1685 SM |
593 | struct auto_source_discovery *auto_disc, |
594 | const bt_interrupter *interrupter) | |
73760435 | 595 | { |
3dae1685 | 596 | auto_source_discovery_internal_status status; |
73760435 SM |
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, | |
97010665 | 602 | "file", original_input_index, plugins, plugin_count, |
3dae1685 SM |
603 | component_class_restrict, log_level, auto_disc, |
604 | interrupter); | |
73760435 SM |
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; | |
3dae1685 | 609 | int dir_status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH; |
73760435 SM |
610 | |
611 | /* It's a directory. */ | |
612 | status = support_info_query_all_sources(input->str, | |
97010665 SM |
613 | "directory", original_input_index, plugins, |
614 | plugin_count, component_class_restrict, log_level, | |
3dae1685 | 615 | auto_disc, interrupter); |
73760435 SM |
616 | |
617 | if (status < 0) { | |
618 | /* Fatal error. */ | |
619 | goto error; | |
3dae1685 SM |
620 | } else if (status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK || |
621 | status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_INTERRUPTED) { | |
73760435 SM |
622 | /* |
623 | * A component class claimed this input as a directory, | |
3dae1685 | 624 | * don't recurse. Or, we got interrupted. |
73760435 SM |
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 | ||
d847ef86 | 634 | if (error->code == G_FILE_ERROR_ACCES) { |
73760435 | 635 | /* This is not a fatal error, we just skip it. */ |
3dae1685 | 636 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH; |
73760435 SM |
637 | goto end; |
638 | } else { | |
97010665 | 639 | BT_AUTODISC_LOGE_APPEND_CAUSE(fmt, input->str, |
73760435 SM |
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( | |
97010665 | 655 | input, original_input_index, plugins, plugin_count, |
3dae1685 SM |
656 | component_class_restrict, log_level, auto_disc, |
657 | interrupter); | |
73760435 SM |
658 | |
659 | g_string_truncate(input, saved_input_len); | |
660 | ||
661 | if (status < 0) { | |
662 | /* Fatal error. */ | |
663 | goto error; | |
3dae1685 SM |
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; | |
73760435 SM |
668 | } |
669 | } else if (errno != 0) { | |
670 | BT_LOGW_ERRNO("Failed to read directory entry", ": dir=%s", input->str); | |
671 | goto error; | |
672 | } | |
5084732e | 673 | } while (dirent); |
73760435 SM |
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); | |
3dae1685 | 680 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_NO_MATCH; |
73760435 SM |
681 | } |
682 | ||
683 | goto end; | |
684 | ||
685 | error: | |
3dae1685 | 686 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR; |
73760435 SM |
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 | |
3dae1685 SM |
706 | auto_source_discovery_internal_status auto_discover_source_for_input_as_dir_or_file( |
707 | const char *input, | |
1ead9076 | 708 | uint64_t original_input_index, |
97010665 SM |
709 | const bt_plugin **plugins, |
710 | size_t plugin_count, | |
73760435 SM |
711 | const char *component_class_restrict, |
712 | enum bt_logging_level log_level, | |
3dae1685 SM |
713 | struct auto_source_discovery *auto_disc, |
714 | const bt_interrupter *interrupter) | |
73760435 SM |
715 | { |
716 | GString *mutable_input; | |
3dae1685 | 717 | auto_source_discovery_internal_status status; |
73760435 SM |
718 | |
719 | mutable_input = g_string_new(input); | |
720 | if (!mutable_input) { | |
3dae1685 | 721 | status = AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_ERROR; |
73760435 SM |
722 | goto end; |
723 | } | |
724 | ||
725 | status = auto_discover_source_for_input_as_dir_or_file_rec( | |
97010665 | 726 | mutable_input, original_input_index, plugins, plugin_count, |
3dae1685 SM |
727 | component_class_restrict, log_level, auto_disc, |
728 | interrupter); | |
73760435 SM |
729 | |
730 | g_string_free(mutable_input, TRUE); | |
731 | end: | |
732 | return status; | |
733 | } | |
734 | ||
3dae1685 | 735 | auto_source_discovery_status auto_discover_source_components( |
73760435 | 736 | const bt_value *inputs, |
97010665 SM |
737 | const bt_plugin **plugins, |
738 | size_t plugin_count, | |
73760435 SM |
739 | const char *component_class_restrict, |
740 | enum bt_logging_level log_level, | |
3dae1685 SM |
741 | struct auto_source_discovery *auto_disc, |
742 | const bt_interrupter *interrupter) | |
73760435 SM |
743 | { |
744 | uint64_t i_inputs, input_count; | |
3dae1685 SM |
745 | auto_source_discovery_internal_status internal_status; |
746 | auto_source_discovery_status status; | |
73760435 | 747 | |
393729a6 | 748 | input_count = bt_value_array_get_length(inputs); |
73760435 | 749 | |
73760435 SM |
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); | |
3dae1685 | 756 | internal_status = auto_discover_source_for_input_as_string(input, i_inputs, |
97010665 | 757 | plugins, plugin_count, component_class_restrict, |
3dae1685 SM |
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. */ | |
764d8fd9 | 761 | status = (auto_source_discovery_status) internal_status; |
73760435 | 762 | goto end; |
3dae1685 | 763 | } else if (internal_status == AUTO_SOURCE_DISCOVERY_INTERNAL_STATUS_OK) { |
73760435 SM |
764 | /* A component class has claimed this input as an arbitrary string. */ |
765 | continue; | |
766 | } | |
767 | ||
3dae1685 | 768 | internal_status = auto_discover_source_for_input_as_dir_or_file(input, |
97010665 | 769 | i_inputs, plugins, plugin_count, |
3dae1685 SM |
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. */ | |
764d8fd9 | 773 | status = (auto_source_discovery_status) internal_status; |
73760435 | 774 | goto end; |
3dae1685 | 775 | } else if (internal_status == 0) { |
73760435 SM |
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 | ||
3dae1685 | 785 | status = AUTO_SOURCE_DISCOVERY_STATUS_OK; |
73760435 | 786 | end: |
73760435 SM |
787 | return status; |
788 | } |