GQuark bd_loop_error_quark (void) { return g_quark_from_static_string ("g-bd-loop-error-quark"); } static gboolean bd_loop_is_tech_avail_stub (BDLoopTech tech, guint64 mode, GError **error) { g_critical ("The function 'bd_loop_is_tech_avail' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_is_tech_avail' called, but not implemented!"); return FALSE; } static gboolean (*_bd_loop_is_tech_avail) (BDLoopTech tech, guint64 mode, GError **error) = bd_loop_is_tech_avail_stub; /** * bd_loop_is_tech_avail: * @tech: the queried tech * @mode: a bit mask of queried modes of operation (#BDLoopTechMode) for @tech * @error: (out): place to store error (details about why the @tech-@mode combination is not available) * * Returns: whether the @tech-@mode combination is available -- supported by the * plugin implementation and having all the runtime dependencies available */ gboolean bd_loop_is_tech_avail (BDLoopTech tech, guint64 mode, GError **error) { return _bd_loop_is_tech_avail (tech, mode, error); } static gchar* bd_loop_get_backing_file_stub (const gchar *dev_name, GError **error) { g_critical ("The function 'bd_loop_get_backing_file' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_get_backing_file' called, but not implemented!"); return NULL; } static gchar* (*_bd_loop_get_backing_file) (const gchar *dev_name, GError **error) = bd_loop_get_backing_file_stub; /** * bd_loop_get_backing_file: * @dev_name: name of the loop device to get backing file for (e.g. "loop0") * @error: (out): place to store error (if any) * * Returns: (transfer full): path of the device's backing file or %NULL if none * is found * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY */ gchar* bd_loop_get_backing_file (const gchar *dev_name, GError **error) { return _bd_loop_get_backing_file (dev_name, error); } static gchar* bd_loop_get_loop_name_stub (const gchar *file, GError **error) { g_critical ("The function 'bd_loop_get_loop_name' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_get_loop_name' called, but not implemented!"); return NULL; } static gchar* (*_bd_loop_get_loop_name) (const gchar *file, GError **error) = bd_loop_get_loop_name_stub; /** * bd_loop_get_loop_name: * @file: path of the backing file to get loop name for * @error: (out): place to store error (if any) * * Returns: (transfer full): name of the loop device associated with the given @file * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY */ gchar* bd_loop_get_loop_name (const gchar *file, GError **error) { return _bd_loop_get_loop_name (file, error); } static gboolean bd_loop_setup_stub (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) { g_critical ("The function 'bd_loop_setup' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_setup' called, but not implemented!"); return FALSE; } static gboolean (*_bd_loop_setup) (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) = bd_loop_setup_stub; /** * bd_loop_setup: * @file: file to setup as a loop device * @offset: offset of the start of the device (in @file) * @size: maximum size of the device (or 0 to leave unspecified) * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE) * @part_scan: whether to enforce partition scan on the newly created device or not * @loop_name: (allow-none) (out): if not %NULL, it is used to store the name of the loop device * @error: (out): place to store error (if any) * * Returns: whether the @file was successfully setup as a loop device or not * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE */ gboolean bd_loop_setup (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) { return _bd_loop_setup (file, offset, size, read_only, part_scan, loop_name, error); } static gboolean bd_loop_setup_from_fd_stub (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) { g_critical ("The function 'bd_loop_setup_from_fd' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_setup_from_fd' called, but not implemented!"); return FALSE; } static gboolean (*_bd_loop_setup_from_fd) (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) = bd_loop_setup_from_fd_stub; /** * bd_loop_setup_from_fd: * @fd: file descriptor for a file to setup as a new loop device * @offset: offset of the start of the device (in file given by @fd) * @size: maximum size of the device (or 0 to leave unspecified) * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE) * @part_scan: whether to enforce partition scan on the newly created device or not * @loop_name: (allow-none) (out): if not %NULL, it is used to store the name of the loop device * @error: (out): place to store error (if any) * * Returns: whether an new loop device was successfully setup for @fd or not * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE */ gboolean bd_loop_setup_from_fd (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) { return _bd_loop_setup_from_fd (fd, offset, size, read_only, part_scan, loop_name, error); } static gboolean bd_loop_teardown_stub (const gchar *loop, GError **error) { g_critical ("The function 'bd_loop_teardown' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_teardown' called, but not implemented!"); return FALSE; } static gboolean (*_bd_loop_teardown) (const gchar *loop, GError **error) = bd_loop_teardown_stub; /** * bd_loop_teardown: * @loop: path or name of the loop device to tear down * @error: (out): place to store error (if any) * * Returns: whether the @loop device was successfully torn down or not * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_DESTROY */ gboolean bd_loop_teardown (const gchar *loop, GError **error) { return _bd_loop_teardown (loop, error); } static gboolean bd_loop_get_autoclear_stub (const gchar *loop, GError **error) { g_critical ("The function 'bd_loop_get_autoclear' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_get_autoclear' called, but not implemented!"); return FALSE; } static gboolean (*_bd_loop_get_autoclear) (const gchar *loop, GError **error) = bd_loop_get_autoclear_stub; /** * bd_loop_get_autoclear: * @loop: path or name of the loop device * @error: (out): place to store error (if any) * * Returns: whether the autoclear flag is set on the @loop device or not (if %FALSE, @error may be set) * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY */ gboolean bd_loop_get_autoclear (const gchar *loop, GError **error) { return _bd_loop_get_autoclear (loop, error); } static gboolean bd_loop_set_autoclear_stub (const gchar *loop, gboolean autoclear, GError **error) { g_critical ("The function 'bd_loop_set_autoclear' called, but not implemented!"); g_set_error (error, BD_INIT_ERROR, BD_INIT_ERROR_NOT_IMPLEMENTED, "The function 'bd_loop_set_autoclear' called, but not implemented!"); return FALSE; } static gboolean (*_bd_loop_set_autoclear) (const gchar *loop, gboolean autoclear, GError **error) = bd_loop_set_autoclear_stub; /** * bd_loop_set_autoclear: * @loop: path or name of the loop device * @autoclear: whether to set or unset the autoclear flag * @error: (out): place to store error (if any) * * Returns: whether the autoclear flag was successfully set on the @loop device or not * * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY */ gboolean bd_loop_set_autoclear (const gchar *loop, gboolean autoclear, GError **error) { return _bd_loop_set_autoclear (loop, autoclear, error); } static gpointer load_loop_from_plugin(const gchar *so_name) { void *handle = NULL; char *error = NULL; gboolean (*check_fn) (void) = NULL; gboolean (*init_fn) (void) = NULL; handle = dlopen(so_name, RTLD_LAZY); if (!handle) { g_warning("failed to load module loop: %s", dlerror()); return NULL; } dlerror(); * (void**) (&check_fn) = dlsym(handle, "bd_loop_check_deps"); if ((error = dlerror()) != NULL) g_debug("failed to load the check() function for loop: %s", error); /* coverity[dead_error_condition] */ if (!g_getenv ("LIBBLOCKDEV_SKIP_DEP_CHECKS") && check_fn && !check_fn()) { dlclose(handle); return NULL; } check_fn = NULL; dlerror(); * (void**) (&init_fn) = dlsym(handle, "bd_loop_init"); if ((error = dlerror()) != NULL) g_debug("failed to load the init() function for loop: %s", error); /* coverity[dead_error_condition] */ if (init_fn && !init_fn()) { dlclose(handle); return NULL; } init_fn = NULL; dlerror(); * (void**) (&_bd_loop_is_tech_avail) = dlsym(handle, "bd_loop_is_tech_avail"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_is_tech_avail: %s", error); dlerror(); * (void**) (&_bd_loop_get_backing_file) = dlsym(handle, "bd_loop_get_backing_file"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_get_backing_file: %s", error); dlerror(); * (void**) (&_bd_loop_get_loop_name) = dlsym(handle, "bd_loop_get_loop_name"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_get_loop_name: %s", error); dlerror(); * (void**) (&_bd_loop_setup) = dlsym(handle, "bd_loop_setup"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_setup: %s", error); dlerror(); * (void**) (&_bd_loop_setup_from_fd) = dlsym(handle, "bd_loop_setup_from_fd"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_setup_from_fd: %s", error); dlerror(); * (void**) (&_bd_loop_teardown) = dlsym(handle, "bd_loop_teardown"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_teardown: %s", error); dlerror(); * (void**) (&_bd_loop_get_autoclear) = dlsym(handle, "bd_loop_get_autoclear"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_get_autoclear: %s", error); dlerror(); * (void**) (&_bd_loop_set_autoclear) = dlsym(handle, "bd_loop_set_autoclear"); if ((error = dlerror()) != NULL) g_warning("failed to load bd_loop_set_autoclear: %s", error); return handle; } static gboolean unload_loop (gpointer handle) { char *error = NULL; gboolean (*close_fn) (void) = NULL; _bd_loop_is_tech_avail = bd_loop_is_tech_avail_stub; _bd_loop_get_backing_file = bd_loop_get_backing_file_stub; _bd_loop_get_loop_name = bd_loop_get_loop_name_stub; _bd_loop_setup = bd_loop_setup_stub; _bd_loop_setup_from_fd = bd_loop_setup_from_fd_stub; _bd_loop_teardown = bd_loop_teardown_stub; _bd_loop_get_autoclear = bd_loop_get_autoclear_stub; _bd_loop_set_autoclear = bd_loop_set_autoclear_stub; dlerror(); * (void**) (&close_fn) = dlsym(handle, "bd_loop_close"); if (((error = dlerror()) != NULL) || !close_fn) g_debug("failed to load the close_plugin() function for loop: %s", error); /* coverity[dead_error_condition] */ if (close_fn) { close_fn(); } return dlclose(handle) == 0; }