virt-df: Match output with native (coreutils) 'df' command (RHBZ#578123).
authorRichard Jones <rjones@redhat.com>
Tue, 30 Mar 2010 15:14:09 +0000 (16:14 +0100)
committerRichard Jones <rjones@redhat.com>
Tue, 30 Mar 2010 15:14:09 +0000 (16:14 +0100)
This commit fixes the 'Use%' field in the output so it matches what
coreutils' 'df' command would print.

Firstly we change the calculation to use the space available to root,
not the space available to non-root.  This means it matches what 'df'
when run as root in the guest would show.

Secondly we display this rounded up to the next whole percent (ie. using
ceil), which is also what 'df' does.

Thirdly we change the regression test so it tests this.

Note that even with these changes you are not guaranteed to get precisely
the same figures from inside and outside the guest, as it depends on
how quiescent the guest is and how recently the superblock was synced.

Thanks: Rita Wu

tools/make-test-img.sh
tools/test-virt-df.sh
tools/virt-df

index c6481cd..9752f1d 100755 (executable)
@@ -49,11 +49,11 @@ lvcreate LV2 VG 32
 lvcreate LV3 VG 64
 
 # Phony /boot filesystem.
-mkfs ext2 /dev/sda1
+mkfs-b ext2 4096 /dev/sda1
 set-e2label /dev/sda1 BOOT
 
 # Phony root filesystem.
-mkfs ext2 /dev/VG/Root
+mkfs-b ext2 4096 /dev/VG/Root
 set-e2label /dev/VG/Root ROOT
 
 # Enough to fool virt-inspector.
@@ -79,9 +79,10 @@ mkfifo 0777 /bin/test6
 mknod 0777 10 10 /bin/test7
 
 # Other filesystems.
-mkfs ext2 /dev/VG/LV1
-mkfs ext2 /dev/VG/LV2
-mkfs ext2 /dev/VG/LV3
+# Note that these should be empty, for testing virt-df.
+mkfs-b ext2 4096 /dev/VG/LV1
+mkfs-b ext2 1024 /dev/VG/LV2
+mkfs-b ext2 2048 /dev/VG/LV3
 EOF
 
 rm fstab
index 8e61063..a7b50b8 100755 (executable)
@@ -4,13 +4,10 @@ export LANG=C
 set -e
 
 # Run virt-df.
-output=$(./virt-df test.img -h)
-
-# The output will be slightly different from one machine to another.
-# So just do some tests to make sure it looks reasonable.
+output=$(./virt-df test.img)
 
 # Check title is the first line.
-if [[ ! $output =~ ^Filesystem[[:space:]]+Size[[:space:]]+Used[[:space:]]+Available[[:space:]]+Use% ]]; then
+if [[ ! $output =~ ^Filesystem.* ]]; then
     echo "$0: error: no title line"
     exit 1
 fi
@@ -44,3 +41,32 @@ if [[ ! $output =~ test.img:/dev/[hsv]da1 ]]; then
     echo "$0: error: filesystem /dev/VG/sda1 was not found"
     exit 1
 fi
+
+# This is what df itself prints for these filesystems (determined
+# by running the test image under virt-rescue):
+#
+# ><rescue> df -h
+# Filesystem            Size  Used Avail Use% Mounted on
+# /dev/dm-1              31M   28K   30M   1% /sysroot/lv1
+# /dev/dm-2              31M  395K   29M   2% /sysroot/lv2
+# /dev/dm-3              62M  144K   59M   1% /sysroot/lv3
+# ><rescue> df -i
+# Filesystem            Inodes   IUsed   IFree IUse% Mounted on
+# /dev/dm-1               8192      11    8181    1% /sysroot/lv1
+# /dev/dm-2               8192      11    8181    1% /sysroot/lv2
+# /dev/dm-3              16384      11   16373    1% /sysroot/lv3
+# ><rescue> df
+# Filesystem           1K-blocks      Used Available Use% Mounted on
+# /dev/dm-1                31728        28     30064   1% /sysroot/lv1
+# /dev/dm-2                31729       395     29696   2% /sysroot/lv2
+# /dev/dm-3                63472       144     60052   1% /sysroot/lv3
+#
+# Only test plain 'df' output at the moment (XXX).
+
+if [ "$(echo "$output" | sort | awk '/VG.LV[123]/ { print $2 " " $3 " " $4 " " $5 }')" != \
+"31728 28 30064 1%
+31729 395 29696 2%
+63472 144 60052 1%" ]; then
+    echo "$0: error: output of virt-df did not match expected (df) output"
+    exit 1
+fi
index 5a064cc..684334d 100755 (executable)
@@ -23,10 +23,13 @@ use Sys::Guestfs;
 use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path
   inspect_all_partitions inspect_partition
   inspect_operating_systems mount_operating_system inspect_in_detail);
+
 use Pod::Usage;
 use Getopt::Long;
 use Data::Dumper;
 use XML::Writer;
+use POSIX qw(ceil);
+
 use Locale::TextDomain 'libguestfs';
 
 =encoding utf8
@@ -106,8 +109,8 @@ my $csv;
 
 =item B<--csv>
 
-Write out the results in CSV format (comma-separated values).  This
-format can be imported easily into databases and spreadsheets, but
+Write out the results in CSV format (comma-separated values).  This format
+can be imported easily into databases and spreadsheets, but
 read L</NOTE ABOUT CSV FORMAT> below.
 
 =cut
@@ -230,9 +233,7 @@ sub print_stat
         push @cols, ($blocks-$bfree)*$factor; # total 1K blocks used
         push @cols, $bavail*$factor;   # total 1K blocks available
 
-        # XXX %used column comes out different from the native 'df'
-        # program.  Need to check how 'df' calculates this.
-        push @cols, 100.0 - 100.0 * $bavail / $blocks;
+        push @cols, 100.0 - 100.0 * $bfree / $blocks;
 
         if ($human) {
             $cols[2] = human_size ($cols[2]);
@@ -248,9 +249,7 @@ sub print_stat
         push @cols, $files-$ffree;
         push @cols, $ffree;
 
-        # XXX %used column comes out different from the native 'df'
-        # program.  Need to check how 'df' calculates this.
-        push @cols, 100.0 - 100.0 * $favail / $files;
+        push @cols, 100.0 - 100.0 * $ffree / $files;
     }
 
     print_cols (@cols);
@@ -292,7 +291,10 @@ sub print_cols
         printf ("%-36s", $label);
         print "\n"," "x36 if length ($label) > 36;
 
-        my $percent = sprintf "%3.1f%%", $_[5];
+        # Use 'ceil' on the percentage in order to emulate
+        # what df itself does.
+        my $percent = sprintf "%3d%%", ceil($_[5]);
+
         printf ("%10s %10s %10s %5s\n", $_[2], $_[3], $_[4], $percent);
     } else {
         printf ("\"%s\",\"%s\",%d,%d,%d,%.1f%%\n", @_);