[pve-devel] [PATCH pve-common] Tools::df: fork and use Filesys::Df

Wolfgang Bumiller w.bumiller at proxmox.com
Thu Oct 29 14:16:59 CET 2015


Instead of depending on the 'df' commandline tool do a
fork() to create a killable process and run Filesys::Df,
returning the data over a pipe.
---
 debian/control   |  2 +-
 src/PVE/Tools.pm | 50 +++++++++++++++++++++++++++++++++++---------------
 2 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/debian/control b/debian/control
index 2d85e01..c00ca5e 100644
--- a/debian/control
+++ b/debian/control
@@ -7,6 +7,6 @@ Standards-Version: 3.8.4
 
 Package: libpve-common-perl
 Architecture: all
-Depends: ${perl:Depends} ${misc:Depends}, libclone-perl, libdevel-cycle-perl, libwww-perl, libjson-perl, liblinux-inotify2-perl, libio-stringy-perl, liburi-perl, libstring-shellquote-perl, libnet-ip-perl
+Depends: ${perl:Depends} ${misc:Depends}, libclone-perl, libdevel-cycle-perl, libwww-perl, libjson-perl, liblinux-inotify2-perl, libio-stringy-perl, liburi-perl, libstring-shellquote-perl, libnet-ip-perl, libfilesys-df-perl
 Description: Proxmox VE base library
  This package contains the base library used by other Proxmox VE components.
diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm
index 32f36ac..c52a3d0 100644
--- a/src/PVE/Tools.pm
+++ b/src/PVE/Tools.pm
@@ -8,6 +8,8 @@ use Socket qw(AF_INET AF_INET6 AI_ALL AI_V4MAPPED);
 use IO::Select;
 use File::Basename;
 use File::Path qw(make_path);
+use Filesys::Df (); # don't overwrite our df()
+use IO::Pipe;
 use IO::File;
 use IO::Dir;
 use IPC::Open3;
@@ -790,33 +792,51 @@ sub next_spice_port {
 # NOTE: NFS syscall can't be interrupted, so alarm does 
 # not work to provide timeouts.
 # from 'man nfs': "Only SIGKILL can interrupt a pending NFS operation"
-# So the spawn external 'df' process instead of using
-# Filesys::Df (which uses statfs syscall)
+# So fork() before using Filesys::Df
 sub df {
     my ($path, $timeout) = @_;
 
-    my $cmd = [ 'df', '-P', '-B', '1', $path];
-
     my $res = {
 	total => 0,
 	used => 0,
 	avail => 0,
     };
 
-    my $parser = sub {
-	my $line = shift;
-	if (my ($fsid, $total, $used, $avail) = $line =~
-	    m/^(\S+.*)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+%\s.*$/) {
-	    $res = {
-		total => $total,
-		used => $used,
-		avail => $avail,
-	    };
+    my $pipe = IO::Pipe->new();
+    my $child = fork();
+    if (!defined($child)) {
+	warn "fork failed: $!\n";
+	return $res;
+    }
+
+    if (!$child) {
+	$pipe->writer();
+	eval {
+	    my $df = Filesys::Df::df($path, 1);
+	    print {$pipe} "$df->{blocks}\n$df->{used}\n$df->{bavail}\n";
+	    $pipe->close();
+	};
+	if (my $err = $@) {
+	    warn $err;
+	    POSIX::_exit(1);
 	}
+	POSIX::_exit(0);
+    }
+
+    $pipe->reader();
+
+    my $readvalues = sub {
+	$res->{total} = int(<$pipe>);
+	$res->{used}  = int(<$pipe>);
+	$res->{avail} = int(<$pipe>);
+    };
+    eval {
+	run_with_timeout($timeout, $readvalues);
     };
-    eval { run_command($cmd, timeout => $timeout, outfunc => $parser); };
     warn $@ if $@;
-
+    $pipe->close();
+    kill('KILL', $child);
+    waitpid($child, 0);
     return $res;
 }
 
-- 
2.1.4




More information about the pve-devel mailing list