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
--- /dev/null
+AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include \
+ -DINSTALL_LIBDIR=\"$(libdir)\"
+
+
+noinst_LTLIBRARIES = libbabeltrace-common.la
+
+libbabeltrace_common_la_SOURCES = common.c
--- /dev/null
+/*
+ * 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;
+}
AC_CONFIG_FILES([
Makefile
types/Makefile
+ common/Makefile
compat/Makefile
formats/Makefile
formats/ctf/Makefile
$(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
#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
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.
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;
}
/*
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;
}
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;
}
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 \
--- /dev/null
+#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 */
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,
$(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
#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>
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)