]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/Tools.pm
deps: moving skiplock breaks qemu-server << 4.0-109
[pve-common.git] / src / PVE / Tools.pm
index 039c9fb8dae5e2d10cb492b9f41ecf4f08397a91..df66047a5032e9f2f4c5fffe47d9b2e46c6009f5 100644 (file)
@@ -2,7 +2,7 @@ package PVE::Tools;
 
 use strict;
 use warnings;
-use POSIX qw(EINTR);
+use POSIX qw(EINTR EEXIST EOPNOTSUPP);
 use IO::Socket::IP;
 use Socket qw(AF_INET AF_INET6 AI_ALL AI_V4MAPPED);
 use IO::Select;
@@ -203,7 +203,13 @@ sub file_set_contents {
     my $tmpname = "$filename.tmp.$$";
 
     eval {
-       my $fh = IO::File->new($tmpname, O_WRONLY|O_CREAT, $perm);
+       my ($fh, $tries) = (undef, 0);
+       while (!$fh && $tries++ < 3) {
+           $fh = IO::File->new($tmpname, O_WRONLY|O_CREAT|O_EXCL, $perm);
+           if (!$fh && $! == EEXIST) {
+               unlink($tmpname) or die "unable to delete old temp file: $!\n";
+           }
+       }
        die "unable to open file '$tmpname' - $!\n" if !$fh;
        die "unable to write '$tmpname' - $!\n" unless print $fh $data;
        die "closing file '$tmpname' failed - $!\n" unless close $fh;
@@ -228,7 +234,7 @@ sub file_get_contents {
     my $fh = IO::File->new($filename, "r") ||
        die "can't open '$filename' - $!\n";
 
-    my $content = safe_read_from($fh, $max);
+    my $content = safe_read_from($fh, $max, 0, $filename);
 
     close $fh;
 
@@ -253,22 +259,24 @@ sub file_read_firstline {
 }
 
 sub safe_read_from {
-    my ($fh, $max, $oneline) = @_;
+    my ($fh, $max, $oneline, $filename) = @_;
 
     $max = 32768 if !$max;
 
+    my $subject = defined($filename) ? "file '$filename'" : 'input';
+
     my $br = 0;
     my $input = '';
     my $count;
     while ($count = sysread($fh, $input, 8192, $br)) {
        $br += $count;
-       die "input too long - aborting\n" if $br > $max;
+       die "$subject too long - aborting\n" if $br > $max;
        if ($oneline && $input =~ m/^(.*)\n/) {
            $input = $1;
            last;
        }
     } 
-    die "unable to read input - $!\n" if !defined($count);
+    die "unable to read $subject - $!\n" if !defined($count);
 
     return $input;
 }
@@ -851,9 +859,9 @@ sub df {
     $pipe->reader();
 
     my $readvalues = sub {
-       $res->{total} = int(<$pipe>);
-       $res->{used}  = int(<$pipe>);
-       $res->{avail} = int(<$pipe>);
+       $res->{total} = int((<$pipe> =~ /^(\d*)$/)[0]);
+       $res->{used}  = int((<$pipe> =~ /^(\d*)$/)[0]);
+       $res->{avail} = int((<$pipe> =~ /^(\d*)$/)[0]);
     };
     eval {
        run_with_timeout($timeout, $readvalues);
@@ -980,15 +988,20 @@ sub decode_utf8_parameters {
 }
 
 sub random_ether_addr {
+    my ($prefix) = @_;
 
     my ($seconds, $microseconds) = gettimeofday;
 
-    my $rand = Digest::SHA::sha1_hex($$, rand(), $seconds, $microseconds);
+    my $rand = Digest::SHA::sha1($$, rand(), $seconds, $microseconds);
 
     # clear multicast, set local id
     vec($rand, 0, 8) = (vec($rand, 0, 8) & 0xfe) | 2;
 
-    return sprintf("%02X:%02X:%02X:%02X:%02X:%02X", unpack("C6", $rand));
+    my $addr = sprintf("%02X:%02X:%02X:%02X:%02X:%02X", unpack("C6", $rand));
+    if (defined($prefix)) {
+       $addr = uc($prefix) . substr($addr, length($prefix));
+    }
+    return $addr;
 }
 
 sub shellquote {
@@ -1293,12 +1306,18 @@ sub tempfile {
     # default permissions are stricter than with file_set_contents
     $perm = 0600 if !defined($perm);
 
-    my $dir = $opts{dir} // '/tmp';
+    my $dir = $opts{dir} // '/run';
     my $mode = $opts{mode} // O_RDWR;
     $mode |= O_EXCL if !$opts{allow_links};
 
-    my $fh = IO::File->new($dir, $mode | O_TMPFILE, $perm)
-       or die "failed to create tempfile: $!\n";
+    my $fh = IO::File->new($dir, $mode | O_TMPFILE, $perm);
+    if (!$fh && $! == EOPNOTSUPP) {
+       $dir = '/tmp' if !defined($opts{dir});
+       $dir .= "/.tmpfile.$$";
+       $fh = IO::File->new($dir, $mode | O_CREAT | O_EXCL, $perm);
+       unlink($dir) if $fh;
+    }
+    die "failed to create tempfile: $!\n" if !$fh;
     return $fh;
 }