]> git.proxmox.com Git - pve-common.git/blobdiff - data/PVE/Tools.pm
correctly call errfunc inside run_command
[pve-common.git] / data / PVE / Tools.pm
index 5cd8460db707bbef381a02611afa188ba982a6a0..33f0de1a217715395c521caf77b218673d9fe51e 100644 (file)
@@ -13,6 +13,8 @@ use base 'Exporter';
 use URI::Escape;
 use Encode;
 use Digest::SHA1;
+use Text::ParseWords;
+use String::ShellQuote;
 
 our @EXPORT_OK = qw(
 lock_file 
@@ -168,7 +170,7 @@ sub run_command {
 
     $cmd = [ $cmd ] if !ref($cmd);
 
-    my $cmdstr = join (' ', @$cmd);
+    my $cmdstr = cmd2string($cmd);
 
     my $errmsg;
     my $laststderr;
@@ -176,12 +178,13 @@ sub run_command {
     my $oldtimeout;
     my $pid;
 
+    my $outfunc;
+    my $errfunc;
+    my $logfunc;
+    my $input;
+    my $output;
+
     eval {
-       my $input;
-       my $output;
-       my $outfunc;
-       my $errfunc;
-       my $logfunc;
 
        foreach my $p (keys %param) {
            if ($p eq 'timeout') {
@@ -190,10 +193,6 @@ sub run_command {
                umask($param{$p});
            } elsif ($p eq 'errmsg') {
                $errmsg = $param{$p};
-               $errfunc = sub {
-                   print STDERR "$laststderr\n" if $laststderr;
-                   $laststderr = shift; 
-               };
            } elsif ($p eq 'input') {
                $input = $param{$p};
            } elsif ($p eq 'output') {
@@ -209,6 +208,20 @@ sub run_command {
            }
        }
 
+       if ($errmsg) {
+           my $origerrfunc = $errfunc;
+           $errfunc = sub {
+               if ($laststderr) {
+                   if ($origerrfunc) {
+                       &$origerrfunc("$laststderr\n");
+                   } else {
+                       print STDERR "$laststderr\n" if $laststderr;
+                   }
+               }
+               $laststderr = shift; 
+           };
+       }
+
        my $reader = $output && $output =~ m/^>&/ ? $output : IO::File->new();
        my $writer = $input && $input =~ m/^<&/ ? $input : IO::File->new();
        my $error  = IO::File->new();
@@ -351,7 +364,9 @@ sub run_command {
 
     alarm(0);
 
-    print STDERR "$laststderr\n" if $laststderr;
+    if ($errmsg && $laststderr) {
+       &$errfunc(undef); # flush laststderr
+    }
 
     umask ($old_umask) if defined($old_umask);
 
@@ -618,7 +633,7 @@ sub upid_open {
  
     my $outfh = IO::File->new ($filename, O_WRONLY|O_CREAT|O_EXCL, $perm) ||
        die "unable to create output file '$filename' - $!\n";
-    chown $wwwid, $outfh;
+    chown $wwwid, -1, $outfh;
 
     return $outfh;
 };
@@ -690,49 +705,64 @@ sub random_ether_addr {
 sub shellquote {
     my $str = shift;
 
-    return "''" if !defined ($str) || ($str eq '');
-    
-    die "unable to quote string containing null (\\000) bytes"
-       if $str =~ m/\x00/;
+    return String::ShellQuote::shell_quote($str);
+}
 
-    # from String::ShellQuote
-    if ($str =~ m|[^\w!%+,\-./:@^]|) {
+sub cmd2string {
+    my ($cmd) = @_;
 
-       # ' -> '\''
-       $str =~ s/'/'\\''/g;
+    die "no arguments" if !$cmd;
 
-       $str = "'$str'";
-       $str =~ s/^''//;
-       $str =~ s/''$//;
-    }
+    return $cmd if !ref($cmd);
 
-    return $str;
+    my @qa = ();
+    foreach my $arg (@$cmd) { push @qa, shellquote($arg); }
+
+    return join (' ', @qa);
 }
 
-# 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() ?
+# split an shell argument string into an array,
 sub split_args {
     my ($str) = @_;
 
-    my $args = [];
+    return $str ? [ Text::ParseWords::shellwords($str) ] : [];
+}
 
-    return $args if !$str;
+sub dump_logfile {
+    my ($filename, $start, $limit) = @_;
 
-    my $cmd = 'perl -e \'foreach my $a (@ARGV) { print "$a\n"; } \' -- ' . $str;
+    my $lines = [];
+    my $count = 0;
 
-    eval {
-       run_command($cmd, outfunc => sub {
-           my $data = shift;
-           push @$args, $data;
-       });
-    };
+    my $fh = IO::File->new($filename, "r");
+    if (!$fh) { 
+       $count++;
+       push @$lines, { n => $count, t => "unable to open file - $!"};
+       return ($count, $lines);
+    }
 
-    my $err = $@;
+    $start = 0 if !$start;
+    $limit = 50 if !$limit;
+
+    my $line;
+    while (defined($line = <$fh>)) {
+       next if $count++ < $start;
+       next if $limit <= 0;
+       chomp $line;
+       push @$lines, { n => $count, t => $line};
+       $limit--;
+    }
 
-    die "unable to parse args: $str\n" if $err;
+    close($fh);
+
+    # HACK: ExtJS store.guaranteeRange() does not like empty array
+    # so we add a line
+    if (!$count) {
+       $count++;
+       push @$lines, { n => $count, t => "no content"};
+    }
 
-    return $args;
+    return ($count, $lines);
 }
 
 1;