From 6e857fc53c95453cd705702c6479add1ed614a27 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Tue, 24 Nov 2020 15:11:30 +0100 Subject: [PATCH 1/2] fs: Add Btrfs to the filesystem plugin This is intended for use case where btrfs is used as a "normal" filesystem on a single device and not as a "volume manager". --- docs/libblockdev-sections.txt | 13 + src/lib/plugin_apis/fs.api | 209 +++++++++++++ src/plugins/fs.c | 14 + src/plugins/fs.h | 6 +- src/plugins/fs/Makefile.am | 6 +- src/plugins/fs/btrfs.c | 469 ++++++++++++++++++++++++++++ src/plugins/fs/btrfs.h | 28 ++ src/plugins/fs/generic.c | 137 ++++++++ src/python/gi/overrides/BlockDev.py | 29 ++ tests/fs_tests/btrfs_test.py | 262 ++++++++++++++++ tests/fs_tests/fs_test.py | 10 + tests/fs_tests/generic_test.py | 56 +++- 12 files changed, 1232 insertions(+), 7 deletions(-) create mode 100644 src/plugins/fs/btrfs.c create mode 100644 src/plugins/fs/btrfs.h create mode 100644 tests/fs_tests/btrfs_test.py diff --git a/docs/libblockdev-sections.txt b/docs/libblockdev-sections.txt index 04fcfd0fc..14e6daf5b 100644 --- a/docs/libblockdev-sections.txt +++ b/docs/libblockdev-sections.txt @@ -704,6 +704,19 @@ bd_fs_exfat_repair bd_fs_exfat_set_label bd_fs_exfat_check_label bd_fs_exfat_wipe +BDFSBtrfsInfo +bd_fs_btrfs_get_info +bd_fs_btrfs_info_copy +bd_fs_btrfs_info_free +bd_fs_btrfs_mkfs +bd_fs_btrfs_wipe +bd_fs_btrfs_check +bd_fs_btrfs_repair +bd_fs_btrfs_set_label +bd_fs_btrfs_check_label +bd_fs_btrfs_set_uuid +bd_fs_btrfs_check_uuid +bd_fs_btrfs_resize
diff --git a/src/lib/plugin_apis/fs.api b/src/lib/plugin_apis/fs.api index c51f8cfb8..26c62820b 100644 --- a/src/lib/plugin_apis/fs.api +++ b/src/lib/plugin_apis/fs.api @@ -516,6 +516,7 @@ typedef enum { BD_FS_TECH_REISERFS, BD_FS_TECH_NILFS2, BD_FS_TECH_EXFAT, + BD_FS_TECH_BTRFS, } BDFSTech; typedef enum { @@ -730,6 +731,67 @@ GType bd_fs_exfat_info_get_type () { return type; } +/** + * BDFSBtrfsInfo: + * @label: label of the filesystem + * @uuid: uuid of the filesystem + * @size: size of the filesystem in bytes + * @free_space: free space on the filesystem in bytes + */ +typedef struct BDFSBtrfsInfo { + gchar *label; + gchar *uuid; + guint64 size; + guint64 free_space; +} BDFSBtrfsInfo; + +/** + * bd_fs_btrfs_info_copy: (skip) + * @data: (allow-none): %BDFSBtrfsInfo to copy + * + * Creates a new copy of @data. + */ +BDFSBtrfsInfo* bd_fs_btrfs_info_copy (BDFSBtrfsInfo *data) { + if (data == NULL) + return NULL; + + BDFSBtrfsInfo *ret = g_new0 (BDFSBtrfsInfo, 1); + + ret->label = g_strdup (data->label); + ret->uuid = g_strdup (data->uuid); + ret->size = data->size; + ret->free_space = data->free_space; + + return ret; +} + +/** + * bd_fs_btrfs_info_free: (skip) + * @data: (allow-none): %BDFSBtrfsInfo to free + * + * Frees @data. + */ +void bd_fs_btrfs_info_free (BDFSBtrfsInfo *data) { + if (data == NULL) + return; + + g_free (data->label); + g_free (data->uuid); + g_free (data); +} + +GType bd_fs_btrfs_info_get_type () { + static GType type = 0; + + if (G_UNLIKELY(type == 0)) { + type = g_boxed_type_register_static("BDFSBtrfsInfo", + (GBoxedCopyFunc) bd_fs_btrfs_info_copy, + (GBoxedFreeFunc) bd_fs_btrfs_info_free); + } + + return type; +} + /** * bd_fs_is_tech_avail: * @tech: the queried tech @@ -2315,4 +2377,151 @@ gboolean bd_fs_exfat_check_label (const gchar *label, GError **error); */ BDFSExfatInfo* bd_fs_exfat_get_info (const gchar *device, GError **error); +/** + * bd_fs_btrfs_mkfs: + * @device: the device to create a new btrfs fs on + * @extra: (allow-none) (array zero-terminated=1): extra options for the creation (right now + * passed to the 'mkfs.btrfs' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether a new btrfs fs was successfully created on @device or not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_MKFS + * + */ +gboolean bd_fs_btrfs_mkfs (const gchar *device, const BDExtraArg **extra, GError **error); + +/** + * bd_fs_btrfs_wipe: + * @device: the device to wipe a Btrfs signature from + * @error: (out): place to store error (if any) + * + * Returns: whether the Btrfs signature was successfully wiped from the @device or + * not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_WIPE + */ +gboolean bd_fs_btrfs_wipe (const gchar *device, GError **error); + +/** + * bd_fs_btrfs_check: + * @device: the device containing the file system to check + * @extra: (allow-none) (array zero-terminated=1): extra options for the check (right now + * passed to the 'btrfsck' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether the filesystem was successfully checked or not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_CHECK + */ +gboolean bd_fs_btrfs_check (const gchar *device, const BDExtraArg **extra, GError **error); + +/** + * bd_fs_btrfs_repair: + * @device: the device containing the file system to repair + * @extra: (allow-none) (array zero-terminated=1): extra options for the repair (right now + * passed to the 'btrfs' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether the filesystem was successfully checked and repaired or not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_REPAIR + */ +gboolean bd_fs_btrfs_repair (const gchar *device, const BDExtraArg **extra, GError **error); + +/** + * bd_fs_btrfs_set_label: + * @mpoint: the mount point of the file system to resize + * @label: label to set + * @error: (out): place to store error (if any) + * + * Returns: whether the label of Btrfs file system on the @mpoint was + * successfully set or not + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_SET_LABEL + */ +gboolean bd_fs_btrfs_set_label (const gchar *mpoint, const gchar *label, GError **error); + +/** + * bd_fs_btrfs_check_label: + * @label: label to check + * @error: (out) (allow-none): place to store error + * + * Returns: whether @label is a valid label for the Btrfs file system or not + * (reason is provided in @error) + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: always available + */ +gboolean bd_fs_btrfs_check_label (const gchar *label, GError **error); + +/** + * bd_fs_btrfs_set_uuid: + * @device: the device containing the file system to set the UUID (serial number) for + * @uuid: (allow-none): UUID to set or %NULL to generate a new one + * @error: (out): place to store error (if any) + * + * Returns: whether the UUID of the Btrfs file system on the @device was + * successfully set or not + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_SET_UUID + */ +gboolean bd_fs_btrfs_set_uuid (const gchar *device, const gchar *uuid, GError **error); + +/** + * bd_fs_btrfs_check_uuid: + * @uuid: UUID to check + * @error: (out) (allow-none): place to store error + * + * Returns: whether @uuid is a valid UUID for the Btrfs file system or not + * (reason is provided in @error) + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: always available + */ +gboolean bd_fs_btrfs_check_uuid (const gchar *uuid, GError **error); + +/** + * bd_fs_btrfs_get_info: + * @mpoint: a mountpoint of the btrfs filesystem to get information about + * @error: (out): place to store error (if any) + * + * Returns: (transfer full): information about the file system on @device or + * %NULL in case of error + * + * Note: This function WON'T WORK for multi device btrfs filesystems, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_QUERY + */ +BDFSBtrfsInfo* bd_fs_btrfs_get_info (const gchar *mpoint, GError **error); + +/** + * bd_fs_btrfs_resize: + * @mpoint: a mountpoint of the to be resized btrfs filesystem + * @new_size: requested new size + * @extra: (allow-none) (array zero-terminated=1): extra options for the volume resize (right now + * passed to the 'btrfs' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether the @mpoint filesystem was successfully resized to @new_size + * or not + * + * Note: This function WON'T WORK for multi device btrfs filesystems, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_BTRFS_TECH_FS-%BD_BTRFS_TECH_MODE_MODIFY + */ +gboolean bd_fs_btrfs_resize (const gchar *mpoint, guint64 new_size, const BDExtraArg **extra, GError **error); + #endif /* BD_FS_API */ diff --git a/src/plugins/fs.c b/src/plugins/fs.c index 54d741cba..a15c7293c 100644 --- a/src/plugins/fs.c +++ b/src/plugins/fs.c @@ -39,6 +39,7 @@ extern gboolean bd_fs_f2fs_is_tech_avail (BDFSTech tech, guint64 mode, GError ** extern gboolean bd_fs_reiserfs_is_tech_avail (BDFSTech tech, guint64 mode, GError **error); extern gboolean bd_fs_nilfs2_is_tech_avail (BDFSTech tech, guint64 mode, GError **error); extern gboolean bd_fs_exfat_is_tech_avail (BDFSTech tech, guint64 mode, GError **error); +extern gboolean bd_fs_btrfs_is_tech_avail (BDFSTech tech, guint64 mode, GError **error); /** * bd_fs_error_quark: (skip) @@ -142,6 +143,17 @@ gboolean bd_fs_check_deps (void) { g_clear_error (&error); } + ret = ret && bd_fs_btrfs_is_tech_avail (BD_FS_TECH_BTRFS, + BD_FS_TECH_MODE_MKFS | BD_FS_TECH_MODE_WIPE | + BD_FS_TECH_MODE_CHECK | BD_FS_TECH_MODE_REPAIR | + BD_FS_TECH_MODE_SET_LABEL | BD_FS_TECH_MODE_QUERY | + BD_FS_TECH_MODE_RESIZE | BD_FS_TECH_MODE_SET_UUID, + &error); + if (!ret && error) { + bd_utils_log_format (BD_UTILS_LOG_WARNING, "%s", error->message); + g_clear_error (&error); + } + return ret; } @@ -206,6 +218,8 @@ gboolean bd_fs_is_tech_avail (BDFSTech tech, guint64 mode, GError **error) { return bd_fs_nilfs2_is_tech_avail (tech, mode, error); case BD_FS_TECH_EXFAT: return bd_fs_exfat_is_tech_avail (tech, mode, error); + case BD_FS_TECH_BTRFS: + return bd_fs_btrfs_is_tech_avail (tech, mode, error); /* coverity[dead_error_begin] */ default: /* this should never be reached (see the comparison with LAST_FS diff --git a/src/plugins/fs.h b/src/plugins/fs.h index 9da86ce2c..20669fd1e 100644 --- a/src/plugins/fs.h +++ b/src/plugins/fs.h @@ -22,7 +22,7 @@ typedef enum { /* XXX: where the file systems start at the enum of technologies */ #define BD_FS_OFFSET 2 -#define BD_FS_LAST_FS 11 +#define BD_FS_LAST_FS 13 typedef enum { BD_FS_TECH_GENERIC = 0, BD_FS_TECH_MOUNT = 1, @@ -35,7 +35,8 @@ typedef enum { BD_FS_TECH_F2FS = 8, BD_FS_TECH_REISERFS = 9, BD_FS_TECH_NILFS2 = 10, - BD_FS_TECH_EXFAT = 11 + BD_FS_TECH_EXFAT = 11, + BD_FS_TECH_BTRFS = 12 } BDFSTech; /* XXX: number of the highest bit of all modes */ @@ -79,3 +80,4 @@ gboolean bd_fs_is_tech_avail (BDFSTech tech, guint64 mode, GError **error); #include "fs/reiserfs.h" #include "fs/nilfs.h" #include "fs/exfat.h" +#include "fs/btrfs.h" diff --git a/src/plugins/fs/Makefile.am b/src/plugins/fs/Makefile.am index 9e2f3d58d..7d55ebd3d 100644 --- a/src/plugins/fs/Makefile.am +++ b/src/plugins/fs/Makefile.am @@ -18,7 +18,8 @@ libbd_fs_la_SOURCES = ../check_deps.c ../check_deps.h \ f2fs.c f2fs.h \ reiserfs.c reiserfs.h \ nilfs.c nilfs.h \ - exfat.c exfat.h + exfat.c exfat.h \ + btrfs.c btrfs.h libincludefsdir = $(includedir)/blockdev/fs/ libincludefs_HEADERS = ext.h \ @@ -30,4 +31,5 @@ libincludefs_HEADERS = ext.h \ f2fs.h \ reiserfs.h \ nilfs.h \ - exfat.h + exfat.h \ + btrfs.h diff --git a/src/plugins/fs/btrfs.c b/src/plugins/fs/btrfs.c new file mode 100644 index 000000000..af4aded03 --- /dev/null +++ b/src/plugins/fs/btrfs.c @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Vojtech Trefny + */ + +#include +#include +#include + +#include "btrfs.h" +#include "fs.h" +#include "common.h" + +static volatile guint avail_deps = 0; +static GMutex deps_check_lock; + +#define DEPS_MKFSBTRFS 0 +#define DEPS_MKFSBTRFS_MASK (1 << DEPS_MKFSBTRFS) +#define DEPS_BTRFSCK 1 +#define DEPS_BTRFSCK_MASK (1 << DEPS_BTRFSCK) +#define DEPS_BTRFS 2 +#define DEPS_BTRFS_MASK (1 << DEPS_BTRFS) +#define DEPS_BTRFSTUNE 3 +#define DEPS_BTRFSTUNE_MASK (1 << DEPS_BTRFSTUNE) + +#define DEPS_LAST 4 + +static const UtilDep deps[DEPS_LAST] = { + {"mkfs.btrfs", NULL, NULL, NULL}, + {"btrfsck", NULL, NULL, NULL}, + {"btrfs", NULL, NULL, NULL}, + {"btrfstune", NULL, NULL, NULL}, +}; + +static guint32 fs_mode_util[BD_FS_MODE_LAST+1] = { + DEPS_MKFSBTRFS_MASK, /* mkfs */ + 0, /* wipe */ + DEPS_BTRFSCK_MASK, /* check */ + DEPS_BTRFSCK_MASK, /* repair */ + DEPS_BTRFS_MASK, /* set-label */ + DEPS_BTRFS_MASK, /* query */ + DEPS_BTRFS_MASK, /* resize */ + DEPS_BTRFSTUNE_MASK, /* set-uuid */ +}; + +#define UNUSED __attribute__((unused)) + +/** + * bd_fs_btrfs_is_tech_avail: + * @tech: the queried tech + * @mode: a bit mask of queried modes of operation (#BDFSTechMode) 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 __attribute__ ((visibility ("hidden"))) +bd_fs_btrfs_is_tech_avail (BDFSTech tech UNUSED, guint64 mode, GError **error) { + guint32 required = 0; + guint i = 0; + + for (i = 0; i <= BD_FS_MODE_LAST; i++) + if (mode & (1 << i)) + required |= fs_mode_util[i]; + + return check_deps (&avail_deps, required, deps, DEPS_LAST, &deps_check_lock, error); +} + +/** + * bd_fs_btrfs_info_copy: (skip) + * + * Creates a new copy of @data. + */ +BDFSBtrfsInfo* bd_fs_btrfs_info_copy (BDFSBtrfsInfo *data) { + if (data == NULL) + return NULL; + + BDFSBtrfsInfo *ret = g_new0 (BDFSBtrfsInfo, 1); + + ret->label = g_strdup (data->label); + ret->uuid = g_strdup (data->uuid); + ret->size = data->size; + ret->free_space = data->free_space; + + return ret; +} + +/** + * bd_fs_btrfs_info_free: (skip) + * + * Frees @data. + */ +void bd_fs_btrfs_info_free (BDFSBtrfsInfo *data) { + if (data == NULL) + return; + + g_free (data->label); + g_free (data->uuid); + g_free (data); +} + +BDExtraArg __attribute__ ((visibility ("hidden"))) +**bd_fs_btrfs_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra) { + GPtrArray *options_array = g_ptr_array_new (); + const BDExtraArg **extra_p = NULL; + + if (options->label) + g_ptr_array_add (options_array, bd_extra_arg_new ("-L", options->label)); + + if (options->uuid) + g_ptr_array_add (options_array, bd_extra_arg_new ("-U", options->uuid)); + + if (options->no_discard) + g_ptr_array_add (options_array, bd_extra_arg_new ("-K", "")); + + if (extra) { + for (extra_p = extra; *extra_p; extra_p++) + g_ptr_array_add (options_array, bd_extra_arg_copy ((BDExtraArg *) *extra_p)); + } + + g_ptr_array_add (options_array, NULL); + + return (BDExtraArg **) g_ptr_array_free (options_array, FALSE); +} + +/** + * bd_fs_btrfs_mkfs: + * @device: the device to create a new btrfs fs on + * @extra: (allow-none) (array zero-terminated=1): extra options for the creation (right now + * passed to the 'mkfs.btrfs' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether a new btrfs fs was successfully created on @device or not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_MKFS + * + */ +gboolean bd_fs_btrfs_mkfs (const gchar *device, const BDExtraArg **extra, GError **error) { + const gchar *args[4] = {"mkfs.btrfs", "-f", device, NULL}; + + if (!check_deps (&avail_deps, DEPS_MKFSBTRFS_MASK, deps, DEPS_LAST, &deps_check_lock, error)) + return FALSE; + + return bd_utils_exec_and_report_error (args, extra, error); +} + +/** + * bd_fs_btrfs_wipe: + * @device: the device to wipe a Btrfs signature from + * @error: (out): place to store error (if any) + * + * Returns: whether the Btrfs signature was successfully wiped from the @device or + * not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_WIPE + */ +gboolean bd_fs_btrfs_wipe (const gchar *device, GError **error) { + return wipe_fs (device, "btrfs", FALSE, error); +} + +/** + * bd_fs_btrfs_check: + * @device: the device containing the file system to check + * @extra: (allow-none) (array zero-terminated=1): extra options for the check (right now + * passed to the 'btrfsck' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether the filesystem was successfully checked or not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_CHECK + */ +gboolean bd_fs_btrfs_check (const gchar *device, const BDExtraArg **extra, GError **error) { + const gchar *argv[4] = {"btrfsck", device, NULL}; + + if (!check_deps (&avail_deps, DEPS_BTRFSCK_MASK, deps, DEPS_LAST, &deps_check_lock, error)) + return FALSE; + + return bd_utils_exec_and_report_error (argv, extra, error); +} + +/** + * bd_fs_btrfs_repair: + * @device: the device containing the file system to repair + * @extra: (allow-none) (array zero-terminated=1): extra options for the repair (right now + * passed to the 'btrfsck' utility) + * @error: (out): place to store error (if any) + * + * Returns: whether the filesystem was successfully checked and repaired or not + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_REPAIR + */ +gboolean bd_fs_btrfs_repair (const gchar *device, const BDExtraArg **extra, GError **error) { + const gchar *argv[5] = {"btrfsck", "--repair", device, NULL}; + + if (!check_deps (&avail_deps, DEPS_BTRFSCK_MASK, deps, DEPS_LAST, &deps_check_lock, error)) + return FALSE; + + return bd_utils_exec_and_report_error (argv, extra, error); +} + +/** + * bd_fs_btrfs_set_label: + * @mpoint: the mount point of the file system to resize + * @label: label to set + * @error: (out): place to store error (if any) + * + * Returns: whether the label of btrfs file system on the @mpoint was + * successfully set or not + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_SET_LABEL + */ +gboolean bd_fs_btrfs_set_label (const gchar *mpoint, const gchar *label, GError **error) { + const gchar *argv[6] = {"btrfs", "filesystem", "label", mpoint, label, NULL}; + + if (!check_deps (&avail_deps, DEPS_BTRFS_MASK, deps, DEPS_LAST, &deps_check_lock, error)) + return FALSE; + + return bd_utils_exec_and_report_error (argv, NULL, error); +} + +/** + * bd_fs_btrfs_check_label: + * @label: label to check + * @error: (out) (allow-none): place to store error + * + * Returns: whether @label is a valid label for the btrfs file system or not + * (reason is provided in @error) + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: always available + */ +gboolean bd_fs_btrfs_check_label (const gchar *label, GError **error) { + if (strlen (label) > 256) { + g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID, + "Label for btrfs filesystem must be at most 256 characters long."); + return FALSE; + } + + if (strchr (label, '\n') != NULL) { + g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID, + "Label for btrfs filesystem cannot contain new lines."); + return FALSE; + } + + return TRUE; +} + +/** + * bd_fs_btrfs_set_uuid: + * @device: the device containing the file system to set the UUID (serial number) for + * @uuid: (allow-none): UUID to set or %NULL to generate a new one + * @error: (out): place to store error (if any) + * + * Returns: whether the UUID of the btrfs file system on the @device was + * successfully set or not + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_SET_UUID + */ +gboolean bd_fs_btrfs_set_uuid (const gchar *device, const gchar *uuid, GError **error) { + const gchar *args[5] = {"btrfstune", NULL, NULL, NULL, NULL}; + + if (!check_deps (&avail_deps, DEPS_BTRFSTUNE_MASK, deps, DEPS_LAST, &deps_check_lock, error)) + return FALSE; + + if (!uuid) { + args[1] = "-u"; + args[2] = device; + } else { + args[1] = "-U"; + args[2] = uuid; + args[3] = device; + } + + return bd_utils_exec_with_input (args, "y\n", NULL, error); +} + +/** + * bd_fs_btrfs_check_uuid: + * @uuid: UUID to check + * @error: (out) (allow-none): place to store error + * + * Returns: whether @uuid is a valid UUID for the btrfs file system or not + * (reason is provided in @error) + * + * Note: This function is intended to be used for btrfs filesystem on a single device, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: always available + */ +gboolean bd_fs_btrfs_check_uuid (const gchar *uuid, GError **error) { + return check_uuid (uuid, error); +} + +/** + * bd_fs_btrfs_get_info: + * @mpoint: a mountpoint of the btrfs filesystem to get information about + * @error: (out): place to store error (if any) + * + * Returns: (transfer full): information about the file system on @device or + * %NULL in case of error + * + * Note: This function WON'T WORK for multi device btrfs filesystems, + * for more complicated setups use the btrfs plugin instead. + * + * Tech category: %BD_FS_TECH_BTRFS-%BD_FS_TECH_MODE_QUERY + */ +BDFSBtrfsInfo* bd_fs_btrfs_get_info (const gchar *mpoint, GError **error) { + const gchar *argv[6] = {"btrfs", "filesystem", "show", "--raw", mpoint, NULL}; + gchar *output = NULL; + gboolean success = FALSE; + gchar const * const pattern = "Label:\\s+(none|'(?P