LCOV - code coverage report
Current view: top level - plugins/fs - ext.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 78.6 % 281 221
Test Date: 2026-01-23 09:12:16 Functions: 88.9 % 54 48
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2017  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 <ext2fs.h>
      21              : #include <e2p.h>
      22              : 
      23              : #include <blockdev/utils.h>
      24              : #include <check_deps.h>
      25              : 
      26              : #include "common.h"
      27              : #include "fs.h"
      28              : #include "ext.h"
      29              : 
      30              : #define EXT2 "ext2"
      31              : #define EXT3 "ext3"
      32              : #define EXT4 "ext4"
      33              : 
      34              : static volatile guint avail_deps = 0;
      35              : static GMutex deps_check_lock;
      36              : 
      37              : #define DEPS_MKE2FS 0
      38              : #define DEPS_MKE2FS_MASK (1 << DEPS_MKE2FS)
      39              : #define DEPS_E2FSCK 1
      40              : #define DEPS_E2FSCK_MASK (1 << DEPS_E2FSCK)
      41              : #define DEPS_TUNE2FS 2
      42              : #define DEPS_TUNE2FS_MASK (1 << DEPS_TUNE2FS)
      43              : #define DEPS_RESIZE2FS 3
      44              : #define DEPS_RESIZE2FS_MASK (1 << DEPS_RESIZE2FS)
      45              : 
      46              : #define DEPS_LAST 4
      47              : 
      48              : static const UtilDep deps[DEPS_LAST] = {
      49              :     {"mke2fs", NULL, NULL, NULL},
      50              :     {"e2fsck", NULL, NULL, NULL},
      51              :     {"tune2fs", NULL, NULL, NULL},
      52              :     {"resize2fs", NULL, NULL, NULL},
      53              : };
      54              : 
      55              : static guint32 fs_mode_util[BD_FS_MODE_LAST+1] = {
      56              :     DEPS_MKE2FS_MASK,       /* mkfs */
      57              :     0,                      /* wipe */
      58              :     DEPS_E2FSCK_MASK,       /* check */
      59              :     DEPS_E2FSCK_MASK,       /* repair */
      60              :     DEPS_TUNE2FS_MASK,      /* set-label */
      61              :     0,                      /* query */
      62              :     DEPS_RESIZE2FS_MASK,    /* resize */
      63              :     DEPS_TUNE2FS_MASK       /* set-uuid */
      64              : };
      65              : 
      66              : 
      67          272 : static gint8 compute_percents (guint8 pass_cur, guint8 pass_total, gint val_cur, gint val_total) {
      68              :     gint perc;
      69              :     gint one_pass;
      70              :     /* first get a percentage in the current pass/stage */
      71          272 :     perc = (val_cur * 100) / val_total;
      72              : 
      73              :     /* now map it to the total progress, splitting the stages equally */
      74          272 :     one_pass = 100 / pass_total;
      75          272 :     perc = ((pass_cur - 1) * one_pass) + (perc / pass_total);
      76              : 
      77          272 :     return perc;
      78              : }
      79              : 
      80              : /**
      81              :  * filter_line_fsck: (skip)
      82              :  * Filter one line - decide what to do with it.
      83              :  *
      84              :  * Returns: Zero or positive number as a percentage, -1 if not a percentage, -2 on an error
      85              :  */
      86          279 : static gint8 filter_line_fsck (const gchar * line, guint8 total_stages) {
      87              :     static GRegex *output_regex = NULL;
      88              :     GMatchInfo *match_info;
      89          279 :     gint8 perc = -1;
      90          279 :     GError *l_error = NULL;
      91              : 
      92          279 :     if (output_regex == NULL) {
      93              :         /* Compile regular expression that matches to e2fsck progress output */
      94            1 :         output_regex = g_regex_new ("^([0-9][0-9]*) ([0-9][0-9]*) ([0-9][0-9]*) (/.*)", 0, 0, &l_error);
      95            1 :         if (output_regex == NULL) {
      96            0 :             bd_utils_log_format (BD_UTILS_LOG_ERR,
      97            0 :                                  "Failed to create regex for parsing progress: %s", l_error->message);
      98            0 :             g_clear_error (&l_error);
      99            0 :             return -2;
     100              :         }
     101              :     }
     102              : 
     103              :     /* Execute regular expression */
     104          279 :     if (g_regex_match (output_regex, line, 0, &match_info)) {
     105              :         guint8 stage;
     106              :         gint64 val_cur;
     107              :         gint64 val_total;
     108              :         gchar *s;
     109              : 
     110              :         /* The output_regex ensures we have a number in these matches, so we can skip
     111              :          * tests for conversion errors.
     112              :          */
     113          272 :         s = g_match_info_fetch (match_info, 1);
     114          272 :         stage = (guint8) g_ascii_strtoull (s, (char **)NULL, 10);
     115          272 :         g_free (s);
     116              : 
     117          272 :         s = g_match_info_fetch (match_info, 2);
     118          272 :         val_cur = g_ascii_strtoll (s, (char **)NULL, 10);
     119          272 :         g_free (s);
     120              : 
     121          272 :         s = g_match_info_fetch (match_info, 3);
     122          272 :         val_total = g_ascii_strtoll (s, (char **)NULL, 10);
     123          272 :         g_free (s);
     124              : 
     125          272 :         perc = compute_percents (stage, total_stages, val_cur, val_total);
     126              :     } else {
     127            7 :         g_match_info_free (match_info);
     128            7 :         bd_utils_log_format (BD_UTILS_LOG_DEBUG,
     129              :                              "Failed to parse progress from: %s", line);
     130            7 :         return -1;
     131              :     }
     132          272 :     g_match_info_free (match_info);
     133          272 :     return perc;
     134              : }
     135              : 
     136          279 : static gboolean extract_e2fsck_progress (const gchar *line, guint8 *completion) {
     137              :     /* A magic number 5, e2fsck has 5 stages, but this can't be read from the output in advance. */
     138              :     gint8 perc;
     139              : 
     140          279 :     perc = filter_line_fsck (line, 5);
     141          279 :     if (perc < 0)
     142            7 :         return FALSE;
     143              : 
     144          272 :     *completion = perc;
     145          272 :     return TRUE;
     146              : }
     147              : 
     148              : 
     149              : /**
     150              :  * bd_fs_ext_is_tech_avail:
     151              :  * @tech: the queried tech
     152              :  * @mode: a bit mask of queried modes of operation (#BDFSTechMode) for @tech
     153              :  * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
     154              :  *
     155              :  * Returns: whether the @tech-@mode combination is available -- supported by the
     156              :  *          plugin implementation and having all the runtime dependencies available
     157              :  */
     158              : G_GNUC_INTERNAL gboolean
     159           21 : bd_fs_ext_is_tech_avail (BDFSTech tech G_GNUC_UNUSED, guint64 mode, GError **error) {
     160           21 :     guint32 required = 0;
     161           21 :     guint i = 0;
     162          189 :     for (i = 0; i <= BD_FS_MODE_LAST; i++)
     163          168 :         if (mode & (1 << i))
     164           39 :             required |= fs_mode_util[i];
     165              : 
     166           21 :     return check_deps (&avail_deps, required, deps, DEPS_LAST, &deps_check_lock, error);
     167              : }
     168              : 
     169              : /**
     170              :  * bd_fs_ext2_info_copy: (skip)
     171              :  *
     172              :  * Creates a new copy of @data.
     173              :  */
     174            0 : BDFSExt2Info* bd_fs_ext2_info_copy (BDFSExt2Info *data) {
     175            0 :     if (data == NULL)
     176            0 :         return NULL;
     177              : 
     178            0 :     BDFSExt2Info *ret = g_new0 (BDFSExt2Info, 1);
     179              : 
     180            0 :     ret->label = g_strdup (data->label);
     181            0 :     ret->uuid = g_strdup (data->uuid);
     182            0 :     ret->state = g_strdup (data->state);
     183            0 :     ret->block_size = data->block_size;
     184            0 :     ret->block_count = data->block_count;
     185            0 :     ret->free_blocks = data->free_blocks;
     186              : 
     187            0 :     return ret;
     188              : }
     189              : 
     190              : /**
     191              :  * bd_fs_ext3_info_copy: (skip)
     192              :  *
     193              :  * Creates a new copy of @data.
     194              :  */
     195            0 : BDFSExt3Info* bd_fs_ext3_info_copy (BDFSExt3Info *data) {
     196            0 :     return (BDFSExt3Info*) bd_fs_ext2_info_copy (data);
     197              : }
     198              : 
     199              : /**
     200              :  * bd_fs_ext4_info_copy: (skip)
     201              :  *
     202              :  * Creates a new copy of @data.
     203              :  */
     204            0 : BDFSExt4Info* bd_fs_ext4_info_copy (BDFSExt4Info *data) {
     205            0 :     return (BDFSExt4Info*) bd_fs_ext2_info_copy (data);
     206              : }
     207              : 
     208              : /**
     209              :  * bd_fs_ext2_info_free: (skip)
     210              :  *
     211              :  * Frees @data.
     212              :  */
     213            0 : void bd_fs_ext2_info_free (BDFSExt2Info *data) {
     214            0 :   if (data == NULL)
     215            0 :       return;
     216              : 
     217            0 :     g_free (data->label);
     218            0 :     g_free (data->uuid);
     219            0 :     g_free (data->state);
     220            0 :     g_free (data);
     221              : }
     222              : 
     223              : /**
     224              :  * bd_fs_ext3_info_free: (skip)
     225              :  *
     226              :  * Frees @data.
     227              :  */
     228            0 : void bd_fs_ext3_info_free (BDFSExt3Info *data) {
     229            0 :     bd_fs_ext2_info_free ((BDFSExt2Info*) data);
     230            0 : }
     231              : 
     232              : /**
     233              :  * bd_fs_ext4_info_free: (skip)
     234              :  *
     235              :  * Frees @data.
     236              :  */
     237            0 : void bd_fs_ext4_info_free (BDFSExt4Info *data) {
     238            0 :     bd_fs_ext2_info_free ((BDFSExt2Info*) data);
     239            0 : }
     240              : 
     241           13 : static BDExtraArg **ext_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra) {
     242           13 :     GPtrArray *options_array = g_ptr_array_new ();
     243           13 :     const BDExtraArg **extra_p = NULL;
     244              : 
     245           13 :     if (options->label && g_strcmp0 (options->label, "") != 0)
     246            4 :         g_ptr_array_add (options_array, bd_extra_arg_new ("-L", options->label));
     247              : 
     248           13 :     if (options->uuid && g_strcmp0 (options->uuid, "") != 0)
     249            4 :         g_ptr_array_add (options_array, bd_extra_arg_new ("-U", options->uuid));
     250              : 
     251           13 :     if (options->dry_run)
     252            5 :         g_ptr_array_add (options_array, bd_extra_arg_new ("-n", ""));
     253              : 
     254           13 :     if (options->no_discard)
     255            0 :         g_ptr_array_add (options_array, bd_extra_arg_new ("-E", "nodiscard"));
     256              : 
     257           13 :     if (options->force)
     258            1 :         g_ptr_array_add (options_array, bd_extra_arg_new ("-F", ""));
     259              : 
     260           13 :     if (extra) {
     261            2 :         for (extra_p = extra; *extra_p; extra_p++)
     262            1 :             g_ptr_array_add (options_array, bd_extra_arg_copy ((BDExtraArg *) *extra_p));
     263              :     }
     264              : 
     265           13 :     g_ptr_array_add (options_array, NULL);
     266              : 
     267           13 :     return (BDExtraArg **) g_ptr_array_free (options_array, FALSE);
     268              : }
     269              : 
     270              : G_GNUC_INTERNAL BDExtraArg **
     271            5 : bd_fs_ext2_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra) {
     272            5 :     return ext_mkfs_options (options, extra);
     273              : }
     274              : 
     275              : G_GNUC_INTERNAL BDExtraArg **
     276            4 : bd_fs_ext3_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra) {
     277            4 :     return ext_mkfs_options (options, extra);
     278              : }
     279              : 
     280              : G_GNUC_INTERNAL BDExtraArg **
     281            4 : bd_fs_ext4_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra) {
     282            4 :     return ext_mkfs_options (options, extra);
     283              : }
     284              : 
     285           55 : static gboolean ext_mkfs (const gchar *device, const BDExtraArg **extra, const gchar *ext_version, GError **error) {
     286           55 :     const gchar *args[5] = {"mke2fs", "-t", ext_version, device, NULL};
     287              : 
     288           55 :     if (!check_deps (&avail_deps, DEPS_MKE2FS_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     289            0 :         return FALSE;
     290              : 
     291           55 :     return bd_utils_exec_and_report_error (args, extra, error);
     292              : }
     293              : 
     294              : /**
     295              :  * bd_fs_ext2_mkfs:
     296              :  * @device: the device to create a new ext2 fs on
     297              :  * @extra: (nullable) (array zero-terminated=1): extra options for the creation (right now
     298              :  *                                                 passed to the 'mke2fs' utility)
     299              :  * @error: (out) (optional): place to store error (if any)
     300              :  *
     301              :  * Returns: whether a new ext2 fs was successfully created on @device or not
     302              :  *
     303              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_MKFS
     304              :  */
     305           17 : gboolean bd_fs_ext2_mkfs (const gchar *device, const BDExtraArg **extra, GError **error) {
     306           17 :     return ext_mkfs (device, extra, EXT2, error);
     307              : }
     308              : 
     309              : /**
     310              :  * bd_fs_ext3_mkfs:
     311              :  * @device: the device to create a new ext3 fs on
     312              :  * @extra: (nullable) (array zero-terminated=1): extra options for the creation (right now
     313              :  *                                                 passed to the 'mke2fs' utility)
     314              :  * @error: (out) (optional): place to store error (if any)
     315              :  *
     316              :  * Returns: whether a new ext3 fs was successfully created on @device or not
     317              :  *
     318              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_MKFS
     319              :  */
     320           15 : gboolean bd_fs_ext3_mkfs (const gchar *device, const BDExtraArg **extra, GError **error) {
     321           15 :     return ext_mkfs (device, extra, EXT3, error);
     322              : }
     323              : 
     324              : /**
     325              :  * bd_fs_ext4_mkfs:
     326              :  * @device: the device to create a new ext4 fs on
     327              :  * @extra: (nullable) (array zero-terminated=1): extra options for the creation (right now
     328              :  *                                                 passed to the 'mkfs.ext4' utility)
     329              :  * @error: (out) (optional): place to store error (if any)
     330              :  *
     331              :  * Returns: whether a new ext4 fs was successfully created on @device or not
     332              :  *
     333              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_MKFS
     334              :  */
     335           23 : gboolean bd_fs_ext4_mkfs (const gchar *device, const BDExtraArg **extra, GError **error) {
     336           23 :     return ext_mkfs (device, extra, EXT4, error);
     337              : }
     338              : 
     339            6 : static gboolean ext_check (const gchar *device, const BDExtraArg **extra, GError **error) {
     340              :     /* Force checking even if the file system seems clean. AND
     341              :      * Open the filesystem read-only, and assume an answer of no to all
     342              :      * questions. */
     343            6 :     const gchar *args_progress[7] = {"e2fsck", "-f", "-n", "-C", "1", device, NULL};
     344            6 :     const gchar *args[5] = {"e2fsck", "-f", "-n", device, NULL};
     345            6 :     gint status = 0;
     346            6 :     gboolean ret = FALSE;
     347              : 
     348            6 :     if (!check_deps (&avail_deps, DEPS_E2FSCK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     349            0 :         return FALSE;
     350              : 
     351            6 :     if (bd_utils_prog_reporting_initialized ()) {
     352            1 :         ret = bd_utils_exec_and_report_progress (args_progress, extra, extract_e2fsck_progress, &status, error);
     353              :     } else {
     354            5 :         ret = bd_utils_exec_and_report_status_error (args, extra, &status, error);
     355              :     }
     356              : 
     357            6 :     if (!ret && (status == 4)) {
     358              :         /* no error should be reported for exit code 4 - File system errors left uncorrected */
     359            0 :         g_clear_error (error);
     360              :     }
     361            6 :     return ret;
     362              : }
     363              : 
     364              : /**
     365              :  * bd_fs_ext2_check:
     366              :  * @device: the device the file system on which to check
     367              :  * @extra: (nullable) (array zero-terminated=1): extra options for the check (right now
     368              :  *                                                 passed to the 'e2fsck' utility)
     369              :  * @error: (out) (optional): place to store error (if any)
     370              :  *
     371              :  * Returns: whether an ext2 file system on the @device is clean or not
     372              :  *
     373              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_CHECK
     374              :  */
     375            1 : gboolean bd_fs_ext2_check (const gchar *device, const BDExtraArg **extra, GError **error) {
     376            1 :     return ext_check (device, extra, error);
     377              : }
     378              : 
     379              : /**
     380              :  * bd_fs_ext3_check:
     381              :  * @device: the device the file system on which to check
     382              :  * @extra: (nullable) (array zero-terminated=1): extra options for the check (right now
     383              :  *                                                 passed to the 'e2fsck' utility)
     384              :  * @error: (out) (optional): place to store error (if any)
     385              :  *
     386              :  * Returns: whether an ext3 file system on the @device is clean or not
     387              :  *
     388              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_CHECK
     389              :  */
     390            1 : gboolean bd_fs_ext3_check (const gchar *device, const BDExtraArg **extra, GError **error) {
     391            1 :     return ext_check (device, extra, error);
     392              : }
     393              : 
     394              : /**
     395              :  * bd_fs_ext4_check:
     396              :  * @device: the device the file system on which to check
     397              :  * @extra: (nullable) (array zero-terminated=1): extra options for the check (right now
     398              :  *                                                 passed to the 'e2fsck' utility)
     399              :  * @error: (out) (optional): place to store error (if any)
     400              :  *
     401              :  * Returns: whether an ext4 file system on the @device is clean or not
     402              :  *
     403              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_CHECK
     404              :  */
     405            4 : gboolean bd_fs_ext4_check (const gchar *device, const BDExtraArg **extra, GError **error) {
     406            4 :     return ext_check (device, extra, error);
     407              : }
     408              : 
     409           11 : static gboolean ext_repair (const gchar *device, gboolean unsafe, const BDExtraArg **extra, GError **error) {
     410              :     /* Force checking even if the file system seems clean. AND
     411              :      *     Automatically repair what can be safely repaired. OR
     412              :      *     Assume an answer of `yes' to all questions. */
     413           11 :     const gchar *args_progress[7] = {"e2fsck", "-f", unsafe ? "-y" : "-p", "-C", "1", device, NULL};
     414           11 :     const gchar *args[5] = {"e2fsck", "-f", unsafe ? "-y" : "-p", device, NULL};
     415           11 :     gint status = 0;
     416           11 :     gboolean ret = FALSE;
     417              : 
     418           11 :     if (!check_deps (&avail_deps, DEPS_E2FSCK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     419            0 :         return FALSE;
     420              : 
     421           11 :     if (bd_utils_prog_reporting_initialized ()) {
     422            0 :         ret = bd_utils_exec_and_report_progress (args_progress, extra, extract_e2fsck_progress, &status, error);
     423              :     } else {
     424           11 :         ret = bd_utils_exec_and_report_status_error (args, extra, &status, error);
     425              :     }
     426              : 
     427           11 :     if (!ret) {
     428            0 :         if (status == 1) {
     429              :             /* no error should be reported for exit code 1 - File system errors corrected */
     430            0 :             g_clear_error (error);
     431            0 :             ret = TRUE;
     432            0 :         } else if (status == 2) {
     433              :             /* no error should be reported for exit code 2 - File system errors corrected, system should be rebooted */
     434            0 :             bd_utils_log_format (BD_UTILS_LOG_WARNING,
     435              :                                  "File system errors on %s were successfully corrected, but system reboot is advised.",
     436              :                                  device);
     437            0 :             g_clear_error (error);
     438            0 :             ret = TRUE;
     439              :         }
     440              :     }
     441           11 :     return ret;
     442              : }
     443              : 
     444              : /**
     445              :  * bd_fs_ext2_repair:
     446              :  * @device: the device the file system on which to repair
     447              :  * @unsafe: whether to do unsafe operations too
     448              :  * @extra: (nullable) (array zero-terminated=1): extra options for the repair (right now
     449              :  *                                                 passed to the 'e2fsck' utility)
     450              :  * @error: (out) (optional): place to store error (if any)
     451              :  *
     452              :  * Returns: whether an ext2 file system on the @device was successfully repaired
     453              :  *          (if needed) or not (error is set in that case)
     454              :  *
     455              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_REPAIR
     456              :  */
     457            3 : gboolean bd_fs_ext2_repair (const gchar *device, gboolean unsafe, const BDExtraArg **extra, GError **error) {
     458            3 :     return ext_repair (device, unsafe, extra, error);
     459              : }
     460              : 
     461              : /**
     462              :  * bd_fs_ext3_repair:
     463              :  * @device: the device the file system on which to repair
     464              :  * @unsafe: whether to do unsafe operations too
     465              :  * @extra: (nullable) (array zero-terminated=1): extra options for the repair (right now
     466              :  *                                                 passed to the 'e2fsck' utility)
     467              :  * @error: (out) (optional): place to store error (if any)
     468              :  *
     469              :  * Returns: whether an ext3 file system on the @device was successfully repaired
     470              :  *          (if needed) or not (error is set in that case)
     471              :  *
     472              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_REPAIR
     473              :  */
     474            3 : gboolean bd_fs_ext3_repair (const gchar *device, gboolean unsafe, const BDExtraArg **extra, GError **error) {
     475            3 :     return ext_repair (device, unsafe, extra, error);
     476              : }
     477              : 
     478              : /**
     479              :  * bd_fs_ext4_repair:
     480              :  * @device: the device the file system on which to repair
     481              :  * @unsafe: whether to do unsafe operations too
     482              :  * @extra: (nullable) (array zero-terminated=1): extra options for the repair (right now
     483              :  *                                                 passed to the 'e2fsck' utility)
     484              :  * @error: (out) (optional): place to store error (if any)
     485              :  *
     486              :  * Returns: whether an ext4 file system on the @device was successfully repaired
     487              :  *          (if needed) or not (error is set in that case)
     488              :  *
     489              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_REPAIR
     490              :  */
     491            5 : gboolean bd_fs_ext4_repair (const gchar *device, gboolean unsafe, const BDExtraArg **extra, GError **error) {
     492            5 :     return ext_repair (device, unsafe, extra, error);
     493              : }
     494              : 
     495           11 : static gboolean ext_set_label (const gchar *device, const gchar *label, GError **error) {
     496           11 :     const gchar *args[5] = {"tune2fs", "-L", label, device, NULL};
     497              : 
     498           11 :     if (!check_deps (&avail_deps, DEPS_TUNE2FS_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     499            0 :         return FALSE;
     500              : 
     501           11 :     return bd_utils_exec_and_report_error (args, NULL, error);
     502              : }
     503              : 
     504              : /**
     505              :  * bd_fs_ext2_set_label:
     506              :  * @device: the device the file system on which to set label for
     507              :  * @label: label to set
     508              :  * @error: (out) (optional): place to store error (if any)
     509              :  *
     510              :  * Returns: whether the label of ext2 file system on the @device was
     511              :  *          successfully set or not
     512              :  *
     513              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_SET_LABEL
     514              :  */
     515            3 : gboolean bd_fs_ext2_set_label (const gchar *device, const gchar *label, GError **error) {
     516            3 :     return ext_set_label (device, label, error);
     517              : }
     518              : 
     519              : /**
     520              :  * bd_fs_ext3_set_label:
     521              :  * @device: the device the file system on which to set label for
     522              :  * @label: label to set
     523              :  * @error: (out) (optional): place to store error (if any)
     524              :  *
     525              :  * Returns: whether the label of ext3 file system on the @device was
     526              :  *          successfully set or not
     527              :  *
     528              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_SET_LABEL
     529              :  */
     530            3 : gboolean bd_fs_ext3_set_label (const gchar *device, const gchar *label, GError **error) {
     531            3 :     return ext_set_label (device, label, error);
     532              : }
     533              : 
     534              : /**
     535              :  * bd_fs_ext4_set_label:
     536              :  * @device: the device the file system on which to set label for
     537              :  * @label: label to set
     538              :  * @error: (out) (optional): place to store error (if any)
     539              :  *
     540              :  * Returns: whether the label of ext4 file system on the @device was
     541              :  *          successfully set or not
     542              :  *
     543              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_SET_LABEL
     544              :  */
     545            5 : gboolean bd_fs_ext4_set_label (const gchar *device, const gchar *label, GError **error) {
     546            5 :     return ext_set_label (device, label, error);
     547              : }
     548              : 
     549              : /**
     550              :  * bd_fs_ext2_check_label:
     551              :  * @label: label to check
     552              :  * @error: (out) (optional): place to store error
     553              :  *
     554              :  * Returns: whether @label is a valid label for the ext2 file system or not
     555              :  *          (reason is provided in @error)
     556              :  *
     557              :  * Tech category: always available
     558              :  */
     559            7 : gboolean bd_fs_ext2_check_label (const gchar *label, GError **error) {
     560            7 :     if (strlen (label) > 16) {
     561            3 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID,
     562              :                      "Label for ext filesystem must be at most 16 characters long.");
     563            3 :         return FALSE;
     564              :     }
     565              : 
     566            4 :     return TRUE;
     567              : }
     568              : 
     569              : /**
     570              :  * bd_fs_ext3_check_label:
     571              :  * @label: label to check
     572              :  * @error: (out) (optional): place to store error (if any)
     573              :  *
     574              :  * Returns: whether @label is a valid label for the ext3 file system or not
     575              :  *          (reason is provided in @error)
     576              :  *
     577              :  * Tech category: always available
     578              :  */
     579            2 : gboolean bd_fs_ext3_check_label (const gchar *label, GError **error) {
     580            2 :     return bd_fs_ext2_check_label (label, error);
     581              : }
     582              : 
     583              : /**
     584              :  * bd_fs_ext4_check_label:
     585              :  * @label: label to check
     586              :  * @error: (out) (optional): place to store error (if any)
     587              :  *
     588              :  * Returns: whether @label is a valid label for the ext4 file system or not
     589              :  *          (reason is provided in @error)
     590              :  *
     591              :  * Tech category: always available
     592              :  */
     593            3 : gboolean bd_fs_ext4_check_label (const gchar *label, GError **error) {
     594            3 :     return bd_fs_ext2_check_label (label, error);
     595              : }
     596              : 
     597           17 : static gboolean ext_set_uuid (const gchar *device, const gchar *uuid, GError **error) {
     598           17 :     const gchar *args[5] = {"tune2fs", "-U", NULL, device, NULL};
     599              : 
     600           17 :     if (!check_deps (&avail_deps, DEPS_TUNE2FS_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     601            0 :         return FALSE;
     602              : 
     603           17 :     if (!uuid)
     604            4 :         args[2] = "random";
     605              :     else
     606           13 :         args[2] = uuid;
     607              : 
     608           17 :     return bd_utils_exec_and_report_error (args, NULL, error);
     609              : }
     610              : 
     611              : /**
     612              :  * bd_fs_ext2_set_uuid:
     613              :  * @device: the device the file system on which to set UUID for
     614              :  * @uuid: (nullable): UUID to set %NULL to generate a new one
     615              :  *                      UUID can also be one of "clear", "random" and "time" to clear,
     616              :  *                      generate a new random/time-based UUID
     617              :  * @error: (out) (optional): place to store error (if any)
     618              :  *
     619              :  * Returns: whether the UUID of ext2 file system on the @device was
     620              :  *          successfully set or not
     621              :  *
     622              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_SET_UUID
     623              :  */
     624            5 : gboolean bd_fs_ext2_set_uuid (const gchar *device, const gchar *uuid, GError **error) {
     625            5 :     return ext_set_uuid (device, uuid, error);
     626              : }
     627              : 
     628              : /**
     629              :  * bd_fs_ext3_set_uuid:
     630              :  * @device: the device the file system on which to set UUID for
     631              :  * @uuid: (nullable): UUID to set %NULL to generate a new one
     632              :  *                      UUID can also be one of "clear", "random" and "time" to clear,
     633              :  *                      generate a new random/time-based UUID
     634              :  * @error: (out) (optional): place to store error (if any)
     635              :  *
     636              :  * Returns: whether the UUID of ext3 file system on the @device was
     637              :  *          successfully set or not
     638              :  *
     639              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_SET_UUID
     640              :  */
     641            5 : gboolean bd_fs_ext3_set_uuid (const gchar *device, const gchar *uuid, GError **error) {
     642            5 :     return ext_set_uuid (device, uuid, error);
     643              : }
     644              : 
     645              : /**
     646              :  * bd_fs_ext4_set_uuid:
     647              :  * @device: the device the file system on which to set UUID for
     648              :  * @uuid: (nullable): UUID to set %NULL to generate a new one
     649              :  *                      UUID can also be one of "clear", "random" and "time" to clear,
     650              :  *                      generate a new random/time-based UUID
     651              :  * @error: (out) (optional): place to store error (if any)
     652              :  *
     653              :  * Returns: whether the UUID of ext4 file system on the @device was
     654              :  *          successfully set or not
     655              :  *
     656              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_SET_UUID
     657              :  */
     658            7 : gboolean bd_fs_ext4_set_uuid (const gchar *device, const gchar *uuid, GError **error) {
     659            7 :     return ext_set_uuid (device, uuid, error);
     660              : }
     661              : 
     662              : /**
     663              :  * bd_fs_ext2_check_uuid:
     664              :  * @uuid: UUID to check
     665              :  * @error: (out) (optional): place to store error
     666              :  *
     667              :  * Returns: whether @uuid is a valid UUID for the ext2 file system or not
     668              :  *          (reason is provided in @error)
     669              :  *
     670              :  * Tech category: always available
     671              :  */
     672            2 : gboolean bd_fs_ext2_check_uuid (const gchar *uuid, GError **error) {
     673            2 :     return check_uuid (uuid, error);
     674              : }
     675              : 
     676              : /**
     677              :  * bd_fs_ext3_check_uuid:
     678              :  * @uuid: UUID to check
     679              :  * @error: (out) (optional): place to store error
     680              :  *
     681              :  * Returns: whether @uuid is a valid UUID for the ext3 file system or not
     682              :  *          (reason is provided in @error)
     683              :  *
     684              :  * Tech category: always available
     685              :  */
     686            2 : gboolean bd_fs_ext3_check_uuid (const gchar *uuid, GError **error) {
     687            2 :     return check_uuid (uuid, error);
     688              : }
     689              : 
     690              : /**
     691              :  * bd_fs_ext4_check_uuid:
     692              :  * @uuid: UUID to check
     693              :  * @error: (out) (optional): place to store error
     694              :  *
     695              :  * Returns: whether @uuid is a valid UUID for the ext4 file system or not
     696              :  *          (reason is provided in @error)
     697              :  *
     698              :  * Tech category: always available
     699              :  */
     700            3 : gboolean bd_fs_ext4_check_uuid (const gchar *uuid, GError **error) {
     701            3 :     return check_uuid (uuid, error);
     702              : }
     703              : 
     704           88 : static gchar *decode_fs_state (unsigned short state) {
     705          176 :     return g_strdup_printf ("%s%s",
     706           88 :                             (state & EXT2_VALID_FS) ? "clean" : "not clean",
     707           88 :                             (state & EXT2_ERROR_FS) ? " with errors" : "");
     708              : }
     709              : 
     710           88 : static gchar *decode_uuid (void *uuid) {
     711           88 :     const char *str = e2p_uuid2str (uuid);
     712           88 :     if (g_strcmp0 (str, "<none>") == 0)
     713            3 :         str = "";
     714           88 :     return g_strdup (str);
     715              : }
     716              : 
     717           88 : static BDFSExtInfo* ext_get_info (const gchar *device, GError **error) {
     718              :     errcode_t retval;
     719              :     ext2_filsys fs;
     720              :     struct ext2_super_block *sb;
     721           88 :     BDFSExtInfo *ret = NULL;
     722              : 
     723           88 :     int flags = (EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES |
     724              :                  EXT2_FLAG_64BITS | EXT2_FLAG_SUPER_ONLY |
     725              :                  EXT2_FLAG_IGNORE_CSUM_ERRORS);
     726              : 
     727              : #ifdef EXT2_FLAG_THREADS
     728           88 :     flags |= EXT2_FLAG_THREADS;
     729              : #endif
     730              : 
     731           88 :     retval = ext2fs_open (device,
     732              :                           flags,
     733              :                           0, /* use_superblock */
     734              :                           0, /* use_blocksize */
     735              :                           unix_io_manager,
     736              :                           &fs);
     737           88 :     if (retval) {
     738            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL, "Failed to open ext4 file system");
     739            0 :         return NULL;
     740              :     }
     741              : 
     742           88 :     sb = fs->super;
     743           88 :     ret = g_new0 (BDFSExtInfo, 1);
     744              : 
     745           88 :     ret->label = g_strndup ((gchar *)sb->s_volume_name, sizeof (sb->s_volume_name));
     746           88 :     ret->uuid = decode_uuid (sb->s_uuid);
     747           88 :     ret->state = decode_fs_state (sb->s_state);
     748           88 :     ret->block_size = EXT2_BLOCK_SIZE (sb);
     749           88 :     ret->block_count = ext2fs_blocks_count (sb);
     750           88 :     ret->free_blocks = ext2fs_free_blocks_count (sb);
     751              : 
     752           88 :     ext2fs_close_free (&fs);
     753           88 :     return ret;
     754              : }
     755              : 
     756              : /**
     757              :  * bd_fs_ext2_get_info:
     758              :  * @device: the device the file system of which to get info for
     759              :  * @error: (out) (optional): place to store error (if any)
     760              :  *
     761              :  * Returns: (transfer full): information about the file system on @device or
     762              :  *                           %NULL in case of error
     763              :  *
     764              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_QUERY
     765              :  */
     766           19 : BDFSExt2Info* bd_fs_ext2_get_info (const gchar *device, GError **error) {
     767           19 :     return (BDFSExt2Info*) ext_get_info (device, error);
     768              : }
     769              : 
     770              : /**
     771              :  * bd_fs_ext3_get_info:
     772              :  * @device: the device the file system of which to get info for
     773              :  * @error: (out) (optional): place to store error (if any)
     774              :  *
     775              :  * Returns: (transfer full): information about the file system on @device or
     776              :  *                           %NULL in case of error
     777              :  *
     778              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_QUERY
     779              :  */
     780           18 : BDFSExt3Info* bd_fs_ext3_get_info (const gchar *device, GError **error) {
     781           18 :     return (BDFSExt3Info*) ext_get_info (device, error);
     782              : }
     783              : 
     784              : /**
     785              :  * bd_fs_ext4_get_info:
     786              :  * @device: the device the file system of which to get info for
     787              :  * @error: (out) (optional): place to store error (if any)
     788              :  *
     789              :  * Returns: (transfer full): information about the file system on @device or
     790              :  *                           %NULL in case of error
     791              :  *
     792              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_QUERY
     793              :  */
     794           45 : BDFSExt4Info* bd_fs_ext4_get_info (const gchar *device, GError **error) {
     795           45 :     return (BDFSExt4Info*) ext_get_info (device, error);
     796              : }
     797              : 
     798           21 : static gboolean ext_resize (const gchar *device, guint64 new_size, const BDExtraArg **extra, GError **error) {
     799           21 :     const gchar *args[4] = {"resize2fs", device, NULL, NULL};
     800           21 :     gboolean ret = FALSE;
     801              : 
     802           21 :     if (!check_deps (&avail_deps, DEPS_RESIZE2FS_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     803            0 :         return FALSE;
     804              : 
     805           21 :     if (new_size != 0)
     806              :         /* resize2fs doesn't understand bytes, just 512B sectors */
     807           15 :         args[2] = g_strdup_printf ("%"G_GUINT64_FORMAT"s", new_size / 512);
     808           21 :     ret = bd_utils_exec_and_report_error (args, extra, error);
     809              : 
     810           21 :     g_free ((gchar *) args[2]);
     811           21 :     return ret;
     812              : }
     813              : 
     814              : /**
     815              :  * bd_fs_ext2_resize:
     816              :  * @device: the device the file system of which to resize
     817              :  * @new_size: new requested size for the file system (if 0, the file system is
     818              :  *            adapted to the underlying block device)
     819              :  * @extra: (nullable) (array zero-terminated=1): extra options for the resize (right now
     820              :  *                                                 passed to the 'resize2fs' utility)
     821              :  * @error: (out) (optional): place to store error (if any)
     822              :  *
     823              :  * Returns: whether the file system on @device was successfully resized or not
     824              :  *
     825              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_RESIZE
     826              :  */
     827            5 : gboolean bd_fs_ext2_resize (const gchar *device, guint64 new_size, const BDExtraArg **extra, GError **error) {
     828            5 :     return ext_resize (device, new_size, extra, error);
     829              : }
     830              : 
     831              : /**
     832              :  * bd_fs_ext3_resize:
     833              :  * @device: the device the file system of which to resize
     834              :  * @new_size: new requested size for the file system (if 0, the file system is
     835              :  *            adapted to the underlying block device)
     836              :  * @extra: (nullable) (array zero-terminated=1): extra options for the resize (right now
     837              :  *                                                 passed to the 'resize2fs' utility)
     838              :  * @error: (out) (optional): place to store error (if any)
     839              :  *
     840              :  * Returns: whether the file system on @device was successfully resized or not
     841              :  *
     842              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_RESIZE
     843              :  */
     844            5 : gboolean bd_fs_ext3_resize (const gchar *device, guint64 new_size, const BDExtraArg **extra, GError **error) {
     845            5 :     return ext_resize (device, new_size, extra, error);
     846              : }
     847              : 
     848              : /**
     849              :  * bd_fs_ext4_resize:
     850              :  * @device: the device the file system of which to resize
     851              :  * @new_size: new requested size for the file system (if 0, the file system is
     852              :  *            adapted to the underlying block device)
     853              :  * @extra: (nullable) (array zero-terminated=1): extra options for the resize (right now
     854              :  *                                                 passed to the 'resize2fs' utility)
     855              :  * @error: (out) (optional): place to store error (if any)
     856              :  *
     857              :  * Returns: whether the file system on @device was successfully resized or not
     858              :  *
     859              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_RESIZE
     860              :  */
     861           11 : gboolean bd_fs_ext4_resize (const gchar *device, guint64 new_size, const BDExtraArg **extra, GError **error) {
     862           11 :     return ext_resize (device, new_size, extra, error);
     863              : }
     864              : 
     865            6 : static guint64 ext_get_min_size (const gchar *device, GError **error) {
     866            6 :     const gchar *args[4] = {"resize2fs", "-P", device, NULL};
     867            6 :     gboolean success = FALSE;
     868            6 :     gchar *output = NULL;
     869            6 :     gchar **lines = NULL;
     870            6 :     gchar **line_p = NULL;
     871            6 :     guint64 min_size = 0;
     872            6 :     gchar **key_val = NULL;
     873            6 :     BDFSExtInfo *info = NULL;
     874              : 
     875            6 :     if (!check_deps (&avail_deps, DEPS_RESIZE2FS_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     876            0 :         return FALSE;
     877              : 
     878            6 :     info = ext_get_info (device, error);
     879            6 :     if (!info)
     880            0 :         return 0;
     881              : 
     882            6 :     success = bd_utils_exec_and_capture_output (args, NULL, &output, error);
     883            6 :     if (!success) {
     884              :         /* error is already populated */
     885            0 :         bd_fs_ext2_info_free (info);
     886            0 :         return 0;
     887              :     }
     888              : 
     889            6 :     lines = g_strsplit (output, "\n", 0);
     890            6 :     g_free (output);
     891              : 
     892            6 :     for (line_p=lines; *line_p; line_p++) {
     893            6 :         if (g_str_has_prefix (*line_p, "Estimated minimum size")) {
     894            6 :             key_val = g_strsplit (*line_p, ":", 2);
     895            6 :             if (g_strv_length (key_val) == 2) {
     896            6 :                 min_size = g_ascii_strtoull (key_val[1], NULL, 0) * info->block_size;
     897            6 :                 g_strfreev (lines);
     898            6 :                 g_strfreev (key_val);
     899            6 :                 bd_fs_ext2_info_free (info);
     900            6 :                 return min_size;
     901              :             } else {
     902            0 :                 g_strfreev (key_val);
     903            0 :                 break;
     904              :             }
     905              :         }
     906              :     }
     907              : 
     908            0 :     g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     909              :                  "Failed to get minimum size for '%s'", device);
     910            0 :     g_strfreev (lines);
     911            0 :     bd_fs_ext2_info_free (info);
     912            0 :     return 0;
     913              : }
     914              : 
     915              : /**
     916              :  * bd_fs_ext2_get_min_size:
     917              :  * @device: the device containing the file system to get min size for
     918              :  * @error: (out) (optional): place to store error (if any)
     919              :  *
     920              :  * Returns: smallest shrunken filesystem size as reported by resize2fs
     921              :  *          in case of error 0 is returned and @error is set
     922              :  *
     923              :  * Tech category: %BD_FS_TECH_EXT2-%BD_FS_TECH_MODE_RESIZE
     924              :  */
     925            4 : guint64 bd_fs_ext2_get_min_size (const gchar *device, GError **error) {
     926            4 :     return ext_get_min_size (device, error);
     927              : }
     928              : 
     929              : /**
     930              :  * bd_fs_ext3_get_min_size:
     931              :  * @device: the device containing the file system to get min size for
     932              :  * @error: (out) (optional): place to store error (if any)
     933              :  *
     934              :  * Returns: smallest shrunken filesystem size as reported by resize2fs
     935              :  *          in case of error 0 is returned and @error is set
     936              :  *
     937              :  * Tech category: %BD_FS_TECH_EXT3-%BD_FS_TECH_MODE_RESIZE
     938              :  */
     939            1 : guint64 bd_fs_ext3_get_min_size (const gchar *device, GError **error) {
     940            1 :     return ext_get_min_size (device, error);
     941              : }
     942              : 
     943              : /**
     944              :  * bd_fs_ext4_get_min_size:
     945              :  * @device: the device containing the file system to get min size for
     946              :  * @error: (out) (optional): place to store error (if any)
     947              :  *
     948              :  * Returns: smallest shrunken filesystem size as reported by resize2fs
     949              :  *          in case of error 0 is returned and @error is set
     950              :  *
     951              :  * Tech category: %BD_FS_TECH_EXT4-%BD_FS_TECH_MODE_RESIZE
     952              :  */
     953            1 : guint64 bd_fs_ext4_get_min_size (const gchar *device, GError **error) {
     954            1 :     return ext_get_min_size (device, error);
     955              : }
        

Generated by: LCOV version 2.0-1