]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/Tools.pm
Output also lockname if it cannot be acquired
[pve-common.git] / src / PVE / Tools.pm
index cda0797ccc25a2b7c41784327892c3df60417e55..64a57e9596dcbdcc15dff98d38161be38cbdf91e 100644 (file)
@@ -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;
@@ -39,6 +41,7 @@ template_replace
 safe_print
 trim
 extract_param
+file_copy
 );
 
 my $pvelogdir = "/var/log/pve";
@@ -65,12 +68,12 @@ our $IPV6RE = "(?:" .
 
 our $IPRE = "(?:$IPV4RE|$IPV6RE)";
 
-use constant (CLONE_NEWNS   => 0x00020000,
+use constant {CLONE_NEWNS   => 0x00020000,
               CLONE_NEWUTS  => 0x04000000,
               CLONE_NEWIPC  => 0x08000000,
               CLONE_NEWUSER => 0x10000000,
               CLONE_NEWPID  => 0x20000000,
-              CLONE_NEWNET  => 0x40000000);
+              CLONE_NEWNET  => 0x40000000};
 
 sub run_with_timeout {
     my ($timeout, $code, @param) = @_;
@@ -128,7 +131,7 @@ sub lock_file_full {
         }
 
         if (!flock ($lock_handles->{$$}->{$filename}, $mode|LOCK_NB)) {
-            print STDERR "trying to aquire lock...";
+            print STDERR "trying to acquire lock...";
            my $success;
            while(1) {
                $success = flock($lock_handles->{$$}->{$filename}, $mode);
@@ -139,7 +142,7 @@ sub lock_file_full {
            }
             if (!$success) {
                 print STDERR " failed\n";
-                die "can't aquire lock - $!\n";
+                die "can't acquire lock '$filename' - $!\n";
             }
             print STDERR " OK\n";
         }
@@ -218,6 +221,12 @@ sub file_get_contents {
     return $content;
 }
 
+sub file_copy {
+    my ($filename, $dst, $max, $perm) = @_;
+
+    file_set_contents ($dst, file_get_contents($filename, $max), $perm);
+}
+
 sub file_read_firstline {
     my ($filename) = @_;
 
@@ -310,6 +319,7 @@ sub run_command {
     my $timeout;
     my $oldtimeout;
     my $pid;
+    my $exitcode;
 
     my $outfunc;
     my $errfunc;
@@ -317,6 +327,7 @@ sub run_command {
     my $input;
     my $output;
     my $afterfork;
+    my $noerr;
 
     eval {
 
@@ -339,6 +350,8 @@ sub run_command {
                $logfunc = $param{$p};
            } elsif ($p eq 'afterfork') {
                $afterfork = $param{$p};
+           } elsif ($p eq 'noerr') {
+               $noerr = $param{$p};
            } else {
                die "got unknown parameter '$p' for run_command\n";
            }
@@ -484,14 +497,14 @@ sub run_command {
            die "failed to execute\n";
        } elsif (my $sig = ($? & 127)) {
            die "got signal $sig\n";
-       } elsif (my $ec = ($? >> 8)) {
-           if (!($ec == 24 && ($cmdstr =~ m|^(\S+/)?rsync\s|))) {
+       } elsif ($exitcode = ($? >> 8)) {
+           if (!($exitcode == 24 && ($cmdstr =~ m|^(\S+/)?rsync\s|))) {
                if ($errmsg && $laststderr) {
                    my $lerr = $laststderr;
                    $laststderr = undef;
                    die "$lerr\n";
                }
-               die "exit code $ec\n";
+               die "exit code $exitcode\n";
            }
        }
 
@@ -520,12 +533,12 @@ sub run_command {
        if ($errmsg) {
            $err =~ s/^usermod:\s*// if $cmdstr =~ m|^(\S+/)?usermod\s|;
            die "$errmsg: $err";
-       } else {
+       } elsif(!$noerr) {
            die "command '$cmdstr' failed: $err";
        }
     }
 
-    return undef;
+    return $exitcode;
 }
 
 sub split_list {
@@ -790,33 +803,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;
 }
 
@@ -940,15 +971,10 @@ sub random_ether_addr {
 
     my $rand = Digest::SHA::sha1_hex($$, rand(), $seconds, $microseconds);
 
-# clear multicast, set local id
+    # clear multicast, set local id
     vec($rand, 0, 8) = (vec($rand, 0, 8) & 0xfe) | 2;
 
-    my $mac = sprintf("%02X:" x 6, unpack("C6", $rand));
-
-# remove superfluous ":" at end
-    chop($mac);
-
-    return $mac;
+    return sprintf("%02X:%02X:%02X:%02X:%02X:%02X", unpack("C6", $rand));
 }
 
 sub shellquote {
@@ -1154,9 +1180,9 @@ sub parse_host_and_port {
     return; # nothing
 }
 
-sub unshare {
+sub unshare($) {
     my ($flags) = @_;
-    syscall 272, $flags;
+    return 0 == syscall(272, $flags);
 }
 
 1;