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 474 : static void set_plugin_so_name (BDPlugin name, const gchar *so_name) {
94 474 : plugins[name].spec.so_name = so_name;
95 474 : }
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 290 : static GSequence* get_config_files (GError **error) {
105 290 : GDir *dir = NULL;
106 290 : GSequence *ret = NULL;
107 290 : gchar *conf_dir_path = NULL;
108 290 : const gchar *dirent = NULL;
109 :
110 290 : conf_dir_path = g_strdup (g_getenv("LIBBLOCKDEV_CONFIG_DIR"));
111 290 : if (!conf_dir_path)
112 0 : conf_dir_path = g_strdup (DEFAULT_CONF_DIR_PATH);
113 :
114 290 : dir = g_dir_open (conf_dir_path, 0, error);
115 290 : 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 290 : ret = g_sequence_new ((GDestroyNotify) g_free);
122 :
123 290 : dirent = g_dir_read_name(dir);
124 581 : while (dirent) {
125 : /* only process .cfg files from the directory */
126 291 : if (g_str_has_suffix (dirent, ".cfg")) {
127 291 : dirent = g_build_filename (conf_dir_path, dirent, NULL);
128 291 : g_sequence_insert_sorted (ret, (gpointer) dirent, config_file_cmp, NULL);
129 : }
130 291 : dirent = g_dir_read_name(dir);
131 : }
132 :
133 290 : g_free (conf_dir_path);
134 290 : g_dir_close (dir);
135 290 : return ret;
136 : }
137 :
138 291 : static gboolean process_config_file (const gchar *config_file, GSList **plugins_sonames, GError **error) {
139 291 : GKeyFile *config = NULL;
140 291 : BDPlugin i = 0;
141 291 : gchar **sonames = NULL;
142 291 : gsize n_sonames = 0;
143 :
144 291 : config = g_key_file_new ();
145 291 : 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 4365 : for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
150 4074 : sonames = g_key_file_get_string_list (config, plugin_names[i], "sonames", &n_sonames, error);
151 4074 : 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 8395 : for (; n_sonames > 0; n_sonames--) {
159 4342 : 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 4053 : g_free (sonames);
164 : }
165 : }
166 :
167 291 : g_key_file_free (config);
168 :
169 291 : return TRUE;
170 : }
171 :
172 290 : static gboolean load_config (GSequence *config_files, GSList **plugins_sonames, GError **error) {
173 290 : GSequenceIter *config_file_iter = NULL;
174 290 : gchar *config_file = NULL;
175 :
176 : /* process config files one after another in order */
177 290 : config_file_iter = g_sequence_get_begin_iter (config_files);
178 581 : while (!g_sequence_iter_is_end (config_file_iter)) {
179 291 : config_file = (gchar *) g_sequence_get (config_file_iter);
180 291 : 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 291 : config_file_iter = g_sequence_iter_next (config_file_iter);
186 : }
187 :
188 290 : return TRUE;
189 : }
190 :
191 280 : static void unload_plugins (void) {
192 280 : 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 280 : plugins[BD_PLUGIN_LVM].handle = NULL;
195 :
196 280 : 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 280 : plugins[BD_PLUGIN_BTRFS].handle = NULL;
199 :
200 280 : 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 280 : plugins[BD_PLUGIN_SWAP].handle = NULL;
203 :
204 280 : 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 280 : plugins[BD_PLUGIN_LOOP].handle = NULL;
207 :
208 280 : 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 280 : plugins[BD_PLUGIN_CRYPTO].handle = NULL;
211 :
212 280 : 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 280 : plugins[BD_PLUGIN_MPATH].handle = NULL;
215 :
216 280 : 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 280 : plugins[BD_PLUGIN_DM].handle = NULL;
219 :
220 280 : 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 280 : 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 280 : 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 280 : plugins[BD_PLUGIN_PART].handle = NULL;
233 :
234 280 : 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 280 : plugins[BD_PLUGIN_FS].handle = NULL;
237 :
238 280 : 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 280 : plugins[BD_PLUGIN_NVDIMM].handle = NULL;
241 :
242 280 : 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 280 : plugins[BD_PLUGIN_NVME].handle = NULL;
245 :
246 280 : 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 280 : plugins[BD_PLUGIN_SMART].handle = NULL;
249 280 : }
250 :
251 474 : static void load_plugin_from_sonames (BDPlugin plugin, LoadFunc load_fn, void **handle, GSList *sonames) {
252 948 : while (!(*handle) && sonames) {
253 474 : *handle = load_fn (sonames->data);
254 474 : if (*handle)
255 948 : set_plugin_so_name(plugin, g_strdup (sonames->data));
256 474 : sonames = g_slist_next (sonames);
257 : }
258 474 : }
259 :
260 290 : static void do_load (GSList **plugins_sonames) {
261 290 : if (!plugins[BD_PLUGIN_LVM].handle && plugins_sonames[BD_PLUGIN_LVM])
262 39 : load_plugin_from_sonames (BD_PLUGIN_LVM, load_lvm_from_plugin, &(plugins[BD_PLUGIN_LVM].handle), plugins_sonames[BD_PLUGIN_LVM]);
263 290 : 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 290 : if (!plugins[BD_PLUGIN_SWAP].handle && plugins_sonames[BD_PLUGIN_SWAP])
266 23 : load_plugin_from_sonames (BD_PLUGIN_SWAP,load_swap_from_plugin, &(plugins[BD_PLUGIN_SWAP].handle), plugins_sonames[BD_PLUGIN_SWAP]);
267 290 : if (!plugins[BD_PLUGIN_LOOP].handle && plugins_sonames[BD_PLUGIN_LOOP])
268 157 : load_plugin_from_sonames (BD_PLUGIN_LOOP, load_loop_from_plugin, &(plugins[BD_PLUGIN_LOOP].handle), plugins_sonames[BD_PLUGIN_LOOP]);
269 290 : if (!plugins[BD_PLUGIN_CRYPTO].handle && plugins_sonames[BD_PLUGIN_CRYPTO])
270 40 : load_plugin_from_sonames (BD_PLUGIN_CRYPTO, load_crypto_from_plugin, &(plugins[BD_PLUGIN_CRYPTO].handle), plugins_sonames[BD_PLUGIN_CRYPTO]);
271 290 : 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 290 : if (!plugins[BD_PLUGIN_DM].handle && plugins_sonames[BD_PLUGIN_DM])
274 18 : load_plugin_from_sonames (BD_PLUGIN_DM, load_dm_from_plugin, &(plugins[BD_PLUGIN_DM].handle), plugins_sonames[BD_PLUGIN_DM]);
275 290 : if (!plugins[BD_PLUGIN_MDRAID].handle && plugins_sonames[BD_PLUGIN_MDRAID])
276 26 : 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 290 : if (!plugins[BD_PLUGIN_PART].handle && plugins_sonames[BD_PLUGIN_PART])
282 36 : load_plugin_from_sonames (BD_PLUGIN_PART, load_part_from_plugin, &(plugins[BD_PLUGIN_PART].handle), plugins_sonames[BD_PLUGIN_PART]);
283 290 : 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 290 : 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 290 : 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 290 : if (!plugins[BD_PLUGIN_SMART].handle && plugins_sonames[BD_PLUGIN_SMART])
290 3 : load_plugin_from_sonames (BD_PLUGIN_SMART, load_smart_from_plugin, &(plugins[BD_PLUGIN_SMART].handle), plugins_sonames[BD_PLUGIN_SMART]);
291 290 : }
292 :
293 290 : static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, guint64 *num_loaded) {
294 290 : guint8 i = 0;
295 290 : gboolean requested_loaded = TRUE;
296 290 : GError *error = NULL;
297 290 : GSequence *config_files = NULL;
298 290 : GSList *plugins_sonames[BD_PLUGIN_UNDEF] = {NULL, NULL, NULL, NULL, NULL,
299 : NULL, NULL, NULL, NULL, NULL,
300 : NULL, NULL};
301 290 : BDPlugin plugin_name = BD_PLUGIN_UNDEF;
302 290 : guint64 required_plugins_mask = 0;
303 :
304 : /* load config files first */
305 290 : config_files = get_config_files (&error);
306 290 : if (config_files) {
307 290 : 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 290 : 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 290 : g_clear_error (&error);
316 :
317 : /* populate missing items with the built-in defaults */
318 4350 : for (i=0; i < BD_PLUGIN_UNDEF; i++)
319 4060 : 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 290 : g_slist_free_full (plugins_sonames[BD_PLUGIN_S390], (GDestroyNotify) g_free);
325 290 : plugins_sonames[BD_PLUGIN_S390] = NULL;
326 : #endif
327 :
328 : /* unload the previously loaded plugins if requested */
329 290 : if (reload) {
330 280 : unload_plugins ();
331 : /* clean all so names and populate back those that are requested or the
332 : defaults */
333 4200 : for (i=0; i < BD_PLUGIN_UNDEF; i++)
334 3920 : plugins[i].spec.so_name = NULL;
335 : }
336 :
337 290 : if (require_plugins) {
338 : /* set requested sonames */
339 783 : for (i=0; *(require_plugins + i); i++) {
340 493 : plugin_name = require_plugins[i]->name;
341 493 : required_plugins_mask |= (1 << plugin_name);
342 493 : if (require_plugins[i]->so_name) {
343 38 : g_slist_free_full (plugins_sonames[plugin_name], (GDestroyNotify) g_free);
344 38 : plugins_sonames[plugin_name] = NULL;
345 76 : 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 4350 : for (i=0; (i < BD_PLUGIN_UNDEF); i++)
351 4060 : if (!(required_plugins_mask & (1 << i))) {
352 : /* plugin not required */
353 3567 : g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free);
354 3567 : plugins_sonames[i] = NULL;
355 : }
356 : }
357 :
358 290 : do_load (plugins_sonames);
359 :
360 290 : *num_loaded = 0;
361 4350 : 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 4060 : if (!require_plugins || (required_plugins_mask & (1 << i))) {
365 : #if !defined(__s390__) && !defined(__s390x__)
366 493 : 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 493 : if (plugins[i].handle)
372 493 : (*num_loaded)++;
373 : else
374 0 : requested_loaded = FALSE;
375 : }
376 : }
377 :
378 : /* clear/free the config */
379 4350 : for (i=0; (i < BD_PLUGIN_UNDEF); i++) {
380 4060 : if (plugins_sonames[i]) {
381 493 : g_slist_free_full (plugins_sonames[i], (GDestroyNotify) g_free);
382 493 : plugins_sonames[i] = NULL;
383 : }
384 : }
385 :
386 290 : 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 3 : gboolean bd_init (BDPluginSpec **require_plugins, BDUtilsLogFunc log_func, GError **error) {
421 3 : gboolean success = TRUE;
422 3 : guint64 num_loaded = 0;
423 :
424 3 : g_mutex_lock (&init_lock);
425 3 : if (initialized) {
426 2 : 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 2 : g_mutex_unlock (&init_lock);
429 2 : 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 1 : gboolean bd_try_init(BDPluginSpec **request_plugins, BDUtilsLogFunc log_func,
553 : gchar ***loaded_plugin_names, GError **error) {
554 1 : gboolean success = TRUE;
555 1 : guint64 num_loaded = 0;
556 :
557 1 : g_mutex_lock (&init_lock);
558 1 : if (initialized) {
559 1 : 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 1 : g_mutex_unlock (&init_lock);
562 1 : 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 285 : gboolean bd_reinit (BDPluginSpec **require_plugins, gboolean reload, BDUtilsLogFunc log_func, GError **error) {
608 285 : gboolean success = TRUE;
609 285 : guint64 num_loaded = 0;
610 :
611 285 : g_mutex_lock (&init_lock);
612 285 : 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 285 : 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 285 : if (require_plugins && (*require_plugins == NULL) && reload)
624 : /* requested to just unload all plugins */
625 10 : success = (num_loaded == 0);
626 :
627 285 : if (num_loaded == 0) {
628 10 : 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 10 : initialized = TRUE;
632 : else
633 0 : initialized = FALSE;
634 : } else
635 275 : initialized = TRUE;
636 :
637 285 : g_mutex_unlock (&init_lock);
638 285 : 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 2 : gboolean bd_try_reinit (BDPluginSpec **require_plugins, gboolean reload, BDUtilsLogFunc log_func,
663 : gchar ***loaded_plugin_names, GError **error) {
664 2 : gboolean success = TRUE;
665 2 : guint64 num_loaded = 0;
666 :
667 2 : g_mutex_lock (&init_lock);
668 2 : 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 2 : success = load_plugins (require_plugins, reload, &num_loaded);
675 2 : if (success && require_plugins && (*require_plugins == NULL) && reload)
676 : /* requested to just unload all plugins */
677 0 : success = (num_loaded == 0);
678 :
679 2 : 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 2 : initialized = TRUE;
688 :
689 2 : if (loaded_plugin_names)
690 2 : *loaded_plugin_names = bd_get_available_plugin_names ();
691 :
692 2 : g_mutex_unlock (&init_lock);
693 2 : 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 239 : gboolean bd_is_initialized (void) {
706 239 : gboolean is = FALSE;
707 239 : g_mutex_lock (&init_lock);
708 239 : is = initialized;
709 239 : g_mutex_unlock (&init_lock);
710 239 : 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 12 : gchar** bd_get_available_plugin_names (void) {
720 12 : guint8 i = 0;
721 12 : guint8 num_loaded = 0;
722 12 : guint8 next = 0;
723 :
724 180 : for (i=0; i < BD_PLUGIN_UNDEF; i++)
725 168 : if (plugins[i].handle)
726 35 : num_loaded++;
727 :
728 12 : gchar **ret_plugin_names = g_new0 (gchar*, num_loaded + 1);
729 180 : for (i=0; i < BD_PLUGIN_UNDEF; i++)
730 168 : if (plugins[i].handle) {
731 35 : ret_plugin_names[next] = plugin_names[i];
732 35 : next++;
733 : }
734 12 : ret_plugin_names[next] = NULL;
735 :
736 12 : 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 14 : gchar* bd_get_plugin_name (BDPlugin plugin) {
773 14 : return plugin_names[plugin];
774 : }
|