]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/Tools.pm
run_fork_with_timeout: allow returning complex structures
[pve-common.git] / src / PVE / Tools.pm
index 9818f636a03dadeaee6329370f2349c6173ff767..3080b3ebebc047daec9d3c98fee5503fe197b84c 100644 (file)
@@ -20,6 +20,7 @@ use base 'Exporter';
 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);
@@ -905,16 +906,13 @@ sub run_fork_with_timeout {
     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;
 
-    # trap before forking to avoid leaving a zombie if the parent get killed
+    # avoid leaving a zombie if the parent gets interrupted
     my $sig_received;
-    local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
-       $sig_received++;
-    };
+    local $SIG{INT} = sub { $sig_received++; };
 
     my $child = fork();
     if (!defined($child)) {
@@ -924,35 +922,33 @@ sub run_fork_with_timeout {
 
     if (!$child) {
        $pipe_out->writer();
-       $pipe_err->writer();
 
        eval {
            $res = $sub->();
-           print {$pipe_out} "$res";
+           print {$pipe_out} encode_json({ result => $res });
            $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();
-    $pipe_err->reader();
 
     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 {
        run_with_timeout($timeout, $readvalues);
     };
     warn $@ if $@;
     $pipe_out->close();
-    $pipe_err->close();
     kill('KILL', $child);
     waitpid($child, 0);
 
@@ -1619,4 +1615,37 @@ sub encrypt_pw {
     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;