plugins FEATURE load external plugins as part of plugins initiation
Use default plugins directories or the directories provided via
environment variable and besides the internal types and extensions
plugins load also the plugins available in those directories.
The default directories (<INSTALL LIBDIR>/libyang/extensions and <INSTALL
LIBDIR>/libyang/types byt default) can be set using cmake and then they
are available via a new configuration header cmake_config.h. Also some
other cmake information regarding the plugins are placed there.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d367f5f..2bd7411 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -84,10 +84,6 @@
set(CMAKE_C_FLAGS_ABICHECK "-g -Og")
include_directories(${PROJECT_BINARY_DIR}/src ${PROJECT_SOURCE_DIR}/src)
-configure_file(${PROJECT_SOURCE_DIR}/src/version.h.in ${PROJECT_BINARY_DIR}/src/version.h @ONLY)
-
-#set(EXTENSIONS_PLUGINS_DIR_MACRO "${PLUGINS_DIR}/extensions")
-#set(USER_TYPES_PLUGINS_DIR_MACRO "${PLUGINS_DIR}/user_types")
# setup bindings
#set(GEN_LANGUAGE_BINDINGS 0 CACHE BOOL "Enable language bindings generation.")
@@ -97,6 +93,9 @@
#set(GEN_PYTHON_VERSION "3" CACHE STRING "Python version")
#set(GEN_JAVASCRIPT_BINDINGS 0 CACHE BOOL "Enable JavaScript bindings.")
+configure_file(${PROJECT_SOURCE_DIR}/src/config.h.in ${PROJECT_BINARY_DIR}/src/config.h @ONLY)
+configure_file(${PROJECT_SOURCE_DIR}/src/version.h.in ${PROJECT_BINARY_DIR}/src/version.h @ONLY)
+
set(libsrc
src/common.c
src/log.c
@@ -205,7 +204,9 @@
#option(ENABLE_CACHE "Enable data caching for schemas and hash tables for data (time-efficient at the cost of increased space-complexity)" ON)
#option(ENABLE_LATEST_REVISIONS "Enable reusing of latest revisions of schemas" ON)
-#set(PLUGINS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libyang" CACHE STRING "Directory with libyang plugins (extensions and user types)")
+set(PLUGINS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libyang" CACHE STRING "Directory with libyang plugins (extensions and user types)")
+set(PLUGINS_DIR_EXTENSIONS "${PLUGINS_DIR}/extensions" CACHE STRING "Directory with libyang user extensions plugins")
+set(PLUGINS_DIR_TYPES "${PLUGINS_DIR}/types" CACHE STRING "Directory with libyang user types plugins")
#if(ENABLE_CACHE)
# set(LY_ENABLED_CACHE 1)
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000..ab861bd
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,26 @@
+/**
+ * @file config.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Various variables provided by cmake and compile time options.
+ *
+ * Copyright (c) 2021 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_CONFIG_H_
+#define LY_CONFIG_H_
+
+/*
+ * Plugins
+ */
+#define LYPLG_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
+#define LYPLG_SUFFIX_LEN (sizeof LYPLG_SUFFIX - 1)
+#define LYPLG_TYPE_DIR "@PLUGINS_DIR_EXTENSIONS@"
+#define LYPLG_EXT_DIR "@PLUGINS_DIR_TYPES@"
+
+#endif /* LY_CONFIG_H_ */
diff --git a/src/plugins.c b/src/plugins.c
index e378773..bb59839 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -12,15 +12,22 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
+#define _GNU_SOURCE
+
#include "plugins.h"
#include "plugins_internal.h"
#include <assert.h>
+#include <dirent.h>
#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
#include <pthread.h>
#include <stddef.h>
#include <string.h>
+#include <sys/types.h>
+#include "config.h"
#include "common.h"
#include "plugins_exts.h"
#include "plugins_types.h"
@@ -88,17 +95,23 @@
const char *id; /**< string identifier: type/extension */
const char *apiver_var; /**< expected variable name holding API version value */
const char *plugins_var; /**< expected variable name holding plugin records */
+ const char *envdir; /**< environment variable containing directory with the plugins */
+ const char *dir; /**< default directory with the plugins (has less priority than envdir) */
uint32_t apiver; /**< expected API version */
} plugins_load_info[] = {
{ /* LYPLG_TYPE */
.id = "type",
.apiver_var = "plugins_types_apiver__",
.plugins_var = "plugins_types__",
+ .envdir = "LIBYANG_TYPES_PLUGINS_DIR",
+ .dir = LYPLG_TYPE_DIR,
.apiver = LYPLG_TYPE_API_VERSION
}, {/* LYPLG_EXTENSION */
.id = "extension",
.apiver_var = "plugins_extensions_apiver__",
.plugins_var = "plugins_extensions__",
+ .envdir = "LIBYANG_EXTENSIONS_PLUGINS_DIR",
+ .dir = LYPLG_EXT_DIR,
.apiver = LYPLG_EXT_API_VERSION
}
};
@@ -307,6 +320,56 @@
return ret;
}
+static LY_ERR
+plugins_insert_dir(enum LYPLG type)
+{
+ LY_ERR ret = LY_SUCCESS;
+ const char *pluginsdir;
+ DIR *dir;
+ ly_bool default_dir = 0;
+
+ /* try to get the plugins directory from environment variable */
+ pluginsdir = getenv(plugins_load_info[type].envdir);
+ if (!pluginsdir) {
+ /* remember that we are going to a default dir and do not print warning if the directory doesn't exist */
+ default_dir = 1;
+ pluginsdir = plugins_load_info[type].dir;
+ }
+
+ dir = opendir(pluginsdir);
+ if (!dir) {
+ /* no directory (or no access to it), no extension plugins */
+ if (!default_dir || (errno != ENOENT)) {
+ LOGWRN(NULL, "Failed to open libyang %s plugins directory \"%s\" (%s).", plugins_load_info[type].id,
+ pluginsdir, strerror(errno));
+ }
+ } else {
+ struct dirent *file;
+
+ while ((file = readdir(dir))) {
+ size_t len;
+ char pathname[PATH_MAX];
+
+ /* required format of the filename is *LYPLG_SUFFIX */
+ len = strlen(file->d_name);
+ if ((len < LYPLG_SUFFIX_LEN + 1) || strcmp(&file->d_name[len - LYPLG_SUFFIX_LEN], LYPLG_SUFFIX)) {
+ continue;
+ }
+
+ /* and construct the filepath */
+ snprintf(pathname, PATH_MAX, "%s/%s", pluginsdir, file->d_name);
+
+ ret = plugins_load_module(pathname);
+ if (ret) {
+ break;
+ }
+ }
+ closedir(dir);
+ }
+
+ return ret;
+}
+
LY_ERR
lyplg_init(void)
{
@@ -339,6 +402,12 @@
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
+ /* external types */
+ LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_TYPE), error);
+
+ /* external extensions */
+ LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_EXTENSION), error);
+
/* initiation done, wake-up possibly waiting threads creating another contexts */
pthread_mutex_unlock(&plugins_guard);
diff --git a/tests/utests/utests.h b/tests/utests/utests.h
index fa686d3..e7d9da7 100644
--- a/tests/utests/utests.h
+++ b/tests/utests/utests.h
@@ -1273,6 +1273,9 @@
/* libyang context */
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, ¤t_utest_context->ctx));
+ /* clean all errors from the setup - usually warnings regarding the plugins directories */
+ UTEST_LOG_CLEAN;
+
return 0;
}