From: Wolfgang Bumiller Date: Thu, 29 Oct 2015 13:16:59 +0000 (+0100) Subject: Tools::df: fork and use Filesys::Df X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=commitdiff_plain;h=97c8c8577dbb91950d1ae16ea295f99d1e84957c Tools::df: fork and use Filesys::Df 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. --- 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; }