Subject: bug#69873: df(1) does not display all UFS mountpoints as valid on FreeBSD

From: "Osipov, Michael (IN IT IN)" <[email-masked]>
Date: Mon, 18 Mar 2024 14:02:23 +0100

Disclaimer: I am not 100% certain whether this is a bug in GNU coreutils 
or FreeBSD Linux emulation layer because the behavior is weird. So, 
please bear with me.

Consider the following output on FreeBSD 13 from FreeBSD's df(1):
> $ df -t ufs -b -T -a
> Filesystem             Type 512-blocks      Used    Avail Capacity  Mounted on
> /dev/da0p2             ufs     4062264   1258336  2478952    34%    /
> /dev/da0p4             ufs     8106616    279080  7179008     4%    /tmp
> /dev/da0p5             ufs     8106616   1727528  5730560    23%    /var
> /dev/da0p6             ufs    16213432   1597320 13319040    11%    /var/tmp
> /dev/da0p7             ufs    24360504  15754536  6657128    70%    /usr
> /dev/gvinum/local      ufs    48721208  33111696 11711816    74%    /usr/local
> /dev/gvinum/ports      ufs    97482872  47860184 41824064    53%    /usr/ports
> /dev/gvinum/obj        ufs    40614392  31031528  6333720    83%    /usr/obj
> /dev/gvinum/pgsql      ufs    64975096  10500360 49276736    18%    /usr/local/pgsql
> /dev/gvinum/nexus2     ufs    64975096  27488304 32288792    46%    /var/nexus2
> /dev/gvinum/svn        ufs    16213432  10366472  4549888    69%    /var/svn
> /dev/gvinum/osipovmi   ufs    60901560  43723800 12305640    78%    /var/osipovmi
> /dev/gvinum/poudriere  ufs   129990648  74002720 45588680    62%    /var/poudriere
> /dev/gvinum/compat     ufs     8106616   1969752  5488336    26%    /compat
> /dev/gvinum/bastille   ufs   162498424 117560720 31937832    79%    /usr/local/bastille
and
> $ df -t ufs -b -T -a /dev/da0p7
> Filesystem  Type 512-blocks     Used   Avail Capacity  Mounted on
> /dev/da0p7  ufs    24360504 15754536 6657128    70%    /usr

Now let's use df(1) from coreutils complied on FreeBSD:
> $ gdf -a -B 512 -P  -t ufs
> Dateisystem           512-Blöcke   Benutzt Verfügbar Kapazität Eingehängt auf
> /dev/da0p2               4062264   1258336   2478952       34% /
> /dev/da0p4               8106616    279080   7179008        4% /tmp
> /dev/da0p5               8106616   1727528   5730560       24% /var
> /dev/da0p6              16213432   1597320  13319040       11% /var/tmp
> /dev/da0p7              24360504  15754536   6657128       71% /usr
> /dev/gvinum/local       48721208  33111696  11711816       74% /usr/local
> /dev/gvinum/ports       97482872  47860184  41824064       54% /usr/ports
> /dev/gvinum/obj         40614392  31031528   6333720       84% /usr/obj
> /dev/gvinum/pgsql       64975096  10500488  49276608       18% /usr/local/pgsql
> /dev/gvinum/nexus2      64975096  27488304  32288792       46% /var/nexus2
> /dev/gvinum/svn         16213432  10366472   4549888       70% /var/svn
> /dev/gvinum/osipovmi    60901560  43723800  12305640       79% /var/osipovmi
> /dev/gvinum/poudriere  129990648  74002720  45588680       62% /var/poudriere
> /dev/gvinum/compat       8106616   1969752   5488336       27% /compat
> /dev/gvinum/bastille   162498424 117560728  31937824       79% /usr/local/bastille
and
> $ gdf -a -B 512 -P  -t ufs /dev/da0p7
> Dateisystem    512-Blöcke  Benutzt Verfügbar Kapazität Eingehängt auf
> /dev/da0p7       24360504 15754536   6657128       71% /usr

So far so good. Now, I need to use a Linux application on FreeBSD which 
expect GNU df(1) in the Linux PATH, did install it and thought at first 
that this is a bug in the version I have installed, so I have compiled 
latest version on RHEL 7 and copied the executable to FreeBSD:
> $ ./df  --version
> df (GNU coreutils) 9.4
> Copyright © 2023 Free Software Foundation, Inc.
> Lizenz GPLv3+: GNU GPL Version 3 oder höher <https://gnu.org/licenses/gpl.html>.
> Dies ist freie Software: Sie können sie ändern und weitergeben.
> Es gibt keinerlei Garantien, soweit wie es das Gesetz erlaubt.
> 
> Geschrieben von Torbjörn Granlund, David MacKenzie und Paul Eggert.
> $ file ./df
> ./df: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=907caf0bb2d7ec27cfbe1f30e7bf63e11328631f, with debug_info, not stripped
> $ file $(which gdf)
> /usr/local/bin/gdf: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 13.2, FreeBSD-style, stripped

