#include #include #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: * * |[ * 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: * * |[ * 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; }