From: Philippe Proulx Date: Tue, 25 Jun 2019 16:50:17 +0000 (-0400) Subject: lib: bt_plugin_find*(): return status code; add "fail on load error" param X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=9736d991ea189f29b908e9cf18103c1452c59e05 lib: bt_plugin_find*(): return status code; add "fail on load error" param The bt_plugin_find*() functions, before this patch, return a plugin object or a plugin set object. When such a function returns `NULL`, you have no way to tell if it's because there was an error or if no plugins were found. Also, when a plugin cannot be loaded for various reasons, sometimes it's considered an error and sometimes not, so there's no way to be strict. This patch makes: * The bt_plugin_find*() functions return a status code, and return the plugin or plugin set object by output parameter. The available, new status codes are: `BT_PLUGIN_STATUS_OK`: Everything is fine. `BT_PLUGIN_STATUS_NOT_FOUND`: No plugins were found. `BT_PLUGIN_STATUS_ERROR`: There was a general error while trying to find plugins. `BT_PLUGIN_STATUS_LOADING_ERROR`: A plugin could not be loaded successfully while trying to find plugins. `BT_PLUGIN_STATUS_NOMEM`: There was an allocation error while trying to find plugins. The bt_plugin_find_all_from_file() and bt_plugin_find_all_from_dir() never return an empty plugin set: they return `BT_PLUGIN_STATUS_NOT_FOUND` instead. * The bt_plugin_find*() functions accept a new `fail_on_load_error` parameter which controls whether a plugin loading error is ignored (can eventually lead to `BT_PLUGIN_STATUS_NOT_FOUND` being returned) or triggers a loading error condition (`BT_PLUGIN_STATUS_LOADING_ERROR`). When `fail_on_load_error` is true, the functions log errors with the WARN level. When it's false, they log errors with the INFO level before ignoring them. A file is known to be a Babeltrace plugin if: * Its extension is `.so` (or `.dll` on Windows), g_module_open() succeeds for that file, and the required `__bt_get_begin_section_plugin_descriptors` symbol can be found. * Its name starts with `bt_` and ends with `.py`. Any file that does not meet the criteria above does not trigger a loading error: the file is simply skipped. A plugin loading error (`BT_PLUGIN_STATUS_LOADING_ERROR`) is caused by: For a shared object (`.so` or `.dll`) plugin, one of: * Missing `__bt_get_end_section_plugin_descriptors` symbol. * Missing `__bt_get_begin_section_plugin_descriptor_attributes` and `__bt_get_end_section_plugin_descriptor_attributes` symbols. * Missing `__bt_get_begin_section_component_class_descriptors` and `__bt_get_end_section_component_class_descriptors` symbols. * Missing `__bt_get_begin_section_component_class_descriptor_attributes` and `__bt_get_end_section_component_class_descriptor_attributes` symbols. * Unknown plugin descriptor attribute. * Unknown component class descriptor attribute. * Unknown component class type in component class descriptors. * Incompatible or missing ABI version. * Failing plugin's user initialization function. For a built-in plugin: * Failing plugin's user initialization function. For a Python plugin, one of: * Failure to load the Python plugin module. * Unexpected/malformed plugin info object (missing attributes, wrong types, etc.). With this patch, you must pass a valid file or directory path to bt_plugin_find_all_from_file() and bt_plugin_find_all_from_dir(). When you don't, the functions fail with `BT_PLUGIN_STATUS_ERROR`. This is not considered a loading error (not `BT_PLUGIN_STATUS_LOADING_ERROR`), as the user can control whether or not this error occurs­ by making sure the path exists, and it does not occur while loading a plugin. As of this patch, the CLI ignores loading errors (like before), that is, passes `BT_FALSE` as the `fail_on_load_error` parameter. A strict mode could be added, controlled by a command-line option. In `native_bt_plugin.i`, wrappers are created to set the output parameter to `NULL` if the status is not `BT_PLUGIN_STATUS_OK`. This is similar to what was already done to wrap bt_plugin_get_version(). If you pass `fail_on_load_error=True` to bt2.find_plugins() or bt2.find_plugin(), then this function can raise `bt2.Error` if there's a loading error. Tests are adapted to check the returned status code. Signed-off-by: Philippe Proulx Change-Id: I88049c07163055503e9551940973390ebedcfae4 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1537 Reviewed-by: Francis Deslauriers Tested-by: jenkins --- diff --git a/include/babeltrace2/plugin/plugin-const.h b/include/babeltrace2/plugin/plugin-const.h index e9d3ee34..e8a8a2b6 100644 --- a/include/babeltrace2/plugin/plugin-const.h +++ b/include/babeltrace2/plugin/plugin-const.h @@ -43,15 +43,28 @@ extern "C" { #endif -extern const bt_plugin *bt_plugin_find(const char *plugin_name); - -extern const bt_plugin_set *bt_plugin_find_all_from_file( - const char *path); - -extern const bt_plugin_set *bt_plugin_find_all_from_dir( - const char *path, bt_bool recurse); - -extern const bt_plugin_set *bt_plugin_find_all_from_static(void); +typedef enum bt_plugin_status { + BT_PLUGIN_STATUS_OK = 0, + BT_PLUGIN_STATUS_NOT_FOUND = 2, + BT_PLUGIN_STATUS_ERROR = -1, + BT_PLUGIN_STATUS_LOADING_ERROR = -2, + BT_PLUGIN_STATUS_NOMEM = -12, +} bt_plugin_status; + +extern bt_plugin_status bt_plugin_find(const char *plugin_name, + bt_bool fail_on_load_error, const bt_plugin **plugin); + +extern bt_plugin_status bt_plugin_find_all_from_file( + const char *path, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set); + +extern bt_plugin_status bt_plugin_find_all_from_dir( + const char *path, bt_bool recurse, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set); + +extern bt_plugin_status bt_plugin_find_all_from_static( + bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set); extern const char *bt_plugin_get_name(const bt_plugin *plugin); diff --git a/src/bindings/python/bt2/bt2/__init__.py.in b/src/bindings/python/bt2/bt2/__init__.py.in index fe987a3d..98a1eb5d 100644 --- a/src/bindings/python/bt2/bt2/__init__.py.in +++ b/src/bindings/python/bt2/bt2/__init__.py.in @@ -106,6 +106,10 @@ class NonexistentClockSnapshot(Error): pass +class PluginLoadingError(Error): + pass + + class _ListenerHandle: def __init__(self, listener_id, obj): self._listener_id = listener_id diff --git a/src/bindings/python/bt2/bt2/native_bt_plugin.i b/src/bindings/python/bt2/bt2/native_bt_plugin.i index 435d40f2..44633f2c 100644 --- a/src/bindings/python/bt2/bt2/native_bt_plugin.i +++ b/src/bindings/python/bt2/bt2/native_bt_plugin.i @@ -22,17 +22,57 @@ * THE SOFTWARE. */ -/* From plugin-const.h */ +/* Output argument typemap for plugin output (always appends) */ +%typemap(in, numinputs=0) + (const bt_plugin **OUT) + (bt_plugin *temp_plugin = NULL) { + $1 = &temp_plugin; +} -extern const bt_plugin *bt_plugin_find(const char *plugin_name); +%typemap(argout) + (const bt_plugin **OUT) { + if (*$1) { + /* SWIG_Python_AppendOutput() steals the created object */ + $result = SWIG_Python_AppendOutput($result, + SWIG_NewPointerObj(SWIG_as_voidptr(*$1), + SWIGTYPE_p_bt_plugin, 0)); + } else { + /* SWIG_Python_AppendOutput() steals Py_None */ + Py_INCREF(Py_None); + $result = SWIG_Python_AppendOutput($result, Py_None); + } +} -extern const bt_plugin_set *bt_plugin_find_all_from_file( - const char *path); +/* Output argument typemap for plugin set output (always appends) */ +%typemap(in, numinputs=0) + (const bt_plugin_set **OUT) + (bt_plugin_set *temp_plugin_set = NULL) { + $1 = &temp_plugin_set; +} -extern const bt_plugin_set *bt_plugin_find_all_from_dir( - const char *path, bt_bool recurse); +%typemap(argout) + (const bt_plugin_set **OUT) { + if (*$1) { + /* SWIG_Python_AppendOutput() steals the created object */ + $result = SWIG_Python_AppendOutput($result, + SWIG_NewPointerObj(SWIG_as_voidptr(*$1), + SWIGTYPE_p_bt_plugin_set, 0)); + } else { + /* SWIG_Python_AppendOutput() steals Py_None */ + Py_INCREF(Py_None); + $result = SWIG_Python_AppendOutput($result, Py_None); + } +} + +/* From plugin-const.h */ -extern const bt_plugin_set *bt_plugin_find_all_from_static(void); +typedef enum bt_plugin_status { + BT_PLUGIN_STATUS_OK = 0, + BT_PLUGIN_STATUS_NOT_FOUND = 2, + BT_PLUGIN_STATUS_ERROR = -1, + BT_PLUGIN_STATUS_LOADING_ERROR = -2, + BT_PLUGIN_STATUS_NOMEM = -12, +} bt_plugin_status; extern const char *bt_plugin_get_name(const bt_plugin *plugin); @@ -44,10 +84,6 @@ extern const char *bt_plugin_get_description(const bt_plugin *plugin); extern const char *bt_plugin_get_path(const bt_plugin *plugin); -extern bt_property_availability bt_plugin_get_version( - const bt_plugin *plugin, unsigned int *OUT, - unsigned int *OUT, unsigned int *OUT, const char **OUT); - extern uint64_t bt_plugin_get_source_component_class_count( const bt_plugin *plugin); @@ -103,14 +139,25 @@ bt_property_availability bt_plugin_get_version_wrapper( const bt_plugin *plugin, unsigned int *OUT, unsigned int *OUT, unsigned int *OUT, const char **OUT); +bt_plugin_status bt_plugin_find_wrapper(const char *plugin_name, + bt_bool fail_on_load_error, const bt_plugin **OUT); + +bt_plugin_status bt_plugin_find_all_from_file_wrapper( + const char *path, bt_bool fail_on_load_error, + const bt_plugin_set **OUT); + +bt_plugin_status bt_plugin_find_all_from_dir_wrapper( + const char *path, bt_bool recurse, bt_bool fail_on_load_error, + const bt_plugin_set **OUT); + %{ /* - * This wrapper ensures that when the API function fails, the `*extra` output - * parameter is set to NULL. This is necessary because the epilogue of the - * "char **OUT" typemap will use that value to make a Python str object. We - * can't rely on the initial value of `*extra`, it could point to unreadable - * memory. + * This *_wrapper() functions below ensure that when the API function + * fails, the output parameter is set to `NULL`. This is necessary + * because the epilogue of the `something **OUT` typemap will use that + * value to make a Python object. We can't rely on the initial value of + * `*OUT`; it could point to unreadable memory. */ bt_property_availability bt_plugin_get_version_wrapper( @@ -128,4 +175,48 @@ bt_property_availability bt_plugin_get_version_wrapper( return ret; } +bt_plugin_status bt_plugin_find_wrapper(const char *plugin_name, + bt_bool fail_on_load_error, const bt_plugin **plugin) +{ + bt_plugin_status status; + + status = bt_plugin_find(plugin_name, fail_on_load_error, + plugin); + if (status != BT_PLUGIN_STATUS_OK) { + *plugin = NULL; + } + + return status; +} + +bt_plugin_status bt_plugin_find_all_from_file_wrapper( + const char *path, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set) +{ + bt_plugin_status status; + + status = bt_plugin_find_all_from_file(path, fail_on_load_error, + plugin_set); + if (status != BT_PLUGIN_STATUS_OK) { + *plugin_set = NULL; + } + + return status; +} + +bt_plugin_status bt_plugin_find_all_from_dir_wrapper( + const char *path, bt_bool recurse, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set) +{ + bt_plugin_status status; + + status = bt_plugin_find_all_from_dir(path, recurse, fail_on_load_error, + plugin_set); + if (status != BT_PLUGIN_STATUS_OK) { + *plugin_set = NULL; + } + + return status; +} + %} diff --git a/src/bindings/python/bt2/bt2/plugin.py b/src/bindings/python/bt2/bt2/plugin.py index 2d0d8b05..b32f8ce2 100644 --- a/src/bindings/python/bt2/bt2/plugin.py +++ b/src/bindings/python/bt2/bt2/plugin.py @@ -27,29 +27,45 @@ import os.path import bt2 -def find_plugins(path, recurse=True): +def _handle_status(status, gen_error_msg): + if status == native_bt.PLUGIN_STATUS_LOADING_ERROR: + raise bt2.PluginLoadingError + elif status < 0: + raise bt2.Error(gen_error_msg) + + +def find_plugins(path, recurse=True, fail_on_load_error=False): utils._check_str(path) utils._check_bool(recurse) + utils._check_bool(fail_on_load_error) plugin_set_ptr = None if os.path.isfile(path): - plugin_set_ptr = native_bt.plugin_find_all_from_file(path) + status, plugin_set_ptr = native_bt.plugin_find_all_from_file_wrapper(path, fail_on_load_error) elif os.path.isdir(path): - plugin_set_ptr = native_bt.plugin_find_all_from_dir(path, int(recurse)) + status, plugin_set_ptr = native_bt.plugin_find_all_from_dir_wrapper(path, int(recurse), int(fail_on_load_error)) + else: + raise bt2.Error("invalid path: '{}'".format(path)) + + _handle_status(status, 'failed to find plugins') - if plugin_set_ptr is None: + if status == native_bt.PLUGIN_STATUS_NOT_FOUND: return + assert plugin_set_ptr is not None return _PluginSet._create_from_ptr(plugin_set_ptr) -def find_plugin(name): +def find_plugin(name, fail_on_load_error=False): utils._check_str(name) - ptr = native_bt.plugin_find(name) + utils._check_bool(fail_on_load_error) + status, ptr = native_bt.plugin_find_wrapper(name, int(fail_on_load_error)) + _handle_status(status, 'failed to find plugin') - if ptr is None: + if status == native_bt.PLUGIN_STATUS_NOT_FOUND: return + assert ptr is not None return _Plugin._create_from_ptr(ptr) diff --git a/src/cli/babeltrace2.c b/src/cli/babeltrace2.c index 3cb751c3..c89fabce 100644 --- a/src/cli/babeltrace2.c +++ b/src/cli/babeltrace2.c @@ -797,7 +797,8 @@ int load_dynamic_plugins(const bt_value *plugin_paths) for (i = 0; i < nr_paths; i++) { const bt_value *plugin_path_value = NULL; const char *plugin_path; - const bt_plugin_set *plugin_set; + const bt_plugin_set *plugin_set = NULL; + bt_plugin_status status; plugin_path_value = bt_value_array_borrow_element_by_index_const( @@ -815,13 +816,20 @@ int load_dynamic_plugins(const bt_value *plugin_paths) continue; } - plugin_set = bt_plugin_find_all_from_dir(plugin_path, false); - if (!plugin_set) { - BT_LOGI("Unable to load dynamic plugins from directory: " + status = bt_plugin_find_all_from_dir(plugin_path, BT_FALSE, + BT_FALSE, &plugin_set); + if (status < 0) { + BT_LOGE("Unable to load dynamic plugins from directory: " "path=\"%s\"", plugin_path); continue; + } else if (status == BT_PLUGIN_STATUS_NOT_FOUND) { + BT_LOGI("No plugins found in directory: path=\"%s\"", + plugin_path); + continue; } + BT_ASSERT(status == BT_PLUGIN_STATUS_OK); + BT_ASSERT(plugin_set); add_to_loaded_plugins(plugin_set); bt_plugin_set_put_ref(plugin_set); } @@ -834,15 +842,21 @@ int load_static_plugins(void) { int ret = 0; const bt_plugin_set *plugin_set; + bt_plugin_status status; BT_LOGI("Loading static plugins."); - plugin_set = bt_plugin_find_all_from_static(); - if (!plugin_set) { + status = bt_plugin_find_all_from_static(BT_FALSE, &plugin_set); + if (status < 0) { BT_LOGE("Unable to load static plugins."); ret = -1; goto end; + } else if (status == BT_PLUGIN_STATUS_NOT_FOUND) { + BT_LOGI("No static plugins found."); + goto end; } + BT_ASSERT(status == BT_PLUGIN_STATUS_OK); + BT_ASSERT(plugin_set); add_to_loaded_plugins(plugin_set); bt_plugin_set_put_ref(plugin_set); end: diff --git a/src/lib/plugin/plugin-so.c b/src/lib/plugin/plugin-so.c index 2ecb1a7e..42b1df6c 100644 --- a/src/lib/plugin/plugin-so.c +++ b/src/lib/plugin/plugin-so.c @@ -174,33 +174,37 @@ void bt_plugin_so_shared_lib_handle_destroy(struct bt_object *obj) } static -struct bt_plugin_so_shared_lib_handle *bt_plugin_so_shared_lib_handle_create( - const char *path) +enum bt_plugin_status bt_plugin_so_shared_lib_handle_create( + const char *path, + struct bt_plugin_so_shared_lib_handle **shared_lib_handle) { - struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL; + enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; + BT_ASSERT(shared_lib_handle); BT_LOGI("Creating shared library handle: path=\"%s\"", path); - shared_lib_handle = g_new0(struct bt_plugin_so_shared_lib_handle, 1); - if (!shared_lib_handle) { + *shared_lib_handle = g_new0(struct bt_plugin_so_shared_lib_handle, 1); + if (!*shared_lib_handle) { BT_LOGE_STR("Failed to allocate one shared library handle."); - goto error; + status = BT_PLUGIN_STATUS_NOMEM; + goto end; } - bt_object_init_shared(&shared_lib_handle->base, + bt_object_init_shared(&(*shared_lib_handle)->base, bt_plugin_so_shared_lib_handle_destroy); if (!path) { goto end; } - shared_lib_handle->path = g_string_new(path); - if (!shared_lib_handle->path) { + (*shared_lib_handle)->path = g_string_new(path); + if (!(*shared_lib_handle)->path) { BT_LOGE_STR("Failed to allocate a GString."); - goto error; + status = BT_PLUGIN_STATUS_NOMEM; + goto end; } - shared_lib_handle->module = g_module_open(path, G_MODULE_BIND_LOCAL); - if (!shared_lib_handle->module) { + (*shared_lib_handle)->module = g_module_open(path, G_MODULE_BIND_LOCAL); + if (!(*shared_lib_handle)->module) { /* * INFO-level logging because we're only _trying_ to * open this file as a Babeltrace plugin: if it's not, @@ -210,21 +214,21 @@ struct bt_plugin_so_shared_lib_handle *bt_plugin_so_shared_lib_handle_create( */ BT_LOGI("Cannot open GModule: %s: path=\"%s\"", g_module_error(), path); - goto error; + BT_OBJECT_PUT_REF_AND_RESET(*shared_lib_handle); + status = BT_PLUGIN_STATUS_NOT_FOUND; + goto end; } goto end; -error: - BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle); - end: - if (shared_lib_handle) { + BT_ASSERT(*shared_lib_handle || status != BT_PLUGIN_STATUS_OK); + if (*shared_lib_handle) { BT_LOGI("Created shared library handle: path=\"%s\", addr=%p", - path, shared_lib_handle); + path, *shared_lib_handle); } - return shared_lib_handle; + return status; } static @@ -271,8 +275,8 @@ void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin) * 6. Freeze the plugin object. */ static -enum bt_plugin_status bt_plugin_so_init( - struct bt_plugin *plugin, +enum bt_plugin_status bt_plugin_so_init(struct bt_plugin *plugin, + bool fail_on_load_error, const struct __bt_plugin_descriptor *descriptor, struct __bt_plugin_descriptor_attribute const * const *attrs_begin, struct __bt_plugin_descriptor_attribute const * const *attrs_end, @@ -352,7 +356,7 @@ enum bt_plugin_status bt_plugin_so_init( sizeof(struct comp_class_full_descriptor)); if (!comp_class_full_descriptors) { BT_LOGE_STR("Failed to allocate a GArray."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; goto end; } @@ -400,21 +404,24 @@ enum bt_plugin_status bt_plugin_so_init( cur_attr->value.version.extra); break; default: - /* - * WARN-level logging because this should not - * happen with the appropriate ABI version. If - * we're here, we know that for the reported - * version of the ABI, this attribute is - * unknown. - */ - BT_LOGW("Ignoring unknown plugin descriptor attribute: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "%s plugin descriptor attribute: " "plugin-path=\"%s\", plugin-name=\"%s\", " "attr-type-name=\"%s\", attr-type-id=%d", + fail_on_load_error ? "Unknown" : + "Ignoring unknown", spec->shared_lib_handle->path ? spec->shared_lib_handle->path->str : NULL, descriptor->name, cur_attr->type_name, cur_attr->type); + + if (fail_on_load_error) { + status = BT_PLUGIN_STATUS_LOADING_ERROR; + goto end; + } + break; } } @@ -660,21 +667,17 @@ enum bt_plugin_status bt_plugin_so_init( } break; default: - /* - * WARN-level logging because this - * should not happen with the - * appropriate ABI version. If we're - * here, we know that for the reported - * version of the ABI, this attribute is - * unknown. - */ - BT_LOGW("Ignoring unknown component class descriptor attribute: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "%s component class descriptor attribute: " "plugin-path=\"%s\", " "plugin-name=\"%s\", " "comp-class-name=\"%s\", " "comp-class-type=%s, " "attr-type-name=\"%s\", " "attr-type-id=%d", + fail_on_load_error ? "Unknown" : + "Ignoring unknown", spec->shared_lib_handle->path ? spec->shared_lib_handle->path->str : NULL, @@ -684,6 +687,12 @@ enum bt_plugin_status bt_plugin_so_init( cur_cc_descr_attr->comp_class_descriptor->type), cur_cc_descr_attr->type_name, cur_cc_descr_attr->type); + + if (fail_on_load_error) { + status = BT_PLUGIN_STATUS_LOADING_ERROR; + goto end; + } + break; } } @@ -695,13 +704,20 @@ enum bt_plugin_status bt_plugin_so_init( BT_LOGD_STR("Calling user's plugin initialization function."); init_status = spec->init((void *) plugin); - BT_LOGD("User function returned: %s", + BT_LOGD("User function returned: status=%s", bt_self_plugin_status_string(init_status)); if (init_status < 0) { - BT_LOGW_STR("User's plugin initialization function failed."); - status = BT_PLUGIN_STATUS_ERROR; - goto end; + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "User's plugin initialization function failed: " + "status=%s", + bt_self_plugin_status_string(init_status)); + + if (fail_on_load_error) { + status = (int) init_status; + goto end; + } } } @@ -751,28 +767,31 @@ enum bt_plugin_status bt_plugin_so_init( sink_comp_class); break; default: - /* - * WARN-level logging because this should not - * happen with the appropriate ABI version. If - * we're here, we know that for the reported - * version of the ABI, this component class type - * is unknown. - */ - BT_LOGW("Ignoring unknown component class type: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "%s component class type: " "plugin-path=\"%s\", plugin-name=\"%s\", " "comp-class-name=\"%s\", comp-class-type=%d", + fail_on_load_error ? "Unknown" : + "Ignoring unknown", spec->shared_lib_handle->path->str ? spec->shared_lib_handle->path->str : NULL, descriptor->name, cc_full_descr->descriptor->name, cc_full_descr->descriptor->type); + + if (fail_on_load_error) { + status = BT_PLUGIN_STATUS_LOADING_ERROR; + goto end; + } + continue; } if (!comp_class) { BT_LOGE_STR("Cannot create component class."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; goto end; } @@ -781,7 +800,7 @@ enum bt_plugin_status bt_plugin_so_init( comp_class, cc_full_descr->description); if (ret) { BT_LOGE_STR("Cannot set component class's description."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(comp_class); goto end; } @@ -792,7 +811,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->help); if (ret) { BT_LOGE_STR("Cannot set component class's help string."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(comp_class); goto end; } @@ -806,7 +825,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.init); if (ret) { BT_LOGE_STR("Cannot set source component class's initialization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -818,7 +837,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.finalize); if (ret) { BT_LOGE_STR("Cannot set source component class's finalization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -830,7 +849,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.query); if (ret) { BT_LOGE_STR("Cannot set source component class's query method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -842,7 +861,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.output_port_connected); if (ret) { BT_LOGE_STR("Cannot set source component class's \"output port connected\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -854,7 +873,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.msg_iter_init); if (ret) { BT_LOGE_STR("Cannot set source component class's message iterator initialization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -866,7 +885,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.msg_iter_finalize); if (ret) { BT_LOGE_STR("Cannot set source component class's message iterator finalization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -878,7 +897,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.msg_iter_seek_ns_from_origin); if (ret) { BT_LOGE_STR("Cannot set source component class's message iterator \"seek nanoseconds from origin\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -890,7 +909,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.msg_iter_seek_beginning); if (ret) { BT_LOGE_STR("Cannot set source component class's message iterator \"seek beginning\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -902,7 +921,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin); if (ret) { BT_LOGE_STR("Cannot set source component class's message iterator \"can seek nanoseconds from origin\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -914,7 +933,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.source.msg_iter_can_seek_beginning); if (ret) { BT_LOGE_STR("Cannot set source component class's message iterator \"can seek beginning\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(src_comp_class); goto end; } @@ -928,7 +947,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.init); if (ret) { BT_LOGE_STR("Cannot set filter component class's initialization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -940,7 +959,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.finalize); if (ret) { BT_LOGE_STR("Cannot set filter component class's finalization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -952,7 +971,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.query); if (ret) { BT_LOGE_STR("Cannot set filter component class's query method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -964,7 +983,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.input_port_connected); if (ret) { BT_LOGE_STR("Cannot set filter component class's \"input port connected\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -976,7 +995,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.output_port_connected); if (ret) { BT_LOGE_STR("Cannot set filter component class's \"output port connected\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -988,7 +1007,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.msg_iter_init); if (ret) { BT_LOGE_STR("Cannot set filter component class's message iterator initialization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -1000,7 +1019,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.msg_iter_finalize); if (ret) { BT_LOGE_STR("Cannot set filter component class's message iterator finalization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -1012,7 +1031,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin); if (ret) { BT_LOGE_STR("Cannot set filter component class's message iterator \"seek nanoseconds from origin\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -1024,7 +1043,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.msg_iter_seek_beginning); if (ret) { BT_LOGE_STR("Cannot set filter component class's message iterator \"seek beginning\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -1036,7 +1055,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin); if (ret) { BT_LOGE_STR("Cannot set filter component class's message iterator \"can seek nanoseconds from origin\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -1048,7 +1067,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.filter.msg_iter_can_seek_beginning); if (ret) { BT_LOGE_STR("Cannot set filter component class's message iterator \"can seek beginning\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class); goto end; } @@ -1062,7 +1081,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.sink.init); if (ret) { BT_LOGE_STR("Cannot set sink component class's initialization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class); goto end; } @@ -1074,7 +1093,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.sink.finalize); if (ret) { BT_LOGE_STR("Cannot set sink component class's finalization method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class); goto end; } @@ -1086,7 +1105,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.sink.query); if (ret) { BT_LOGE_STR("Cannot set sink component class's query method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class); goto end; } @@ -1098,7 +1117,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.sink.input_port_connected); if (ret) { BT_LOGE_STR("Cannot set sink component class's \"input port connected\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class); goto end; } @@ -1110,7 +1129,7 @@ enum bt_plugin_status bt_plugin_so_init( cc_full_descr->methods.sink.graph_is_configured); if (ret) { BT_LOGE_STR("Cannot set sink component class's \"graph is configured\" method."); - status = BT_PLUGIN_STATUS_ERROR; + status = BT_PLUGIN_STATUS_NOMEM; BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class); goto end; } @@ -1192,8 +1211,9 @@ size_t count_non_null_items_in_section(const void *begin, const void *end) } static -struct bt_plugin_set *bt_plugin_so_create_all_from_sections( +enum bt_plugin_status bt_plugin_so_create_all_from_sections( struct bt_plugin_so_shared_lib_handle *shared_lib_handle, + bool fail_on_load_error, struct __bt_plugin_descriptor const * const *descriptors_begin, struct __bt_plugin_descriptor const * const *descriptors_end, struct __bt_plugin_descriptor_attribute const * const *attrs_begin, @@ -1201,20 +1221,22 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_sections( struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin, struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end, struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin, - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end) + struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end, + struct bt_plugin_set **plugin_set_out) { + enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; size_t descriptor_count; size_t attrs_count; size_t cc_descriptors_count; size_t cc_descr_attrs_count; size_t i; - struct bt_plugin_set *plugin_set = NULL; + BT_ASSERT(plugin_set_out); + *plugin_set_out = NULL; descriptor_count = count_non_null_items_in_section(descriptors_begin, descriptors_end); attrs_count = count_non_null_items_in_section(attrs_begin, attrs_end); cc_descriptors_count = count_non_null_items_in_section(cc_descriptors_begin, cc_descriptors_end); cc_descr_attrs_count = count_non_null_items_in_section(cc_descr_attrs_begin, cc_descr_attrs_end); - BT_LOGI("Creating all SO plugins from sections: " "plugin-path=\"%s\", " "descr-begin-addr=%p, descr-end-addr=%p, " @@ -1230,9 +1252,10 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_sections( cc_descr_attrs_begin, cc_descr_attrs_end, descriptor_count, attrs_count, cc_descriptors_count, cc_descr_attrs_count); - plugin_set = bt_plugin_set_create(); - if (!plugin_set) { + *plugin_set_out = bt_plugin_set_create(); + if (!*plugin_set_out) { BT_LOGE_STR("Cannot create empty plugin set."); + status = BT_PLUGIN_STATUS_NOMEM; goto error; } @@ -1251,73 +1274,91 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_sections( descriptor->name, descriptor->major, descriptor->minor); if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) { - /* - * INFO-level logging because we're only - * _trying_ to open this file as a compatible - * Babeltrace plugin: if it's not, it's not an - * error. And because this can be tried during - * bt_plugin_find_all_from_dir(), it's not even - * a warning. - */ - BT_LOGI("Unknown ABI major version: abi-major=%d", - descriptor->major); - goto error; + BT_LOG_WRITE(fail_on_load_error ? BT_LOG_WARN : + BT_LOG_INFO, BT_LOG_TAG, + "Unknown ABI major version: abi-major=%d", + descriptor->major); + + if (fail_on_load_error) { + status = BT_PLUGIN_STATUS_LOADING_ERROR; + goto error; + } else { + continue; + } } plugin = bt_plugin_so_create_empty(shared_lib_handle); if (!plugin) { BT_LOGE_STR("Cannot create empty shared library handle."); + status = BT_PLUGIN_STATUS_NOMEM; goto error; } if (shared_lib_handle && shared_lib_handle->path) { - bt_plugin_set_path(plugin, shared_lib_handle->path->str); + bt_plugin_set_path(plugin, + shared_lib_handle->path->str); } - status = bt_plugin_so_init(plugin, descriptor, attrs_begin, - attrs_end, cc_descriptors_begin, cc_descriptors_end, + status = bt_plugin_so_init(plugin, fail_on_load_error, + descriptor, attrs_begin, attrs_end, + cc_descriptors_begin, cc_descriptors_end, cc_descr_attrs_begin, cc_descr_attrs_end); - if (status < 0) { + if (status == BT_PLUGIN_STATUS_OK) { + /* Add to plugin set */ + bt_plugin_set_add_plugin(*plugin_set_out, plugin); + BT_OBJECT_PUT_REF_AND_RESET(plugin); + } else if (status < 0) { /* - * DEBUG-level logging because we're only - * _trying_ to open this file as a compatible - * Babeltrace plugin: if it's not, it's not an - * error. And because this can be tried during - * bt_plugin_find_all_from_dir(), it's not - * even a warning. + * bt_plugin_so_init() handles + * `fail_on_load_error`, so this is a "real" + * error. */ - BT_LOGD_STR("Cannot initialize SO plugin object from sections."); + BT_LOGW_STR("Cannot initialize SO plugin object from sections."); BT_OBJECT_PUT_REF_AND_RESET(plugin); goto error; } - /* Add to plugin set */ - bt_plugin_set_add_plugin(plugin_set, plugin); - bt_object_put_ref(plugin); + BT_ASSERT(!plugin); + } + + BT_ASSERT(*plugin_set_out); + + if ((*plugin_set_out)->plugins->len == 0) { + BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out); + status = BT_PLUGIN_STATUS_NOT_FOUND; } goto end; error: - BT_OBJECT_PUT_REF_AND_RESET(plugin_set); + BT_ASSERT(status < 0); + BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out); end: - return plugin_set; + return status; } BT_HIDDEN -struct bt_plugin_set *bt_plugin_so_create_all_from_static(void) +enum bt_plugin_status bt_plugin_so_create_all_from_static( + bool fail_on_load_error, + struct bt_plugin_set **plugin_set_out) { - struct bt_plugin_set *plugin_set = NULL; - struct bt_plugin_so_shared_lib_handle *shared_lib_handle = - bt_plugin_so_shared_lib_handle_create(NULL); + enum bt_plugin_status status; + struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL; - if (!shared_lib_handle) { + BT_ASSERT(plugin_set_out); + *plugin_set_out = NULL; + status = bt_plugin_so_shared_lib_handle_create(NULL, + &shared_lib_handle); + if (status != BT_PLUGIN_STATUS_OK) { + BT_ASSERT(!shared_lib_handle); goto end; } + BT_ASSERT(shared_lib_handle); BT_LOGD_STR("Creating all SO plugins from built-in plugins."); - plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle, + status = bt_plugin_so_create_all_from_sections(shared_lib_handle, + fail_on_load_error, __bt_get_begin_section_plugin_descriptors(), __bt_get_end_section_plugin_descriptors(), __bt_get_begin_section_plugin_descriptor_attributes(), @@ -1325,19 +1366,22 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_static(void) __bt_get_begin_section_component_class_descriptors(), __bt_get_end_section_component_class_descriptors(), __bt_get_begin_section_component_class_descriptor_attributes(), - __bt_get_end_section_component_class_descriptor_attributes()); + __bt_get_end_section_component_class_descriptor_attributes(), + plugin_set_out); + BT_ASSERT((status == BT_PLUGIN_STATUS_OK && *plugin_set_out && + (*plugin_set_out)->plugins->len > 0) || !*plugin_set_out); end: BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle); - - return plugin_set; + return status; } BT_HIDDEN -struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) +enum bt_plugin_status bt_plugin_so_create_all_from_file(const char *path, + bool fail_on_load_error, struct bt_plugin_set **plugin_set_out) { size_t path_len; - struct bt_plugin_set *plugin_set = NULL; + enum bt_plugin_status status; struct __bt_plugin_descriptor const * const *descriptors_begin = NULL; struct __bt_plugin_descriptor const * const *descriptors_end = NULL; struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL; @@ -1358,6 +1402,8 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL; BT_ASSERT(path); + BT_ASSERT(plugin_set_out); + *plugin_set_out = NULL; path_len = strlen(path); BT_ASSERT_PRE(path_len > PLUGIN_SUFFIX_LEN, "Path length is too short: path-length=%zu, min-length=%zu", @@ -1377,14 +1423,17 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) NATIVE_PLUGIN_SUFFIX_LEN); if (!is_shared_object && !is_libtool_wrapper) { /* Name indicates this is not a plugin file; not an error */ - BT_LOGI("File is not a SO plugin file: path=\"%s\"", path); + BT_LOGI("File is not an SO plugin file: path=\"%s\"", path); + status = BT_PLUGIN_STATUS_NOT_FOUND; goto end; } - shared_lib_handle = bt_plugin_so_shared_lib_handle_create(path); - if (!shared_lib_handle) { + status = bt_plugin_so_shared_lib_handle_create(path, + &shared_lib_handle); + if (status != BT_PLUGIN_STATUS_OK) { /* bt_plugin_so_shared_lib_handle_create() logs more details */ - BT_LOGD_STR("Cannot create shared library handle."); + BT_ASSERT(!shared_lib_handle); + BT_LOGE_STR("Cannot create shared library handle."); goto end; } @@ -1392,19 +1441,34 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) (gpointer *) &get_begin_section_plugin_descriptors)) { descriptors_begin = get_begin_section_plugin_descriptors(); } else { + /* + * Use this first symbol to know whether or not this + * shared object _looks like_ a Babeltrace plugin. Since + * g_module_symbol() failed, assume that this is not a + * Babeltrace plugin, so it's not an error. + */ BT_LOGI("Cannot resolve plugin symbol: path=\"%s\", " "symbol=\"%s\"", path, "__bt_get_begin_section_plugin_descriptors"); + status = BT_PLUGIN_STATUS_NOT_FOUND; goto end; } + /* + * If g_module_symbol() fails for any of the other symbols, fail + * if `fail_on_load_error` is true. + */ if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_plugin_descriptors", (gpointer *) &get_end_section_plugin_descriptors)) { descriptors_end = get_end_section_plugin_descriptors(); } else { - BT_LOGI("Cannot resolve plugin symbol: path=\"%s\", " + BT_LOG_WRITE(fail_on_load_error ? BT_LOG_WARN : BT_LOG_INFO, + BT_LOG_TAG, + "Cannot resolve plugin symbol: path=\"%s\", " "symbol=\"%s\"", path, "__bt_get_end_section_plugin_descriptors"); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto end; } @@ -1427,13 +1491,17 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) } if ((!!attrs_begin - !!attrs_end) != 0) { - BT_LOGI("Found section start or end symbol, but not both: " + BT_LOG_WRITE(fail_on_load_error ? BT_LOG_WARN : BT_LOG_INFO, + BT_LOG_TAG, + "Found section start or end symbol, but not both: " "path=\"%s\", symbol-start=\"%s\", " "symbol-end=\"%s\", symbol-start-addr=%p, " "symbol-end-addr=%p", path, "__bt_get_begin_section_plugin_descriptor_attributes", "__bt_get_end_section_plugin_descriptor_attributes", attrs_begin, attrs_end); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto end; } @@ -1456,13 +1524,17 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) } if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) { - BT_LOGI("Found section start or end symbol, but not both: " + BT_LOG_WRITE(fail_on_load_error ? BT_LOG_WARN : BT_LOG_INFO, + BT_LOG_TAG, + "Found section start or end symbol, but not both: " "path=\"%s\", symbol-start=\"%s\", " "symbol-end=\"%s\", symbol-start-addr=%p, " "symbol-end-addr=%p", path, "__bt_get_begin_section_component_class_descriptors", "__bt_get_end_section_component_class_descriptors", cc_descriptors_begin, cc_descriptors_end); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto end; } @@ -1485,26 +1557,31 @@ struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path) } if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) { - BT_LOGI("Found section start or end symbol, but not both: " + BT_LOG_WRITE(fail_on_load_error ? BT_LOG_WARN : BT_LOG_INFO, + BT_LOG_TAG, + "Found section start or end symbol, but not both: " "path=\"%s\", symbol-start=\"%s\", " "symbol-end=\"%s\", symbol-start-addr=%p, " "symbol-end-addr=%p", path, "__bt_get_begin_section_component_class_descriptor_attributes", "__bt_get_end_section_component_class_descriptor_attributes", cc_descr_attrs_begin, cc_descr_attrs_end); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto end; } /* Initialize plugin */ BT_LOGD_STR("Initializing plugin object."); - plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle, + status = bt_plugin_so_create_all_from_sections(shared_lib_handle, + fail_on_load_error, descriptors_begin, descriptors_end, attrs_begin, attrs_end, cc_descriptors_begin, cc_descriptors_end, - cc_descr_attrs_begin, cc_descr_attrs_end); + cc_descr_attrs_begin, cc_descr_attrs_end, plugin_set_out); end: BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle); - return plugin_set; + return status; } static diff --git a/src/lib/plugin/plugin-so.h b/src/lib/plugin/plugin-so.h index 328cc148..a2259c8b 100644 --- a/src/lib/plugin/plugin-so.h +++ b/src/lib/plugin/plugin-so.h @@ -53,10 +53,13 @@ struct bt_plugin_so_spec_data { }; BT_HIDDEN -struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path); +enum bt_plugin_status bt_plugin_so_create_all_from_file(const char *path, + bool fail_on_load_error, struct bt_plugin_set **plugin_set_out); BT_HIDDEN -struct bt_plugin_set *bt_plugin_so_create_all_from_static(void); +enum bt_plugin_status bt_plugin_so_create_all_from_static( + bool fail_on_load_error, + struct bt_plugin_set **plugin_set_out); void bt_plugin_so_on_add_component_class(struct bt_plugin *plugin, struct bt_component_class *comp_class); diff --git a/src/lib/plugin/plugin.c b/src/lib/plugin/plugin.c index c0cd158a..47b49cf9 100644 --- a/src/lib/plugin/plugin.c +++ b/src/lib/plugin/plugin.c @@ -57,15 +57,22 @@ #include static -struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) = +enum bt_plugin_status (*bt_plugin_python_create_all_from_file_sym)( + const char *path, bool fail_on_load_error, + struct bt_plugin_set **plugin_set_out) = bt_plugin_python_create_all_from_file; static -void init_python_plugin_provider(void) {} +void init_python_plugin_provider(void) +{ +} #else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */ static GModule *python_plugin_provider_module; + static -struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path); +enum bt_plugin_status (*bt_plugin_python_create_all_from_file_sym)( + const char *path, bool fail_on_load_error, + struct bt_plugin_set **plugin_set_out); static void init_python_plugin_provider(void) { @@ -77,6 +84,11 @@ void init_python_plugin_provider(void) { python_plugin_provider_module = g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME, 0); if (!python_plugin_provider_module) { + /* + * This is not an error. The whole point of having an + * external Python plugin provider is that it can be + * missing and the Babeltrace library still works. + */ BT_LOGI("Cannot open `%s`: %s: continuing without Python plugin support.", PYTHON_PLUGIN_PROVIDER_FILENAME, g_module_error()); return; @@ -85,8 +97,15 @@ void init_python_plugin_provider(void) { if (!g_module_symbol(python_plugin_provider_module, PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR, (gpointer) &bt_plugin_python_create_all_from_file_sym)) { - BT_LOGI("Cannot find the Python plugin provider loading symbol: continuing without Python plugin support: " + /* + * This is an error because, since we found the Python + * plugin provider shared object, we expect this symbol + * to exist. + */ + BT_LOGE("Cannot find the Python plugin provider loading symbol: " + "%s: continuing without Python plugin support: " "file=\"%s\", symbol=\"%s\"", + g_module_error(), PYTHON_PLUGIN_PROVIDER_FILENAME, PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR); return; @@ -125,45 +144,70 @@ const struct bt_plugin *bt_plugin_set_borrow_plugin_by_index_const( return g_ptr_array_index(plugin_set->plugins, index); } -const struct bt_plugin_set *bt_plugin_find_all_from_static(void) +enum bt_plugin_status bt_plugin_find_all_from_static( + bt_bool fail_on_load_error, + const struct bt_plugin_set **plugin_set_out) { /* bt_plugin_so_create_all_from_static() logs errors */ - return bt_plugin_so_create_all_from_static(); + return bt_plugin_so_create_all_from_static(fail_on_load_error, + (void *) plugin_set_out); } -const struct bt_plugin_set *bt_plugin_find_all_from_file(const char *path) +enum bt_plugin_status bt_plugin_find_all_from_file(const char *path, + bt_bool fail_on_load_error, + const struct bt_plugin_set **plugin_set_out) { - struct bt_plugin_set *plugin_set = NULL; + enum bt_plugin_status status; BT_ASSERT_PRE_NON_NULL(path, "Path"); + BT_ASSERT_PRE_NON_NULL(path, "Plugin set (output)"); BT_LOGI("Creating plugins from file: path=\"%s\"", path); /* Try shared object plugins */ - plugin_set = bt_plugin_so_create_all_from_file(path); - if (plugin_set) { + status = bt_plugin_so_create_all_from_file(path, fail_on_load_error, + (void *) plugin_set_out); + if (status == BT_PLUGIN_STATUS_OK) { + BT_ASSERT(*plugin_set_out); + BT_ASSERT((*plugin_set_out)->plugins->len > 0); + goto end; + } else if (status < 0) { + BT_ASSERT(!*plugin_set_out); goto end; } + BT_ASSERT(status == BT_PLUGIN_STATUS_NOT_FOUND); + BT_ASSERT(!*plugin_set_out); + /* Try Python plugins if support is available */ init_python_plugin_provider(); if (bt_plugin_python_create_all_from_file_sym) { - plugin_set = bt_plugin_python_create_all_from_file_sym(path); - if (plugin_set) { + status = bt_plugin_python_create_all_from_file_sym(path, + fail_on_load_error, (void *) plugin_set_out); + if (status == BT_PLUGIN_STATUS_OK) { + BT_ASSERT(*plugin_set_out); + BT_ASSERT((*plugin_set_out)->plugins->len > 0); + goto end; + } else if (status < 0) { + BT_ASSERT(!*plugin_set_out); goto end; } + + BT_ASSERT(status == BT_PLUGIN_STATUS_NOT_FOUND); + BT_ASSERT(!*plugin_set_out); } end: - if (plugin_set) { + if (status == BT_PLUGIN_STATUS_OK) { BT_LOGI("Created %u plugins from file: " "path=\"%s\", count=%u, plugin-set-addr=%p", - plugin_set->plugins->len, path, - plugin_set->plugins->len, plugin_set); - } else { + (*plugin_set_out)->plugins->len, path, + (*plugin_set_out)->plugins->len, + *plugin_set_out); + } else if (status == BT_PLUGIN_STATUS_NOT_FOUND) { BT_LOGI("Found no plugins in file: path=\"%s\"", path); } - return plugin_set; + return status; } static void destroy_gstring(void *data) @@ -171,7 +215,8 @@ static void destroy_gstring(void *data) g_string_free(data, TRUE); } -const struct bt_plugin *bt_plugin_find(const char *plugin_name) +enum bt_plugin_status bt_plugin_find(const char *plugin_name, + bt_bool fail_on_load_error, const struct bt_plugin **plugin_out) { const char *system_plugin_dir; char *home_plugin_dir = NULL; @@ -180,14 +225,17 @@ const struct bt_plugin *bt_plugin_find(const char *plugin_name) const struct bt_plugin_set *plugin_set = NULL; GPtrArray *dirs = NULL; int ret; + enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; size_t i, j; BT_ASSERT_PRE_NON_NULL(plugin_name, "Name"); + BT_ASSERT_PRE_NON_NULL(plugin_out, "Plugin (output)"); BT_LOGI("Finding named plugin in standard directories and built-in plugins: " "name=\"%s\"", plugin_name); dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring); if (!dirs) { BT_LOGE_STR("Failed to allocate a GPtrArray."); + status = BT_PLUGIN_STATUS_NOMEM; goto end; } @@ -210,17 +258,18 @@ const struct bt_plugin *bt_plugin_find(const char *plugin_name) ret = bt_common_append_plugin_path_dirs(envvar, dirs); if (ret) { BT_LOGE_STR("Failed to append plugin path to array of directories."); + status = BT_PLUGIN_STATUS_NOMEM; goto end; } } home_plugin_dir = bt_common_get_home_plugin_path(BT_LOG_OUTPUT_LEVEL); if (home_plugin_dir) { - GString *home_plugin_dir_str = - g_string_new(home_plugin_dir); + GString *home_plugin_dir_str = g_string_new(home_plugin_dir); if (!home_plugin_dir_str) { BT_LOGE_STR("Failed to allocate a GString."); + status = BT_PLUGIN_STATUS_NOMEM; goto end; } @@ -234,6 +283,7 @@ const struct bt_plugin *bt_plugin_find(const char *plugin_name) if (!system_plugin_dir_str) { BT_LOGE_STR("Failed to allocate a GString."); + status = BT_PLUGIN_STATUS_NOMEM; goto end; } @@ -256,13 +306,21 @@ const struct bt_plugin *bt_plugin_find(const char *plugin_name) } /* bt_plugin_find_all_from_dir() logs details/errors */ - plugin_set = bt_plugin_find_all_from_dir(dir->str, BT_FALSE); - if (!plugin_set) { + status = bt_plugin_find_all_from_dir(dir->str, BT_FALSE, + fail_on_load_error, &plugin_set); + if (status < 0) { + BT_ASSERT(!plugin_set); + goto end; + } else if (status == BT_PLUGIN_STATUS_NOT_FOUND) { + BT_ASSERT(!plugin_set); BT_LOGI("No plugins found in directory: path=\"%s\"", dir->str); continue; } + BT_ASSERT(status == BT_PLUGIN_STATUS_OK); + BT_ASSERT(plugin_set); + for (j = 0; j < plugin_set->plugins->len; j++) { const struct bt_plugin *candidate_plugin = g_ptr_array_index(plugin_set->plugins, j); @@ -271,8 +329,8 @@ const struct bt_plugin *bt_plugin_find(const char *plugin_name) plugin_name) == 0) { BT_LOGI("Plugin found in directory: name=\"%s\", path=\"%s\"", plugin_name, dir->str); - plugin = candidate_plugin; - bt_object_get_no_null_check(plugin); + *plugin_out = candidate_plugin; + bt_object_get_no_null_check(*plugin_out); goto end; } } @@ -281,24 +339,39 @@ const struct bt_plugin *bt_plugin_find(const char *plugin_name) plugin_name, dir->str); } - bt_object_put_ref(plugin_set); - plugin_set = bt_plugin_find_all_from_static(); - if (plugin_set) { - for (j = 0; j < plugin_set->plugins->len; j++) { - const struct bt_plugin *candidate_plugin = - g_ptr_array_index(plugin_set->plugins, j); + BT_OBJECT_PUT_REF_AND_RESET(plugin_set); + status = bt_plugin_find_all_from_static(fail_on_load_error, + &plugin_set); + if (status < 0) { + BT_ASSERT(!plugin_set); + goto end; + } - if (strcmp(bt_plugin_get_name(candidate_plugin), - plugin_name) == 0) { - BT_LOGI("Plugin found in built-in plugins: " - "name=\"%s\"", plugin_name); - plugin = candidate_plugin; - bt_object_get_no_null_check(plugin); - goto end; - } + if (status == BT_PLUGIN_STATUS_NOT_FOUND) { + BT_ASSERT(!plugin_set); + BT_LOGI_STR("No plugins found in built-in plugins."); + goto end; + } + + BT_ASSERT(status == BT_PLUGIN_STATUS_OK); + BT_ASSERT(plugin_set); + + for (j = 0; j < plugin_set->plugins->len; j++) { + const struct bt_plugin *candidate_plugin = + g_ptr_array_index(plugin_set->plugins, j); + + if (strcmp(bt_plugin_get_name(candidate_plugin), + plugin_name) == 0) { + BT_LOGI("Plugin found in built-in plugins: " + "name=\"%s\"", plugin_name); + *plugin_out = candidate_plugin; + bt_object_get_no_null_check(*plugin_out); + goto end; } } + status = BT_PLUGIN_STATUS_NOT_FOUND; + end: free(home_plugin_dir); bt_object_put_ref(plugin_set); @@ -307,28 +380,30 @@ end: g_ptr_array_free(dirs, TRUE); } - if (plugin) { + if (status == BT_PLUGIN_STATUS_OK) { BT_LIB_LOGI("Found plugin in standard directories and built-in plugins: " "%!+l", plugin); - } else { + } else if (status == BT_PLUGIN_STATUS_NOT_FOUND) { BT_LOGI("No plugin found in standard directories and built-in plugins: " "name=\"%s\"", plugin_name); } - return plugin; + return status; } static struct { pthread_mutex_t lock; struct bt_plugin_set *plugin_set; bool recurse; + bool fail_on_load_error; + enum bt_plugin_status status; } append_all_from_dir_info = { .lock = PTHREAD_MUTEX_INITIALIZER }; static -int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag, - struct FTW *s) +int nftw_append_all_from_dir(const char *file, + const struct stat *sb, int flag, struct FTW *s) { int ret = 0; const char *name = file + s->base; @@ -341,7 +416,7 @@ int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag, switch (flag) { case FTW_F: { - const struct bt_plugin_set *plugins_from_file; + const struct bt_plugin_set *plugins_from_file = NULL; if (name[0] == '.') { /* Skip hidden files */ @@ -349,11 +424,15 @@ int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag, goto end; } - plugins_from_file = bt_plugin_find_all_from_file(file); - - if (plugins_from_file) { + append_all_from_dir_info.status = + bt_plugin_find_all_from_file(file, + append_all_from_dir_info.fail_on_load_error, + &plugins_from_file); + if (append_all_from_dir_info.status == BT_PLUGIN_STATUS_OK) { size_t j; + BT_ASSERT(plugins_from_file); + for (j = 0; j < plugins_from_file->plugins->len; j++) { struct bt_plugin *plugin = g_ptr_array_index(plugins_from_file->plugins, j); @@ -367,12 +446,26 @@ int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag, } bt_object_put_ref(plugins_from_file); + goto end; + } else if (append_all_from_dir_info.status < 0) { + /* bt_plugin_find_all_from_file() logs errors */ + BT_ASSERT(!plugins_from_file); + ret = -1; + goto end; } + + /* + * Not found in this file: this is no an error; continue + * walking the directories. + */ + BT_ASSERT(!plugins_from_file); + BT_ASSERT(append_all_from_dir_info.status == + BT_PLUGIN_STATUS_NOT_FOUND); break; } case FTW_DNR: /* Continue to next file / directory. */ - BT_LOGW("Cannot enter directory: continuing: path=\"%s\"", file); + BT_LOGI("Cannot enter directory: continuing: path=\"%s\"", file); break; case FTW_NS: /* Continue to next file / directory. */ @@ -387,10 +480,11 @@ end: static enum bt_plugin_status bt_plugin_create_append_all_from_dir( struct bt_plugin_set *plugin_set, const char *path, - bt_bool recurse) + bt_bool recurse, bt_bool fail_on_load_error) { int nftw_flags = FTW_PHYS; - enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK; + int ret; + enum bt_plugin_status status; BT_ASSERT(plugin_set); BT_ASSERT(path); @@ -398,50 +492,87 @@ enum bt_plugin_status bt_plugin_create_append_all_from_dir( pthread_mutex_lock(&append_all_from_dir_info.lock); append_all_from_dir_info.plugin_set = plugin_set; append_all_from_dir_info.recurse = recurse; + append_all_from_dir_info.status = BT_PLUGIN_STATUS_OK; + append_all_from_dir_info.fail_on_load_error = fail_on_load_error; ret = nftw(path, nftw_append_all_from_dir, APPEND_ALL_FROM_DIR_NFDOPEN_MAX, nftw_flags); + append_all_from_dir_info.plugin_set = NULL; + status = append_all_from_dir_info.status; pthread_mutex_unlock(&append_all_from_dir_info.lock); - if (ret != 0) { - BT_LOGW_ERRNO("Cannot open directory", ": path=\"%s\"", path); - ret = BT_PLUGIN_STATUS_ERROR; + if (ret) { + BT_LOGW_ERRNO("Failed to walk directory", + ": path=\"%s\", recurse=%d", + path, recurse); + status = BT_PLUGIN_STATUS_ERROR; + goto end; + } + + if (status == BT_PLUGIN_STATUS_NOT_FOUND) { + /* + * We're just appending in this function; even if + * nothing was found, it's still okay from the caller's + * perspective. + */ + status = BT_PLUGIN_STATUS_OK; } +end: return ret; } -const struct bt_plugin_set *bt_plugin_find_all_from_dir(const char *path, - bt_bool recurse) +enum bt_plugin_status bt_plugin_find_all_from_dir(const char *path, + bt_bool recurse, bt_bool fail_on_load_error, + const struct bt_plugin_set **plugin_set_out) { - struct bt_plugin_set *plugin_set; - enum bt_plugin_status status; + enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; + BT_ASSERT_PRE_NON_NULL(plugin_set_out, "Plugin set (output)"); BT_LOGI("Creating all plugins in directory: path=\"%s\", recurse=%d", path, recurse); - plugin_set = bt_plugin_set_create(); - if (!plugin_set) { + *plugin_set_out = bt_plugin_set_create(); + if (!*plugin_set_out) { BT_LOGE_STR("Cannot create empty plugin set."); + status = BT_PLUGIN_STATUS_NOMEM; goto error; } - /* Append found plugins to array */ - status = bt_plugin_create_append_all_from_dir(plugin_set, path, - recurse); + /* + * Append found plugins to array (never returns + * `BT_PLUGIN_STATUS_NOT_FOUND`) + */ + status = bt_plugin_create_append_all_from_dir((void *) *plugin_set_out, + path, recurse, fail_on_load_error); if (status < 0) { + /* + * bt_plugin_create_append_all_from_dir() handles + * `fail_on_load_error`, so this is a "real" error. + */ BT_LOGW("Cannot append plugins found in directory: " "path=\"%s\", status=%s", path, bt_plugin_status_string(status)); goto error; } + BT_ASSERT(status == BT_PLUGIN_STATUS_OK); + + if ((*plugin_set_out)->plugins->len == 0) { + /* Nothing was appended: not found */ + BT_LOGI("No plugins found in directory: path=\"%s\"", path); + status = BT_PLUGIN_STATUS_NOT_FOUND; + goto error; + } + BT_LOGI("Created %u plugins from directory: count=%u, path=\"%s\"", - plugin_set->plugins->len, plugin_set->plugins->len, path); + (*plugin_set_out)->plugins->len, + (*plugin_set_out)->plugins->len, path); goto end; error: - BT_OBJECT_PUT_REF_AND_RESET(plugin_set); + BT_ASSERT(status != BT_PLUGIN_STATUS_OK); + BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out); end: - return plugin_set; + return status; } const char *bt_plugin_get_name(const struct bt_plugin *plugin) diff --git a/src/lib/plugin/plugin.h b/src/lib/plugin/plugin.h index ed2fc4a7..46b2b117 100644 --- a/src/lib/plugin/plugin.h +++ b/src/lib/plugin/plugin.h @@ -45,12 +45,6 @@ enum bt_plugin_type { BT_PLUGIN_TYPE_PYTHON = 1, }; -enum bt_plugin_status { - BT_PLUGIN_STATUS_OK = 0, - BT_PLUGIN_STATUS_ERROR = -1, - BT_PLUGIN_STATUS_NOMEM = -12, -}; - struct bt_plugin { struct bt_object base; enum bt_plugin_type type; @@ -99,8 +93,12 @@ const char *bt_plugin_status_string(enum bt_plugin_status status) switch (status) { case BT_PLUGIN_STATUS_OK: return "BT_PLUGIN_STATUS_OK"; + case BT_PLUGIN_STATUS_NOT_FOUND: + return "BT_PLUGIN_STATUS_NOT_FOUND"; case BT_PLUGIN_STATUS_ERROR: return "BT_PLUGIN_STATUS_ERROR"; + case BT_PLUGIN_STATUS_LOADING_ERROR: + return "BT_PLUGIN_STATUS_LOADING_ERROR"; case BT_PLUGIN_STATUS_NOMEM: return "BT_PLUGIN_STATUS_NOMEM"; default: diff --git a/src/python-plugin-provider/python-plugin-provider.c b/src/python-plugin-provider/python-plugin-provider.c index 6f775cb0..42cc642f 100644 --- a/src/python-plugin-provider/python-plugin-provider.c +++ b/src/python-plugin-provider/python-plugin-provider.c @@ -53,16 +53,23 @@ enum python_state { /* init_python() called once without success */ PYTHON_STATE_CANNOT_INITIALIZE, + + /* + * init_python() called, but environment variable asks the + * Python interpreter not to be loaded. + */ + PYTHON_STATE_WONT_INITIALIZE, } python_state = PYTHON_STATE_NOT_INITED; static PyObject *py_try_load_plugin_module_func = NULL; static bool python_was_initialized_by_us; static -void print_python_traceback_warn(void) +void print_python_traceback(int log_level) { - if (BT_LOG_ON_WARN && Py_IsInitialized() && PyErr_Occurred()) { - BT_LOGW_STR("Exception occured: traceback: "); + if (BT_LOG_ON(log_level) && Py_IsInitialized() && PyErr_Occurred()) { + BT_LOG_WRITE(log_level, BT_LOG_TAG, + "Exception occured: Python traceback: "); PyErr_Print(); } } @@ -96,7 +103,7 @@ void init_python(void) dis_python_env = getenv("BABELTRACE_DISABLE_PYTHON_PLUGINS"); if (dis_python_env && strcmp(dis_python_env, "1") == 0) { BT_LOGI_STR("Python plugin support is disabled because `BABELTRACE_DISABLE_PYTHON_PLUGINS=1`."); - python_state = PYTHON_STATE_CANNOT_INITIALIZE; + python_state = PYTHON_STATE_WONT_INITIALIZE; goto end; } @@ -113,7 +120,7 @@ void init_python(void) py_bt2_py_plugin_mod = PyImport_ImportModule("bt2.py_plugin"); if (!py_bt2_py_plugin_mod) { - BT_LOGI_STR("Cannot import bt2.py_plugin Python module: Python plugin support is disabled."); + BT_LOGW_STR("Cannot import bt2.py_plugin Python module: Python plugin support is disabled."); python_state = PYTHON_STATE_CANNOT_INITIALIZE; goto end; } @@ -121,7 +128,7 @@ void init_python(void) py_try_load_plugin_module_func = PyObject_GetAttrString(py_bt2_py_plugin_mod, "_try_load_plugin_module"); if (!py_try_load_plugin_module_func) { - BT_LOGI_STR("Cannot get _try_load_plugin_module attribute from bt2.py_plugin Python module: Python plugin support is disabled."); + BT_LOGW_STR("Cannot get _try_load_plugin_module attribute from bt2.py_plugin Python module: Python plugin support is disabled."); python_state = PYTHON_STATE_CANNOT_INITIALIZE; goto end; } @@ -135,7 +142,7 @@ end: } #endif - print_python_traceback_warn(); + print_python_traceback(BT_LOG_WARN); pyerr_clear(); Py_XDECREF(py_bt2_py_plugin_mod); return; @@ -157,9 +164,10 @@ void fini_python(void) { } static -bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) +enum bt_plugin_status bt_plugin_from_python_plugin_info(PyObject *plugin_info, + bool fail_on_load_error, bt_plugin **plugin_out) { - bt_plugin *plugin = NULL; + enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; PyObject *py_name = NULL; PyObject *py_author = NULL; PyObject *py_description = NULL; @@ -172,72 +180,111 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) const char *license = NULL; unsigned int major = 0, minor = 0, patch = 0; const char *version_extra = NULL; - int ret; + BT_ASSERT(plugin_out); + *plugin_out = NULL; BT_ASSERT(plugin_info); BT_ASSERT(python_state == PYTHON_STATE_FULLY_INITIALIZED); py_name = PyObject_GetAttrString(plugin_info, "name"); if (!py_name) { - BT_LOGW("Cannot find `name` attribute in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot find `name` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } py_author = PyObject_GetAttrString(plugin_info, "author"); if (!py_author) { - BT_LOGW("Cannot find `author` attribute in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot find `author` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } py_description = PyObject_GetAttrString(plugin_info, "description"); if (!py_description) { - BT_LOGW("Cannot find `desciption` attribute in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot find `desciption` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } py_license = PyObject_GetAttrString(plugin_info, "license"); if (!py_license) { - BT_LOGW("Cannot find `license` attribute in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot find `license` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } py_version = PyObject_GetAttrString(plugin_info, "version"); if (!py_version) { - BT_LOGW("Cannot find `version` attribute in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot find `version` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } py_comp_class_addrs = PyObject_GetAttrString(plugin_info, "comp_class_addrs"); if (!py_comp_class_addrs) { - BT_LOGW("Cannot find `comp_class_addrs` attribute in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot find `comp_class_addrs` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } if (PyUnicode_Check(py_name)) { name = PyUnicode_AsUTF8(py_name); if (!name) { - BT_LOGW("Cannot decode Python plugin name string: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot decode Python plugin name string: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? + BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } } else { /* Plugin name is mandatory */ - BT_LOGW("Plugin name is not a string: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Plugin name is not a string: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } if (PyUnicode_Check(py_author)) { author = PyUnicode_AsUTF8(py_author); if (!author) { - BT_LOGW("Cannot decode Python plugin author string: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot decode Python plugin author string: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? + BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } } @@ -245,8 +292,13 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) if (PyUnicode_Check(py_description)) { description = PyUnicode_AsUTF8(py_description); if (!description) { - BT_LOGW("Cannot decode Python plugin description string: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot decode Python plugin description string: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? + BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } } @@ -254,8 +306,13 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) if (PyUnicode_Check(py_license)) { license = PyUnicode_AsUTF8(py_license); if (!license) { - BT_LOGW("Cannot decode Python plugin license string: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot decode Python plugin license string: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? + BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } } @@ -284,8 +341,13 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) if (PyErr_Occurred()) { /* Overflow error, most probably */ - BT_LOGW("Invalid Python plugin version format: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Invalid Python plugin version format: " "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? + BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } } @@ -298,35 +360,41 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) if (PyUnicode_Check(py_extra)) { version_extra = PyUnicode_AsUTF8(py_extra); if (!version_extra) { - BT_LOGW("Cannot decode Python plugin version's extra string: " - "py-plugin-info-addr=%p", plugin_info); + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot decode Python plugin version's extra string: " + "py-plugin-info-addr=%p", plugin_info); + status = fail_on_load_error ? + BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } } } } - plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_PYTHON); - if (!plugin) { + *plugin_out = bt_plugin_create_empty(BT_PLUGIN_TYPE_PYTHON); + if (!*plugin_out) { BT_LOGE_STR("Cannot create empty plugin object."); + status = BT_PLUGIN_STATUS_NOMEM; goto error; } - bt_plugin_set_name(plugin, name); + bt_plugin_set_name(*plugin_out, name); if (description) { - bt_plugin_set_description(plugin, description); + bt_plugin_set_description(*plugin_out, description); } if (author) { - bt_plugin_set_author(plugin, author); + bt_plugin_set_author(*plugin_out, author); } if (license) { - bt_plugin_set_license(plugin, license); + bt_plugin_set_license(*plugin_out, license); } - bt_plugin_set_version(plugin, major, minor, patch, version_extra); + bt_plugin_set_version(*plugin_out, major, minor, patch, version_extra); if (PyList_Check(py_comp_class_addrs)) { size_t i; @@ -341,27 +409,36 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) if (PyLong_Check(py_comp_class_addr)) { comp_class = PyLong_AsVoidPtr(py_comp_class_addr); } else { - BT_LOGW("Component class address is not an integer in Python plugin info object: " + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Component class address is not an integer in Python plugin info object: " "py-plugin-info-addr=%p, index=%zu", plugin_info, i); + + if (fail_on_load_error) { + status = BT_PLUGIN_STATUS_LOADING_ERROR; + goto error; + } + continue; } - ret = bt_plugin_add_component_class(plugin, comp_class); - if (ret < 0) { + status = bt_plugin_add_component_class(*plugin_out, + comp_class); + if (status < 0) { BT_LOGE("Cannot add component class to plugin: " "py-plugin-info-addr=%p, " "plugin-addr=%p, plugin-name=\"%s\", " "comp-class-addr=%p, " "comp-class-name=\"%s\", " "comp-class-type=%s", - plugin_info, - plugin, bt_plugin_get_name(plugin), + plugin_info, *plugin_out, + bt_plugin_get_name(*plugin_out), comp_class, bt_component_class_get_name(comp_class), bt_component_class_type_string( bt_component_class_get_type(comp_class))); - continue; + goto error; } } } @@ -369,9 +446,10 @@ bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) goto end; error: - print_python_traceback_warn(); + BT_ASSERT(status != BT_PLUGIN_STATUS_OK); + print_python_traceback(fail_on_load_error ? BT_LOG_WARN : BT_LOG_INFO); pyerr_clear(); - BT_OBJECT_PUT_REF_AND_RESET(plugin); + BT_OBJECT_PUT_REF_AND_RESET(*plugin_out); end: Py_XDECREF(py_name); @@ -380,17 +458,18 @@ end: Py_XDECREF(py_license); Py_XDECREF(py_version); Py_XDECREF(py_comp_class_addrs); - return plugin; + return status; } G_MODULE_EXPORT -bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path) +enum bt_plugin_status bt_plugin_python_create_all_from_file(const char *path, + bool fail_on_load_error, struct bt_plugin_set **plugin_set_out) { - bt_plugin_set *plugin_set = NULL; bt_plugin *plugin = NULL; PyObject *py_plugin_info = NULL; gchar *basename = NULL; size_t path_len; + enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; BT_ASSERT(path); @@ -400,6 +479,15 @@ bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path) * here because we already know Python cannot be fully * initialized. */ + status = BT_PLUGIN_STATUS_ERROR; + goto error; + } else if (python_state == PYTHON_STATE_WONT_INITIALIZE) { + /* + * This is not an error: the environment requires that + * Python plugins are disabled, so it's simply not + * found. + */ + status = BT_PLUGIN_STATUS_NOT_FOUND; goto error; } @@ -412,13 +500,15 @@ bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path) PYTHON_PLUGIN_FILE_EXT, PYTHON_PLUGIN_FILE_EXT_LEN) != 0) { BT_LOGI("Skipping non-Python file: path=\"%s\"", path); + status = BT_PLUGIN_STATUS_NOT_FOUND; goto error; } /* File name starts with `bt_plugin_` */ basename = g_path_get_basename(path); if (!basename) { - BT_LOGW("Cannot get path's basename: path=\"%s\"", path); + BT_LOGE("Cannot get path's basename: path=\"%s\"", path); + status = BT_PLUGIN_STATUS_ERROR; goto error; } @@ -426,6 +516,7 @@ bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path) PYTHON_PLUGIN_FILE_PREFIX_LEN) != 0) { BT_LOGI("Skipping Python file not starting with `%s`: " "path=\"%s\"", PYTHON_PLUGIN_FILE_PREFIX, path); + status = BT_PLUGIN_STATUS_NOT_FOUND; goto error; } @@ -438,13 +529,22 @@ bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path) * this waiting time everytime you load the library. */ init_python(); - if (python_state != PYTHON_STATE_FULLY_INITIALIZED) { + if (python_state == PYTHON_STATE_WONT_INITIALIZE) { + /* + * This is not an error: the environment requires that + * Python plugins are disabled, so it's simply not + * found. + */ + status = BT_PLUGIN_STATUS_NOT_FOUND; + goto error; + } else if (python_state != PYTHON_STATE_FULLY_INITIALIZED) { /* * For some reason we cannot initialize Python, * import the required modules, and get the required * attributes from them. */ - BT_LOGI("Failed to initialize Python interpreter."); + BT_LOGE("Failed to initialize Python interpreter."); + status = BT_PLUGIN_STATUS_ERROR; goto error; } @@ -458,42 +558,61 @@ bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path) py_plugin_info = PyObject_CallFunction(py_try_load_plugin_module_func, "(s)", path); if (!py_plugin_info || py_plugin_info == Py_None) { - BT_LOGW("Cannot load Python plugin: path=\"%s\"", path); - print_python_traceback_warn(); + BT_LOG_WRITE(fail_on_load_error ? + BT_LOG_WARN : BT_LOG_INFO, BT_LOG_TAG, + "Cannot load Python plugin: path=\"%s\"", path); + print_python_traceback(fail_on_load_error ? BT_LOG_WARN : + BT_LOG_INFO); PyErr_Clear(); + status = fail_on_load_error ? BT_PLUGIN_STATUS_LOADING_ERROR : + BT_PLUGIN_STATUS_NOT_FOUND; goto error; } /* * Get bt_plugin from plugin info object. */ - plugin = bt_plugin_from_python_plugin_info(py_plugin_info); - if (!plugin) { + plugin = NULL; + status = bt_plugin_from_python_plugin_info(py_plugin_info, + fail_on_load_error, &plugin); + if (status < 0) { + /* + * bt_plugin_from_python_plugin_info() handles + * `fail_on_load_error`, so this is a "real" error. + */ BT_LOGW("Cannot create plugin object from Python plugin info object: " "path=\"%s\", py-plugin-info-addr=%p", path, py_plugin_info); + BT_ASSERT(!plugin); + goto error; + } else if (status == BT_PLUGIN_STATUS_NOT_FOUND) { + BT_ASSERT(!plugin); goto error; } + BT_ASSERT(status == BT_PLUGIN_STATUS_OK); + BT_ASSERT(plugin); bt_plugin_set_path(plugin, path); - plugin_set = bt_plugin_set_create(); - if (!plugin_set) { + *plugin_set_out = bt_plugin_set_create(); + if (!*plugin_set_out) { BT_LOGE_STR("Cannot create empty plugin set."); + status = BT_PLUGIN_STATUS_NOMEM; goto error; } - bt_plugin_set_add_plugin(plugin_set, plugin); + bt_plugin_set_add_plugin(*plugin_set_out, plugin); BT_LOGD("Created all Python plugins from file: path=\"%s\", " "plugin-addr=%p, plugin-name=\"%s\"", path, plugin, bt_plugin_get_name(plugin)); goto end; error: - BT_OBJECT_PUT_REF_AND_RESET(plugin_set); + BT_ASSERT(status != BT_PLUGIN_STATUS_OK); + BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out); end: bt_plugin_put_ref(plugin); Py_XDECREF(py_plugin_info); g_free(basename); - return plugin_set; + return status; } diff --git a/src/python-plugin-provider/python-plugin-provider.h b/src/python-plugin-provider/python-plugin-provider.h index 1d7aa2ce..a8848c74 100644 --- a/src/python-plugin-provider/python-plugin-provider.h +++ b/src/python-plugin-provider/python-plugin-provider.h @@ -26,6 +26,7 @@ #include extern -struct bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path); +enum bt_plugin_status bt_plugin_python_create_all_from_file(const char *path, + struct bt_plugin_set **plugin_set_out); #endif /* BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H */ diff --git a/tests/bindings/python/bt2/test_plugin.py b/tests/bindings/python/bt2/test_plugin.py index 4df92d07..8384cf31 100644 --- a/tests/bindings/python/bt2/test_plugin.py +++ b/tests/bindings/python/bt2/test_plugin.py @@ -47,9 +47,13 @@ class PluginSetTestCase(unittest.TestCase): class FindPluginsTestCase(unittest.TestCase): - def test_find_none(self): - pset = bt2.find_plugins('/this/does/not/exist/246703df-cb85-46d5-8406-5e8dc4a88b41') - self.assertIsNone(pset) + def test_find_nonexistent_dir(self): + with self.assertRaises(bt2.Error): + bt2.find_plugins('/this/does/not/exist/246703df-cb85-46d5-8406-5e8dc4a88b41') + + def test_find_none_existing_dir(self): + plugins = bt2.find_plugins(_TEST_PLUGIN_PLUGINS_PATH, recurse=False) + self.assertIsNone(plugins) def test_find_dir(self): pset = bt2.find_plugins(_TEST_PLUGIN_PLUGINS_PATH) diff --git a/tests/lib/test_plugin.c b/tests/lib/test_plugin.c index a22d2b27..0bee0447 100644 --- a/tests/lib/test_plugin.c +++ b/tests/lib/test_plugin.c @@ -24,7 +24,7 @@ #include "tap/tap.h" #include "common.h" -#define NR_TESTS 35 +#define NR_TESTS 38 #define NON_EXISTING_PATH "/this/hopefully/does/not/exist/5bc75f8d-0dba-4043-a509-d7984b97e42b.so" /* Those symbols are written to by some test plugins */ @@ -64,17 +64,21 @@ static char *get_test_plugin_path(const char *plugin_dir, static void test_minimal(const char *plugin_dir) { - const bt_plugin_set *plugin_set; + const bt_plugin_set *plugin_set = NULL; const bt_plugin *plugin; char *minimal_path = get_test_plugin_path(plugin_dir, "minimal"); + bt_plugin_status status; BT_ASSERT(minimal_path); diag("minimal plugin test below"); reset_test_plugin_env_vars(); - plugin_set = bt_plugin_find_all_from_file(minimal_path); - ok(plugin_set && bt_plugin_set_get_plugin_count(plugin_set) == 1, + status = bt_plugin_find_all_from_file(minimal_path, BT_FALSE, + &plugin_set); + ok(status == BT_PLUGIN_STATUS_OK, "bt_plugin_find_all_from_file() succeeds with a valid file"); + ok(plugin_set, + "bt_plugin_find_all_from_file() returns a plugin set"); ok(check_env_var("BT_TEST_PLUGIN_INIT_CALLED") == 1, "plugin's initialization function is called during bt_plugin_find_all_from_file()"); ok(bt_plugin_set_get_plugin_count(plugin_set) == 1, @@ -109,7 +113,7 @@ static void test_minimal(const char *plugin_dir) static void test_sfs(const char *plugin_dir) { - const bt_plugin_set *plugin_set; + const bt_plugin_set *plugin_set = NULL; const bt_plugin *plugin; const bt_component_class_sink *sink_comp_class; const bt_component_class_source *source_comp_class; @@ -127,13 +131,15 @@ static void test_sfs(const char *plugin_dir) bt_graph_status graph_ret; bt_query_executor *query_exec = bt_query_executor_create(); int ret; + bt_plugin_status status; BT_ASSERT(query_exec); BT_ASSERT(sfs_path); diag("sfs plugin test below"); - plugin_set = bt_plugin_find_all_from_file(sfs_path); - BT_ASSERT(plugin_set && bt_plugin_set_get_plugin_count(plugin_set) == 1); + status = bt_plugin_find_all_from_file(sfs_path, BT_FALSE, &plugin_set); + BT_ASSERT(status == BT_PLUGIN_STATUS_OK && plugin_set && + bt_plugin_set_get_plugin_count(plugin_set) == 1); plugin = bt_plugin_set_borrow_plugin_by_index_const(plugin_set, 0); ok(bt_plugin_get_version(plugin, &major, &minor, &patch, &extra) == BT_PROPERTY_AVAILABILITY_AVAILABLE, @@ -211,15 +217,22 @@ static void test_sfs(const char *plugin_dir) static void test_create_all_from_dir(const char *plugin_dir) { const bt_plugin_set *plugin_set; + bt_plugin_status status; diag("create from all test below"); - plugin_set = bt_plugin_find_all_from_dir(NON_EXISTING_PATH, BT_FALSE); - ok(!plugin_set, + status = bt_plugin_find_all_from_dir(NON_EXISTING_PATH, BT_FALSE, + BT_FALSE, &plugin_set); + ok(status == BT_PLUGIN_STATUS_ERROR, "bt_plugin_find_all_from_dir() fails with an invalid path"); - plugin_set = bt_plugin_find_all_from_dir(plugin_dir, BT_FALSE); - ok(plugin_set, "bt_plugin_find_all_from_dir() succeeds with a valid path"); + plugin_set = NULL; + status = bt_plugin_find_all_from_dir(plugin_dir, BT_FALSE, BT_FALSE, + &plugin_set); + ok(status == BT_PLUGIN_STATUS_OK, + "bt_plugin_find_all_from_dir() succeeds with a valid path"); + ok(plugin_set, + "bt_plugin_find_all_from_dir() returns a plugin set with a valid path"); /* 2 or 4, if `.la` files are considered or not */ ok(bt_plugin_set_get_plugin_count(plugin_set) == 2 || @@ -234,9 +247,11 @@ static void test_find(const char *plugin_dir) int ret; const bt_plugin *plugin; char *plugin_path; + bt_plugin_status status; - ok(!bt_plugin_find(NON_EXISTING_PATH), - "bt_plugin_find() returns NULL with an unknown plugin name"); + ok(bt_plugin_find(NON_EXISTING_PATH, BT_FALSE, &plugin) == + BT_PLUGIN_STATUS_NOT_FOUND, + "bt_plugin_find() returns BT_PLUGIN_STATUS_NOT_FOUND with an unknown plugin name"); ret = asprintf(&plugin_path, "%s" G_SEARCHPATH_SEPARATOR_S G_DIR_SEPARATOR_S "ec1d09e5-696c-442e-b1c3-f9c6cf7f5958" G_SEARCHPATH_SEPARATOR_S G_SEARCHPATH_SEPARATOR_S @@ -246,9 +261,11 @@ static void test_find(const char *plugin_dir) NON_EXISTING_PATH, plugin_dir); BT_ASSERT(ret > 0 && plugin_path); g_setenv("BABELTRACE_PLUGIN_PATH", plugin_path, 1); - plugin = bt_plugin_find("test_minimal"); - ok(plugin, + plugin = NULL; + status = bt_plugin_find("test_minimal", BT_FALSE, &plugin); + ok(status == BT_PLUGIN_STATUS_OK, "bt_plugin_find() succeeds with a plugin name it can find"); + ok(plugin, "bt_plugin_find() returns a plugin object"); ok(strcmp(bt_plugin_get_author(plugin), "Janine Sutto") == 0, "bt_plugin_find() finds the correct plugin for a given name"); BT_PLUGIN_PUT_REF_AND_RESET(plugin);