Add bt_plugin_create_from_name()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 7 Feb 2017 06:22:10 +0000 (01:22 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:37 +0000 (12:57 -0400)
This new function creates a new bt_plugin object from a simple plugin
name. It returns the first plugin which has the given name within the
following directories, in this order:

1. The colon-separated directories listed in the BABELTRACE_PLUGIN_PATH
   environment variable.
2. ~/.local/lib/babeltrace/plugins
3. $libdir/babeltrace/plugins, where $libdir is the value of --libdir
   at configure time (/usr/local/lib by default, typically /usr/lib
   when installed through a distribution).
4. The statically built-in plugins.

This makes it easier for any application using libbabeltrace to find a
Babeltrace plugin in a standard way without having to know the exact
location of the plugin file:

    ctf_plugin = bt_plugin_create_from_name("ctf");

Since babeltrace(1) also does this search, but has a --plugin-path
parameter to insert other directories at a specific place within the
search list, the common functions are put in the new
common/libbabeltrace-common.la convenience library. This is where new
(and existing) common functions between libbabeltrace and other parts of
the source tree (converter, plugins, etc.) should be put.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Makefile.am
common/Makefile.am [new file with mode: 0644]
common/common.c [new file with mode: 0644]
configure.ac
converter/Makefile.am
converter/babeltrace-cfg.c
include/Makefile.am
include/babeltrace/common-internal.h [new file with mode: 0644]
include/babeltrace/plugin/plugin.h
lib/Makefile.am
lib/plugin/plugin.c

index 0544bd1684aaee0d03688d435763fa9edee2e09e..4b517db724308208f4c699a68daf8cffb9a15841 100644 (file)
@@ -2,7 +2,7 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = include types compat lib formats plugins converter bindings tests doc extras
+SUBDIRS = include common types compat lib formats plugins converter bindings tests doc extras
 
 dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \
                std-ext-lib.txt README
diff --git a/common/Makefile.am b/common/Makefile.am
new file mode 100644 (file)
index 0000000..a4543dd
--- /dev/null
@@ -0,0 +1,7 @@
+AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include \
+       -DINSTALL_LIBDIR=\"$(libdir)\"
+
+
+noinst_LTLIBRARIES = libbabeltrace-common.la
+
+libbabeltrace_common_la_SOURCES = common.c
diff --git a/common/common.c b/common/common.c
new file mode 100644 (file)
index 0000000..47186e1
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Babeltrace common functions
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <assert.h>
+#include <glib.h>
+#include <babeltrace/babeltrace-internal.h>
+
+#define SYSTEM_PLUGIN_PATH     INSTALL_LIBDIR "/babeltrace/plugins"
+#define HOME_ENV_VAR           "HOME"
+#define HOME_PLUGIN_SUBPATH    "/.local/lib/babeltrace/plugins"
+
+BT_HIDDEN
+const char *bt_common_get_system_plugin_path(void)
+{
+       return SYSTEM_PLUGIN_PATH;
+}
+
+BT_HIDDEN
+bool bt_common_is_setuid_setgid(void)
+{
+       return (geteuid() != getuid() || getegid() != getgid());
+}
+
+static char *bt_secure_getenv(const char *name)
+{
+       if (bt_common_is_setuid_setgid()) {
+               printf_error("Disregarding %s environment variable for setuid/setgid binary",
+                       name);
+               return NULL;
+       }
+       return getenv(name);
+}
+
+static const char *get_home_dir(void)
+{
+       char *val = NULL;
+       struct passwd *pwd;
+
+       val = bt_secure_getenv(HOME_ENV_VAR);
+       if (val) {
+               goto end;
+       }
+       /* Fallback on password file. */
+       pwd = getpwuid(getuid());
+       if (!pwd) {
+               goto end;
+       }
+       val = pwd->pw_dir;
+end:
+       return val;
+}
+
+BT_HIDDEN
+char *bt_common_get_home_plugin_path(void)
+{
+       char *path = NULL;
+       const char *home_dir;
+
+       home_dir = get_home_dir();
+       if (!home_dir) {
+               goto end;
+       }
+
+       if (strlen(home_dir) + strlen(HOME_PLUGIN_SUBPATH) + 1 >= PATH_MAX) {
+               printf_error("Home directory path is too long: `%s`\n",
+                       home_dir);
+               goto end;
+       }
+
+       path = malloc(PATH_MAX);
+       if (!path) {
+               goto end;
+       }
+
+       strcpy(path, home_dir);
+       strcat(path, HOME_PLUGIN_SUBPATH);
+
+end:
+       return path;
+}
+
+BT_HIDDEN
+int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs)
+{
+       int ret = 0;
+       const char *at;
+       const char *end;
+       size_t init_dirs_len;
+
+       assert(dirs);
+       init_dirs_len = dirs->len;
+
+       if (!paths) {
+               /* Nothing to append */
+               goto end;
+       }
+
+       at = paths;
+       end = paths + strlen(paths);
+
+       while (at < end) {
+               GString *path;
+               const char *next_colon;
+
+               next_colon = strchr(at, ':');
+               if (next_colon == at) {
+                       /*
+                        * Empty path: try next character (supported
+                        * to conform to the typical parsing of $PATH).
+                        */
+                       at++;
+                       continue;
+               } else if (!next_colon) {
+                       /* No more colon: use the remaining */
+                       next_colon = paths + strlen(paths);
+               }
+
+               path = g_string_new(NULL);
+               if (!path) {
+                       goto error;
+               }
+
+               g_string_append_len(path, at, next_colon - at);
+               at = next_colon + 1;
+               g_ptr_array_add(dirs, path);
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+       /* Remove the new entries in dirs */
+       while (dirs->len > init_dirs_len) {
+               g_ptr_array_remove_index(dirs, init_dirs_len);
+       }
+
+end:
+       return ret;
+}
index f4902254f872b3b67ab8ef0c1ddf89b7b7151f6b..de5553b94a141f86e6504082b5ab82874fdc552d 100644 (file)
@@ -438,6 +438,7 @@ AS_IF([test "x$enable_api_doc" = "xyes"], [
 AC_CONFIG_FILES([
        Makefile
        types/Makefile
+       common/Makefile
        compat/Makefile
        formats/Makefile
        formats/ctf/Makefile
index 6c8db944ab0923f0dd33f6b0520fbb066a605745..35c64ec5df7a923bf24151410f0bb3c1f9043135 100644 (file)
@@ -25,7 +25,8 @@ babeltrace_bin_LDADD = \
        $(top_builddir)/formats/ctf-text/libbabeltrace-ctf-text.la \
        $(top_builddir)/formats/ctf-metadata/libbabeltrace-ctf-metadata.la \
        $(top_builddir)/formats/bt-dummy/libbabeltrace-dummy.la \
-       $(top_builddir)/formats/lttng-live/libbabeltrace-lttng-live.la
+       $(top_builddir)/formats/lttng-live/libbabeltrace-lttng-live.la \
+       $(top_builddir)/common/libbabeltrace-common.la
 
 if ENABLE_DEBUG_INFO
 babeltrace_bin_LDADD += $(top_builddir)/lib/libdebug-info.la
index 5811f4447d06ab955853196d903717ea91224442..608b65484df49c06490a7c3ea23795607a9650a3 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdbool.h>
 #include <inttypes.h>
 #include <babeltrace/babeltrace.h>
+#include <babeltrace/common-internal.h>
 #include <babeltrace/values.h>
 #include <popt.h>
 #include <glib.h>
 #include <pwd.h>
 #include "babeltrace-cfg.h"
 
-#define SYSTEM_PLUGIN_PATH             INSTALL_LIBDIR "/babeltrace/plugins"
 #define DEFAULT_SOURCE_COMPONENT_NAME  "ctf.fs"
 #define DEFAULT_SINK_COMPONENT_NAME    "text.text"
-#define HOME_ENV_VAR                   "HOME"
-#define HOME_SUBPATH                   "/.babeltrace/plugins"
 
 /*
  * Error printf() macro which prepends "Error: " the first time it's
@@ -970,6 +968,11 @@ bool is_setuid_setgid(void)
        return (geteuid() != getuid() || getegid() != getgid());
 }
 
+static void destroy_gstring(void *data)
+{
+       g_string_free(data, TRUE);
+}
+
 /*
  * Extracts the various paths from the string arg, delimited by ':',
  * and converts them to an array value object.
@@ -982,46 +985,31 @@ static
 enum bt_value_status plugin_paths_from_arg(struct bt_value *plugin_paths,
                const char *arg)
 {
-       const char *at = arg;
-       const char *end = arg + strlen(arg);
+       enum bt_value_status status = BT_VALUE_STATUS_OK;
+       GPtrArray *dirs = g_ptr_array_new_with_free_func(destroy_gstring);
+       int ret;
+       size_t i;
 
-       while (at < end) {
-               int ret;
-               GString *path;
-               const char *next_colon;
+       if (!dirs) {
+               status = BT_VALUE_STATUS_ERROR;
+               goto end;
+       }
 
-               next_colon = strchr(at, ':');
-               if (next_colon == at) {
-                       /*
-                        * Empty path: try next character (supported
-                        * to conform to the typical parsing of $PATH).
-                        */
-                       at++;
-                       continue;
-               } else if (!next_colon) {
-                       /* No more colon: use the remaining */
-                       next_colon = arg + strlen(arg);
-               }
+       ret = bt_common_append_plugin_path_dirs(arg, dirs);
+       if (ret) {
+               status = BT_VALUE_STATUS_ERROR;
+               goto end;
+       }
 
-               path = g_string_new(NULL);
-               if (!path) {
-                       print_err_oom();
-                       goto error;
-               }
+       for (i = 0; i < dirs->len; i++) {
+               GString *dir = g_ptr_array_index(dirs, i);
 
-               g_string_append_len(path, at, next_colon - at);
-               at = next_colon + 1;
-               ret = bt_value_array_append_string(plugin_paths, path->str);
-               g_string_free(path, TRUE);
-               if (ret) {
-                       print_err_oom();
-                       goto error;
-               }
+               bt_value_array_append_string(plugin_paths, dir->str);
        }
 
-       return BT_VALUE_STATUS_OK;
-error:
-       return BT_VALUE_STATUS_ERROR;
+end:
+       g_ptr_array_free(dirs, TRUE);
+       return status;
 }
 
 /*
@@ -2254,53 +2242,23 @@ not_found:
        return -1;
 }
 
-static char *bt_secure_getenv(const char *name)
-{
-       if (is_setuid_setgid()) {
-               printf_err("Disregarding %s environment variable for setuid/setgid binary", name);
-               return NULL;
-       }
-       return getenv(name);
-}
-
-static const char *get_home_dir(void)
-{
-       char *val = NULL;
-       struct passwd *pwd;
-
-       val = bt_secure_getenv(HOME_ENV_VAR);
-       if (val) {
-               goto end;
-       }
-       /* Fallback on password file. */
-       pwd = getpwuid(getuid());
-       if (!pwd) {
-               goto end;
-       }
-       val = pwd->pw_dir;
-end:
-       return val;
-}
-
 static int add_internal_plugin_paths(struct bt_config *cfg)
 {
-       if (!cfg->omit_home_plugin_path) {
-               char path[PATH_MAX];
-               const char *home_dir;
+       int ret;
 
-               if (is_setuid_setgid()) {
+       if (!cfg->omit_home_plugin_path) {
+               if (bt_common_is_setuid_setgid()) {
                        printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
                } else {
-                       home_dir = get_home_dir();
-                       if (home_dir) {
-                               if (strlen(home_dir) + strlen(HOME_SUBPATH) + 1
-                                               >= PATH_MAX) {
-                                       printf_err("Home directory path too long\n");
-                                       goto error;
-                               }
-                               strcpy(path, home_dir);
-                               strcat(path, HOME_SUBPATH);
-                               if (plugin_paths_from_arg(cfg->plugin_paths, path)) {
+                       char *home_plugin_dir =
+                               bt_common_get_home_plugin_path();
+
+                       if (home_plugin_dir) {
+                               ret = plugin_paths_from_arg(cfg->plugin_paths,
+                                       home_plugin_dir);
+                               free(home_plugin_dir);
+
+                               if (ret) {
                                        printf_err("Invalid home plugin path\n");
                                        goto error;
                                }
@@ -2310,7 +2268,7 @@ static int add_internal_plugin_paths(struct bt_config *cfg)
 
        if (!cfg->omit_system_plugin_path) {
                if (plugin_paths_from_arg(cfg->plugin_paths,
-                               SYSTEM_PLUGIN_PATH)) {
+                               bt_common_get_system_plugin_path())) {
                        printf_err("Invalid system plugin path\n");
                        goto error;
                }
index b05e6469ddd2e46334ded95d7af63e805ffe2082..dbd49630b72160c16e0988bea2e58834cf625a47 100644 (file)
@@ -68,6 +68,7 @@ noinst_HEADERS = \
        babeltrace/babeltrace-internal.h \
        babeltrace/bitfield.h \
        babeltrace/clock-internal.h \
+       babeltrace/common-internal.h \
        babeltrace/compiler.h \
        babeltrace/context-internal.h \
        babeltrace/format-internal.h \
diff --git a/include/babeltrace/common-internal.h b/include/babeltrace/common-internal.h
new file mode 100644 (file)
index 0000000..64299e9
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef BABELTRACE_COMMON_INTERNAL_H
+#define BABELTRACE_COMMON_INTERNAL_H
+
+#include <babeltrace/babeltrace-internal.h>
+
+BT_HIDDEN
+bool bt_common_is_setuid_setgid(void);
+
+BT_HIDDEN
+const char *bt_common_get_system_plugin_path(void);
+
+BT_HIDDEN
+char *bt_common_get_home_plugin_path(void);
+
+BT_HIDDEN
+int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs);
+
+#endif /* BABELTRACE_COMMON_INTERNAL_H */
index 9bb04f2e6b126284d4fdab48498e7b4a4f59ceba..0ec3b6c03e777aae3b1a8ecfb13f1b3fae2be37a 100644 (file)
@@ -51,6 +51,8 @@ enum bt_plugin_status {
        BT_PLUGIN_STATUS_NOMEM =        -4,
 };
 
+extern struct bt_plugin *bt_plugin_create_from_name(const char *plugin_name);
+
 extern struct bt_plugin **bt_plugin_create_all_from_file(const char *path);
 
 extern struct bt_plugin **bt_plugin_create_all_from_dir(const char *path,
index 71af87a5640f25750b981db5af7e94ce215fd743..c47d581b8c819c3960bf1a5de0804b9eb545ea8d 100644 (file)
@@ -32,4 +32,5 @@ libbabeltrace_la_LIBADD = \
        $(top_builddir)/types/libbabeltrace_types.la \
        $(top_builddir)/compat/libcompat.la \
        component/libcomponent.la \
-       plugin/libplugin.la
+       plugin/libplugin.la \
+       $(top_builddir)/common/libbabeltrace-common.la
index ce3a866f18935d0e4f803980a06dbdc249adf020..0e62889030a63f229a08d7811191caa42e9efb9c 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <babeltrace/compiler.h>
 #include <babeltrace/ref.h>
+#include <babeltrace/common-internal.h>
 #include <babeltrace/plugin/plugin-internal.h>
 #include <babeltrace/plugin/plugin-so-internal.h>
 #include <glib.h>
@@ -180,6 +181,139 @@ end:
        return plugins;
 }
 
+static void destroy_gstring(void *data)
+{
+       g_string_free(data, TRUE);
+}
+
+void free_plugins(struct bt_plugin **plugins) {
+       if (plugins) {
+               struct bt_plugin **cur_plugin = plugins;
+
+               while (*cur_plugin) {
+                       bt_put(*cur_plugin);
+                       cur_plugin++;
+               }
+
+               free(plugins);
+       }
+}
+
+struct bt_plugin *bt_plugin_create_from_name(const char *plugin_name)
+{
+       const char *system_plugin_dir;
+       char *home_plugin_dir = NULL;
+       const char *envvar;
+       struct bt_plugin *plugin = NULL;
+       struct bt_plugin **plugins = NULL;
+       struct bt_plugin **cur_plugin;
+       GPtrArray *dirs = NULL;
+       int ret;
+       size_t i;
+
+       if (!plugin_name) {
+               goto end;
+       }
+
+       dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
+       if (!dirs) {
+               goto end;
+       }
+
+       /*
+        * Search order is:
+        *
+        * 1. BABELTRACE_PLUGIN_PATH environment variable
+        *    (colon-separated list of directories)
+        * 2. ~/.local/lib/babeltrace/plugins
+        * 3. Default system directory for Babeltrace plugins, usually
+        *    /usr/lib/babeltrace/plugins or
+        *    /usr/local/lib/babeltrace/plugins if installed
+        *    locally
+        * 4. Built-in plugins (static)
+        *
+        * Directories are searched non-recursively.
+        */
+       envvar = getenv("BABELTRACE_PLUGIN_PATH");
+       if (envvar) {
+               ret = bt_common_append_plugin_path_dirs(envvar, dirs);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       home_plugin_dir = bt_common_get_home_plugin_path();
+       if (home_plugin_dir) {
+               GString *home_plugin_dir_str =
+                       g_string_new(home_plugin_dir);
+
+               if (!home_plugin_dir_str) {
+                       goto end;
+               }
+
+               g_ptr_array_add(dirs, home_plugin_dir_str);
+       }
+
+       system_plugin_dir = bt_common_get_system_plugin_path();
+       if (system_plugin_dir) {
+               GString *system_plugin_dir_str =
+                       g_string_new(system_plugin_dir);
+
+               if (!system_plugin_dir_str) {
+                       goto end;
+               }
+
+               g_ptr_array_add(dirs, system_plugin_dir_str);
+       }
+
+       for (i = 0; i < dirs->len; i++) {
+               GString *dir = g_ptr_array_index(dirs, i);
+
+               printf_verbose("Trying to load plugins from directory `%s`\n",
+                       dir->str);
+               free_plugins(plugins);
+               plugins = bt_plugin_create_all_from_dir(dir->str, false);
+               if (!plugins) {
+                       continue;
+               }
+
+               cur_plugin = plugins;
+
+               while (*cur_plugin) {
+                       if (strcmp(bt_plugin_get_name(*cur_plugin), plugin_name)
+                                       == 0) {
+                               plugin = bt_get(*cur_plugin);
+                               goto end;
+                       }
+
+                       cur_plugin++;
+               }
+       }
+
+       free_plugins(plugins);
+       plugins = bt_plugin_create_all_from_static();
+       cur_plugin = plugins;
+
+       while (*cur_plugin) {
+               if (strcmp(bt_plugin_get_name(*cur_plugin), plugin_name) == 0) {
+                       plugin = bt_get(*cur_plugin);
+                       goto end;
+               }
+
+               cur_plugin++;
+       }
+
+end:
+       free(home_plugin_dir);
+       free_plugins(plugins);
+
+       if (dirs) {
+               g_ptr_array_free(dirs, TRUE);
+       }
+
+       return plugin;
+}
+
 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
 static
 struct dirent *alloc_dirent(const char *path)
This page took 0.032785 seconds and 4 git commands to generate.