Ok, here is the code snippet. In a perl nutshell, the parent forks a child which does the actual o/s command, and the parent continues to monitor the child's duration and output size.
The child will redirect its output to the pipes and exec(). The parent _needs_ to acquire the child's stdout and stderr as fast as possible, and be able to handle (kill) a child running for longer than X time or larger than Y size.
pipe READOUT,WRITEOUT;
pipe READERR,WRITEERR;
$g_pid = fork();
if ( $g_pid < 0 ) { # Error
die "Error: fork failed with error $g_pid: $!.";
$rc = 1;
} elsif ( $g_pid == 0 ) { # Child
close(READOUT);
close(READERR);
close(STDOUT);
open(STDOUT,">&WRITEOUT");
close(STDERR);
open(STDERR,">&WRITEERR");
close(STDIN);
open(STDIN,"</dev/null");
exec($$cmdref);
exit(1);
} else { # Parent
$g_did_run++;
$g_pids{$g_pid} = 1;
close(WRITEOUT);
close(WRITEERR);
if ( $g_timeout > 0 ) {
$g_stop = 0;
alarm $g_timeout;
}
my $r_in = "";
my $w_in = "";
vec($r_in,fileno(READOUT),1) = 1;
vec($r_in,fileno(READERR),1) = 1;
vec($w_in,fileno(STDOUT),1) = 1;
my $e_in = $r_in | $w_in;
my ($r_out,$w_out,$e_out);
my $cnt=0;
my $eof_e = 0;
my $eof_o = 0;
while (1) {
my ($nfound,$timeleft) = select($r_out=$r_in,undef,$e_out=$e_
+in,1);
prog_log(20,sprintf("run_cmd: select returned time [%d] found
+ [$nfound] timeleft [$timeleft] r_out [%s] r_err [%s] e_out [%s] e_er
+r [%s]\n", time,
vec($r_out,fileno(READOUT),1)?'y':'n',
vec($r_out,fileno(READERR),1)?'y':'n',
vec($e_out,fileno(READOUT),1)?'y':'n',
vec($e_out,fileno(READERR),1)?'y':'n'));
if ( vec($r_out,fileno(READERR),1) and !vec($e_out,fileno(REA
+DERR),1) ) {
if ( eof(READERR) ) {
$eof_e = 1;
} else {
my $line = <READERR>;
chomp $line;
push @$errref, $line;
}
}
if ( vec($r_out,fileno(READOUT),1) and ! vec($e_out,fileno(RE
+ADOUT),1) ) {
if ( eof(READOUT) ) {
$eof_o = 1;
} else {
my $line = <READOUT>;
chomp $line;
push @$outref, $line;
}
}
last if ( $eof_e and $eof_o );
last if ( $g_stop );
}
if ( $g_stop ) { # Indicator for select loop to break
$rc = 2;
} else {
my $loglvl = 5;
my $t_pid = waitpid($g_pid,0);
if ( $t_pid < 0 ) {
$rc = 3;
} elsif ( $t_pid == 0 ) {
# Process no terminated yet!
$loglvl = 1;
$rc = 4;
} elsif ( $t_pid == $g_pid ) {
$rc = $?;
} else {
# Not possible!
$loglvl = 1;
$rc = 5;
}
close(READOUT);
close(READERR);
delete $g_pids{$g_pid};
prog_log($loglvl,"run_cmd: waitpid($g_pid) returned $t_pid -
+rc $rc.");
}
Thanks in advance!
-0xbeef