# two parameters:
# cmd - a command or reference to an array of command + arguments
# timeout - number of seconds to wait (0 = forever)
# returns:
# cmd exit status (-1 if timed out)
# cmd results (STDERR and STDOUT merged into an array ref)
sub ExecCmd {
my $cmd = shift || return(0, []);
my $timeout = shift || 0;
# opening a pipe creates a forked process
my $pid = open(my $pipe, '-|');
return(-1, "Can't fork: $!") unless defined $pid;
if ($pid) {
# this code is running in the parent process
my @result = ();
if ($timeout) {
my $failed = 1;
eval {
# set a signal to die if the timeout is reached
local $SIG{ALRM} = sub { die "alarm\n" };
alarm $timeout;
@result = <$pipe>;
alarm 0;
$failed = 0;
};
return(-1, ['command timeout', @result]) if $failed;
}
else {
@result = <$pipe>;
}
close($pipe);
# return exit status, command output
return ($? >> 8), \@result;
}
# this code is running in the forked child process
{ # skip warnings in this block
no warnings;
# redirect STDERR to STDOUT
open(STDERR, '>&STDOUT');
# exec transfers control of the process
# to the command
ref($cmd) eq 'ARRAY' ? exec(@$cmd) : exec($cmd);
}
# this code will not execute unless exec fails!
print "Can't exec @$cmd: $!";
exit 1;
}
|