From ee823b0be40e7074bf1607a9593d4af8c68d1268 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Fri, 22 Jul 2022 13:13:28 +0100 Subject: [PATCH] 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] 07ad43a1072a104543bfc45bc5d357f3d8f8d6f6 Create loop devices for BTRFS read file system interface tests (!49) [2] 82c6265fa5599bd5acfe33abecaa99de150d71e9 Update parsing of btrfs filesystem show for the UUID (#733601) [3] eca732fb0cefe35db76a7ac96145e2004e8eed08 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] eb034b17597713bbc08dd3ab90444eaa2c0e7ff5 Add labelling of mounted btrfs (#163) Closes !105 - Update used btrfs file system commands, new minimum is btrfs-progs 4.5 --- src/btrfs.cc | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/btrfs.cc b/src/btrfs.cc index 99461347..e8ad9862 100644 --- a/src/btrfs.cc +++ b/src/btrfs.cc @@ -20,8 +20,10 @@ #include "FileSystem.h" #include "Mount_Info.h" #include "Partition.h" +#include "Utils.h" #include +#include #include #include @@ -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()), - 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 ) + exit_status = Utils::execute_command("btrfs filesystem label " + Glib::shell_quote(partition.get_path()), + output, error, true); + 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()),