X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=blobdiff_plain;f=data%2FPVE%2FTools.pm;h=5cd8460db707bbef381a02611afa188ba982a6a0;hp=985b31ef4ec4a1523cda4e669846a719068cb0f1;hb=f912566320b1a877f64540b833f70e4fe7a85874;hpb=d2b0374d4888b5aad6f195db202fbd46569b153c diff --git a/data/PVE/Tools.pm b/data/PVE/Tools.pm index 985b31e..5cd8460 100644 --- a/data/PVE/Tools.pm +++ b/data/PVE/Tools.pm @@ -177,13 +177,11 @@ sub run_command { my $pid; eval { - my $reader = IO::File->new(); - my $writer = IO::File->new(); - my $error = IO::File->new(); - my $input; + my $output; my $outfunc; my $errfunc; + my $logfunc; foreach my $p (keys %param) { if ($p eq 'timeout') { @@ -198,15 +196,23 @@ sub run_command { }; } elsif ($p eq 'input') { $input = $param{$p}; + } elsif ($p eq 'output') { + $output = $param{$p}; } elsif ($p eq 'outfunc') { $outfunc = $param{$p}; } elsif ($p eq 'errfunc') { $errfunc = $param{$p}; + } elsif ($p eq 'logfunc') { + $logfunc = $param{$p}; } else { die "got unknown parameter '$p' for run_command\n"; } } + my $reader = $output && $output =~ m/^>&/ ? $output : IO::File->new(); + my $writer = $input && $input =~ m/^<&/ ? $input : IO::File->new(); + my $error = IO::File->new(); + # try to avoid locale related issues/warnings my $lang = $param{lang} || 'C'; @@ -219,6 +225,15 @@ sub run_command { local $ENV{LVM_SUPPRESS_FD_WARNINGS} = "1"; $pid = open3($writer, $reader, $error, @$cmd) || die $!; + + # if we pipe fron STDIN, open3 closes STDIN, so we we + # a perl warning "Filehandle STDIN reopened as GENXYZ .. " + # as soon as we open a new file. + # to avoid that we open /dev/null + if (!ref($writer) && !defined(fileno(STDIN))) { + POSIX::close(0); + open(STDIN, "add($reader); + $select->add($reader) if ref($reader); $select->add($error); my $outlog = ''; @@ -261,12 +278,13 @@ sub run_command { } $select->remove ($h) if !$count; if ($h eq $reader) { - if ($outfunc) { + if ($outfunc || $logfunc) { eval { $outlog .= $buf; while ($outlog =~ s/^([^\010\r\n]*)(\r|\n|(\010)+|\r\n)//s) { my $line = $1; - &$outfunc($line); + &$outfunc($line) if $outfunc; + &$logfunc($line) if $logfunc; } }; my $err = $@; @@ -280,12 +298,13 @@ sub run_command { *STDOUT->flush(); } } elsif ($h eq $error) { - if ($errfunc) { + if ($errfunc || $logfunc) { eval { $errlog .= $buf; while ($errlog =~ s/^([^\010\r\n]*)(\r|\n|(\010)+|\r\n)//s) { my $line = $1; - &$errfunc($line); + &$errfunc($line) if $errfunc; + &$logfunc($line) if $logfunc; } }; my $err = $@; @@ -303,7 +322,10 @@ sub run_command { } &$outfunc($outlog) if $outfunc && $outlog; + &$logfunc($outlog) if $logfunc && $outlog; + &$errfunc($errlog) if $errfunc && $errlog; + &$logfunc($errlog) if $logfunc && $errlog; waitpid ($pid, 0); @@ -312,12 +334,14 @@ sub run_command { } elsif (my $sig = ($? & 127)) { die "got signal $sig\n"; } elsif (my $ec = ($? >> 8)) { - if ($errmsg && $laststderr) { - my $lerr = $laststderr; - $laststderr = undef; - die "$lerr\n"; + if (!($ec == 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 $ec\n"; } alarm(0); @@ -346,6 +370,8 @@ sub run_command { die "command '$cmdstr' failed: $err"; } } + + return undef; } sub split_list { @@ -661,4 +687,52 @@ sub random_ether_addr { return $mac; } +sub shellquote { + my $str = shift; + + return "''" if !defined ($str) || ($str eq ''); + + die "unable to quote string containing null (\\000) bytes" + if $str =~ m/\x00/; + + # from String::ShellQuote + if ($str =~ m|[^\w!%+,\-./:@^]|) { + + # ' -> '\'' + $str =~ s/'/'\\''/g; + + $str = "'$str'"; + $str =~ s/^''//; + $str =~ s/''$//; + } + + return $str; +} + +# a clumsy way to split an shell argument string into an array, +# we simply pass it to the cli (exec call) +# fixme: use Text::ParseWords::shellwords() ? +sub split_args { + my ($str) = @_; + + my $args = []; + + return $args if !$str; + + my $cmd = 'perl -e \'foreach my $a (@ARGV) { print "$a\n"; } \' -- ' . $str; + + eval { + run_command($cmd, outfunc => sub { + my $data = shift; + push @$args, $data; + }); + }; + + my $err = $@; + + die "unable to parse args: $str\n" if $err; + + return $args; +} + 1;