With these fixes, killed children at least are reported correctly for my setup.
- check this scope: if(my $writer_pid=fork...) makes a rather short-lived variable
- it might be preferable to use keys %child_status when testing the hash.
- error: check your process-id variable naming: _pid or nothing (incl. a clash with your FH naming)?
Notes
- I just used sleep 301/sleep 302 and added a copy invocation plus
some warn() e.g. when checking or setting child_status to arrive at the above list.
- As I used sleep, I didn't check filehandles and actual cat/tar.
- paranoia: missing or die() after open, fork, exec
- paranoia: consider killing the surviving process
on error after a short grace period like sleep 5 or another few iterations
HTH,
Peter
Update: Did this catch all errors :) ?
Update 2: appended the working variant above to track down remaining errors (+ /msg'ed).
modified version with just sleeps.
use Data::Dumper;
my %child_status=();
sub reaper {
my $child;
while (($child=waitpid(-1,WNOHANG))>0) {
warn "signal: $child\n";
$child_status{$child} = $? >> 8;
}
}
sub copy {
my $file = shift;
my $dir = shift;
local $SIG{CHLD} = \&reaper;
my $reader_pid = open( my $reader, '-|' );
if ($reader_pid) {
}
else {
exec 'sleep 301';
exit;
}
my $writer_pid;
if ($writer_pid = fork()) {
}
else {
chdir($dir);
open( STDIN, "<&=" . fileno($reader) );
exec 'sleep 302';
exit;
}
while (1) {
sleep 1;
next if !%child_status;
print Dumper \%child_status;
warn "r $reader_pid, w $writer_pid\n";
foreach my $pid ($reader_pid, $writer_pid) {
if ($child_status{$pid} != 0) {
%child_status = ();
die "failed tar\n";
}
}
if (exists $child_status{$writer_pid} && exists $child_status{
+$reader_pid}) {
last;
}
}
}
copy("/etc/hosts",".");