Fix reading FAT16/32 FS labels on Alpine Linux (!104)

Several of the FAT16/32 file system unit tests fail on Alpine Linux.  In
this commit we are just looking at the failure to read the label.  The
test fails like this:
    $ ./test_SupportedFileSystems --gtest_filter='*CreateAndReadLabel/fat16'
    ...
    [ RUN      ] My/SupportedFileSystemsTest.CreateAndReadLabel/fat16
    test_SupportedFileSystems.cc:551: Failure
    Expected equality of these values:
      fs_label
        Which is: "TEST_LABEL"
      m_partition.get_filesystem_label().c_str()
        Which is: ""
    test_SupportedFileSystems.cc:554: Failure
    Value of: m_partition.get_messages().empty()
      Actual: false
    Expected: true
    Partition messages:
    Mtools version 4.0.39, dated April 10th, 2022
    Usage: mlabel [-vscVn] [-N serial] drive:

    [  FAILED  ] My/SupportedFileSystemsTest.CreateAndReadLabel/fat16, where GetParam() = 13 (21 ms)

The same error can be seen by using GParted to display a FAT16 or FAT32
file system on Alpine Linux.  The Partition Information dialog displays
this warning:
    Mtools version 4.0.39, dated April 10th, 2022
    Usage: mlabel [-vscVn] [-N serial] drive:

Reproduce this on the command line:
    # mkfs.fat -F 16 -v -I -n TEST_LABEL /dev/sdb1
    # mlabel -s :: -i /dev/sdb1
    Mtools version 4.0.39, dated April 10th, 2022
    Usage: mlabel [-vscVn] [-N serial] drive:
    # echo $?
    1

The mlabel.c source [1] uses getopt(3) to parse the command line
arguments.  musl libc's [2] getopt(3) must be strictly POSIX compliant
[3][4] and stops reading options at the first non-option argument, '::'
in this case.  Move the non-option argument to the end of the command
line and it works:
    # mlabel -s -i /dev/sdb1 ::
     Volume label is TEST_LABEL

Where as GNU Libc's getopt(3) [5] says that by default it reorders argv
eventually moving all non-option arguments to the end, hence why this
has worked on every Linux distribution using GNU Libc.  This can be
broken on any Linux distribution using GNU Libc by enforcing strict
POSIX behaviour from getopt(3).  For example on Fedora 36:
    # mkfs.fat -F 16 -v -I -n TEST_LABEL /dev/sdb1
    # export POSIXLY_CORRECT=1
    # mlabel -s :: -i /dev/sdb1
    Mtools version 4.0.39, dated April 10th, 2022
    Usage: mlabel [-vscVn] [-N serial] drive:
    # echo $?
    1
    # mlabel -s -i /dev/sdb1 ::
    Hidden (2048) does not match sectors (63)
     Volume label is TEST_LABEL
    # echo $?
    0

Fix by moving the non-option (image file drive specification) '::' to
the end of the mlabel command line.

[1] Mtools
    https://www.gnu.org/software/mtools/
[2] musl libc
    https://musl.libc.org/
    "musl is an implementation of the C standard library built on top of
    the Linux system call API, including interfaces defined in the base
    language standard, POSIX, and widely agreed-upon extensions.
    "
[3] POSIX.1-2017, Functions, getopt
    https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
[4] getopt(3p)
    https://man7.org/linux/man-pages/man3/getopt.3p.html
[5] getopt(3)
    https://www.man7.org/linux/man-pages/man3/getopt.3.html
    "By default, getopt() permutes the contents of argv as it scans, so
    that eventually all the nonoptions are at the end.  Two other
    scanning modes are also implemented.  If the first character of
    optstring is '+' or the environment variable POSIXLY_CORRECT is set,
    then option processing stops as soon as a nonoption argument is
    encountered.
    "

Closes !104 - Add Alpine Linux CI jobs and resolve label and UUID issues
              with FAT16/32
This commit is contained in:
Mike Fleetwood 2022-06-17 11:16:43 +01:00 committed by Curtis Gedak
parent 407e0ac6e3
commit a48b29ba19
1 changed files with 1 additions and 1 deletions

View File

@ -192,7 +192,7 @@ void fat16::set_used_sectors( Partition & partition )
void fat16::read_label(Partition& partition)
{
exit_status = Utils::execute_command("mlabel -s :: -i " + Glib::shell_quote(partition.get_path()),
exit_status = Utils::execute_command("mlabel -s -i " + Glib::shell_quote(partition.get_path()) + " ::",
output, error, true);
if (exit_status != 0)
{