Use btrfs filesystem label to read the FS label (!105)

Until now GParted has run 'btrfs filesystem show' to read the file
system label.  This has a number of issues and limitations:
1.  Doesn't work on a file system image so can't be unit tested in the
    GitLab CI test job where a loop device can't be created [1] or as a
    non-root user.
2.  Reported failed exit status 1 when successfully showing a mounted
    btrfs, but only when using btrfs-progs v3.14 and 3.14.1 [2][3].
3.  Failed to distinguish between label set to "none" and no label
    reported as none, but only when mounted and with btrfs-progs v3.12
    [3].

As non-root user run btrfs read label unit test:
    $ tests/test_SupportedFileSystems --gtest_filter='*CreateAndReadLabel/btrfs'
    ...
    [ RUN      ] My/SupportedFileSystemsTest.CreateAndReadLabel/btrfs
    test_SupportedFileSystem.cc:539: Skip test.  Not root to be able to create required loop device
    [       OK ] My/SupportedFileSystemsTest.CreateAndReadLabel/btrfs (0 ms)

Even as root, 'btrfs filesystem show' fails to work on an image file:
    # truncate -s 256M /tmp/test.img
    # mkfs.btrfs /tmp/test.img
    # btrfs filesystem show /tmp/test.img
    ERROR: not a valid btrfs filesystem: /tmp/test.img
    # echo $?
    1
    # rm /tmp/test.img

Instead use 'btrfs filesystem label' to read the label.  It also works
on an image file, the exit status is informative and output is just the
label followed by a new line character [4] so very simple to parse.

Error case:
    $ truncate -s 256M /tmp/test.img
    $ btrfs filesystem label /tmp/test.img
    No valid Btrfs found on /tmp/test.img
    $ echo $?
    255

No label case:
    $ mkfs.btrfs /tmp/test.img
    $ btrfs filesystem label /tmp/test.img

    $ echo $?
    0
    $ btrfs filesystem label /tmp/test.img | hexdump -C
    00000000  0a                                                |.|
    00000001

Label case:
    $ mkfs.btrfs -L 'label with
    > new line and trailing space ' /tmp/test.img
    $ btrfs filesystem label /tmp/test.img
    label with
    new line and trailing space
    $ echo $?
    0
    $ btrfs filesystem label /tmp/test.img | hexdump -C
    00000000  6c 61 62 65 6c 20 77 69  74 68 0a 6e 65 77 20 6c  |label with.new l|
    00000010  69 6e 65 20 61 6e 64 20  74 72 61 69 6c 69 6e 67  |ine and trailing|
    00000020  20 73 70 61 63 65 20 0a                           | space .|
    00000028

Run 'btrfs filesystem label' always passing the block device as this
works for both mounted and unmounted file systems.  This is in
contrast to writing the label for a mounted btrfs where the mount
mount must be used [5].
    # mkfs.btrfs -L 'test label' /dev/sdb1
    # btrfs filesystem label /dev/sdb1
    test label
    # mount /dev/sdb1 /mnt/1
    # btrfs filesystem label /dev/sdb1
    test label

[1] 07ad43a107
    Create loop devices for BTRFS read file system interface tests (!49)
[2] 82c6265fa5
    Update parsing of btrfs filesystem show for the UUID (#733601)
[3] eca732fb0c
    Update parsing of btrfs filesystem show for the label (#733601)
[4] btrfs-progs v3.14, cmd_label() function
    https://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git/tree/cmds-filesystem.c?h=v3.14#n984
[5] eb034b1759
    Add labelling of mounted btrfs (#163)

Closes !105 - Update used btrfs file system commands, new minimum is
              btrfs-progs 4.5
This commit is contained in:
Mike Fleetwood 2022-07-22 13:13:28 +01:00 committed by Curtis Gedak
parent f30317477a
commit ee823b0be4
1 changed files with 18 additions and 27 deletions

View File

@ -20,8 +20,10 @@
#include "FileSystem.h"
#include "Mount_Info.h"
#include "Partition.h"
#include "Utils.h"
#include <ctype.h>
#include <glibmm/ustring.h>
#include <glibmm/miscutils.h>
#include <glibmm/shell.h>
@ -341,40 +343,29 @@ bool btrfs::resize( const Partition & partition_new, OperationDetail & operation
return success ;
}
void btrfs::read_label( Partition & partition )
void btrfs::read_label(Partition& partition)
{
Utils::execute_command("btrfs filesystem show " + Glib::shell_quote(partition.get_path()),
exit_status = Utils::execute_command("btrfs filesystem label " + Glib::shell_quote(partition.get_path()),
output, error, true);
//In many cases the exit status doesn't reflect valid output or an error condition
// so rely on parsing the output to determine success.
if ( output .compare( 0, 18, "Label: none uuid:" ) == 0 )
if (exit_status != 0)
{
//Indistinguishable cases of either no label or the label is actually set
// to "none". Assume no label case.
partition.set_filesystem_label( "" );
if (! output.empty())
partition.push_back_message(output);
if (! error.empty())
partition.push_back_message(error);
return;
}
else
{
// Try matching a label enclosed in single quotes, then without quotes, to
// handle reporting of mounted file systems by old btrfs-progs 3.12.
Glib::ustring label = Utils::regexp_label( output, "^Label: '(.*)' uuid:" ) ;
if ( label .empty() )
label = Utils::regexp_label( output, "^Label: (.*) uuid:" ) ;
if ( ! label .empty() )
partition.set_filesystem_label( label );
else
{
if ( ! output .empty() )
partition.push_back_message( output );
// Strip terminating new line from output.
size_t len = output.length();
if (len > 0 && output[len-1] == '\n')
output.resize(len-1);
if ( ! error .empty() )
partition.push_back_message( error );
}
}
partition.set_filesystem_label(output);
}
void btrfs::read_uuid( Partition & partition )
{
Utils::execute_command("btrfs filesystem show " + Glib::shell_quote(partition.get_path()),