[pve-devel] [PATCH pve-common 2/2] Tools::run_command: array of arrays special case

Wolfgang Bumiller w.bumiller at proxmox.com
Tue Sep 15 10:01:33 CEST 2015


Passing an array of arrays to run_command will cause each
array to be treated like a command piped to the following
command. Each argument is shell-quoted unless its passed by
reference.
---
 src/PVE/Tools.pm | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm
index f25cc4b..9fb9f07 100644
--- a/src/PVE/Tools.pm
+++ b/src/PVE/Tools.pm
@@ -255,13 +255,39 @@ sub safe_read_from {
 #  -) an array of arguments (strings)
 #    Will be executed without interference from a shell. (Parameters are passed
 #    as is, no escape sequences of strings will be touched.)
+#  -) an array of arrays
+#    Each array represents a command, and each command's output is piped into
+#    the following command's standard input.
+#    For this a shell command string is created with pipe symbols between each
+#    command.
+#    Each command is a list of strings meant to end up in the final command
+#    unchanged. In order to achieve this, every argument is shell-quoted.
+#    Quoting can be disabled for a particular argument by turning it into a
+#    reference, this allows inserting arbitrary shell options.
+#    For instance: the $cmd [ [ 'echo', 'hello', \'>/dev/null' ] ] will not
+#    produce any output, while the $cmd [ [ 'echo', 'hello', '>/dev/null' ] ]
+#    will literally print: hello >/dev/null
 sub run_command {
     my ($cmd, %param) = @_;
 
     my $old_umask;
     my $cmdstr;
 
-    if (!ref($cmd)) {
+    if (my $ref = ref($cmd)) {
+	if (ref($cmd->[0])) {
+	    $cmdstr = 'set -o pipefail && ';
+	    my $pipe = '';
+	    foreach my $command (@$cmd) {
+		# concatenate quoted parameters
+		# strings which are passed by reference are NOT shell quoted
+		$cmdstr .= $pipe .  join(' ', map { ref($_) ? $$_ : shellquote($_) } @$command);
+		$pipe = ' | ';
+	    }
+	    $cmd = [ '/bin/bash', '-c', "set -o pipefail && $cmdstr" ];
+	} else {
+	    $cmdstr = cmd2string($cmd);
+	}
+    } else {
 	$cmdstr = $cmd;
 	if ($cmd =~ m/\|/) {
 	    # see 'man bash' for option pipefail
@@ -269,8 +295,6 @@ sub run_command {
 	} else {
 	    $cmd = [ $cmd ];
 	}
-    } else {
-	$cmdstr = cmd2string($cmd);
     }
 
     my $errmsg;
-- 
2.1.4





More information about the pve-devel mailing list