List detected component classes
[babeltrace.git] / plugins / component-factory.c
index b4ebe3f2ef9f0ac57abae257bdfac92a9f30c63a..65840d4cac79e883b6a025846d2405b099b3d9a2 100644 (file)
 
 #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 LIBTOOL_PLUGIN_SUFFIX ".la"
 #define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
-#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX),\
-                               sizeof(LIBTOOL_PLUGIN_SUFFIX))
-
-static
-void module_close(gpointer data)
-{
-       if (g_module_close((GModule *) data)) {
-               printf_error("Failed to close plugin");
-       }
-}
-
-static
-void factory_destroy(gpointer data)
-{
-       bt_component_factory_destroy((struct bt_component_factory *)data);
-}
+#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
+               sizeof(LIBTOOL_PLUGIN_SUFFIX))
 
 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
 static
@@ -78,8 +70,11 @@ 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 bt_plugin *plugin;
+       bool is_libtool_wrapper = false, is_shared_object = false;
 
        if (!factory || !path) {
                ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
@@ -88,6 +83,7 @@ bt_component_factory_load_file(struct bt_component_factory *factory,
 
        path_len = strlen(path);
        if (path_len <= PLUGIN_SUFFIX_LEN) {
+               ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
                goto end;
        }
 
@@ -96,23 +92,53 @@ bt_component_factory_load_file(struct bt_component_factory *factory,
         * 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)) {
-               /* Not a plugin file. */
+       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;
        }
 
        module = g_module_open(path, 0);
        if (!module) {
                printf_error("Module open error: %s", g_module_error());
+               ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Load plugin and make sure it defines the required entry points */
+       plugin = bt_plugin_create(module, path);
+       if (!plugin) {
+               ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
+               if (!g_module_close(module)) {
+                       printf_error("Module close error: %s",
+                               g_module_error());
+               }
                goto end;
        }
 
-       /* Check if the module defines the appropriate entry points */
+       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;
 }
@@ -151,11 +177,25 @@ bt_component_factory_load_dir_recursive(struct bt_component_factory *factory,
                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;
@@ -173,35 +213,44 @@ bt_component_factory_load_dir_recursive(struct bt_component_factory *factory,
 
                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;
                        }
                } else if (S_ISREG(st.st_mode)) {
-                       ret = bt_component_factory_load_file(factory,
-                               file_path);
-                       if (ret != BT_COMPONENT_FACTORY_STATUS_OK) {
-                               goto end;
-                       }
+                       bt_component_factory_load_file(factory, file_path);
                }
        }
 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;
 
@@ -210,56 +259,162 @@ bt_component_factory_create(void)
                goto end;
        }
 
-       factory->modules = g_ptr_array_new_with_free_func(module_close);
-       if (!factory->modules) {
-               goto error;
-       }
-
-       factory->components = g_ptr_array_new_with_free_func(factory_destroy);
-       if (factory->components) {
+       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);
+}
This page took 0.05209 seconds and 4 git commands to generate.