LCOV - code coverage report
Current view: top level - plugins - loop.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 65.8 % 278 183
Test Date: 2026-01-26 13:19:28 Functions: 78.6 % 14 11
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2014  Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Vratislav Podzimek <vpodzime@redhat.com>
      18              :  */
      19              : 
      20              : #include <glib.h>
      21              : #include <unistd.h>
      22              : #include <glob.h>
      23              : #include <string.h>
      24              : #include <fcntl.h>
      25              : #include <sys/ioctl.h>
      26              : #include <linux/loop.h>
      27              : #include <errno.h>
      28              : #include <blockdev/utils.h>
      29              : #include "loop.h"
      30              : 
      31              : #ifndef LOOP_SET_BLOCK_SIZE
      32              : #define LOOP_SET_BLOCK_SIZE     0x4C09
      33              : #endif
      34              : 
      35              : /**
      36              :  * SECTION: loop
      37              :  * @short_description: plugin for operations with loop devices
      38              :  * @title: Loop
      39              :  * @include: loop.h
      40              :  *
      41              :  * A plugin for operations with loop devices. All sizes passed
      42              :  * in/out to/from the functions are in bytes.
      43              :  */
      44              : 
      45              : static GMutex loop_control_lock;
      46              : 
      47              : /**
      48              :  * bd_loop_error_quark: (skip)
      49              :  */
      50            0 : GQuark bd_loop_error_quark (void)
      51              : {
      52            0 :     return g_quark_from_static_string ("g-bd-loop-error-quark");
      53              : }
      54              : 
      55              : /**
      56              :  * bd_loop_init:
      57              :  *
      58              :  * Initializes the plugin. **This function is called automatically by the
      59              :  * library's initialization functions.**
      60              :  *
      61              :  */
      62          157 : gboolean bd_loop_init (void) {
      63              :     /* nothing to do here */
      64          157 :     return TRUE;
      65              : };
      66              : 
      67              : /**
      68              :  * bd_loop_close:
      69              :  *
      70              :  * Cleans up after the plugin. **This function is called automatically by the
      71              :  * library's functions that unload it.**
      72              :  *
      73              :  */
      74          157 : void bd_loop_close (void) {
      75              :     /* nothing to do here */
      76          157 : }
      77              : 
      78              : 
      79              : /**
      80              :  * bd_loop_is_tech_avail:
      81              :  * @tech: the queried tech
      82              :  * @mode: a bit mask of queried modes of operation (#BDLoopTechMode) for @tech
      83              :  * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
      84              :  *
      85              :  * Returns: whether the @tech-@mode combination is available -- supported by the
      86              :  *          plugin implementation and having all the runtime dependencies available
      87              :  */
      88            1 : gboolean bd_loop_is_tech_avail (BDLoopTech tech G_GNUC_UNUSED, guint64 mode G_GNUC_UNUSED, GError **error G_GNUC_UNUSED) {
      89              :     /* all combinations are supported by this implementation of the plugin */
      90            1 :     return TRUE;
      91              : }
      92              : 
      93            0 : void bd_loop_info_free (BDLoopInfo *info) {
      94            0 :     if (info == NULL)
      95            0 :         return;
      96              : 
      97            0 :     g_free (info->backing_file);
      98            0 :     g_free (info);
      99              : }
     100              : 
     101            0 : BDLoopInfo* bd_loop_info_copy (BDLoopInfo *info) {
     102            0 :     if (info == NULL)
     103            0 :         return NULL;
     104              : 
     105            0 :     BDLoopInfo *new_info = g_new0 (BDLoopInfo, 1);
     106              : 
     107            0 :     new_info->backing_file = g_strdup (info->backing_file);
     108            0 :     new_info->offset = info->offset;
     109            0 :     new_info->autoclear = info->autoclear;
     110            0 :     new_info->direct_io = info->direct_io;
     111            0 :     new_info->part_scan = info->part_scan;
     112            0 :     new_info->read_only = info->read_only;
     113              : 
     114            0 :     return new_info;
     115              : }
     116              : 
     117           10 : static gchar* _loop_get_backing_file (const gchar *dev_name, GError **error) {
     118           10 :     gchar *sys_path = g_strdup_printf ("/sys/class/block/%s/loop/backing_file", dev_name);
     119           10 :     gchar *ret = NULL;
     120           10 :     gboolean success = FALSE;
     121              : 
     122           10 :     if (access (sys_path, R_OK) != 0) {
     123            0 :         g_free (sys_path);
     124            0 :         return NULL;
     125              :     }
     126              : 
     127           10 :     success = g_file_get_contents (sys_path, &ret, NULL, error);
     128           10 :     if (!success) {
     129              :         /* error is already populated */
     130            0 :         g_free (sys_path);
     131            0 :         return NULL;
     132              :     }
     133              : 
     134           10 :     g_free (sys_path);
     135           10 :     return g_strstrip (ret);
     136              : }
     137              : 
     138              : /**
     139              :  * bd_loop_info:
     140              :  * @loop: name of the loop device to get information about (e.g. "loop0")
     141              :  * @error: (out) (optional): place to store error (if any)
     142              :  *
     143              :  * Returns: (transfer full): information about the @loop device or %NULL in case of error
     144              :  *
     145              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
     146              :  */
     147           10 : BDLoopInfo* bd_loop_info (const gchar *loop, GError **error) {
     148           10 :     BDLoopInfo *info = NULL;
     149           10 :     g_autofree gchar *dev_loop = NULL;
     150           10 :     gint fd = -1;
     151              :     struct loop_info64 li64;
     152           10 :     GError *l_error = NULL;
     153              : 
     154           10 :     if (!g_str_has_prefix (loop, "/dev/"))
     155           10 :         dev_loop = g_strdup_printf ("/dev/%s", loop);
     156              : 
     157           10 :     fd = open (dev_loop ? dev_loop : loop, O_RDONLY);
     158           10 :     if (fd < 0) {
     159            0 :         g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
     160              :                      "Failed to open device %s: %m", loop);
     161            0 :         return NULL;
     162              :     }
     163              : 
     164           10 :     memset (&li64, 0, sizeof (li64));
     165           10 :     if (ioctl (fd, LOOP_GET_STATUS64, &li64) < 0) {
     166            0 :         g_set_error (error, BD_LOOP_ERROR,
     167            0 :                      errno == ENXIO ? BD_LOOP_ERROR_DEVICE : BD_LOOP_ERROR_FAIL,
     168              :                      "Failed to get status of the device %s: %m", loop);
     169            0 :         close (fd);
     170            0 :         return NULL;
     171              :     }
     172              : 
     173           10 :     close (fd);
     174              : 
     175           10 :     info = g_new0 (BDLoopInfo, 1);
     176           10 :     info->offset = li64.lo_offset;
     177           10 :     if ((li64.lo_flags & LO_FLAGS_AUTOCLEAR) != 0)
     178            2 :         info->autoclear = TRUE;
     179           10 :     if ((li64.lo_flags & LO_FLAGS_DIRECT_IO) != 0)
     180            0 :         info->direct_io = TRUE;
     181           10 :     if ((li64.lo_flags & LO_FLAGS_PARTSCAN) != 0)
     182            9 :         info->part_scan = TRUE;
     183           10 :     if ((li64.lo_flags & LO_FLAGS_READ_ONLY) != 0)
     184            1 :         info->read_only = TRUE;
     185              : 
     186           10 :     info->backing_file = _loop_get_backing_file (loop, &l_error);
     187           10 :     if (l_error) {
     188            0 :         bd_loop_info_free (info);
     189            0 :         g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     190            0 :                      "Failed to get backing file of the device %s: %s", loop, l_error->message);
     191            0 :         g_clear_error (&l_error);
     192            0 :         return NULL;
     193              :     }
     194              : 
     195           10 :     return info;
     196              : }
     197              : 
     198              : /**
     199              :  * bd_loop_get_loop_name:
     200              :  * @file: path of the backing file to get loop name for
     201              :  * @error: (out) (optional): place to store error (if any)
     202              :  *
     203              :  * Returns: (transfer full): name of the loop device associated with the given
     204              :  * @file or %NULL if failed to determine
     205              :  *
     206              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
     207              :  */
     208            2 : gchar* bd_loop_get_loop_name (const gchar *file, GError **error G_GNUC_UNUSED) {
     209              :     glob_t globbuf;
     210              :     gchar **path_p;
     211            2 :     gboolean success = FALSE;
     212            2 :     gchar *content = NULL;
     213            2 :     gboolean found = FALSE;
     214              :     gchar **parts;
     215              :     gchar *ret;
     216              : 
     217            2 :     if (glob ("/sys/block/loop*/loop/backing_file", GLOB_NOSORT, NULL, &globbuf) != 0) {
     218            1 :         return NULL;
     219              :     }
     220              : 
     221            2 :     for (path_p = globbuf.gl_pathv; *path_p && !found; path_p++) {
     222            1 :         success = g_file_get_contents (*path_p, &content, NULL, NULL);
     223            1 :         if (!success)
     224            0 :             continue;
     225              : 
     226            1 :         g_strstrip (content);
     227            1 :         found = (g_strcmp0 (content, file) == 0);
     228            1 :         g_free (content);
     229              :     }
     230              : 
     231            1 :     if (!found) {
     232            0 :         globfree (&globbuf);
     233            0 :         return NULL;
     234              :     }
     235              : 
     236            1 :     parts = g_strsplit (*(path_p - 1), "/", 5);
     237            1 :     ret = g_strdup (parts[3]);
     238            1 :     g_strfreev (parts);
     239              : 
     240            1 :     globfree (&globbuf);
     241            1 :     return ret;
     242              : }
     243              : 
     244              : /**
     245              :  * bd_loop_setup:
     246              :  * @file: file to setup as a loop device
     247              :  * @offset: offset of the start of the device (in @file)
     248              :  * @size: maximum size of the device (or 0 to leave unspecified)
     249              :  * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
     250              :  * @part_scan: whether to enforce partition scan on the newly created device or not
     251              :  * @sector_size: logical sector size for the loop device in bytes (or 0 for default)
     252              :  * @loop_name: (optional) (out): if not %NULL, it is used to store the name of the loop device
     253              :  * @error: (out) (optional): place to store error (if any)
     254              :  *
     255              :  * Returns: whether the @file was successfully setup as a loop device or not
     256              :  *
     257              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
     258              :  */
     259           31 : gboolean bd_loop_setup (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, guint64 sector_size, const gchar **loop_name, GError **error) {
     260           31 :     gint fd = -1;
     261           31 :     gboolean ret = FALSE;
     262              : 
     263              :     /* open as RDWR so that @read_only determines whether the device is
     264              :        read-only or not */
     265           31 :     fd = open (file, O_RDWR);
     266           31 :     if (fd < 0) {
     267            1 :         g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     268              :                      "Failed to open the backing file '%s': %m", file);
     269            1 :         return FALSE;
     270              :     }
     271              : 
     272           30 :     ret = bd_loop_setup_from_fd (fd, offset, size, read_only, part_scan, sector_size, loop_name, error);
     273           30 :     close (fd);
     274           30 :     return ret;
     275              : }
     276              : 
     277              : /**
     278              :  * bd_loop_setup_from_fd:
     279              :  * @fd: file descriptor for a file to setup as a new loop device
     280              :  * @offset: offset of the start of the device (in file given by @fd)
     281              :  * @size: maximum size of the device (or 0 to leave unspecified)
     282              :  * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
     283              :  * @part_scan: whether to enforce partition scan on the newly created device or not
     284              :  * @sector_size: logical sector size for the loop device in bytes (or 0 for default)
     285              :  * @loop_name: (optional) (out): if not %NULL, it is used to store the name of the loop device
     286              :  * @error: (out) (optional): place to store error (if any)
     287              :  *
     288              :  * Returns: whether a new loop device was successfully setup for @fd or not
     289              :  *
     290              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
     291              :  */
     292           30 : gboolean bd_loop_setup_from_fd (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, guint64 sector_size, const gchar **loop_name, GError **error) {
     293           30 :     gint loop_control_fd = -1;
     294           30 :     gint loop_number = -1;
     295           30 :     gchar *loop_device = NULL;
     296           30 :     gint loop_fd = -1;
     297              :     struct loop_info64 li64;
     298           30 :     guint64 progress_id = 0;
     299           30 :     gint status = 0;
     300           30 :     guint n_try = 0;
     301           30 :     GError *l_error = NULL;
     302              : 
     303           30 :     progress_id = bd_utils_report_started ("Started setting up loop device");
     304              : 
     305           30 :     loop_control_fd = open ("/dev/loop-control", O_RDWR);
     306           30 :     if (loop_control_fd == -1) {
     307            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     308              :                      "Failed to open the loop-control device: %m");
     309            0 :         bd_utils_report_finished (progress_id, l_error->message);
     310            0 :         g_propagate_error (error, l_error);
     311            0 :         return FALSE;
     312              :     }
     313              : 
     314              :     /* XXX: serialize access to loop-control (seems to be required, but it's not
     315              :             documented anywhere) */
     316           30 :     g_mutex_lock (&loop_control_lock);
     317           30 :     loop_number = ioctl (loop_control_fd, LOOP_CTL_GET_FREE);
     318           30 :     g_mutex_unlock (&loop_control_lock);
     319           30 :     close (loop_control_fd);
     320           30 :     if (loop_number < 0) {
     321            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     322              :                      "Failed to open the loop-control device: %m");
     323            0 :         bd_utils_report_finished (progress_id, l_error->message);
     324            0 :         g_propagate_error (error, l_error);
     325            0 :         return FALSE;
     326              :     }
     327              : 
     328           30 :     bd_utils_report_progress (progress_id, 33, "Got free loop device");
     329              : 
     330           30 :     loop_device = g_strdup_printf ("/dev/loop%d", loop_number);
     331           30 :     loop_fd = open (loop_device, read_only ? O_RDONLY : O_RDWR);
     332           30 :     if (loop_fd == -1) {
     333            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     334              :                      "Failed to open the %s device: %m", loop_device);
     335            0 :         g_free (loop_device);
     336            0 :         bd_utils_report_finished (progress_id, l_error->message);
     337            0 :         g_propagate_error (error, l_error);
     338            0 :         return FALSE;
     339              :     }
     340              : 
     341           30 :     memset (&li64, '\0', sizeof (li64));
     342           30 :     if (read_only)
     343            2 :         li64.lo_flags |= LO_FLAGS_READ_ONLY;
     344           30 :     if (part_scan)
     345           28 :         li64.lo_flags |= LO_FLAGS_PARTSCAN;
     346           30 :     if (offset > 0)
     347            2 :         li64.lo_offset = offset;
     348           30 :     if (size > 0)
     349            1 :         li64.lo_sizelimit = size;
     350           30 :     if (ioctl (loop_fd, LOOP_SET_FD, fd) < 0) {
     351            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
     352              :                      "Failed to associate the %s device with the file descriptor: %m", loop_device);
     353            0 :         g_free (loop_device);
     354            0 :         close (loop_fd);
     355            0 :         bd_utils_report_finished (progress_id, l_error->message);
     356            0 :         g_propagate_error (error, l_error);
     357            0 :         return FALSE;
     358              :     }
     359              : 
     360           30 :     bd_utils_report_progress (progress_id, 66, "Associated the loop device");
     361              : 
     362              :     /* we may need to try multiple times with some delays in case the device is
     363              :        busy at the very moment */
     364           30 :     for (n_try=10, status=-1; (status != 0) && (n_try > 0); n_try--) {
     365           30 :         status = ioctl (loop_fd, LOOP_SET_STATUS64, &li64);
     366           30 :         if (status < 0 && errno == EAGAIN)
     367            0 :             g_usleep (100 * 1000); /* microseconds */
     368              :         else
     369              :             break;
     370              :     }
     371              : 
     372           30 :     if (status != 0) {
     373            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     374              :                      "Failed to set status for the %s device: %m", loop_device);
     375            0 :         g_free (loop_device);
     376            0 :         close (loop_fd);
     377            0 :         bd_utils_report_finished (progress_id, l_error->message);
     378            0 :         g_propagate_error (error, l_error);
     379            0 :         return FALSE;
     380              :     }
     381              : 
     382           30 :     if (sector_size > 0) {
     383            2 :         for (n_try=10, status=-1; (status != 0) && (n_try > 0); n_try--) {
     384            2 :             status = ioctl (loop_fd, LOOP_SET_BLOCK_SIZE, (unsigned long) sector_size);
     385            2 :             if (status < 0 && errno == EAGAIN)
     386            0 :                 g_usleep (100 * 1000); /* microseconds */
     387              :             else
     388              :                 break;
     389              :         }
     390              : 
     391            2 :         if (status != 0) {
     392            0 :             g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     393              :                          "Failed to set sector size for the %s device: %m", loop_device);
     394            0 :             g_free (loop_device);
     395            0 :             close (loop_fd);
     396            0 :             bd_utils_report_finished (progress_id, l_error->message);
     397            0 :             g_propagate_error (error, l_error);
     398            0 :             return FALSE;
     399              :         }
     400              :     }
     401              : 
     402           30 :     if (loop_name)
     403           30 :         *loop_name = g_strdup_printf ("loop%d", loop_number);
     404              : 
     405           30 :     g_free (loop_device);
     406           30 :     close (loop_fd);
     407           30 :     bd_utils_report_finished (progress_id, "Completed");
     408           30 :     return TRUE;
     409              : }
     410              : 
     411              : /**
     412              :  * bd_loop_teardown:
     413              :  * @loop: path or name of the loop device to tear down
     414              :  * @error: (out) (optional): place to store error (if any)
     415              :  *
     416              :  * Returns: whether the @loop device was successfully torn down or not
     417              :  *
     418              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_DESTROY
     419              :  */
     420           34 : gboolean bd_loop_teardown (const gchar *loop, GError **error) {
     421           34 :     gchar *dev_loop = NULL;
     422           34 :     gint loop_fd = -1;
     423           34 :     guint64 progress_id = 0;
     424           34 :     GError *l_error = NULL;
     425              : 
     426           34 :     progress_id = bd_utils_report_started ("Started tearing down loop device");
     427              : 
     428           34 :     if (!g_str_has_prefix (loop, "/dev/"))
     429           15 :         dev_loop = g_strdup_printf ("/dev/%s", loop);
     430              : 
     431           34 :     loop_fd = open (dev_loop ? dev_loop : loop, O_RDONLY);
     432           34 :     g_free (dev_loop);
     433           34 :     if (loop_fd == -1) {
     434            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     435              :                      "Failed to open the %s device: %m", loop);
     436            0 :         bd_utils_report_finished (progress_id, l_error->message);
     437            0 :         g_propagate_error (error, l_error);
     438            0 :         return FALSE;
     439              :     }
     440              : 
     441           34 :     if (ioctl (loop_fd, LOOP_CLR_FD) < 0) {
     442            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     443              :                      "Failed to detach the backing file from the %s device: %m", loop);
     444            0 :         close (loop_fd);
     445            0 :         bd_utils_report_finished (progress_id, l_error->message);
     446            0 :         g_propagate_error (error, l_error);
     447            0 :         return FALSE;
     448              :     }
     449              : 
     450           34 :     close (loop_fd);
     451           34 :     bd_utils_report_finished (progress_id, "Completed");
     452              : 
     453           34 :     return TRUE;
     454              : }
     455              : 
     456              : /**
     457              :  * bd_loop_set_autoclear:
     458              :  * @loop: path or name of the loop device
     459              :  * @autoclear: whether to set or unset the autoclear flag
     460              :  * @error: (out) (optional): place to store error (if any)
     461              :  *
     462              :  * Returns: whether the autoclear flag was successfully set on the @loop device or not
     463              :  *
     464              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
     465              :  */
     466            5 : gboolean bd_loop_set_autoclear (const gchar *loop, gboolean autoclear, GError **error) {
     467            5 :     gchar *dev_loop = NULL;
     468            5 :     gint fd = -1;
     469              :     struct loop_info64 li64;
     470            5 :     guint64 progress_id = 0;
     471            5 :     gchar *msg = NULL;
     472            5 :     GError *l_error = NULL;
     473              : 
     474            5 :     if (!g_str_has_prefix (loop, "/dev/"))
     475            3 :         dev_loop = g_strdup_printf ("/dev/%s", loop);
     476              : 
     477            5 :     msg = g_strdup_printf ("Started setting up the autoclear flag on the /dev/%s device",
     478              :                            dev_loop ? dev_loop : loop);
     479            5 :     progress_id = bd_utils_report_started (msg);
     480            5 :     g_free (msg);
     481              : 
     482            5 :     fd = open (dev_loop ? dev_loop : loop, O_RDWR);
     483            5 :     g_free (dev_loop);
     484            5 :     if (fd < 0) {
     485            1 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
     486              :                      "Failed to open device %s: %m", loop);
     487            1 :         bd_utils_report_finished (progress_id, l_error->message);
     488            1 :         g_propagate_error (error, l_error);
     489            1 :         return FALSE;
     490              :     }
     491              : 
     492            4 :     memset (&li64, 0, sizeof (li64));
     493            4 :     if (ioctl (fd, LOOP_GET_STATUS64, &li64) < 0) {
     494            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     495              :                      "Failed to get status of the device %s: %m", loop);
     496            0 :         close (fd);
     497            0 :         bd_utils_report_finished (progress_id, l_error->message);
     498            0 :         g_propagate_error (error, l_error);
     499            0 :         return FALSE;
     500              :     }
     501              : 
     502            4 :     if (autoclear)
     503            2 :         li64.lo_flags |= LO_FLAGS_AUTOCLEAR;
     504              :     else
     505            2 :         li64.lo_flags &= (~LO_FLAGS_AUTOCLEAR);
     506              : 
     507            4 :     if (ioctl (fd, LOOP_SET_STATUS64, &li64) < 0) {
     508            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     509              :                      "Failed to set status of the device %s: %m", loop);
     510            0 :         close (fd);
     511            0 :         bd_utils_report_finished (progress_id, l_error->message);
     512            0 :         g_propagate_error (error, l_error);
     513            0 :         return FALSE;
     514              :     }
     515              : 
     516            4 :     close (fd);
     517            4 :     bd_utils_report_finished (progress_id, "Completed");
     518            4 :     return TRUE;
     519              : }
     520              : 
     521              : /**
     522              :  * bd_loop_set_capacity:
     523              :  * @loop: path or name of the loop device
     524              :  * @error: (out) (optional): place to store error (if any)
     525              :  *
     526              :  * Force the loop driver to reread the size of the file associated with the
     527              :  * specified @loop device.
     528              :  *
     529              :  * Returns: whether the LOOP_SET_CAPACITY ioctl was successfully issued or not.
     530              :  *
     531              :  * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
     532              :  */
     533            2 : gboolean bd_loop_set_capacity (const gchar *loop, GError **error) {
     534            2 :     gchar *dev_loop = NULL;
     535            2 :     gint fd = -1;
     536            2 :     guint64 progress_id = 0;
     537            2 :     gchar *msg = NULL;
     538            2 :     guint n_try = 0;
     539            2 :     gint status = 0;
     540            2 :     GError *l_error = NULL;
     541              : 
     542            2 :     if (!g_str_has_prefix (loop, "/dev/"))
     543            2 :         dev_loop = g_strdup_printf ("/dev/%s", loop);
     544              : 
     545            2 :     msg = g_strdup_printf ("Started setting up capacity on the %s device",
     546              :                            dev_loop ? dev_loop : loop);
     547            2 :     progress_id = bd_utils_report_started (msg);
     548            2 :     g_free (msg);
     549              : 
     550            2 :     fd = open (dev_loop ? dev_loop : loop, O_RDWR);
     551            2 :     g_free (dev_loop);
     552            2 :     if (fd < 0) {
     553            1 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
     554              :                      "Failed to open device %s: %m", loop);
     555            1 :         bd_utils_report_finished (progress_id, l_error->message);
     556            1 :         g_propagate_error (error, l_error);
     557            1 :         return FALSE;
     558              :     }
     559              : 
     560            1 :     for (n_try=10, status=-1; (status != 0) && (n_try > 0); n_try--) {
     561            1 :         status = ioctl (fd, LOOP_SET_CAPACITY, 0);
     562            1 :         if (status < 0 && errno == EAGAIN)
     563            0 :             g_usleep (100 * 1000); /* microseconds */
     564              :         else
     565              :             break;
     566              :     }
     567              : 
     568            1 :     if (status != 0) {
     569            0 :         g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
     570              :                      "Failed to set capacity of the device %s: %m", loop);
     571            0 :         close (fd);
     572            0 :         bd_utils_report_finished (progress_id, l_error->message);
     573            0 :         g_propagate_error (error, l_error);
     574            0 :         return FALSE;
     575              :     }
     576              : 
     577            1 :     close (fd);
     578            1 :     bd_utils_report_finished (progress_id, "Completed");
     579            1 :     return TRUE;
     580              : }
        

Generated by: LCOV version 2.0-1