#include <babeltrace/plugin/component-factory.h>
#include <babeltrace/plugin/component-factory-internal.h>
+#include <babeltrace/plugin/component-class-internal.h>
+#include <babeltrace/plugin/source-internal.h>
+#include <babeltrace/plugin/sink-internal.h>
#include <babeltrace/babeltrace-internal.h>
#include <babeltrace/compiler.h>
+#include <babeltrace/ref.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
+#include <gmodule.h>
+#include <stdbool.h>
#define NATIVE_PLUGIN_SUFFIX ".so"
#define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
sizeof(LIBTOOL_PLUGIN_SUFFIX))
-static
-void component_destroy(gpointer data)
-{
- g_free(data);
-}
-
-static
-void plugin_destroy(gpointer data)
-{
- struct plugin *plugin = data;
-
- if (plugin->module && g_module_close(plugin->module)) {
- printf_error("Failed to close plugin");
- }
-
- if (plugin->components) {
- g_ptr_array_free(plugin->components, TRUE);
- }
-
- g_free(plugin);
-}
-
-static
-struct plugin *plugin_create(void)
-{
- struct plugin *plugin = g_new0(struct plugin, 1);
-
- if (!plugin) {
- goto end;
- }
-
- plugin->components = g_ptr_array_new_with_free_func(component_destroy);
- if (!plugin->components) {
- g_free(plugin);
- plugin = NULL;
- goto end;
- }
-end:
- return plugin;
-}
-
/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
static
struct dirent *alloc_dirent(const char *path)
return entry;
}
-static
-struct plugin *load_plugin(GModule *module)
-{
- return NULL;
-}
-
static
enum bt_component_factory_status
bt_component_factory_load_file(struct bt_component_factory *factory,
const char *path)
{
enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
+ enum bt_component_status component_status;
size_t path_len;
GModule *module;
- struct plugin *plugin;
+ struct bt_plugin *plugin;
+ bool is_libtool_wrapper = false, is_shared_object = false;
if (!factory || !path) {
ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
* Check if the file ends with a known plugin file type suffix (i.e. .so
* or .la on Linux).
*/
- if (strncmp(NATIVE_PLUGIN_SUFFIX,
- path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
- NATIVE_PLUGIN_SUFFIX_LEN) &&
- strncmp(LIBTOOL_PLUGIN_SUFFIX,
- path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
- LIBTOOL_PLUGIN_SUFFIX_LEN)) {
+ is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
+ path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
+ LIBTOOL_PLUGIN_SUFFIX_LEN);
+ is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
+ path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
+ NATIVE_PLUGIN_SUFFIX_LEN);
+ if (!is_shared_object && !is_libtool_wrapper) {
/* Name indicates that this is not a plugin file. */
ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
goto end;
goto end;
}
- /* Check if the module defines the appropriate entry points */
- plugin = load_plugin(module);
+ /* Load plugin and make sure it defines the required entry points */
+ plugin = bt_plugin_create(module, path);
if (!plugin) {
- /* Not a Babeltrace plugin */
- ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
+ ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
if (!g_module_close(module)) {
printf_error("Module close error: %s",
- g_module_error());
+ g_module_error());
}
goto end;
}
+
+ factory->current_plugin = plugin;
+ component_status = bt_plugin_register_component_classes(plugin,
+ factory);
+ factory->current_plugin = NULL;
+ if (component_status != BT_COMPONENT_STATUS_OK) {
+ switch (component_status) {
+ case BT_COMPONENT_STATUS_NOMEM:
+ ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
+ break;
+ default:
+ ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
+ break;
+ }
+
+ BT_PUT(plugin);
+ goto end;
+ }
end:
return ret;
}
file_path[path_len++] = '/';
}
+ directory = opendir(file_path);
+ if (!directory) {
+ perror("Failed to open plug-in directory");
+ ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
+ goto end;
+ }
+
/* Recursively walk directory */
while (!readdir_r(directory, entry, &result) && result) {
struct stat st;
int stat_ret;
- size_t file_name_len = strlen(result->d_name);
+ size_t file_name_len;
+
+ if (result->d_name[0] == '.') {
+ /* Skip hidden files, . and .. */
+ continue;
+ }
+
+ file_name_len = strlen(result->d_name);
if (path_len + file_name_len >= PATH_MAX) {
continue;
if (S_ISDIR(st.st_mode)) {
ret = bt_component_factory_load_dir_recursive(factory,
- file_path);
+ file_path);
if (ret != BT_COMPONENT_FACTORY_STATUS_OK) {
goto end;
}
}
}
end:
+ if (directory) {
+ if (closedir(directory)) {
+ /*
+ * We don't want to override the error since there is
+ * nothing could do.
+ */
+ perror("Failed to close plug-in directory");
+ }
+ }
free(entry);
free(file_path);
return ret;
}
-void bt_component_factory_destroy(struct bt_component_factory *factory)
+static
+void bt_component_factory_destroy(struct bt_object *obj)
{
- if (!factory) {
- return;
- }
+ struct bt_component_factory *factory = NULL;
+ assert(obj);
+ factory = container_of(obj, struct bt_component_factory, base);
+
+ if (factory->component_classes) {
+ g_ptr_array_free(factory->component_classes, TRUE);
+ }
g_free(factory);
}
-struct bt_component_factory *
-bt_component_factory_create(void)
+struct bt_component_factory *bt_component_factory_create(void)
{
struct bt_component_factory *factory;
goto end;
}
- factory->plugins = g_ptr_array_new_with_free_func(plugin_destroy);
- if (!factory->plugins) {
+ bt_object_init(factory, bt_component_factory_destroy);
+ factory->component_classes = g_ptr_array_new_with_free_func(
+ (GDestroyNotify) bt_put);
+ if (!factory->component_classes) {
goto error;
}
end:
return factory;
error:
- bt_component_factory_destroy(factory);
+ BT_PUT(factory);
+ return factory;
+}
+
+int bt_component_factory_get_component_class_count(
+ struct bt_component_factory *factory)
+{
+ return factory ? factory->component_classes->len : -1;
+}
+
+struct bt_component_class *bt_component_factory_get_component_class_index(
+ struct bt_component_factory *factory, int index)
+{
+ struct bt_component_class *component_class = NULL;
+
+ if (!factory || index < 0 || index >= factory->component_classes->len) {
+ goto end;
+ }
+
+ component_class = bt_get(g_ptr_array_index(
+ factory->component_classes, index));
+end:
+ return component_class;
+}
+
+struct bt_component_class *bt_component_factory_get_component_class(
+ struct bt_component_factory *factory,
+ const char *plugin_name, enum bt_component_type type,
+ const char *component_name)
+{
+ size_t i;
+ struct bt_component_class *component_class = NULL;
+
+ if (!factory || (!plugin_name && !component_name &&
+ type == BT_COMPONENT_TYPE_UNKNOWN)) {
+ /* At least one criterion must be provided. */
+ goto no_match;
+ }
+
+ for (i = 0; i < factory->component_classes->len; i++) {
+ struct bt_plugin *plugin = NULL;
+
+ component_class = g_ptr_array_index(factory->component_classes,
+ i);
+ plugin = bt_component_class_get_plugin(component_class);
+ assert(plugin);
+
+ if (type != BT_COMPONENT_TYPE_UNKNOWN) {
+ if (type != bt_component_class_get_type(
+ component_class)) {
+ continue;
+ }
+ }
+
+ if (plugin_name) {
+ const char *cur_plugin_name = bt_plugin_get_name(
+ plugin);
+
+ assert(cur_plugin_name);
+ if (strcmp(plugin_name, cur_plugin_name)) {
+ continue;
+ }
+ }
+
+ if (component_name) {
+ const char *cur_cc_name = bt_component_class_get_name(
+ component_class);
+
+ assert(cur_cc_name);
+ if (strcmp(component_name, cur_cc_name)) {
+ continue;
+ }
+ }
+
+ /* All criteria met. */
+ goto match;
+ }
+
+no_match:
return NULL;
+match:
+ return bt_get(component_class);
}
enum bt_component_factory_status bt_component_factory_load(
struct bt_component_factory *factory, const char *path)
{
enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
- DIR *directory = NULL;
if (!factory || !path) {
ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
goto end;
}
- directory = opendir(path) ;
- if (!directory) {
- switch (errno) {
- case ENOTDIR:
- /* Try loading as a file. */
- break;
- case ENOENT:
- ret = BT_COMPONENT_FACTORY_STATUS_NOENT;
- goto end;
- default:
- ret = BT_COMPONENT_FACTORY_STATUS_IO;
- goto end;
- }
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ ret = BT_COMPONENT_FACTORY_STATUS_NOENT;
+ goto end;
}
- if (directory) {
+ if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
ret = bt_component_factory_load_dir_recursive(factory, path);
- } else {
+ } else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) ||
+ g_file_test(path, G_FILE_TEST_IS_SYMLINK)) {
ret = bt_component_factory_load_file(factory, path);
+ } else {
+ ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
+ goto end;
}
end:
- if (directory) {
- closedir(directory);
+ return ret;
+}
+
+static
+enum bt_component_factory_status
+add_component_class(struct bt_component_factory *factory, const char *name,
+ const char *description, bt_component_init_cb init,
+ enum bt_component_type type)
+{
+ struct bt_component_class *class;
+ enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
+
+ if (!factory || !name || !init) {
+ ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
+ goto end;
}
+
+ class = bt_component_class_create(type, name, description,
+ factory->current_plugin);
+ g_ptr_array_add(factory->component_classes, class);
+end:
return ret;
}
+
+enum bt_component_factory_status
+bt_component_factory_register_source_component_class(
+ struct bt_component_factory *factory, const char *name,
+ const char *description, bt_component_init_cb init)
+{
+ return add_component_class(factory, name, description, init,
+ BT_COMPONENT_TYPE_SOURCE);
+}
+
+enum bt_component_factory_status
+bt_component_factory_register_sink_component_class(
+ struct bt_component_factory *factory, const char *name,
+ const char *description, bt_component_init_cb init)
+{
+ return add_component_class(factory, name, description, init,
+ BT_COMPONENT_TYPE_SINK);
+}