LCOV - code coverage report
Current view: top level - lib - blockdev.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 71.7 % 329 236
Test Date: 2026-01-23 09:12:16 Functions: 85.0 % 20 17
Legend: Lines: hit not hit

            Line data    Source code
       1              : #include <dlfcn.h>
       2              : #include <blockdev/utils.h>
       3              : #include "blockdev.h"
       4              : #include "plugins.h"
       5              : 
       6              : #include "plugin_apis/lvm.h"
       7              : #include "plugin_apis/lvm.c"
       8              : #include "plugin_apis/btrfs.h"
       9              : #include "plugin_apis/btrfs.c"
      10              : #include "plugin_apis/swap.h"
      11              : #include "plugin_apis/swap.c"
      12              : #include "plugin_apis/loop.h"
      13              : #include "plugin_apis/loop.c"
      14              : #include "plugin_apis/crypto.h"
      15              : #include "plugin_apis/crypto.c"
      16              : #include "plugin_apis/mpath.h"
      17              : #include "plugin_apis/mpath.c"
      18              : #include "plugin_apis/dm.h"
      19              : #include "plugin_apis/dm.c"
      20              : #include "plugin_apis/mdraid.h"
      21              : #include "plugin_apis/mdraid.c"
      22              : #include "plugin_apis/part.h"
      23              : #include "plugin_apis/part.c"
      24              : #include "plugin_apis/fs.h"
      25              : #include "plugin_apis/fs.c"
      26              : #include "plugin_apis/nvdimm.h"
      27              : #include "plugin_apis/nvdimm.c"
      28              : #include "plugin_apis/nvme.h"
      29              : #include "plugin_apis/nvme.c"
      30              : #include "plugin_apis/smart.h"
      31              : #include "plugin_apis/smart.c"
      32              : 
      33              : #if defined(__s390__) || defined(__s390x__)
      34              : #include "plugin_apis/s390.h"
      35              : #include "plugin_apis/s390.c"
      36              : #endif
      37              : 
      38              : /**
      39              :  * SECTION: blockdev
      40              :  * @short_description: a library for doing low-level operations with block devices
      41              :  * @title: blockdev library
      42              :  * @include: blockdev.h
      43              :  *
      44              :  */
      45              : 
      46              : #define DEFAULT_CONF_DIR_PATH "/etc/libblockdev/3/conf.d/"
      47              : 
      48              : static GMutex init_lock;
      49              : static gboolean initialized = FALSE;
      50              : 
      51              : typedef struct BDPluginStatus {
      52              :     BDPluginSpec spec;
      53              :     gpointer handle;
      54              : } BDPluginStatus;
      55              : 
      56              : typedef void* (*LoadFunc) (const gchar *so_name);
      57              : 
      58              : /* KEEP THE ORDERING OF THESE ARRAYS MATCHING THE BDPluginName ENUM! */
      59              : static gchar * default_plugin_so[BD_PLUGIN_UNDEF] = {
      60              :     "libbd_lvm.so.3", "libbd_btrfs.so.3",
      61              :     "libbd_swap.so.3", "libbd_loop.so.3",
      62              :     "libbd_crypto.so.3", "libbd_mpath.so.3",
      63              :     "libbd_dm.so.3", "libbd_mdraid.so.3",
      64              :     "libbd_s390.so.3", "libbd_part.so.3",
      65              :     "libbd_fs.so.3", "libbd_nvdimm.so.3",
      66              :     "libbd_nvme.so.3",
      67              : #if defined(HAVE_SMART) || !defined(HAVE_SMARTMONTOOLS)
      68              :      "libbd_smart.so.3",
      69              : #else
      70              :      "libbd_smartmontools.so.3",
      71              : #endif
      72              : };
      73              : static BDPluginStatus plugins[BD_PLUGIN_UNDEF] = {
      74              :     {{BD_PLUGIN_LVM, NULL}, NULL},
      75              :     {{BD_PLUGIN_BTRFS, NULL}, NULL},
      76              :     {{BD_PLUGIN_SWAP, NULL}, NULL},
      77              :     {{BD_PLUGIN_LOOP, NULL}, NULL},
      78              :     {{BD_PLUGIN_CRYPTO, NULL}, NULL},
      79              :     {{BD_PLUGIN_MPATH, NULL}, NULL},
      80              :     {{BD_PLUGIN_DM, NULL}, NULL},
      81              :     {{BD_PLUGIN_MDRAID, NULL}, NULL},
      82              :     {{BD_PLUGIN_S390, NULL}, NULL},
      83              :     {{BD_PLUGIN_PART, NULL}, NULL},
      84              :     {{BD_PLUGIN_FS, NULL}, NULL},
      85              :     {{BD_PLUGIN_NVDIMM, NULL}, NULL},
      86              :     {{BD_PLUGIN_NVME, NULL}, NULL},
      87              :     {{BD_PLUGIN_SMART, NULL}, NULL},
      88              : };
      89              : static gchar* plugin_names[BD_PLUGIN_UNDEF] = {
      90              :     "lvm", "btrfs", "swap", "loop", "crypto", "mpath", "dm", "mdraid", "s390", "part", "fs", "nvdimm", "nvme", "smart"
      91              : };
      92              : 
      93          460 : static void set_plugin_so_name (BDPlugin name, const gchar *so_name) {
      94          460 :     plugins[name].spec.so_name = so_name;
      95          460 : }
      96              : 
      97            1 : static gint config_file_cmp (gconstpointer a, gconstpointer b, gpointer user_data G_GNUC_UNUSED) {
      98            1 :     const gchar *name1 = (const gchar *) a;
      99            1 :     const gchar *name2 = (const gchar *) b;
     100              : 
     101            1 :     return g_strcmp0 (name1, name2);
     102              : }
     103              : 
     104          281 : static GSequence* get_config_files (GError **error) {
     105          281 :     GDir *dir = NULL;
     106          281 :     GSequence *ret = NULL;
     107          281 :     gchar *conf_dir_path = NULL;
     108          281 :     const gchar *dirent = NULL;
     109              : 
     110          281 :     conf_dir_path = g_strdup (g_getenv("LIBBLOCKDEV_CONFIG_DIR"));
     111          281 :     if (!conf_dir_path)
     112            0 :         conf_dir_path = g_strdup (DEFAULT_CONF_DIR_PATH);
     113              : 
     114          281 :     dir = g_dir_open (conf_dir_path, 0, error);
     115          281 :     if (!dir) {
     116            0 :         g_prefix_error (error, "Failed to get contents of the config dir (%s)", conf_dir_path);
     117            0 :         g_free (conf_dir_path);
     118            0 :         return NULL;
     119              :     }
     120              : 
     121          281 :     ret = g_sequence_new ((GDestroyNotify) g_free);
     122              : 
     123          281 :     dirent = g_dir_read_name(dir);
     124          563 :     while (dirent) {
     125              :         /* only process .cfg files from the directory */
     126          282 :         if (g_str_has_suffix (dirent, ".cfg")) {
     127          282 :             dirent = g_build_filename (conf_dir_path, dirent, NULL);
     128          282 :             g_sequence_insert_sorted (ret, (gpointer) dirent, config_file_cmp, NULL);
     129              :         }
     130          282 :         dirent = g_dir_read_name(dir);
     131              :     }
     132              : 
     133          281 :     g_free (conf_dir_path);
     134          281 :     g_dir_close (dir);
     135          281 :     return ret;
     136              : }
     137              : 
     138          282 : static gboolean process_config_file (const gchar *config_file, GSList **plugins_sonames, GError **error) {
     139          282 :     GKeyFile *config = NULL;
     140          282 :     BDPlugin i = 0;
     141          282 :     gchar **sonames = NULL;
     142          282 :     gsize n_sonames = 0;
     143              : 
     144          282 :     config = g_key_file_new ();
     145          282 :     if (!g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, error))
     146            0 :         return FALSE;
     147              : 
     148              :     /* get sonames for each plugin (if specified) */
     149         4230 :     for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
     150         3948 :         sonames = g_key_file_get_string_list (config, plugin_names[i], "sonames", &n_sonames, error);
     151         3948 :         if (!sonames) {
     152              :             /* no sonames specified or an error occurred */
     153           21 :             if (*error)
     154           21 :                 g_clear_error (error);
     155              :         } else {
     156              :             /* go through the sonames in the reversed order (because we prepend
     157              :                them to the list) */
     158         8134 :             for (; n_sonames > 0; n_sonames--) {
     159         4207 :                 plugins_sonames[i] = g_slist_prepend (plugins_sonames[i], sonames[n_sonames-1]);
     160              :             }
     161              :             /* we need to free only the array here not its items because those
     162              :                were put into the list above as pointers */
     163         3927 :             g_free (sonames);
     164              :         }
     165              :     }
     166              : 
     167          282 :     g_key_file_free (config);
     168              : 
     169          282 :     return TRUE;
     170              : }
     171              : 
     172          281 : static gboolean load_config (GSequence *config_files, GSList **plugins_sonames, GError **error) {
     173          281 :     GSequenceIter *config_file_iter = NULL;
     174          281 :     gchar *config_file = NULL;
     175              : 
     176              :     /* process config files one after another in order */
     177          281 :     config_file_iter = g_sequence_get_begin_iter (config_files);
     178          563 :     while (!g_sequence_iter_is_end (config_file_iter)) {
     179          282 :         config_file = (gchar *) g_sequence_get (config_file_iter);
     180          282 :         if (!process_config_file (config_file, plugins_sonames, error)) {
     181            0 :             bd_utils_log_format (BD_UTILS_LOG_WARNING, "Cannot process the config file '%s': %s. Skipping.",
     182            0 :                                  config_file, (*error)->message);
     183            0 :             g_clear_error (error);
     184              :         }
     185          282 :         config_file_iter = g_sequence_iter_next (config_file_iter);
     186              :     }
     187              : 
     188          281 :     return TRUE;
     189              : }
     190              : 
     191          271 : static void unload_plugins (void) {
     192          271 :     if (plugins[BD_PLUGIN_LVM].handle && !unload_lvm (plugins[BD_PLUGIN_LVM].handle))
     193            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the lvm plugin");
     194          271 :     plugins[BD_PLUGIN_LVM].handle = NULL;
     195              : 
     196          271 :     if (plugins[BD_PLUGIN_BTRFS].handle && !unload_btrfs (plugins[BD_PLUGIN_BTRFS].handle))
     197            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the btrfs plugin");
     198          271 :     plugins[BD_PLUGIN_BTRFS].handle = NULL;
     199              : 
     200          271 :     if (plugins[BD_PLUGIN_SWAP].handle && !unload_swap (plugins[BD_PLUGIN_SWAP].handle))
     201            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the swap plugin");
     202          271 :     plugins[BD_PLUGIN_SWAP].handle = NULL;
     203              : 
     204          271 :     if (plugins[BD_PLUGIN_LOOP].handle && !unload_loop (plugins[BD_PLUGIN_LOOP].handle))
     205            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the loop plugin");
     206          271 :     plugins[BD_PLUGIN_LOOP].handle = NULL;
     207              : 
     208          271 :     if (plugins[BD_PLUGIN_CRYPTO].handle && !unload_crypto (plugins[BD_PLUGIN_CRYPTO].handle))
     209            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the crypto plugin");
     210          271 :     plugins[BD_PLUGIN_CRYPTO].handle = NULL;
     211              : 
     212          271 :     if (plugins[BD_PLUGIN_MPATH].handle && !unload_mpath (plugins[BD_PLUGIN_MPATH].handle))
     213            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the mpath plugin");
     214          271 :     plugins[BD_PLUGIN_MPATH].handle = NULL;
     215              : 
     216          271 :     if (plugins[BD_PLUGIN_DM].handle && !unload_dm (plugins[BD_PLUGIN_DM].handle))
     217            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the dm plugin");
     218          271 :     plugins[BD_PLUGIN_DM].handle = NULL;
     219              : 
     220          271 :     if (plugins[BD_PLUGIN_MDRAID].handle && !unload_mdraid (plugins[BD_PLUGIN_MDRAID].handle))
     221            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the mdraid plugin");
     222          271 :     plugins[BD_PLUGIN_MDRAID].handle = NULL;
     223              : 
     224              : #if defined(__s390__) || defined(__s390x__)
     225              :     if (plugins[BD_PLUGIN_S390].handle && !unload_s390 (plugins[BD_PLUGIN_S390].handle))
     226              :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the s390 plugin");
     227              :     plugins[BD_PLUGIN_S390].handle = NULL;
     228              : #endif
     229              : 
     230          271 :     if (plugins[BD_PLUGIN_PART].handle && !unload_part (plugins[BD_PLUGIN_PART].handle))
     231            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the part plugin");
     232          271 :     plugins[BD_PLUGIN_PART].handle = NULL;
     233              : 
     234          271 :     if (plugins[BD_PLUGIN_FS].handle && !unload_fs (plugins[BD_PLUGIN_FS].handle))
     235            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the fs plugin");
     236          271 :     plugins[BD_PLUGIN_FS].handle = NULL;
     237              : 
     238          271 :     if (plugins[BD_PLUGIN_NVDIMM].handle && !unload_nvdimm (plugins[BD_PLUGIN_NVDIMM].handle))
     239            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the nvdimm plugin");
     240          271 :     plugins[BD_PLUGIN_NVDIMM].handle = NULL;
     241              : 
     242          271 :     if (plugins[BD_PLUGIN_NVME].handle && !unload_nvme (plugins[BD_PLUGIN_NVME].handle))
     243            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the nvme plugin");
     244          271 :     plugins[BD_PLUGIN_NVME].handle = NULL;
     245              : 
     246          271 :     if (plugins[BD_PLUGIN_SMART].handle && !unload_smart (plugins[BD_PLUGIN_SMART].handle))
     247            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to close the smart plugin");
     248          271 :     plugins[BD_PLUGIN_SMART].handle = NULL;
     249          271 : }
     250              : 
     251          460 : static void load_plugin_from_sonames (BDPlugin plugin, LoadFunc load_fn, void **handle, GSList *sonames) {
     252          920 :     while (!(*handle) && sonames) {
     253          460 :         *handle = load_fn (sonames->data);
     254          460 :         if (*handle)
     255          920 :             set_plugin_so_name(plugin, g_strdup (sonames->data));
     256          460 :         sonames = g_slist_next (sonames);
     257              :     }
     258          460 : }
     259              : 
     260          281 : static void do_load (GSList **plugins_sonames) {
     261          281 :     if (!plugins[BD_PLUGIN_LVM].handle && plugins_sonames[BD_PLUGIN_LVM])
     262           34 :         load_plugin_from_sonames (BD_PLUGIN_LVM, load_lvm_from_plugin, &(plugins[BD_PLUGIN_LVM].handle), plugins_sonames[BD_PLUGIN_LVM]);
     263          281 :     if (!plugins[BD_PLUGIN_BTRFS].handle && plugins_sonames[BD_PLUGIN_BTRFS])
     264           24 :         load_plugin_from_sonames (BD_PLUGIN_BTRFS, load_btrfs_from_plugin, &(plugins[BD_PLUGIN_BTRFS].handle), plugins_sonames[BD_PLUGIN_BTRFS]);
     265          281 :     if (!plugins[BD_PLUGIN_SWAP].handle && plugins_sonames[BD_PLUGIN_SWAP])
     266           21 :         load_plugin_from_sonames (BD_PLUGIN_SWAP,load_swap_from_plugin, &(plugins[BD_PLUGIN_SWAP].handle), plugins_sonames[BD_PLUGIN_SWAP]);
     267          281 :     if (!plugins[BD_PLUGIN_LOOP].handle && plugins_sonames[BD_PLUGIN_LOOP])
     268          155 :         load_plugin_from_sonames (BD_PLUGIN_LOOP, load_loop_from_plugin, &(plugins[BD_PLUGIN_LOOP].handle), plugins_sonames[BD_PLUGIN_LOOP]);
     269          281 :     if (!plugins[BD_PLUGIN_CRYPTO].handle && plugins_sonames[BD_PLUGIN_CRYPTO])
     270           39 :         load_plugin_from_sonames (BD_PLUGIN_CRYPTO, load_crypto_from_plugin, &(plugins[BD_PLUGIN_CRYPTO].handle), plugins_sonames[BD_PLUGIN_CRYPTO]);
     271          281 :     if (!plugins[BD_PLUGIN_MPATH].handle && plugins_sonames[BD_PLUGIN_MPATH])
     272            3 :         load_plugin_from_sonames (BD_PLUGIN_MPATH, load_mpath_from_plugin, &(plugins[BD_PLUGIN_MPATH].handle), plugins_sonames[BD_PLUGIN_MPATH]);
     273          281 :     if (!plugins[BD_PLUGIN_DM].handle && plugins_sonames[BD_PLUGIN_DM])
     274           17 :         load_plugin_from_sonames (BD_PLUGIN_DM, load_dm_from_plugin, &(plugins[BD_PLUGIN_DM].handle), plugins_sonames[BD_PLUGIN_DM]);
     275          281 :     if (!plugins[BD_PLUGIN_MDRAID].handle && plugins_sonames[BD_PLUGIN_MDRAID])
     276           25 :         load_plugin_from_sonames (BD_PLUGIN_MDRAID, load_mdraid_from_plugin, &(plugins[BD_PLUGIN_MDRAID].handle), plugins_sonames[BD_PLUGIN_MDRAID]);
     277              : #if defined(__s390__) || defined(__s390x__)
     278              :     if (!plugins[BD_PLUGIN_S390].handle && plugins_sonames[BD_PLUGIN_S390])
     279              :         load_plugin_from_sonames (BD_PLUGIN_S390, load_s390_from_plugin, &(plugins[BD_PLUGIN_S390].handle), plugins_sonames[BD_PLUGIN_S390]);
     280              : #endif
     281          281 :     if (!plugins[BD_PLUGIN_PART].handle && plugins_sonames[BD_PLUGIN_PART])
     282           35 :         load_plugin_from_sonames (BD_PLUGIN_PART, load_part_from_plugin, &(plugins[BD_PLUGIN_PART].handle), plugins_sonames[BD_PLUGIN_PART]);
     283          281 :     if (!plugins[BD_PLUGIN_FS].handle && plugins_sonames[BD_PLUGIN_FS])
     284          102 :         load_plugin_from_sonames (BD_PLUGIN_FS, load_fs_from_plugin, &(plugins[BD_PLUGIN_FS].handle), plugins_sonames[BD_PLUGIN_FS]);
     285          281 :     if (!plugins[BD_PLUGIN_NVDIMM].handle && plugins_sonames[BD_PLUGIN_NVDIMM])
     286            0 :         load_plugin_from_sonames (BD_PLUGIN_NVDIMM, load_nvdimm_from_plugin, &(plugins[BD_PLUGIN_NVDIMM].handle), plugins_sonames[BD_PLUGIN_NVDIMM]);
     287          281 :     if (!plugins[BD_PLUGIN_NVME].handle && plugins_sonames[BD_PLUGIN_NVME])
     288            3 :         load_plugin_from_sonames (BD_PLUGIN_NVME, load_nvme_from_plugin, &(plugins[BD_PLUGIN_NVME].handle), plugins_sonames[BD_PLUGIN_NVME]);
     289          281 :     if (!plugins[BD_PLUGIN_SMART].handle && plugins_sonames[BD_PLUGIN_SMART])
     290            2 :         load_plugin_from_sonames (BD_PLUGIN_SMART, load_smart_from_plugin, &(plugins[BD_PLUGIN_SMART].handle), plugins_sonames[BD_PLUGIN_SMART]);
     291          281 : }
     292              : 
     293          281 : static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, guint64 *num_loaded) {
     294          281 :     guint8 i = 0;
     295          281 :     gboolean requested_loaded = TRUE;
     296          281 :     GError *error = NULL;
     297          281 :     GSequence *config_files = NULL;
     298          281 :     GSList *plugins_sonames[BD_PLUGIN_UNDEF] = {NULL, NULL, NULL, NULL, NULL,
     299              :                                                 NULL, NULL, NULL, NULL, NULL,
     300              :                                                 NULL, NULL};
     301          281 :     BDPlugin plugin_name = BD_PLUGIN_UNDEF;
     302          281 :     guint64 required_plugins_mask = 0;
     303              : 
     304              :     /* load config files first */
     305          281 :     config_files = get_config_files (&error);
     306          281 :     if (config_files) {
     307          281 :         if (!load_config (config_files, plugins_sonames, &error))
     308            0 :             bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to load config files: %s. Using the built-in config",
     309            0 :                                  error->message);
     310              : 
     311          281 :         g_sequence_free (config_files);
     312              :     } else
     313            0 :         bd_utils_log_format (BD_UTILS_LOG_INFO, "Failed to load config files: %s. Using the built-in config",
     314            0 :                              error->message);
     315          281 :     g_clear_error (&error);
     316              : 
     317              :     /* populate missing items with the built-in defaults */
     318         4215 :     for (i=0; i < BD_PLUGIN_UNDEF; i++)
     319         3934 :         if (!plugins_sonames[i])
     320           16 :             plugins_sonames[i] = g_slist_prepend (plugins_sonames[i], g_strdup (default_plugin_so[i]));
     321              : 
     322              : #if !defined(__s390__) && !defined(__s390x__)
     323              :     /* do not load the s390 plugin by default if not on s390(x) */
     324          281 :     g_slist_free_full (plugins_sonames[BD_PLUGIN_S390], (GDestroyNotify) g_free);
     325          281 :     plugins_sonames[BD_PLUGIN_S390] = NULL;
     326              : #endif
     327              : 
     328              :     /* unload the previously loaded plugins if requested */
     329          281 :     if (reload) {
     330          271 :         unload_plugins ();
     331              :         /* clean all so names and populate back those that are requested or the
     332              :            defaults */
     333         4065 :         for (i=0; i < BD_PLUGIN_UNDEF; i++)
     334         3794 :             plugins[i].spec.so_name = NULL;
     335              :     }
     336              : 
     337          281 :     if (require_plugins) {
     338              :         /* set requested sonames */
     339          760 :         for (i=0; *(require_plugins + i); i++) {
     340          479 :             plugin_name = require_plugins[i]->name;
     341          479 :             required_plugins_mask |= (1 << plugin_name);
     342          479 :             if (require_plugins[i]->so_name) {
     343           31 :                 g_slist_free_full (plugins_sonames[plugin_name], (GDestroyNotify) g_free);
     344           31 :                 plugins_sonames[plugin_name] = NULL;
     345           62 :                 plugins_sonames[plugin_name] = g_slist_prepend(plugins_sonames[plugin_name], g_strdup (require_plugins[i]->so_name));
     346              :             }
     347              :         }
     348              : 
     349              :         /* now remove the defaults for plugins that are not required */
     350         4215 :         for (i=0; (i < BD_PLUGIN_UNDEF); i++)
     351         3934 :             if (!(required_plugins_mask & (1 << i))) {
     352              :                 /* plugin not required */
     353         3455 :                 g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free);
     354         3455 :                 plugins_sonames[i] = NULL;
     355              :             }
     356              :     }
     357              : 
     358          281 :     do_load (plugins_sonames);
     359              : 
     360          281 :     *num_loaded = 0;
     361         4215 :     for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
     362              :         /* if this plugin was required or all plugins were required, check if it
     363              :            was successfully loaded or not */
     364         3934 :         if (!require_plugins || (required_plugins_mask & (1 << i))) {
     365              : #if !defined(__s390__) && !defined(__s390x__)
     366          479 :             if (!require_plugins && (i == BD_PLUGIN_S390))
     367              :                 /* do not check the s390 plugin on different archs unless
     368              :                    explicitly required */
     369            0 :                 continue;
     370              : #endif
     371          479 :             if (plugins[i].handle)
     372          479 :                 (*num_loaded)++;
     373              :             else
     374            0 :                 requested_loaded = FALSE;
     375              :         }
     376              :     }
     377              : 
     378              :     /* clear/free the config */
     379         4215 :     for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
     380         3934 :         if (plugins_sonames[i]) {
     381          479 :             g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free);
     382          479 :             plugins_sonames[i] = NULL;
     383              :         }
     384              :     }
     385              : 
     386          281 :     return requested_loaded;
     387              : }
     388              : 
     389            4 : GQuark bd_init_error_quark (void)
     390              : {
     391            4 :     return g_quark_from_static_string ("g-bd-init-error-quark");
     392              : }
     393              : 
     394              : /**
     395              :  * bd_init:
     396              :  * @require_plugins: (nullable) (array zero-terminated=1): %NULL-terminated list
     397              :  *                 of plugins that should be loaded (if no so_name is specified
     398              :  *                 for the plugin, the default is used) or %NULL to load all
     399              :  *                 plugins
     400              :  * @log_func: (nullable) (scope notified): logging function to use
     401              :  * @error: (out) (optional): place to store error (if any)
     402              :  *
     403              :  * Returns: whether the library was successfully initialized with all the
     404              :  *          required or default (see @require_plugins) plugins or not
     405              :  *
     406              :  * Example of libblockdev initialization with 'fs' and 'lvm' plugins. Specific
     407              :  * version of the lvm plugin is required:
     408              :  *
     409              :  * |[<!-- language="C" -->
     410              :  * GError *error = NULL;
     411              :  * gboolean ret = FALSE;
     412              :  * BDPluginSpec fs_plugin = {BD_PLUGIN_FS, NULL};
     413              :  * BDPluginSpec lvm_plugin = {BD_PLUGIN_LVM, "libbd_lvm.so.3"};
     414              :  *
     415              :  * BDPluginSpec *plugins[] = {&fs_plugin, &lvm_plugin, NULL};
     416              :  *
     417              :  * ret = bd_init (plugins, NULL, &error);
     418              :  * ]|
     419              :  */
     420            2 : gboolean bd_init (BDPluginSpec **require_plugins, BDUtilsLogFunc log_func, GError **error) {
     421            2 :     gboolean success = TRUE;
     422            2 :     guint64 num_loaded = 0;
     423              : 
     424            2 :     g_mutex_lock (&init_lock);
     425            2 :     if (initialized) {
     426            1 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "bd_init() called more than once! Use bd_reinit() to reinitialize "
     427              :                              "or bd_is_initialized() to get the current state.");
     428            1 :         g_mutex_unlock (&init_lock);
     429            1 :         return FALSE;
     430              :     }
     431              : 
     432            1 :     if (log_func && !bd_utils_init_logging (log_func, error)) {
     433              :         /* the error is already populated */
     434            0 :         g_mutex_unlock (&init_lock);
     435            0 :         return FALSE;
     436              :     }
     437              : 
     438            1 :     if (!load_plugins (require_plugins, FALSE, &num_loaded)) {
     439            0 :         g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_PLUGINS_FAILED,
     440              :                      "Failed to load plugins");
     441            0 :         success = FALSE;
     442              :     }
     443              : 
     444            1 :     if (num_loaded == 0) {
     445            0 :         if (require_plugins && (*require_plugins == NULL))
     446              :             /* requested to load no plugins (NULL is the first item in the
     447              :                array), none loaded -> OK */
     448            0 :             initialized = TRUE;
     449              :         else
     450            0 :             initialized = FALSE;
     451              :     } else
     452            1 :         initialized = TRUE;
     453              : 
     454            1 :     g_mutex_unlock (&init_lock);
     455              : 
     456            1 :     return success;
     457              : }
     458              : 
     459              : /**
     460              :  * bd_ensure_init:
     461              :  * @require_plugins: (nullable) (array zero-terminated=1): %NULL-terminated list
     462              :  *                 of plugins that should be loaded (if no so_name is specified
     463              :  *                 for the plugin, the default is used) or %NULL to load all
     464              :  *                 plugins
     465              :  * @log_func: (nullable) (scope notified): logging function to use
     466              :  * @error: (out) (optional): place to store error (if any)
     467              :  *
     468              :  * Checks the state of the library and if it is uninitialized or not all the
     469              :  * @require_plugins plugins are available, tries to (re)initialize it. Otherwise
     470              :  * just returns early. The difference between:
     471              :  *
     472              :  * |[<!-- language="C" -->
     473              :  * if (!bd_is_initialized())
     474              :  *     bd_init(None, None, &error);
     475              :  * ]|
     476              :  *
     477              :  * and this function is that this function does the check and init in an atomic
     478              :  * way (holding the lock preventing other threads from doing changes in
     479              :  * between).
     480              :  *
     481              :  * Returns: whether the library was successfully initialized with all the
     482              :  *          required or default (see @require_plugins) plugins or not either
     483              :  *          before or by this call
     484              :  */
     485            4 : gboolean bd_ensure_init (BDPluginSpec **require_plugins, BDUtilsLogFunc log_func, GError **error) {
     486            4 :     gboolean success = TRUE;
     487            4 :     BDPluginSpec **check_plugin = NULL;
     488            4 :     gboolean missing = FALSE;
     489            4 :     guint64 num_loaded = 0;
     490            4 :     BDPlugin plugin = BD_PLUGIN_UNDEF;
     491              : 
     492            4 :     g_mutex_lock (&init_lock);
     493            4 :     if (initialized) {
     494            4 :         if (require_plugins)
     495           16 :             for (check_plugin=require_plugins; !missing && *check_plugin; check_plugin++)
     496           12 :                 missing = !bd_is_plugin_available((*check_plugin)->name);
     497              :         else
     498              :             /* all plugins requested */
     499            0 :             for (plugin=BD_PLUGIN_LVM; plugin != BD_PLUGIN_UNDEF; plugin++)
     500            0 :                 missing = !bd_is_plugin_available(plugin);
     501              : 
     502            4 :         if (!missing) {
     503            2 :             g_mutex_unlock (&init_lock);
     504            2 :             return TRUE;
     505              :         }
     506              :     }
     507              : 
     508            2 :     if (log_func && !bd_utils_init_logging (log_func, error)) {
     509              :         /* the error is already populated */
     510            0 :         g_mutex_unlock (&init_lock);
     511            0 :         return FALSE;
     512              :     }
     513              : 
     514            2 :     if (!load_plugins (require_plugins, FALSE, &num_loaded)) {
     515            0 :         g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_PLUGINS_FAILED,
     516              :                      "Failed to load plugins");
     517            0 :         success = FALSE;
     518              :     }
     519              : 
     520            2 :     if (num_loaded == 0) {
     521            0 :         if (require_plugins && (*require_plugins == NULL))
     522              :             /* requested to load no plugins (NULL is the first item in the
     523              :                array), none loaded -> OK */
     524            0 :             initialized = TRUE;
     525              :         else
     526            0 :             initialized = FALSE;
     527              :     } else
     528            2 :         initialized = TRUE;
     529              : 
     530            2 :     g_mutex_unlock (&init_lock);
     531              : 
     532            2 :     return success;
     533              : }
     534              : 
     535              : /**
     536              :  * bd_try_init:
     537              :  * @request_plugins: (nullable) (array zero-terminated=1): %NULL-terminated list
     538              :  *                   of plugins that should be loaded (if no so_name is specified
     539              :  *                   for the plugin, the default is used) or %NULL to load all
     540              :  *                   plugins
     541              :  * @log_func: (nullable) (scope notified): logging function to use
     542              :  * @loaded_plugin_names: (optional) (out) (transfer container) (array zero-terminated=1): names
     543              :  *                       of the successfully loaded plugins
     544              :  * @error: (out) (optional): place to store error (if any)
     545              :  *
     546              :  * Returns: whether the library was successfully initialized with all the
     547              :  *          required or default (see @require_plugins) plugins or not
     548              :  *
     549              :  * *UNLIKE IN CASE OF bd_init() AND bd_ensure_init(), FAILURE TO LOAD A PLUGIN
     550              :  *  IS NOT CONSIDERED ERROR*
     551              :  */
     552            0 : gboolean bd_try_init(BDPluginSpec **request_plugins, BDUtilsLogFunc log_func,
     553              :                      gchar ***loaded_plugin_names, GError **error) {
     554            0 :     gboolean success = TRUE;
     555            0 :     guint64 num_loaded = 0;
     556              : 
     557            0 :     g_mutex_lock (&init_lock);
     558            0 :     if (initialized) {
     559            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "bd_try_init() called more than once! Use bd_reinit() "
     560              :                              "to reinitialize or bd_is_initialized() to get the current state.");
     561            0 :         g_mutex_unlock (&init_lock);
     562            0 :         return FALSE;
     563              :     }
     564              : 
     565            0 :     if (log_func && !bd_utils_init_logging (log_func, error)) {
     566              :         /* the error is already populated */
     567            0 :         g_mutex_unlock (&init_lock);
     568            0 :         return FALSE;
     569              :     }
     570              : 
     571            0 :     success = load_plugins (request_plugins, FALSE, &num_loaded);
     572              : 
     573            0 :     if (num_loaded == 0) {
     574            0 :         if (request_plugins && (*request_plugins == NULL))
     575              :             /* requested to load no plugins (NULL is the first item in the
     576              :                array), none loaded -> OK */
     577            0 :             initialized = TRUE;
     578              :         else
     579            0 :             initialized = FALSE;
     580              :     } else
     581            0 :         initialized = TRUE;
     582              : 
     583            0 :     if (loaded_plugin_names)
     584            0 :         *loaded_plugin_names = bd_get_available_plugin_names ();
     585              : 
     586            0 :     g_mutex_unlock (&init_lock);
     587              : 
     588            0 :     return success;
     589              : }
     590              : 
     591              : /**
     592              :  * bd_reinit:
     593              :  * @require_plugins: (nullable) (array zero-terminated=1): %NULL-terminated list
     594              :  *                 of plugins that should be loaded (if no so_name is specified
     595              :  *                 for the plugin, the default is used) or %NULL to load all
     596              :  *                 plugins
     597              :  * @reload: whether to reload the already loaded plugins or not
     598              :  * @log_func: (nullable) (scope notified): logging function to use or %NULL
     599              :  *                                           to keep the old one
     600              :  * @error: (out) (optional): place to store error (if any)
     601              :  *
     602              :  * Returns: whether the library was successfully initialized or not
     603              :  *
     604              :  * If @reload is %TRUE all the plugins are closed and reloaded otherwise only
     605              :  * the missing plugins are loaded.
     606              :  */
     607          278 : gboolean bd_reinit (BDPluginSpec **require_plugins, gboolean reload, BDUtilsLogFunc log_func, GError **error) {
     608          278 :     gboolean success = TRUE;
     609          278 :     guint64 num_loaded = 0;
     610              : 
     611          278 :     g_mutex_lock (&init_lock);
     612          278 :     if (log_func && !bd_utils_init_logging (log_func, error)) {
     613              :         /* the error is already populated */
     614            0 :         g_mutex_unlock (&init_lock);
     615            0 :         return FALSE;
     616              :     }
     617              : 
     618          278 :     if (!load_plugins (require_plugins, reload, &num_loaded)) {
     619            0 :         g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_PLUGINS_FAILED,
     620              :                      "Failed to load plugins");
     621            0 :         success = FALSE;
     622              :     } else
     623          278 :         if (require_plugins && (*require_plugins == NULL) && reload)
     624              :             /* requested to just unload all plugins */
     625            9 :             success = (num_loaded == 0);
     626              : 
     627          278 :     if (num_loaded == 0) {
     628            9 :         if (require_plugins && (*require_plugins == NULL))
     629              :             /* requested to load no plugins (NULL is the first item in the
     630              :                array), none loaded -> OK */
     631            9 :             initialized = TRUE;
     632              :         else
     633            0 :             initialized = FALSE;
     634              :     } else
     635          269 :         initialized = TRUE;
     636              : 
     637          278 :     g_mutex_unlock (&init_lock);
     638          278 :     return success;
     639              : }
     640              : 
     641              : /**
     642              :  * bd_try_reinit:
     643              :  * @require_plugins: (nullable) (array zero-terminated=1): %NULL-terminated list
     644              :  *                 of plugins that should be loaded (if no so_name is specified
     645              :  *                 for the plugin, the default is used) or %NULL to load all
     646              :  *                 plugins
     647              :  * @reload: whether to reload the already loaded plugins or not
     648              :  * @log_func: (nullable) (scope notified): logging function to use or %NULL
     649              :  *                                           to keep the old one
     650              :  * @loaded_plugin_names: (optional) (out) (transfer container) (array zero-terminated=1): names of the successfully
     651              :  *                                                                loaded plugins
     652              :  * @error: (out) (optional): place to store error (if any)
     653              :  *
     654              :  * Returns: whether the library was successfully initialized or not
     655              :  *
     656              :  * If @reload is %TRUE all the plugins are closed and reloaded otherwise only
     657              :  * the missing plugins are loaded.
     658              :  *
     659              :  * *UNLIKE IN CASE OF bd_init() AND bd_ensure_init(), FAILURE TO LOAD A PLUGIN
     660              :  *  IS NOT CONSIDERED ERROR*
     661              :  */
     662            0 : gboolean bd_try_reinit (BDPluginSpec **require_plugins, gboolean reload, BDUtilsLogFunc log_func,
     663              :                         gchar ***loaded_plugin_names, GError **error) {
     664            0 :     gboolean success = TRUE;
     665            0 :     guint64 num_loaded = 0;
     666              : 
     667            0 :     g_mutex_lock (&init_lock);
     668            0 :     if (log_func && !bd_utils_init_logging (log_func, error)) {
     669              :         /* the error is already populated */
     670            0 :         g_mutex_unlock (&init_lock);
     671            0 :         return FALSE;
     672              :     }
     673              : 
     674            0 :     success = load_plugins (require_plugins, reload, &num_loaded);
     675            0 :     if (success && require_plugins && (*require_plugins == NULL) && reload)
     676              :         /* requested to just unload all plugins */
     677            0 :         success = (num_loaded == 0);
     678              : 
     679            0 :     if (num_loaded == 0) {
     680            0 :         if (require_plugins && (*require_plugins == NULL))
     681              :             /* requested to load no plugins (NULL is the first item in the
     682              :                array), none loaded -> OK */
     683            0 :             initialized = TRUE;
     684              :         else
     685            0 :             initialized = FALSE;
     686              :     } else
     687            0 :         initialized = TRUE;
     688              : 
     689            0 :     if (loaded_plugin_names)
     690            0 :         *loaded_plugin_names = bd_get_available_plugin_names ();
     691              : 
     692            0 :     g_mutex_unlock (&init_lock);
     693            0 :     return success;
     694              : }
     695              : 
     696              : /**
     697              :  * bd_is_initialized:
     698              :  *
     699              :  * Returns: whether the library is initialized or not
     700              :  *
     701              :  * The library is considered initialized if some of the *init*() functions
     702              :  * was/were called and either at least one plugin is loaded or 0 plugins are
     703              :  * loaded after an explicit call that requested 0 plugins to be loaded.
     704              :  */
     705          235 : gboolean bd_is_initialized (void) {
     706          235 :     gboolean is = FALSE;
     707          235 :     g_mutex_lock (&init_lock);
     708          235 :     is = initialized;
     709          235 :     g_mutex_unlock (&init_lock);
     710          235 :     return is;
     711              : }
     712              : 
     713              : /**
     714              :  * bd_get_available_plugin_names:
     715              :  *
     716              :  * Returns: (transfer container) (array zero-terminated=1): an array of string
     717              :  * names of plugins that are available
     718              :  */
     719            9 : gchar** bd_get_available_plugin_names (void) {
     720            9 :     guint8 i = 0;
     721            9 :     guint8 num_loaded = 0;
     722            9 :     guint8 next = 0;
     723              : 
     724          135 :     for (i=0; i < BD_PLUGIN_UNDEF; i++)
     725          126 :         if (plugins[i].handle)
     726           27 :             num_loaded++;
     727              : 
     728            9 :     gchar **ret_plugin_names = g_new0 (gchar*, num_loaded + 1);
     729          135 :     for (i=0; i < BD_PLUGIN_UNDEF; i++)
     730          126 :         if (plugins[i].handle) {
     731           27 :             ret_plugin_names[next] = plugin_names[i];
     732           27 :             next++;
     733              :         }
     734            9 :     ret_plugin_names[next] = NULL;
     735              : 
     736            9 :     return ret_plugin_names;
     737              : }
     738              : 
     739              : /**
     740              :  * bd_is_plugin_available:
     741              :  * @plugin: the queried plugin
     742              :  *
     743              :  * Returns: whether the given plugin is available or not
     744              :  */
     745           12 : gboolean bd_is_plugin_available (BDPlugin plugin) {
     746           12 :     if (plugin < BD_PLUGIN_UNDEF)
     747           12 :         return plugins[plugin].handle != NULL;
     748              :     else
     749            0 :         return FALSE;
     750              : }
     751              : 
     752              : /**
     753              :  * bd_get_plugin_soname:
     754              :  * @plugin: the queried plugin
     755              :  *
     756              :  * Returns: (transfer full): name of the shared object loaded for the plugin or
     757              :  * %NULL if none is loaded
     758              :  */
     759           15 : gchar* bd_get_plugin_soname (BDPlugin plugin) {
     760           15 :     if (plugins[plugin].handle)
     761           30 :         return g_strdup (plugins[plugin].spec.so_name);
     762              : 
     763            0 :     return NULL;
     764              : }
     765              : 
     766              : /**
     767              :  * bd_get_plugin_name:
     768              :  * @plugin: the queried plugin
     769              :  *
     770              :  * Returns: (transfer none): name of the plugin
     771              :  */
     772            0 : gchar* bd_get_plugin_name (BDPlugin plugin) {
     773            0 :     return plugin_names[plugin];
     774              : }
        

Generated by: LCOV version 2.0-1