]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/Tools.pm
lock_file_full: add missing trailing newline
[pve-common.git] / src / PVE / Tools.pm
index 9ddcfda3444fde95fe76fad78b088986ec77177a..13e70f1afe828baa50cc84f2eab650e6331b6d60 100644 (file)
@@ -20,6 +20,7 @@ use base 'Exporter';
 use URI::Escape;
 use Encode;
 use Digest::SHA;
 use URI::Escape;
 use Encode;
 use Digest::SHA;
+use JSON;
 use Text::ParseWords;
 use String::ShellQuote;
 use Time::HiRes qw(usleep gettimeofday tv_interval alarm);
 use Text::ParseWords;
 use String::ShellQuote;
 use Time::HiRes qw(usleep gettimeofday tv_interval alarm);
@@ -149,7 +150,7 @@ sub lock_file_full {
            or die "can't open file - $!\n";
 
        if (!flock($fh, $mode|LOCK_NB)) {
            or die "can't open file - $!\n";
 
        if (!flock($fh, $mode|LOCK_NB)) {
-           print STDERR "trying to acquire lock...";
+           print STDERR "trying to acquire lock...\n";
            my $success;
            while(1) {
                $success = flock($fh, $mode);
            my $success;
            while(1) {
                $success = flock($fh, $mode);
@@ -905,7 +906,6 @@ sub run_fork_with_timeout {
     my $res;
     my $error;
     my $pipe_out = IO::Pipe->new();
     my $res;
     my $error;
     my $pipe_out = IO::Pipe->new();
-    my $pipe_err = IO::Pipe->new();
 
     # disable pending alarms, save their remaining time
     my $prev_alarm = alarm 0;
 
     # disable pending alarms, save their remaining time
     my $prev_alarm = alarm 0;
@@ -922,35 +922,37 @@ sub run_fork_with_timeout {
 
     if (!$child) {
        $pipe_out->writer();
 
     if (!$child) {
        $pipe_out->writer();
-       $pipe_err->writer();
 
        eval {
            $res = $sub->();
 
        eval {
            $res = $sub->();
-           print {$pipe_out} "$res";
+           print {$pipe_out} encode_json({ result => $res });
            $pipe_out->flush();
        };
        if (my $err = $@) {
            $pipe_out->flush();
        };
        if (my $err = $@) {
-           print {$pipe_err} "$err";
-           $pipe_err->flush();
+           print {$pipe_out} encode_json({ error => $err });
+           $pipe_out->flush();
            POSIX::_exit(1);
        }
        POSIX::_exit(0);
     }
 
     $pipe_out->reader();
            POSIX::_exit(1);
        }
        POSIX::_exit(0);
     }
 
     $pipe_out->reader();
-    $pipe_err->reader();
 
     my $readvalues = sub {
        local $/ = undef;
 
     my $readvalues = sub {
        local $/ = undef;
-       $res = <$pipe_out>;
-       $error = <$pipe_err>;
+       my $child_res = decode_json(scalar<$pipe_out>);
+       $res = $child_res->{result};
+       $error = $child_res->{error};
     };
     eval {
     };
     eval {
-       run_with_timeout($timeout, $readvalues);
+       if (defined($timeout)) {
+           run_with_timeout($timeout, $readvalues);
+       } else {
+           $readvalues->();
+       }
     };
     warn $@ if $@;
     $pipe_out->close();
     };
     warn $@ if $@;
     $pipe_out->close();
-    $pipe_err->close();
     kill('KILL', $child);
     waitpid($child, 0);
 
     kill('KILL', $child);
     waitpid($child, 0);
 
@@ -961,6 +963,11 @@ sub run_fork_with_timeout {
     return $res;
 }
 
     return $res;
 }
 
+sub run_fork {
+    my ($code) = @_;
+    return run_fork_with_timeout(undef, $code);
+}
+
 # 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"
 # 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"
@@ -985,7 +992,8 @@ sub df {
        $pipe->writer();
        eval {
            my $df = Filesys::Df::df($path, 1);
        $pipe->writer();
        eval {
            my $df = Filesys::Df::df($path, 1);
-           print {$pipe} "$df->{blocks}\n$df->{used}\n$df->{bavail}\n";
+           print {$pipe} "$df->{blocks}\n$df->{used}\n$df->{bavail}\n"
+               if defined($df);
            $pipe->close();
        };
        if (my $err = $@) {
            $pipe->close();
        };
        if (my $err = $@) {
@@ -998,9 +1006,9 @@ sub df {
     $pipe->reader();
 
     my $readvalues = sub {
     $pipe->reader();
 
     my $readvalues = sub {
-       $res->{total} = int((<$pipe> =~ /^(\d*)$/)[0]);
-       $res->{used}  = int((<$pipe> =~ /^(\d*)$/)[0]);
-       $res->{avail} = int((<$pipe> =~ /^(\d*)$/)[0]);
+       $res->{total} = int(((<$pipe> // 0) =~ /^(\d*)$/)[0]);
+       $res->{used}  = int(((<$pipe> // 0) =~ /^(\d*)$/)[0]);
+       $res->{avail} = int(((<$pipe> // 0) =~ /^(\d*)$/)[0]);
     };
     eval {
        run_with_timeout($timeout, $readvalues);
     };
     eval {
        run_with_timeout($timeout, $readvalues);
@@ -1617,4 +1625,37 @@ sub encrypt_pw {
     return crypt(encode("utf8", $pw), "\$5\$$salt\$");
 }
 
     return crypt(encode("utf8", $pw), "\$5\$$salt\$");
 }
 
+# intended usage: convert_size($val, "kb" => "gb")
+# on reduction (converting to a bigger unit) we round up by default if
+# information got lost. E.g. `convert_size(1023, "b" => "kb")` returns 1
+# use $no_round_up to switch this off, above example would then return 0
+sub convert_size {
+    my ($value, $from, $to, $no_round_up) = @_;
+
+    my $units = {
+       b  => 0,
+       kb => 1,
+       mb => 2,
+       gb => 3,
+       tb => 4,
+       pb => 5,
+    };
+
+    $from = lc($from); $to = lc($to);
+    die "unknown 'from' and/or 'to' units ($from => $to)"
+       if !(defined($units->{$from}) && defined($units->{$to}));
+
+    my $shift_amount = $units->{$from} - $units->{$to};
+
+    if ($shift_amount > 0) {
+       $value <<= ($shift_amount * 10);
+    } elsif ($shift_amount < 0) {
+       my $remainder = ($value & (1 << abs($shift_amount)*10) - 1);
+       $value >>= abs($shift_amount) * 10;
+       $value++ if $remainder && !$no_round_up;
+    }
+
+    return $value;
+}
+
 1;
 1;