#include <dlfcn.h>
#include <blockdev/utils.h>
#include "blockdev.h"
#include "plugins.h"
#include "plugin_apis/lvm.h"
#include "plugin_apis/lvm.c"
#include "plugin_apis/btrfs.h"
#include "plugin_apis/btrfs.c"
#include "plugin_apis/swap.h"
#include "plugin_apis/swap.c"
#include "plugin_apis/loop.h"
#include "plugin_apis/loop.c"
#include "plugin_apis/crypto.h"
#include "plugin_apis/crypto.c"
#include "plugin_apis/mpath.h"
#include "plugin_apis/mpath.c"
#include "plugin_apis/dm.h"
#include "plugin_apis/dm.c"
#include "plugin_apis/mdraid.h"
#include "plugin_apis/mdraid.c"
#include "plugin_apis/kbd.h"
#include "plugin_apis/kbd.c"
#include "plugin_apis/part.h"
#include "plugin_apis/part.c"
#include "plugin_apis/fs.h"
#include "plugin_apis/fs.c"
#include "plugin_apis/nvdimm.h"
#include "plugin_apis/nvdimm.c"
#include "plugin_apis/vdo.h"
#include "plugin_apis/vdo.c"
#if defined(__s390__) || defined(__s390x__)
#include "plugin_apis/s390.h"
#include "plugin_apis/s390.c"
#endif
/**
* SECTION: blockdev
* @short_description: a library for doing low-level operations with block devices
* @title: blockdev library
* @include: blockdev.h
*
*/
#define DEFAULT_CONF_DIR_PATH "/etc/libblockdev/conf.d/"
static GMutex init_lock;
static gboolean initialized = FALSE;
static GMutex env_lock;
typedef struct BDPluginStatus {
BDPluginSpec spec;
gpointer handle;
} BDPluginStatus;
typedef void* (*LoadFunc) (const gchar *so_name);
/* KEEP THE ORDERING OF THESE ARRAYS MATCHING THE BDPluginName ENUM! */
static gchar * default_plugin_so[BD_PLUGIN_UNDEF] = {
"libbd_lvm.so."@MAJOR_VER@, "libbd_btrfs.so."@MAJOR_VER@,
"libbd_swap.so."@MAJOR_VER@, "libbd_loop.so."@MAJOR_VER@,
"libbd_crypto.so."@MAJOR_VER@, "libbd_mpath.so."@MAJOR_VER@,
"libbd_dm.so."@MAJOR_VER@, "libbd_mdraid.so."@MAJOR_VER@,
"libbd_kbd.so."@MAJOR_VER@,"libbd_s390.so."@MAJOR_VER@,
"libbd_part.so."@MAJOR_VER@, "libbd_fs.so."@MAJOR_VER@,
"libbd_nvdimm.so."@MAJOR_VER@, "libbd_vdo.so."@MAJOR_VER@
};
static BDPluginStatus plugins[BD_PLUGIN_UNDEF] = {
{{BD_PLUGIN_LVM, NULL}, NULL},
{{BD_PLUGIN_BTRFS, NULL}, NULL},
{{BD_PLUGIN_SWAP, NULL}, NULL},
{{BD_PLUGIN_LOOP, NULL}, NULL},
{{BD_PLUGIN_CRYPTO, NULL}, NULL},
{{BD_PLUGIN_MPATH, NULL}, NULL},
{{BD_PLUGIN_DM, NULL}, NULL},
{{BD_PLUGIN_MDRAID, NULL}, NULL},
{{BD_PLUGIN_KBD, NULL}, NULL},
{{BD_PLUGIN_S390, NULL}, NULL},
{{BD_PLUGIN_PART, NULL}, NULL},
{{BD_PLUGIN_FS, NULL}, NULL},
{{BD_PLUGIN_NVDIMM, NULL}, NULL},
{{BD_PLUGIN_VDO, NULL}, NULL},
};
static gchar* plugin_names[BD_PLUGIN_UNDEF] = {
"lvm", "btrfs", "swap", "loop", "crypto", "mpath", "dm", "mdraid", "kbd", "s390", "part", "fs", "nvdimm", "vdo"
};
static void set_plugin_so_name (BDPlugin name, const gchar *so_name) {
plugins[name].spec.so_name = so_name;
}
static gint config_file_cmp (gconstpointer a, gconstpointer b, gpointer user_data __attribute__((unused))) {
const gchar *name1 = (const gchar *) a;
const gchar *name2 = (const gchar *) b;
return g_strcmp0 (name1, name2);
}
static GSequence* get_config_files (GError **error) {
GDir *dir = NULL;
GSequence *ret = NULL;
gchar *conf_dir_path = NULL;
const gchar *dirent = NULL;
conf_dir_path = g_strdup (g_getenv("LIBBLOCKDEV_CONFIG_DIR"));
if (!conf_dir_path)
conf_dir_path = g_strdup (DEFAULT_CONF_DIR_PATH);
dir = g_dir_open (conf_dir_path, 0, error);
if (!dir) {
g_prefix_error (error, "Failed to get contents of the config dir (%s)", conf_dir_path);
g_free (conf_dir_path);
return NULL;
}
ret = g_sequence_new ((GDestroyNotify) g_free);
dirent = g_dir_read_name(dir);
while (dirent) {
/* only process .cfg files from the directory */
if (g_str_has_suffix (dirent, ".cfg")) {
dirent = g_build_filename (conf_dir_path, dirent, NULL);
g_sequence_insert_sorted (ret, (gpointer) dirent, config_file_cmp, NULL);
}
dirent = g_dir_read_name(dir);
}
g_free (conf_dir_path);
g_dir_close (dir);
return ret;
}
static gboolean process_config_file (const gchar *config_file, GSList **plugins_sonames, GError **error) {
GKeyFile *config = NULL;
BDPlugin i = 0;
gchar **sonames = NULL;
gsize n_sonames = 0;
config = g_key_file_new ();
if (!g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, error))
return FALSE;
/* get sonames for each plugin (if specified) */
for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
sonames = g_key_file_get_string_list (config, plugin_names[i], "sonames", &n_sonames, error);
if (!sonames) {
/* no sonames specified or an error occurred */
if (*error)
g_clear_error (error);
} else {
/* go through the sonames in the reversed order (because we prepend
them to the list) */
for (; n_sonames > 0; n_sonames--) {
plugins_sonames[i] = g_slist_prepend (plugins_sonames[i], sonames[n_sonames-1]);
}
/* we need to free only the array here not its items because those
were put into the list above as pointers */
g_free (sonames);
}
}
g_key_file_free (config);
return TRUE;
}
static gboolean load_config (GSequence *config_files, GSList **plugins_sonames, GError **error) {
GSequenceIter *config_file_iter = NULL;
gchar *config_file = NULL;
/* process config files one after another in order */
config_file_iter = g_sequence_get_begin_iter (config_files);
while (!g_sequence_iter_is_end (config_file_iter)) {
config_file = (gchar *) g_sequence_get (config_file_iter);
if (!process_config_file (config_file, plugins_sonames, error)) {
g_warning ("Cannot process the config file '%s': %s. Skipping.", config_file, (*error)->message);
g_clear_error (error);
}
config_file_iter = g_sequence_iter_next (config_file_iter);
}
return TRUE;
}
static void unload_plugins (void) {
if (plugins[BD_PLUGIN_LVM].handle && !unload_lvm (plugins[BD_PLUGIN_LVM].handle))
g_warning ("Failed to close the lvm plugin");
plugins[BD_PLUGIN_LVM].handle = NULL;
if (plugins[BD_PLUGIN_BTRFS].handle && !unload_btrfs (plugins[BD_PLUGIN_BTRFS].handle))
g_warning ("Failed to close the btrfs plugin");
plugins[BD_PLUGIN_BTRFS].handle = NULL;
if (plugins[BD_PLUGIN_SWAP].handle && !unload_swap (plugins[BD_PLUGIN_SWAP].handle))
g_warning ("Failed to close the swap plugin");
plugins[BD_PLUGIN_SWAP].handle = NULL;
if (plugins[BD_PLUGIN_LOOP].handle && !unload_loop (plugins[BD_PLUGIN_LOOP].handle))
g_warning ("Failed to close the loop plugin");
plugins[BD_PLUGIN_LOOP].handle = NULL;
if (plugins[BD_PLUGIN_CRYPTO].handle && !unload_crypto (plugins[BD_PLUGIN_CRYPTO].handle))
g_warning ("Failed to close the crypto plugin");
plugins[BD_PLUGIN_CRYPTO].handle = NULL;
if (plugins[BD_PLUGIN_MPATH].handle && !unload_mpath (plugins[BD_PLUGIN_MPATH].handle))
g_warning ("Failed to close the mpath plugin");
plugins[BD_PLUGIN_MPATH].handle = NULL;
if (plugins[BD_PLUGIN_DM].handle && !unload_dm (plugins[BD_PLUGIN_DM].handle))
g_warning ("Failed to close the dm plugin");
plugins[BD_PLUGIN_DM].handle = NULL;
if (plugins[BD_PLUGIN_MDRAID].handle && !unload_mdraid (plugins[BD_PLUGIN_MDRAID].handle))
g_warning ("Failed to close the mdraid plugin");
plugins[BD_PLUGIN_MDRAID].handle = NULL;
if (plugins[BD_PLUGIN_KBD].handle && !unload_kbd (plugins[BD_PLUGIN_KBD].handle))
g_warning ("Failed to close the kbd plugin");
plugins[BD_PLUGIN_KBD].handle = NULL;
#if defined(__s390__) || defined(__s390x__)
if (plugins[BD_PLUGIN_S390].handle && !unload_s390 (plugins[BD_PLUGIN_S390].handle))
g_warning ("Failed to close the s390 plugin");
plugins[BD_PLUGIN_S390].handle = NULL;
#endif
if (plugins[BD_PLUGIN_PART].handle && !unload_part (plugins[BD_PLUGIN_PART].handle))
g_warning ("Failed to close the part plugin");
plugins[BD_PLUGIN_PART].handle = NULL;
if (plugins[BD_PLUGIN_FS].handle && !unload_fs (plugins[BD_PLUGIN_FS].handle))
g_warning ("Failed to close the fs plugin");
plugins[BD_PLUGIN_FS].handle = NULL;
if (plugins[BD_PLUGIN_NVDIMM].handle && !unload_nvdimm (plugins[BD_PLUGIN_NVDIMM].handle))
g_warning ("Failed to close the nvdimm plugin");
plugins[BD_PLUGIN_NVDIMM].handle = NULL;
if (plugins[BD_PLUGIN_VDO].handle && !unload_vdo (plugins[BD_PLUGIN_VDO].handle))
g_warning ("Failed to close the VDO plugin");
plugins[BD_PLUGIN_VDO].handle = NULL;
}
static void load_plugin_from_sonames (BDPlugin plugin, LoadFunc load_fn, void **handle, GSList *sonames) {
while (!(*handle) && sonames) {
*handle = load_fn (sonames->data);
if (*handle)
set_plugin_so_name(plugin, g_strdup (sonames->data));
sonames = g_slist_next (sonames);
}
}
static void do_load (GSList **plugins_sonames) {
if (!plugins[BD_PLUGIN_LVM].handle && plugins_sonames[BD_PLUGIN_LVM])
load_plugin_from_sonames (BD_PLUGIN_LVM, load_lvm_from_plugin, &(plugins[BD_PLUGIN_LVM].handle), plugins_sonames[BD_PLUGIN_LVM]);
if (!plugins[BD_PLUGIN_BTRFS].handle && plugins_sonames[BD_PLUGIN_BTRFS])
load_plugin_from_sonames (BD_PLUGIN_BTRFS, load_btrfs_from_plugin, &(plugins[BD_PLUGIN_BTRFS].handle), plugins_sonames[BD_PLUGIN_BTRFS]);
if (!plugins[BD_PLUGIN_SWAP].handle && plugins_sonames[BD_PLUGIN_SWAP])
load_plugin_from_sonames (BD_PLUGIN_SWAP,load_swap_from_plugin, &(plugins[BD_PLUGIN_SWAP].handle), plugins_sonames[BD_PLUGIN_SWAP]);
if (!plugins[BD_PLUGIN_LOOP].handle && plugins_sonames[BD_PLUGIN_LOOP])
load_plugin_from_sonames (BD_PLUGIN_LOOP, load_loop_from_plugin, &(plugins[BD_PLUGIN_LOOP].handle), plugins_sonames[BD_PLUGIN_LOOP]);
if (!plugins[BD_PLUGIN_CRYPTO].handle && plugins_sonames[BD_PLUGIN_CRYPTO])
load_plugin_from_sonames (BD_PLUGIN_CRYPTO, load_crypto_from_plugin, &(plugins[BD_PLUGIN_CRYPTO].handle), plugins_sonames[BD_PLUGIN_CRYPTO]);
if (!plugins[BD_PLUGIN_MPATH].handle && plugins_sonames[BD_PLUGIN_MPATH])
load_plugin_from_sonames (BD_PLUGIN_MPATH, load_mpath_from_plugin, &(plugins[BD_PLUGIN_MPATH].handle), plugins_sonames[BD_PLUGIN_MPATH]);
if (!plugins[BD_PLUGIN_DM].handle && plugins_sonames[BD_PLUGIN_DM])
load_plugin_from_sonames (BD_PLUGIN_DM, load_dm_from_plugin, &(plugins[BD_PLUGIN_DM].handle), plugins_sonames[BD_PLUGIN_DM]);
if (!plugins[BD_PLUGIN_MDRAID].handle && plugins_sonames[BD_PLUGIN_MDRAID])
load_plugin_from_sonames (BD_PLUGIN_MDRAID, load_mdraid_from_plugin, &(plugins[BD_PLUGIN_MDRAID].handle), plugins_sonames[BD_PLUGIN_MDRAID]);
if (!plugins[BD_PLUGIN_KBD].handle && plugins_sonames[BD_PLUGIN_KBD])
load_plugin_from_sonames (BD_PLUGIN_KBD, load_kbd_from_plugin, &(plugins[BD_PLUGIN_KBD].handle), plugins_sonames[BD_PLUGIN_KBD]);
#if defined(__s390__) || defined(__s390x__)
if (!plugins[BD_PLUGIN_S390].handle && plugins_sonames[BD_PLUGIN_S390])
load_plugin_from_sonames (BD_PLUGIN_S390, load_s390_from_plugin, &(plugins[BD_PLUGIN_S390].handle), plugins_sonames[BD_PLUGIN_S390]);
#endif
if (!plugins[BD_PLUGIN_PART].handle && plugins_sonames[BD_PLUGIN_PART])
load_plugin_from_sonames (BD_PLUGIN_PART, load_part_from_plugin, &(plugins[BD_PLUGIN_PART].handle), plugins_sonames[BD_PLUGIN_PART]);
if (!plugins[BD_PLUGIN_FS].handle && plugins_sonames[BD_PLUGIN_FS])
load_plugin_from_sonames (BD_PLUGIN_FS, load_fs_from_plugin, &(plugins[BD_PLUGIN_FS].handle), plugins_sonames[BD_PLUGIN_FS]);
if (!plugins[BD_PLUGIN_NVDIMM].handle && plugins_sonames[BD_PLUGIN_NVDIMM])
load_plugin_from_sonames (BD_PLUGIN_NVDIMM, load_nvdimm_from_plugin, &(plugins[BD_PLUGIN_NVDIMM].handle), plugins_sonames[BD_PLUGIN_NVDIMM]);
if (!plugins[BD_PLUGIN_VDO].handle && plugins_sonames[BD_PLUGIN_VDO])
load_plugin_from_sonames (BD_PLUGIN_VDO, load_vdo_from_plugin, &(plugins[BD_PLUGIN_VDO].handle), plugins_sonames[BD_PLUGIN_VDO]);
}
static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, guint64 *num_loaded) {
guint8 i = 0;
gboolean requested_loaded = TRUE;
GError *error = NULL;
GSequence *config_files = NULL;
GSList *plugins_sonames[BD_PLUGIN_UNDEF] = {NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL};
BDPlugin plugin_name = BD_PLUGIN_UNDEF;
guint64 required_plugins_mask = 0;
/* load config files first */
config_files = get_config_files (&error);
if (config_files) {
if (!load_config (config_files, plugins_sonames, &error))
g_warning ("Failed to load config files: %s. Using the built-in config", error->message);
g_sequence_free (config_files);
} else
g_warning ("Failed to load config files: %s. Using the built-in config", error->message);
g_clear_error (&error);
/* populate missing items with the built-in defaults */
for (i=0; i < BD_PLUGIN_UNDEF; i++)
if (!plugins_sonames[i])
plugins_sonames[i] = g_slist_prepend (plugins_sonames[i], g_strdup (default_plugin_so[i]));
#if !defined(__s390__) && !defined(__s390x__)
/* do not load the s390 plugin by default if not on s390(x) */
g_slist_free_full (plugins_sonames[BD_PLUGIN_S390], (GDestroyNotify) g_free);
plugins_sonames[BD_PLUGIN_S390] = NULL;
#endif
/* unload the previously loaded plugins if requested */
if (reload) {
unload_plugins ();
/* clean all so names and populate back those that are requested or the
defaults */
for (i=0; i < BD_PLUGIN_UNDEF; i++)
plugins[i].spec.so_name = NULL;
}
if (require_plugins) {
/* set requested sonames */
for (i=0; *(require_plugins + i); i++) {
plugin_name = require_plugins[i]->name;
required_plugins_mask |= (1 << plugin_name);
if (require_plugins[i]->so_name) {
g_slist_free_full (plugins_sonames[plugin_name], (GDestroyNotify) g_free);
plugins_sonames[plugin_name] = NULL;
plugins_sonames[plugin_name] = g_slist_prepend(plugins_sonames[plugin_name], g_strdup (require_plugins[i]->so_name));
}
}
/* now remove the defaults for plugins that are not required */
for (i=0; (i < BD_PLUGIN_UNDEF); i++)
if (!(required_plugins_mask & (1 << i))) {
/* plugin not required */
g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free);
plugins_sonames[i] = NULL;
}
}
do_load (plugins_sonames);
*num_loaded = 0;
for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
/* if this plugin was required or all plugins were required, check if it
was successfully loaded or not */
if (!require_plugins || (required_plugins_mask & (1 << i))) {
#if !defined(__s390__) && !defined(__s390x__)
if (!require_plugins && (i == BD_PLUGIN_S390))
/* do not check the s390 plugin on different archs unless
explicitly required */
continue;
#endif
if (plugins[i].handle)
(*num_loaded)++;
else
requested_loaded = FALSE;
}
}
/* clear/free the config */
for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
if (plugins_sonames[i]) {
g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free);
plugins_sonames[i] = NULL;
}
}
return requested_loaded;
}
GQuark bd_init_error_quark (void)
{
return g_quark_from_static_string ("g-bd-init-error-quark");
}
/**
* bd_init:
* @require_plugins: (allow-none) (array zero-terminated=1): %NULL-terminated list
* of plugins that should be loaded (if no so_name is specified
* for the plugin, the default is used) or %NULL to load all
* plugins
* @log_func: (allow-none) (scope notified): logging function to use
* @error: (out): place to store error (if any)
*
* Returns: whether the library was successfully initialized with all the
* required or default (see @require_plugins) plugins or not
*
* Example of libblockdev initialization with 'fs' and 'lvm' plugins. Specific
* version of the lvm plugin is required:
*
* |[<!-- language="C" -->
* GError *error = NULL;
* gboolean ret = FALSE;
* BDPluginSpec fs_plugin = {BD_PLUGIN_FS, NULL};
* BDPluginSpec lvm_plugin = {BD_PLUGIN_LVM, "libbd_lvm.so.2"};
*
* BDPluginSpec *plugins[] = {&fs_plugin, &lvm_plugin, NULL};
*
* ret = bd_init (plugins, NULL, &error);
* ]|
*/
gboolean bd_init (BDPluginSpec **require_plugins, BDUtilsLogFunc log_func, GError **error) {
gboolean success = TRUE;
guint64 num_loaded = 0;
g_mutex_lock (&init_lock);
if (initialized) {
g_warning ("bd_init() called more than once! Use bd_reinit() to reinitialize "
"or bd_is_initialized() to get the current state.");
g_mutex_unlock (&init_lock);
return FALSE;
}
if (log_func && !bd_utils_init_logging (log_func, error)) {
/* the error is already populated */
g_mutex_unlock (&init_lock);
return FALSE;
}
if (!load_plugins (require_plugins, FALSE, &num_loaded)) {
g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_PLUGINS_FAILED,
"Failed to load plugins");
success = FALSE;
}
if (num_loaded == 0) {
if (require_plugins && (*require_plugins == NULL))
/* requested to load no plugins (NULL is the first item in the
array), none loaded -> OK */
initialized = TRUE;
else
initialized = FALSE;
} else
initialized = TRUE;
g_mutex_unlock (&init_lock);
return success;
}
/**
* bd_ensure_init:
* @require_plugins: (allow-none) (array zero-terminated=1): %NULL-terminated list
* of plugins that should be loaded (if no so_name is specified
* for the plugin, the default is used) or %NULL to load all
* plugins
* @log_func: (allow-none) (scope notified): logging function to use
* @error: (out): place to store error (if any)
*
* Checks the state of the library and if it is uninitialized or not all the
* @require_plugins plugins are available, tries to (re)initialize it. Otherwise
* just returns early. The difference between:
*
* |[<!-- language="C" -->
* if (!bd_is_initialized())
* bd_init(None, None, &error);
* ]|
*
* and this function is that this function does the check and init in an atomic
* way (holding the lock preventing other threads from doing changes in
* between).
*
* Returns: whether the library was successfully initialized with all the
* required or default (see @require_plugins) plugins or not either
* before or by this call
*/
gboolean bd_ensure_init (BDPluginSpec **require_plugins, BDUtilsLogFunc log_func, GError **error) {
gboolean success = TRUE;
BDPluginSpec **check_plugin = NULL;
gboolean missing = FALSE;
guint64 num_loaded = 0;
BDPlugin plugin = BD_PLUGIN_UNDEF;
g_mutex_lock (&init_lock);
if (initialized) {
if (require_plugins)
for (check_plugin=require_plugins; !missing && *check_plugin; check_plugin++)
missing = !bd_is_plugin_available((*check_plugin)->name);
else
/* all plugins requested */
for (plugin=BD_PLUGIN_LVM; plugin != BD_PLUGIN_UNDEF; plugin++)
missing = !bd_is_plugin_available(plugin);
if (!missing) {
g_mutex_unlock (&init_lock);
return TRUE;
}
}
if (log_func && !bd_utils_init_logging (log_func, error)) {
/* the error is already populated */
g_mutex_unlock (&init_lock);
return FALSE;
}
if (!load_plugins (require_plugins, FALSE, &num_loaded)) {
g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_PLUGINS_FAILED,
"Failed to load plugins");
success = FALSE;
}
if (num_loaded == 0) {
if (require_plugins && (*require_plugins == NULL))
/* requested to load no plugins (NULL is the first item in the
array), none loaded -> OK */
initialized = TRUE;
else
initialized = FALSE;
} else
initialized = TRUE;
g_mutex_unlock (&init_lock);
return success;
}
/**
* bd_try_init:
* @request_plugins: (allow-none) (array zero-terminated=1): %NULL-terminated list
* of plugins that should be loaded (if no so_name is specified
* for the plugin, the default is used) or %NULL to load all
* plugins
* @log_func: (allow-none) (scope notified): logging function to use
* @loaded_plugin_names: (allow-none) (out) (transfer container) (array zero-terminated=1): names
* of the successfully loaded plugins
* @error: (out): place to store error (if any)
*
* Returns: whether the library was successfully initialized with all the
* required or default (see @require_plugins) plugins or not
*
* *UNLIKE IN CASE OF bd_init() AND bd_ensure_init(), FAILURE TO LOAD A PLUGIN
* IS NOT CONSIDERED ERROR*
*/
gboolean bd_try_init(BDPluginSpec **request_plugins, BDUtilsLogFunc log_func,
gchar ***loaded_plugin_names, GError **error) {
gboolean success = TRUE;
guint64 num_loaded = 0;
g_mutex_lock (&init_lock);
if (initialized) {
g_warning ("bd_try_init() called more than once! Use bd_reinit() to reinitialize "
"or bd_is_initialized() to get the current state.");
g_mutex_unlock (&init_lock);
return FALSE;
}
if (log_func && !bd_utils_init_logging (log_func, error)) {
/* the error is already populated */
g_mutex_unlock (&init_lock);
return FALSE;
}
success = load_plugins (request_plugins, FALSE, &num_loaded);
if (num_loaded == 0) {
if (request_plugins && (*request_plugins == NULL))
/* requested to load no plugins (NULL is the first item in the
array), none loaded -> OK */
initialized = TRUE;
else
initialized = FALSE;
} else
initialized = TRUE;
if (loaded_plugin_names)
*loaded_plugin_names = bd_get_available_plugin_names ();
g_mutex_unlock (&init_lock);
return success;
}
/**
* bd_reinit:
* @require_plugins: (allow-none) (array zero-terminated=1): %NULL-terminated list
* of plugins that should be loaded (if no so_name is specified
* for the plugin, the default is used) or %NULL to load all
* plugins
* @reload: whether to reload the already loaded plugins or not
* @log_func: (allow-none) (scope notified): logging function to use or %NULL
* to keep the old one
* @error: (out): place to store error (if any)
*
* Returns: whether the library was successfully initialized or not
*
* If @reload is %TRUE all the plugins are closed and reloaded otherwise only
* the missing plugins are loaded.
*/
gboolean bd_reinit (BDPluginSpec **require_plugins, gboolean reload, BDUtilsLogFunc log_func, GError **error) {
gboolean success = TRUE;
guint64 num_loaded = 0;
g_mutex_lock (&init_lock);
if (log_func && !bd_utils_init_logging (log_func, error)) {
/* the error is already populated */
g_mutex_unlock (&init_lock);
return FALSE;
}
if (!load_plugins (require_plugins, reload, &num_loaded)) {
g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_PLUGINS_FAILED,
"Failed to load plugins");
success = FALSE;
} else
if (require_plugins && (*require_plugins == NULL) && reload)
/* requested to just unload all plugins */
success = (num_loaded == 0);
if (num_loaded == 0) {
if (require_plugins && (*require_plugins == NULL))
/* requested to load no plugins (NULL is the first item in the
array), none loaded -> OK */
initialized = TRUE;
else
initialized = FALSE;
} else
initialized = TRUE;
g_mutex_unlock (&init_lock);
return success;
}
/**
* bd_try_reinit:
* @require_plugins: (allow-none) (array zero-terminated=1): %NULL-terminated list
* of plugins that should be loaded (if no so_name is specified
* for the plugin, the default is used) or %NULL to load all
* plugins
* @reload: whether to reload the already loaded plugins or not
* @log_func: (allow-none) (scope notified): logging function to use or %NULL
* to keep the old one
* @loaded_plugin_names: (allow-none) (out) (transfer container) (array zero-terminated=1): names of the successfully
* loaded plugins
* @error: (out): place to store error (if any)
*
* Returns: whether the library was successfully initialized or not
*
* If @reload is %TRUE all the plugins are closed and reloaded otherwise only
* the missing plugins are loaded.
*
* *UNLIKE IN CASE OF bd_init() AND bd_ensure_init(), FAILURE TO LOAD A PLUGIN
* IS NOT CONSIDERED ERROR*
*/
gboolean bd_try_reinit (BDPluginSpec **require_plugins, gboolean reload, BDUtilsLogFunc log_func,
gchar ***loaded_plugin_names, GError **error) {
gboolean success = TRUE;
guint64 num_loaded = 0;
g_mutex_lock (&init_lock);
if (log_func && !bd_utils_init_logging (log_func, error)) {
/* the error is already populated */
g_mutex_unlock (&init_lock);
return FALSE;
}
success = load_plugins (require_plugins, reload, &num_loaded);
if (success && require_plugins && (*require_plugins == NULL) && reload)
/* requested to just unload all plugins */
success = (num_loaded == 0);
if (num_loaded == 0) {
if (require_plugins && (*require_plugins == NULL))
/* requested to load no plugins (NULL is the first item in the
array), none loaded -> OK */
initialized = TRUE;
else
initialized = FALSE;
} else
initialized = TRUE;
if (loaded_plugin_names)
*loaded_plugin_names = bd_get_available_plugin_names ();
g_mutex_unlock (&init_lock);
return success;
}
/**
* bd_is_initialized:
*
* Returns: whether the library is initialized or not
*
* The library is considered initialized if some of the *init*() functions
* was/were called and either at least one plugin is loaded or 0 plugins are
* loaded after an explicit call that requested 0 plugins to be loaded.
*/
gboolean bd_is_initialized (void) {
gboolean is = FALSE;
g_mutex_lock (&init_lock);
is = initialized;
g_mutex_unlock (&init_lock);
return is;
}
/**
* bd_get_available_plugin_names:
*
* Returns: (transfer container) (array zero-terminated=1): an array of string
* names of plugins that are available
*/
gchar** bd_get_available_plugin_names (void) {
guint8 i = 0;
guint8 num_loaded = 0;
guint8 next = 0;
for (i=0; i < BD_PLUGIN_UNDEF; i++)
if (plugins[i].handle)
num_loaded++;
gchar **ret_plugin_names = g_new0 (gchar*, num_loaded + 1);
for (i=0; i < BD_PLUGIN_UNDEF; i++)
if (plugins[i].handle) {
ret_plugin_names[next] = plugin_names[i];
next++;
}
ret_plugin_names[next] = NULL;
return ret_plugin_names;
}
/**
* bd_is_plugin_available:
* @plugin: the queried plugin
*
* Returns: whether the given plugin is available or not
*/
gboolean bd_is_plugin_available (BDPlugin plugin) {
if (plugin < BD_PLUGIN_UNDEF)
return plugins[plugin].handle != NULL;
else
return FALSE;
}
/**
* bd_get_plugin_soname:
* @plugin: the queried plugin
*
* Returns: (transfer full): name of the shared object loaded for the plugin or
* %NULL if none is loaded
*/
gchar* bd_get_plugin_soname (BDPlugin plugin) {
if (plugins[plugin].handle)
return g_strdup (plugins[plugin].spec.so_name);
return NULL;
}
/**
* bd_get_plugin_name:
* @plugin: the queried plugin
*
* Returns: (transfer none): name of the plugin
*/
gchar* bd_get_plugin_name (BDPlugin plugin) {
return plugin_names[plugin];
}
/**
* bd_switch_init_checks:
* @enable: whether to enable init checks (%TRUE) or not (%FALSE)
* @error: (out): place to store error (if any)
*
* Enables or disables plugins' init checks based on @enable.
*
* Note: The current implementation (un)sets the LIBBLOCKDEV_SKIP_DEP_CHECKS
* environment variable.
*/
gboolean bd_switch_init_checks (gboolean enable, GError **error) {
/* getenv/setenv/unsetenv are not thread-safe, better use a lock here */
g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&env_lock);
if (!enable && !g_getenv ("LIBBLOCKDEV_SKIP_DEP_CHECKS")) {
if (!g_setenv ("LIBBLOCKDEV_SKIP_DEP_CHECKS", "", FALSE)) {
g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_FAILED,
"Failed to set the LIBBLOCKDEV_SKIP_DEP_CHECKS environment variable");
return FALSE;
}
return TRUE;
} else if (enable && g_getenv ("LIBBLOCKDEV_SKIP_DEP_CHECKS")) {
g_unsetenv ("LIBBLOCKDEV_SKIP_DEP_CHECKS");
return TRUE;
} else
return TRUE;
}