sys: command: handle EINTR in run_command()

Previously, the I/O loop would continue endlessly until the subprocess
exited.
This explicit handling allows run_command() to be used with e.g.
alarm().

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
This commit is contained in:
Christoph Heiss 2024-02-13 16:14:00 +01:00 committed by Thomas Lamprecht
parent 152bbef439
commit 7a95f3873f
2 changed files with 19 additions and 1 deletions

View File

@ -134,10 +134,17 @@ sub run_command {
$select->add($error); $select->add($error);
my ($ostream, $logout) = ('', '', ''); my ($ostream, $logout) = ('', '', '');
my $caught_sig;
while ($select->count) { while ($select->count) {
my @handles = $select->can_read (0.2); my @handles = $select->can_read (0.2);
# If we catch a signal, stop processing & clean up
if ($!{EINTR}) {
$caught_sig = 1;
last;
}
Proxmox::UI::process_events(); Proxmox::UI::process_events();
next if !scalar (@handles); # timeout next if !scalar (@handles); # timeout
@ -170,7 +177,7 @@ sub run_command {
&$func($logout) if $func; &$func($logout) if $func;
my $ec = wait_for_process($pid); my $ec = wait_for_process($pid, kill => $caught_sig);
# behave like standard system(); returns -1 in case of errors too # behave like standard system(); returns -1 in case of errors too
return ($ec // -1) if $noout; return ($ec // -1) if $noout;

View File

@ -27,6 +27,17 @@ my $ret = run_command('bash -c "echo test; sleep 1000; echo test"', sub {
}); });
is($ret, '', 'using CMD_FINISHED'); is($ret, '', 'using CMD_FINISHED');
# https://bugzilla.proxmox.com/show_bug.cgi?id=4872
my $prev;
eval {
local $SIG{ALRM} = sub { die "timed out!\n" };
$prev = alarm(1);
$ret = run_command('sleep 5');
};
alarm($prev);
is($@, "timed out!\n", 'SIGALRM interaction');
# Check the log for errors/warnings # Check the log for errors/warnings
my $log = file_read_all($log_file->filename); my $log = file_read_all($log_file->filename);
ok($log !~ m/(WARN|ERROR): /, 'no warnings or errors logged'); ok($log !~ m/(WARN|ERROR): /, 'no warnings or errors logged');