]> git.proxmox.com Git - pve-installer.git/commitdiff
sys: command: allow terminating the process early from log subroutine
authorChristoph Heiss <c.heiss@proxmox.com>
Tue, 13 Feb 2024 15:14:01 +0000 (16:14 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Fri, 23 Feb 2024 13:19:56 +0000 (14:19 +0100)
If the logging subroutine $func returns CMD_FINISHED after processing a
line, the running subprocess is killed early.
This mechanism can be used when e.g. only a certain part of the output
of a (long-running) command is needed, avoiding the extra time it would
take the command to finish properly.

This is done in a entirely backwards-compatible way, i.e. existing
usages don't need any modification.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Proxmox/Sys/Command.pm

index 6389b17e196aa2a908812522a14d9a9b278f7292..36e99c158df48fbf146b788cefc37085df62795e 100644 (file)
@@ -15,7 +15,9 @@ use Proxmox::Log;
 use Proxmox::UI;
 
 use base qw(Exporter);
-our @EXPORT_OK = qw(run_command syscmd);
+our @EXPORT_OK = qw(run_command syscmd CMD_FINISHED);
+
+use constant CMD_FINISHED => 1;
 
 my sub shellquote {
     my $str = shift;
@@ -79,7 +81,8 @@ sub syscmd {
 #
 # Arguments:
 # * $cmd - The command to run, either a single string or array with individual arguments
-# * $func - Logging subroutine to call, receives both stdout and stderr
+# * $func - Logging subroutine to call, receives both stdout and stderr. Might return CMD_FINISHED
+#           to exit early and ignore the rest of the process output.
 # * $input - Stdin contents for the spawned subprocess
 # * $noout - Whether to append any process output to the return value
 sub run_command {
@@ -163,7 +166,13 @@ sub run_command {
                $logout .= $buf;
                while ($logout =~ s/^([^\010\r\n]*)(\r|\n|(\010)+|\r\n)//s) {
                    my $line = $1;
-                   $func->($line) if $func;
+                   if ($func) {
+                       my $ret = $func->($line);
+                       if (defined($ret) && $ret == CMD_FINISHED) {
+                           wait_for_process($pid, kill => 1);
+                           return $ostream;
+                       }
+                   };
                }
 
            } elsif ($h eq $error) {