Now let's repeat the operation:
> $ ./df -a -B 512 -P  -t ufs
> Dateisystem           512-Blöcke   Benutzt Verfügbar Kapazität Eingehängt auf
> /dev/da0p2               4062264   1258336   2478952       34% /
> /dev/da0p4               8106616   1969752   5488336       27% /tmp
> /dev/da0p5                     -         -         -         - /var
> /dev/da0p6              16213432   1597320  13319040       11% /var/tmp
> /dev/da0p7                     -         -         -         - /usr
> /dev/gvinum/local       48721208  33111696  11711816       74% /usr/local
> /dev/gvinum/ports       97482872  47860184  41824064       54% /usr/ports
> /dev/gvinum/obj         40614392  31031528   6333720       84% /usr/obj 
> /dev/gvinum/pgsql       64975096  10500360  49276736       18% /usr/local/pgsql
> /dev/gvinum/nexus2      64975096  27488304  32288792       46% /var/nexus2
> /dev/gvinum/svn         16213432  10366472   4549888       70% /var/svn
> /dev/gvinum/osipovmi    60901560  43723800  12305640       79% /var/osipovmi
> /dev/gvinum/poudriere  129990648  74002720  45588680       62% /var/poudriere
> /dev/gvinum/compat             -         -         -         - /compat
> /dev/gvinum/bastille   162498424 117560736  31937816       79% /usr/local/bastille
as you can see two filesystems aren't proper and will not appear if the 
'-a'  is not used. Let's probe this filesystem.
> $ ./df -a -B 512 -P  -t ufs /dev/da0p7
> Dateisystem    512-Blöcke Benutzt Verfügbar Kapazität Eingehängt auf
> /dev/da0p7        8106616 1969752   5488336       27% /usr

Does not make sense to me. So I traced both calls with truss to see 
where GNU df(1) (the Linux executable) get's the data from.
I can see that both calls do:
> linux_open("/dev/da0p7",0x900,030270500)     = 3 (0x3)
> linux_newfstat(3,0x617140)           = 0 (0x0)
> close(3)                     = 0 (0x0)
> linux_open("/proc/self/mountinfo",0x80000,0666)  = 3 (0x3)
> linux_fcntl(0x3,0x3,0x0)             = 0 (0x0)
> linux_newfstat(3,0x7fffffffc6b0)         = 0 (0x0)
> linux_mmap2(0x0,0x1000,0x3,0x22,0xffffffffffffffff,0x0) = 34366255104 (0x800637000)
> read(3, ...

Now the value in the buffer for read() contains the following in *both* 
cases:
> 590926158 0 0:0 / / rw - ufs /dev/da0p2 rw
> 1895890801 0 0:0 / /dev rw - devfs devfs rw
> 699185331 0 0:0 / /tmp rw - ufs /dev/da0p4 rw
> 2391341225 0 0:0 / /var rw - ufs /dev/da0p5 rw
> 1704285867 0 0:0 / /var/tmp rw - ufs /dev/da0p6 rw
> 456922077 0 0:0 / /usr rw - ufs /dev/da0p7 rw
> 1493237592 0 0:0 / /dev/fd rw - fdescfs fdescfs rw
> 1037017996 0 0:0 / /usr/local rw - ufs /dev/gvinum/local rw
> 3473945877 0 0:0 / /usr/ports rw - ufs /dev/gvinum/ports rw
> 2770259572 0 0:0 / /usr/obj rw - ufs /dev/gvinum/obj rw
> 2912479969 0 0:0 / /usr/local/pgsql rw - ufs /dev/gvinum/pgsql rw
> 3422049217 0 0:0 / /var/nexus2 rw - ufs /dev/gvinum/nexus2 rw
> 3712243071 0 0:0 / /var/svn rw - ufs /dev/gvinum/svn rw
> 1709919602 0 0:0 / /var/osipovmi rw - ufs /dev/gvinum/osipovmi rw
> 2191125346 0 0:0 / /var/poudriere rw - ufs /dev/gvinum/poudriere rw
> 2575517705 0 0:0 / /compat rw - ufs /dev/gvinum/compat rw
> 829465671 0 0:0 / /usr/local/bastille rw - ufs /dev/gvinum/bastille rw
> 3036741558 0 0:0 / /proc rw - proc proc rw
> 2315321230 0

I assume that some code after parsing, likely matching does fail here to 
properly identify the filesystem?

Any idea why this happens, where to start digging or what to try?

Michael